國際慣例,先上效果圖:
一、場景佈置:
ok,下面將介紹如果實現搖桿操作物體,在這裏我會創建一個res的文件夾用來存放這三張圖:
創建一個but節點掛到場景節點下,分別將內圓和外圓的圖片掛載到該節點下,更名爲out_cricle和in_cricle,再將飛機的圖片掛到與but節點同級的節點下並更名爲obj,然後全部轉換類型爲image類型,並全部設置錨點爲0.5的位置:
Ok,場景基礎就這樣:
- 編寫代碼組件:
去到代碼編輯器界面,在src下創建一個scprit的文件夾,再創建一個名爲but的typescript代碼模板,將組件掛到but節點下:
在but.ts中分別創建四個屬性:max_r(搖桿移動最大範圍)、min_r(搖桿移動最小範圍)、but(搖桿節點)、obj(移動的物體):
/** @prop {name:max_r, tips:"按鈕最大範圍", type:Int, default:90}*/
public max_r: number = 78;
/** @prop {name:min_r, tips:"按鈕最小範圍", type:Int, default:30}*/
public min_r: number = 40;
/** @prop {name:but, tips:"按鈕", type:Node, default:null}*/
public but: Laya.Node;
/** @prop {name:obj, tips:"物體", type:Node, default:null}*/
public obj: Laya.Node;
我這裏自己調整了下圖片大小,最大範圍設爲78,最小範圍爲40,接下來再定義三個變量:
private is_start:boolean = false;
private speed:number = 200;
private v:Laya.Point = Laya.Point.create();
(1)Is_start用於標識按鈕是否按下觸發了Laya.Event.MOUSE_DOWN事件,如果按鈕按下再(2)is_sart設置爲true.
(3)speed用來設置物體移動的速度
v用來存儲搖桿移動的位置信息,後面要賦給物體使用。
可能有的讀者有疑問:當物體觸發MOUSE_DOWN事件之後應該自動會切換到MOUSE_MOVE事件,爲什麼還要特地聲明一個變量來標記?
其實是因爲我們平時在操控搖桿的時候,搖桿必然會移動到搖桿的範圍之外去,但是如果觸碰到了外面,搖桿節點就會一直卡死在最後的位置,導致物體不停按最後給的觸碰信息進行移動:
所以爲了解決這個問題,我們將MOUSE_MOVE和MOUSE_UP事件全用Laya.stage來監聽,搖桿本身來監聽MOUSE_DOWN:
this.but.on(Laya.Event.MOUSE_DOWN,this,this.but_down);
Laya.stage.on(Laya.Event.MOUSE_MOVE,this,this.but_move);
Laya.stage.on(Laya.Event.MOUSE_UP,this,this.but_up);
然後分別創建三個監聽返回的回調用函數:but_down、but_move、but_up,接下來就是寫組件的基本邏輯:
- 按鈕按下:is_start標記爲true,表示開始移動。
- 按鈕移動:將移動返回的觸碰信息保存到變量,後面用來驅動物體移動,判斷搖桿是否超出規定範圍,如果超過再限定在圈內。
- 按鈕彈起:關閉is_start,按鈕返回原點位置。
- 重寫onUpdate()方法,將保存的變量拿出來做相關速度運算再賦給物體,之後通過Math.atan2()算出旋轉的信息,將弧度轉成角度賦給物體。
下面是全部代碼,註釋有詳細說明:
export default class but extends Laya.Script {
/** @prop {name:max_r, tips:"按鈕最大範圍", type:Int, default:90}*/
public max_r: number = 78;
/** @prop {name:min_r, tips:"按鈕最小範圍", type:Int, default:30}*/
public min_r: number = 40;
/** @prop {name:but, tips:"按鈕", type:Node, default:null}*/
public but: Laya.Node;
/** @prop {name:obj, tips:"物體", type:Node, default:null}*/
public obj: Laya.Node;
private is_start:boolean = false;
private speed:number = 200;
private v:Laya.Point = Laya.Point.create();
constructor() { super(); }
onAwake(){
this.but.on(Laya.Event.MOUSE_DOWN,this,this.but_down);
Laya.stage.on(Laya.Event.MOUSE_MOVE,this,this.but_move);
Laya.stage.on(Laya.Event.MOUSE_UP,this,this.but_up);
}
but_down(e){
if(this.is_start == true){
return;
}
this.is_start = true;
}
but_move(e){
if(this.is_start ==false){
return;
}
//因爲要使用x、y座標相關方法,將搖桿節點和but節點轉爲Laya.Sprite
var node:Laya.Sprite = this.owner as Laya.Sprite;
var but_node:Laya.Sprite = this.but as Laya.Sprite;
//創建一個Laya.Point的變量存儲在鼠標移動後全局返回的x、y座標,將這個座標轉到組件所在節點的局部座標系下
var mouse_pos:Laya.Point = Laya.Point.create();
mouse_pos.x = Laya.MouseManager.instance.mouseX;
mouse_pos.y = Laya.MouseManager.instance.mouseY;
node.globalToLocal(mouse_pos);
//算出x、y到原點的距離,算出sin(x)和cos(y)的比例係數
//得到一個固定值,再使用上面聲明的變量v來存儲轉完後的信息:
var length = mouse_pos.distance(0,0);
this.v.x = mouse_pos.x / length;
this.v.y = mouse_pos.y / length;
//判斷是否超出搖桿最大範圍
if(length > this.max_r){
mouse_pos.x = mouse_pos.x * this.max_r / length;
mouse_pos.y = mouse_pos.y * this.max_r / length;
}//判斷是否超出搖桿最小範圍
else if(length < this.min_r){
but_node.pos(mouse_pos.x,mouse_pos.y);
return;
}
but_node.pos(mouse_pos.x,mouse_pos.y);
}
but_up(e){
if(this.is_start == false){
return;
}
var but_node:Laya.Sprite = this.but as Laya.Sprite;
var obj_node:Laya.Sprite = this.obj as Laya.Sprite;
but_node.pos(0,0); //搖桿彈起返回原點位置
this.is_start = false; //關閉監聽狀態
this.v.x = 0;
this.v.y = 0;
}
onUpdate(){
if(this.v.x == 0 && this.v.y == 0){
return;
}
var dt = Laya.timer.delta / 1000;
var obj_node:Laya.Sprite = this.obj as Laya.Sprite;
//給物體賦x、y的移動信息
obj_node.x += (this.v.x * this.speed) * dt;
obj_node.y += (this.v.y * this.speed) * dt;
var rot:number = 180 / Math.PI;
var deg:number = Math.atan2(this.v.y,this.v.x);
//給物體賦x、y的旋轉信息
obj_node.rotation = rot * deg + 90 ;
}
}