Compare commits
2 Commits
a99a7c192d
...
e93ef2111c
| Author | SHA1 | Date | |
|---|---|---|---|
| e93ef2111c | |||
| 3d2a9071bc |
@@ -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()
|
||||
|
||||
@@ -296,6 +296,17 @@ namespace Northbound
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 토대 등록 (업그레이드 등으로 생성된 토대)
|
||||
/// </summary>
|
||||
public void RegisterFoundation(BuildingFoundation foundation)
|
||||
{
|
||||
if (!placedFoundations.Contains(foundation))
|
||||
{
|
||||
placedFoundations.Add(foundation);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 사전 배치 건물 등록 (씬에 미리 있는 건물용)
|
||||
/// </summary>
|
||||
@@ -516,5 +527,91 @@ namespace Northbound
|
||||
Destroy(buildingObj);
|
||||
}
|
||||
}
|
||||
|
||||
#region Upgrade System
|
||||
|
||||
/// <summary>
|
||||
/// ID로 TowerData 찾기
|
||||
/// </summary>
|
||||
public TowerData GetTowerDataById(int towerId)
|
||||
{
|
||||
foreach (var data in availableBuildings)
|
||||
{
|
||||
if (data != null && data.id == towerId)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 건물 업그레이드 (서버에서만 호출)
|
||||
/// </summary>
|
||||
public void UpgradeBuilding(Building building, TowerData upgradeData)
|
||||
{
|
||||
if (!IsServer) return;
|
||||
if (building == null || upgradeData == null) return;
|
||||
if (upgradeData.prefab == null)
|
||||
{
|
||||
Debug.LogError($"[BuildingManager] 업그레이드 프리팹이 없습니다: {upgradeData.buildingName}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 기존 건물 정보 저장
|
||||
Vector3Int gridPos = building.gridPosition;
|
||||
int rotation = building.rotation;
|
||||
ulong ownerId = building.GetOwnerId();
|
||||
TeamType team = building.GetTeam();
|
||||
|
||||
// 기존 건물 제거
|
||||
placedBuildings.Remove(building);
|
||||
|
||||
// FogOfWar 시스템에서 제거
|
||||
if (building.buildingData != null && building.buildingData.providesVision)
|
||||
{
|
||||
FogOfWarSystem.Instance?.UnregisterVisionProvider(building);
|
||||
}
|
||||
|
||||
// 기존 건물 파괴
|
||||
building.NetworkObject.Despawn(true);
|
||||
|
||||
// 새 건물 생성
|
||||
Vector3 worldPosition = GridToWorld(gridPos);
|
||||
GameObject newBuildingObj = Instantiate(upgradeData.prefab, worldPosition + upgradeData.placementOffset, Quaternion.Euler(0, rotation * 90f, 0));
|
||||
NetworkObject netObj = newBuildingObj.GetComponent<NetworkObject>();
|
||||
|
||||
// FogOfWarVisibility 추가
|
||||
if (newBuildingObj.GetComponent<FogOfWarVisibility>() == null)
|
||||
{
|
||||
var visibility = newBuildingObj.AddComponent<FogOfWarVisibility>();
|
||||
visibility.showInExploredAreas = true;
|
||||
visibility.updateInterval = 0.2f;
|
||||
}
|
||||
|
||||
if (netObj != null)
|
||||
{
|
||||
netObj.SpawnWithOwnership(ownerId);
|
||||
|
||||
Building newBuilding = newBuildingObj.GetComponent<Building>();
|
||||
if (newBuilding == null)
|
||||
{
|
||||
newBuilding = newBuildingObj.AddComponent<Building>();
|
||||
}
|
||||
|
||||
// 새 건물 초기화
|
||||
newBuilding.Initialize(upgradeData, gridPos, rotation, ownerId, team);
|
||||
placedBuildings.Add(newBuilding);
|
||||
|
||||
Debug.Log($"<color=green>[BuildingManager] 건물 업그레이드 완료: {upgradeData.buildingName}</color>");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"<color=red>[BuildingManager] 업그레이드 프리팹에 NetworkObject가 없습니다!</color>");
|
||||
Destroy(newBuildingObj);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user