건축 및 고용에 비용 소모 기능 추가
This commit is contained in:
@@ -193,6 +193,22 @@ namespace Northbound
|
|||||||
return;
|
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))
|
if (!IsValidPlacement(data, position, rotation, out Vector3 snappedPosition))
|
||||||
{
|
{
|
||||||
@@ -345,6 +361,22 @@ namespace Northbound
|
|||||||
return;
|
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)
|
if (foundationPrefab == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -328,16 +328,20 @@ namespace Northbound
|
|||||||
|
|
||||||
if (Physics.Raycast(ray, out RaycastHit hit, maxPlacementDistance, groundLayer))
|
if (Physics.Raycast(ray, out RaycastHit hit, maxPlacementDistance, groundLayer))
|
||||||
{
|
{
|
||||||
|
|
||||||
// Check if placement is valid
|
// Check if placement is valid
|
||||||
bool isValid = BuildingManager.Instance.IsValidPlacement(data, hit.point, currentRotation, out Vector3 snappedPosition);
|
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 적용)
|
// Update preview position (placementOffset 적용)
|
||||||
previewObject.transform.position = snappedPosition + data.placementOffset;
|
previewObject.transform.position = snappedPosition + data.placementOffset;
|
||||||
previewObject.transform.rotation = Quaternion.Euler(0, currentRotation * 90f, 0);
|
previewObject.transform.rotation = Quaternion.Euler(0, currentRotation * 90f, 0);
|
||||||
|
|
||||||
// Update material based on validity
|
// Update material based on validity and affordability
|
||||||
Material targetMat = isValid ? validMaterial : invalidMaterial;
|
Material targetMat = (isValid && canAfford) ? validMaterial : invalidMaterial;
|
||||||
foreach (var renderer in previewRenderers)
|
foreach (var renderer in previewRenderers)
|
||||||
{
|
{
|
||||||
Material[] mats = new Material[renderer.materials.Length];
|
Material[] mats = new Material[renderer.materials.Length];
|
||||||
@@ -462,6 +466,10 @@ namespace Northbound
|
|||||||
Vector3 dragEndPosition = hit.point;
|
Vector3 dragEndPosition = hit.point;
|
||||||
List<Vector3> positions = CalculateDragBuildingPositions(dragStartPosition, dragEndPosition, data);
|
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();
|
ClearDragPreviews();
|
||||||
|
|
||||||
@@ -476,9 +484,9 @@ namespace Northbound
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isValid = BuildingManager.Instance.IsValidPlacement(data, pos, currentRotation, out Vector3 snappedPosition);
|
bool isValid = BuildingManager.Instance.IsValidPlacement(data, pos, currentRotation, out Vector3 snappedPosition);
|
||||||
|
|
||||||
GameObject preview = Instantiate(data.prefab);
|
GameObject preview = Instantiate(data.prefab);
|
||||||
|
|
||||||
// Remove NetworkObject and Building components
|
// Remove NetworkObject and Building components
|
||||||
if (preview.GetComponent<NetworkObject>() != null)
|
if (preview.GetComponent<NetworkObject>() != null)
|
||||||
Destroy(preview.GetComponent<NetworkObject>());
|
Destroy(preview.GetComponent<NetworkObject>());
|
||||||
@@ -490,7 +498,7 @@ namespace Northbound
|
|||||||
preview.transform.rotation = Quaternion.Euler(0, currentRotation * 90f, 0);
|
preview.transform.rotation = Quaternion.Euler(0, currentRotation * 90f, 0);
|
||||||
|
|
||||||
// Apply materials
|
// Apply materials
|
||||||
Material targetMat = isValid ? validMaterial : invalidMaterial;
|
Material targetMat = (isValid && canAffordAll) ? validMaterial : invalidMaterial;
|
||||||
Renderer[] renderers = preview.GetComponentsInChildren<Renderer>();
|
Renderer[] renderers = preview.GetComponentsInChildren<Renderer>();
|
||||||
foreach (var renderer in renderers)
|
foreach (var renderer in renderers)
|
||||||
{
|
{
|
||||||
@@ -569,6 +577,14 @@ namespace Northbound
|
|||||||
|
|
||||||
TowerData selectedData = BuildingManager.Instance.availableBuildings[selectedBuildingIndex];
|
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;
|
int successCount = 0;
|
||||||
foreach (var position in dragBuildingPositions)
|
foreach (var position in dragBuildingPositions)
|
||||||
{
|
{
|
||||||
@@ -608,7 +624,15 @@ namespace Northbound
|
|||||||
if (Physics.Raycast(ray, out RaycastHit hit, maxPlacementDistance, groundLayer))
|
if (Physics.Raycast(ray, out RaycastHit hit, maxPlacementDistance, groundLayer))
|
||||||
{
|
{
|
||||||
TowerData selectedData = BuildingManager.Instance.availableBuildings[selectedBuildingIndex];
|
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))
|
if (BuildingManager.Instance.IsValidPlacement(selectedData, hit.point, currentRotation, out Vector3 groundPosition))
|
||||||
{
|
{
|
||||||
// 토대 배치 요청
|
// 토대 배치 요청
|
||||||
|
|||||||
@@ -68,6 +68,28 @@ namespace Northbound
|
|||||||
InitializeSlots();
|
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>
|
/// <summary>
|
||||||
/// 퀵슬롯 Input Actions 초기화 및 구독 (직접 참조)
|
/// 퀵슬롯 Input Actions 초기화 및 구독 (직접 참조)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -52,6 +52,20 @@ namespace Northbound
|
|||||||
UpdateVisuals();
|
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>
|
/// <summary>
|
||||||
/// UI 업데이트
|
/// UI 업데이트
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -75,7 +89,10 @@ namespace Northbound
|
|||||||
// 이름 설정
|
// 이름 설정
|
||||||
if (nameText != null)
|
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}";
|
||||||
}
|
}
|
||||||
|
|
||||||
// 배경 색상
|
// 배경 색상
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ namespace Northbound
|
|||||||
public float followDistance = 3f;
|
public float followDistance = 3f;
|
||||||
public float movementSpeed = 3.5f;
|
public float movementSpeed = 3.5f;
|
||||||
public int resourcesPerMining = 5;
|
public int resourcesPerMining = 5;
|
||||||
|
public int recruitmentCost = 10;
|
||||||
|
|
||||||
[Header("Interaction")]
|
[Header("Interaction")]
|
||||||
public string interactionAnimationTrigger = "Recruit";
|
public string interactionAnimationTrigger = "Recruit";
|
||||||
@@ -320,7 +321,17 @@ namespace Northbound
|
|||||||
|
|
||||||
public bool CanInteract(ulong playerId)
|
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)
|
public void Interact(ulong playerId)
|
||||||
@@ -348,6 +359,20 @@ namespace Northbound
|
|||||||
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
|
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
|
||||||
private void RecruitWorkerServerRpc(ulong playerId, ulong workerNetObjectId)
|
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;
|
_ownerPlayerId.Value = playerId;
|
||||||
SetState(WorkerState.Following);
|
SetState(WorkerState.Following);
|
||||||
UpdatePlayerTransform();
|
UpdatePlayerTransform();
|
||||||
@@ -389,7 +414,11 @@ namespace Northbound
|
|||||||
{
|
{
|
||||||
if (_ownerPlayerId.Value == ulong.MaxValue)
|
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)
|
else if (NetworkManager.Singleton != null && _ownerPlayerId.Value == NetworkManager.Singleton.LocalClientId)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ namespace Northbound
|
|||||||
public float spawnRadius = 2f;
|
public float spawnRadius = 2f;
|
||||||
public int maxWorkers = 5;
|
public int maxWorkers = 5;
|
||||||
public float spawnCooldown = 5f;
|
public float spawnCooldown = 5f;
|
||||||
|
public int recruitmentCost = 20;
|
||||||
|
|
||||||
[Header("Interaction")]
|
[Header("Interaction")]
|
||||||
public string interactionAnimationTrigger = "Build";
|
public string interactionAnimationTrigger = "Build";
|
||||||
@@ -59,6 +60,10 @@ namespace Northbound
|
|||||||
if (workerPrefab == null)
|
if (workerPrefab == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
var coreResourceManager = CoreResourceManager.Instance;
|
||||||
|
if (coreResourceManager != null && !coreResourceManager.CanAfford(recruitmentCost))
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +87,21 @@ namespace Northbound
|
|||||||
return;
|
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;
|
Vector3 spawnPosition = spawnPoint != null ? spawnPoint.position : transform.position;
|
||||||
|
|
||||||
float randomAngle = Random.Range(0f, 360f);
|
float randomAngle = Random.Range(0f, 360f);
|
||||||
@@ -185,7 +205,11 @@ namespace Northbound
|
|||||||
if (cooldownRemaining > 0)
|
if (cooldownRemaining > 0)
|
||||||
return $"워커 생성 대기 중 ({cooldownRemaining:F1}s)";
|
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()
|
public string GetInteractionAnimation()
|
||||||
|
|||||||
Reference in New Issue
Block a user