(Feat) Bed Systeme

This commit is contained in:
2026-07-08 18:08:34 +02:00
parent 78fd2d534a
commit ebb7ff5713
13 changed files with 344 additions and 55 deletions
+51
View File
@@ -0,0 +1,51 @@
using UnityEngine;
using Ashwild.Interaction;
using Ashwild.Player;
namespace Ashwild.Building
{
/// <summary>
/// A placed bed the local player interacts with to make it their respawn point (Valheim-style
/// claim). Interacting pushes the bed's pose onto the bus, where the local PlayerLifecycle adopts
/// it — so the respawn point is per-player and never networked: one bed at the base can serve as
/// everyone's spawn, yet each teammate only rebinds their own by interacting, and a bed placed
/// far away changes nobody else's. The bed itself is an ordinary built structure (instantiated
/// locally on every client from the BuildRegistry), never a NetworkObject — so there is nothing
/// to add on the build side: dropping this component on a buildable's BuiltPrefab is enough.
/// </summary>
[DisallowMultipleComponent]
[RequireComponent(typeof(Collider))]
public class Bed : MonoBehaviour, IInteractable
{
#region Serialized Fields
[Header("Respawn")]
[Tooltip("Where the player reappears when respawning here — a child placed beside the bed, facing away from it. Falls back to the bed's own transform when left empty.")]
[SerializeField] private Transform respawnAnchor;
[Tooltip("Label shown under the crosshair while aiming at the bed.")]
[SerializeField] private string interactionPrompt = "Définir le point de réveil";
#endregion
#region IInteractable
/// <summary>
/// Label shown under the crosshair while aiming at the bed.
/// </summary>
public string InteractionPrompt => interactionPrompt;
/// <summary>
/// Claims this bed as the local player's respawn point by broadcasting its pose over the bus.
/// Called by PlayerInteractor on the interacting client only (it is owner-gated), so only that
/// player rebinds — teammates are untouched.
/// </summary>
public void Interact()
{
Transform anchor = respawnAnchor != null ? respawnAnchor : transform;
PlayerEvents.RaiseRespawnPointChanged(anchor.position, anchor.rotation);
}
#endregion
}
}
+2
View File
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5b64acb9b3e11a6408744a646644c073
@@ -151,6 +151,7 @@ namespace Ashwild.Player
public static event Action Died;
public static event Action Respawned;
public static event Action<bool> DeathChanged;
public static event Action<Vector3, Quaternion> RespawnPointChanged; // the local player's respawn pose was reassigned (e.g. claimed a bed)
// ============================================================
// Network / session events
@@ -318,6 +319,16 @@ namespace Ashwild.Player
DeathChanged?.Invoke(false);
}
/// <summary>
/// Reassigns the local player's respawn pose (e.g. after claiming a bed). Owner-side only;
/// the pose is pure local state and is never networked — each client keeps its own.
/// </summary>
public static void RaiseRespawnPointChanged(Vector3 position, Quaternion rotation)
{
Log(nameof(RespawnPointChanged));
RespawnPointChanged?.Invoke(position, rotation);
}
public static void RaiseSessionStarting() { Log(nameof(SessionStarting)); SessionStarting?.Invoke(); }
public static void RaiseSessionStarted(string code)
{
+68 -11
View File
@@ -2,12 +2,25 @@ 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;
@@ -15,12 +28,23 @@ namespace Ashwild.Player
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)
@@ -35,9 +59,31 @@ namespace Ashwild.Player
}
}
private void OnEnable() { PlayerEvents.Died += OnDied; }
private void OnDisable() { PlayerEvents.Died -= OnDied; }
/// <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;
@@ -45,6 +91,21 @@ namespace Ashwild.Player
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)
@@ -52,8 +113,7 @@ namespace Ashwild.Player
rb.linearVelocity = Vector3.zero;
rb.angularVelocity = Vector3.zero;
}
transform.position = spawnPosition;
transform.rotation = spawnRotation;
transform.SetPositionAndRotation(spawnPosition, spawnRotation);
if (PlayerStats.Instance != null) PlayerStats.Instance.Revive();
if (locomotion != null) locomotion.SetDead(false);
@@ -61,18 +121,15 @@ namespace Ashwild.Player
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;
}
public void SetSpawnPoint(Transform t)
{
if (t == null) return;
spawnPoint = t;
spawnPosition = t.position;
spawnRotation = t.rotation;
}
#endregion
}
}