import CMath from "./CMath"; /** * 摇杆 */ const { ccclass, property } = cc._decorator; const TouchType = cc.Enum({ DEFAULT: 0,//摇杆固定位置 FOLLOW: 1//摇杆跟随 }); const DirectionType = cc.Enum({ FOUR: 4, EIGHT: 8, ALL: 0, }); @ccclass export default class Joystick extends cc.Component { @property({ type: TouchType, displayName: '触摸类型', }) mTouchType = TouchType.DEFAULT; @property({ type: DirectionType, displayName: '方向类型', }) mDirectionType = TouchType.DEFAULT; @property(cc.Node) mDot: cc.Node = null;//摇杆 @property(cc.Node) mRing: cc.Node = null;//摇杆底 @property(cc.Node) mDir: cc.Node = null;//方向指示图 public isDisable = false; private _radius: number;//半径 private _angle: number;//当前触摸的角度 private _distance: number = 0;//点击与中心的距离 private tmpDir = { x: 0, y: 0 } /** * @runing 行走 * @angle 角度 * @distance 距离[0-1] */ private callback: (move: boolean, v2: any, angle: number) => void; public onLoad() { this._radius = (this.mRing.width - this.mDot.width) / 2; this.mDir.opacity = 0; this.mDot.opacity = 100; this._initTouchEvent(); } public stop() { // this.isDisable = true; this._touchEndEvent(); } public setCallback(callback: (move: boolean, any, angle: number) => void) { this.callback = callback; } //对圆圈的触摸监听 private _initTouchEvent() { this.node.on(cc.Node.EventType.TOUCH_START, this._touchStartEvent, this); this.node.on(cc.Node.EventType.TOUCH_MOVE, this._touchMoveEvent, this); // // 触摸在圆圈内离开或在圆圈外离开后,摇杆归位,player速度为0 this.node.on(cc.Node.EventType.TOUCH_END, this._touchEndEvent, this); this.node.on(cc.Node.EventType.TOUCH_CANCEL, this._touchEndEvent, this); cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyPressed, this); cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyReleased, this); } private _touchStartEvent(event) { if (this.isDisable) { return; } // 获取触摸位置的世界坐标转换成圆圈的相对坐标(以圆圈的锚点为基准) let touchPos = this.node.convertToNodeSpaceAR(event.getLocation()); // let ringPos = this.mRing.getPosition(); // //触摸点与圆圈中心的距离 // let distance = this._getDistance(touchPos, ringPos); // //手指在圆圈内触摸,控杆跟随触摸点 // if (this._radius > distance) { // this.mDot.setPosition(touchPos); // this.updateAngle(); // return true; // }else{ // if(this.mTouchType == TouchType.FOLLOW){ // this.mRing.setPosition(touchPos); // this.mDot.setPosition(touchPos); // return true; // } // } this.mDir.opacity = 255; this.mDot.opacity = 255; if (this.mTouchType == TouchType.FOLLOW) { this.mRing.setPosition(touchPos); this.mDot.setPosition(touchPos); this.mDir.setPosition(touchPos); return true; } return false; } private _touchMoveEvent(event) { if (this.isDisable) { return; } var touchPos = this.node.convertToNodeSpaceAR(event.getLocation()); let ringPos = this.mRing.getPosition(); var distance = this._getDistance(touchPos, ringPos); this._distance = distance; if (this._radius > distance) { this.mDot.setPosition(touchPos); } else { //控杆永远保持在圈内,并在圈内跟随触摸更新角度 let radian = CMath.getAngle(ringPos, touchPos); let x = ringPos.x + Math.cos(radian) * this._radius; let y = ringPos.y + Math.sin(radian) * this._radius; this.mDot.setPosition(cc.v2(x, y)); } //更新角度 this.updateAngle(); } private getDisTance(): number { if (this._distance > this._radius) { return 1; } else { return this._distance / this._radius; } } private _touchEndEvent() { this.mDot.setPosition(this.mRing.getPosition()); this._angle = 0; if (this.callback) { this.callback(false, { x: 0, y: 0 }, 0); } this.mDir.opacity = 0; this.mDot.opacity = 100; } private onKeyPressed(event) { let keyCode = event.keyCode; switch (keyCode) { case cc.macro.KEY.w: case cc.macro.KEY.up: this.tmpDir.y = 1; break; case cc.macro.KEY.s: case cc.macro.KEY.down: this.tmpDir.y = -1; break; case cc.macro.KEY.a: case cc.macro.KEY.left: this.tmpDir.x = -1; break; case cc.macro.KEY.d: case cc.macro.KEY.right: this.tmpDir.x = 1; break; } this.reviseValue(); } private onKeyReleased(event) { let keyCode = event.keyCode; switch (keyCode) { case cc.macro.KEY.w: case cc.macro.KEY.up: this.tmpDir.y = 0; break; case cc.macro.KEY.s: case cc.macro.KEY.down: this.tmpDir.y = 0; break; case cc.macro.KEY.a: case cc.macro.KEY.left: this.tmpDir.x = 0; break; case cc.macro.KEY.d: case cc.macro.KEY.right: this.tmpDir.x = 0; break; } this.reviseValue(); } private reviseValue() { if (this.callback) { if (this.tmpDir.x == 0 && this.tmpDir.y == 0) { this.callback(false, { x: 0, y: 0 }, 0); } else { let angle = Math.atan2(this.tmpDir.y, this.tmpDir.x); this.callback(true, { x: this.tmpDir.x, y: this.tmpDir.y }, angle); } } } private updateAngle() { let p1 = this.mRing.getPosition(); let p2 = this.mDot.getPosition(); let angle = Math.atan2(p2.y - p1.y, p2.x - p1.x); this.mDir.angle = angle * 180 / Math.PI; this._angle = angle; let xx = this.getDir(this.mDir.angle) if (this.callback) { this.callback(true, xx, angle); } return this._angle; } //计算两点间的距离并返回 private _getDistance(pos1: cc.Vec2, pos2: cc.Vec2) { return Math.sqrt(Math.pow(pos1.x - pos2.x, 2) + Math.pow(pos1.y - pos2.y, 2)); } /** * 根据弧度获取方向 * @param angle */ private getDir(angle: number) { if (angle >= -30 && angle < 30) { return { x: 1.4, y: 0 } } else if (angle >= 30 && angle < 60) { return { x: 1, y: 1 } } else if (angle >= 60 && angle < 120) { return { x: 0, y: 1.4 } } else if (angle >= 120 && angle < 150) { return { x: -1, y: 1 } } else if (angle >= 150 && angle < 180) { return { x: -1.4, y: 0 } } else if (angle >= -180 && angle < -150) { return { x: -1.4, y: 0 } } else if (angle >= -150 && angle < -120) { return { x: -1, y: -1 } } else if (angle >= -120 && angle < -60) { return { x: 0, y: -1.4 } } else if (angle >= -60 && angle < -30) { return { x: 1, y: -1 } } else { return { x: 0, y: 0 } } } }