如何让Cocos Creator中飞机沿指定直径圆周转向新角度而非立即转向?
问题描述
我想要模仿《Missiles》游戏的操作效果,当前在Cocos Creator中实现了触摸控制飞机旋转与直线移动,但希望调整为:改变角度时,飞机沿特定半径的圆周轨迹移动,而非直接直线转向移动。现有Main类代码如下:
const { ccclass, property } = cc._decorator; export const event_instance = new cc.EventTarget(); @ccclass export default class Main extends cc.Component { @property(cc.Node) cameraNode: cc.Node = null; @property(cc.Node) Game: cc.Node = null; private touchStartPos: cc.Vec2 = cc.Vec2.ZERO; private isRotating: boolean = false; private newAngle: number = 0; private moveDir: cc.Vec2 = cc.Vec2.ZERO; protected onLoad(): void { this.init(); } init(): void { this.cameraNode.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this); this.cameraNode.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this); this.cameraNode.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this); } onTouchStart(event: cc.Event.EventTouch): void { this.touchStartPos = event.getLocation(); } onTouchMove(event: cc.Event.EventTouch): void { this.isRotating = true; const touchPos = event.getLocation(); const moveVec = touchPos.subtract(this.touchStartPos).normalize(); this.moveDir = moveVec; this.newAngle = cc.misc.radiansToDegrees(Math.atan2(moveVec.y, moveVec.x)) - 90; } onTouchEnd(event: cc.Event.EventTouch): void { this.isRotating = false; this.touchStartPos = cc.Vec2.ZERO; } protected update(dt: number): void { if (this.isRotating) { this.Game.getChildByName('Plane').angle = this.newAngle; this.Game.getChildByName('Plane').setPosition(this.Game.getChildByName('Plane').getPosition().add( this.moveDir.clone().multiplyScalar(15) )); this.cameraNode.setPosition(this.Game.getChildByName('Plane').position); } } }
解决方案
要实现飞机沿圆周轨迹移动,核心是基于圆周的圆心和半径,根据触摸输入的角度计算飞机在圆周上的位置,同时保持飞机朝向与圆周切线方向一致。具体修改步骤如下:
1. 添加圆周参数
在类中定义圆周轨迹的核心参数,可在编辑器中可视化调整半径:
// 圆周轨迹的半径(可在Cocos编辑器中调整) @property private circleRadius: number = 100; // 圆周轨迹的圆心位置 private circleCenter: cc.Vec2 = cc.Vec2.ZERO; // 记录飞机当前在圆周上的弧度角度 private currentRadian: number = 0;
2. 初始化圆心与初始弧度
在onLoad方法中,根据飞机初始位置确定圆周圆心(示例中默认飞机初始在圆心正上方):
protected onLoad(): void { this.init(); const plane = this.Game.getChildByName('Plane'); // 设置圆心为飞机初始位置下方radius距离处 this.circleCenter = plane.position.subtract(cc.v2(0, this.circleRadius)); // 初始弧度对应正上方位置 this.currentRadian = Math.PI / 2; }
3. 修改触摸移动逻辑
触摸移动时,根据横向偏移量调整飞机在圆周上的弧度位置,替代原有的直线方向计算:
onTouchMove(event: cc.Event.EventTouch): void { this.isRotating = true; const touchPos = event.getLocation(); const moveVec = touchPos.subtract(this.touchStartPos); // 调整旋转灵敏度,数值越大旋转越快 const rotateSpeed = 0.02; this.currentRadian += moveVec.x * rotateSpeed; // 保持弧度在0~2π范围内循环 if (this.currentRadian < 0) this.currentRadian += Math.PI * 2; if (this.currentRadian > Math.PI * 2) this.currentRadian -= Math.PI * 2; // 更新触摸起始点,避免偏移量累积过大 this.touchStartPos = touchPos; }
4. 更新飞机位置与朝向
在update方法中,根据当前弧度计算飞机在圆周上的坐标,并设置朝向为圆周切线方向:
protected update(dt: number): void { if (this.isRotating) { const plane = this.Game.getChildByName('Plane'); // 计算圆周上的目标位置:x=圆心x+半径*cos(弧度),y=圆心y+半径*sin(弧度) const targetPos = cc.v2( this.circleCenter.x + this.circleRadius * Math.cos(this.currentRadian), this.circleCenter.y + this.circleRadius * Math.sin(this.currentRadian) ); plane.setPosition(targetPos); // 设置飞机朝向为切线方向(根据你的飞机精灵初始朝向调整角度偏移) plane.angle = cc.misc.radiansToDegrees(this.currentRadian) + 90; // 相机跟随飞机位置 this.cameraNode.setPosition(targetPos); } }
完整修改后的代码
const { ccclass, property } = cc._decorator; export const event_instance = new cc.EventTarget(); @ccclass export default class Main extends cc.Component { @property(cc.Node) cameraNode: cc.Node = null; @property(cc.Node) Game: cc.Node = null; // 圆周轨迹参数 @property private circleRadius: number = 100; private circleCenter: cc.Vec2 = cc.Vec2.ZERO; private currentRadian: number = 0; private touchStartPos: cc.Vec2 = cc.Vec2.ZERO; private isRotating: boolean = false; protected onLoad(): void { this.init(); const plane = this.Game.getChildByName('Plane'); // 初始圆心设置为飞机初始位置下方radius距离处 this.circleCenter = plane.position.subtract(cc.v2(0, this.circleRadius)); this.currentRadian = Math.PI / 2; } init(): void { this.cameraNode.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this); this.cameraNode.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this); this.cameraNode.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this); } onTouchStart(event: cc.Event.EventTouch): void { this.touchStartPos = event.getLocation(); } onTouchMove(event: cc.Event.EventTouch): void { this.isRotating = true; const touchPos = event.getLocation(); const moveVec = touchPos.subtract(this.touchStartPos); // 调整旋转灵敏度 const rotateSpeed = 0.02; this.currentRadian += moveVec.x * rotateSpeed; // 保持弧度在0~2π区间循环 if (this.currentRadian < 0) this.currentRadian += Math.PI * 2; if (this.currentRadian > Math.PI * 2) this.currentRadian -= Math.PI * 2; this.touchStartPos = touchPos; } onTouchEnd(event: cc.Event.EventTouch): void { this.isRotating = false; this.touchStartPos = cc.Vec2.ZERO; } protected update(dt: number): void { if (this.isRotating) { const plane = this.Game.getChildByName('Plane'); // 计算圆周上的目标位置 const targetPos = cc.v2( this.circleCenter.x + this.circleRadius * Math.cos(this.currentRadian), this.circleCenter.y + this.circleRadius * Math.sin(this.currentRadian) ); plane.setPosition(targetPos); // 设置飞机朝向为切线方向(根据你的飞机精灵初始朝向调整角度偏移) plane.angle = cc.misc.radiansToDegrees(this.currentRadian) + 90; this.cameraNode.setPosition(targetPos); } } }
内容的提问来源于stack exchange,提问作者Khang
相关产品推荐
相关产品推荐

