using Unity.Netcode;
using UnityEngine;
namespace Northbound
{
///
/// 적대 유닛 (적대세력 또는 몬스터)
///
public class EnemyUnit : NetworkBehaviour, IDamageable, ITeamMember, IVisionProvider
{
[Header("Team Settings")]
[Tooltip("이 유닛의 팀 (Hostile = 적대세력, Monster = 몬스터)")]
public TeamType enemyTeam = TeamType.Hostile;
[Header("Combat")]
public int maxHealth = 100;
public float visionRange = 10f;
[Header("Visual")]
public GameObject damageEffectPrefab;
public GameObject destroyEffectPrefab;
private NetworkVariable _currentHealth = new NetworkVariable(
0,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server
);
private NetworkVariable _team = new NetworkVariable(
TeamType.Neutral,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server
);
public override void OnNetworkSpawn()
{
base.OnNetworkSpawn();
if (IsServer)
{
_currentHealth.Value = maxHealth;
_team.Value = enemyTeam;
// FogOfWar 시스템에 등록
FogOfWarSystem.Instance?.RegisterVisionProvider(this);
Debug.Log($"[EnemyUnit] {gameObject.name} 스폰됨 (팀: {TeamManager.GetTeamName(_team.Value)})");
}
}
public override void OnNetworkDespawn()
{
base.OnNetworkDespawn();
if (IsServer)
{
FogOfWarSystem.Instance?.UnregisterVisionProvider(this);
}
}
#region IDamageable Implementation
public void TakeDamage(int damage, ulong attackerId)
{
if (!IsServer) return;
if (_currentHealth.Value <= 0) return;
// 공격자의 팀 확인
if (NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(attackerId, out NetworkObject attackerObj))
{
var attackerTeamMember = attackerObj.GetComponent();
if (attackerTeamMember != null)
{
if (!TeamManager.CanAttack(attackerTeamMember, this))
{
Debug.Log($"[EnemyUnit] {TeamManager.GetTeamName(attackerTeamMember.GetTeam())} 팀은 {TeamManager.GetTeamName(_team.Value)} 팀을 공격할 수 없습니다.");
return;
}
}
}
int actualDamage = Mathf.Min(damage, _currentHealth.Value);
_currentHealth.Value -= actualDamage;
Debug.Log($"[EnemyUnit] {gameObject.name} ({TeamManager.GetTeamName(_team.Value)})이(가) {actualDamage} 데미지를 받았습니다. 남은 체력: {_currentHealth.Value}/{maxHealth}");
// 데미지 이펙트
ShowDamageEffectClientRpc();
// 체력이 0이 되면 파괴
if (_currentHealth.Value <= 0)
{
DestroyUnit(attackerId);
}
}
private void DestroyUnit(ulong attackerId)
{
if (!IsServer) return;
Debug.Log($"[EnemyUnit] {gameObject.name} ({TeamManager.GetTeamName(_team.Value)})이(가) 파괴되었습니다! (공격자: {attackerId})");
// 파괴 이펙트
ShowDestroyEffectClientRpc();
// FogOfWar 시스템에서 제거
FogOfWarSystem.Instance?.UnregisterVisionProvider(this);
// 네트워크 오브젝트 파괴
Invoke(nameof(DespawnUnit), 0.5f);
}
private void DespawnUnit()
{
if (IsServer && NetworkObject != null)
{
NetworkObject.Despawn(true);
}
}
[ClientRpc]
private void ShowDamageEffectClientRpc()
{
if (damageEffectPrefab != null)
{
GameObject effect = Instantiate(damageEffectPrefab, transform.position, Quaternion.identity);
Destroy(effect, 2f);
}
}
[ClientRpc]
private void ShowDestroyEffectClientRpc()
{
if (destroyEffectPrefab != null)
{
GameObject effect = Instantiate(destroyEffectPrefab, transform.position, Quaternion.identity);
Destroy(effect, 3f);
}
}
#endregion
#region ITeamMember Implementation
public TeamType GetTeam() => _team.Value;
public void SetTeam(TeamType team)
{
if (!IsServer) return;
_team.Value = team;
}
#endregion
#region IVisionProvider Implementation
public ulong GetOwnerId() => OwnerClientId;
public float GetVisionRange() => visionRange;
public Transform GetTransform() => transform;
public bool IsActive() => IsSpawned && _currentHealth.Value > 0;
#endregion
private void OnDrawGizmosSelected()
{
// 팀 색상으로 시야 범위 표시
Color teamColor = Application.isPlaying
? TeamManager.GetTeamColor(_team.Value)
: TeamManager.GetTeamColor(enemyTeam);
Gizmos.color = new Color(teamColor.r, teamColor.g, teamColor.b, 0.3f);
Gizmos.DrawWireSphere(transform.position, visionRange);
#if UNITY_EDITOR
if (Application.isPlaying)
{
UnityEditor.Handles.Label(transform.position + Vector3.up * 2f,
$"Team: {TeamManager.GetTeamName(_team.Value)}\nHP: {_currentHealth.Value}/{maxHealth}");
}
else
{
UnityEditor.Handles.Label(transform.position + Vector3.up * 2f,
$"Team: {TeamManager.GetTeamName(enemyTeam)}");
}
#endif
}
}
}