通常来说,只要谈到影子及影子制作,首先想到的不外乎3D。游戏中的影子设计大致可分为硬实现和软实现两种,比如像“游戏影子制作技术”这篇文章所谈到3D游戏影子制作方案Projective Shadow、Shadow Map以及Shadow Volume均属于硬实现。硬实现的效果最逼真,相对的运算量也较高;而对于Silverlight开发2.5D网游来说,我们通常会采用折中的软实现去表述场景中的动态光影效果。精致的光影能让玩家充分体验到空间立体感,当然也是2.5D网游所不可或缺的条件之一。
Silverlight 2.5D网游中的光影效果软实现主要采用模拟仿真方法,传统的处理方案大致有三种:
一)垂直照射的固定圆影。我们可以假想当角色被头顶上的光源所照射时会产生圆形光影,游戏中我们仅需一个圆影素材,根据角色的占地比例进行缩放匹配,2.5D立体效果立刻显现:
二)基于纸娃娃系统的动态光影。原理也很简单,就是将影子作为角色纸娃娃的部件之一根据角色的实时动作与其他部件进行动态组合。以增加美术的工作量为代价换取程序设计简单化:
三)动作同步映射的动态光影。与上一种方法所达到的效果一致,区别在于此方案我们无需额外的影子图片资源,而是通过Silverlight内置的WriteableBitmap配合上OpacityMask(透明蒙版)来实现,比如类似如下逻辑:
WriteableBitmap writeableBitmap = new WriteableBitmap(role.OverallWidth, role.OverallHeight);
writeableBitmap.Render(role.Entity, null);
writeableBitmap.Invalidate();
Rectangle rectangle = new Rectangle() { Width = role.OverallWidth, Height = role.OverallHeight, Fill = new SolidColorBrush(Colors.Black) };
rectangle.OpacityMask = new ImageBrush() { ImageSource = writeableBitmap };
大致思路是首先创建一个角色最大可能面积时的尺寸作为宽、高的WriteableBitmap对象;然后将该角色的实体部分(除去名字、血条等的外形部分)绘入WriteableBitmap中;最后再将该WriteableBitmap作为与其尺寸一致的黑色矩形的透明蒙版图像源。将整个逻辑置入角色的动作切帧方法(事件)中,一个黑黝黝的实时影子便会横空出世。当然,此时的影子还需要按照假想的场景光源位置进行偏移才能达到最终的模拟仿真效果。在Silverlight中实现透视和扭曲变形不外乎两种方案:TransformGroup和PlaneProjection。本节中我选择使用后者来实现目标:
shadow.Projection = new PlaneProjection() {
GlobalOffsetX = -p.X + shadow.Center.X,
GlobalOffsetY = -p.Y + shadow.Center.Y,
LocalOffsetX = -48,
LocalOffsetY = 92,
RotationX = 86,
RotationY = 7.6
};
shadow.Opacity = 0.5;
PlaneProjection的变换参数多达12个,相当强大,任意基于平面的3D透视效果都可轻松实现:
最后需要指出的是,如果计划为游戏添加全局的阴影开关/切换功能,建议编写一个单独的阴影管理器作为所有角色影子的存放和管理容器,而不是将影子内置到角色控件中。本节源码我对场景部分进行了重构,层次更显分明。最底层为背景地图,采用400*400切片依据主角所处位置动态加载,相关参数为屏幕分辨率(通过调用Javascript的 screen.width 和 screen.height函数获取)以及OOB模式时的窗口尺寸;往上一层便是阴影层,角色移动及动作变换时都会触发与其ID一致的影子同步行动,当然前提是该角色在以主角为中心的屏幕范围内(Visible);再往上一层便是场景空间层(Space),一切角色、动画、遮挡等均处于该层中,毕竟它们需要交互彼此之间的Z层次关系。
本节源码下载地址:Demo2.rar
在线演示地址:http://silverfuture.cn