版本:2.3.4
參考:
【持續更新】Cocos Creator源碼分享——針對遊戲中的各種功能
下載下傳:
虛拟搖杆demo_cocos2.3.4
在cocos論壇找了一篇虛拟搖杆的制作文章。但是實際使用還要考慮多一些。這裡在原來代碼基礎上做了一些改動。
1. 監聽事件不使用字元串。例如"touchstart",使用cc.Node.EventType.TOUCH_START。因為使用字元串容易拼錯。
2. 增加觸摸響應區域。因為正常遊戲中,虛拟搖杆可響應範圍不僅僅是虛拟搖杆圖檔範圍,而是一個可根據策劃需求調整的範圍,例如今天500x400,明天覺得600x400,隻需要修改代碼,不需要重新制作圖檔了。
3. 防止多點觸摸。增加了touchID的判斷,防止多個手指觸摸導緻的問題。例如一個手指在操作搖杆,另一個手指不小心在觸摸區域點選了一下,導緻觸發了touch_end,使搖杆失效。
4. 增加了小圓移動範圍設定。原來文章用大圓圖檔的高寬限制小圓的移動範圍。但是大圓圖檔可能有透明區域,是以這裡小圓的移動範圍在代碼裡手動設定。
5.增加了搖杆是否正在移動的标志位。因為搖杆沒有在使用的時候,不需要去執行角色的移動計算。是以增加了moving來表示搖杆是否在運作中,減少搖杆空閑時對角色移動的計算量。
6.增加了角度(弧度)計算。因為可能根據搖杆的角度,進行一些操作。例如人物如果是八方向或四方向,需要根據角度轉向。如果不需要,可以自行屏蔽角度的代碼。
7.增加了enable開關。在虛拟搖杆沒有操作的時候,不需要執行update,較少計算量。
UI如下圖,為了友善area用綠色顯示,實際使用去掉就行了。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5yMzMWZlF2MkRDMlNGM4IWM3MDOiRjZzAzYxQzM1IGN58CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
虛拟搖杆代碼
// 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;
}
}
}
示範效果