国际惯例,先上效果图:
一、场景布置:
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 ;
}
}