兩段代碼:
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