目录
搭建UI
编写代码
搭建UI
?①创建一个image 命名为?ControlArea 作为按钮识别的检测范围 并将透明度设置为1(透明度为0不触发事件检测)
②如下图的父子关系添加 image 并命名 找到合适的素材拖给相应的image? 设置合适的大小(根据自己的喜好和素材的大小自行设置)
③注意选中joystick 的 锚点(花)放到左下角 防止因为分辨率改变使得按钮位置改变? 中心点(pivot)的位置设置为(0.5,0.5)如下图
?
实现脚本
①使用单例UIManger 对某些公共方法进行管理
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
public class UIManger : MonoBehaviour
{
public static UIManger Instance;
public static UIManger GetInstance()
{
if (Instance == null)
{
Instance = new UIManger();
}
return Instance;
}
public static void AddCustomEnventListener(UIBehaviour contral, EventTriggerType type, UnityAction<BaseEventData> callback)
{
EventTrigger trigger = contral.GetComponent<EventTrigger>();
if (trigger == null)
trigger = contral.gameObject.AddComponent<EventTrigger>();
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = type;
entry.callback.AddListener(callback);
trigger.triggers.Add(entry);
}
}
②事件分发器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
//事件分发器
public class EventCenter : MonoBehaviour
{
//声明一个带参数的委托
public delegate void CallBack<T>(T t);
//声明一个字典 事件码与事件进行绑定
public static Dictionary<string, Delegate> m_EventTable = new Dictionary<string, Delegate>();
/// <summary>
/// 添加监听的方法
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="str">事件码</param>
/// <param name="callBack">泛型为委托</param>
public static void Addlistener<T>(string str , CallBack<T> callBack)
{
//
if (!m_EventTable.ContainsKey(str))
{
m_EventTable.Add(str,null);
}
Delegate d = m_EventTable[str];
if (d != null && d.GetType() != callBack.GetType())
{
throw new Exception("监听添加错误!!");
}
//订阅事件
m_EventTable[str] = (CallBack<T>)m_EventTable[str] + callBack;
}
/// <summary>
/// 移除监听的方法
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="str">事件码</param>
/// <param name="callBack">泛型委托</param>
public static void RemoveListener<T>(string str, CallBack<T> callBack)
{
if (m_EventTable.ContainsKey(str))
{
Delegate d = m_EventTable[str];
if (d == null)
{
throw new Exception(string.Format("监听移除失败,事件{0}没有委托", str));
}
else if (d.GetType() != callBack.GetType())
{
throw new Exception(string.Format("监听移除失败,事件类型不对应{0},{1}", str.GetType(), callBack.GetType()));
}
}
else
{
throw new Exception(string.Format("监听移除失败,没有事件码{0}", str));
}
//取消订阅
m_EventTable[str] = (CallBack<T>)m_EventTable[str] - callBack;
if (m_EventTable[str] == null)
{
m_EventTable.Remove(str);
}
}
/// <summary>
/// 广播
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
/// <param name="str">事件码</param>
/// <param name="arg">T 的参数</param>
public static void BroadCast<T>(string str,T arg)
{
Delegate d;
if (m_EventTable.TryGetValue(str, out d))
{
CallBack<T> callBack = d as CallBack<T>;
if (d != null)
{
callBack(arg);
}
else { throw new Exception("广播错误!!!"); }
}
}
}
③将下面的脚本该再到?ControlArea 上去
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class JoystickContral : UIManger
{
public float MaxL;
private Image ControlBK;
private Image Joystick;
private Image Handle;
// Start is called before the first frame update
void Start()
{
//根据按钮的中心到按钮父物体边界的距离
MaxL = 75;
//控制按钮监听的范围
ControlBK = this.GetComponent<Image>();
Joystick = transform.Find("Joystick").GetComponent<Image>();
Handle = transform.GetChild(0).GetChild(0).GetComponent<Image>();
//添加自定义事件监听的方法 把对应的函数和 事件 关联起来
UIManger.AddCustomEnventListener(ControlBK, EventTriggerType.PointerDown, PointerDown);
UIManger.AddCustomEnventListener(ControlBK, EventTriggerType.PointerUp, PointerUp);
UIManger.AddCustomEnventListener(ControlBK, EventTriggerType.Drag, Drag);
}
private void PointerDown(BaseEventData data)
{
//Debug.Log("我被按下了");
}
private void PointerUp(BaseEventData data)
{
Handle.transform.localPosition = Vector3.zero;
//Debug.Log("我抬起来了");
EventCenter.BroadCast<Vector2>("JC", Vector2.zero);
}
private void Drag(BaseEventData data)
{
Vector2 localPos;
//将一个屏幕空间点转换为 RectTransform 的本地空间中位于其矩形平面上的一个位置(将其转换为ControlBK 范围内的位置)
RectTransformUtility.ScreenPointToLocalPointInRectangle(
Joystick.rectTransform,//你想改变位置对象(handle)的 父对象(joystick)
(data as PointerEventData).position,//得到当前鼠标的位置
(data as PointerEventData).enterEventCamera,//UI用的摄像机
out localPos);//的到一个转换来的 相对坐标
Handle.transform.localPosition = localPos;
if (localPos.magnitude > MaxL)
Handle.transform.localPosition = localPos.normalized * MaxL;
//EventCenter.Addlistener<Vector2>("yaogan", localPos.normalized);
EventCenter.BroadCast<Vector2>("JC", localPos.normalized);
}
}
④测试脚本 挂载到要移动的物体上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class text : MonoBehaviour
{
private Vector3 dir;
// Start is called before the first frame update
private void Awake()
{
EventCenter.Addlistener<Vector2>("JC", CheckDirChange);
}
private void OnDestroy()
{
EventCenter.RemoveListener<Vector2>("JC", CheckDirChange);
}
// Update is called once per frame
void Update()
{
this.transform.Translate(dir*Time.deltaTime, Space.World);
}
private void CheckDirChange(Vector2 dir)
{
this.dir.x = dir.x;
this.dir.z = dir.y;
}
}
|