Files
DTrierFlood_New/Assets/Scripts/Drone/SimpleXrDroneController.cs

204 lines
7.8 KiB
C#

using UnityEngine;
using UnityEngine.InputSystem;
namespace FloodSWE.Drone
{
/// <summary>
/// Action-based XR drone movement for OpenXR/Input System.
/// Attach to XR Origin root and wire actions from an InputActionAsset.
/// </summary>
public sealed class SimpleXrDroneController : MonoBehaviour
{
[Header("References")]
[SerializeField] private Transform movementReference;
[Header("Actions")]
[SerializeField] private InputActionReference moveAction;
[SerializeField] private InputActionReference liftYawAction;
[SerializeField] private InputActionReference liftUpButtonAction;
[SerializeField] private InputActionReference liftDownButtonAction;
[SerializeField] private InputActionReference boostAction;
[SerializeField] private bool autoEnableActions = true;
[SerializeField] private bool useLiftAxis = true;
[SerializeField] private bool useLiftButtons = true;
[Header("Flight")]
[SerializeField] private float moveSpeedMps = 8.0f;
[SerializeField] private float liftSpeedMps = 5.0f;
[SerializeField] private float yawSpeedDegPerSec = 75.0f;
[SerializeField] private float boostMultiplier = 2.0f;
[SerializeField] private float axisDeadzone = 0.15f;
[SerializeField] private bool flattenReferenceForward = true;
private bool moveEnabledByThis;
private bool liftYawEnabledByThis;
private bool liftUpEnabledByThis;
private bool liftDownEnabledByThis;
private bool boostEnabledByThis;
private bool boostActive;
private float currentHorizontalSpeedMps;
private float currentVerticalSpeedMps;
private float currentCombinedSpeedMps;
private float currentMaxSpeedMps;
public float MoveSpeedMps => Mathf.Max(0.0f, moveSpeedMps);
public float LiftSpeedMps => Mathf.Max(0.0f, liftSpeedMps);
public float YawSpeedDegPerSec => Mathf.Max(0.0f, yawSpeedDegPerSec);
public float BoostMultiplier => Mathf.Max(1.0f, boostMultiplier);
public bool BoostActive => boostActive;
public float CurrentHorizontalSpeedMps => currentHorizontalSpeedMps;
public float CurrentVerticalSpeedMps => currentVerticalSpeedMps;
public float CurrentCombinedSpeedMps => currentCombinedSpeedMps;
public float CurrentMaxSpeedMps => currentMaxSpeedMps;
public float ConfiguredBaseMaxSpeedMps => Mathf.Sqrt(MoveSpeedMps * MoveSpeedMps + LiftSpeedMps * LiftSpeedMps);
public float ConfiguredBoostedMaxSpeedMps => ConfiguredBaseMaxSpeedMps * BoostMultiplier;
private void OnEnable()
{
if (!autoEnableActions)
{
return;
}
moveEnabledByThis = TryEnable(moveAction);
liftYawEnabledByThis = TryEnable(liftYawAction);
liftUpEnabledByThis = TryEnable(liftUpButtonAction);
liftDownEnabledByThis = TryEnable(liftDownButtonAction);
boostEnabledByThis = TryEnable(boostAction);
}
private void OnDisable()
{
if (!autoEnableActions)
{
return;
}
TryDisable(moveAction, moveEnabledByThis);
TryDisable(liftYawAction, liftYawEnabledByThis);
TryDisable(liftUpButtonAction, liftUpEnabledByThis);
TryDisable(liftDownButtonAction, liftDownEnabledByThis);
TryDisable(boostAction, boostEnabledByThis);
moveEnabledByThis = false;
liftYawEnabledByThis = false;
liftUpEnabledByThis = false;
liftDownEnabledByThis = false;
boostEnabledByThis = false;
}
private void Update()
{
Vector2 move = ReadVector2(moveAction);
Vector2 liftYaw = ReadVector2(liftYawAction);
bool boost = ReadButton(boostAction);
move = ApplyDeadzone(move, axisDeadzone);
liftYaw = ApplyDeadzone(liftYaw, axisDeadzone);
float liftInput = 0.0f;
if (useLiftAxis)
liftInput += liftYaw.y;
if (useLiftButtons)
{
if (ReadButton(liftUpButtonAction))
liftInput += 1.0f;
if (ReadButton(liftDownButtonAction))
liftInput -= 1.0f;
}
liftInput = Mathf.Clamp(liftInput, -1.0f, 1.0f);
float multiplier = boost ? Mathf.Max(1.0f, boostMultiplier) : 1.0f;
boostActive = boost;
Transform reference = movementReference != null ? movementReference : transform;
Vector3 forward = reference.forward;
Vector3 right = reference.right;
if (flattenReferenceForward)
{
forward.y = 0.0f;
right.y = 0.0f;
forward = forward.sqrMagnitude > 1e-6f ? forward.normalized : Vector3.forward;
right = right.sqrMagnitude > 1e-6f ? right.normalized : Vector3.right;
}
Vector3 planarVelocity =
(forward * move.y + right * move.x) * Mathf.Max(0.0f, moveSpeedMps) * multiplier;
Vector3 liftVelocity = Vector3.up * liftInput * Mathf.Max(0.0f, liftSpeedMps) * multiplier;
transform.position += (planarVelocity + liftVelocity) * Time.deltaTime;
currentHorizontalSpeedMps = planarVelocity.magnitude;
currentVerticalSpeedMps = Mathf.Abs(liftVelocity.y);
currentCombinedSpeedMps = (planarVelocity + liftVelocity).magnitude;
float maxMove = Mathf.Max(0.0f, moveSpeedMps) * multiplier;
float maxLift = Mathf.Max(0.0f, liftSpeedMps) * multiplier;
currentMaxSpeedMps = Mathf.Sqrt(maxMove * maxMove + maxLift * maxLift);
float yawDelta = liftYaw.x * Mathf.Max(0.0f, yawSpeedDegPerSec) * Time.deltaTime;
transform.Rotate(0.0f, yawDelta, 0.0f, Space.World);
}
public void SetMoveSpeed(float value)
{
moveSpeedMps = Mathf.Max(0.0f, value);
}
public void SetLiftSpeed(float value)
{
liftSpeedMps = Mathf.Max(0.0f, value);
}
public void SetYawSpeed(float value)
{
yawSpeedDegPerSec = Mathf.Max(0.0f, value);
}
public void SetBoostMultiplier(float value)
{
boostMultiplier = Mathf.Max(1.0f, value);
}
private static bool TryEnable(InputActionReference actionRef)
{
InputAction action = actionRef != null ? actionRef.action : null;
if (action == null || action.enabled)
{
return false;
}
action.Enable();
return true;
}
private static void TryDisable(InputActionReference actionRef, bool enabledByThis)
{
if (!enabledByThis)
{
return;
}
InputAction action = actionRef != null ? actionRef.action : null;
if (action != null && action.enabled)
{
action.Disable();
}
}
private static Vector2 ReadVector2(InputActionReference actionRef)
{
InputAction action = actionRef != null ? actionRef.action : null;
return action != null ? action.ReadValue<Vector2>() : Vector2.zero;
}
private static bool ReadButton(InputActionReference actionRef)
{
InputAction action = actionRef != null ? actionRef.action : null;
return action != null && action.IsPressed();
}
private static Vector2 ApplyDeadzone(Vector2 value, float deadzone)
{
float threshold = Mathf.Clamp(deadzone, 0.0f, 0.99f);
return value.sqrMagnitude >= threshold * threshold ? value : Vector2.zero;
}
}
}