Silverlight C# 游戏开发:面向对象在游戏中的实例(二)

简介:

本系列所有代码都是使用Microsoft Visual Studio 2008开发,为基于Silverlight的游戏开发技术,如果您看完之后觉得不错,回复顶一下,万分感激:)

在上一次,介绍了面向对象在怪物上的应用,比较简单的代码完成了多重怪物的不同逻辑,然而并不是非常明显的使用了面向对象,因为数量较小,这次我们搞一个对象数目繁多的应用,来证明面向对象在游戏开发中是多么的好用。还是老规矩,仍然提供一个实例。代码在这里下载

是否还记得,这个系列中的《Flyer》小游戏,那个系列为了更好的介绍Silverlight的基础知识没有使用面向对象方法,所有的对象都是独立编程,因此我们发现所有的基础对象都有这么一段代码。

 
  1. public double Speed = 4;  
  2.  
  3. public double X  
  4.  
  5. {  
  6.  
  7. get { return Canvas.GetLeft(this); }  
  8.  
  9. set { Canvas.SetLeft(this, value); }  
  10.  
  11. }  
  12.  
  13. public double Y  
  14.  
  15. {  
  16.  
  17. get { return Canvas.GetTop(this); }  
  18.  
  19. set { Canvas.SetTop(this, value); }  
  20.  
  21. }  
  22.  
  23. public Rect MyRect  
  24.  
  25. {  
  26.  
  27. get   
  28.  
  29. {  
  30.  
  31. return new Rect(X, Y, _rectangle.Width, _rectangle.Height);  
  32.  
  33. }  
  34.  
  35. }  


恐怕非常的不爽,先不说维护起来麻烦,就是来回的复制粘贴也够费劲的,以后要是增加了各种各样的物体,这个工作就够手疼的,但是我们在面向对象的面前就省去了很多力气,然而……这个世界没有公平的事情,手不疼了,脑袋就要疼了,嘿嘿,具体为什么,下面就知道。

我们的目的是,用面向对象实现之前《Flyer》的功能,为了更好的说明,这个游戏就不写太多的逻辑代码,有兴趣的朋友自行研究:)

建立工程……(请参阅其他文章)

为了更加方便快速的完成,这次我们用上Blend,请参照下图设置:

然后加入之前的图片,这次的图片没有做动画,一切从简,否则复杂的代码不利于大家读代码。

这个时候,我们开始研究如何创造类的结构,使用面向对象的方法来完成这个项目,这需要编程人员的经验以及基础的共同作用,所以,在写之前先要想好,经过思考,我们发现很多可以抽象出来的东西,咱们画了一个类结构图:



类从Canvas继承,完成所有的图形方面的事情,并且将坐标XY直观化,提供初始化接口。

ClassActivityRole
类更加高级了一点,它可以做一些行为,提供检测还有移动等方法。

ClassSolid
类是不需要操作的物体集合。

ClassFlyer
ClassSolid有本质的不同,ClassSolid只需要向上移动就行,但是Flyer却不行,它需要键盘的控制,所以,作为ClassSolid的子类不合适,所以我们将ClassActivityRole作为父类。

ClassCloud 
ClassFood、、ClassScrewClassSolid继承获得了有用的部分,而且告诉大家,我是一个Solid,但是他们之间不同的是三种完全不同的作用,Cloud什么都不做只是向上飘,Food在碰撞的时候会加血,Screw则是损血,这是完全不同的三种逻辑,这个部分和上一个篇里打怪物的情况几乎一样,所以可以使用同一的碰撞逻辑(这部分的代码未实现,如要请参考其他篇)

