功能
1. 点击屏幕任意位置 显示在对应的位置
2. 松开后消失
UI结构
DynamicJoystick 组件:
- Background: 拖入Background
- Handle: 拖入Handle
- Background Group: 拖入Background(自动获取CanvasGroup)图片
代码
using UnityEngine;
using UnityEngine.EventSystems;
/// <summary>
/// 动态虚拟摇杆
/// </summary>
public class DynamicJoystick : MonoBehaviour, IPointerDownHandler, IDragHandler, IPointerUpHandler
{
[Header( "摇杆组件" )]
[SerializeField] private RectTransform background;
[SerializeField] private RectTransform handle;
[SerializeField] private CanvasGroup backgroundGroup; // 用CanvasGroup控制显隐
[Header( "摇杆参数" )]
[SerializeField] private float handleRange = 50f;
[SerializeField] private float deadZone = 0.1f;
private Vector2 inputVector;
private Canvas canvas;
private Camera cam;
private RectTransform inputArea;
public Vector2 Direction => inputVector.magnitude < deadZone ? Vector2.zero : inputVector;
public float Horizontal => Direction.x;
public float Vertical => Direction.y;
private void Awake( )
{
inputArea = GetComponent<RectTransform>( );
canvas = GetComponentInParent<Canvas>( );
// 自动添加透明Image用于接收射线
RaycastZone img = GetComponent<RaycastZone>( );
if ( img == null )
{
img = gameObject.AddComponent<RaycastZone>( );
}
img.raycastTarget = true;
// 自动添加CanvasGroup
if ( backgroundGroup == null && background != null )
{
backgroundGroup = background.GetComponent<CanvasGroup>( );
if ( backgroundGroup == null )
backgroundGroup = background.gameObject.AddComponent<CanvasGroup>( );
}
}
private void Start( )
{
if ( canvas.renderMode == RenderMode.ScreenSpaceOverlay )
cam = null;
else
cam = canvas.worldCamera;
// 初始隐藏摇杆(用alpha,不用SetActive)
HideJoystick( );
}
public void OnPointerDown( PointerEventData eventData )
{
Vector2 position;
if ( RectTransformUtility.ScreenPointToLocalPointInRectangle(
inputArea,
eventData.position,
cam,
out position ) )
{
// 在点击位置显示摇杆
background.anchoredPosition = position;
ShowJoystick( );
// 手柄归中
handle.anchoredPosition = Vector2.zero;
inputVector = Vector2.zero;
}
}
public void OnDrag( PointerEventData eventData )
{
Vector2 position;
if ( RectTransformUtility.ScreenPointToLocalPointInRectangle(
background,
eventData.position,
cam,
out position ) )
{
position = Vector2.ClampMagnitude( position, handleRange );
handle.anchoredPosition = position;
inputVector = position / handleRange;
}
}
public void OnPointerUp( PointerEventData eventData )
{
HideJoystick( );
handle.anchoredPosition = Vector2.zero;
inputVector = Vector2.zero;
}
/// <summary>
/// 显示摇杆(不触发Canvas重构)
/// </summary>
private void ShowJoystick( )
{
backgroundGroup.alpha = 1f;
//backgroundGroup.interactable = true;
//backgroundGroup.blocksRaycasts = true;
}
/// <summary>
/// 隐藏摇杆(不触发Canvas重构)
/// </summary>
private void HideJoystick( )
{
backgroundGroup.alpha = 0f;
//backgroundGroup.interactable = false;
//backgroundGroup.blocksRaycasts = false;
}
}
