0%

摇杆实现方法1

wwwwwww
自己做了个飞行模拟的小游戏,发布到手机上需要用到摇杆来控制,所以自己写了一个Joystick类,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
using UnityEngine;
using UnityEngine.EventSystems;
using System;

/// <summary>
/// UGUI游戏摇杆
/// </summary>
public class Joystick : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler
{
public static Joystick instance;
[SerializeField] Camera uiCamera;//摇杆对应的ui摄像机
[SerializeField] RectTransform _triggerArea;//触发启动摇杆区域
[SerializeField] RectTransform _joyStickArea;//摇杆活动区域
[SerializeField] RectTransform centerTrans;//摇杆图标
[SerializeField] float sensitivity = 1;//摇杆灵敏度
[SerializeField] float triggerAreaScale = 1;//摇杆控制区域
/// <summary>
/// 摇杆偏移方向
/// </summary>
public Vector2 moveDir { get; private set; }
/// <summary>
/// 摇杆偏移长度[0-1]
/// </summary>
public float moveLen { get; private set; }
/// <summary>
/// 是否在操控摇杆
/// </summary>
public bool isDraging { get; private set; }
/// <summary>
/// 摇杆横向偏移量
/// </summary>
public float Horizontal { get { return moveDir.x * moveLen; } }
/// <summary>
/// 摇杆纵向偏移量
/// </summary>
public float Vertical { get { return moveDir.y * moveLen; } }

Canvas _canvas;
Canvas canvas { get { if (_canvas == null) _canvas = transform.GetComponentInParent<Canvas>(); return _canvas; } }
Vector3 targetScreenPointPos = Vector3.zero;


float radius = 0f;
Vector3 centerScreenPos;
float depth { get { return centerScreenPos.z; } }
bool hasInit = false;

public Action onJoyStickPointerUp;
private void Start()
{
instance = this;

}
void OnEnable()
{
InitParam();
}
void OnDisable()
{
isDraging = false;
targetScreenPointPos = centerScreenPos;
centerTrans.localPosition = Vector3.zero;
}
void InitParam()
{
if (hasInit) return;
hasInit = true;
centerScreenPos = uiCamera.WorldToScreenPoint(_joyStickArea.position);
Rect rect = RectTransformUtility.PixelAdjustRect(_joyStickArea, canvas);
radius = triggerAreaScale * rect.width/2;
targetScreenPointPos = centerScreenPos;
}
public void OnPointerDown(PointerEventData eventData)
{
InitParam();
Vector2 pointScreenPos = eventData.position;
//if (Vector2.Distance(pointScreenPos, centerScreenPos) > radius) return;

isDraging = true;


//targetScreenPointPos = uiCamera.WorldToScreenPoint(eventData.pointerCurrentRaycast.worldPosition);

}
public void OnDrag(PointerEventData eventData)
{
if (!isDraging) return;
Vector3 pointScreenPos = eventData.position;
pointScreenPos.z = depth;
Vector3 dir = pointScreenPos - centerScreenPos;
float len = dir.magnitude;
len = len > radius ? radius : len;
dir = len * dir.normalized;
targetScreenPointPos = centerScreenPos + dir;
}

public void OnPointerUp(PointerEventData eventData)
{
isDraging = false;
targetScreenPointPos = centerScreenPos;
onJoyStickPointerUp?.Invoke();
}

private void Update()
{
Vector3 screenPointPos = uiCamera.WorldToScreenPoint(centerTrans.position);
if(Vector3.Distance(screenPointPos, targetScreenPointPos)<4)
{
screenPointPos = targetScreenPointPos;
}
else
{
screenPointPos = Vector3.Lerp(screenPointPos, targetScreenPointPos, sensitivity * Time.deltaTime);
}

centerTrans.position = uiCamera.ScreenToWorldPoint(screenPointPos);
moveDir = screenPointPos - centerScreenPos;
moveDir /= radius;
moveLen = moveDir.magnitude;
moveLen = moveLen > 1 ? 1 : moveLen;
}
}

通过属性器可以获取当前摇杆的状态参数,包括偏移方向以及强度,方向是360度,强度是[0-1]。还有几个SerializeField面板设置参数,结构如下图: