diff --git a/Assets/Scripts/BuildingManager.cs b/Assets/Scripts/BuildingManager.cs
index a774be4..68dbe94 100644
--- a/Assets/Scripts/BuildingManager.cs
+++ b/Assets/Scripts/BuildingManager.cs
@@ -193,6 +193,22 @@ namespace Northbound
return;
}
+ // 자원 확인 및 소비
+ var coreResourceManager = CoreResourceManager.Instance;
+ if (coreResourceManager == null)
+ {
+ Debug.LogWarning("[BuildingManager] CoreResourceManager 인스턴스를 찾을 수 없습니다.");
+ return;
+ }
+
+ if (!coreResourceManager.CanAfford(data.mana))
+ {
+ Debug.LogWarning($"[BuildingManager] 코어 자원이 부족합니다. 필요: {data.mana} (클라이언트: {requestingClientId})");
+ return;
+ }
+
+ coreResourceManager.SpendResources(data.mana);
+
// 배치 가능 여부 확인
if (!IsValidPlacement(data, position, rotation, out Vector3 snappedPosition))
{
@@ -345,6 +361,22 @@ namespace Northbound
return;
}
+ // 자원 확인 및 소비
+ var coreResourceManager = CoreResourceManager.Instance;
+ if (coreResourceManager == null)
+ {
+ Debug.LogWarning("[BuildingManager] CoreResourceManager 인스턴스를 찾을 수 없습니다.");
+ return;
+ }
+
+ if (!coreResourceManager.CanAfford(data.mana))
+ {
+ Debug.LogWarning($"[BuildingManager] 코어 자원이 부족합니다. 필요: {data.mana}");
+ return;
+ }
+
+ coreResourceManager.SpendResources(data.mana);
+
// 토대 프리팹 확인
if (foundationPrefab == null)
{
diff --git a/Assets/Scripts/BuildingPlacement.cs b/Assets/Scripts/BuildingPlacement.cs
index 6d1b78f..52014da 100644
--- a/Assets/Scripts/BuildingPlacement.cs
+++ b/Assets/Scripts/BuildingPlacement.cs
@@ -328,16 +328,20 @@ namespace Northbound
if (Physics.Raycast(ray, out RaycastHit hit, maxPlacementDistance, groundLayer))
{
-
+
// Check if placement is valid
bool isValid = BuildingManager.Instance.IsValidPlacement(data, hit.point, currentRotation, out Vector3 snappedPosition);
+ // Check affordability
+ var coreResourceManager = CoreResourceManager.Instance;
+ bool canAfford = coreResourceManager != null && coreResourceManager.CanAfford(data.mana);
+
// Update preview position (placementOffset 적용)
previewObject.transform.position = snappedPosition + data.placementOffset;
previewObject.transform.rotation = Quaternion.Euler(0, currentRotation * 90f, 0);
- // Update material based on validity
- Material targetMat = isValid ? validMaterial : invalidMaterial;
+ // Update material based on validity and affordability
+ Material targetMat = (isValid && canAfford) ? validMaterial : invalidMaterial;
foreach (var renderer in previewRenderers)
{
Material[] mats = new Material[renderer.materials.Length];
@@ -462,6 +466,10 @@ namespace Northbound
Vector3 dragEndPosition = hit.point;
List positions = CalculateDragBuildingPositions(dragStartPosition, dragEndPosition, data);
+ // Check affordability for all buildings
+ var coreResourceManager = CoreResourceManager.Instance;
+ bool canAffordAll = coreResourceManager != null && coreResourceManager.CanAfford(data.mana * positions.Count);
+
// 기존 프리뷰 정리
ClearDragPreviews();
@@ -476,9 +484,9 @@ namespace Northbound
}
bool isValid = BuildingManager.Instance.IsValidPlacement(data, pos, currentRotation, out Vector3 snappedPosition);
-
+
GameObject preview = Instantiate(data.prefab);
-
+
// Remove NetworkObject and Building components
if (preview.GetComponent() != null)
Destroy(preview.GetComponent());
@@ -490,7 +498,7 @@ namespace Northbound
preview.transform.rotation = Quaternion.Euler(0, currentRotation * 90f, 0);
// Apply materials
- Material targetMat = isValid ? validMaterial : invalidMaterial;
+ Material targetMat = (isValid && canAffordAll) ? validMaterial : invalidMaterial;
Renderer[] renderers = preview.GetComponentsInChildren();
foreach (var renderer in renderers)
{
@@ -569,6 +577,14 @@ namespace Northbound
TowerData selectedData = BuildingManager.Instance.availableBuildings[selectedBuildingIndex];
+ // Check affordability
+ var coreResourceManager = CoreResourceManager.Instance;
+ if (coreResourceManager == null || !coreResourceManager.CanAfford(selectedData.mana * dragBuildingPositions.Count))
+ {
+ Debug.Log("[BuildingPlacement] 자원이 부족합니다.");
+ return;
+ }
+
int successCount = 0;
foreach (var position in dragBuildingPositions)
{
@@ -608,7 +624,15 @@ namespace Northbound
if (Physics.Raycast(ray, out RaycastHit hit, maxPlacementDistance, groundLayer))
{
TowerData selectedData = BuildingManager.Instance.availableBuildings[selectedBuildingIndex];
-
+
+ // Check affordability
+ var coreResourceManager = CoreResourceManager.Instance;
+ if (coreResourceManager != null && !coreResourceManager.CanAfford(selectedData.mana))
+ {
+ Debug.Log("[BuildingPlacement] 자원이 부족합니다.");
+ return;
+ }
+
if (BuildingManager.Instance.IsValidPlacement(selectedData, hit.point, currentRotation, out Vector3 groundPosition))
{
// 토대 배치 요청
diff --git a/Assets/Scripts/BuildingQuickslotUI.cs b/Assets/Scripts/BuildingQuickslotUI.cs
index eb2eaa6..d360727 100644
--- a/Assets/Scripts/BuildingQuickslotUI.cs
+++ b/Assets/Scripts/BuildingQuickslotUI.cs
@@ -68,6 +68,28 @@ namespace Northbound
InitializeSlots();
}
+ private void Update()
+ {
+ if (quickslotPanel != null && quickslotPanel.activeSelf)
+ {
+ UpdateCostDisplays();
+ }
+ }
+
+ ///
+ /// 모든 슬롯의 비용 표시 업데이트
+ ///
+ public void UpdateCostDisplays()
+ {
+ foreach (var slot in slotButtons)
+ {
+ if (slot != null)
+ {
+ slot.UpdateCostDisplay();
+ }
+ }
+ }
+
///
/// 퀵슬롯 Input Actions 초기화 및 구독 (직접 참조)
///
diff --git a/Assets/Scripts/BuildingSlotButton.cs b/Assets/Scripts/BuildingSlotButton.cs
index 2a94241..b2150de 100644
--- a/Assets/Scripts/BuildingSlotButton.cs
+++ b/Assets/Scripts/BuildingSlotButton.cs
@@ -52,6 +52,20 @@ namespace Northbound
UpdateVisuals();
}
+ ///
+ /// 비용 표시 업데이트 (자원 변화 시 호출)
+ ///
+ public void UpdateCostDisplay()
+ {
+ if (nameText != null && buildingData != null)
+ {
+ var coreResourceManager = CoreResourceManager.Instance;
+ bool canAfford = coreResourceManager != null && coreResourceManager.CanAfford(buildingData.mana);
+ string costText = canAfford ? $"{buildingData.mana}" : $"{buildingData.mana}";
+ nameText.text = $"{buildingData.buildingName}\n비용: {costText}";
+ }
+ }
+
///
/// UI 업데이트
///
@@ -75,7 +89,10 @@ namespace Northbound
// 이름 설정
if (nameText != null)
{
- nameText.text = buildingData.buildingName;
+ var coreResourceManager = CoreResourceManager.Instance;
+ bool canAfford = coreResourceManager != null && coreResourceManager.CanAfford(buildingData.mana);
+ string costText = canAfford ? $"{buildingData.mana}" : $"{buildingData.mana}";
+ nameText.text = $"{buildingData.buildingName}\n비용: {costText}";
}
// 배경 색상
diff --git a/Assets/Scripts/Worker.cs b/Assets/Scripts/Worker.cs
index f203b3d..b2c3a0c 100644
--- a/Assets/Scripts/Worker.cs
+++ b/Assets/Scripts/Worker.cs
@@ -20,6 +20,7 @@ namespace Northbound
public float followDistance = 3f;
public float movementSpeed = 3.5f;
public int resourcesPerMining = 5;
+ public int recruitmentCost = 10;
[Header("Interaction")]
public string interactionAnimationTrigger = "Recruit";
@@ -320,7 +321,17 @@ namespace Northbound
public bool CanInteract(ulong playerId)
{
- return _ownerPlayerId.Value == ulong.MaxValue || _ownerPlayerId.Value == playerId;
+ if (_ownerPlayerId.Value != ulong.MaxValue && _ownerPlayerId.Value != playerId)
+ return false;
+
+ if (_ownerPlayerId.Value == ulong.MaxValue)
+ {
+ var coreResourceManager = CoreResourceManager.Instance;
+ if (coreResourceManager != null && !coreResourceManager.CanAfford(recruitmentCost))
+ return false;
+ }
+
+ return true;
}
public void Interact(ulong playerId)
@@ -348,6 +359,20 @@ namespace Northbound
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
private void RecruitWorkerServerRpc(ulong playerId, ulong workerNetObjectId)
{
+ var coreResourceManager = CoreResourceManager.Instance;
+ if (coreResourceManager == null)
+ {
+ Debug.LogWarning("[Worker] CoreResourceManager 인스턴스를 찾을 수 없습니다.");
+ return;
+ }
+
+ if (!coreResourceManager.CanAfford(recruitmentCost))
+ {
+ Debug.LogWarning($"[Worker] 코어 자원이 부족합니다. 필요: {recruitmentCost}");
+ return;
+ }
+
+ coreResourceManager.SpendResources(recruitmentCost);
_ownerPlayerId.Value = playerId;
SetState(WorkerState.Following);
UpdatePlayerTransform();
@@ -389,7 +414,11 @@ namespace Northbound
{
if (_ownerPlayerId.Value == ulong.MaxValue)
{
- return "[E] 워커 채용";
+ var coreResourceManager = CoreResourceManager.Instance;
+ if (coreResourceManager != null && !coreResourceManager.CanAfford(recruitmentCost))
+ return $"자원 부족 (필요: {recruitmentCost})";
+
+ return $"[E] 워커 채용 - 비용: {recruitmentCost}";
}
else if (NetworkManager.Singleton != null && _ownerPlayerId.Value == NetworkManager.Singleton.LocalClientId)
{
diff --git a/Assets/Scripts/WorkerSpawner.cs b/Assets/Scripts/WorkerSpawner.cs
index 8e31aed..075700b 100644
--- a/Assets/Scripts/WorkerSpawner.cs
+++ b/Assets/Scripts/WorkerSpawner.cs
@@ -11,6 +11,7 @@ namespace Northbound
public float spawnRadius = 2f;
public int maxWorkers = 5;
public float spawnCooldown = 5f;
+ public int recruitmentCost = 20;
[Header("Interaction")]
public string interactionAnimationTrigger = "Build";
@@ -59,6 +60,10 @@ namespace Northbound
if (workerPrefab == null)
return false;
+ var coreResourceManager = CoreResourceManager.Instance;
+ if (coreResourceManager != null && !coreResourceManager.CanAfford(recruitmentCost))
+ return false;
+
return true;
}
@@ -82,6 +87,21 @@ namespace Northbound
return;
}
+ var coreResourceManager = CoreResourceManager.Instance;
+ if (coreResourceManager == null)
+ {
+ Debug.LogWarning("[WorkerSpawner] CoreResourceManager 인스턴스를 찾을 수 없습니다.");
+ return;
+ }
+
+ if (!coreResourceManager.CanAfford(recruitmentCost))
+ {
+ Debug.LogWarning($"[WorkerSpawner] 코어 자원이 부족합니다. 필요: {recruitmentCost}");
+ return;
+ }
+
+ coreResourceManager.SpendResources(recruitmentCost);
+
Vector3 spawnPosition = spawnPoint != null ? spawnPoint.position : transform.position;
float randomAngle = Random.Range(0f, 360f);
@@ -185,7 +205,11 @@ namespace Northbound
if (cooldownRemaining > 0)
return $"워커 생성 대기 중 ({cooldownRemaining:F1}s)";
- return $"{interactionPrompt} ({_workerCount.Value}/{maxWorkers})";
+ var coreResourceManager = CoreResourceManager.Instance;
+ if (coreResourceManager != null && !coreResourceManager.CanAfford(recruitmentCost))
+ return $"자원 부족 (필요: {recruitmentCost})";
+
+ return $"{interactionPrompt} ({_workerCount.Value}/{maxWorkers}) - 비용: {recruitmentCost}";
}
public string GetInteractionAnimation()