下一篇:C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(十七) 完美精灵之八面玲珑①

紧接着上一节,首先得解释一下为什么需要将这272张图片合成为一张大图。因为如果游戏中还有装备、坐骑等其他设置,那么我们就需要对图片源进行时时的合成;同时对272张甚至更多的图片进行合成效率高还是对2张大图进行合成效率高这是显而易见的。在本节例子中,主角由身体(衣服)及武器两个部分组成;因此,我们还需要定义一个交错数组来保存已经加载的角色装备合成图到内存中:
  1.         /// <summary>

  2.         /// 角色图片缓存

  3.         /// 交错数组示例PartImage[a,b][c,d]

  4.         /// a为衣服代号(在本例中也可以理解为身体代号,因为换衣服就相当于换角色身体)

  5.         /// b为武器代号

  6.         /// c为角色朝向代号

  7.         /// d代表当前动作帧所处于整合图中的列数

  8.         /// 本例中1-5列为站立,6-13列为跑动,14-20列为攻击,21-26列为施法,27-34列为死亡

  9.         /// 本例中PartImage = new BitmapSource[10, 20][,];即初步设定有10个角色,20种武器

  10.         /// </summary>

  11.         public static BitmapSource[,][,] PartImage = new BitmapSource[10, 20][,];
复制代码
例如PartImage[0,6]即代表0号角色拿着6号武器8个方向所有动作帧图片源

    PartImage[4,0]则代表4号角色空着手8个方向所有动作帧图片源

    ……依此类推

    如果您的游戏中还有帽子及坐骑,则需要BitmapSource[,][,,,] PartImage这样将第二组定义为4维数组。

    ……依此类推

    当然,你也可以使用Hashtable(哈希表)、Dictionary(字典)等来代替PartImage[,][,]。但是在数字类型键与对象值对应保存的方式中,我更倾向于交错数组,因为它更清晰、优雅且高效。

    有了承接角色的载体,下面就是如何对上一节中合成的角色大图与武器大图(提取及合成方法同上一节相同)进行拼装,最后分帧存储进PartImage。嘿嘿,又现精华:
  1.         /// <summary>

  2.         ///  拼装角色+装备后切割成系列帧图片并保存进内存(装备角色)

  3.         /// </summary>

  4.         /// <param name="Equipment">装备代号数组</param>

  5.         /// <param name="rowNum">帧合成图行数</param>

  6.         /// <param name="colNum">帧合成图列数</param>

  7.         /// <param name="totalWidth">帧图合成后总宽</param>

  8.         /// <param name="totalHeight">帧图合成后总高</param>

  9.         /// <param name="singleWidth">单帧图宽</param>

  10.         /// <param name="singleHeight">单帧图高</param>

  11.         /// <returns>如果缓存中有则读取缓存,否则返回合成的图片源</returns>

  12.         public static BitmapSource[,] EquipPart(int[] Equipment, int rowNum, int colNum, int totalWidth, int totalHeight, int singleWidth, int singleHeight) {

  13.             //Equipment[0]为衣服代号,Equipment[1]为武器代号,本例中装备只由衣服+武器组成

  14.             //假如内存中没有该装备的角色现成图片源则进行读取

  15.             if (PartImage[Equipment[0], Equipment[1]] == null) {

  16.                 BitmapSource[,] bitmap = new BitmapSource[rowNum, colNum];

  17.                 //加载角色衣服(身体)大图

  18.                 BitmapSource bitmapSource = new BitmapImage(new Uri(@"Images\Body" + Equipment[0].ToString() + ".gif", UriKind.Relative));

  19.                 //假如武器不是0,即如果角色手上有武器而非空手

  20.                 if (Equipment[1] != 0) {

  21.                     //加载武器大图,并与衣服大图组装

  22.                     BitmapSource bitmapSource1 = new BitmapImage(new Uri(@"Images\Weapon" + Equipment[1].ToString() + ".gif", UriKind.Relative));

  23.                     DrawingVisual drawingVisual = new DrawingVisual();

  24.                     Rect rect = new Rect(0, 0, totalWidth, totalHeight);

  25.                     DrawingContext drawingContext = drawingVisual.RenderOpen();

  26.                     drawingContext.DrawImage(bitmapSource, rect);

  27.                     drawingContext.DrawImage(bitmapSource1, rect);

  28.                     drawingContext.Close();

  29.                     RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(totalWidth, totalHeight, 0, 0, PixelFormats.Pbgra32);

  30.                     renderTargetBitmap.Render(drawingVisual);

  31.                     bitmapSource = renderTargetBitmap;

  32.                     //降低图片质量以提高系统性能(由于本身图片已经为低质量的gif类型,因此效果不大)

  33.                     //RenderOptions.SetBitmapScalingMode(bitmapSource, BitmapScalingMode.LowQuality);

  34.                 }

  35.                 for (int i = 0; i < rowNum; i++) {

  36.                     for (int j = 0; j < colNum; j++) {

  37.                         bitmap[i, j] = new CroppedBitmap(bitmapSource, new Int32Rect(j * singleWidth, i * singleHeight, singleWidth, singleHeight));

  38.                     }

  39.                 }

  40.                 //将装备合成图放进内存

  41.                 PartImage[Equipment[0], Equipment[1]] = bitmap;

  42.                 return bitmap;

  43.             } else {

  44.                 //如果内存中已存在该装备的角色图片源则从内存中返回合成图,极大提高性能

  45.                 return PartImage[Equipment[0], Equipment[1]];

  46.             }

  47.         }
复制代码
该方法我已经做了非常详细的注释,大致原理就是将上一节中合成的角色身体大图(5100*1200那张)与一张同样尺寸的武器大图进行合成,组装成一张5100*1200像素的带武器的角色图,最后再将这张图进行所有序列单帧按150*150尺寸进行切割存储进PartImage这个数组中:

附件: 1.jpg
TOP