Files
2026-05-23 14:12:25 +02:00

276 lines
6.9 KiB
C#

using System;
using UnityEngine;
[Serializable]
public class Joystick : MonoBehaviour
{
[NonSerialized]
private static Joystick[] joysticks;
[NonSerialized]
private static bool enumeratedJoysticks;
[NonSerialized]
private static float tapTimeDelta = 0.3f;
public bool touchPad;
public Rect touchZone;
public Vector2 deadZone = Vector2.zero;
public bool normalize;
public Vector2 position;
public int tapCount;
private int lastFingerId = -1;
private float tapTimeWindow;
private Vector2 fingerDownPos;
private float fingerDownTime;
private float firstDeltaTime = 0.5f;
private Rect defaultRect;
private Boundary guiBoundary = new Boundary();
private Vector2 guiTouchOffset;
private Vector2 guiCenter;
void Start()
{
defaultRect = new Rect(
Screen.width * 0.1f,
Screen.height * 0.1f,
128,
128
);
if (touchPad)
{
touchZone = defaultRect;
return;
}
guiTouchOffset.x = defaultRect.width * 0.5f;
guiTouchOffset.y = defaultRect.height * 0.5f;
guiCenter.x = defaultRect.x + guiTouchOffset.x;
guiCenter.y = defaultRect.y + guiTouchOffset.y;
guiBoundary.min.x = defaultRect.x - guiTouchOffset.x;
guiBoundary.max.x = defaultRect.x + guiTouchOffset.x;
guiBoundary.min.y = defaultRect.y - guiTouchOffset.y;
guiBoundary.max.y = defaultRect.y + guiTouchOffset.y;
}
public void Disable()
{
gameObject.SetActive(false);
enumeratedJoysticks = false;
}
public void ResetJoystick()
{
lastFingerId = -1;
position = Vector2.zero;
defaultRect.x = guiCenter.x - guiTouchOffset.x;
defaultRect.y = guiCenter.y - guiTouchOffset.y;
}
public bool IsFingerDown()
{
return lastFingerId != -1;
}
public void LatchedFinger(int fingerId)
{
if (lastFingerId == fingerId)
{
ResetJoystick();
}
}
void Update()
{
if (!enumeratedJoysticks)
{
joysticks = FindObjectsOfType<Joystick>();
enumeratedJoysticks = true;
}
int count = Input.touchCount;
if (tapTimeWindow > 0)
{
tapTimeWindow -= Time.deltaTime;
}
else
{
tapCount = 0;
}
if (count == 0)
{
ResetJoystick();
}
else
{
for (int i = 0; i < count; i++)
{
Touch touch = Input.GetTouch(i);
Vector2 guiTouchPos = touch.position - guiTouchOffset;
bool shouldLatchFinger = false;
if (touchPad)
{
if (touchZone.Contains(touch.position))
{
shouldLatchFinger = true;
}
}
else
{
Rect touchRect = new Rect(
guiCenter.x - guiTouchOffset.x,
guiCenter.y - guiTouchOffset.y,
guiTouchOffset.x * 2,
guiTouchOffset.y * 2
);
if (touchRect.Contains(touch.position))
{
shouldLatchFinger = true;
}
}
if (
shouldLatchFinger &&
(lastFingerId == -1 || lastFingerId != touch.fingerId)
)
{
if (touchPad)
{
fingerDownPos = touch.position;
fingerDownTime = Time.time;
}
lastFingerId = touch.fingerId;
if (tapTimeWindow > 0)
{
tapCount++;
}
else
{
tapCount = 1;
tapTimeWindow = tapTimeDelta;
}
foreach (Joystick j in joysticks)
{
if (j != this)
{
j.LatchedFinger(touch.fingerId);
}
}
}
if (lastFingerId == touch.fingerId)
{
if (touch.tapCount > tapCount)
{
tapCount = touch.tapCount;
}
if (touchPad)
{
position.x = Mathf.Clamp(
(touch.position.x - fingerDownPos.x) /
(touchZone.width / 2),
-1,
1
);
position.y = Mathf.Clamp(
(touch.position.y - fingerDownPos.y) /
(touchZone.height / 2),
-1,
1
);
}
else
{
defaultRect.x = Mathf.Clamp(
guiTouchPos.x,
guiBoundary.min.x,
guiBoundary.max.x
);
defaultRect.y = Mathf.Clamp(
guiTouchPos.y,
guiBoundary.min.y,
guiBoundary.max.y
);
}
if (
touch.phase == TouchPhase.Ended ||
touch.phase == TouchPhase.Canceled
)
{
ResetJoystick();
}
}
}
}
if (!touchPad)
{
position.x =
(defaultRect.x + guiTouchOffset.x - guiCenter.x) /
guiTouchOffset.x;
position.y =
(defaultRect.y + guiTouchOffset.y - guiCenter.y) /
guiTouchOffset.y;
}
float absoluteX = Mathf.Abs(position.x);
float absoluteY = Mathf.Abs(position.y);
if (absoluteX < deadZone.x)
{
position.x = 0;
}
else if (normalize)
{
position.x =
Mathf.Sign(position.x) *
(absoluteX - deadZone.x) /
(1 - deadZone.x);
}
if (absoluteY < deadZone.y)
{
position.y = 0;
}
else if (normalize)
{
position.y =
Mathf.Sign(position.y) *
(absoluteY - deadZone.y) /
(1 - deadZone.y);
}
}
}