chore: Project Restructuring & Theatre
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using OctoCore.Inputs;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace OctoCore.Components
|
||||
{
|
||||
@@ -10,6 +11,16 @@ namespace OctoCore.Components
|
||||
public enum PlayerModes { FirstPerson, ThirdPerson }
|
||||
public enum Orientations { World, Camera }
|
||||
|
||||
[System.Serializable]
|
||||
public class StateMachine
|
||||
{
|
||||
public bool IsFocussed;
|
||||
public bool IsPaused;
|
||||
public bool IsRunning;
|
||||
public float Yaw;
|
||||
public float Pitch;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class References
|
||||
{
|
||||
@@ -34,17 +45,8 @@ namespace OctoCore.Components
|
||||
[Tooltip("Maximum jump height reached at the apex (meters).")]
|
||||
public float JumpHeight = .4f;
|
||||
|
||||
[Tooltip("Maximum step height (meters).")]
|
||||
public float StepHeight = 0.3f;
|
||||
|
||||
[Tooltip("Downward acceleration applied to the player (m/s²).")]
|
||||
public float Gravity = 9.8f;
|
||||
|
||||
[Tooltip("Enable jump.")]
|
||||
public bool CanJump = true;
|
||||
|
||||
[Tooltip("Enable sprint.")]
|
||||
public bool CanRun = true;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
@@ -60,6 +62,7 @@ namespace OctoCore.Components
|
||||
private class FirstPerson
|
||||
{
|
||||
[Header("References")]
|
||||
|
||||
public Camera Camera;
|
||||
|
||||
[Header("Settings")]
|
||||
@@ -77,18 +80,17 @@ namespace OctoCore.Components
|
||||
public float MaxPitch = 80f;
|
||||
}
|
||||
|
||||
[OctoReadOnly] public StateMachine State;
|
||||
[SerializeField] private References _references;
|
||||
[SerializeField] private Settings _settings;
|
||||
[SerializeField] private Mapping _mapping;
|
||||
[SerializeField] private FirstPerson _firstPerson;
|
||||
|
||||
private bool _isPaused;
|
||||
private bool _wasPausedBeforeUnfocuss;
|
||||
private bool _jumpInput;
|
||||
private bool _jumpping;
|
||||
private bool _runInput;
|
||||
private float _runInertia;
|
||||
private float _yaw;
|
||||
private float _pitch;
|
||||
private float _jumpLerp;
|
||||
private float _jumpTime;
|
||||
private float _jumpAltitude;
|
||||
@@ -97,36 +99,8 @@ namespace OctoCore.Components
|
||||
private Vector3 _moveInertia;
|
||||
private Vector3 _moveDirection;
|
||||
|
||||
public bool IsPaused => _isPaused;
|
||||
public float Radius => _references.Controller ? _references.Controller.radius : 0;
|
||||
|
||||
/// <summary>True when the player is actively sprinting (inertia > 0.1 and CanRun enabled).</summary>
|
||||
public bool IsRunning => _settings.CanRun && _runInertia > 0.1f;
|
||||
|
||||
// Public access to yaw and pitch for external aim assist systems
|
||||
public float Yaw
|
||||
{
|
||||
get => _yaw;
|
||||
set => _yaw = value;
|
||||
}
|
||||
|
||||
public float Pitch
|
||||
{
|
||||
get => _pitch;
|
||||
set => _pitch = Mathf.Clamp(value, _firstPerson.MinPitch, _firstPerson.MaxPitch);
|
||||
}
|
||||
|
||||
public bool CanJump
|
||||
{
|
||||
get => _settings.CanJump;
|
||||
set => _settings.CanJump = value;
|
||||
}
|
||||
|
||||
public bool CanRun
|
||||
{
|
||||
get => _settings.CanRun;
|
||||
set => _settings.CanRun = value;
|
||||
}
|
||||
public bool IsPaused => State.IsPaused;
|
||||
public float Radius => _references.Controller ? _references.Controller.radius : 0;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
@@ -138,9 +112,11 @@ namespace OctoCore.Components
|
||||
OctoCore.Instance.Inputs.SubscribeAction(_mapping.RunAction, Run);
|
||||
OctoCore.Instance.Inputs.SubscribeAction(_mapping.JumpAction, Jump);
|
||||
|
||||
_yaw = transform.eulerAngles.y;
|
||||
State.Yaw = transform.eulerAngles.y;
|
||||
|
||||
Pause(_isPaused);
|
||||
State.IsFocussed = Application.isFocused;
|
||||
|
||||
Pause(State.IsPaused);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
@@ -154,23 +130,66 @@ namespace OctoCore.Components
|
||||
|
||||
void Update()
|
||||
{
|
||||
_moveInput = _isPaused ? Vector2.zero : Vector2.ClampMagnitude(_moveInput, 1);
|
||||
Camera cam = (_firstPerson.Camera && _firstPerson.Camera.enabled && _firstPerson.Camera.gameObject.activeInHierarchy)
|
||||
? _firstPerson.Camera
|
||||
: Camera.main;
|
||||
bool escapePressed = false;
|
||||
bool mouseClicked = false;
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
escapePressed = Keyboard.current != null && Keyboard.current.escapeKey.wasPressedThisFrame;
|
||||
mouseClicked =
|
||||
Mouse.current != null &&
|
||||
(
|
||||
Mouse.current.leftButton.wasPressedThisFrame ||
|
||||
Mouse.current.rightButton.wasPressedThisFrame ||
|
||||
Mouse.current.middleButton.wasPressedThisFrame ||
|
||||
Mouse.current.forwardButton.wasPressedThisFrame ||
|
||||
Mouse.current.backButton.wasPressedThisFrame
|
||||
);
|
||||
#else
|
||||
escapePressed = Input.GetKeyDown(KeyCode.Escape);
|
||||
mouseClicked =
|
||||
Input.GetMouseButtonDown(0) ||
|
||||
Input.GetMouseButtonDown(1) ||
|
||||
Input.GetMouseButtonDown(2);
|
||||
#endif
|
||||
|
||||
|
||||
if (!Application.isFocused || escapePressed)
|
||||
{
|
||||
if (State.IsFocussed)
|
||||
{
|
||||
State.IsFocussed = false;
|
||||
_wasPausedBeforeUnfocuss = State.IsPaused;
|
||||
Pause(true);
|
||||
}
|
||||
}
|
||||
else if (!State.IsFocussed && mouseClicked)
|
||||
{
|
||||
State.IsFocussed = true;
|
||||
if (!_wasPausedBeforeUnfocuss)
|
||||
Pause(false);
|
||||
}
|
||||
|
||||
|
||||
_moveInput = (State.IsPaused || !State.IsFocussed) ? Vector2.zero : Vector2.ClampMagnitude(_moveInput, 1);
|
||||
Camera cam = (_firstPerson.Camera && _firstPerson.Camera.enabled && _firstPerson.Camera.gameObject.activeInHierarchy) ? _firstPerson.Camera : Camera.main;
|
||||
|
||||
bool accelerating = _moveInput.magnitude > .1f;
|
||||
bool isGrounded = _references.Controller ? _references.Controller.isGrounded : true;
|
||||
float t = Time.deltaTime / 3.6f;
|
||||
bool isGrounded = _references.Controller ? _references.Controller.isGrounded : true;
|
||||
float t = Time.deltaTime / 3.6f;
|
||||
|
||||
// ── Move ────────────────────────────────────────────────────────────
|
||||
// Move
|
||||
|
||||
Vector3 move = new Vector3(_moveInput.x, 0, _moveInput.y);
|
||||
|
||||
if (_settings.Orientation == Orientations.Camera && cam)
|
||||
{
|
||||
Vector3 camForward = cam.transform.forward; camForward.y = 0; camForward.Normalize();
|
||||
Vector3 camRight = cam.transform.right; camRight.y = 0; camRight.Normalize();
|
||||
Vector3 camForward = cam.transform.forward;
|
||||
camForward.y = 0;
|
||||
camForward.Normalize();
|
||||
|
||||
Vector3 camRight = cam.transform.right;
|
||||
camRight.y = 0;
|
||||
camRight.Normalize();
|
||||
|
||||
move = camRight * move.x + camForward * move.z;
|
||||
}
|
||||
|
||||
@@ -178,115 +197,78 @@ namespace OctoCore.Components
|
||||
_moveDirection = Vector3.Lerp(_moveDirection, move, deltaSmooth * 1.5f);
|
||||
|
||||
deltaSmooth *= 1 - Vector3.Cross(_moveInertia, _moveDirection).magnitude;
|
||||
_moveInertia = Vector3.Lerp(_moveInertia, move, deltaSmooth);
|
||||
_moveInertia = Vector3.Lerp(_moveInertia, move, deltaSmooth);
|
||||
|
||||
if (!accelerating && _moveInertia.magnitude < .01f) _moveInertia = Vector3.zero;
|
||||
|
||||
// Sprint inertia — clamped to 0 if CanRun is off
|
||||
_runInertia = Mathf.Lerp(
|
||||
_runInertia,
|
||||
(_runInput && _settings.CanRun) ? 1f : 0f,
|
||||
t * (accelerating ? 5 : 3)
|
||||
);
|
||||
_runInertia = Mathf.Lerp(_runInertia, _runInput ? 1 : 0, t * (accelerating ? 5 : 3));
|
||||
State.IsRunning = _runInertia > .1f;
|
||||
|
||||
Vector3 moveDelta = _moveInertia * t * Mathf.Lerp(_settings.WalkSpeed, _settings.RunSpeed, _runInertia);
|
||||
|
||||
// ── Jump ────────────────────────────────────────────────────────────
|
||||
|
||||
if (isGrounded && _jumpInput && !_jumpping && _settings.CanJump)
|
||||
if (isGrounded && _jumpInput && !_jumpping)
|
||||
{
|
||||
_jumpInput = false;
|
||||
_jumpping = true;
|
||||
_jumpLerp = 0;
|
||||
_jumpTime = Time.timeSinceLevelLoad;
|
||||
_jumpInput = false;
|
||||
_jumpping = true;
|
||||
_jumpLerp = 0;
|
||||
_jumpTime = Time.timeSinceLevelLoad;
|
||||
_jumpAltitude = transform.position.y;
|
||||
}
|
||||
|
||||
// Consume the input even if CanJump is off, so it doesn't queue up
|
||||
if (_jumpInput && !_settings.CanJump) _jumpInput = false;
|
||||
|
||||
float jumpOffset = 0;
|
||||
|
||||
if (_jumpping)
|
||||
{
|
||||
_jumpInput = false;
|
||||
_jumpLerp = (Time.timeSinceLevelLoad - _jumpTime) / _settings.JumpDuration;
|
||||
|
||||
// FIX: added 0.15s grace period before checking isGrounded to avoid immediate re-trigger
|
||||
bool landingAllowed = (Time.timeSinceLevelLoad - _jumpTime) > 0.15f;
|
||||
|
||||
if (_jumpLerp >= 1 || (_jumpLerp > .5f && isGrounded && landingAllowed))
|
||||
if (_jumpLerp >= 1 || (_jumpLerp > .3f && isGrounded))
|
||||
{
|
||||
_jumpping = false;
|
||||
_jumpLerp = 0;
|
||||
_jumpping = false;
|
||||
_jumpLerp = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
float x = _jumpLerp * 2 - 1f;
|
||||
float y = x < 0
|
||||
? Mathf.Sqrt(1f - x * x)
|
||||
: Mathf.Cos(x * .5f * Mathf.PI);
|
||||
float x = _jumpLerp;
|
||||
x = x * 2 - 1;
|
||||
|
||||
float y;
|
||||
if (x < 0) y = Mathf.Sqrt(1f - x * x);
|
||||
else y = Mathf.Cos(x * .5f * Mathf.PI);
|
||||
|
||||
y = _jumpAltitude + y * _settings.JumpHeight;
|
||||
|
||||
y = _jumpAltitude + y * _settings.JumpHeight;
|
||||
jumpOffset = y - transform.position.y;
|
||||
jumpOffset = y - transform.position.y;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Step-up ─────────────────────────────────────────────────────────
|
||||
if (_references.Controller && isGrounded && !_jumpping)
|
||||
{
|
||||
float feetY = transform.position.y - (_references.Controller.height * 0.5f);
|
||||
|
||||
float castFromY = feetY + _settings.StepHeight;
|
||||
|
||||
Vector3 stepOrigin = new Vector3(transform.position.x, castFromY, transform.position.z);
|
||||
Vector3 stepDir = new Vector3(moveDelta.x, 0, moveDelta.z).normalized;
|
||||
|
||||
if (stepDir.magnitude > 0.1f)
|
||||
{
|
||||
float stepDist = _references.Controller.radius + 0.05f;
|
||||
|
||||
|
||||
if (!Physics.Raycast(stepOrigin, stepDir, stepDist))
|
||||
{
|
||||
Vector3 probeOrigin = stepOrigin + stepDir * stepDist;
|
||||
if (Physics.Raycast(probeOrigin, Vector3.down, out RaycastHit hit, _settings.StepHeight))
|
||||
{
|
||||
float stepUp = hit.point.y - feetY;
|
||||
if (stepUp > 0.05f)
|
||||
moveDelta.y = Mathf.Max(moveDelta.y, stepUp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Apply ───────────────────────────────────────────────────────────
|
||||
|
||||
if (_jumpping)
|
||||
moveDelta.y = jumpOffset;
|
||||
else if (!isGrounded)
|
||||
else
|
||||
moveDelta.y -= _settings.Gravity * Time.deltaTime;
|
||||
else moveDelta.y = -0.1f;
|
||||
|
||||
if (_references.Controller)
|
||||
_references.Controller.Move(moveDelta);
|
||||
else
|
||||
transform.position += moveDelta;
|
||||
|
||||
// ── Rotate ──────────────────────────────────────────────────────────
|
||||
// Rotate
|
||||
|
||||
switch (_settings.Mode)
|
||||
{
|
||||
case PlayerModes.FirstPerson:
|
||||
if (cam && !_isPaused)
|
||||
if (cam && !State.IsPaused)
|
||||
{
|
||||
float mouseX = _lookInput.x * _firstPerson.SensitivityX;
|
||||
float mouseY = _lookInput.y * _firstPerson.SensitivityY * -1;
|
||||
Vector2 delta = (State.IsPaused || !State.IsFocussed) ? Vector2.zero : _lookInput;
|
||||
|
||||
_yaw += mouseX;
|
||||
_pitch = Mathf.Clamp(_pitch + mouseY, _firstPerson.MinPitch, _firstPerson.MaxPitch);
|
||||
float mouseX = delta.x * _firstPerson.SensitivityX;
|
||||
float mouseY = delta.y * _firstPerson.SensitivityY * -1;
|
||||
|
||||
transform.rotation = Quaternion.Euler(0, _yaw, 0);
|
||||
cam.transform.localRotation = Quaternion.Euler(_pitch, 0, 0);
|
||||
State.Yaw += mouseX;
|
||||
State.Pitch = Mathf.Clamp(State.Pitch + mouseY, _firstPerson.MinPitch, _firstPerson.MaxPitch);
|
||||
|
||||
transform.rotation = Quaternion.Euler(0, State.Yaw, 0);
|
||||
cam.transform.localRotation = Quaternion.Euler(State.Pitch, 0, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -296,61 +278,77 @@ namespace OctoCore.Components
|
||||
if (_moveInertia.magnitude > .002f)
|
||||
{
|
||||
Vector3 offset = _moveInertia - _moveDirection;
|
||||
offset *= _moveInertia.magnitude * _runInertia;
|
||||
offset = Vector3.ClampMagnitude(offset, 1f);
|
||||
Vector3 up = (Vector3.up - offset).normalized;
|
||||
offset *= _moveInertia.magnitude * _runInertia;
|
||||
offset = Vector3.ClampMagnitude(offset * 1f, 1f);
|
||||
Vector3 up = (Vector3.up - offset).normalized;
|
||||
Quaternion lookRot = Quaternion.LookRotation(_moveInertia, up);
|
||||
targetRot = Quaternion.Lerp(targetRot, lookRot, t * 30);
|
||||
targetRot = Quaternion.Lerp(targetRot, lookRot, t * 30);
|
||||
}
|
||||
transform.rotation = targetRot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Reset ───────────────────────────────────────────────────────────
|
||||
// Reset
|
||||
|
||||
_moveInput = Vector2.zero;
|
||||
_lookInput = Vector2.zero;
|
||||
_runInput = false;
|
||||
_runInput = false;
|
||||
}
|
||||
|
||||
public void Teleport(Vector3 position, Quaternion rotation)
|
||||
{
|
||||
_isPaused = _jumpInput = _jumpping = _runInput = false;
|
||||
State.IsPaused = _jumpInput = _jumpping = _runInput = false;
|
||||
_runInertia = _jumpLerp = _jumpTime = _jumpAltitude = 0;
|
||||
_moveInput = _lookInput = Vector2.zero;
|
||||
_moveInput = _lookInput = Vector2.zero;
|
||||
_moveInertia = _moveDirection = Vector3.zero;
|
||||
_yaw = rotation.eulerAngles.y;
|
||||
_pitch = 0;
|
||||
State.Yaw = rotation.eulerAngles.y;
|
||||
State.Pitch = 0;
|
||||
|
||||
if (_references.Controller)
|
||||
_references.Controller.enabled = false;
|
||||
|
||||
if (_references.Controller) _references.Controller.enabled = false;
|
||||
transform.position = position;
|
||||
transform.rotation = rotation;
|
||||
if (_references.Controller) _references.Controller.enabled = true;
|
||||
|
||||
if (_references.Controller)
|
||||
_references.Controller.enabled = true;
|
||||
}
|
||||
|
||||
public void Pause(bool pause)
|
||||
{
|
||||
_isPaused = pause;
|
||||
if (OctoCore.Instance) OctoCore.Instance.UI.SetCursor();
|
||||
State.IsPaused = pause;
|
||||
|
||||
if (OctoCore.Instance)
|
||||
OctoCore.Instance.UI.SetCursor();
|
||||
}
|
||||
|
||||
// Convenience methods for external scripts
|
||||
public void SetCanJump(bool value) => _settings.CanJump = value;
|
||||
public void SetCanRun(bool value) => _settings.CanRun = value;
|
||||
public void SetYaw(float yaw) { State.Yaw = yaw; }
|
||||
public void SetPitch(float pitch) { State.Yaw = pitch; }
|
||||
|
||||
private void Move(Vector2 value) { _moveInput = value; }
|
||||
private void Look(Vector2 value) { _lookInput = value; }
|
||||
private void Run() { _runInput = true; }
|
||||
private void Run() { _runInput = true; }
|
||||
private void Jump() { _jumpInput = true; }
|
||||
|
||||
private void SetMode()
|
||||
{
|
||||
switch (_settings.Mode)
|
||||
{
|
||||
case PlayerModes.FirstPerson: break;
|
||||
case PlayerModes.ThirdPerson: break;
|
||||
case PlayerModes.FirstPerson:
|
||||
// Activate First Person Camera
|
||||
break;
|
||||
|
||||
case PlayerModes.ThirdPerson:
|
||||
// Activate Third Person Camera
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*public static float Arc(float x)
|
||||
{
|
||||
x = Mathf.Clamp01(x) * 2 - 1f;
|
||||
return Mathf.Sqrt(1f - x * x);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user