本系列所有代碼都是使用Microsoft Visual Studio 2008開發,為基于Silverlight的遊戲開發技術,如果您看完之後覺得不錯,回複頂一下,萬分感激:)
是否還記得,這個系列中的《Flyer》小遊戲,那個系列為了更好的介紹Silverlight的基礎知識沒有使用面向對象方法,所有的對象都是獨立程式設計,是以我們發現所有的基礎對象都有這麼一段代碼。
public double Speed = 4;
public double X
{
get { return Canvas.GetLeft(this); }
set { Canvas.SetLeft(this, value); }
}
public double Y
get { return Canvas.GetTop(this); }
set { Canvas.SetTop(this, value); }
public Rect MyRect
get
return new Rect(X, Y, _rectangle.Width, _rectangle.Height);
恐怕非常的不爽,先不說維護起來麻煩,就是來回的複制粘貼也夠費勁的,以後要是增加了各種各樣的物體,這個工作就夠手疼的,但是我們在面向對象的面前就省去了很多力氣,然而……這個世界沒有公平的事情,手不疼了,腦袋就要疼了,嘿嘿,具體為什麼,下面就知道。
我們的目的是,用面向對象實作之前《Flyer》的功能,為了更好的說明,這個遊戲就不寫太多的邏輯代碼,有興趣的朋友自行研究:)
建立工程……(請參閱其他文章)
為了更加友善快速的完成,這次我們用上Blend,請參照下圖設定:
然後加入之前的圖檔,這次的圖檔沒有做動畫,一切從簡,否則複雜的代碼不利于大家讀代碼。
這個時候,我們開始研究如何創造類的結構,使用面向對象的方法來完成這個項目,這需要程式設計人員的經驗以及基礎的共同作用,是以,在寫之前先要想好,經過思考,我們發現很多可以抽象出來的東西,咱們畫了一個類結構圖:
類從Canvas繼承,完成所有的圖形方面的事情,并且将坐标XY直覺化,提供初始化接口。
ClassActivityRole類更加進階了一點,它可以做一些行為,提供檢測還有移動等方法。
ClassSolid類是不需要操作的物體集合。
ClassFlyer與ClassSolid有本質的不同,ClassSolid隻需要向上移動就行,但是Flyer卻不行,它需要鍵盤的控制,是以,作為ClassSolid的子類不合适,是以我們将ClassActivityRole作為父類。
ClassCloud 、ClassFood、、ClassScrew從ClassSolid繼承獲得了有用的部分,而且告訴大家,我是一個Solid,但是他們之間不同的是三種完全不同的作用,Cloud什麼都不做隻是向上飄,Food在碰撞的時候會加血,Screw則是損血,這是完全不同的三種邏輯,這個部分和上一個篇裡打怪物的情況幾乎一樣,是以可以使用同一的碰撞邏輯(這部分的代碼未實作,如要請參考其他篇)
public class ClassBaseRole : Canvas
public Image ResImage = new Image();
public ClassBaseRole()
this.Children.Add(ResImage);
InitializtionRole();
public virtual void InitializtionRole()
/// <summary>
/// 移動速度
/// </summary>
public double Speed = 1;
/// 修改或擷取X坐标
/// 修改或擷取Y坐标
public class ClassActivityRole : ClassBaseRole
public ClassActivityRole()
MyRectangle = new Rectangle() { Width = 32, Height = 32, Stroke = new SolidColorBrush(Colors.Red) };
this.Children.Add(MyRectangle);
}
protected Rectangle MyRectangle;
/// 取得自身的碰撞區域
get
return new Rect(X, Y, MyRectangle.Width, MyRectangle.Height);
/// 碰撞測試
/// <param name="objective">目标物體</param>
/// <returns></returns>
public bool CollidedTest(ClassActivityRole objective)
Rect rt = objective.MyRect;
rt.Intersect(this.MyRect);
if (!double.IsInfinity(rt.Height) && !double.IsInfinity(rt.Width))
return true;
else
return false;
public virtual void DownWard()
Y += base.Speed;
public virtual void UpWard()
Y -= base.Speed;
public virtual void RightWard()
X += base.Speed;
public virtual void LeftWard()
X -= base.Speed;
public virtual void LoopLogic()
後面還有更多,在這裡不一一列舉,直接看效果:
另外,我們可以最後的完成的檔案情況:
<a target="_blank" href="http://blog.51cto.com/attachment/201111/160026646.jpg"></a>
寫的類很少,并且去掉了這個Group那個Group,并且每個類的代碼很少,沒有超過50行,最少的就5行代碼,這是為什麼呢,因為我們用了面向對象,現在将首頁面寫成這樣:
public partial class MainPage : UserControl
public static Random random = new Random((int)DateTime.Now.Ticks);
public static double ScreenWidth = 400;
public static double ScreenHeight = 400;
public ClassFlyer Hero = new ClassFlyer();
public MainPage()
InitializeComponent();
for (int i = 0; i < 20; i++)
Sky.Children.Add(new ClassCloud());
Sky.Children.Add(new ClassFood());
Sky.Children.Add(new ClassScrew());
Sky.Children.Add(Hero);
DispatcherTimer GameLoop = new DispatcherTimer();
GameLoop.Interval = TimeSpan.FromMilliseconds(40);
GameLoop.Tick += new EventHandler(GameLoop_Tick);
GameLoop.Start();
base.KeyDown += new KeyEventHandler(MainPage_KeyDown);
base.KeyUp += new KeyEventHandler(MainPage_KeyUp);
void MainPage_KeyUp(object sender, KeyEventArgs e)
Hero.FylerState = EmFlyerState.正常;
void MainPage_KeyDown(object sender, KeyEventArgs e)
switch (e.Key)
case Key.Up:
Hero.FylerState = EmFlyerState.向上;
break;
case Key.Down:
Hero.FylerState = EmFlyerState.向下;
case Key.Left:
Hero.FylerState = EmFlyerState.向左;
case Key.Right:
Hero.FylerState = EmFlyerState.向右;
void GameLoop_Tick(object sender, EventArgs e)
{
foreach (var item in Sky.Children)
if (item is ClassActivityRole)
ClassActivityRole temp = (item as ClassActivityRole);
temp.LoopLogic();
if (temp.Y <= -32)
temp.InitializtionRole();
if (temp.CollidedTest(Hero) && !(temp is ClassCloud))
綜述,我們從這個例子中,可以看到有關于多重的類别對象在整體管理時候的應用,在做整體的遊戲管理時候,隻需要調用基本對象,基本類的方法會直接調用繼承下來的類,比如說LoopLogic,對于不同的對象Solid、Flyer、Cloud、Food處理不同的邏輯,在CollidedTest中更加明顯,隻需要傳入基類即可,不需要做單獨的判定條件。
本代碼中沒有做損血和加血,主要是為了更加直覺,損血和加血隻需要寫在碰撞檢測裡就可以,也不需要做太多的代碼,甚至碰撞檢測可以寫在自身的邏輯中,而不需要每次都調用疊代器做判定
它在實際開發中非常重要,它能很好的簡化代碼,讓結構更加清晰,而且修改起來非常容易,即便是增加功能也是非常簡單的事情,比如我們搞一個橫着飛的火球,隻需要簡單繼承,修改一下飛行軌迹即可,可能在其他方面的應用更加廣泛和舒适,歡迎共同探讨,各位高手可能有更加面向對象的例子,我也想好好學習啊:)
ClassBaseRole
<a target="_blank" href="http://blog.51cto.com/attachment/201111/160222105.jpg"></a>
本文轉自nowpaper 51CTO部落格,原文連結:http://blog.51cto.com/nowpaper/712577