這裡我們通過GetTreeNode()方法得到Sign==”0”的Map節點,然後以該節點為參數初始化地圖表層:
private void InitMapSurface(XElement args) {
MapSurface = new QXMap();
MapSurface.Source = BitmapFrame.Create(new Uri(string.Format(@"{0}", args.Attribute("Src").Value), UriKind.Relative));
MapSurface.Width_ = Convert.ToDouble(args.Attribute("Width").Value);
MapSurface.Height_ = Convert.ToDouble(args.Attribute("Height").Value);
MapSurface.X = Convert.ToDouble(args.Attribute("X").Value);
MapSurface.Y = Convert.ToDouble(args.Attribute("Y").Value);
CarrIEr.Children.Add(MapSurface);
}
最後按照args.Attribute(“屬性名”).Value這樣的方式,我們將從此節點中獲取的屬性值對應賦予到MapSurface相應的屬性中,從而完成了從設置配置文件到成功加載的整個流程。其他的如地圖遮罩、障礙物數組等配置的加載如出一轍,源碼中有這裡就不累述了。
這樣,我們在游戲中換地圖時只需重新加載相應代號地圖節點,然後讀取其中的地表層與遮罩層相關信息即可實現場景輕松切換。並且,如果游戲客戶端需要添加幾張新地圖,或是要對現有地圖配置進行修改,那麼我們只需更新XML文件,然後讓對方(客戶端)下載替換即可以進行版本的升級,這就是典型的面向對象的分層開發模式。
三、取其精華,去掉糟粕,讓代碼質量得到質的飛躍:
在WPF/Silverlight中,大家是否有發現一個比較古怪的情況,每個控件都有這樣兩個屬性:x:Name和Name,它們的區別到底在哪?我可以謹慎的告訴大家,其實使用起來兩者效果是一模一樣的。例如我設置x:Name=”A”,或設置Name=”A”,在Behind代碼中兩種方式均可以將”A”值識別。這可頭大了,難道MS在搞飛機?其實區別僅僅是上帝創造的先後問題,這對於絕大多數人來說毫無意義。因此我們可以將之歸納到重復屬性的范疇,其他的類似情況在WPF/Silverlight中還有很多,連帶頭老大哥都這樣龌龊,我們的開發中出現類似情況也算情有可原。所以,在重構時,我們還需要對所有的屬性進行理性的審視,是否有重復的,是否有不合理的,是否有沒用到卻還凳在那的,這些統統得回爐再造。惟有如此,才能給程序的擴展提供更便利的支持。同樣的,我以一個活生生的例子給大家講解。
是否還記得上一節中,要實現9區域的主角移動,首先得定義WindowCenterX與WindowCenterY這兩個變量,然後通過讓它倆參與到范圍判斷中從而得到主角當前所處的區域。但是大家有沒想過,如果游戲窗口尺寸是可變的,為了兼容前面實現的功能,每次窗口尺寸改變(如拖動邊緣、最大化、窗口化等)時,我們都得重新設置WindowCenterX和WindowCenterY這兩個值,不但增加了代碼量,而且毫無擴展性而言,這是相當糟糕的。因此,我使用游戲窗口現有變量:ActualWidth與ActualHeight來取代WindowCenterX與WindowCenterY,即ActualWidth /2=WindowCenterX,ActualHeight/2=WindowCenterY,然後替換掉全部其他所有調用到WindowCenterX與WindowCenterY的地方。結果是,我們不論如何調整窗體尺寸,都不需要再更改任何代碼,ActualWidth與ActualHeight就好比心有靈犀的得力助手,為您提供時時的游戲窗口實際寬度與高度。
當然,重構的方式還有很多很多,但是它們的最終目的都只有一個:讓代碼插上翅膀自由飛翔。可以這麼說,本節的代碼在保證前一節功能不變的前提下我對其進行了大幅度的代碼重構,不僅優化結構,更可貴的是將整個架構提升到極具拓展性的高度。當然,嘴上說的沒有一點價值,事實將勝於雄辯:下節我將給您演示短短十幾行代碼輕松實現WPF下窗口及其內部所有對象的任意縮放,完美比擬MMORPG中的全屏與窗口模式切換,敬請關注。