플레이어/적/몬스터 팀 시스템 생성
몬스터 및 적 AI 구현
This commit is contained in:
191
Assets/Scripts/EnemyUnit.cs
Normal file
191
Assets/Scripts/EnemyUnit.cs
Normal file
@@ -0,0 +1,191 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user