chunk 1: core gameplay scripts scenes runtime assets

This commit is contained in:
2026-04-06 11:02:34 +03:00
parent fa0388bc79
commit 0d11a097d8
703 changed files with 2292651 additions and 0 deletions

View File

@@ -0,0 +1,427 @@
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.EnhancedTouch;
using UnityEngine.InputSystem.Utilities;
using EnhancedTouchSupport = UnityEngine.InputSystem.EnhancedTouch.EnhancedTouchSupport;
using EnhancedTouchTouch = UnityEngine.InputSystem.EnhancedTouch.Touch;
using EnhancedTouchPhase = UnityEngine.InputSystem.TouchPhase;
using UnityTouch = UnityEngine.Touch;
using TouchPhaseLegacy = UnityEngine.TouchPhase;
/// <summary>
/// Aggregates look input from mouse, gamepad sticks, and mobile touch into a single delta value.
/// Works with either the legacy Input Manager or the newer Input System.
/// </summary>
[DisallowMultipleComponent]
public sealed class LookInputRouter : MonoBehaviour
{
private const float TinyThreshold = 0.0001f;
[Header("General")]
[SerializeField] private bool autoDetectInputSystem = true;
[SerializeField] private bool preferNewInputSystem = true;
[Header("Input System (New)")]
[Tooltip("Optional PlayerInput component containing the action map with a Look action.")]
[SerializeField] private PlayerInput playerInput;
[Tooltip("Action name used for look deltas when using the new Input System.")]
[SerializeField] private string lookActionName = "Look";
[Header("Legacy Input Manager")]
[SerializeField] private string mouseXAxis = "Mouse X";
[SerializeField] private string mouseYAxis = "Mouse Y";
[SerializeField] private string rightStickXAxis = "Joystick X";
[SerializeField] private string rightStickYAxis = "Joystick Y";
[Header("Sensitivities")]
[SerializeField] private float mouseSensitivity = 1.0f;
[SerializeField] private float stickSensitivity = 120.0f;
[SerializeField] private float touchSensitivity = 0.15f;
[Header("Filtering")]
[Tooltip("Inputs below this magnitude will be ignored and reset to zero.")]
[SerializeField] private float deadzone = 0.05f;
[Tooltip("Optional smoothing duration in seconds. Set to zero for raw input.")]
[SerializeField] private float smoothingTime = 0.08f;
[Tooltip("Maximum magnitude allowed for a single look delta.")]
[SerializeField] private float maxMagnitude = 5.0f;
private InputAction cachedLookAction;
private bool usingNewInputSystem;
private Vector2 currentDelta;
private Vector2 smoothVelocity;
// Touch state
private int activeTouchId = -1;
private Vector2 lastTouchPosition;
private void Awake()
{
DetectInputSystem();
}
private void OnEnable()
{
// Enable Enhanced Touch so we can use the high-level Touch struct API.
EnhancedTouchSupport.Enable();
if (usingNewInputSystem)
{
EnableLookAction();
}
}
private void OnDisable()
{
if (cachedLookAction != null)
{
cachedLookAction.Disable();
}
cachedLookAction = null;
// Pair with Enable() to keep the global reference count balanced.
EnhancedTouchSupport.Disable();
}
private void Update()
{
Vector2 rawDelta = usingNewInputSystem ? ReadNewSystemDelta() : ReadLegacyDelta();
if (!usingNewInputSystem && preferNewInputSystem)
{
// If no PlayerInput was supplied but the Input System package is present,
// fall back to gathering from Gamepad/Touchscreen directly.
rawDelta += ReadDirectDeviceDelta();
}
rawDelta = Vector2.ClampMagnitude(rawDelta, maxMagnitude);
if (smoothingTime > TinyThreshold)
{
currentDelta = Vector2.SmoothDamp(currentDelta, rawDelta, ref smoothVelocity, smoothingTime, Mathf.Infinity, Time.unscaledDeltaTime);
}
else
{
currentDelta = rawDelta;
}
if (currentDelta.magnitude < deadzone)
{
currentDelta = Vector2.zero;
}
}
public bool TryGetLookDelta(out Vector2 delta)
{
delta = currentDelta;
return delta.sqrMagnitude > TinyThreshold;
}
private void DetectInputSystem()
{
if (!autoDetectInputSystem)
{
usingNewInputSystem = preferNewInputSystem && playerInput != null;
CacheLookAction();
return;
}
// If PlayerInput is explicitly assigned, use it.
if (playerInput == null)
{
playerInput = GetComponent<PlayerInput>();
}
if (playerInput != null && preferNewInputSystem)
{
usingNewInputSystem = true;
CacheLookAction();
}
else
{
usingNewInputSystem = false;
}
}
private void CacheLookAction()
{
if (playerInput == null)
return;
var actions = playerInput.actions;
if (actions == null)
return;
cachedLookAction = actions.FindAction(lookActionName, false);
if (cachedLookAction != null && !cachedLookAction.enabled && isActiveAndEnabled)
{
cachedLookAction.SafeEnable();
}
}
private void EnableLookAction()
{
if (cachedLookAction == null && playerInput != null)
{
CacheLookAction();
}
cachedLookAction?.SafeEnable();
}
private Vector2 ReadNewSystemDelta()
{
if (cachedLookAction == null)
return ReadDirectDeviceDelta();
Vector2 value = cachedLookAction.ReadValue<Vector2>();
return value * Time.unscaledDeltaTime;
}
private Vector2 ReadLegacyDelta()
{
// Replace legacy Input.GetAxis usage with InputSystem device reads where possible.
float x = 0f, y = 0f;
if (UnityEngine.InputSystem.Mouse.current != null)
{
Vector2 mouseDelta = UnityEngine.InputSystem.Mouse.current.delta.ReadValue();
x = mouseDelta.x * mouseSensitivity;
y = mouseDelta.y * mouseSensitivity;
}
float stickX = 0f, stickY = 0f;
if (UnityEngine.InputSystem.Gamepad.current != null)
{
Vector2 right = UnityEngine.InputSystem.Gamepad.current.rightStick.ReadValue();
stickX = right.x * stickSensitivity * Time.unscaledDeltaTime;
stickY = right.y * stickSensitivity * Time.unscaledDeltaTime;
}
return new Vector2(x + stickX, y + stickY);
}
private Vector2 ReadDirectDeviceDelta()
{
Vector2 aggregate = Vector2.zero;
if (Mouse.current != null)
{
Vector2 mouseDelta = Mouse.current.delta.ReadValue();
aggregate += mouseDelta * mouseSensitivity * Time.unscaledDeltaTime;
}
if (Gamepad.current != null)
{
Vector2 stick = Gamepad.current.rightStick.ReadValue();
aggregate += stick * stickSensitivity * Time.unscaledDeltaTime;
}
aggregate += ReadTouchDelta();
return aggregate;
}
private Vector2 ReadTouchDelta()
{
if (EnhancedTouchSupport.enabled)
{
var enhancedDelta = ReadEnhancedTouchDelta();
if (enhancedDelta != Vector2.zero || EnhancedTouchTouch.activeTouches.Count > 0)
return enhancedDelta;
}
if (Touchscreen.current != null)
{
var touchscreenDelta = ReadTouchscreenDelta();
if (touchscreenDelta != Vector2.zero)
return touchscreenDelta;
}
return ReadLegacyTouch();
}
private Vector2 ReadEnhancedTouchDelta()
{
var touches = EnhancedTouchTouch.activeTouches;
if (touches.Count <= 0)
{
ResetTouchTracking();
return Vector2.zero;
}
for (int i = 0; i < touches.Count; ++i)
{
var touch = touches[i];
if (!touch.valid)
continue;
if (activeTouchId == -1)
{
activeTouchId = touch.touchId;
lastTouchPosition = touch.screenPosition;
}
if (touch.touchId != activeTouchId)
continue;
if (touch.phase == EnhancedTouchPhase.Ended || touch.phase == EnhancedTouchPhase.Canceled)
{
ResetTouchTracking();
return Vector2.zero;
}
if (touch.phase == EnhancedTouchPhase.Began)
{
lastTouchPosition = touch.screenPosition;
return Vector2.zero;
}
Vector2 delta = (touch.screenPosition - lastTouchPosition) * touchSensitivity * Time.unscaledDeltaTime;
lastTouchPosition = touch.screenPosition;
return delta;
}
return Vector2.zero;
}
private Vector2 ReadTouchscreenDelta()
{
if (Touchscreen.current == null)
{
return Vector2.zero;
}
if (!AnyTouchPressed(Touchscreen.current.touches))
{
ResetTouchTracking();
return Vector2.zero;
}
foreach (var touchControl in Touchscreen.current.touches)
{
if (!touchControl.press.isPressed)
continue;
int id = touchControl.touchId.ReadValue();
Vector2 position = touchControl.position.ReadValue();
if (activeTouchId == -1)
{
activeTouchId = id;
lastTouchPosition = position;
continue;
}
if (activeTouchId != id)
continue;
Vector2 delta = (position - lastTouchPosition) * touchSensitivity;
lastTouchPosition = position;
return delta * Time.unscaledDeltaTime;
}
return Vector2.zero;
}
private Vector2 ReadLegacyTouch()
{
// Prefer the Input System touchscreen if available. Fall back to legacy Input.touches only when necessary.
if (UnityEngine.InputSystem.Touchscreen.current != null)
{
var touches = UnityEngine.InputSystem.Touchscreen.current.touches;
if (touches.Count <= 0)
{
ResetTouchTracking();
return Vector2.zero;
}
for (int i = 0; i < touches.Count; ++i)
{
var tc = touches[i];
if (!tc.press.isPressed)
continue;
int id = tc.touchId.ReadValue();
Vector2 pos = tc.position.ReadValue();
// We already check tc.press.isPressed above. No additional phase check is required
// here for the Input System touch path. This avoids ambiguous TouchPhase enum
// comparisons between the legacy and new Input System types.
if (activeTouchId == -1)
{
activeTouchId = id;
lastTouchPosition = pos;
continue;
}
if (activeTouchId != id)
continue;
Vector2 delta = (pos - lastTouchPosition) * touchSensitivity * Time.unscaledDeltaTime;
lastTouchPosition = pos;
return delta;
}
return Vector2.zero;
}
// Legacy fallback
if (Input.touchCount <= 0)
{
ResetTouchTracking();
return Vector2.zero;
}
for (int i = 0; i < Input.touchCount; i++)
{
UnityTouch touch = Input.GetTouch(i);
if (touch.phase == TouchPhaseLegacy.Ended || touch.phase == TouchPhaseLegacy.Canceled)
continue;
if (activeTouchId == -1)
{
activeTouchId = touch.fingerId;
lastTouchPosition = touch.position;
continue;
}
if (activeTouchId != touch.fingerId)
continue;
Vector2 delta = touch.deltaPosition * touchSensitivity * Time.unscaledDeltaTime;
lastTouchPosition = touch.position;
return delta;
}
return Vector2.zero;
}
private void ResetTouchTracking()
{
activeTouchId = -1;
lastTouchPosition = Vector2.zero;
}
public void ResetLookDelta()
{
currentDelta = Vector2.zero;
smoothVelocity = Vector2.zero;
}
private static bool AnyTouchPressed(ReadOnlyArray<TouchControl> touches)
{
for (int i = 0; i < touches.Count; ++i)
{
if (touches[i].press.isPressed)
return true;
}
return false;
}
}