RacingGame学习笔记6——基础图形部分5

 

文件十二:UIRenderer.cs

正如UIRenderer类头顶上的注释所说,这个辅助类负责绘制界面上所有的2D元素。但当你看完这个类的代码以后,你会发现注释中所说的2D元素的范畴,比你想像的还要大。

这个文件比较长,并且长的让你找不出太多批驳它的理由。同时这个文件又很枯燥,仿佛就是个枯燥代码的集中营。这又有什么办法呢?一个程序中总难免有这样的类,像一个老黄牛,帮别人把不想干的活揽起来,让别人享受一个个简单的接口。实在是公仆的典范,当代的活雷锋啊~

不乱扯了,回归正题。先来看看Contants区间。这里记录了大量的贴图的位置矩型数据。相信不会有谁对这些东西抱有很大的兴趣。我们知道了它们的作用以后也就罢了。

Variables区间声明了一些将会使用到的贴图,一些将要使用的辅助类的实例等。当中有两个类,PostScreenMenuPostScreenGlow。他们是用来添加屏幕特效的。我们将在下一节仔细探讨。

接下来的PropertiesConstructorDispose区间也没有什么特别的地方了。就跳过了吧。让我们直接来看看几个文件中略有些意思的地方。

首先看到Add time fadeup effect区间。这个区间为游戏的界面添加了一个文字上升并逐渐淡去的效果(fadeup)。这个功能很多游戏里都可以见到,实现起来也并不难,采用的方法也可以是多种多样的。Benjamin的方法正如代码所示:先定义一个类来储存特效字的信息。(见TimeFadeupText。)然后定义一个函数来在游戏中添加一个FadeUp特效字。(见AddTimeFadeupEffect。)这个函数会将新建的TimeFadeupText注册到一个列表中。而另一个负责绘制字体的函数(RenderTimeFadeupEffects)则对列表中的每一个TimeFadeupText完成这样3个任务:检查当前TimeFadeupText对象是否已经过期的。如是,则从列表中去除;使用当前TimeFadeupText对象中的记载特效存在时间的成员(showTimeMs)来计算文字的绘制位置和透明通道的值,并将文字绘制在屏幕上;最后更新TimefadeupText对象中的showTimeMs成员。其中在第二个过程中,便能实现我们想要的渐变功能了。比如可以将

TextureFont.WriteTextCentered( BaseGame.Width / 2,

BaseGame.Height / 3 - (int)(moveUpAmount * BaseGame.Height / 3),

fadeupText.text,

ColorHelper.ApplyAlphaToColor( fadeupText.color, alpha ),

2.25f );

中的第二行的减号改成加号,接着运行下游戏看看哪里有变化。

接下来看看Render menu background区间的代码。大家一定注意到了游戏的界面后方会显示一个跑车疾驰的背景。这个效果就是在这里完成的。从

Matrix carMatrix =

RacingGameManager.Landscape.BestReplay.GetCarMatrixAtTime(carMenuTime );

这行代码中可以看出。背景中的播放的实际上是玩家自己的BestReplay。而背景绘制过程,实质上与游戏界面的绘制过程是相同的。而RenderMenuBackground函数则将绘制界面背景的任务统一了起来。其中的“Show RacingGame logo bouncing with the music”注释下是一段比较有意思的代码。记得游戏界面中右上角那个不断跳动的RacingGamelogo吗?其跳动效果便是在这里实现的。过程跟刚才那个Fadeup字体特效异曲同工。先获得一个与时间相关的量,再将这个量作用在绘制过程中。这里调用的BaseGame.CalcRectangleWithBounce便是通过传入的bounceSize来计算贴图绘制的位置。

然后再看看RenderBottomButtons区间。这里绘制的是游戏子选单右下角的显示手柄AB按键功能的贴图。这里可以看到这两个按键相应鼠标事件的实现方式:当鼠标不在按键所在矩形中时,使用的是一张贴图;当鼠标移动到矩形中时,会使用另一张贴图来绘制。这样就给按键添加了交互感。交互性在游戏中的重要性就不用我多说了吧。

