129 lines
4.7 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|