using Arena.Combat; using UnityEngine; using UnityEngine.InputSystem; namespace Arena.Characters { public class Player : MonoBehaviour, IDamageable { [System.Serializable] private class Settings { [Tooltip("Movement speed, in km/h.")] public float Speed = 10; } [System.Serializable] private struct References { public CharacterController Controller; public InputActionReference MoveAction; } [System.Serializable] public class StateContainer { public bool IsMoving = false; } #region FIELDS public static Player Instance { get; private set; } const float KMH_TO_MS = 1 / 3.6f; [SerializeField] private Settings _settings; [SerializeField] private References _references; [SerializeField] private StateContainer _state; [SerializeField] private Health _health; public StateContainer State => _state; private Vector2 _moveInput; private Camera _camera; #endregion #region UNITY LIFECYCLES void Awake() { if (Instance && Instance != this) { Debug.LogWarning($"A second Player was found on {name}, it is destroyed."); Destroy(gameObject); return; } Instance = this; _health.Initialize(); _camera = Camera.main; } void OnEnable() { _references.MoveAction.action.Enable(); } void OnDisable() { if (Instance == this) _references.MoveAction.action.Disable(); } void OnDestroy() { if (Instance == this) Instance = null; } void Update() { if (_health.IsDead) return; float t = Time.deltaTime; GetInputs(); Move(t); } #endregion #region Public Methods public void TakeDamage(int amount) { _health.TakeDamage(amount); } #endregion #region Private Methods #if UNITY_EDITOR [ContextMenu("Debug/Take 25 Damage")] private void DebugTakeDamage() { TakeDamage(25); } #endif private void GetInputs() { _moveInput = _references.MoveAction.action.ReadValue(); } private void Move(float t) { Vector3 direction = ToWorldDirection(_moveInput); Vector3 velocity = direction * KMH_TO_MS * _settings.Speed; _state.IsMoving = velocity.sqrMagnitude > .01f; _references.Controller.Move(velocity * t); } private Vector3 ToWorldDirection(Vector2 input) { // Only the camera rotation around the vertical axis is kept Quaternion cameraHeading = Quaternion.Euler(0f, _camera.transform.eulerAngles.y, 0f); return cameraHeading * new Vector3(input.x, 0f, input.y); } #endregion } }