接着看看Game UI区间。这个区间中仅有一个很长的函数。函数的作用便是绘制游戏场景中的所有2D元素。你可以在函数的最开始加上一个return,然后看看游戏场景中都少了些什么。而这个函数就属于那种黄牛函数了,充斥着一条条的绘制代码。也找不出啥亮点来,也就不在详细分析了。

另外在这个文件中仍值得一提的是在Render区间中的RenderTextsAndMouseCuror函数。绘制游戏帧频(fps)和鼠标的代码就在这里了。但游戏帧频信息和鼠标的位置信息却分别由BaseGameInput类提供的。我们马上就会开始对前者的分析。

 

文件十三:BaseGame.cs

讨论这个文件前有必要先谈谈一些有关游戏整体结构的问题。一般的游戏,往往会从结构上分为包含绘制、资源管理、碰撞检测以及物理支持等功能的辅助部分和管理特定游戏逻辑的逻辑部分。其中辅助部分经过发展之后往往变成能在不同游戏中使用的游戏引擎;而游戏逻辑部分则与具体游戏内容相关。这样的层次结构,有利于程序的不断改进,也有利于代码的重用。(例如所有BenjaminXNA示例中,辅助部分的代码均大同小异。)

这里的BaseGame类实际上封装了游戏中所有与绘制相关的类。而逻辑层的主要的管理类RacingGameManager则从BaseGame类继承。与BaseGame类看上去格外庞大的身躯相比,RacingGameManager类一共只有440行,显得很整洁。这便从实际上体现出分层的好处了。

BaseGame类中的大量代码显然是随着游戏其他部分的需要而不断添加的。除去这些代码之外,我们需要注意以下几个地方。

文件中将GraphicsDevice对象、ContentManager对象以及大量单实例对象声明为类的公有静态成员。这样做相当与将他们作为全局对象。在全局范围内提供了方便的访问。

1317行处开始有一个每隔1秒中执行一次的代码块,其中计算了当前的帧频。其中

fpsInterpolated = MathHelper.Lerp( fpsInterpolated, fpsLastSecond, 0.1f );

能使fpsInterpolated的值保持相对的稳定,过滤掉实际帧频的突然波动。接下来通过判断fpsInterpolated的值来确定MaxViewDistance的值。而MaxViewDistance将决定每一帧绘制图形的数量。当帧频降低时就减少绘制模型的数量,而帧频较高时就提高渲染的效果。这样跟计算fpsInterpolated的代码一起组成了一个稳定的结构,比较有借鉴价值。

接着看1398行开始的Draw函数。BaseGame类很大的一个好处就是管理了绘制上大量的繁琐过程。可以看到在Draw函数的1412行,调用了Render函数。而BaseGame类中的Render函数实际上是个空函数,而他的作用就是被重载的。通过这种方法,BaseGame的子类(如RacingGameManager类)只需要重载Render函数,并在函数中添加绘制代码。绘制前的准备过程(如调用spriteBatchBegin函数。)以及绘制后的过程都无需关心。

同时我们也可以在Draw函数中看到一行对PostUIRender函数的调用。机制上与Render是相同的,只不过这个用于绘制用户界面。今后我们会在GameScreens目录中看到这里实际运行的代码。Draw中剩下的代码的作用是在到达终点以后绘制出奖杯,以及调用我们上一个文件中看到的UIManagerRenderTextsAndMouseCursor函数来绘制FPS和鼠标贴图。

接下来看看Set and reset render targets区间。在此必须要介绍一下RenderTarget的作用。从字面上理解,RenderTarget意为渲染目标。实际上也正是如此,可以通过Device.SetRenderTarget来将一个渲染目标设置到图形设备中,接下来,图形设备的就会一切绘制过程的结果,存储到这个RenderTarget中。然后我们就可以通过RenderTarget2D.GetTexture函数来获得绘制数据。这样做的目的是为了能对获得的数据进行一些特效处理。我们将在下一节看到的Post Screen Effect就会需要进行这个过程。我们也将会在那个时候,对这里的方法进行更详细的介绍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值