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

129 lines
4.7 KiB
C#

using UnityEngine;
using Fusion;
namespace OnlyScove.Scripts
{
public class PlayerMovement : NetworkBehaviour
{
[field: Header("Movement Settings")]
[field: SerializeField] public float WalkSpeed { get; private set; } = 3f;
[field: SerializeField] public float RunSpeed { get; private set; } = 6f;
[field: SerializeField] public float SprintSpeed { get; private set; } = 9f;
[field: SerializeField] public float SneakSpeed { get; private set; } = 1.5f;
[field: SerializeField] public float DashForce { get; private set; } = 10f;
[field: SerializeField] public float RotationSpeed { get; private set; } = 500f;
[field: Header("Airborne Settings")]
[field: SerializeField] public float JumpHeight { get; private set; } = 2f;
[field: SerializeField] public float Gravity { get; private set; } = -15f;
[field: SerializeField] public float ThrustDownwardForce { get; private set; } = -20f;
[field: Header("Ground Check")]
[field: SerializeField] public float GroundCheckRadius { get; private set; } = 0.2f;
[field: SerializeField] public Vector3 GroundCheckOffset { get; private set; }
[field: SerializeField] public LayerMask GroundMask { get; private set; }
// Networked shadow properties
[Networked] private NetworkBool _isGroundedNet { get; set; }
[Networked] private NetworkBool _wasGroundedNet { get; set; }
[Networked] private float _velocityYNet { get; set; }
[Networked] public Vector3 NetworkedPosition { get; set; }
// Local backing fields for Offline mode
private bool _isGroundedLocal;
private bool _wasGroundedLocal;
private float _velocityYLocal;
// Public wrappers that handle both Online and Offline
public bool IsGrounded
{
get => (Object != null && Object.IsValid) ? (bool)_isGroundedNet : _isGroundedLocal;
set { if (Object != null && Object.IsValid) _isGroundedNet = value; _isGroundedLocal = value; }
}
public bool WasGrounded
{
get => (Object != null && Object.IsValid) ? (bool)_wasGroundedNet : _wasGroundedLocal;
set { if (Object != null && Object.IsValid) _wasGroundedNet = value; _wasGroundedLocal = value; }
}
public float VelocityY
{
get => (Object != null && Object.IsValid) ? _velocityYNet : _velocityYLocal;
set { if (Object != null && Object.IsValid) _velocityYNet = value; _velocityYLocal = value; }
}
private CharacterController controller;
private float jumpCooldown = 0f;
public void Initialize(CharacterController controller)
{
this.controller = controller;
_isGroundedLocal = true; // Safe local initialization
}
public override void Spawned()
{
// Initialize networked state once spawned (only on State Authority)
if (Object.HasStateAuthority)
{
_isGroundedNet = true;
_wasGroundedNet = true;
_velocityYNet = 0f;
}
}
public void CheckGround(Transform playerTransform, float deltaTime)
{
if (jumpCooldown > 0)
{
jumpCooldown -= deltaTime;
WasGrounded = IsGrounded;
IsGrounded = false;
return;
}
WasGrounded = IsGrounded;
bool sphereCheck = Physics.CheckSphere(playerTransform.TransformPoint(GroundCheckOffset), GroundCheckRadius, GroundMask);
bool ccCheck = (controller != null) && controller.isGrounded;
IsGrounded = sphereCheck || ccCheck;
if (Object != null && Object.IsValid && Object.HasStateAuthority)
{
// State authority updates the networked position for reconciliation
NetworkedPosition = playerTransform.position;
}
}
public void Jump()
{
// Physic formula: v = sqrt(h * -2 * g)
VelocityY = Mathf.Sqrt(JumpHeight * -2f * Gravity);
IsGrounded = false;
jumpCooldown = 0.15f; // Ngăn không cho dính đất trong 0.15s đầu
}
public void Move(CharacterController controller, Vector3 velocity, float deltaTime)
{
if (controller != null && controller.enabled)
{
controller.Move(velocity * deltaTime);
}
}
public void Rotate(Transform playerTransform, Vector3 moveDirection, float deltaTime)
{
if (moveDirection == Vector3.zero) return;
Quaternion targetRot = Quaternion.LookRotation(moveDirection);
playerTransform.rotation = Quaternion.RotateTowards(playerTransform.rotation, targetRot, RotationSpeed * deltaTime);
}
public void SetGroundCheck(float radius, Vector3 offset)
{
GroundCheckRadius = radius;
GroundCheckOffset = offset;
}
}
}