那么下面就是Coding的时间,我在这里给出部分代码,详细的请下载源文件

 
  1. public class ClassBaseRole : Canvas  
  2.  
  3. {  
  4.  
  5. public Image ResImage = new Image();  
  6.  
  7. public ClassBaseRole()  
  8.  
  9. {  
  10.  
  11. this.Children.Add(ResImage);  
  12.  
  13. InitializtionRole();  
  14.  
  15. }  
  16.  
  17. public virtual void InitializtionRole()  
  18.  
  19. {  
  20.  
  21. }  
  22.  
  23. /// <summary> 
  24.  
  25. /// 移动速度  
  26.  
  27. /// </summary> 
  28.  
  29. public double Speed = 1;  
  30.  
  31. /// <summary> 
  32.  
  33. /// 修改或获取X坐标  
  34.  
  35. /// </summary> 
  36.  
  37. public double X  
  38.  
  39. {  
  40.  
  41. get { return Canvas.GetLeft(this); }  
  42.  
  43. set { Canvas.SetLeft(this, value); }  
  44.  
  45. }  
  46.  
  47. /// <summary> 
  48.  
  49. /// 修改或获取Y坐标  
  50.  
  51. /// </summary> 
  52.  
  53. public double Y  
  54.  
  55. {  
  56.  
  57. get { return Canvas.GetTop(this); }  
  58.  
  59. set { Canvas.SetTop(this, value); }  
  60.  
  61. }  
  62.  
  63. }  
  64.  
  65. public class ClassActivityRole : ClassBaseRole  
  66.  
  67. {  
  68.  
  69. public ClassActivityRole()  
  70.  
  71. {  
  72.  
  73. MyRectangle = new Rectangle() { Width = 32Height = 32Stroke = new SolidColorBrush(Colors.Red) };  
  74.  
  75. this.Children.Add(MyRectangle);  
  76.  
  77. }   
  78.  
  79. protected Rectangle MyRectangle;  
  80.  
  81. /// <summary> 
  82.  
  83. /// 取得自身的碰撞区域  
  84.  
  85. /// </summary> 
  86.  
  87. public Rect MyRect  
  88.  
  89. {  
  90.  
  91. get  
  92.  
  93. {  
  94.  
  95. return new Rect(X, Y, MyRectangle.Width, MyRectangle.Height);  
  96.  
  97. }  
  98.  
  99. }  
  100.  
  101. /// <summary> 
  102.  
  103. /// 碰撞测试  
  104.  
  105. /// </summary> 
  106.  
  107. /// <param name="objective">目标物体</param> 
  108.  
  109. /// <returns></returns> 
  110.  
  111. public bool CollidedTest(ClassActivityRole objective)  
  112.  
  113. {  
  114.  
  115. Rect rt = objective.MyRect;  
  116.  
  117. rt.Intersect(this.MyRect);  
  118.  
  119. if (!double.IsInfinity(rt.Height) && !double.IsInfinity(rt.Width))   
  120.  
  121. return true;   
  122.  
  123. else  
  124.  
  125. return false;  
  126.  
  127. }  
  128.  
  129. public virtual void DownWard()  
  130.  
  131. {  
  132.  
  133. Y += base.Speed;  
  134.  
  135. }  
  136.  
  137. public virtual void UpWard()  
  138.  
  139. {  
  140.  
  141. -base.Speed;  
  142.  
  143. }  
  144.  
  145. public virtual void RightWard()  
  146.  
  147. {  
  148.  
  149. X += base.Speed;  
  150.  
  151. }  
  152.  
  153. public virtual void LeftWard()  
  154.  
  155. {  
  156.  
  157. -base.Speed;  
  158.  
  159. }  
  160.  
  161. public virtual void LoopLogic()  
  162.  
  163. {  
  164.  
  165. }  
  166.  
  167. }  


后面还有更多,在这里不一一列举,直接看效果:
另外,我们可以最后的完成的文件情况:

 

 

 

 

 

写的类很少,并且去掉了这个Group那个Group,并且每个类的代码很少,没有超过50行,最少的就5行代码,这是为什么呢,因为我们用了面向对象,现在将主页面写成这样:

 
  1. public partial class MainPage : UserControl  
  2.  
  3. {  
  4.  
  5. public static Random random = new Random((int)DateTime.Now.Ticks);   
  6.  
  7. public static double ScreenWidth = 400;  
  8.  
  9. public static double ScreenHeight = 400;  
  10.  
  11. public ClassFlyer Hero = new ClassFlyer();  
  12.  
  13. public MainPage()  
  14.  
  15. {  
  16.  
  17. InitializeComponent();  
  18.  
  19. for (int i = 0; i < 20; i++)  
  20.  
  21. {  
  22.  
  23. Sky.Children.Add(new ClassCloud());  
  24.  
  25. Sky.Children.Add(new ClassFood());  
  26.  
  27. Sky.Children.Add(new ClassScrew());  
  28.  
  29. }  
  30.  
  31. Sky.Children.Add(Hero);  
  32.  
  33. DispatcherTimer GameLoop = new DispatcherTimer();  
  34.  
  35. GameLoop.Interval = TimeSpan.FromMilliseconds(40);  
  36.  
  37. GameLoop.Tick += new EventHandler(GameLoop_Tick);  
  38.  
  39. GameLoop.Start();  
  40.  
  41.  
  42.  
  43. base.KeyDown += new KeyEventHandler(MainPage_KeyDown);  
  44.  
  45. base.KeyUp += new KeyEventHandler(MainPage_KeyUp);  
  46.  
  47. }  
  48.  
  49.  
  50.  
  51. void MainPage_KeyUp(object sender, KeyEventArgs e)  
  52.  
  53. {  
  54.  
  55. Hero.FylerState = EmFlyerState.正常;  
  56.  
  57. }  
  58.  
  59.  
  60.  
  61. void MainPage_KeyDown(object sender, KeyEventArgs e)  
  62.  
  63. {  
  64.  
  65. switch (e.Key)  
  66.  
  67. {  
  68.  
  69. case Key.Up:  
  70.  
  71. Hero.FylerState = EmFlyerState.向上;  
  72.  
  73. break;  
  74.  
  75. case Key.Down:  
  76.  
  77. Hero.FylerState = EmFlyerState.向下;  
  78.  
  79. break;  
  80.  
  81. case Key.Left:  
  82.  
  83. Hero.FylerState = EmFlyerState.向左;  
  84.  
  85. break;  
  86.  
  87. case Key.Right:  
  88.  
  89. Hero.FylerState = EmFlyerState.向右;  
  90.  
  91. break;  
  92.  
  93. }  
  94.  
  95. }  
  96.  
  97. void GameLoop_Tick(object sender, EventArgs e)  
  98.  
  99. {   
  100.  
  101. foreach (var item in Sky.Children)  
  102.  
  103. {  
  104.  
  105. if (item is ClassActivityRole)  
  106.  
  107. {  
  108.  
  109. ClassActivityRole temp = (item as ClassActivityRole);  
  110.  
  111. temp.LoopLogic();  
  112.  
  113. if (temp.Y <= -32)  
  114.  
  115. {  
  116.  
  117. temp.InitializtionRole();  
  118.  
  119. }  
  120.  
  121. else  
  122.  
  123. {  
  124.  
  125. if (temp.CollidedTest(Hero) && !(temp is ClassCloud))  
  126.  
  127. {  
  128.  
  129. temp.InitializtionRole();  
  130.  
  131. }  
  132.  
  133. }  
  134.  
  135. }  
  136.  
  137. }  
  138.  
  139. }  
  140.  
  141. }  


