程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#開發WPF/Silverlight動畫及游戲系列教程(Game Tutorial):(四十三)

C#開發WPF/Silverlight動畫及游戲系列教程(Game Tutorial):(四十三)

編輯:關於C#

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/

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved