两段代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FairyGUI;
using DG.Tweening;
public class JoyStick : EventDispatcher
{
//事件监听者
public EventListener onMove { get; private set; }
public EventListener onEnd { get; private set; }
//mainUI里的对象
private GButton joyStickButton;
private GObject thumb;
private GObject touchArea;
private GObject center;
//摇杆的属性
private float initX;
private float initY;
private float startStageX;
private float startStageY;
private float lastStageX;
private float lastStageY;
private int touchID;
private Tweener tweener;
public int radius { get; set; }
public JoyStick(GComponent mainUI)
{
onMove = new EventListener(this, "onMove");
onEnd = new EventListener(this, "onEnd");
joyStickButton = mainUI.GetChild("joyStick").asButton;
joyStickButton.changeStateOnClick = false;
thumb = joyStickButton.GetChild("thumb");
touchArea = mainUI.GetChild("triggleArea");
center = mainUI.GetChild("joyStickCenter");
initX = center.x + center.width / 2;
initY = center.y + center.height / 2;
touchID = -1;
radius = 150;
touchArea.onTouchBegin.Add(OnTouchBegin);
touchArea.onTouchMove.Add(OnTouchMove);
touchArea.onTouchEnd.Add(OnTouchEnd);
}
private void OnTouchBegin(EventContext context)
{
if (touchID == -1)
{
InputEvent inputEvent = (InputEvent)context.data;
touchID = inputEvent.touchId;
if (tweener != null)
{
tweener.Kill();
tweener = null;
}
Vector2 localPos = GRoot.inst.GlobalToLocal(new Vector2(inputEvent.x, inputEvent.y));
float posX = localPos.x;
float posY = localPos.y;
joyStickButton.selected = true;
lastStageX = posX;
lastStageY = posY;
startStageX = posX;
startStageY = posY;
center.visible = true;
center.SetXY(posX - center.width / 2, posY - center.height / 2);
joyStickButton.SetXY(posX - joyStickButton.width / 2, posY - joyStickButton.height / 2);
float deltax = posX - initX;
float deltay = posY - initY;
float degrees = Mathf.Atan2(deltay, deltax) * 180 / Mathf.PI;
thumb.rotation = degrees;
context.CaptureTouch();
}
}
private void OnTouchMove(EventContext context)
{
InputEvent inputEvent = (InputEvent)context.data;
if (touchID != -1 && inputEvent.touchId == touchID)
{
Vector2 localPos = GRoot.inst.GlobalToLocal(new Vector2(inputEvent.x, inputEvent.y));
float posX = localPos.x;
float posY = localPos.y;
float moveX = posX - lastStageX;
float moveY = posY - lastStageY;
lastStageX = posX;
lastStageY = posY;
float buttonX = joyStickButton.x + moveX;
float buttonY = joyStickButton.y + moveY;
float deltaX = buttonX + joyStickButton.width / 2 - startStageX;
float deltaY = buttonY + joyStickButton.width / 2 - startStageY;
float rad = Mathf.Atan2(deltaY, deltaX);
float degree = rad * 180 / Mathf.PI;
thumb.rotation = degree;
float maxX = radius * Mathf.Cos(rad);
float maxY = radius * Mathf.Sin(rad);
if (Mathf.Abs(deltaX) > Mathf.Abs(maxX))
{
deltaX = maxX;
}
if (Mathf.Abs(deltaY) > Mathf.Abs(maxY))
{
deltaY = maxY;
}
buttonX = startStageX + deltaX;
buttonY = startStageY + deltaY;
joyStickButton.SetXY(buttonX - joyStickButton.width / 2, buttonY - joyStickButton.height / 2);
onMove.Call(degree);
}
}
private void OnTouchEnd(EventContext context)
{
InputEvent inputEvent = (InputEvent)context.data;
if (touchID != -1 && inputEvent.touchId == touchID)
{
touchID = -1;
thumb.rotation = thumb.rotation + 180;
center.visible = false;
tweener = joyStickButton.TweenMove(new Vector2(initX - joyStickButton.width / 2, initY - joyStickButton.height / 2), 0.3f).OnComplete(() =>
{
tweener = null;
joyStickButton.selected = false;
thumb.rotation = 0;
center.visible = true;
center.SetXY(initX - center.width / 2, initY - center.height / 2);
});
}
onEnd.Call();
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using FairyGUI;
public class JoyStickMain : MonoBehaviour
{
private GComponent mainUI;
private GTextField gTextField;
private JoyStick joyStick;
// Start is called before the first frame update
void Start()
{
mainUI = GetComponent<UIPanel>().ui;
gTextField = mainUI.GetChild("T5").asTextField;
joyStick = new JoyStick(mainUI);
joyStick.onMove.Add(Move);
joyStick.onEnd.Add(End);
}
// Update is called once per frame
void Update()
{
}
private void Move(EventContext context)
{
float degree = (float)context.data;
gTextField.text = degree.ToString();
}
private void End()
{
gTextField.text = "";
}
}
首先是EventListener:用来对事件调用回调函数的
如:
//第一段代码中定义和初始化:
public EventListener onMove { get; private set; }
public EventListener onEnd { get; private set; }
onMove = new EventListener(this, "onMove");
onEnd = new EventListener(this, "onEnd");
//第二段代码中添加回调函数:
joyStick.onMove.Add(Move);
joyStick.onEnd.Add(End);
//第一段代码中调用:
onMove.Call(degree);
onEnd.Call();
初始化需要说明一下:第一个参数是该事件侦听器的拥有者,第二个参数侦听事件的类型,不能乱写
关于回调函数:就是在某个事件发生后去调用的一个函数,有两种形式,两种形式的使用方法都是相同的,差别在于不带参数或带一个参数,只是为了方便在不需要用到EventContext时少写一点而已
如:
private void Move(EventContext context)
{
float degree = (float)context.data;
gTextField.text = degree.ToString();
}
private void End()
{
gTextField.text = "";
}
关于EventContext:该类中包含了一些事件中可能会用到的信息,如输入信息(也就是InputEvent)等
关于InputEvent:包含了键盘事件和鼠标/触摸事件的一些数据
如:
InputEvent inputEvent = (InputEvent)context.data;
注意context是一个EventContext类型的变量,这句话的意思就是将context中的data属性中的数据包装为一个InputEvent类型的变量。data:事件的数据。根据事件不同,可以有不同的含义
joyStickButton.changeStateOnClick = false;
将按钮的自动切换状态关闭
touchArea.onTouchBegin.Add(OnTouchBegin);
touchArea.onTouchMove.Add(OnTouchMove);
touchArea.onTouchEnd.Add(OnTouchEnd);
对touchArea对象的开始移动,移动中,结束移动事件添加回调函数
touchID = inputEvent.touchId;
inputEvent.touchId:当前事件相关的手指ID;在PC平台,该值为0,没有意义。
private Tweener tweener;
if (tweener != null)
{
tweener.Kill();
tweener = null;
}
tweener = joyStickButton.TweenMove(new Vector2(initX - joyStickButton.width / 2, initY - joyStickButton.height / 2), 0.3f).OnComplete(() =>
{
tweener = null;
joyStickButton.selected = false;
thumb.rotation = 0;
center.visible = true;
center.SetXY(initX - center.width / 2, initY - center.height / 2);
});
Tweener:和缓动有关的一个类 。Kill()命令将当前tweener的缓动效果给删除,然后再设为空。下面是为joyStickButton对象添加缓动效果,同时将该缓动效果赋值给tweener。TweenMove的两个参数第一个是目标位置,第二个是所用时间
OnComplete是缓动执行完之后调用其中的函数
Selected表示按钮是否已被点击
Vector2 localPos = GRoot.inst.GlobalToLocal(new Vector2(inputEvent.x, inputEvent.y));
将屏幕坐标(点击的位置)转换为本地坐标(理想中的位置)
Mathf.Atan2(deltay, deltax)
将其中的正切值转换为弧度
context.CaptureTouch();
再OnTouchBegin中调用,用来捕获Move和End事件的,没有它OnTouchMove将不会触发,OnTouchEnd可能不会触发,详细请参考:http://www.fairygui.com/guide/unity/input.html
private GTextField gTextField;
对应于文本框组件的类
参考:http://www.fairygui.com/guide/unity/event.html
http://www.fairygui.com/guide/unity/input.html
https://baike.baidu.com/item/%E4%BA%8B%E4%BB%B6/6129089#viewPageContent