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;
        }
    }
}

 

  

 

posted on 2021-11-29 16:24  gamedaybyday  阅读(953)  评论(0编辑  收藏  举报