程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#開發WPF/Silverlight動畫及游戲系列教程(Game Tutorial):(三十七)

C#開發WPF/Silverlight動畫及游戲系列教程(Game Tutorial):(三十七)

編輯:關於C#

C#開發WPF/Silverlight動畫及游戲系列教程(Game Tutorial):(三十七)地圖自適應區域加載

目前地圖編輯器已經能夠對地圖圖片進行切片了,那麼接下來我們需要做的是對切好的地圖片進行拼裝從而取代整張大地圖。需要特別說明的是,如果一次性將所有的切片加載進游戲中並顯示出來,那麼效果與使用一張整的地圖幾乎沒區別,性能上甚至可能會更差;本節我們最終要達到的目的是利用這些切片自適應的填充游戲窗口區域,即用最少的地圖片實現窗口的無縫填充,從而提升游戲的整體性能。

教程示例游戲窗口模式時的窗體尺寸為800*600,那麼我們首先根據此尺寸以400*300為單位利用地圖編輯器切割出若干地圖切片:

此時我們回過頭來對照一下地圖原圖的容量與現在切好片的地圖片的容量總和即會發現,在保持畫質不變的前提下,切片後的總容量比之前減少了近一半。如果您做的是網絡版,那麼通過切片來實現按需下載,將縮短用戶加載程序的時間同時降低服務器的負擔:

接下來是關鍵了,游戲窗口800*600,地圖切片每張為400*300,那麼每次最少需要顯示多少張切片才能在主角無論處於何位置時都能填滿游戲窗口呢?大家不妨先看下圖:

主角始終處於游戲窗口的正中,那麼它距離左邊400像素,距離頂端300像素,因此,我們通過邊緣法可以得出,只需要根據主角的x,y坐標計算出主角當前所處的地圖切片代號。以上圖為例,此時主角所處的切片為2_3.jpg,那麼我們只需加載2_3以及它周邊的9張切片:1_2.jpg、2_2.jpg、3_2.jpg、1_3.jpg、2_3.jpg、3_3.jpg、1_4.jpg、2_4.jpg、3_4.jpg即可完美填充整個游戲窗口。當然,填充用地圖切片必須是自適應的,即時時根據主角所處位置來更換所需要切片。

理解原理後,代碼實現起來就簡單多了,首先我們需要修改地圖Surface初始化代碼:

Canvas MapSurface;
int mapSectionWidth, mapSectionHeight, mapSectionXNum, mapSectionYNum;
/// <summary>
/// 初始化地圖地表層
/// </summary>
private void InitMapSurface(XElement args) {
 MapSurface = new Canvas() {
  Width = Convert.ToDouble(args.Attribute("Width").Value),
  Height = Convert.ToDouble(args.Attribute("Height").Value),
 };
 Add(MapSurface);
 mapSectionWidth = Convert.ToInt32(args.Attribute("SectionWidth").Value);
 mapSectionHeight = Convert.ToInt32(args.Attribute("SectionHeight").Value);
 mapSectionXNum = (int)(MapSurface.Width / mapSectionWidth);
  mapSectionYNum = (int)(MapSurface.Height / mapSectionHeight);
}

然後我們定義兩個非常重要的切片定位用變量:

int _leaderSectionX;
/// <summary>
/// 主角所處的切片X值
/// </summary>
public int leaderSectionX {
 get { return _leaderSectionX; }
 set { if (_leaderSectionX != value) { _leaderSectionX = value; ChangeMapSection(); } }
}
int _leaderSectionY;
/// <summary>
/// 主角所處的切片Y值
/// </summary>
public int leaderSectionY {
 get { return _leaderSectionY; }
 set { if (_leaderSectionY != value) { _leaderSectionY = value; ChangeMapSection(); } }
}

leaderSectionX和leaderSectionY分別為主角所處的切片X,Y值(對應切片命名中下劃線“_”兩端的值),其中任意一個更改後都將激發ChangeMapSection方法:

