Silverlight4 Bata1发布了,在无数银光FANS的期待中悄悄的诞生了。如大家所愿,MS几乎满足了所有我们之前在Silverligh3中抱怨且无法做到的一切。它是一个极具里程碑意义的版本,从功能范围上讲,它已经开始有超越Flash的苗头;而从性能上说,官方公布的图形渲染速度将大幅度提升更是给目前本身性能就不是非常好的FLASH当头一棒;外加Silverlight在内存管理方面的优异表现,我更加期待Silverlight4这个伟大神作的降临。
用什么来承受未来几个月日思夜想的折磨?除了学习还是学习。
感慨了一翻,嘿嘿。本节我将为大家讲解如何为Silverlight游戏制作一个精美的Mini地图。Mini地图又分两种,一种是通常处于游戏窗口右上角的Mini雷达(导航)地图;另一种是全景Mini寻路地图。本节我先向大家讲解如何制作导航Mini雷达地图。此类地图在游戏中主要起到导航作用,即引导主角前行的方向,并且呈现出主角周围的各种对象,诸如:怪物、NPC、传送点等等;更多的,您还可以为之添加近距离寻路等高级功能。
首先是设计阶段,大家不妨先看一副图:
我为本教程游戏制作的Mini雷达地图包含大致几个功能:
1)显示/隐藏Mini地图功能。实现起来很简单,只需修改Mini雷达地图的身体呈现区域部分的Visibility即可。但是该功能却对整个游戏的性能起着巨大的调节作用。大家应该都清楚Mini雷达地图几乎相当于游戏窗口的一个缩小型副本,它更新且呈现的元素是很多的,特别是在对性能要求很大的WebGame中,这迫使我们必须为之安装个开关以控制当我们不需要看导航Mini地图时暂时将之关闭,从而停掉相关的逻辑运算及对象呈现;比如在大量杀怪中,Mini雷达地图基本没什么作用,这时我们就可以通过此按钮关闭它,节省出更多的CPU使游戏更加流畅,使玩家更能体验战斗的快感。
2)Mini地图缩放功能。这里我需要先向大家讲解一下我的Mini雷达地图制作及处理方法;当然,或许您还有比之更好的解决方案,望提出。至于我这个方案,则是建立在多种尝试之后筛选出来的个人感觉比较完美的处理方式。
第一步,我首先为每张地图制作一个等比例缩小N倍,且统一尺寸的地图图片。以我的Demo中第一个地图为例,该地图原始尺寸为4800*3600,那么我将之缩小8倍后尺寸为600*450;然后通过PS保存出30质量的图片容量只有30多K,同时它还可以做为下一节中我将为大家讲解到的Mini雷达地图图片源所用,一举两得。同样的,第二副地图尺寸为2400*1800,那么我将之缩小4倍后尺寸同样为600*450,依次类推。当然,如果不规则尺寸的地图也可以同样处理,只需将之缩小一定倍数,使之最终尺寸小于且接近600*450这个尺寸即可,至于600*450这个尺寸怎么来的?详见下节。
第二步,为Mini雷达地图添加配置,以第一副地图为例:
<MiniMap Scaling="8" MinScaling="1" MaxScaling="30" />
该配置描述了Mini雷达地图缩小的倍数,以及最小、最大值变动缩放限制范围。即对应上图中的X,以及右边的-、+按钮功能。
第三步,在游戏地图初始化完后加载它及相关参数:
private void LoadMiniMap() {
if (miniMap == null) { return; }
//加载mini地图
miniMap.MiniMap.Children.Add(new Image() {
Name = "MiniMapImage",
IsHitTestVisible = false,
Stretch = Stretch.Fill,
Source = Super.GetImage(string.Format("/Image/Map/{0}/MiniMap/0.jpg", mapCode)),
});
miniMap.VSName = "一区[亚特兰蒂斯]";
miniMap.VMapName = Super.Settings[mapData].Attribute("Name").Value;
miniMap.MapOriginalWidth = mapWidth;
miniMap.MapOriginalHeight = mapHeight;
miniMap.Scaling = (double)Super.Settings[mapData].Element("MiniMap").Attribute("Scaling");
miniMap.MinScaling = (int)Super.Settings[mapData].Element("MiniMap").Attribute("MinScaling");
miniMap.MaxScaling = (int)Super.Settings[mapData].Element("MiniMap").Attribute("MaxScaling");
}
第四步,实现对应的-、+缩放按钮功能:
//鼠标左键路由点击
private void UserControl_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) {
//如果点到伸缩按钮
if (e.OriginalSource == Telescopic) {
……
} else if (e.OriginalSource == Narrow) {
if (Scaling > MinScaling) { Scaling -= 1; }
} else if (e.OriginalSource == Zoom) {
if (Scaling < MaxScaling) { Scaling += 1; }
}
e.Handled = true;
}
通过以上步骤,我们即可轻松的实现Mini雷达地图的缩放功能。这里我也想说说我曾经尝试过的其他方案,例如根据主角当前位置加载一定数量缩小后的地图图片到Mini雷达地图窗口中,但此方法瞬间性能消耗很大;还比如在地图初始化时通过WriteableBitmap将所有地图图片合成为一张整图再按比例缩小,此方法理论上可行,但是将导致一开始必须将所有地图片全部下载下来,此方法与本引擎地图片按需下载的原理相违背。同时我还测试过其他两种更不科学的方案,具体就不说了。因此,最终我选择了本文上述讲解的方案,不仅性能高,消耗的资源少,而且可以被Mini雷达地图与Mini寻路地图所共用,算是个人感觉比较完美的方案了。
3)对象及参数呈现功能。本文开头曾说过,该Mini雷达地图的呈现原理其实与主角在游戏地图中移动原理几乎一样,这又该如何理解呢?我们先看下图:
我通过一块蒙板恰当的覆盖在Mini雷达地图面板上,从而只有在该蒙板面积区域内的对象,包括小地图及它上面呈现的对象等才能被显示出来。因此我们可以将主角移动用的“托盘式”主位地图移动模式完美移植到Mini雷达地图中,两者可调用同样的方法(参数不同而已)。这里还涉及到一些性能方面的技巧,例如主角的坐标及Mini雷达地图地图图片的移动是时时的;而其他物体对象的移动则可以将它们放到间隔为500毫秒的辅助后台线程中处理,包括他们的添加/移除。在本教程示例游戏中,我设定可以添加进Mini雷达地图中的对象呈现类型为UIElement,这意味着大家可以充分发挥想象与创造力来美化它。例如我将主角用绿色文字来表示,而怪物则用粉色描边的圆矩形表示等等。
......
if (sprite == Leader) {
miniMap.MiniMap.Children.Add(new TextBlock() {
Name = string.Format("Obj{0}", sprite.Name),
Text = Leader.VSName,
FontSize = 10,
Foreground = new SolidColorBrush(Color.FromArgb(255, 206, 241, 190)),
});
} else {
miniMap.MiniMap.Children.Add(new Rectangle() {
Name = string.Format("Obj{0}", sprite.Name),
Width = 6,
Height = 6,
RadiusX = 3,
RadiusY = 3,
Stretch = Stretch.Fill,
Fill = new SolidColorBrush(Color.FromArgb(255, 184, 105, 167)),
StrokeThickness = 1,
Stroke = new SolidColorBrush(Color.FromArgb(255, 88, 88, 88))
});
}
……
此Mini雷达地图可谓麻雀随小五脏俱全,大家可以在此基础上发挥更多的创新,例如在上面代码中为每加入的新的对象矩形添加一个ToolTip;这样,当我们鼠标悬停在它上面时即可以显示该对象的名字等等。
下一节,我将继续为大家讲解如何制作另一种Mini雷达地图:全景Mini寻路地图,敬请关注。
附:
-- 09.11.20
1)修正魔法装饰特效偏移错误问题
2)修正障碍物会被突破BUG
源码请到目录中下载,在线演示地址:http://silverfuture.cn