191 lines
6.1 KiB
C#
191 lines
6.1 KiB
C#
using Unity.Netcode;
|
|
using UnityEngine;
|
|
|
|
namespace Northbound
|
|
{
|
|
/// <summary>
|
|
/// 적대 유닛 (적대세력 또는 몬스터)
|
|
/// </summary>
|
|
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<int> _currentHealth = new NetworkVariable<int>(
|
|
0,
|
|
NetworkVariableReadPermission.Everyone,
|
|
NetworkVariableWritePermission.Server
|
|
);
|
|
|
|
private NetworkVariable<TeamType> _team = new NetworkVariable<TeamType>(
|
|
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($"<color=magenta>[EnemyUnit] {gameObject.name} 스폰됨 (팀: {TeamManager.GetTeamName(_team.Value)})</color>");
|
|
}
|
|
}
|
|
|
|
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<ITeamMember>();
|
|
if (attackerTeamMember != null)
|
|
{
|
|
if (!TeamManager.CanAttack(attackerTeamMember, this))
|
|
{
|
|
Debug.Log($"<color=yellow>[EnemyUnit] {TeamManager.GetTeamName(attackerTeamMember.GetTeam())} 팀은 {TeamManager.GetTeamName(_team.Value)} 팀을 공격할 수 없습니다.</color>");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
int actualDamage = Mathf.Min(damage, _currentHealth.Value);
|
|
_currentHealth.Value -= actualDamage;
|
|
|
|
Debug.Log($"<color=red>[EnemyUnit] {gameObject.name} ({TeamManager.GetTeamName(_team.Value)})이(가) {actualDamage} 데미지를 받았습니다. 남은 체력: {_currentHealth.Value}/{maxHealth}</color>");
|
|
|
|
// 데미지 이펙트
|
|
ShowDamageEffectClientRpc();
|
|
|
|
// 체력이 0이 되면 파괴
|
|
if (_currentHealth.Value <= 0)
|
|
{
|
|
DestroyUnit(attackerId);
|
|
}
|
|
}
|
|
|
|
private void DestroyUnit(ulong attackerId)
|
|
{
|
|
if (!IsServer) return;
|
|
|
|
Debug.Log($"<color=red>[EnemyUnit] {gameObject.name} ({TeamManager.GetTeamName(_team.Value)})이(가) 파괴되었습니다! (공격자: {attackerId})</color>");
|
|
|
|
// 파괴 이펙트
|
|
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
|
|
}
|
|
}
|
|
} |