import { _decorator, Node, UITransform, v3, v2, misc, Component, EventTouch, Vec2, Sprite, SpriteFrame } from "cc";

const { ccclass, property } = _decorator;

/**
 * 角度控制按钮组件
 */
@ccclass("Joystick")
export class Joystick extends Component {

    @property(Node)
    private handle: Node = null;

    @property(Sprite)
    private bg: Sprite = null;

    @property(SpriteFrame) normalSp: SpriteFrame = null;
    @property(SpriteFrame) pressedSp: SpriteFrame = null;

    private maxRadius = 100;

    /** 方向向量 */
    private dir: Vec2 = v2(0, 0);

    /** 当前角度 */
    public angle: number = 0;

    onLoad() {

        this.bg.spriteFrame = this.normalSp;

        this.maxRadius = this.getComponent(UITransform).contentSize.width / 2;

        // 注册触摸事件
        this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.node.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
    }

    /**
     * 触摸开始回调
     */
    onTouchStart(event: EventTouch) {
        this.calcPos(event.getUILocation());
        this.bg.spriteFrame = this.pressedSp;
    }

    /**
     * 触摸移动回调
     */
    onTouchMove(event: EventTouch) {
        this.calcPos(event.getUILocation());
    }

    /**
     * 触摸结束回调
     */
    onTouchEnd(event: EventTouch) {
        // 重置方向和圆点位置
        this.dir.x = this.dir.y = 0;
        this.handle.setPosition(0, 0);
        this.bg.spriteFrame = this.normalSp;
    }

    /**
     * 计算圆点位置和角度
     */
    calcPos = (() => {
        const worldPos = v3();
        const nodePos = v3();

        return (pos: Vec2) => {

            worldPos.x = pos.x;
            worldPos.y = pos.y;

            // 转换到节点本地坐标
            this.getComponent(UITransform).convertToNodeSpaceAR(worldPos, nodePos);
            nodePos.z = 0;

            // 计算长度并限制在最大半径内
            const len = nodePos.length();
            if (len > this.maxRadius) {
                nodePos.multiplyScalar(this.maxRadius / len);
            }

            this.handle.setPosition(nodePos);

            nodePos.normalize();

            this.dir.set(nodePos.x, nodePos.y);

            // 计算角度
            this.angle = this.vectorsToDegree(this.dir);
        };
    })();

    /**
     * 向量转角度
     */
    vectorsToDegree(vector: Vec2): number {
        const right = v2(1, 0);
        const radian = vector.signAngle(right);
        return misc.radiansToDegrees(radian);
    }
}