C#開發WPF/Silverlight動畫及游戲系列教程(Game Tutorial):(三十六)地圖自定義切片與導出
做為提升游戲性能的一個重要環節就是地圖的優化,作為基於Web的游戲來說,可以通過將地圖切成若干同尺寸的片後,根據主角的位置進行時時的按需加載。舉個簡單例子,好比一幅20000*20000的地圖,我們將之以400*400像素為一個地圖片單位切成2500片,假若游戲窗口尺寸為800*600,那麼我們每次只需加載以主角為中心的周圍9塊地圖片(1200*900像素)即可實現填充,這比起一次性加載諾大一張地圖,且在移動時對其不停的切割,性能優越得太多太多。
那麼本節我將向大家講解如何為地圖編輯器添加自定義切片與導出功能,從而為下一節的游戲地圖性能優化做准備。
大家是否還記得在第三十四節中,我將地圖顯示部份分為了三層:障礙物層,障礙物單元格邊線層及地圖切片邊線層。我曾在文中提過利用Grid的ShowGridLines來為單元格設置邊框操作,盡管使用簡單但性能卻極其低下。這裡我們可以通過在障礙物單元格邊線層中繪制Line的方式來優化它:
/// <summary>
/// 繪制網格邊線
/// </summary>
private void SetGridLines(Canvas carrier, double totalWidth, double totalHeight, double singleWidth, double singleHeight,Color lineColor, double dashWidth, double dashSpace) {
carrier.Children.Clear();
int sectionXNum = (int)(totalWidth / singleWidth);
int sectionYNum = (int)(totalHeight / singleHeight);
for (int x = 1; x <= sectionXNum; x++) {
Line line = new Line() {
X1 = x * singleWidth,
X2 = x * singleWidth,
Y1 = 0,
Y2 = totalHeight,
Stroke = new SolidColorBrush(lineColor),
StrokeDashArray = new DoubleCollection() { dashWidth, dashSpace },
};
carrier.Children.Add(line);}
for (int y = 1; y <= sectionYNum; y++) {
Line line = new Line() {
X1 = 0,
X2 = totalWidth,
Y1 = y * singleHeight,
Y2 = y * singleHeight,
Stroke = new SolidColorBrush(lineColor),
StrokeDashArray = new DoubleCollection() { dashWidth, dashSpace },
};
carrier.Children.Add(line);
}
}
其中Line的Stroke參數用於設置線條顏色(注意Fill屬性對它來說沒有任何效果),而StrokeDashArray參數則用來定義線條虛線部分的寬與間距。既然地圖切的是矩形片,那麼我們同樣可以將此方法用於地圖切片分割的功能上。為了在地圖編輯器上增加可以自定義切片尺寸的選擇器,考慮到Slider不太合適,這裡我選擇使用WinForm控件庫中的NumericUpDown,即靈活又強大。在WPF中的添加WinForm控件需要幾個步驟:
1)添加dll引用:需要引用WindowsFormsIntegrationl和System.Windows.Forms。
2)如果是在xaml中使用,則需要添加類似如下的定義:
xmlns:WinFormHost = "clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
xmlns:WinForm = "clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
3)使用的時候通過一個WinFormHost包含一個WinForm控件的形式,以添加兩個NumericUpDown為例,我們可以這樣寫:
<WinFormHost:WindowsFormsHost Canvas.Left="820" Canvas.Top="170" Height="20" Width="101">
<WinForm:NumericUpDown x:Name="SectionWidth" Maximum="500" Minimum="100" Increment="10" Value="300" ValueChanged="SectionSize_ValueChanged" />
</WinFormHost:WindowsFormsHost>
<WinFormHost:WindowsFormsHost Canvas.Left="820" Canvas.Top="196" Height="20" Width="101">
<WinForm:NumericUpDown x:Name="SectionHeight" Maximum="500" Minimum="100" Increment="10" Value="300" ValueChanged="SectionSize_ValueChanged" />
</WinFormHost:WindowsFormsHost>
在VS設計器中我們僅能看到它們以WinFormHost的描述形式顯示,只有在運行時才能看到它們真正的實體內容:
那麼接下來同樣的我們通過繪制Line的方式來繪制切片邊線,具體方法與繪制障礙物邊線非常相似,額外再通過一些簡單的事件即可實現自定義地圖切片設計:
上圖中灰色虛線為10*10像素單位的障礙物單元格邊線,棕紅色虛線為250*286像素單位的切片邊線,通過NumericUpDown可以非常方便的定義最大值、最小值、有效值及跨越值,並且通過它的ValueChanged事件實現輕松的所見即所得。
設定完切片邊線的顯示後,最後將根據此切片預覽實現真正的地圖片導出功能。這裡我們可以使FolderBrowserDialog文件夾選擇對話框,並配合如下方法來實現此功能:
int sectionXNum = (int)(mapWidth / (double)SectionWidth.Value);
int sectionYNum = (int)(mapHeight / (double)SectionHeight.Value);
for (int x = 0; x < sectionXNum; x++) {
for (int y = 0; y < sectionYNum; y++) {
CroppedBitmap croppedBitmap =
new CroppedBitmap(mapSource, new Int32Rect(x * (int)SectionWidth.Value, y * (int)SectionHeight.Value, (int)SectionWidth.Value, (int)SectionHeight.Value));
System.IO.FileStream fileStream =
new System.IO.FileStream(string.Format(@"{0}/{1}_{2}.jpg", outputSection.SelectedPath, x, y), System.IO.FileMode.Create);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(croppedBitmap));
encoder.Save(fileStream);
fileStream.Close();
}
}
通過前面章節的學習,大家對CroppedBitmap再熟悉不過了,它應該算是WPF中最受寵愛的對象之一。此方法根據地圖切片數量(sectionXNum,sectionYNum),利用FileStream和JpegBitmapEncoder循環導出jpg圖片到FolderBrowserDialog指定的文件夾(SelectedPath)中。最後得到的是類似如下若干被自動切割得整整齊齊的地圖切片:
最後還有兩個問題需要說明:
1)設定的切割尺寸最好能完整切割完整張地圖,例如地圖尺寸為2800*3200,那麼您可以將切片的單位尺寸設定為350*400,這樣切割下來剛好64張;如果您將切片尺寸設定為320*400,則地圖最右邊緣的一部分將不被切割出來。因此地圖尺寸與切割尺寸需要默契配合,這理當屬於美工的范疇,作到應該不難。
2)為了降低地圖編輯器的設計難度,我並未在Stream中對圖片數據流進行壓縮處理,這將使得導出的jpg圖片由於質量過高而引起容量很大,基於Web的游戲對文件大小非常敏感。因此,我建議您可以自行添加數據流壓縮方法,或者通過photoshop的壓縮批處理來完成這些操作。下面是以上地圖片壓縮前後的容量對比:
嘿嘿~這一節非常有意思吧。那麼多的圖片眼睛都快花了,該怎樣使用呢?下一節我將向大家講解如何在本教程示例游戲中使用它們來實現地圖的區域性按需加載,關注哦。
出處:http://alamiye010.cnblogs.com/