3D战斗游戏之运动模式准备篇2
在上一篇文章中,我们提到Cocos2d尚未支持3D运动,因此通过更改引擎代码的方式,自行实现了MoveTo3D和Moveby3D。然而,这种方法较为激进,并非所有开发者都愿意对引擎代码进行修改,即便该引擎是开源的。在本文中,我们将介绍一种相对温和的实现方式。
实现原理
Cocos依靠update事件来逐帧刷新屏幕。要将一个物体从A点移动到B点,只需在两点间构建一条直线,并将其分割成若干小段,使物体每帧移动一小段距离。利用这种方法,无论是2D还是3D的移动都能够实现。
代码实现
假设存在一个bulletSprite精灵,并且已经为其pTargetPos和pSpeed进行了赋值,例如pTargetPos = Vec3(100, 100, -1000),pSpeed = 100.0f。以下是实现物体移动的代码:
Vec3 curPos = bulletSprite->getPosition3D();
Vec3 newFaceDir = pTargetPos - curPos;
newFaceDir.normalize();
Vec3 offset = newFaceDir * pSpeed * dt; // 当前点到目标点的距离矢量 * 速度 * 每帧时间 = 移动距离
curPos += offset;
bulletSprite->setPosition3D(curPos);
将上述代码放置在场景的update函数中,在每帧刷新时,程序会计算出该帧bulletSprite向着目标点的位移量,并重新设置其位置。在屏幕上呈现的效果就是子弹射向pTargetPos点。
代码封装与优势
这段代码可以进行封装,并通过schedule或者update方法进行调用,实现起来并不复杂,这里就不再赘述。这种实现方式的最大优势在于,子弹每帧的偏移量offset是实时计算的,因此可以轻松实现子弹的非直线飞行,例如让子弹呈鸟状、抛物线状等多种形态飞行。
参考示例
在上一篇文章中,有朋友提到《FantasyWarrior3D》中实现了3D子弹飞行效果。实际上,该游戏正是采用每帧计算子弹位置的方式来实现的。有兴趣的读者可以查看其AttackCommand.lua文件中的solveAttacks(dt)和ArcherNormalAttack:onUpdate(dt)函数,下面是ArcherNormalAttack:onUpdate(dt)函数的代码片段供参考:
function ArcherNormalAttack:onUpdate(dt)
local selfPos = getPosTable(self)
local nextPos = cc.pRotateByAngle(cc.pAdd({x=self.speed*dt, y=0},selfPos),selfPos,self.facing)
self:setPosition(nextPos)
end