综述,我们从这个例子中,可以看到有关于多重的类别对象在整体管理时候的应用,在做整体的游戏管理时候,只需要调用基本对象,基本类的方法会直接调用继承下来的类,比如说LoopLogic,对于不同的对象SolidFlyerCloudFood处理不同的逻辑,在CollidedTest中更加明显,只需要传入基类即可,不需要做单独的判定条件。

本代码中没有做损血和加血,主要是为了更加直观,损血和加血只需要写在碰撞检测里就可以,也不需要做太多的代码,甚至碰撞检测可以写在自身的逻辑中,而不需要每次都调用迭代器做判定

它在实际开发中非常重要,它能很好的简化代码,让结构更加清晰,而且修改起来非常容易,即便是增加功能也是非常简单的事情,比如我们搞一个横着飞的火球,只需要简单继承,修改一下飞行轨迹即可,可能在其他方面的应用更加广泛和舒适,欢迎共同探讨,各位高手可能有更加面向对象的例子,我也想好好学习啊:)
 

 

ClassBaseRole



本文转自nowpaper 51CTO博客,原文链接:http://blog.51cto.com/nowpaper/712577

相关文章
|
3月前
|
存储 开发框架 .NET
【C#】C# 基础语法与游戏开发
【1月更文挑战第21天】【C#】C# 基础语法与游戏开发
|
6月前
|
C# 图形学
C#之四十九 游戏编程周每日总结
C#之四十九 游戏编程周每日总结
31 0
|
7月前
|
自然语言处理 Java 编译器
C#OOP之一面向对象简介
C#OOP之一面向对象简介
40 0
|
1月前
|
存储 C# 开发工具
22.C# 中使用变量记录玩家创建的角色名:实现与游戏角色的互动
22.C# 中使用变量记录玩家创建的角色名:实现与游戏角色的互动
14 0
|
1月前
|
存储 开发框架 安全
C# .NET面试系列二:面向对象
<h2>面向对象 #### 1. 什么是构造函数? 构造函数(Constructor)是一种特殊类型的方法,它在创建类的实例(对象)时被调用,用于初始化对象的状态。构造函数的名称必须与包含它的类的名称相同,并且没有返回类型。 主要特点和用途包括: 初始化对象: ```c# 构造函数主要用于初始化类的实例。当使用 new 关键字创建类的对象时,构造函数会被调用,确保对象在使用之前处于一个合适的状态。 ``` 与类同名: ``` 构造函数的名称必须与包含它的类的名称完全相同。 ``` 没有返回类型: ```c# 构造函数没有返回类型,甚至不能声明 void。它的目的是初始化对象
48 0
|
3月前
|
存储 开发框架 .NET
【C#】认识C# (为了游戏开发 O(≧口≦)O)
【1月更文挑战第26天】【C#】认识C# (为了游戏开发 O(≧口≦)O)
|
3月前
|
定位技术 C# 图形学
Unity和C#游戏编程入门:创建迷宫小球游戏示例
Unity和C#游戏编程入门:创建迷宫小球游戏示例
71 2
|
8月前
|
设计模式 算法 C#
28【WinForm】C#实现商场收银软件,从面向过程到面向对象,设计模式的应用
实现商场收银系统从简单的面向过程到面向对象的演变。
85 0
|
8月前
|
C#
C#实现的打飞机游戏(课程设计)
C#实现的打飞机游戏(课程设计)
99 1