건축 및 고용에 비용 소모 기능 추가

This commit is contained in:
2026-02-02 20:26:44 +09:00
parent 9dea9daaa9
commit 958ae1cb75
6 changed files with 159 additions and 11 deletions

View File

@@ -193,6 +193,22 @@ namespace Northbound
return;
}
// 자원 확인 및 소비
var coreResourceManager = CoreResourceManager.Instance;
if (coreResourceManager == null)
{
Debug.LogWarning("<color=red>[BuildingManager] CoreResourceManager 인스턴스를 찾을 수 없습니다.</color>");
return;
}
if (!coreResourceManager.CanAfford(data.mana))
{
Debug.LogWarning($"<color=yellow>[BuildingManager] 코어 자원이 부족합니다. 필요: {data.mana} (클라이언트: {requestingClientId})</color>");
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("<color=red>[BuildingManager] CoreResourceManager 인스턴스를 찾을 수 없습니다.</color>");
return;
}
if (!coreResourceManager.CanAfford(data.mana))
{
Debug.LogWarning($"<color=yellow>[BuildingManager] 코어 자원이 부족합니다. 필요: {data.mana}</color>");
return;
}
coreResourceManager.SpendResources(data.mana);
// 토대 프리팹 확인
if (foundationPrefab == null)
{

View File

@@ -332,12 +332,16 @@ namespace Northbound
// 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<Vector3> 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();
@@ -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<Renderer>();
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("<color=yellow>[BuildingPlacement] 자원이 부족합니다.</color>");
return;
}
int successCount = 0;
foreach (var position in dragBuildingPositions)
{
@@ -609,6 +625,14 @@ namespace Northbound
{
TowerData selectedData = BuildingManager.Instance.availableBuildings[selectedBuildingIndex];
// Check affordability
var coreResourceManager = CoreResourceManager.Instance;
if (coreResourceManager != null && !coreResourceManager.CanAfford(selectedData.mana))
{
Debug.Log("<color=yellow>[BuildingPlacement] 자원이 부족합니다.</color>");
return;
}
if (BuildingManager.Instance.IsValidPlacement(selectedData, hit.point, currentRotation, out Vector3 groundPosition))
{
// 토대 배치 요청

View File

@@ -68,6 +68,28 @@ namespace Northbound
InitializeSlots();
}
private void Update()
{
if (quickslotPanel != null && quickslotPanel.activeSelf)
{
UpdateCostDisplays();
}
}
/// <summary>
/// 모든 슬롯의 비용 표시 업데이트
/// </summary>
public void UpdateCostDisplays()
{
foreach (var slot in slotButtons)
{
if (slot != null)
{
slot.UpdateCostDisplay();
}
}
}
/// <summary>
/// 퀵슬롯 Input Actions 초기화 및 구독 (직접 참조)
/// </summary>

View File

@@ -52,6 +52,20 @@ namespace Northbound
UpdateVisuals();
}
/// <summary>
/// 비용 표시 업데이트 (자원 변화 시 호출)
/// </summary>
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}" : $"<color=red>{buildingData.mana}</color>";
nameText.text = $"{buildingData.buildingName}\n비용: {costText}";
}
}
/// <summary>
/// UI 업데이트
/// </summary>
@@ -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}" : $"<color=red>{buildingData.mana}</color>";
nameText.text = $"{buildingData.buildingName}\n비용: {costText}";
}
// 배경 색상

View File

@@ -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)
{

View File

@@ -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()