C#開發WPF/Silverlight動畫及游戲系列教程(Game Tutorial):(四十四)制作主角屬性面板及加點器
游戲中會使用大量的菜單面板,而這些面板往往都帶有選項卡。如果用Silverlight工具中的TabControl,則需要通過復雜的xaml重寫模板來實現自定義樣式,這一點時常讓開發者頭疼,畢竟界面的東西應該屬於美工的范疇,這也是我所發現在目前Silverlight中唯一一處只能通過xaml而無法用代碼實現的地方。當然,如果您對此特別感興趣,同樣可以到http://www.codeplex.com/Silverlight中下載最新的開源工具源碼,其中的示例項目中有非常詳細的模板重寫案例。本節,我將通過創建用戶控件的方式來創建自定義的TabControl和RepeatButton,實現主角屬性面板及其中的屬性加點器。
首先,我創建一個QXTabControl用戶控件,該控件界面可以很簡單,只需要包含一個頭和一個身體即可:
<UserControl x:Class="QXGameEngine.Control.QXTabControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas>
<StackPanel x:Name="Head"/>
<ContentPresenter x:Name="Body"/>
</Canvas>
</UserControl>
Head 用做TabItem的容器,作為StackPanel類型控件,它可以對內部控件進行橫排或豎排,從而基本滿足大多數情況需要;而Body是ContentPresenter類型,在第四十二節中我曾提及過它,相當於一個萬用變身控件,將它作為選項卡的身體部分再合適不過了。當我們點擊不同的選項卡時,將不同的面板控件作為值賦予給Body,輕松實現高度自由的選項內容變換。
那麼用什麼控件來替代TabItem呢?在《劍俠世界》中,選項卡做得別具特色,不光在默認情況下鼠標進入與離開會呈現不同的圖片;當被點中後,同樣實現另外的兩張圖片間的切換。這樣的效果相當精致,而我們又該如何將它實現呢?此時,不得不想到我們可愛的QXIcon控件,我為它添加了新的類型:IconTypes.HitModes,定義很簡單,根據該控件是否被點擊從而對4張圖片進行相應切換:
case IconTypes.HitModes:
this.MouseEnter += (s, e) => { Container.Background = Hit ? HitNewBodySource : NewSource; };
this.MouseLeave += (s, e) => { Container.Background = Hit ? HitBodySource : _BodySource; };
this.MouseLeftButtonDown += (s, e) => { Hit = Hit ? false : true; };
break;
實現後的效果如下圖:
在QXTabControl中包含一個List<QXIcon> tabItemList = new List<QXIcon>();用於管理現有的所有選項卡;我還模仿TabControl在QXTabControl中創建SelectionChanged事件:
public delegate void SelectionChangedEventHandler(object sender, QXIcon tabItem);
public event SelectionChangedEventHandler SelectionChanged;
當某個選項卡被點擊時,觸發該事件:
……
tabItem.MouseLeftButtonDown += (sender, e) => {
foreach (QXIcon icon in tabItemList) {
if (icon == sender) {
icon.Hit = true;
icon.Container.Background = icon.HitNewBodySource;
} else {
icon.Hit = false;
icon.Container.Background = icon.BodySource;
}
}
SelectionChanged(this, sender as QXIcon);
e.Handled = true;
};
……
這樣我們就可以在游戲窗口中對已創建的選項卡控件注冊SelectionChanged事件了:
//主角屬性選項卡內容
QXTabControl tc = new QXTabControl() {
TabItemOrientation = Orientation.Horizontal,
TabItemHeight = 28,
BodyLeft = -4,
BodyTop = 27
};
//添加4個選項卡
tc.AddItem(63, 28, 1, "/Image/Icon/39.png", "/Image/Icon/40.png", "/Image/Icon/41.png", "/Image/Icon/42.png", "屬 性");
tc.AddItem(63, 28, 1, "/Image/Icon/39.png", "/Image/Icon/40.png", "/Image/Icon/41.png", "/Image/Icon/42.png", "聲 望");
tc.AddItem(63, 28, 1, "/Image/Icon/39.png", "/Image/Icon/40.png", "/Image/Icon/41.png", "/Image/Icon/42.png", "稱 號");
tc.AddItem(63, 28, 1, "/Image/Icon/39.png", "/Image/Icon/40.png", "/Image/Icon/41.png", "/Image/Icon/42.png", "榮 譽");
……
tc.SelectionChanged += (sender, item) => {
QXTabControl tabControl = sender as QXTabControl;
switch (item.Text) {
case "屬 性":
tabControl.SetBody(leaderAttributePart);
break;
case "聲 望":
tabControl.SetBody(new Canvas() {
Background = new ImageBrush() { ImageSource = Super.GetImage("/Image/Plate/RoleAttributeBack1.png") },
Width = 350,
Height = 389,
});
break;
case "稱 號":
tabControl.SetBody(new Canvas() {
Background = new ImageBrush() { ImageSource = Super.GetImage("/Image/Plate/RoleAttributeBack2.png") },
Width = 350,
Height = 389,
});
break;
default:
tabControl.SetBody(null);
break;
};
};
運行時效果:
很棒吧?嘿嘿。在角色屬性面板裡除了顯示角色的屬性值等個人資料外,還有裝備管理及屬性加點器兩個重要部分。關於裝備,後面的章節再細說。下面我向大家講講如何制作這個屬性加點器。
如果不論樣式,我們直接可以使用官方提供的NumericUpDown控件即可,該控件非常強大,看了它的源碼,其本身為一個組合控件,由4大部分組成:文本(TextBlock)、文本容器(ContentPresenter)、加按鈕(RepeatButton)及減按鈕(RepeatButton),且模式很多,你能想到的基本都有。當然同樣的,要重寫它的樣式實在是麻煩之事,其實該控件的重點就就在RepeatButton上,如何實現這個Repeat動作又是關鍵中的關鍵。我們不妨從它的原理出發,當鼠標在此按鈕上按下時開始計時,如果鼠標一直未放開,則當到達預先設定的Delay時間間隔後即觸發後面的連續重復動作,且這些動作以Interval為間隔不斷重復下去直到鼠標左鍵被放開或鼠標離開該控件。此時,我又想到了美麗的QXIcon,再次為它添加一種新模式:IconTypes.RepeatButton:
case IconTypes.RepeatButton:
DispatcherTimer timer = new DispatcherTimer();
timer.Tick += (s, e) => { timer.Interval = TimeSpan.FromMilliseconds(Interval); RepeatClick(this, e); };
this.MouseEnter += (s, e) => { Container.Background = NewSource; };
this.MouseLeave += (s, e) => { Container.Background = _BodySource; timer.Stop(); };
this.MouseLeftButtonDown += (s, e) => { timer.Interval = TimeSpan.FromMilliseconds(Delay); timer.Start(); };
this.MouseLeftButtonUp += (s, e) => { timer.Stop(); e.Handled = true; };
break;
根據前面對RepeatButton工作原理的描述,在這種模式下,我通過創建一個DispatcherTimer,當它Tick時觸發public event EventHandler RepeatClick;事件。其中配合控件自身的 MouseLeftButtonDown、MouseLeftButtonUp及MouseLeave來開停Timer及設置它的間隔。
接著,我們就可以將此控件應用到主角屬性面板中制作屬性加點器了。配合上相應邏輯,當屬性點數加完並提交後,主角的新屬性值會立即更新反映到界面中。按照第二十八節的屬性設置,主角擁有5大基本屬性,當修改這些屬性時會分別影響相關的值數據。例如,默認情況下主角的智慧為30,魔法攻擊基本傷害范圍為460-615(不包括魔法自身的攻擊力),此時用激光魔法攻擊敵人可造成約600左右傷血:
而當我將智慧加到200並點擊確定後,魔法攻擊到了3010-4015,此時攻擊敵人可以造成3500左右的傷害,很酷吧。嘿嘿:
本教程示例游戲中,我為主角賦予了1000點的潛能點,大家可以自由分配到不同的屬性上,例如增加力量屬性可以增加物理攻擊力,增加體格可以提升血上限及防御等,增加敏捷可以加快移動及施法速度等,增加幸運可以提高暴擊率等等,測試起來還是相當有趣的呢~
不過目前的屬性加點器還不能通用,畢竟不同的游戲中加點器的實現都有差異。例如有些只有加沒有減,每次點擊都會直接提交,這種處理最簡單;而有的每次加點都會直接反應到界面上,且中途如果不滿意取消後又會恢復原樣,這種模式做起來相對復雜些,需要一些臨時字段來存儲數據,只有提交後才更新到服務器。本節功能上我選擇了折中的處理方式。
游戲中的面板基本上大同小異,前面章節中的對象監視面板、雷達地圖面板、尋路地圖面板、主角屬性面板的制作基本上含蓋了大多數情況,後面的章節我將不再圍繞面板這個羅嗦的話題了,打算將重心放到裝備、物品、技能存放與拖動的實現方面,敬請關注。
本節源碼請到目錄中下載,在線演示地址:http://silverfuture.cn
出處:http://alamiye010.cnblogs.com/