cocos版本:2.4.4
Demo地址:跟踪导弹Demo
效果图:

实现原理:
需求是导弹飞到目的地

cocos坐标系中角度

通过Math.atan2可以获得导弹和目的地之间的角度
let missile:cc.Node; //导弹 let targetPos:cc.Vec2; //目的地 let radian = Math.atan2(targetPos.y - missile.y, targetPos.x - missile.x); //导弹和目的地之间弧度 let angle = radian*180/Math.PI; //弧度转换成角度

导弹每帧进行角度旋转和移动
let moveAngle = 2; //角速度(每帧角度变化) let moveRadian = moveAngle*Math.PI/180; //弧度(角速度转成弧度) let moveSpeed = 5; //移动速度 missile.angle += moveAngle; //角度每帧变化 missile.x += Math.cos(moveRadian)*moveSpeed; //x变化 missile.y += Math.sin(moveRadian)*moveSpeed; //y变化
导弹位置都到达目的地,那么导弹的追踪完成。
15是临近值,如果直接判断 导弹位置 = 目的地位置,那么导弹可能会在目的地附近不停的抖动。
//判断导弹和目的地的距离,如果小于一定值(这里取15),则判定到达目的地。
if(cc.Vec2.distance(missile.position, targetPosition) < 15){
//导弹到达目的地
}
跟踪导弹效果就是追着一个位置变化的物体,所以只要不停的改变目的地targetPos,再进行计算就行了。
注意点:
由于Math.atan2在边界值180和-180交接处,从-180瞬间变化到180,或者从180瞬间变化到-180,所以在计算时要处理这种情况,不然导弹会反复绕圈。

导弹的代码:
const { ccclass, property } = cc._decorator;
@ccclass
export default class Missile extends cc.Component {
/**目标地点 */
public targetPos: cc.Vec2 = new cc.Vec2();
/**角速度 */
public angleSpeed: number = 5;
/**移动速度 */
public moveSpeed: number = 5;
/**移动限制距离,相距目的地距离>moveLimit时才会移动,防止抖动 */
private moveLimit: number = 20;
/**每帧变化的角度 */
private stepAngle: number = null;
/**
* 设置目标点
* @param xPos x坐标
* @param yPos y坐标
*/
public setTargetPos(xPos: number, yPos: number) {
this.targetPos.x = xPos;
this.targetPos.y = yPos;
this.stepAngle = null;
}
/**重置 */
public reset() {
this.stepAngle = null;
}
update() {
//距离目的地一定距离才会移动,防止抖动
if (Math.sqrt(Math.pow(this.node.x - this.targetPos.x, 2) + Math.pow(this.node.y - this.targetPos.y, 2)) > this.moveLimit) {
//导弹和目标点之间弧度、角度
let targetRadian = Math.atan2(this.targetPos.y - this.node.y, this.targetPos.x - this.node.x);
let targetAngle = targetRadian * 180 / Math.PI;
//导弹当前角度
let curAngle = this.node.angle;
//导弹当前角度和导弹最终指向角度的差
let distAngle = targetAngle - curAngle;
//导弹转动的角速度,根据角度差来判断顺时针或逆时针。( stepAngle=null时才会计算旋转角度,为了防止导弹出现在边界值附近左右摇摆的问题,一旦确定旋转角度方向,则不再改变)
if (this.stepAngle == null) {
this.stepAngle = distAngle > 0 ? this.angleSpeed : -this.angleSpeed;
}
//临界值判断 (Math.atan2会在边界值位置直接从180变成-180,或-180变成180,导致永远到不了目标角度)
if (Math.abs((curAngle + 360) % 360 - (targetAngle + 360) % 360) > (Math.abs(this.stepAngle) + 1)) {
//角度未达到临近值才会++,防止抖动
if (Math.abs(this.node.angle - targetAngle) > (Math.abs(this.stepAngle) + 1)) {
this.node.angle += this.stepAngle;
}
}
//移动
let nextRadian = this.node.angle * Math.PI / 180;
this.node.x += Math.cos(nextRadian) * this.moveSpeed;
this.node.y += Math.sin(nextRadian) * this.moveSpeed;
}
}
}
浙公网安备 33010602011771号