Cocos Creator之摇杆的实现

一 , 数学准备

    Ⅰ, 三角函数
node

        B02.png

ox1/ox = oy1/oy (类似三角形)ide

二 , 关于弧度 Math.atan2 在-PI (3,4象限)到 PI(1,2象限) 之间 . 若是要在3,4象限获得正值, 则须要使用 2PI - X的方式. 角度也是同样, 代码以下:

/**
 * 获取方向弧度
 */
public getRadian(): number {
    if( this.dir.x == 0 && this.dir.y == 0){
        return 0;
    }
    let radian: number =  Math.atan2( this.dir.y ,this.dir.x );
    if( radian >= 0 ) return radian;
    return 2*Math.PI + radian;
}

/**
 * 获取方向角度
 */
public getAngle(): number{
    let angle: number = this.getRadian()/ Math.PI * 180;
    if( angle >= 0 ) return angle;
    return 360 + angle;
}

三, 层级管理器以下

B03.png

场景设计以下图, 能够看到要把stick限制在bg内须要用到类似三角形的原理, 部分代码以下:函数

let screenPos: Vec2 = e.getLocation();//获取屏幕坐标(stick所在的)
let pos: Vec3 = (this.node.getComponent(UITransform) as UITransform).convertToNodeSpaceAR( v3( screenPos.x, screenPos.y, 0 ));//转joystick和bg同样
let len: number = Vec2.len( v2(pos.x,pos.y) );//求模
this.dir.x = pos.x / len;//cos x
this.dir.y = pos.y / len;//sin y
if( len > this.maxR ){
    pos.x = pos.x * this.maxR/len;
    pos.y = pos.y * this.maxR/len;
}else if( len < this.minR && this.minR > 0){
    pos.x = pos.x * this.minR/len;
    pos.y = pos.y * this.minR/len;
}
this.stick.setPosition( pos.x,pos.y);

 

B04.png

四, 所有代码

import { _decorator, Component, Node, log, EventTouch, Vec2, UITransform, Vec3, v3, v2 } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('JoyStickCtr')
export class JoyStickCtr extends Component {
    @property( { type: Node }  )
    // @ts-ignore
    private stick: Node;
    @property
    private maxR: number = 128;//最大移动半径
    @property
    private minR: number = 20;//最小移动半径
    //@ts-ignore
    private dir: Vec2;

    onEnable(){
        this.listener( true );
    }
    onDisable(){
        this.listener( false );
    }


    private listener( isAdd: boolean ): void {
        if( isAdd ) {
            this.stick.on( Node.EventType.TOUCH_START, this.onTouchHandler, this);
            this.stick.on( Node.EventType.TOUCH_MOVE, this.onTouchHandler, this);
            this.stick.on( Node.EventType.TOUCH_END, this.onTouchHandler, this);
            this.stick.on( Node.EventType.TOUCH_CANCEL, this.onTouchHandler, this);
        }else{
            this.stick.off( Node.EventType.TOUCH_START, this.onTouchHandler, this);
            this.stick.off( Node.EventType.TOUCH_MOVE, this.onTouchHandler, this);
            this.stick.off( Node.EventType.TOUCH_END, this.onTouchHandler, this);
            this.stick.off( Node.EventType.TOUCH_CANCEL, this.onTouchHandler, this);
        }
    }
    private onTouchHandler( e : EventTouch): void{
        switch (e.type){
            case Node.EventType.TOUCH_START:
                break;
            case Node.EventType.TOUCH_MOVE:
                let screenPos: Vec2 = e.getLocation();//获取屏幕坐标(stick所在的)
                let pos: Vec3 = (this.node.getComponent(UITransform) as UITransform).convertToNodeSpaceAR( v3( screenPos.x, screenPos.y, 0 ));//转joystick和bg同样
                let len: number = Vec2.len( v2(pos.x,pos.y) );//求模
                this.dir.x = pos.x / len;//cos x
                this.dir.y = pos.y / len;//sin y
                if( len > this.maxR ){
                    pos.x = pos.x * this.maxR/len;
                    pos.y = pos.y * this.maxR/len;
                }else if( len < this.minR && this.minR > 0){
                    pos.x = pos.x * this.minR/len;
                    pos.y = pos.y * this.minR/len;
                }
                this.stick.setPosition( pos.x,pos.y);
                break;
            case Node.EventType.TOUCH_END:
            case Node.EventType.TOUCH_CANCEL:
                this.stick.setPosition(0,0);
                this.dir.x = this.dir.y = 0;
                break;
        }
    }
    /**
     * 获取方向向量
     */
    public getDir(): Vec2{
        return this.dir;
    }

    /**
     * 获取方向弧度(0~2PI)
     */
    public getRadian(): number {
        if( this.dir.x == 0 && this.dir.y == 0){
            return 0;
        }
        let radian: number =  Math.atan2( this.dir.y ,this.dir.x );
        if( radian >= 0 ) return radian;
        return 2*Math.PI + radian;
    }

    /**
     * 获取方向角度(0~360)
     */
    public getAngle(): number{
        let angle: number = this.getRadian()/ Math.PI * 180;
        if( angle >= 0 ) return angle;
        return 360 + angle;
    }

    start () {
        this.dir = v2(0,0);
        // this.listener( true );
    }

    // update (deltaTime: number) {
    //     // [4]
    // }
}



注: 使用Cocos Creator 3.0.1 引擎this