목차
UI 구축
①버튼 인식 감지 범위로 ControlArea라는 이름의 이미지를 생성하고 투명도를 1로 설정합니다 (투명도가 0이면 이벤트 감지가 트리거되지 않음)
② 아래 그림과 같이 이미지를 추가하고 친자 관계에 이름을 지정 하여 적당한 재질을 찾아 해당 이미지로 드래그하여 적당한 크기를 설정합니다.
③ 조이스틱의 앵커 포인트(꽃)를 선택하여 해상도 변경으로 인해 버튼의 위치가 변경되지 않도록 좌측 하단에 배치하는데 주의를 기울이고 중심점(피봇)의 위치는 (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;
}
}