Cocos Creator 虚拟摇杆
版本:2.3.4
参考:
【持续更新】Cocos Creator源码分享——针对游戏中的各种功能
在cocos论坛找了一篇虚拟摇杆的制作文章。但是实际使用还要考虑多一些。这里在原来代码基础上做了一些改动。
1. 监听事件不使用字符串。例如"touchstart",使用cc.Node.EventType.TOUCH_START。因为使用字符串容易拼错。
2. 增加触摸响应区域。因为常规游戏中,虚拟摇杆可响应范围不仅仅是虚拟摇杆图片范围,而是一个可根据策划需求调整的范围,例如今天500x400,明天觉得600x400,只需要修改代码,不需要重新制作图片了。
3. 防止多点触摸。增加了touchID的判断,防止多个手指触摸导致的问题。例如一个手指在操作摇杆,另一个手指不小心在触摸区域点击了一下,导致触发了touch_end,使摇杆失效。
4. 增加了小圆移动范围设置。原来文章用大圆图片的高宽限制小圆的移动范围。但是大圆图片可能有透明区域,所以这里小圆的移动范围在代码里手动设置。
5.增加了摇杆是否正在移动的标志位。因为摇杆没有在使用的时候,不需要去执行角色的移动计算。所以增加了moving来表示摇杆是否在运作中,减少摇杆空闲时对角色移动的计算量。
6.增加了角度(弧度)计算。因为可能根据摇杆的角度,进行一些操作。例如人物如果是八方向或四方向,需要根据角度转向。如果不需要,可以自行屏蔽角度的代码。
7.增加了enable开关。在虚拟摇杆没有操作的时候,不需要执行update,较少计算量。
UI如下图,为了方便area用绿色显示,实际使用去掉就行了。
虚拟摇杆代码
// Learn TypeScript: // - https://docs.cocos.com/creator/manual/en/scripting/typescript.html // Learn Attribute: // - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html // Learn life-cycle callbacks: // - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html const {ccclass, property} = cc._decorator; @ccclass export default class JoyStick extends cc.Component { @property(cc.Node) panel:cc.Node = null; //大圆 @property(cc.Node) btn:cc.Node = null; //小圆 @property(cc.Integer) private panelWidth:number = 130; //去掉透明区域的大圆宽度 private panelInitPos:cc.Vec2; //大圆初始位置 private touchID:number; //触摸ID public dir:cc.Vec3 = new cc.Vec3(0,0,0); //移动方向 public angle:number = 0; //弧度(角度) public moving:boolean = false; //是否正在移动 onLoad(){ this.panelInitPos = new cc.Vec2(this.panel.x, this.panel.y); } start () { this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this); this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this); this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this); this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this); } public stop(){ this.node.off(cc.Node.EventType.TOUCH_START, this.onTouchStart, this); this.node.off(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this); this.node.off(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this); this.node.off(cc.Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this); this.moving = false; this.enabled = false; } private onTouchStart(e:cc.Touch){ console.log("start"); //触摸点世界坐标转成局部坐标 let pos = this.node.convertToNodeSpaceAR(e.getLocation()); this.panel.setPosition(pos); this.btn.setPosition(0,0); this.touchID = e.getID(); this.moving = false; this.enabled = true; } private onTouchMove(e:cc.Touch){ console.log("move"); if(this.touchID != e.getID()){ return; } //小圆移动 let posDelta = e.getDelta(); this.btn.x += posDelta.x; this.btn.y += posDelta.y; //正在移动 this.moving = true; } update(){ console.log("update"); if(this.moving){ //将小圆限制大圆范围内 let ratio = this.btn.position.mag() / this.panelWidth; if (ratio > 1) { this.btn.setPosition(this.btn.position.div(ratio)); } //获取向量归一化 this.dir = this.btn.position.normalizeSelf(); //获取弧度 this.angle = Math.atan2(this.btn.y, this.btn.x); } } private onTouchEnd(e:cc.Touch){ console.log("end"); if(this.touchID != e.getID()){ return; } this.panel.setPosition(this.panelInitPos); this.btn.setPosition(0,0); this.moving = false; this.enabled = false; } private onTouchCancel(e:cc.Touch){ console.log("cancel"); 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(); } }
实际操作
@ccclass export default class Helloworld extends cc.Component { //虚拟摇杆Area @property(cc.Node) joyStickArea:cc.Node = null; //虚拟摇杆代码 joyStick:JoyStick; //角色 @property(cc.Node) role:cc.Node = null; //速度 speed:cc.Vec2 = new cc.Vec2(5,5); onLoad(){ this.joyStick = this.joyStickArea.getComponent(JoyStick); } start() { } update(){ if(this.joyStick.moving){ //根据角度移动 // this.role.x += Math.cos(this.joyStick.angle)*this.speed.x; // this.role.y += Math.sin(this.joyStick.angle)*this.speed.y; //根据向量移动 this.role.x += this.joyStick.dir.x*this.speed.x; this.role.y += this.joyStick.dir.y*this.speed.y; } } }
演示效果