游戏中帧函数调用的顺序问题——基于HGE引擎的打砖块游戏
我们都知道HGE引擎中的帧函数和渲染函数是对应的,每刷新一帧会先调用帧函数,然后再调用一次渲染函数。我现在做的游戏都是以界面类来作为基础来进行的,开发结构大致如下:
大致有三个界面类,每个界面类中都有属于自己界面的帧函数和渲染函数。游戏根据你当前所处的界面来执行该界面的帧函数和渲染函数。当你从一个界面跳转到另外一个界面的时候,问题就产生了!
1)界面跳转代码的调用地方和控制办法
我们对游戏中参数的修改都是放到帧函数中的,这样我们自然就会想到把界面跳转放到帧函数中。由于程序结构先执行的是帧函数,然后才执行渲染函数,当我们在帧函数中修改了界面,那么渲染函数就会执行我们修改之后的界面的渲染函数。也就是说,我们在CGameMenuScene的SceneFram中修改了界面进入到了CGamePlayScene中,程序的结构是没调用一次帧函数SceneFrame,就会调用一次渲染函数SceneRenerDraw,此时已经调用帧函数SceneFram修改了界面,那执行渲染函数时,程序根据当前界面(已经跳转到了CGamePlayScene界面),执行了该界面(CGamePlayScene)的渲染函数。这就导致界面的帧函数和渲染函数的不对应——帧函数和渲染函数不属于同一个界面!
帧函数和渲染函数的不对应会导致我们想要执行的代码执行不到,或者造成程序的错误执行。解决的办法有两种(个人想到的)
1. 偷懒的办法
把界面跳转代码放到渲染函数中。这个办法虽然简单,但是会造成程序的混乱和代码的不合理。
2. 个人认为的较好的办法
由于界面的帧函数和渲染函数的调用switch语句是在基类GameBase中书写的,我们可以在基类中进行界面的控制。当界面跳转之后,让程 序重新从帧函数开始执行,这样就不会造成帧函数和渲染函数的不对应。
2)游戏中界面元素的更新的顺序问题
我们都玩过或者看过打砖块的游戏,游戏中主要有3类元素:托盘——用于接住和反弹碰撞球,碰撞球——由于击打砖块,砖块——被击打的东西。每类元素都设计成一个类,那么我们在游戏界面类中对这3类元素进行更新的时候,他们更新的顺序有没有关系呢?
我一开始也觉得无所谓,接随便将他们的更新函数放到了帧函数中调用。
this->UpdateBall( dt );//更新小球
this->UpdateBrick( dt );//更新砖块
this->UpdatePlate( dt );//更新托盘
一开始,我也没在意,等到了游戏开发快结束的时候,我发现托盘和小球的碰撞老出现问题,当我拖动托盘越快,碰撞的误差越大!然后我对碰撞检测的代码进行了优化,没次碰撞之后,我将小球的坐标重新设定一次,让小球刚好和托盘接触。修改之后,虽然好了一点,但是问题依然严重。这是我想到了以上代码的调用顺序问题!
我重新设定小球的坐标是根据当前托盘的坐标来的,但是我先更新的是小球,而托盘的坐标还是上一帧的,当我拖动托盘越快,误差也就越大。所以我把调用的顺修改了一下,问题才得到解决!
this->UpdatePlate( dt );
this->UpdateBall( dt );
this->UpdateBrick( dt );
这里我总结一个规律:游戏中运动速度最不稳定(托盘)和最快的(小球)元素应该首先进行更新,速度不变的(砖块)后进行更新。至于速度不稳定的和速度快的物体,哪个先进行更新能减小误差就先更新哪个!
以上是个人在使用HGE开发游戏中的一点体会,当然也还要很多其他问题,没有一一列出来,自己记不得了。
最后就是打砖块中碰撞检测的问题,这里向有经验的朋友请教一下:
当小球运动速度越来越快的时候,小球和砖块碰撞判断的误差就会越来越大,如果这个误差值固定不变,会导致碰撞检测失败。这个问题如何解决?有经验或者好的想法和办法的给我留言或者E-mail: zhaxun@yahoo.cn
新的方法:在当前帧显示上一帧的画面,也就是预先算好下一帧的数据