都是坑啊,最先写的时候改变的全都是UI的position,本来看似都OK的,但是发现改变屏幕分辨率之后,摇杆可拖动范围居然不一样。这就很影响体验了,最后还是耐着性子把原本需要改变position来实现的改成了更改UI元素的anchoredPosition,也就是锚点位置,因为锚点位置是相对的,所以不同分辨率下,相对位置始终不变,即可以自适应了。

话不多说,下面是代码。

代码挺简单的,注释也挺详细,就不多赘述了。

因为是用Fingergesture做的,所以没有继承IDrag那些接口。

因为在做的过程中发现使用那些接口去做Drag事件的话,当动态改变位置的那一瞬间,UI识别不到drag事件,具体原因不详,后来改为了Fingergesture来做。

using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class JoystickController : MonoBehaviour
{

//摇杆半径
private float joyRadius;
[HideInInspector]
public Vector3 playerMoveDir;
//摇杆中心
[SerializeField]
private RectTransform joyCenter;
//摇杆外围
private RectTransform joyRange;

[Range(0, 1)]
public float gravitySensitivity = 0.3f;
//摇杆外围起始位置
private Vector2 joyRangeBeginPos;
//摇杆中心起始位置
private Vector2 joyCenterBeginPos;

//画布
private Canvas canvas;
//UI相机
private Camera uirootCamera;


void Start()
{
//获取圆的半径
joyRadius = this.GetComponent<RectTransform>().rect.size.x * 0.5f;
canvas = GameObject.Find("UIRoot").transform.GetChild(0).GetComponent<Canvas>();
uirootCamera = GameObject.Find("UIRoot").transform.GetChild(2).GetComponent<Camera>();
joyRange = this.GetComponent<RectTransform>();
}


public void OnBeginDrag()
{

Vector2 _posMouse = new Vector2();
//屏幕坐标和UI坐标的转换
RectTransformUtility.ScreenPointToLocalPointInRectangle(joyRange, Input.mousePosition, uirootCamera, out _posMouse);
//因为我的摇杆锚点在左下,所以做一个差值计算
joyRangeBeginPos = new Vector2(_posMouse.x - joyRange.sizeDelta.x * 0.5f, _posMouse.y - joyRange.sizeDelta.x * 0.5f);
//将摇杆的中心位置设置为鼠标点击的位置,即动态变化摇杆位置
joyRange.anchoredPosition = joyRangeBeginPos;
//记录下当前摇杆拖动的位置
joyCenterBeginPos = joyCenter.anchoredPosition;

}

public void OnDrag()
{

Vector2 _posMouse = new Vector2();
RectTransformUtility.ScreenPointToLocalPointInRectangle(joyRange, Input.mousePosition, uirootCamera, out _posMouse);
_posMouse = new Vector2(_posMouse.x - joyRange.sizeDelta.x * 0.5f, _posMouse.y - joyRange.sizeDelta.x * 0.5f);
//拖拽方向
Vector2 dragDir = _posMouse - joyCenterBeginPos;
//拖拽距离
float dis = dragDir.magnitude;

if (dis <= joyRadius)
{
joyCenter.anchoredPosition = _posMouse;
}
else
{
joyCenter.anchoredPosition = dragDir.normalized * joyRadius;
}
//玩家移动方向
playerMoveDir = new Vector3(dragDir.x, dragDir.y, 0);

}

public void OnEndDrag()
{
joyRange.anchoredPosition = joyCenter.anchoredPosition = Vector2.zero;
}

}


下面是工程截图,以及摇杆锚点轴点示意图:

[Unity]自适应,动态变化位置的摇杆的实现。_拖拽


--------------------------------------------------分割线-----------------------------------------------------


RectTransformUtility.ScreenPointToLocalPointInRectangle


其实这个矩阵变换方法的第一个参数设为UGUI的根canvans的RectTransform就行:

RectTransformUtility.ScreenPointToLocalPointInRectangle(RootCanvas.GetComponent<RectTransform>(), screenPos, UICamera, out tarVec);


tips:

canvans的RectTransform可以以.GetComponent<RectTransform>()的方式获得,目前使用没有什么问题。

但是有文章写道不推荐这么获得RectTransform,如果.GetComponent<RectTransform>()有什么问题的话可以尝试他推荐的:

RootCanvas.transform as RectTransform;

这种方式获得。