건물 업그레이드 기능

This commit is contained in:
2026-02-25 18:56:26 +09:00
parent 0828bb214f
commit 3d2a9071bc
2 changed files with 381 additions and 1 deletions

View File

@@ -5,7 +5,7 @@ using Northbound.Data;
namespace Northbound
{
public class Building : NetworkBehaviour, IDamageable, IVisionProvider, ITeamMember, IHealthProvider
public class Building : NetworkBehaviour, IDamageable, IVisionProvider, ITeamMember, IHealthProvider, IInteractable
{
[Header("References")]
public TowerData buildingData;
@@ -66,6 +66,26 @@ namespace Northbound
private UnitHealthBar _healthBar;
private float _lastRegenTime;
// 업그레이드 관련
private NetworkVariable<bool> _isUpgrading = new NetworkVariable<bool>(
false,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server
);
private NetworkVariable<float> _upgradeProgress = new NetworkVariable<float>(
0f,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server
);
private NetworkVariable<int> _upgradeTargetId = new NetworkVariable<int>(
0,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server
);
private float _lastInteractionTime;
private const float INTERACTION_COOLDOWN = 0.5f;
public override void OnNetworkSpawn()
{
base.OnNetworkSpawn();
@@ -108,6 +128,8 @@ namespace Northbound
// 이벤트 구독
_currentHealth.OnValueChanged += OnHealthValueChanged;
_team.OnValueChanged += OnTeamValueChanged;
_upgradeProgress.OnValueChanged += OnUpgradeProgressChanged;
_isUpgrading.OnValueChanged += OnUpgradingChanged;
// 체력바 생성
if (showHealthBar && healthBarPrefab != null)
@@ -124,6 +146,8 @@ namespace Northbound
{
_currentHealth.OnValueChanged -= OnHealthValueChanged;
_team.OnValueChanged -= OnTeamValueChanged;
_upgradeProgress.OnValueChanged -= OnUpgradeProgressChanged;
_isUpgrading.OnValueChanged -= OnUpgradingChanged;
// FogOfWar 시스템에서 제거
if (IsServer && buildingData != null && buildingData.providesVision)
@@ -480,6 +504,265 @@ namespace Northbound
#endregion
#region IInteractable Implementation (Upgrade)
/// <summary>
/// 상호작용 가능 여부
/// </summary>
public bool CanInteract(ulong playerId)
{
// 쿨다운 확인
if (Time.time - _lastInteractionTime < INTERACTION_COOLDOWN)
return false;
// 같은 팀만 업그레이드 가능
TeamType team = GetPlayerTeam(playerId);
if (team != _team.Value)
return false;
// 업그레이드 중이면 진행 가능
if (_isUpgrading.Value)
return true;
// 업그레이드 시작 가능 여부 확인
if (buildingData == null || buildingData.upgradeTo == 0)
return false;
TowerData upgradeData = GetUpgradeData();
if (upgradeData == null)
return false;
// 자원이 충분한지 확인
var coreResourceManager = CoreResourceManager.Instance;
if (coreResourceManager == null || !coreResourceManager.CanAfford(upgradeData.mana))
return false;
return true;
}
/// <summary>
/// 상호작용 실행 (업그레이드)
/// </summary>
public void Interact(ulong playerId)
{
if (!CanInteract(playerId))
return;
// 서버에 업그레이드 요청
RequestUpgradeServerRpc(playerId);
}
[Rpc(SendTo.Server)]
private void RequestUpgradeServerRpc(ulong playerId)
{
if (!CanInteract(playerId))
return;
_lastInteractionTime = Time.time;
// 업그레이드가 시작되지 않았으면 시작만 하고 종료
if (!_isUpgrading.Value)
{
TowerData upgradeData = GetUpgradeData();
if (upgradeData == null)
return;
// 자원 확인 및 소비
var coreResourceManager = CoreResourceManager.Instance;
if (coreResourceManager == null || !coreResourceManager.CanAfford(upgradeData.mana))
return;
coreResourceManager.SpendResources(upgradeData.mana);
// 업그레이드 시작 - 토대로 교체
StartUpgradeToFoundation(upgradeData);
return;
}
// 이미 업그레이드 중이면 플레이어의 manpower만큼 진행
float playerManpower = GetPlayerManpower(playerId);
_upgradeProgress.Value += playerManpower;
// 완료 체크
TowerData targetData = BuildingManager.Instance?.GetTowerDataById(_upgradeTargetId.Value);
if (targetData != null && _upgradeProgress.Value >= targetData.manpower)
{
CompleteUpgrade(targetData);
}
}
/// <summary>
/// 업그레이드 시작 - 건물을 토대로 교체
/// </summary>
private void StartUpgradeToFoundation(TowerData upgradeData)
{
if (!IsServer) return;
if (BuildingManager.Instance == null) return;
if (BuildingManager.Instance.foundationPrefab == null) return;
// 현재 건물 정보 저장
Vector3Int gridPos = gridPosition;
int rot = rotation;
ulong owner = _ownerId.Value;
TeamType team = _team.Value;
// BuildingManager에서 건물 제거
BuildingManager.Instance.RemoveBuilding(this);
// FogOfWar 시스템에서 제거
if (buildingData != null && buildingData.providesVision)
{
FogOfWarSystem.Instance?.UnregisterVisionProvider(this);
}
// 현재 건물 제거
NetworkObject.Despawn(true);
// 토대 생성
Vector3 worldPosition = BuildingManager.Instance.GridToWorld(gridPos);
GameObject foundationObj = Instantiate(BuildingManager.Instance.foundationPrefab, worldPosition + upgradeData.placementOffset, Quaternion.Euler(0, rot * 90f, 0));
NetworkObject foundationNetObj = foundationObj.GetComponent<NetworkObject>();
if (foundationNetObj != null)
{
foundationNetObj.Spawn();
BuildingFoundation foundation = foundationObj.GetComponent<BuildingFoundation>();
if (foundation != null)
{
foundation.Initialize(upgradeData, gridPos, rot, owner, team);
BuildingManager.Instance.RegisterFoundation(foundation);
}
}
else
{
Destroy(foundationObj);
}
}
/// <summary>
/// 업그레이드 완료
/// </summary>
private void CompleteUpgrade(TowerData upgradeData)
{
if (!IsServer) return;
BuildingManager.Instance?.UpgradeBuilding(this, upgradeData);
}
/// <summary>
/// 상호작용 프롬프트 텍스트
/// </summary>
public string GetInteractionPrompt()
{
// 업그레이드 중이면 진행도 표시
if (_isUpgrading.Value)
{
TowerData targetData = BuildingManager.Instance?.GetTowerDataById(_upgradeTargetId.Value);
if (targetData != null)
{
float percentage = (_upgradeProgress.Value / targetData.manpower) * 100f;
return $"[E] Upgrading to {targetData.buildingName} ({percentage:F0}%)";
}
return "[E] Upgrading...";
}
TowerData upgradeData = GetUpgradeData();
if (upgradeData == null)
return "";
var coreResourceManager = CoreResourceManager.Instance;
bool canAfford = coreResourceManager != null && coreResourceManager.CanAfford(upgradeData.mana);
string costText = canAfford ? $"{upgradeData.mana}" : $"<color=red>{upgradeData.mana}</color>";
return $"[E] Upgrade to {upgradeData.buildingName} ({costText})";
}
public string GetInteractionAnimation()
{
return "Build"; // 건설 애니메이션 재사용
}
public EquipmentData GetEquipmentData()
{
return buildingData?.constructionEquipment;
}
Transform IInteractable.GetTransform()
{
return transform;
}
/// <summary>
/// 업그레이드 대상 TowerData 반환
/// </summary>
public TowerData GetUpgradeData()
{
if (buildingData == null || buildingData.upgradeTo == 0)
return null;
if (BuildingManager.Instance == null)
return null;
return BuildingManager.Instance.GetTowerDataById(buildingData.upgradeTo);
}
/// <summary>
/// 플레이어의 팀 가져오기
/// </summary>
private TeamType GetPlayerTeam(ulong playerId)
{
if (NetworkManager.Singleton != null && NetworkManager.Singleton.ConnectedClients != null)
{
if (NetworkManager.Singleton.ConnectedClients.TryGetValue(playerId, out var client))
{
if (client.PlayerObject != null)
{
var teamMember = client.PlayerObject.GetComponent<ITeamMember>();
if (teamMember != null)
{
return teamMember.GetTeam();
}
}
}
}
return TeamType.Player;
}
/// <summary>
/// 플레이어의 manpower 가져오기
/// </summary>
private float GetPlayerManpower(ulong playerId)
{
if (NetworkManager.Singleton != null && NetworkManager.Singleton.ConnectedClients != null)
{
if (NetworkManager.Singleton.ConnectedClients.TryGetValue(playerId, out var client))
{
if (client.PlayerObject != null)
{
var playerInteraction = client.PlayerObject.GetComponent<PlayerInteraction>();
if (playerInteraction != null)
{
return playerInteraction.WorkPower;
}
}
}
}
return 10f; // 기본값
}
private void OnUpgradeProgressChanged(float oldValue, float newValue)
{
// 업그레이드 진행 UI 업데이트 (필요시 구현)
}
private void OnUpgradingChanged(bool oldValue, bool newValue)
{
// 업그레이드 상태 변경 시 처리 (필요시 구현)
}
#endregion
#region Gizmos
private void OnDrawGizmos()