C#開發WPF/Silverlight動畫及游戲系列教程(Game Course):(十四) 精靈控件橫空出世!①
在上一節中,我們實現了地圖牽引式移動,同時還遺留著一個小尾巴:主角和障礙物該如何跟隨著地圖的移動而移動?
上節中有點到,只要在地圖移動的同時,時時根據主角等對象物體的X,Y坐標進行相對於地圖的X,Y坐標移動即可達到目的。但是由此又引來了新問題:主角為Image控件,障礙物則為矩形控件,它們都沒有X,Y這兩個屬性,我們該如何對它們的坐標進行記錄呢?
最簡單且最直接的方法莫過於將它們的X,Y坐標通過分隔符連接然後記錄進Tag屬性中,在調用的時候再將它分離取出。例如我們可以在構建障礙物的時候這樣做:
//構建障礙物(本節只為演示,隨便建一個)
for (int y = 11; y <= 14; y++) {
for (int x = 31; x <= 40; x++) {
//障礙物在矩陣中用0表示
Matrix[x, y] = 0;
rect = new Rectangle();
//目前暫時不新創一個自定義控件,而把坐標儲存在Tag屬性中
rect.Tag = x + "," + y;
……
}
}
其中上圖中黃色的代碼即為將障礙物的X,Y坐標記錄進它的Tag屬性,然後我們可以通過下面的函數在需要的時候對Tag屬性進行分離調用:
//從矩形障礙物的Tag屬性中分離出它的坐標Point
private Point getPointFromTag(object tag) {
string[] str = tag.ToString().Split(new char[] { ',' });
return new Point(Convert.ToDouble(str[0]), Convert.ToDouble(str[1]));
}
但是,這樣做的效率是極其低下的;更主要的是它毫無擴展性可言。障礙物還好對付,如果是主角呢?它不光有X,Y兩個屬性,還有名字、門派、血條、藍條、金木水火土、力量、智慧……、線程參數、方向、裝備代號等等等等(暈了。。。列不完的),太多太多的五花八門的屬性,難不成全都要記錄進這一個Tag屬性中?將霸王龍關進籠子裡這是件很可怕的事情,裝也難,取也難!兩個字:恐怖。
讀者聲音:老大,那該怎麼辦?搞不定難道還要上吊呀?
作者:安啦,急什麼?下面才是重點。可要認真看呀,超大一個精華!!!
如果有做過游戲開發的朋友,或者說有了解過游戲開發相關內容的朋友一定會發現,游戲中除了地圖引擎外,最關鍵的莫過於精靈的創建。精靈是游戲中大家見得最多的對象物體,它可以是主角,可以是其他玩家,可以是NPC,可以是怪物及BOSS,甚至可以是坐騎、障礙物等等。很多初學的朋友往往在為如何使用外國人制作好的通用精靈而發愁(畢竟繁雜的英文專業術語及超量的對象屬性及方法是大多數人無法輕易弄通的)。幸運的是,在WPF/Silverlight中我們可以找到強大且使用簡單的相關支持,它就是下文中我將詳細講解的傳說中的精靈控件!
我們首先來看看如何在WPF/Silverlight中創建一個精靈控件。第一步要做的是在項目中添加一個文件夾(取名Controls)來歸類保存它,接下來在該文件夾上點右鍵添加一個用戶控件(取名叫QXSpirit.xaml,嘿嘿,當然其他名字都可啦,高興就好),如下圖。
准備工作完成啦,第二步就是去豐富這個控件,多多給它加內容,讓它強大起來。那麼我們雙擊QXSpirit.xaml,窗口中顯示的就是它的界面了,暫時是一片空白的,我們首要添加的當然就是迫不及待想要出世的角色了,所以我們這樣寫:
<UserControl x:Class="WPFGameCourse.Controls.QXSpirit"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml xmlns:QXControl="clr-namespace:QX.Game.Controls;assembly=QX">
<Canvas x:Name="Spirit">
<Image x:Name="Body" Width="150" Height="150"/>
<StackPanel Name="Describtion" Width="150" Height="58" Canvas.Top="-21">
<!--門派-->
<QXControl:BorderText x:Name="Faction" Fill="Orchid" FontSize="12" Bold="True" Stroke="Black" StrokeThickness="0.1" Text="娥眉大師姐" Height="13" HorizontalAlignment="Center" />
<!--家族-->
<QXControl:BorderText x:Name="Clan" Fill="DarkOrange" FontSize="12" Bold="True" Stroke="Black" StrokeThickness="0.1" Text="破天一劍" Height="13" HorizontalAlignment="Center" />
<!--名字-->
<QXControl:BorderText x:Name="Name" Fill="SteelBlue" FontSize="12" Bold="True" Stroke="Black" StrokeThickness="0.1" Text="愛在後院前" Height="13" HorizontalAlignment="Center" />
</StackPanel>
</Canvas>
</UserControl>
代碼很簡單,我先定義一個名為Spirit的Canvas主布局控件(為了方便自由定位它內部的其他子控件,所以在選擇上我依然使用我鐘愛的Canvas。當然,你也可以使用別的布局控件作為主控件)。然後在它的內部建立一個名為Body的Image子控件,它就是精靈的身體啦(也就是我們前面章節中一直使用著的Image Spirit=new Image())。游戲中的精靈不光只有身體部分,還包括關於它的很多附加信息顯示在周圍:例如名字、幫派、家族等等。在上面代碼中,我將這3個描述精靈身份的文字控件放在一個名為Describtion,類型為StackPanel的布局控件(該布局控件特點為可以輕松的排列子控件)中並且稍微調整一下它的位置以便在角色身體上方合適的位置顯示(Canvas.Top="-21")。而這3個描述身份的文字控件均為我事先寫好的帶描邊的名為BorderText的控件,該控件同樣編譯封裝在項目源碼中的Dll文件夾中的QX.dll中。在WPF/Silverlight中要引用程序集中的控件,必須在xaml開頭申明它。因此,我們需要在UserControl中寫這樣一句申明:xmlns:QXControl="clr-namespace:QX.Game.Controls;assembly=QX",其中QXControl為下文中引用該控件時需要申明的前綴名稱,clr-namespace和assembly這兩個詞應該不用再解釋了吧,會編程的人都應該知道。需要特別說明的是:這麼幾個字,用TextBlock或Label現成的控件不就行了,何必要勞師動眾那麼誇張自己去寫個控件來實現?對WPF/Silverlight中的中文字有一定了解的朋友都知道,在WPF/Silverlight中,文字都是矢量的,它在顯示時被處理過(仿佛像是Photoshop中的文字銳利效果),因此顯得模糊不清。例如假設我將本例的3個描述身份控件全用TextBlock來替換,那麼效果將如下圖:
我們可以很清晰的看到,在位圖中12像素的字是不會顯示成這樣的;但是在WPF/Silverlight中,它的效果看上去是帶模糊。而我在QXControl:BorderText控件中添加了一個Stroke屬性和一個StrokeThickness屬性,它們分別用來設置文字的描邊線顏色和描邊線粗細。並且StrokeThickness是double型,這樣我就可以以任意想要的粗細對文字描邊進行設置了。在上文代碼中,我將之設置為0.1,這樣顯示出來的效果如下圖:
雖然還無法達到最好的效果,但比起普通無描邊的文字來說會美化些。由於文字只有12像素大小,在它上面描邊無法很清晰的顯示。因為,為了讓大家更好理解WPF/Silverlight中TextBlock和QXControl:BorderText文字效果區別,我分別在這兩個控件中輸入“深藍色”3個字,48像素,其中QXControl:BorderText以黑色1.5像素描邊(該控件默認字體為“微軟雅黑”),得到以下效果比較圖:
左邊為<TextBlock FontSize="48" FontFamily="微軟雅黑" Text="深藍色" Foreground="Pink" />創建的,
右邊為<QXControl:BorderText FontSize="48" Stroke="Black" StrokeThickness="1.5" Text="深藍色" Fill="Pink" />創建的,不用我說大家都會明白誰更幽雅漂亮了吧?更可貴的是,它提供了另一種WPF/Silverlight中關於中文字體模糊的解決方案。因此,在後面的游戲設計中,我將以QXControl:BorderText作為主要的文字控件使用。
呼呼,到此終於將我們可愛的精靈控件界面xaml代碼寫完,剩下的就是在Behind代碼中豐富精靈的內部了。在下一節中,我將就精靈控件後台代碼及上一節中遺留的問題:在地圖移動中,主角(精靈)與障礙物如何跟隨移動進行講解,敬請關注。