天天看點

Silverlight C# 遊戲開發:面向對象在遊戲中的執行個體(二)

本系列所有代碼都是使用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 &lt; 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 &lt;= -32)  

temp.InitializtionRole();  

if (temp.CollidedTest(Hero) &amp;&amp; !(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