程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
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):(四十二)制作精美的Mini地圖②

前面章節中講解的包括對象頭像面板、Mini雷達地圖等窗體都是位置固定的,在處理起來方式多樣且簡單;而RPG、SLG、休閒養成等類型的游戲中往往會大量使用到懸浮且可自由拖動的窗體,比如包裹面板、武器裝備面板、個人屬性面板、技能面板、系統設置面板等等,這就要求我們必須為游戲量身定做一個通用且易用的ChildWindow控件。那麼本節我將為大家講解如何制作一個包含可拖動頭部、關閉按鈕及內容主體3大部件高自由度的自定義ChildWindow控件,並用它來實現Mini尋路地圖。

首先,我們需要確定該ChildWindow的功能需求,從布局上說包含上述3大部分,且這3部分都是可以用任意對象來實現的,這樣才能實現高度拓展;從功能上說,ChildWindow可在游戲窗口中任意拖動,且多個ChildWindow實例之間同樣存在一個可協調的層次關系,這方面內容大家可以參考我關於ChildWindow的另一篇文章;從整體結構上說,ChildWindow即可以與游戲中與對象輕松交互,同時也不能影響到游戲中其它對象的活動。

那麼接下來進入實質性設計階段,此時我們有3條路可以選擇:

1)通過底層的繼承來實現。例如新建一個BaseWindow.cs類文件,然後讓之繼承Control或ContentControl或UserControl等均可,並通過代碼添加並布局好各部分控件,同時實現各部分應有的功能事件,最後讓this.Content=總的布局控件或其它方式來完成基類的定義。那麼其他的控件就可以通過繼承此BaseWindow,在擁有所有BaseWindow功能的基礎上再拓展出各自控件自身的特定功能。總的來說這是傳統的方案,但是在WPF/Silverlight中易用性不強,因為有著xaml這一層東西在;且目前大多數的開發者都不一定具備底層控件開發的技術與經驗,實現起來難度較大。

2)通過Silverlight模板控件來實現。國外很多Silverlight開發者都比較喜歡使用此方式進行控件開發。具體步驟:在項目上右鍵->添加->新建項->Silverlight模板化控件:

新建好後,大家可以看到的項目結構中出現了一個Themes文件夾,且裡面包含著一個名為Generic.xaml的模板文件,主體代碼如下:

<Style TargetType="local:QXChildWindow">
 <Setter Property="Template">
  <Setter.Value>
   <ControlTemplate TargetType="local:QXChildWindow">
     ……模板內容……
   </ControlTemplate>
  </Setter.Value>
 </Setter>
</Style>

以後如果還有新的模板添加進項目,那麼所有模板的xaml部分均會以如上格式追加到此文件中,只是它們綁定的TargetType不同(cs文件不同)罷了:

當我們打開QXChildWindow.cs文件可以看到,此QXChildWindow模板控件繼承自Control,且通過this.DefaultStyleKey = typeof(QXChildWindow);這句話來實現與Generic.xaml中的模板界面對接。既然是非partial文件,因此其拓展起來還是很方便的。我也曾嘗試使用此方法來實現ChildWindow,功能是有了,但過程很是別扭,例如模板中對中文的支持不好;重載OnApplyTemplate()方法中的base.OnApplyTemplate()在控件加載中並不靈活等等,個人感覺從拓展度及開發難度上說效果並非最理想。

3)通過用戶控件來實現。Silverlight中的用戶控件大家應該再熟悉不過了,此時肯定會有朋友質疑它是否真的如此萬能?連ChildWindow也可以實現嗎?其實用戶控件本身繼承自UserControl,既然是面向對象的,又為何不能呢?下面是我寫的QXChildWindow界面部分代碼:

<UserControl x:Class="QXGameEngine.Control.QXChildWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" MouseLeftButtonDown="UserControl_MouseLeftButtonDown">
<Canvas>
  <Canvas x:Name="Head" MouseLeftButtonUp="Head_MouseLeftButtonUp" MouseMove="Head_MouseMove">
   <ContentPresenter x:Name="HeadPresenter" />
   <Rectangle x:Name="CloseButton">
    <ToolTipService.ToolTip>
     <TextBlock x:Name="Tip" Text="關閉" />
    </ToolTipService.ToolTip>
   </Rectangle>
  </Canvas>
  <Canvas x:Name="Body">
   <ContentPresenter x:Name="BodyPresenter" />
  </Canvas>
 </Canvas>
</UserControl>

整個xaml就是如此簡單,但是卻蘊涵著高度的靈活性,此話怎講?不妨先看下面這張結構描述圖:

