效果
在很多游戏中,跟踪子弹是一个在许多射击游戏或策略游戏中都会出现的效果,它允许子弹跟踪并击中移动的目标。效果图如下:
实现思路
由于目标的位置可能实时变化,所以子弹的终点位置是不确定的,同时在移动的时候,子弹的方向也需要进行实时的调整,因此需要在update的时候去实时改变子弹的方向和处理速度变化。在每帧的回调中,我们可以拿到当前目标的位置和子弹的位置,通过向量减法,算出子弹到目标的归一化变量,然后再给子弹做位置的叠加和角度的叠加。
这里面涉及到了向量的减法,为何要用向量减法,先看下图:
从图中我们可以很清楚的看到,a向量 减去 b向量的结果,刚好可以得出b到a的方向向量,用这个原理,就可以很容易算出子弹到目标的方向向量,通过对方向向量的归一化后,可以很方便的计算出子弹的位置和方向。
首先先通过向量减法,算出子弹到目标的方向向量
typescript
let targetPos: cc.Vec2 = this.target.getPosition();
let bulletPos: cc.Vec2 = this.bullet.getPosition();
// 减法
let directionVec: cc.Vec2 = targetPos.subtract(bulletPos);
得到方向向量后,将方向向量做归一化处理,转成单位向量,这样就可以算出子弹每一帧的位置
typescript
// 方向向量归一化
const normalizeVec: cc.Vec2 = directionVec.normalize();
// 算法子弹节点的位置
this.bulletNode.x += normalizeVec.x * this.bulletSpeed * dt;
this.bulletNode.y += normalizeVec.y * this.bulletSpeed * dt;
子弹的位置算出来后,还需要计算每一帧子弹的角度
typescript
// 角度变化以y轴正方向为起点,逆时针角度递增
this.bulletNode.angle = cc.v2(0, 1).signAngle(normalizeVec) * 180 / Math.PI;
这样就实现了子弹的跟踪效果,实时的位置和方向。
上面的效果图中,我们看到子弹碰到目标后,会爆炸,在每一帧update的后面,还需要需要进行下碰撞检测
typescript
// 获取目标的包围盒
let rect = this.role.getBoundingBox();
// 碰撞检测, 命中后响应碰撞
if (rect.contains(bulletPos)) this.hitTheTarget();
hitTheTarget
处理碰撞后的爆炸结果和目标的消失
typescript
// 碰撞响应
hitTheTarget() {
// 子弹消失
this.bulletNode.active = false;
// 显示爆炸效果
this.boom.active = true;
// 0.2庙后,爆炸效果和目标消失
this.scheduleOnce(() => {
this.boom.active = false;
this.role.active = false;
}, 0.2);
}
到此就实现了开头的效果。
需要注意的是:对于大量的子弹和目标,每帧计算所有的距离和方向可能会引起性能问题。为了优化性能,考虑使用四叉树或其他数据结构来减少不必要的计算。