/** 轴 */ export enum Axis { /** 正 X 轴 */ positiveX, /** 正 Y 轴 */ positiveY, /** 负 X 轴 */ negativeX, /** 负 Y 轴 */ negativeY } const { ccclass, property, executeInEditMode, playOnFocus } = cc._decorator; /** * 围绕旋转组件 * @author 薛鸿潇 */ @ccclass @executeInEditMode() @playOnFocus() export default class RotateAround extends cc.Component { @property({ type: cc.Node, tooltip: '围绕旋转的目标' }) public target: cc.Node = null; @property({ tooltip: '顺时针旋转' }) public clockwise: boolean = true; @property({ tooltip: '旋转一圈花费的时间' }) public timePerRound: number = 10; @property({ tooltip: '是否始终面向目标节点' }) public faceToTarget: boolean = false; @property({ type: cc.Enum(Axis), tooltip: '面向目标节点的轴:\n- PositiveX:正 X 轴\n- PositiveY:正 Y 轴\n- NegativeX:负 X 轴\n- NegativeY:负 Y 轴', visible() { return this.faceToTarget } }) public faceAxis: Axis = Axis.negativeY; @property({ tooltip: '自动开始旋转' }) public auto_start: boolean = false; /** 编辑器预览 */ private _edit_play: boolean = false; @property({ displayName: '编辑器预览' }) get edit_play(): boolean { if (this._edit_play && !this.radius) this.run(); this.isRotating = this._edit_play; return this._edit_play; } set edit_play(v: boolean) { this._edit_play = v; } /** 角度 */ public angle: number = 0; /** 半径 */ public radius: number = 0; /** 标志位,是否正在旋转 */ private isRotating: boolean = false; protected start() { if (this.auto_start) this.run(); } protected update(dt: number) { if (!this.isRotating || !this.target) return; // 将角度转换为弧度 let radian = (Math.PI / 180) * this.angle; // 更新节点的位置 this.node.x = this.target.x + this.radius * Math.cos(radian); this.node.y = this.target.y + this.radius * Math.sin(radian); // 更新节点的角度 if (this.faceToTarget) { switch (this.faceAxis) { case Axis.positiveX: this.node.angle = this.angle + 180; break; case Axis.positiveY: this.node.angle = this.angle + 90; break; case Axis.negativeX: this.node.angle = this.angle; break; case Axis.negativeY: this.node.angle = this.angle - 90; break; } } // 计算下一帧的角度 let anglePerFrame = dt * (360 / this.timePerRound); if (this.clockwise) this.angle -= anglePerFrame; else this.angle += anglePerFrame; // 重置角度,避免数值过大 if (this.angle >= 360) this.angle %= 360; else if (this.angle <= -360) this.angle %= -360; } /** * 开始围绕目标节点旋转 * @param target 目标节点 * @param clockwise 是否顺时针旋转 * @param timePerRound 旋转一圈的时间 * @param faceToTarget 是否始终面向目标节点 * @param faceAxis 面向目标节点的轴 */ public run(target?: cc.Node, clockwise?: boolean, timePerRound?: number, faceToTarget?: boolean, faceAxis?: Axis) { if (target) this.target = target; if (clockwise) this.clockwise = clockwise; if (timePerRound) this.timePerRound = timePerRound; if (faceToTarget) this.faceToTarget = faceToTarget; if (faceAxis) this.faceAxis = faceAxis; if (!this.target) return cc.log('No target!'); if (this.isRotating) return; // 计算初始角度和半径 this.angle = this.getAngle(this.target.getPosition(), this.node.getPosition()); this.radius = this.getDistance(this.target.getPosition(), this.node.getPosition()); // 开始 this.isRotating = true; } /** * 停止旋转 */ public stop() { this.isRotating = false; } /** * 获取两点间的角度 * @param p1 点1 * @param p2 点2 */ public getAngle(p1: cc.Vec2, p2: cc.Vec2): number { return Math.atan((p2.y - p1.y) / (p2.x - p1.x)); } /** * 获取两点间的距离 * @param p1 点1 * @param p2 点2 */ public getDistance(p1: cc.Vec2, p2: cc.Vec2): number { return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2)); } }