以頭部Head為例,它是Canvas類型,因此我們可以將它的Background設置為任意Brush對象,如漸變顏色、圖片、乃至視頻;並且它內部還包含著一個名為HeadPresenter 的ContentPresenter,這又是何方神聖?我們可以在後台代碼中通過HeadPresenter=object來實現對其完全的重新定義,這意味著HeadPresenter可以是任何東西,比如矩形啦、圖片啦、畫布啦、甚至新的用戶控件,甚至再來個QXChildWindow實例,嘿嘿(當然,這麼做是沒意義的)。且由於HeadPresenter在Canvas畫布中,因此對它的布局也是完全自由的。Body部分則是同樣的道理,不累述了。接下來定義好對這些對象進行賦值的CLR屬性,並通過路由的MouseLeftButtonDown、MouseLeftButtonUp、MouseMove事件分別實現ChildWindow應該有的功能,最終就完成了這個QXChildWindow控件的制作

如果您到此還不能完全感受到它的強大與靈活?那麼接下來我將使用該控件實例出一個mini尋路地圖,讓大家近距離接觸這個牛氣烘烘的新家伙。

創建過程是很簡單的,只需為游戲窗體注冊一個鍵盤敲下事件,通過設置激發的按鈕或按鈕組合來顯示窗口:

//鍵盤按下事件
private void UserControl_KeyDown(object sender, KeyEventArgs e) {
 //顯示尋路地圖(組合按住Ctrl再+Tab)
 if (e.Key == Key.Tab) {
  if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) {
   ……
  }
 }
}

這裡我用的是Ctrl+Tab鍵,目前Silverlight3.0版本中鍵盤處理還不算完善,4.0中將實現所有的鍵位。接下來我們通過賦予一個QXChildWindow實例相應的參數,如頭部寬、高、背景圖片,身體寬、高、背景圖片等等,並將之添加進Root中。到此,一個Mini地圖尋路面板就完成了:

//初始化尋路地圖
wayfindingWindow = new QXChildWindow() {
 Left = 105,
 Top = 40,
 HeadLeft = 0,
 HeadTop = 0,
 HeadWidth = 604,
 HeadHeight = 37,
 HeadBackground = new ImageBrush() { ImageSource = Super.GetImage("/Image/Plate/WayfindingMapHead.png") },
 BodyLeft = 0,
 BodyTop = 37,
 BodyWidth = 604,
 BodyHeight = 479,
 BodyBackground = new ImageBrush() { ImageSource = Super.GetImage("/Image/Plate/WayfindingMapBody.png") },
 CloseButtonLeft = 582,
 CloseButtonTop = 0,
 CloseButtonWidth = 22,
 CloseButtonHeight = 22,
 CloseButtonFill = new ImageBrush() { ImageSource = Super.GetImage("/Image/Icon/11.png") },
};
 Root.Children.Add(wayfindingWindow);

簡約且簡單~這才是我們開發的目的。而其面板中的其他一些內容,如地圖名稱(Grid),地圖畫板(Canvas)等則可以很輕松的分別通過前文提到的HeadPresenter和BodyPresenter來實現,具體代碼就不列出來了,大家可以到源碼中查看。

在該Mini尋路地圖中,主角位置的刷新是在間隔為500毫秒的後台線程中進行,與Mini雷達地圖一樣的道理,只有在自身為顯示的前提下才會更新,這樣不用時將節約出大量性能。

另外關於此Mini尋路地圖中的一些小細節,其中的主角位置圖標為一張默認朝北的三角圖片,當主角朝向改變時,我通過Angle = Leader.Direction * 45來旋轉它從而使之與主角實際的朝向吻合;另外,我在主角位置圖標與尋路地圖中點擊的點之間添加了一條釣魚連接線,模仿《劍俠世界》的啦,嘿嘿。該線可以方便玩家把握自身與目標之間的距離並監視目標點。

寫了很多了~不知道大家是否能全部掌握?最後我們運行一下,在游戲中按下Ctrl+Tab來看看勞動成果吧:

當前由於Silverlight自身渲染方式的原因,在MouseMove中實現拖動對象性能並非最好,同時更讓人感到奇怪的是它與MouseDown、MouseUp同為路由事件,可是卻無法實現e.Handled,導致游戲中的命中測試會穿越面上的ChildWindow層,希望4.0或未來的版本能將之做得更好~加油!

源碼請到目錄中下載,在線演示地址:http://silverfuture.cn

出處:http://alamiye010.cnblogs.com

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