通过第十四节第十五节的学习,我们掌握了如何创建一个初具雏形的精灵控件。目前我已经赋予了它少量的属性,但是离完美还有很长的距离。因此,我打算在后面的章节中以辅助游戏设计为前提,对该精灵控件进行全方位的包装,使之更加趋于完美与和谐(^-^||)。

    在前面所有章节的示例中,角色均只有一个方向,且动作均为跑步状态,因此很多朋友都问我该如何实现角色的全方向及全动作。尽管我在文中已经提级了相关的解决方案;但是,对于初次接触WPF/Silverlight游戏制作的朋友在逻辑上或许还是有较大难度的。那么本节将实现主角8方向(在下文中凡涉及到角色方向时,我均会以时钟0点的位置为0,然后顺时针方向依次为1234567,通俗来讲即方向代号0代表角色面朝1代表东北2代表3代表东南4代表5代表西南6代表西7代表西北)如下图:

    5大基本动作(每个动作均由若干帧组成,就拿本教程后面都要用到的主角图片为例,其中站立动作由5张图片连续播放形成、跑动8张、攻击7张、施法6张、翘辫子8张。当然,在高质量的游戏中一个角色并不只这5个动作,还有例如受伤、眩晕、上马下马等等动作,本教程以教会大家如何去基础使用与常规制作为目的,关于更精细的活还得靠大家自行发挥与创新。至于你问我这些动作的帧数设置是否是最合理,我可以告诉大家肯定不是(图片为破天一剑的,我保留了原先的帧配置未做大的改动)。如果你打算开发的是Silverlight游戏,我建议尽量让每个动作帧数不要超过5帧,实践证明这在网页游戏中能达到性能与效果的黄金分割;至于在WPF这样带客户端的游戏中,你大可将所有的动作均设置为10+帧都无所谓,在后面的教程中我将给大家见识一下剑侠世界中的16帧动作)如下图:

    全面讲解即将开始,一定要认真听哦!坐正啦!

    首先我们需要通过3DMAX等工具制作出一个拥有这5个动作的3D动画角色,然后将之导出为8个方向5个动作的系列帧图片(大家如果只是做练习用,可以从网上下载相关素材或通过提取工具来提取,但是请勿用于商业用途,否则是需要承担法律责任的)。这个过程不在本教程范围内,所以就不详细讲解了。接下来为了节省时间,我就不再重新提取素材了,我将以QXGame(WPF GAME ENGINE)游戏引擎中的主角为例进行相关解说。

    如果素材是通过3D渲染2D的方式得到的,那么素材均为统一标准尺寸的连续单幅图片(不是的话找美工的麻烦);但是如果是从网上下载或提取的话,每帧图片的尺寸并不统一。因此,我们首要做的是将这些图片通过Photoshop中的“动作”功能进行批量处理,使所有帧图片尺寸规格统一。就以本节中的主角为例,我将它的所有帧图片规格均统一为150*150像素,并且主角在图片中的水平及垂直方向均居中,如下图(该图为局部,一共有8*34=272张)。

 

    尺寸规格统一好以后,接下来还需要对所有图片进行微调(可想而知,游戏制作中对美工人数的需求是极其庞大的。就如我在前面章节中说到的,游戏开发的成功,极大幅度取决于美工,程序逻辑方面仅位列游戏需求分析、界面地图美术设计之后排在第三)。所谓微调,就是将角色的各帧图片通过测试工具让它运动起来(如第四第五节中的方法),然后观察每帧图片重叠起来位置是否吻合,不吻合的则需要通过Photoshop进行微调,使它上面的角色处于图片正确的位置上(如下图则为错误的叠加,我们必须将所有帧图片完全对齐,这样连续切换的时候才能不漏破绽):

    至此就完成了素材准备阶段。一切就绪后,接下来的工作就是将主角8方向5动作的所有帧图片(本例子中的272张)进行处理,最终合成一张将这所有图片按一定规律排列的8方向5动作整合图。就以这272张图片为例,如何使用WPF类库中的方法将它们合并为一张图片呢?来看本节的第一个精华ComposeImage()方法:

        /// <summary>

        /// N帧图片合成一张8方向角色各动作分布图

        /// </summary>

        /// <param name="SourcePath">源文件路径</param>

        /// <param name="SavaToPath">保存文件到目标路径</param>

        /// <param name="imgnum">源图片数量</param>

        /// <param name="imgwidth">单位图片宽</param>

        /// <param name="imgheight">单位图片高</param>

        public static void ComposeImage(string SourcePath, string SavaToPath, int imgNum, int imgWidth, int imgHeight) {

            System.IO.FileStream fileStream = new System.IO.FileStream(SavaToPath, System.IO.FileMode.Create);

            DrawingVisual drawingVisual = new DrawingVisual();

            DrawingContext drawingContext = drawingVisual.RenderOpen();

            int count = 1;

            for (int i = 0; i < 8; i++) {

                for (int j = 0; j < imgNum / 8; j++) {

                    drawingContext.DrawImage(new BitmapImage(new Uri(SourcePath + count + "-1.png")), new Rect(j * imgWidth, i * imgHeight, imgWidth, imgHeight));

                    count += 1;

                }

            }

            drawingContext.Close();

            RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap((imgNum / 8) * imgWidth, 8 * imgHeight, 0, 0, PixelFormats.Pbgra32);

            renderTargetBitmap.Render(drawingVisual);

            PngBitmapEncoder encoder = new PngBitmapEncoder();

            encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));

            encoder.Save(fileStream);

            fileStream.Close();

        }

    我将该方法写在一个名叫Super的静态类中,关于它的参数意思在注释中已经写得很清楚了,至于它是如何实现将这272张图片有规律的合成为1张我们能够在后面使用的合成图,大家只需要注意我用黄色突出的代码,这是主要的算法逻辑(单张图片的文件名格式如前文中的格式图上的一样,例如1-1.png2-1.png3-1.png4-1.png5-1.png6-1.png……等等,如果你的图片是1.png2.png3.png4.png5.png6.png7.png8.png……等等这样的取名格式,那么只需要将"-1.png"换成".png"即可)。至于其它的部分大家稍微看一下就可以轻松理解了。

    上图上部分即为我调用Super.ComposeImage(@"E:\Body\", "Body0.png", 272, 150, 150);方法合成的主角8方向5动作的一张宽150*34=510034=5+8+7+6+8)像素、高150*8=12008=8个方向,按照上文中的顺序)像素的整合图。(由于该图尺寸过大(5100*1200像素),所以我将之缩小为原尺寸的15%左右以供给大家展示)

    从上图下部分中(上部分的局部放大图),大家可以很清晰的发现图片排列的规律:即834列;从行看,由上至下的8行分别为代号0-78个方向的所有图片;从列看1-5列为站立帧图片,6-13列为跑动帧图片,14-20列为攻击帧图片,21-26列为施法帧图片,27-34列为死亡帧图片。理清了规律后,如何对它进行局部单图截取?嘿嘿,且听下回分解。

WPF/Silverlight
作者:深蓝色右手
出处:http://alamiye010.cnblogs.com
教程目录及源码下载:点击进入(欢迎加入WPF/Silverlight小组 WPF/Silverlight博客团队)
本文版权归作者和博客园共有,欢迎转载。但未经作者同意必须保留此段声明,且在文章页面显著位置给出原文连接,否则保留追究法律责任的权利。
posted on 2009-06-26 20:11  深蓝色右手  阅读(13374)  评论(23编辑  收藏  举报