Files
Ipseity-Demo/Packages/OctoCore/Runtime/Scripts/Components/OctoPlayer.cs
T

354 lines
12 KiB
C#

using OctoCore.Inputs;
using UnityEngine;
using UnityEngine.InputSystem;
namespace OctoCore.Components
{
public class OctoPlayer : MonoBehaviour
{
public static OctoPlayer Instance { get; private set; }
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
{
public CharacterController Controller;
}
[System.Serializable]
private class Settings
{
public PlayerModes Mode = PlayerModes.FirstPerson;
public Orientations Orientation = Orientations.Camera;
[Tooltip("Walk speed (km/h).")]
public float WalkSpeed = 10;
[Tooltip("Run speed (km/h).")]
public float RunSpeed = 20;
[Tooltip("Jump duration (seconds).")]
public float JumpDuration = .4f;
[Tooltip("Maximum jump height reached at the apex (meters).")]
public float JumpHeight = .4f;
[Tooltip("Downward acceleration applied to the player (m/s²).")]
public float Gravity = 9.8f;
}
[System.Serializable]
private class Mapping
{
public OctoActions MoveAction;
public OctoActions LookAction;
public OctoActions RunAction;
public OctoActions JumpAction;
}
[System.Serializable]
private class FirstPerson
{
[Header("References")]
public Camera Camera;
[Header("Settings")]
[Tooltip("Horizontal sensitivity (Yaw).")]
public float SensitivityX = 0.1f;
[Tooltip("Vertical sensitivity (Pitch).")]
public float SensitivityY = 0.1f;
[Tooltip("Minimum pitch (looking down).")]
public float MinPitch = -80f;
[Tooltip("Maximum pitch (looking up).")]
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 _wasPausedBeforeUnfocuss;
private bool _jumpInput;
private bool _jumpping;
private bool _runInput;
private float _runInertia;
private float _jumpLerp;
private float _jumpTime;
private float _jumpAltitude;
private Vector2 _moveInput;
private Vector2 _lookInput;
private Vector3 _moveInertia;
private Vector3 _moveDirection;
public bool IsPaused => State.IsPaused;
public float Radius => _references.Controller ? _references.Controller.radius : 0;
void OnEnable()
{
if (!Instance) Instance = this;
else Destroy(gameObject);
OctoCore.Instance.Inputs.SubscribeAction(_mapping.MoveAction, Move);
OctoCore.Instance.Inputs.SubscribeAction(_mapping.LookAction, Look);
OctoCore.Instance.Inputs.SubscribeAction(_mapping.RunAction, Run);
OctoCore.Instance.Inputs.SubscribeAction(_mapping.JumpAction, Jump);
State.Yaw = transform.eulerAngles.y;
State.IsFocussed = Application.isFocused;
Pause(State.IsPaused);
}
void OnDisable()
{
OctoCore.Instance.Inputs.UnsubscribeAction(_mapping.MoveAction, Move);
OctoCore.Instance.Inputs.UnsubscribeAction(_mapping.RunAction, Run);
OctoCore.Instance.Inputs.UnsubscribeAction(_mapping.JumpAction, Jump);
if (Instance == this) Instance = null;
}
void Update()
{
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;
// 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();
move = camRight * move.x + camForward * move.z;
}
float deltaSmooth = t * (accelerating ? 30 : 15);
_moveDirection = Vector3.Lerp(_moveDirection, move, deltaSmooth * 1.5f);
deltaSmooth *= 1 - Vector3.Cross(_moveInertia, _moveDirection).magnitude;
_moveInertia = Vector3.Lerp(_moveInertia, move, deltaSmooth);
if (!accelerating && _moveInertia.magnitude < .01f) _moveInertia = Vector3.zero;
_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);
if (isGrounded && _jumpInput && !_jumpping)
{
_jumpInput = false;
_jumpping = true;
_jumpLerp = 0;
_jumpTime = Time.timeSinceLevelLoad;
_jumpAltitude = transform.position.y;
}
float jumpOffset = 0;
if (_jumpping)
{
_jumpInput = false;
_jumpLerp = (Time.timeSinceLevelLoad - _jumpTime) / _settings.JumpDuration;
if (_jumpLerp >= 1 || (_jumpLerp > .3f && isGrounded))
{
_jumpping = false;
_jumpLerp = 0;
}
else
{
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;
jumpOffset = y - transform.position.y;
}
}
if (_jumpping)
moveDelta.y = jumpOffset;
else
moveDelta.y -= _settings.Gravity * Time.deltaTime;
if (_references.Controller)
_references.Controller.Move(moveDelta);
else
transform.position += moveDelta;
// Rotate
switch (_settings.Mode)
{
case PlayerModes.FirstPerson:
if (cam && !State.IsPaused)
{
Vector2 delta = (State.IsPaused || !State.IsFocussed) ? Vector2.zero : _lookInput;
float mouseX = delta.x * _firstPerson.SensitivityX;
float mouseY = delta.y * _firstPerson.SensitivityY * -1;
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;
case PlayerModes.ThirdPerson:
{
Quaternion targetRot = transform.rotation;
if (_moveInertia.magnitude > .002f)
{
Vector3 offset = _moveInertia - _moveDirection;
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);
}
transform.rotation = targetRot;
break;
}
}
// Reset
_moveInput = Vector2.zero;
_lookInput = Vector2.zero;
_runInput = false;
}
public void Teleport(Vector3 position, Quaternion rotation)
{
State.IsPaused = _jumpInput = _jumpping = _runInput = false;
_runInertia = _jumpLerp = _jumpTime = _jumpAltitude = 0;
_moveInput = _lookInput = Vector2.zero;
_moveInertia = _moveDirection = Vector3.zero;
State.Yaw = rotation.eulerAngles.y;
State.Pitch = 0;
if (_references.Controller)
_references.Controller.enabled = false;
transform.position = position;
transform.rotation = rotation;
if (_references.Controller)
_references.Controller.enabled = true;
}
public void Pause(bool pause)
{
State.IsPaused = pause;
if (OctoCore.Instance)
OctoCore.Instance.UI.SetCursor();
}
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 Jump() { _jumpInput = true; }
private void SetMode()
{
switch (_settings.Mode)
{
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);
}*/
}
}