虚拟摇杆,可以控制人物的的移动,及其旋转,或者是控制技能的释放方向。此篇博客就unity中如何实现利用UI(虚拟摇杆)控制物体的移动和旋转
场景界面【等待完善】
代码如下:
using UnityEngine;
using UnityEngine.EventSystems;
using System;
using UnityEngine.UI;
using GA;
public class RockerCtrl : IPointerDownHandler,IPointerUpHandler,IDragHandler
{
[Header("滑动区域")]
public RectTransform sildeArea;
[Header("摇杆背景")]
public RectTransform rockerBg;
[Header("摇杆点")]
public RectTransform rockerPoint;
[Header("摇杆半径")]
public float radius;
public RockerCtrl Instance;
public CanvasScaler canvasScaler;
/// <summary>
/// 是否正在摇杆滑动
/// </summary>
[NonSerialized]
public bool isRockering = false;
/// <summary>
/// 设置移动方向
/// </summary>
private static Action<Vector2> setDir;
/// <summary>
/// 开始点击的位置(世界坐标系)
/// </summary>
private Vector3 startWorldPos = Vector2.zero;
/// <summary>
/// 开始点击的位置(屏幕坐标系)
/// </summary>
private Vector2 startEventPos = Vector2.zero;
/// <summary>
/// 摇杆默认位置
/// </summary>
private Vector2 defaultPos = Vector2.zero;
protected void Awake()
{
Instance = this;
//初始化变量
if (rockerBg.gameObject.activeSelf)
rockerBg.gameObject.SetActive(false);
}
private void Start()
{
canvasScaler = transform.parent.parent.parent.GetComponent<CanvasScaler>();//TODO
radius *= GetWidthOrHeightAspect();//计算在不同分辨率下的半径
}
/// <summary>
/// 点击事件
/// </summary>
public void OnPointerDown(PointerEventData eventData)
{
isRockering = true;
//在点击点显示摇杆
//摄像机模式 需要将屏幕坐标转化世界坐标
Vector3 worldPos;
bool isOk = RectTransformUtility.ScreenPointToWorldPointInRectangle(sildeArea, eventData.position, eventData.enterEventCamera, out worldPos);//设置摇杆位置
if (isOk)
{
rockerBg.position = worldPos;
startEventPos = eventData.position;
startWorldPos = worldPos;
}
rockerBg.gameObject.SetActive(true);//显示摇杆
}
/// <summary>
/// 拖拽事件
/// </summary>
public void OnDrag(PointerEventData eventData)
{
Vector3 currentPos;//世界坐标
bool isOk = RectTransformUtility.ScreenPointToWorldPointInRectangle(sildeArea, eventData.position, eventData.enterEventCamera, out currentPos);
if (isOk)
{
Vector3 dir = eventData.position - startEventPos;//屏幕坐标系下滑动的向量
float len = dir.magnitude;//滑动向量的 长度
if (len > radius)//滑动的位置大于滑动半径 控制point在半径边界
{
Vector3 clampDir = Vector3.ClampMagnitude(dir, radius);//限制向量的宽度
rockerPoint.localPosition = clampDir;
}
else
rockerPoint.position = currentPos;
if (setDir != null)
setDir(-dir.normalized);//去反方向 和运动方向保持一致
}
}
/// <summary>
/// 抬起事件
/// </summary>
/// <param name="eventData"></param>
public void OnPointerUp(PointerEventData eventData)
{
isRockering = false;
//摇杆归位
rockerBg.position = defaultPos;
rockerPoint.position = defaultPos;
rockerBg.gameObject.SetActive(false);//隐藏摇杆
if (setDir != null)
setDir(Vector2.zero);
}
/// <summary>
/// 添加设置移动方向事件
/// </summary>
public static void AddSetDirEvent(Action<Vector2> action)
{
if (setDir == null && action != null)
setDir = action;
}
/// <summary>
/// 移除设置移动方向事件
/// </summary>
public static void RemoveSetDirEvent()
{
if (setDir != null)
setDir = null;
}
/// <summary>
/// 得到相对宽高比
/// </summary>
public float GetWidthOrHeightAspect()
{
float temp = 1.0f;
float matchWidthOrHeight = canvasScaler.matchWidthOrHeight;
if (matchWidthOrHeight > 0)//高适配
temp = Screen.height * 1.0f /Config.Instance.CanvasRealHeight;
else//宽适配
temp = Screen.width * 1.0f / Config.Instance.CanvasRealWidth;
return temp;
}
}