效果如下图:
控件核心组成
1.RotateStick:空物体,挂载核心脚本 ;
2.Handle:摇杆,使用圆形图片;
3.RotateCenter:空物体,位置必须在摇杆旋转中心点;
4.HandleCenter:空物体,位置必须在Handle中心点。
核心代码
代码如下(在项目Assets文件夹内新建C#脚本后复制以下代码粘贴到新建的脚本内,挂载到“RotateStick”上即可。)。
通过读取实例中的rotateAngle属性获取摇杆旋转角度,以实现其他控制操作。
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class RotateStick : MonoBehaviour
{
public Transform centerTransform; // 指定的圆心Transform
public float innerRadius = 50f; // 内圆半径
public float outerRadius = 100f; // 外圆半径
public Vector2 value;
public Vector3 nowControlPos;
RectTransform bar;
RectTransform range;
public Transform center;
public static int bindFingerIndex = -1;
public float rotateAngle;
void OnDisable()
{
if (center != null)
{
bindFingerIndex = -1;
nowControlPos = center.position;
bar.position = center.position;
}
}
void Start()
{
this.transform.SetAsFirstSibling();
range = transform.GetChild(0) as RectTransform;
bar = range.GetChild(0) as RectTransform;
//bar.localPosition = Vector3.zero;
bar.position = center.position;
Image rangeImage = range.GetComponent<Image>();
rangeImage.alphaHitTestMinimumThreshold = 0.1f;
void OnBeginDrag(PointerEventData peDate)
{
bindFingerIndex = Input.touchCount - 1;
Vector2 aimPos = peDate.position;
nowControlPos = aimPos;
Vector3 constrainedPosition = ConstrainToQuarterRing(aimPos);
bar.position = constrainedPosition;
}
void OnDrag(PointerEventData peDate)
{
Vector2 aimPos = peDate.position;
nowControlPos = aimPos;
Vector3 constrainedPosition = ConstrainToQuarterRing(aimPos);
Debug.Log(constrainedPosition);
//if (constrainedPosition.y < 332)
//{
// constrainedPosition.y = 332;
//}
bar.position = constrainedPosition;
}
void OnEndDrag(PointerEventData peDate)
{
bindFingerIndex = -1;
nowControlPos = center.position;
bar.position = center.position;
}
SetTriggerEvent(rangeImage, EventTriggerType.BeginDrag, (bed) =>
{
OnBeginDrag(bed as PointerEventData);
});
SetTriggerEvent(rangeImage, EventTriggerType.PointerDown, (bed) =>
{
OnBeginDrag(bed as PointerEventData);
});
SetTriggerEvent(rangeImage, EventTriggerType.Drag, (bed) =>
{
OnDrag(bed as PointerEventData);
});
SetTriggerEvent(rangeImage, EventTriggerType.EndDrag, (bed) =>
{
OnEndDrag(bed as PointerEventData);
});
}
void Update()
{
Vector3 dir = (bar.position - centerTransform.position);
dir.x /= outerRadius;
dir.y /= outerRadius; // Normalize both x and y
value = dir;
if (Input.touchCount == 0 && !Input.GetMouseButton(0))
{
if (bar.localPosition != Vector3.zero)
{
bindFingerIndex = -1;
nowControlPos = center.position;
bar.position = center.position;
rotateAngle = 0;
}
}
}
private Vector3 ConstrainToQuarterRing(Vector2 position)
{
Vector3 dir = position - (Vector2)centerTransform.position;
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
float distance = dir.magnitude;
if (angle < 0) angle = 180;
if (angle < 90) angle = 90;
Debug.Log(angle-135);
rotateAngle = -(angle - 135)/45f;
distance = Mathf.Clamp(distance, innerRadius, outerRadius);
float radian = angle * Mathf.Deg2Rad;
return new Vector3(Mathf.Cos(radian) * distance, Mathf.Sin(radian) * distance, 0) + centerTransform.position;
}
private void SetTriggerEvent(MaskableGraphic ui, EventTriggerType type, UnityAction<BaseEventData> doSth)
{
EventTrigger eventTrigger = ui.gameObject.GetComponent<EventTrigger>();
if (eventTrigger == null)
{
eventTrigger = ui.gameObject.AddComponent<EventTrigger>();
}
EventTrigger.Entry entry = new EventTrigger.Entry();
entry.eventID = type;
UnityAction<BaseEventData> callback = doSth;
entry.callback.AddListener(callback);
eventTrigger.triggers.Add(entry);
}
}
脚本配置界面如下
CenterTransform:摇杆旋转中心点;
Inner/Outer Radius:摇杆移动范围;
Value:当前摇杆XY轴的值(用于精细控制);
Center:摇杆中心点(用于EndDrag时摇杆位置归零);
RotateAngle:摇杆最终角度,用于外部读取摇杆状态;
注意事项
BackGround的Raycast Target属性,勾选上Stick可以滑动和点击,取消勾选则Stick只能点击不能滑动,根据需要自行修改。