C#開發WPF/Silverlight動畫及游戲系列教程(Game Tutorial):(四十三)制作游戲主菜單面板及鼠標左右鍵快捷技能欄
每款MMORPG都有一個主菜單,通常置於窗口的底部。游戲中主角大部分的設置操作都從這裡開啟。如人物屬性、物品(包裹)、技能、任務、隊伍、地圖、家族、門派、商城、系統設置等等;當然,還包括快捷自定義菜單欄,以及類似《暗黑破壞神》中經典式的左右鍵快捷技能欄。這些內容在不同的游戲中往往會根據自身的特性稍做調整,但整體上大同小異。本節,我將同樣以《劍俠世界》的游戲主界面為例,向家講解如何在Silverlight中制作一個精美的主菜單面板及鼠標左右鍵快捷技能欄。
首先,我們需要整出一張主界面的框架素材:
在《劍俠世界》中,該面板從左至右分別是鍵盤快捷菜單,鼠標左右鍵快捷菜單及游戲主菜單,那麼我首先從右邊的主菜單說起。大家可以看到該界面中已經被镂空的部分,這些地方是用來填充相應的菜單按鈕的。如果單純的只是用一張圖片來填充,游戲的精致程度將大打折扣;大家回想一下網頁中的導航菜單欄,當鼠標進入時它會通過Css或Js變換樣式,從而達到突出美化的效果。我們游戲中同樣可以采用類似的方案,即當鼠標進入主菜單按鈕時,菜單按鈕的圖片由原先的灰暗切換成明亮,例如:
這是通過兩張圖片相互切換來實現的按鈕突出效果;但在實際開發中,特別是Silverlight這樣基於素材時時下載的游戲中,我們需要盡量減少素材資源的數量與容量,因此我特別推薦使用透明高亮遮罩來實現按鈕的突出,例如:
當鼠標進入按鈕時,我們可以添加一個圖標蒙板並使之重疊於按鈕圖標圖片上方,從而同樣可以達到高亮突出按鈕的效果;不僅如此,通常一款游戲中所有的物品圖標和技能圖標尺寸是統一的,通過此方式,我們只需一張圖標蒙板就能達到所有圖標的高亮顯示,既大幅節約了素材資源空間,同時也達到了美化效果,一舉兩得。~嘿嘿
需求都清晰了,該用什麼控件來實現呢?當然是QXIcon,不過這次我們得對它進行一些改造,使之目前至少能兼容3種情況:
public enum IconTypes {
/// <summary>
/// 無
/// </summary>
None = 0,
/// <summary>
/// 變換突出
/// </summary>
Transform = 1,
/// <summary>
/// 高亮突出
/// </summary>
Highlights = 2,
}
QXIcon的主要構造如下:
/// <summary>
/// 圖標控件
/// </summary>
public QXIcon(IconTypes iconTypes) {
InitializeComponent();
switch (iconTypes) {
case IconTypes.Transform:
this.MouseEnter += delegate { Container.Background = NewSource; };
this.MouseLeave += delegate { Container.Background = _BodySource; };
break;
case IconTypes.Highlights:
Rectangle mask = new Rectangle() { Visibility = Visibility.Collapsed };
Container.Children.Add(mask);
this.MouseEnter += delegate {
mask.Width = this.Width;
mask.Height = this.Height;
mask.Fill = NewSource;
mask.Visibility = Visibility.Visible; };
this.MouseLeave += delegate { mask.Visibility = Visibility.Collapsed; };
break;
}
}
Brush _BodySource;
/// <summary>
/// 獲取或設置圖標筆刷
/// </summary>
public Brush BodySource {
get { return _BodySource; }
set { Container.Background = _BodySource = value; }
}
/// <summary>
/// 獲取或設置變換後(或蒙板)筆刷
/// </summary>
public Brush NewSource { get; set; }
默認情況下,即參數為IconTypes.None時,該圖標控件僅僅是一個帶Toolkit的普通圖標;當參數為IconTypes.Transform時,圖標控件中的圖片會根據鼠標進入與離開分別在NewSource和_BodySource之間切換,即前文中提到的第一種情況;而當參數為IconTypes.Highlights時,效果即上敘第二種情況,通過圖標蒙板來實現圖標的高亮突出。
同時,我也對該QXIcon的Toolkit進行了改造,使之更加新穎別致:
<ToolTipService.ToolTip>
<ToolTip>
<ToolTip.Template>
<ControlTemplate>
<ContentPresenter Content="{TemplateBinding Content}"/>
</ControlTemplate>
</ToolTip.Template>
<ToolTip.Content>
<Canvas x:Name="Dialog"> <Rectangle x:Name="DialogBack" Fill="Black" RadiusX="7" RadiusY="7" Stroke="Gray" StrokeThickness="2" Opacity="0.4" />
<TextBlock x:Name="Details" Foreground="Snow" TextWrapping="Wrap" Width="150" Canvas.Left="5" Canvas.Top="5" />
</Canvas>
</ToolTip.Content>
</ToolTip>
</ToolTipService.ToolTip>
當提示文字發生變化時,它的背景將根據文字的長度與寬度自適應尺寸,且此背景為一個透明度40%的黑色圓角矩形,很漂亮的哦~:
/// <summary>
/// 獲取或設置圖標懸停提示
/// </summary>
public string Tip {
get { return Details.Text; }
set {
Details.Text = value;
DialogBack.Width = Details.ActualWidth + 10;
DialogBack.Height = Details.ActualHeight + 10;
}
}
最終效果如下:
接下來我們還是利用QXIcon來實現鼠標左右鍵快捷技能欄,這裡我定義左鍵只負責主角的跑動、對象選中及主角的物理攻擊,前面章節中已經全部實現了。而右鍵則負責施放魔法,此方案應該算是Silverlight的極限了。需求就是當我們在右鍵快捷按鈕圖標上點擊時,會像《暗黑破壞神》一樣,彈出主角已學會(可用)的所有法術和技能。在Silverlight中,我們可以用微軟開源工具包中WrapPanel輕松將之實現。WrapPanel是一個可以實現內部控件排列超出限定寬度後自動換行的容器,繼承自Panel,和Canvas等容器控件屬同一等級,大家可以到http://www.codeplex.com/Silverlight下載最新的版本。本教程示例游戲中,我直接引用它的dll,除它外,該dll還包含其他的一些控件,一方面由於時間有限,我暫時不去單獨分離了;另一方面,後期制作中很有可能還會用到其中的某些控件,因此先讓它這樣吧~,還挺大的呢(112K)。
如果是網絡游戲,那麼在主角初始化後,我們將從服務器接收到主角的數據,當然包括主角已經掌握的魔法技能,這裡我用一個Magic類來表示:
public class Magic {
/// <summary>
/// 代號
/// </summary>
public int Code { get; set; }
/// <summary>
/// 等級
/// </summary>
public int Level { get; set; }
/// <summary>
/// 名稱
/// </summary>
public string Name { get; set; }
}
暫時先就這幾個參數吧,接下來定義一個主角可用魔法列表List<Magic> availableMagic = new List<Magic>();這裡我假設主角已經掌握了代號為0-5的6種魔法,且每種都到了9級,那麼我將這6種魔法按如下方式加入到availableMagic表中:
//初始化主角可用的所有魔法
availableMagic.Clear();
for (int i = 0; i < 6; i++) {
availableMagic.Add(new Magic() {
Code = i,
Level = 9,
Name = string.Format("名稱:{0}\r\n描述:{1}",
Super.GetXElement(Data.Settings["Arguments"], "Magic",
"Code", i.ToString()).Attribute("Name").Value,
Super.GetXElement(Data.Settings["Arguments"], "Magic", "Code",i.ToString()).Attribute("Description").Value) });
}
當鼠標在右鍵快捷按鈕圖標上點擊時,我將availableMagic中的所有對象以圖標的形式添加進名為rightButtonMagicList的WrapPanel中,由於此Demo中圖標的寬高均為27像素,因此我約束rightButtonMagicList寬為270,即一行如果超過10個圖標則自動換行。最後為它賦予相應的事件,當點中某個魔法技能,主角當前的右鍵默認魔法更改為此魔法,且右鍵快捷按鈕圖標的魔法也換成它:
……
//右鍵魔法選擇
rightButtonMagicIcon.MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs e) {
if (rightButtonMagicList == null) {
rightButtonMagicList = new WrapPanel() {
Orientation = Orientation.Horizontal,
Width = 270, //一行放10個圖標,每個27寬};
foreach (Magic magic in availableMagic) {
QXIcon magicIcon = new QXIcon(IconTypes.Highlights) {
BodySource = new ImageBrush() { ImageSource = Super.GetImage(string.Format("/Image/Magic/{0}/0.png", magic.Code)) },
NewSource = new ImageBrush() { ImageSource = Super.GetImage("/Image/Icon/34.png") },
Width = 27,
Height = 27,
Tip = magic.Name,
Tag = magic,
};
magicIcon.MouseLeftButtonDown += delegate(object ss, MouseButtonEventArgs ee) {
QXIcon icon = ss as QXIcon;
Magic m = icon.Tag as Magic;
rightButtonMagicIcon.BodySource = icon.BodySource;
rightButtonMagicIcon.Tip = m.Name;
Leader.CurrentMagic.Code = m.Code;
Leader.CurrentMagic.Level = m.Level;
rightButtonMagicList.Visibility = Visibility.Collapsed;
ee.Handled = true; };
rightButtonMagicList.Children.Add(magicIcon);
}
BottomMenu.Children.Add(rightButtonMagicList);
Canvas.SetLeft(rightButtonMagicList, 437); Canvas.SetTop(rightButtonMagicList, -Math.Ceiling(rightButtonMagicList.Children.Count / (rightButtonMagicList.Width / 27)) * 27);
} else {
if (rightButtonMagicList.Visibility == Visibility.Collapsed) {
rightButtonMagicList.Visibility = Visibility.Visible;
Canvas.SetTop(rightButtonMagicList, -rightButtonMagicList.ActualHeight);
} else {
rightButtonMagicList.Visibility = Visibility.Collapsed;
}
}
e.Handled = true;
……
具體邏輯大家仔細看就明白了~還算比較簡單的。實際效果如下:
另外的,大家不妨自行修改一下循環代碼,多加幾個魔法上去體驗一下WrapPanel的強大:
游戲主界面菜單已初具雛形,接下來的任務就是去完善它的各面板及相應功能~敬請關注。
源碼請到目錄中下載,在線演示地址:http://silverfuture.cn
出處:http://alamiye010.cnblogs.com/