플레이어/적/몬스터 팀 시스템 생성
몬스터 및 적 AI 구현
This commit is contained in:
@@ -6,12 +6,17 @@ namespace Northbound
|
||||
/// <summary>
|
||||
/// 플레이어가 자원을 건내받아 게임의 전역 자원으로 관리하는 중앙 허브
|
||||
/// </summary>
|
||||
public class Core : NetworkBehaviour, IInteractable
|
||||
public class Core : NetworkBehaviour, IInteractable, IDamageable, ITeamMember
|
||||
{
|
||||
[Header("Core Settings")]
|
||||
public int maxStorageCapacity = 1000; // 코어의 최대 저장 용량
|
||||
public bool unlimitedStorage = false; // 무제한 저장소
|
||||
|
||||
[Header("Health")]
|
||||
public int maxHealth = 1000;
|
||||
public GameObject damageEffectPrefab;
|
||||
public GameObject destroyEffectPrefab;
|
||||
|
||||
[Header("Deposit Settings")]
|
||||
public bool depositAll = true; // true: 전부 건네기, false: 일부만 건네기
|
||||
public int depositAmountPerInteraction = 10; // depositAll이 false일 때 한 번에 건네는 양
|
||||
@@ -32,17 +37,163 @@ namespace Northbound
|
||||
NetworkVariableWritePermission.Server
|
||||
);
|
||||
|
||||
private NetworkVariable<int> _currentHealth = new NetworkVariable<int>(
|
||||
0,
|
||||
NetworkVariableReadPermission.Everyone,
|
||||
NetworkVariableWritePermission.Server
|
||||
);
|
||||
|
||||
public int TotalResources => _totalResources.Value;
|
||||
public int MaxStorageCapacity => maxStorageCapacity;
|
||||
public int CurrentHealth => _currentHealth.Value;
|
||||
public int MaxHealth => maxHealth;
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
if (IsServer)
|
||||
{
|
||||
_totalResources.Value = 0;
|
||||
_currentHealth.Value = maxHealth;
|
||||
}
|
||||
|
||||
_currentHealth.OnValueChanged += OnHealthChanged;
|
||||
}
|
||||
|
||||
public override void OnNetworkDespawn()
|
||||
{
|
||||
_currentHealth.OnValueChanged -= OnHealthChanged;
|
||||
}
|
||||
|
||||
private void OnHealthChanged(int previousValue, int newValue)
|
||||
{
|
||||
Debug.Log($"<color=red>[Core] 코어 체력 변경: {previousValue} → {newValue} ({newValue}/{maxHealth})</color>");
|
||||
}
|
||||
|
||||
#region ITeamMember Implementation
|
||||
|
||||
public TeamType GetTeam()
|
||||
{
|
||||
return TeamType.Player; // 코어는 플레이어 팀
|
||||
}
|
||||
|
||||
public void SetTeam(TeamType team)
|
||||
{
|
||||
// 코어의 팀은 변경할 수 없음 (항상 플레이어 팀)
|
||||
Debug.LogWarning("[Core] 코어의 팀은 변경할 수 없습니다.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDamageable Implementation
|
||||
|
||||
public void TakeDamage(int damage, ulong attackerId)
|
||||
{
|
||||
if (!IsServer) return;
|
||||
if (_currentHealth.Value <= 0) return;
|
||||
|
||||
int actualDamage = Mathf.Min(damage, _currentHealth.Value);
|
||||
_currentHealth.Value -= actualDamage;
|
||||
|
||||
Debug.Log($"<color=red>[Core] 코어가 {actualDamage} 데미지를 받았습니다! 남은 체력: {_currentHealth.Value}/{maxHealth}</color>");
|
||||
|
||||
// 데미지 이펙트
|
||||
ShowDamageEffectClientRpc();
|
||||
|
||||
// 체력이 0이 되면 게임 오버
|
||||
if (_currentHealth.Value <= 0)
|
||||
{
|
||||
OnCoreDestroyed();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCoreDestroyed()
|
||||
{
|
||||
if (!IsServer) return;
|
||||
|
||||
Debug.Log($"<color=red>[Core] 코어가 파괴되었습니다! 게임 오버!</color>");
|
||||
|
||||
// 파괴 이펙트
|
||||
ShowDestroyEffectClientRpc();
|
||||
|
||||
// 게임 오버 로직 (추후 구현)
|
||||
// GameManager.Instance?.OnGameOver();
|
||||
}
|
||||
|
||||
[Rpc(SendTo.ClientsAndHost)]
|
||||
private void ShowDamageEffectClientRpc()
|
||||
{
|
||||
if (damageEffectPrefab != null)
|
||||
{
|
||||
GameObject effect = Instantiate(damageEffectPrefab, transform.position + Vector3.up * 2f, Quaternion.identity);
|
||||
Destroy(effect, 2f);
|
||||
}
|
||||
}
|
||||
|
||||
[Rpc(SendTo.ClientsAndHost)]
|
||||
private void ShowDestroyEffectClientRpc()
|
||||
{
|
||||
if (destroyEffectPrefab != null)
|
||||
{
|
||||
GameObject effect = Instantiate(destroyEffectPrefab, transform.position, Quaternion.identity);
|
||||
Destroy(effect, 5f);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Resource Management
|
||||
|
||||
/// <summary>
|
||||
/// 자원을 소비할 수 있는지 확인
|
||||
/// </summary>
|
||||
public bool CanConsumeResource(int amount)
|
||||
{
|
||||
return _totalResources.Value >= amount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 자원 소비 (서버에서만)
|
||||
/// </summary>
|
||||
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
|
||||
public void ConsumeResourceServerRpc(int amount)
|
||||
{
|
||||
if (!CanConsumeResource(amount))
|
||||
{
|
||||
Debug.LogWarning($"[Core] 자원이 부족합니다. 필요: {amount}, 보유: {_totalResources.Value}");
|
||||
return;
|
||||
}
|
||||
|
||||
int previousAmount = _totalResources.Value;
|
||||
_totalResources.Value -= amount;
|
||||
|
||||
Debug.Log($"<color=yellow>[Core] {amount} 자원 소비. 남은 자원: {_totalResources.Value}/{maxStorageCapacity}</color>");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 자원 추가 (서버에서만)
|
||||
/// </summary>
|
||||
public void AddResource(int amount)
|
||||
{
|
||||
if (!IsServer) return;
|
||||
|
||||
if (!unlimitedStorage)
|
||||
{
|
||||
int availableSpace = maxStorageCapacity - _totalResources.Value;
|
||||
amount = Mathf.Min(amount, availableSpace);
|
||||
}
|
||||
|
||||
if (amount > 0)
|
||||
{
|
||||
_totalResources.Value += amount;
|
||||
Debug.Log($"<color=green>[Core] {amount} 자원 추가. 총 자원: {_totalResources.Value}" +
|
||||
(unlimitedStorage ? "" : $"/{maxStorageCapacity}") + "</color>");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IInteractable Implementation
|
||||
|
||||
public bool CanInteract(ulong playerId)
|
||||
{
|
||||
// 저장소가 가득 찼는지 확인 (무제한이 아닐 때)
|
||||
@@ -75,6 +226,33 @@ namespace Northbound
|
||||
DepositResourceServerRpc(playerId);
|
||||
}
|
||||
|
||||
public string GetInteractionPrompt()
|
||||
{
|
||||
if (unlimitedStorage)
|
||||
{
|
||||
return "자원 보관 (무제한)";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"자원 보관 ({_totalResources.Value}/{maxStorageCapacity})";
|
||||
}
|
||||
}
|
||||
|
||||
public string GetInteractionAnimation()
|
||||
{
|
||||
return interactionAnimationTrigger;
|
||||
}
|
||||
|
||||
public InteractionEquipmentData GetEquipmentData()
|
||||
{
|
||||
return equipmentData;
|
||||
}
|
||||
|
||||
public Transform GetTransform()
|
||||
{
|
||||
return transform;
|
||||
}
|
||||
|
||||
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
|
||||
private void DepositResourceServerRpc(ulong playerId)
|
||||
{
|
||||
@@ -132,8 +310,8 @@ namespace Northbound
|
||||
// 코어에 자원 추가
|
||||
_totalResources.Value += depositAmount;
|
||||
|
||||
Debug.Log($"플레이어 {playerId}가 {depositAmount} 자원을 코어에 건넸습니다. 코어 총 자원: {_totalResources.Value}" +
|
||||
(unlimitedStorage ? "" : $"/{maxStorageCapacity}"));
|
||||
Debug.Log($"<color=green>[Core] 플레이어 {playerId}가 {depositAmount} 자원을 건넸습니다. 코어 총 자원: {_totalResources.Value}" +
|
||||
(unlimitedStorage ? "" : $"/{maxStorageCapacity}") + "</color>");
|
||||
|
||||
ShowDepositEffectClientRpc();
|
||||
}
|
||||
@@ -148,76 +326,6 @@ namespace Northbound
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 게임 시스템이 코어의 자원을 사용 (건물 건설 등)
|
||||
/// </summary>
|
||||
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
|
||||
public void ConsumeResourceServerRpc(int amount)
|
||||
{
|
||||
if (amount <= 0) return;
|
||||
|
||||
int actualAmount = Mathf.Min(amount, _totalResources.Value);
|
||||
_totalResources.Value -= actualAmount;
|
||||
|
||||
Debug.Log($"코어에서 {actualAmount} 자원을 사용했습니다. 남은 자원: {_totalResources.Value}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 자원을 사용할 수 있는지 확인
|
||||
/// </summary>
|
||||
public bool CanConsumeResource(int amount)
|
||||
{
|
||||
return _totalResources.Value >= amount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 코어에 자원 추가 (디버그/관리자 기능)
|
||||
/// </summary>
|
||||
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
|
||||
public void AddResourceServerRpc(int amount)
|
||||
{
|
||||
if (amount <= 0) return;
|
||||
|
||||
if (!unlimitedStorage)
|
||||
{
|
||||
int availableSpace = maxStorageCapacity - _totalResources.Value;
|
||||
amount = Mathf.Min(amount, availableSpace);
|
||||
}
|
||||
|
||||
_totalResources.Value += amount;
|
||||
Debug.Log($"코어에 {amount} 자원이 추가되었습니다. 현재: {_totalResources.Value}");
|
||||
}
|
||||
|
||||
public string GetInteractionPrompt()
|
||||
{
|
||||
if (unlimitedStorage)
|
||||
{
|
||||
return depositAll ?
|
||||
$"[E] 자원 모두 건네기" :
|
||||
$"[E] 자원 건네기 ({depositAmountPerInteraction}개씩)";
|
||||
}
|
||||
|
||||
if (_totalResources.Value >= maxStorageCapacity)
|
||||
return "코어 저장소 가득 찼음";
|
||||
|
||||
return depositAll ?
|
||||
$"[E] 자원 모두 건네기 ({_totalResources.Value}/{maxStorageCapacity})" :
|
||||
$"[E] 자원 건네기 ({_totalResources.Value}/{maxStorageCapacity})";
|
||||
}
|
||||
|
||||
public string GetInteractionAnimation()
|
||||
{
|
||||
return interactionAnimationTrigger;
|
||||
}
|
||||
|
||||
public InteractionEquipmentData GetEquipmentData()
|
||||
{
|
||||
return equipmentData;
|
||||
}
|
||||
|
||||
public Transform GetTransform()
|
||||
{
|
||||
return transform;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user