二、通過加載配置文件,進行系統參數設置:
在游戲設計中,很多參數是在啟動游戲時就必須加載的,即游戲的初始化讀取(Loading Data…),例如當前的地圖、障礙物、遮擋物、聲音等資料數據。這些數據往往在游戲開發初期習慣性的被程序員放在代碼中(內存中),目的是方便頻繁的修改及調試;但是,當項目進展到需要實現具體功能的實質性階段,此時迫切需要將這些數據進行歸類並統一放到一些配置文件中,這樣我們可以通過修改外圍配置文件實現不同的游戲啟動配置而不必再重新編譯,從而極大幅度的提高設計的拓展性且易於維護和更新。舉個最簡單的例子,網絡游戲在運營中如果服務器地址發生變更,由IP:145.10.6.8換成IP:167.10.8.9,那麼你會怎麼做?在游戲代碼中更改服務器連接IP,然後重新編譯發布後告訴所有的玩家:“請重新下載游戲新版本客戶端,否則將無法登陸服務器。”這是極其愚蠢的做法不是嗎?因此,網絡游戲在啟動時均會檢測更新,通過接收更新服務器傳來的新版文件替換掉每個客戶端的舊配置文件,這樣游戲啟動時即可以加載新的配置參數連接上新的服務器地址。
那麼,在WPF/Silverlight中我們應該以什麼作為配置文件載體?ini文件?不,那太原始了。XML文件才是.Net開發者的追求。下面我以設置地表層與遮罩層配置為例,向大家講解在WPF/Silverlight中如何加載XML配置文件。
首先我們需要在項目中添加一個名為System的文件夾,然後在其中新建一個名為Config.XML的配置文件並寫入如下內容:
<?XML version="1.0" encoding="utf-8" ?>
< Config>
<Maps>
<Map Sign="0">
<Surface Src="Map\0\0.jpg" Width="1750" Height="1440" X="0" Y="0"></Surface>
<Mask Src="Map\0\0.jpg" Width="55" Height="73" X="1040" Y="179" CenterY="73" Opacity="0.7"></Mask>
<Mask Src="Map\0\0.jpg" Width="202" Height="395" X="793" Y="612" CenterY="395" Opacity="0.7"></Mask>
……
< /Map>
<Map Sign="1">
……
< /Map>
<Map Sign="2">
……
< /Map>
……
</Maps>
< /Config>
從上面代碼可以看到,它配置了地圖集合節點<Maps>,在此節點下是不同代號的地圖節點:<Map Sign="0">、<Map Sign="1">、<Map Sign="2">等,以代號為0(Sign=”0”)的地圖節點為例,在它下面有一個Surface節點和若干個Mask節點,它們描述的是0號地圖的一個地表層與若干遮擋物,而這些節點中的屬性,如Src、Width、Height、X、Y等等,均是以它們自身的屬性名來命名,這樣在調用的時候可以很方便的對應上。
設置完配置文件後,接下來的任務就是在代碼中調用之。目前加載xml文件的方法很多,我選擇XLINQ(LINQ TO XML),為什麼?因為我喜歡LINQ,它是我見過最具藝術感的語法尤物。
話不多說,先看本節的精華方法GetTreeNode():
/// <summary>
/// 獲取XML文件樹節點
/// </summary>
/// <param name="xml">XML文件載體</param>
/// <param name="mainnode">要查找的主節點</param>
/// <param name="attribute">主節點條件屬性名</param>
/// <param name="value">主節點條件屬性值</param>
/// <returns>以該主節點為根的XElement</returns>
public static XElement GetTreeNode(XElement XML, string newroot, string attribute, string value) {
return XML.DescendantsAndSelf(newroot).Single(X => X.Attribute(attribute).Value == value);
}
該方法僅僅一行代碼,卻可以高速查找出XML樹中任意節點,強悍得只能用“了得”兩個字來形容。接著就是使用它來加載地圖表層Surface配置:
/// <summary>
/// 初始化游戲物件對象
/// </summary>
private void InitializeGameObject() {
//獲取代號為0的地圖數據
XElement mapdata = Super.GetTreeNode(Super.SystemConfig, "Map", "Sign", "0");
//抽離地圖數據中的地表層參數並用其來初始化地圖地表層
InitMapSurface(mapdata.Element("Surface"));
……
}