diff --git a/Assets/Scripts/Player/PlayerNetworkController.cs b/Assets/Scripts/Player/PlayerNetworkController.cs index 6dcce4b0..22a6da79 100644 --- a/Assets/Scripts/Player/PlayerNetworkController.cs +++ b/Assets/Scripts/Player/PlayerNetworkController.cs @@ -18,6 +18,7 @@ namespace Colosseum.Player // 네트워크 동기화 변수 private NetworkVariable currentHealth = new NetworkVariable(100f); private NetworkVariable currentMana = new NetworkVariable(50f); + private NetworkVariable isDead = new NetworkVariable(false); public float Health => currentHealth.Value; public float Mana => currentMana.Value; @@ -29,9 +30,13 @@ namespace Colosseum.Player public event Action OnHealthChanged; // (oldValue, newValue) public event Action OnManaChanged; // (oldValue, newValue) + // 사망 이벤트 + public event Action OnDeath; + public event Action OnDeathStateChanged; // (isDead) + // IDamageable 구현 public float CurrentHealth => currentHealth.Value; - public bool IsDead => currentHealth.Value <= 0f; + public bool IsDead => isDead.Value; public override void OnNetworkSpawn() { @@ -44,12 +49,14 @@ namespace Colosseum.Player // 네트워크 변수 변경 콜백 등록 currentHealth.OnValueChanged += HandleHealthChanged; currentMana.OnValueChanged += HandleManaChanged; + isDead.OnValueChanged += HandleDeathStateChanged; // 초기화 if (IsServer) { currentHealth.Value = MaxHealth; currentMana.Value = MaxMana; + isDead.Value = false; } } @@ -58,6 +65,7 @@ namespace Colosseum.Player // 콜백 해제 currentHealth.OnValueChanged -= HandleHealthChanged; currentMana.OnValueChanged -= HandleManaChanged; + isDead.OnValueChanged -= HandleDeathStateChanged; } private void HandleHealthChanged(float oldValue, float newValue) @@ -70,12 +78,19 @@ namespace Colosseum.Player OnManaChanged?.Invoke(oldValue, newValue); } + private void HandleDeathStateChanged(bool oldValue, bool newValue) + { + OnDeathStateChanged?.Invoke(newValue); + } + /// /// 대미지 적용 (서버에서만 실행) /// [Rpc(SendTo.Server)] public void TakeDamageRpc(float damage) { + if (isDead.Value) return; + currentHealth.Value = Mathf.Max(0f, currentHealth.Value - damage); if (currentHealth.Value <= 0f) @@ -111,10 +126,75 @@ namespace Colosseum.Player currentMana.Value = Mathf.Min(MaxMana, currentMana.Value + amount); } + /// + /// 사망 처리 (서버에서만 실행) + /// private void HandleDeath() { - // TODO: 사망 처리 로직 - Debug.Log($"Player {OwnerClientId} died!"); + if (isDead.Value) return; + + isDead.Value = true; + + // 이동 비활성화 + var movement = GetComponent(); + if (movement != null) + { + movement.enabled = false; + } + + // 스킬 입력 비활성화 + var skillInput = GetComponent(); + if (skillInput != null) + { + skillInput.enabled = false; + } + + // 사망 애니메이션 재생 + var animator = GetComponentInChildren(); + if (animator != null) + { + animator.SetTrigger("Die"); + } + + // 사망 이벤트 발생 + OnDeath?.Invoke(this); + + Debug.Log($"[Player] Player {OwnerClientId} died!"); + } + + /// + /// 리스폰 (서버에서만 실행) + /// + public void Respawn() + { + if (!IsServer) return; + + isDead.Value = false; + currentHealth.Value = MaxHealth; + currentMana.Value = MaxMana; + + // 이동 재활성화 + var movement = GetComponent(); + if (movement != null) + { + movement.enabled = true; + } + + // 스킬 입력 재활성화 + var skillInput = GetComponent(); + if (skillInput != null) + { + skillInput.enabled = true; + } + + // 애니메이션 리셋 + var animator = GetComponentInChildren(); + if (animator != null) + { + animator.Rebind(); + } + + Debug.Log($"[Player] Player {OwnerClientId} respawned!"); } #region IDamageable @@ -123,7 +203,7 @@ namespace Colosseum.Player /// public float TakeDamage(float damage, object source = null) { - if (!IsServer) return 0f; + if (!IsServer || isDead.Value) return 0f; float actualDamage = Mathf.Min(damage, currentHealth.Value); currentHealth.Value = Mathf.Max(0f, currentHealth.Value - damage); @@ -141,7 +221,7 @@ namespace Colosseum.Player /// public float Heal(float amount) { - if (!IsServer) return 0f; + if (!IsServer || isDead.Value) return 0f; float actualHeal = Mathf.Min(amount, MaxHealth - currentHealth.Value); currentHealth.Value = Mathf.Min(MaxHealth, currentHealth.Value + amount); diff --git a/Assets/Scripts/Player/PlayerSkillInput.cs b/Assets/Scripts/Player/PlayerSkillInput.cs index c69f2798..d5574d30 100644 --- a/Assets/Scripts/Player/PlayerSkillInput.cs +++ b/Assets/Scripts/Player/PlayerSkillInput.cs @@ -107,6 +107,10 @@ namespace Colosseum.Player return; } + // 사망 상태 체크 + if (networkController != null && networkController.IsDead) + return; + // 로컬 체크 (빠른 피드백용) if (skillController.IsExecutingSkill) { @@ -145,6 +149,10 @@ namespace Colosseum.Player if (skill == null) return; // 서버에서 다시 검증 + // 사망 상태 체크 + if (networkController != null && networkController.IsDead) + return; + if (skillController.IsExecutingSkill || skillController.IsOnCooldown(skill)) return;