Image mapSection;
int startSectionX, startSectionY,endSectionX,endSectionY;
/// <summary>
/// 更新呈現的地圖切片
/// </summary>
private void ChangeMapSection() {
 MapSurface.Children.Clear();
 if (leaderSectionX == 0) {
  startSectionX = 0; endSectionX = 2;
 } else if (leaderSectionX == mapSectionXNum - 1) {
  startSectionX = leaderSectionX - 2; endSectionX = leaderSectionX;
 } else {
  startSectionX = leaderSectionX - 1; endSectionX = leaderSectionX + 1;
 }
 if (leaderSectionY == 0) {
  startSectionY = 0; endSectionY = 2;
 } else if (leaderSectionY == mapSectionYNum - 1) {
  startSectionY = leaderSectionY - 2; endSectionY = leaderSectionY;
 } else {
  startSectionY = leaderSectionY - 1; endSectionY = leaderSectionY + 1;
 }
 for (int x = startSectionX; x <= endSectionX; x++) {
   for (int y = startSectionY; y <= endSectionY; y++) {
     mapSection = new Image() {
                         Source = Super.getImage(string.Format("Map/{0}/Surface/{1}_{2}.jpg", mapCode.ToString(), x, y)),
       Width = mapSectionWidth,
       Height = mapSectionHeight,
       Stretch = Stretch.Fill,
     };
     MapSurface.Children.Add(mapSection);
     Canvas.SetLeft(mapSection, x * mapSectionWidth);
     Canvas.SetTop(mapSection, y * mapSectionHeight);
   }
 }
}

這裡我的處理是每次更換切片時都首先清除原有的9塊切片,然後再添加新的9塊切片到指定位置,終究是比較苯的辦法,但實現起來簡單;優化它的方法有兩種:1)判斷主角是向右移動到了新的切片上還是向左或是向下、向下,然後移除對應的3塊再添加3塊。2)將所有切片加載進地圖中,只顯示主角當前所處的9塊切片,而其他的所有切片均處於Visibility.Collapsed狀態不參加布局。此兩種方法應該算得上最終解決方案,您可以根據您游戲的實際需要進行選擇。

最後,在游戲的輔助線程中間隔檢測主角所處的切片位置(由於有間隔,所以在區域轉換時偶爾會出現白邊的現象,如果接受不了,您完全可以將下面兩行代碼放到畫面Loop中進行時時判斷處理):

leaderSectionX = (int)(Leader.X / mapSectionWidth);
leaderSectionY = (int)(Leader.Y / mapSectionHeight);

嘿嘿~是不是很簡單,且讓我們先運行一下看看效果:

問題出來了,切片的邊緣怎麼也給顯示了出來?難道是我們沒有切割好嗎?我將這些切片放進PS中重新對接,其實是可以完美吻合的,問題到底出在哪?希望好心的朋友告訴一下啦~。當然,這些縫隙是可以很輕易處理掉的,只需將每塊切片的寬與高各加1即可:

……
mapSection = new Image() {
 Source = Super.getImage(string.Format("Map/{0}/Surface/{1}_{2}.jpg", mapCode.ToString(), x, y)),
 Width = mapSectionWidth + 1,
 Height = mapSectionHeight + 1,
 Stretch = Stretch.Fill,
};
……

修改後,我們再次運行游戲,當主角移動到右下角時,我們會看到兩片白色無圖區域:

難道又是BUG?NO,NO。在上一節中我曾說過,地圖編輯器只會按比例切割出同尺寸圖片,如果某片的尺寸小於每片單位尺寸,則不切割。由於我們使用的示例地圖圖片的尺寸為2560*1920,因此以每片400*300為單位,只能切割出2400*1800的區域,這就是導致游戲中最終出現上圖情況的原因了。

遇到這種情況我們該如何處理呢?最好的辦法就是規范統一地圖尺寸與切片尺寸:假設您的游戲窗口尺寸為800*600,切片單位為400*300,那麼您的整張地圖尺寸必須設定寬度為400的整倍數,高度為300的整倍數。另一種方案就是通過邏輯來呈現這些邊緣不標准的切片。

地圖自適應區域加載的實現,在一定程度上優化了游戲的整體性能,在地圖尺寸越大的游戲中表現得更為突出。所有關於地圖的教程快接近尾聲了,下一節我將為大家講解如何實現地圖切換與傳送,敬請關注。

出處:http://alamiye010.cnblogs.com/

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved