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

2016-08-20 11:08:07来源:http://nowpaper.blog.51cto.com/3893223/712577作者:nowpaper人点击


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


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

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


publicdoubleSpeed=4; publicdoubleX { get{returnCanvas.GetLeft(this);} set{Canvas.SetLeft(this,value);} } publicdoubleY { get{returnCanvas.GetTop(this);} set{Canvas.SetTop(this,value);} } publicRectMyRect { get { returnnewRect(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则是损血,这是完全不同的三种逻辑,这个部分和上一个篇里打怪物的情况几乎一样,所以可以使用同一的碰撞逻辑(这部分的代码未实现,如要请参考其他篇)

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


publicclassClassBaseRole:Canvas { publicImageResImage=newImage(); publicClassBaseRole() { this.Children.Add(ResImage); InitializtionRole(); } publicvirtualvoidInitializtionRole() { } ///<summary>///移动速度 ///</summary>publicdoubleSpeed=1; ///<summary>///修改或获取X坐标 ///</summary>publicdoubleX { get{returnCanvas.GetLeft(this);} set{Canvas.SetLeft(this,value);} } ///<summary>///修改或获取Y坐标 ///</summary>publicdoubleY { get{returnCanvas.GetTop(this);} set{Canvas.SetTop(this,value);} } } publicclassClassActivityRole:ClassBaseRole { publicClassActivityRole() { MyRectangle=newRectangle(){Width=32,Height=32,Stroke=newSolidColorBrush(Colors.Red)}; this.Children.Add(MyRectangle); } protectedRectangleMyRectangle; ///<summary>///取得自身的碰撞区域 ///</summary>publicRectMyRect { get { returnnewRect(X,Y,MyRectangle.Width,MyRectangle.Height); } } ///<summary>///碰撞测试 ///</summary>///<paramname="objective">目标物体</param>///<returns></returns>publicboolCollidedTest(ClassActivityRoleobjective) { Rectrt=objective.MyRect; rt.Intersect(this.MyRect); if(!double.IsInfinity(rt.Height)&&!double.IsInfinity(rt.Width)) returntrue; else returnfalse; } publicvirtualvoidDownWard() { Y+=base.Speed; } publicvirtualvoidUpWard() { Y-=base.Speed; } publicvirtualvoidRightWard() { X+=base.Speed; } publicvirtualvoidLeftWard() { X-=base.Speed; } publicvirtualvoidLoopLogic() { } }


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








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


publicpartialclassMainPage:UserControl { publicstaticRandomrandom=newRandom((int)DateTime.Now.Ticks); publicstaticdoubleScreenWidth=400; publicstaticdoubleScreenHeight=400; publicClassFlyerHero=newClassFlyer(); publicMainPage() { InitializeComponent(); for(inti=0;i<20;i++) { Sky.Children.Add(newClassCloud()); Sky.Children.Add(newClassFood()); Sky.Children.Add(newClassScrew()); } Sky.Children.Add(Hero); DispatcherTimerGameLoop=newDispatcherTimer(); GameLoop.Interval=TimeSpan.FromMilliseconds(40); GameLoop.Tick+=newEventHandler(GameLoop_Tick); GameLoop.Start(); base.KeyDown+=newKeyEventHandler(MainPage_KeyDown); base.KeyUp+=newKeyEventHandler(MainPage_KeyUp); } voidMainPage_KeyUp(objectsender,KeyEventArgse) { Hero.FylerState=EmFlyerState.正常; } voidMainPage_KeyDown(objectsender,KeyEventArgse) { switch(e.Key) { caseKey.Up: Hero.FylerState=EmFlyerState.向上; break; caseKey.Down: Hero.FylerState=EmFlyerState.向下; break; caseKey.Left: Hero.FylerState=EmFlyerState.向左; break; caseKey.Right: Hero.FylerState=EmFlyerState.向右; break; } } voidGameLoop_Tick(objectsender,EventArgse) { foreach(variteminSky.Children) { if(itemisClassActivityRole) { ClassActivityRoletemp=(itemasClassActivityRole); temp.LoopLogic(); if(temp.Y<=-32) { temp.InitializtionRole(); } else { if(temp.CollidedTest(Hero)&&!(tempisClassCloud)) { temp.InitializtionRole(); } } } } } }


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

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

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



ClassBaseRole




最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台