Files
BABA_YAGA/Assets/Scripts/Player Controller/PlayerStateMachine.cs

243 lines
9.5 KiB
C#
Raw Normal View History

2026-03-26 20:27:19 +07:00
using System.Collections.Generic;
using UnityEngine;
2026-04-03 22:46:17 +07:00
using Fusion;
2026-03-26 20:27:19 +07:00
namespace OnlyScove.Scripts
{
[RequireComponent(typeof(CharacterController), typeof(InputReader), typeof(Animator))]
2026-04-28 00:07:42 +07:00
[RequireComponent(typeof(PlayerStats), typeof(PlayerInteraction), typeof(PlayerMovement))]
[RequireComponent(typeof(PlayerAnimationHandler))]
2026-04-03 22:46:17 +07:00
public class PlayerStateMachine : NetworkBehaviour
2026-03-26 20:27:19 +07:00
{
[field: Header("References")]
[field: SerializeField] public CharacterController Controller { get; private set; }
[field: SerializeField] public virtual InputReader Input { get; private set; }
[field: SerializeField] public Animator Anim { get; private set; }
[field: SerializeField] public EnvironmentScanner Scanner { get; private set; }
public CameraController Cam { get; private set; }
2026-04-28 00:07:42 +07:00
[Header("Modules")]
public PlayerStats Stats;
public PlayerInteraction Interaction;
public PlayerMovement Movement;
public PlayerAnimationHandler AnimationHandler;
2026-03-26 20:27:19 +07:00
2026-04-03 22:46:17 +07:00
[Networked] public Quaternion NetworkedCameraRotation { get; set; }
2026-04-05 00:08:43 +07:00
[Networked] public Vector2 NetworkedMoveInput { get; set; }
[Networked] public float NetworkedSpeed { get; set; }
2026-04-23 23:09:54 +07:00
2026-04-28 00:07:42 +07:00
// Pass-through properties for State Compatibility
2026-04-05 00:08:43 +07:00
public Vector2 MoveInput { get; private set; }
public bool IsSprintHeld { get; private set; }
2026-04-30 16:52:19 +07:00
public float VelocityY
{
get => (Object != null && Object.IsValid && Movement != null) ? Movement.VelocityY : 0f;
set { if (Object != null && Object.IsValid && Movement != null) Movement.VelocityY = value; }
}
public bool IsGrounded => (Object != null && Object.IsValid && Movement != null) ? Movement.IsGrounded : true;
public bool WasGrounded => (Object != null && Object.IsValid && Movement != null) ? Movement.WasGrounded : true;
2026-04-25 18:20:16 +07:00
2026-04-28 00:07:42 +07:00
public float WalkSpeed => Movement.WalkSpeed;
public float RunSpeed => Movement.RunSpeed;
public float SprintSpeed => Movement.SprintSpeed;
public float SneakSpeed => Movement.SneakSpeed;
public float DashForce => Movement.DashForce;
public float JumpHeight => Movement.JumpHeight;
public float ThrustDownwardForce => Movement.ThrustDownwardForce;
public float Gravity => Movement.Gravity;
public float InteractionRange => Interaction.InteractionRange;
public LayerMask InteractionMask => Interaction.InteractionMask;
public static PlayerStateMachine Local { get; private set; }
public string CurrentStateName => currentState != null ? currentState.GetType().Name : "None";
2026-04-30 16:52:19 +07:00
public Quaternion CameraRotation
2026-04-25 18:20:16 +07:00
{
2026-04-30 16:52:19 +07:00
get
2026-04-25 18:20:16 +07:00
{
2026-04-30 16:52:19 +07:00
if (Runner != null && Runner.IsRunning && Object != null && Object.IsValid) return NetworkedCameraRotation;
2026-04-25 18:20:16 +07:00
return Cam != null ? Cam.PlanarRotation : transform.rotation;
}
}
2026-04-03 22:46:17 +07:00
2026-03-26 20:27:19 +07:00
private PlayerBaseState currentState;
private bool hasControl = true;
2026-04-25 18:20:16 +07:00
private float localAnimatorSpeed;
2026-04-08 12:38:39 +07:00
2026-03-26 20:27:19 +07:00
protected virtual void Awake()
{
Controller = GetComponent<CharacterController>();
Input = GetComponent<InputReader>();
Anim = GetComponentInChildren<Animator>();
Scanner = GetComponent<EnvironmentScanner>();
2026-04-30 16:52:19 +07:00
2026-04-28 00:07:42 +07:00
Stats = GetComponent<PlayerStats>();
Interaction = GetComponent<PlayerInteraction>();
Movement = GetComponent<PlayerMovement>();
AnimationHandler = GetComponent<PlayerAnimationHandler>();
2026-04-05 00:08:43 +07:00
2026-04-28 00:07:42 +07:00
AnimationHandler.Initialize(Anim);
Movement.Initialize(Controller);
Interaction.Initialize(Scanner);
2026-03-26 20:27:19 +07:00
}
2026-04-15 19:53:29 +07:00
private void Start()
{
2026-04-25 18:20:16 +07:00
if (Runner == null || !Runner.IsRunning) InitializePlayer();
2026-04-15 19:53:29 +07:00
}
2026-04-03 22:46:17 +07:00
public override void Spawned()
2026-03-26 20:27:19 +07:00
{
2026-04-15 19:53:29 +07:00
InitializePlayer();
if (Object != null && !Object.HasInputAuthority && Runner.IsClient)
{
if (Controller != null) Controller.enabled = false;
}
}
private void InitializePlayer()
{
2026-04-25 18:20:16 +07:00
if (currentState == null) SwitchState(new PlayerIdleState(this));
2026-03-26 20:27:19 +07:00
2026-04-15 19:53:29 +07:00
bool isOffline = Runner == null || !Runner.IsRunning;
2026-04-25 18:20:16 +07:00
if (isOffline || (Object != null && Object.HasInputAuthority))
2026-03-26 20:27:19 +07:00
{
2026-04-03 22:46:17 +07:00
Local = this;
CameraController cameraController = GameObject.FindAnyObjectByType<CameraController>();
if (cameraController != null)
{
Cam = cameraController;
2026-04-05 00:08:43 +07:00
Cam.followTarget = transform;
Cam.inputReader = Input;
2026-04-03 22:46:17 +07:00
}
2026-04-30 16:52:19 +07:00
if (Input != null)
{
Input.OnNextInteractEvent -= Interaction.NextInteract;
Input.OnNextInteractEvent += Interaction.NextInteract;
Input.OnPreviousInteractEvent -= Interaction.PreviousInteract;
Input.OnPreviousInteractEvent += Interaction.PreviousInteract;
}
2026-04-15 19:53:29 +07:00
if (Controller != null) Controller.enabled = true;
2026-04-08 12:38:39 +07:00
}
2026-03-26 20:27:19 +07:00
}
2026-04-30 16:52:19 +07:00
private void OnDestroy()
{
if (Input != null && Interaction != null)
{
Input.OnNextInteractEvent -= Interaction.NextInteract;
Input.OnPreviousInteractEvent -= Interaction.PreviousInteract;
}
}
2026-04-08 12:38:39 +07:00
public void Rotate(Vector3 moveDirection, float deltaTime)
{
2026-04-28 00:07:42 +07:00
Movement.Rotate(transform, moveDirection, deltaTime);
2026-04-08 12:38:39 +07:00
}
public void Move(Vector3 velocity, float animatorSpeed, float deltaTime)
2026-04-05 00:08:43 +07:00
{
2026-04-30 16:52:19 +07:00
bool canMove = (Runner == null || !Runner.IsRunning) || (Object != null && Object.IsValid && (Object.HasInputAuthority || Runner.IsServer));
2026-04-15 19:53:29 +07:00
if (!canMove) return;
2026-04-08 12:38:39 +07:00
2026-04-28 00:07:42 +07:00
Movement.Move(Controller, velocity, deltaTime);
2026-04-30 16:52:19 +07:00
2026-04-08 12:38:39 +07:00
localAnimatorSpeed = animatorSpeed;
2026-04-30 16:52:19 +07:00
if (Object != null && Object.IsValid && Object.HasStateAuthority)
2026-04-05 00:08:43 +07:00
{
2026-04-08 12:38:39 +07:00
NetworkedSpeed = animatorSpeed;
2026-04-05 00:08:43 +07:00
NetworkedMoveInput = MoveInput;
}
UpdateAnimator(deltaTime);
}
private void UpdateAnimator(float deltaTime)
{
2026-04-30 16:52:19 +07:00
bool isNetworked = Runner != null && Runner.IsRunning && Object != null && Object.IsValid;
float speedValue = (!isNetworked || Object.HasInputAuthority) ? localAnimatorSpeed : NetworkedSpeed;
Vector2 inputVector = (!isNetworked || Object.HasInputAuthority) ? MoveInput : NetworkedMoveInput;
2026-04-28 00:07:42 +07:00
AnimationHandler.UpdateAnimator(speedValue, inputVector, deltaTime);
2026-04-05 00:08:43 +07:00
}
2026-04-03 22:46:17 +07:00
public override void FixedUpdateNetwork()
2026-03-26 20:27:19 +07:00
{
2026-04-15 19:53:29 +07:00
bool isRunning = Runner != null && Runner.IsRunning;
2026-04-30 16:52:19 +07:00
if (isRunning && (Object == null || !Object.IsValid)) return;
2026-04-03 22:46:17 +07:00
2026-04-05 00:08:43 +07:00
if (GetInput(out PlayerInputData data))
2026-04-03 22:46:17 +07:00
{
2026-04-05 00:08:43 +07:00
MoveInput = data.Direction;
2026-04-30 16:52:19 +07:00
IsSprintHeld = (bool)data.sprint;
2026-04-15 19:53:29 +07:00
if (isRunning) NetworkedCameraRotation = data.rot;
}
else if (!isRunning)
{
MoveInput = new Vector2(UnityEngine.Input.GetAxisRaw("Horizontal"), UnityEngine.Input.GetAxisRaw("Vertical"));
IsSprintHeld = UnityEngine.Input.GetKey(KeyCode.LeftShift);
2026-04-03 22:46:17 +07:00
}
2026-04-30 16:52:19 +07:00
if (!isRunning || (Object != null && Object.IsValid && (Object.HasInputAuthority || Runner.IsServer)))
2026-04-25 18:20:16 +07:00
{
if (hasControl)
{
2026-04-28 00:07:42 +07:00
Movement.CheckGround(transform);
Interaction.UpdateInteractables();
2026-04-25 18:20:16 +07:00
currentState?.Tick(isRunning ? Runner.DeltaTime : Time.fixedDeltaTime);
}
}
2026-04-29 13:10:00 +07:00
}
public override void Render()
{
bool isRunning = Runner != null && Runner.IsRunning;
2026-04-30 16:52:19 +07:00
if (isRunning && Object != null && Object.IsValid && !Object.HasInputAuthority)
2026-04-05 00:08:43 +07:00
{
2026-04-29 13:10:00 +07:00
// Smooth interpolation for proxies
if (Movement.NetworkedPosition != Vector3.zero)
{
transform.position = Vector3.Lerp(transform.position, Movement.NetworkedPosition, Runner.DeltaTime * 15f);
}
2026-04-05 00:08:43 +07:00
UpdateAnimator(Runner.DeltaTime);
}
2026-04-29 13:10:00 +07:00
else if (!isRunning)
{
UpdateAnimator(Time.deltaTime);
}
2026-04-15 19:53:29 +07:00
}
private void Update()
{
2026-04-25 18:20:16 +07:00
if (Runner == null || !Runner.IsRunning) FixedUpdateNetwork();
2026-03-26 20:27:19 +07:00
}
2026-04-28 00:07:42 +07:00
public IInteractable GetInteractable() => Interaction.GetInteractable();
public void SetGroundCheck(float radius, Vector3 offset) => Movement.SetGroundCheck(radius, offset);
2026-03-26 20:27:19 +07:00
public void SwitchState(PlayerBaseState newState)
{
currentState?.Exit();
currentState = newState;
currentState?.Enter();
}
public void SetControl(bool control)
{
hasControl = control;
2026-04-05 00:08:43 +07:00
if (Controller != null) Controller.enabled = control;
2026-04-28 00:07:42 +07:00
if (!control) AnimationHandler.SetSpeed(0f);
2026-03-26 20:27:19 +07:00
}
private void OnDrawGizmosSelected()
{
2026-04-28 00:07:42 +07:00
if (Movement == null) return;
2026-03-26 20:27:19 +07:00
Gizmos.color = new Color(0, 1, 0, 0.5f);
2026-04-28 00:07:42 +07:00
Gizmos.DrawSphere(transform.TransformPoint(Movement.GroundCheckOffset), Movement.GroundCheckRadius);
2026-03-26 20:27:19 +07:00
}
}
2026-04-23 23:09:54 +07:00
}