C#開發WPF/Silverlight動畫及游戲系列教程(Game Course):(十八) 完美精靈之八面玲珑(WPF Only)②
緊接著上一節,首先得解釋一下為什麼需要將這272張圖片合成為一張大圖。因為如果游戲中還有裝備、坐騎等其他設置,那麼我們就需要對圖片源進行時時的合成;同時對272張甚至更多的圖片進行合成效率高還是對2張大圖進行合成效率高這是顯而易見的。在本節例子中,主角由身體(衣服)及武器兩個部分組成;因此,我們還需要定義一個交錯數組來保存已經加載的角色裝備合成圖到內存中:
/// <summary>
/// 角色圖片緩存
/// 交錯數組示例PartImage[a,b][c,d]
/// a為衣服代號(在本例中也可以理解為身體代號,因為換衣服就相當於換角色身體)
/// b為武器代號
/// c為角色朝向代號
/// d代表當前動作幀所處於整合圖中的列數
/// 本例中1-5列為站立,6-13列為跑動,14-20列為攻擊,21-26列為施法,27-34列為死亡
/// 本例中PartImage = new BitmapSource[10, 20][,];即初步設定有10個角色,20種武器
/// </summary>
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。嘿嘿,又現精華:
/// <summary>
/// 拼裝角色+裝備後切割成系列幀圖片並保存進內存(裝備角色)
/// </summary>
/// <param name="Equipment">裝備代號數組</param>
/// <param name="rowNum">幀合成圖行數</param>
/// <param name="colNum">幀合成圖列數</param>
/// <param name="totalWidth">幀圖合成後總寬</param>
/// <param name="totalHeight">幀圖合成後總高</param>
/// <param name="singleWidth">單幀圖寬</param>
/// <param name="singleHeight">單幀圖高</param>
/// <returns>如果緩存中有則讀取緩存,否則返回合成的圖片源</returns>
public static BitmapSource[,] EquipPart(int[] Equipment, int rowNum, int colNum, int totalWidth, int totalHeight, int singleWidth, int singleHeight) {
//Equipment[0]為衣服代號,Equipment[1]為武器代號,本例中裝備只由衣服+武器組成
//假如內存中沒有該裝備的角色現成圖片源則進行讀取
if (PartImage[Equipment[0], Equipment[1]] == null) {
BitmapSource[,] bitmap = new BitmapSource[rowNum, colNum];
//加載角色衣服(身體)大圖
BitmapSource bitmapSource = new BitmapImage(new Uri(@"Images\Body" + Equipment[0].ToString() + ".gif", UriKind.Relative));
//假如武器不是0,即如果角色手上有武器而非空手
if (Equipment[1] != 0) {
//加載武器大圖,並與衣服大圖組裝
BitmapSource bitmapSource1 = new BitmapImage(new Uri(@"Images\Weapon" + Equipment[1].ToString() + ".gif", UriKind.Relative));
DrawingVisual drawingVisual = new DrawingVisual();
Rect rect = new Rect(0, 0, totalWidth, totalHeight);
DrawingContext drawingContext = drawingVisual.RenderOpen();
drawingContext.DrawImage(bitmapSource, rect);
drawingContext.DrawImage(bitmapSource1, rect);
drawingContext.Close();
RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(totalWidth, totalHeight, 0, 0, PixelFormats.Pbgra32);
renderTargetBitmap.Render(drawingVisual);
bitmapSource = renderTargetBitmap;
//降低圖片質量以提高系統性能(由於本身圖片已經為低質量的gif類型,因此效果不大)
//RenderOptions.SetBitmapScalingMode(bitmapSource, BitmapScalingMode.LowQuality);
}
for (int i = 0; i < rowNum; i++) {
for (int j = 0; j < colNum; j++) {
bitmap[i, j] = new CroppedBitmap(bitmapSource, new Int32Rect(j * singleWidth, i * singleHeight, singleWidth, singleHeight));
}
}
//將裝備合成圖放進內存
PartImage[Equipment[0], Equipment[1]] = bitmap;
return bitmap;
} else {
//如果內存中已存在該裝備的角色圖片源則從內存中返回合成圖,極大提高性能
return PartImage[Equipment[0], Equipment[1]];
}
}