项目结构如下图:

1.说明:为了测试方便我都把两个脚本挂载到了Canvas上了。加了三个精灵组件一个dayuan(大圆),就是大浅蓝色的,作为摇杆盘,一个xiaoyuan(小圆)就是深蓝色的作为摇杆,还有一个feidie(飞碟)作为被控制的角色。其中xiaoyuan精灵节点时dayuan的子节点。

2.把下面两个脚本组件都挂在到Canvas上

摇杆代码Joystick.ts

import { _decorator, Component, Node, Vec3, Touch, UITransform, v3 } from 'cc';
const { ccclass, property } = _decorator;

/**
 * Predefined variables
 * Name = JoyStick
 * DateTime = Mon Jun 20 2022 14:42:05 GMT+0800 (中国标准时间)
 * Author = fangfan001
 * FileBasename = JoyStick.ts
 * FileBasenameNoExtension = JoyStick
 * URL = db://assets/scripts/JoyStick.ts
 * ManualUrl = https://docs.cocos.com/creator/3.4/manual/zh/
 *
 */

@ccclass('JoyStick')
export class JoyStick extends Component {
    //大圆
    @property(Node)
    panel: Node = null;
    //小圆
    @property(Node)
    btn: Node = null;

    //小圆在大圆中移动的限制距离
    private panelWidth: number = 100;
    //大圆初始位置
    private panelInitPos: Vec3;

    //触摸ID
    private touchID: number;

    //用于保存移动方向向量
    public dir: Vec3 = new Vec3(0, 0, 0);
    //保存弧度(角度)
    public angle: number = 0;

    //是否正在移动
    public moving: boolean = false;

    onLoad() {
        //初始化大圆的为止
        this.panelInitPos = new Vec3(-250, -150, 0);
    }

    start() {
        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.onTouchCancel, this);
    }

    public stop() {
        this.node.off(Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.node.off(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.node.off(Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.node.off(Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this);

        this.moving = false;
        this.enabled = false;
    }

    private onTouchStart(e: Touch) {

        //触摸点世界坐标转成局部坐标
        let uiTransform = this.node.getComponent(UITransform);
        let p = new Vec3(e.getLocation().x, e.getLocation().y, 0);
        let pos = new Vec3();
        uiTransform.convertToNodeSpaceAR(p, pos);

        //当触摸时设置大圆和小圆的显示位置
        this.panel.setPosition(pos);
        this.btn.setPosition(new Vec3(0, 0, 0));
        this.touchID = e.getID();
        this.moving = false;
        this.enabled = true;
    }

    private onTouchMove(e: Touch) {


        if (this.touchID != e.getID()) {
            return;
        }
        //小圆移动,改变小圆实时位置
        let posDelta = e.getDelta();
        console.log("posDelta", this.btn.getPosition());
        let x = this.btn.getPosition().x + posDelta.x;
        let y = this.btn.getPosition().y + posDelta.y;
        //console.log("posDelta",x,y);
        this.btn.setPosition(new Vec3(x, y, 0));
        //正在移动
        this.moving = true;
    }

    update() {

        if (this.moving) {
            //将小圆限制大圆范围内
            console.log("this.btn.position", this.btn.position);
            let ratio = this.btn.position.length() / this.panelWidth;
            let xbi = this.btn.position.x / this.btn.position.length();
            let ybi = this.btn.position.y / this.btn.position.length();
            console.log("ratio", this.btn.position.length());
            if (ratio > 1) {

                this.btn.setPosition(new Vec3(xbi * this.panelWidth, ybi * this.panelWidth, 0));
            }
            //保存向量方向
            this.dir = new Vec3(xbi, ybi, 0);
            console.log("this.dir", this.dir);
            //获取弧度
            this.angle = Math.atan2(this.btn.getPosition().y, this.btn.getPosition().x);
        }
    }

    private onTouchEnd(e: Touch) {
        //还原大圆和小圆位置
        if (this.touchID != e.getID()) {
            return;
        }
        this.panel.setPosition(this.panelInitPos);
        this.btn.setPosition(new Vec3(0, 0, 0));
        this.moving = false;
        this.enabled = false;
    }

    private onTouchCancel(e: Touch) {
        if (this.touchID != e.getID()) {
            return;
        }
        this.panel.setPosition(this.panelInitPos);
        this.btn.setPosition(0, 0);
        this.moving = false;
        this.enabled = false;
    }

    onDestroy() {
        this.stop();
    }

}

初始化代码组件:

yaogan.ts

import { _decorator, Component, Node, Vec3 } from 'cc';
const { ccclass, property } = _decorator;
//import { JoyStick } from './JoyStick';

/**
 * Predefined variables
 * Name = yaogan
 * DateTime = Mon Jun 20 2022 10:20:08 GMT+0800 (中国标准时间)
 * Author = fangfan001
 * FileBasename = yaogan.ts
 * FileBasenameNoExtension = yaogan
 * URL = db://assets/scripts/yaogan.ts
 * ManualUrl = https://docs.cocos.com/creator/3.4/manual/zh/
 *
 */

@ccclass('yaogan')
export class yaogan extends Component {
    //虚拟摇杆组件
    joyStick: any = null;

    //角色
    @property(Node)
    role: Node = null;
    //速度
    speed: Vec3 = new Vec3(6, 6, 0);

    onLoad() {
        this.joyStick = this.node.getComponent("JoyStick");
    }

    start() {

    }

    update() {
        if (this.joyStick.moving) {
            //根据角度移动
            let x = this.role.getPosition().x + Math.cos(this.joyStick.angle) * this.speed.x;
            let y = this.role.getPosition().y + Math.sin(this.joyStick.angle) * this.speed.y;
            //根据向量移动
            // let x = this.role.getPosition().x+this.joyStick.dir.x*this.speed.x;
            // let y = this.role.getPosition().y+this.joyStick.dir.y*this.speed.y;

            this.role.setPosition(new Vec3(x, y, 0));
        }
    }
}

3.将组件代码挂载后,将精灵节点拖到对应的节点框,保存场景后运行即可

4.如果谁有更好的实现虚拟摇杆的方法,请给我留言,给我传授传授经验。谢谢抱拳

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