136 lines
4.2 KiB
C#
136 lines
4.2 KiB
C#
using UnityEngine;
|
|
|
|
namespace Ashwild.Player
|
|
{
|
|
/// <summary>
|
|
/// Owns the local player's death-and-return. It flips locomotion into its dead state when the
|
|
/// player dies, and on <see cref="Respawn"/> teleports the body back to the current respawn pose,
|
|
/// revives the stats and clears the dead state. The respawn pose starts at the assigned spawn
|
|
/// point (or wherever the player begins) and is reassigned live when the player claims a bed —
|
|
/// pushed in over the bus, so it stays pure local state that never crosses the wire (§3).
|
|
/// </summary>
|
|
[DisallowMultipleComponent]
|
|
public class PlayerLifecycle : MonoBehaviour
|
|
{
|
|
#region Serialized Fields
|
|
|
|
[Header("Spawn point (auto-captured at scene start if left empty)")]
|
|
[SerializeField] private Transform spawnPoint;
|
|
|
|
#endregion
|
|
|
|
#region State
|
|
|
|
private PlayerLocomotion locomotion;
|
|
private Rigidbody rb;
|
|
|
|
private Vector3 spawnPosition;
|
|
private Quaternion spawnRotation;
|
|
private bool isDead;
|
|
|
|
#endregion
|
|
|
|
#region Unity Lifecycle
|
|
|
|
/// <summary>
|
|
/// Caches the sibling components the respawn drives.
|
|
/// </summary>
|
|
private void Awake()
|
|
{
|
|
locomotion = GetComponent<PlayerLocomotion>();
|
|
rb = GetComponent<Rigidbody>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Seeds the respawn pose from the assigned spawn point, or the player's starting pose when
|
|
/// none is set, so a death before any bed is claimed still returns somewhere valid.
|
|
/// </summary>
|
|
private void Start()
|
|
{
|
|
if (spawnPoint != null)
|
|
{
|
|
spawnPosition = spawnPoint.position;
|
|
spawnRotation = spawnPoint.rotation;
|
|
}
|
|
else
|
|
{
|
|
spawnPosition = transform.position;
|
|
spawnRotation = transform.rotation;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Subscribes to death and to respawn-point reassignments (claiming a bed).
|
|
/// </summary>
|
|
private void OnEnable()
|
|
{
|
|
PlayerEvents.Died += OnDied;
|
|
PlayerEvents.RespawnPointChanged += HandleRespawnPointChanged;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unsubscribes — mirrors OnEnable exactly.
|
|
/// </summary>
|
|
private void OnDisable()
|
|
{
|
|
PlayerEvents.Died -= OnDied;
|
|
PlayerEvents.RespawnPointChanged -= HandleRespawnPointChanged;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Event Handlers
|
|
|
|
/// <summary>
|
|
/// Freezes the player into its dead state once, ignoring repeat death events.
|
|
/// </summary>
|
|
private void OnDied()
|
|
{
|
|
if (isDead) return;
|
|
isDead = true;
|
|
if (locomotion != null) locomotion.SetDead(true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adopts a new respawn pose pushed over the bus (the player claimed a bed). Local state
|
|
/// only — the respawn location is never networked, so each client keeps its own.
|
|
/// </summary>
|
|
private void HandleRespawnPointChanged(Vector3 position, Quaternion rotation)
|
|
=> SetSpawnPoint(position, rotation);
|
|
|
|
#endregion
|
|
|
|
#region Public API
|
|
|
|
/// <summary>
|
|
/// Returns the player to the current respawn pose: zeroes momentum, teleports the body,
|
|
/// revives the stats and clears the dead state.
|
|
/// </summary>
|
|
public void Respawn()
|
|
{
|
|
if (rb != null)
|
|
{
|
|
rb.linearVelocity = Vector3.zero;
|
|
rb.angularVelocity = Vector3.zero;
|
|
}
|
|
transform.SetPositionAndRotation(spawnPosition, spawnRotation);
|
|
|
|
if (PlayerStats.Instance != null) PlayerStats.Instance.Revive();
|
|
if (locomotion != null) locomotion.SetDead(false);
|
|
|
|
isDead = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Overrides the respawn pose directly with a world position and rotation.
|
|
/// </summary>
|
|
public void SetSpawnPoint(Vector3 position, Quaternion rotation)
|
|
{
|
|
spawnPosition = position;
|
|
spawnRotation = rotation;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|