자원 채집 및 반환 기능

텍스트 기능 및 폰트 추가
This commit is contained in:
2026-01-26 02:29:07 +09:00
parent 33bd90658a
commit aa086a7a2b
108 changed files with 286005 additions and 191 deletions

View File

@@ -69,7 +69,7 @@ namespace Northbound
Debug.Log($"플레이어 {playerId} 공격! (적중: {hits.Length}개)");
}
[ServerRpc(RequireOwnership = false)]
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
private void AttackServerRpc(ulong playerId, ulong targetNetworkId)
{
if (NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(targetNetworkId, out NetworkObject targetObj))

View File

@@ -439,7 +439,7 @@ namespace Northbound
}
private void OnDestroy()
override public void OnDestroy()
{
DestroyPreview();
@@ -447,6 +447,8 @@ namespace Northbound
{
_inputActions.Dispose();
}
base.OnDestroy();
}
}
}

223
Assets/Scripts/Core.cs Normal file
View File

@@ -0,0 +1,223 @@
using Unity.Netcode;
using UnityEngine;
namespace Northbound
{
/// <summary>
/// 플레이어가 자원을 건내받아 게임의 전역 자원으로 관리하는 중앙 허브
/// </summary>
public class Core : NetworkBehaviour, IInteractable
{
[Header("Core Settings")]
public int maxStorageCapacity = 1000; // 코어의 최대 저장 용량
public bool unlimitedStorage = false; // 무제한 저장소
[Header("Deposit Settings")]
public bool depositAll = true; // true: 전부 건네기, false: 일부만 건네기
public int depositAmountPerInteraction = 10; // depositAll이 false일 때 한 번에 건네는 양
[Header("Animation")]
public string interactionAnimationTrigger = "Deposit"; // 플레이어 애니메이션 트리거
[Header("Equipment")]
public InteractionEquipmentData equipmentData = null; // 도구 필요 없음
[Header("Visual")]
public GameObject depositEffectPrefab;
public Transform effectSpawnPoint;
private NetworkVariable<int> _totalResources = new NetworkVariable<int>(
0,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server
);
public int TotalResources => _totalResources.Value;
public int MaxStorageCapacity => maxStorageCapacity;
public override void OnNetworkSpawn()
{
if (IsServer)
{
_totalResources.Value = 0;
}
}
public bool CanInteract(ulong playerId)
{
// 저장소가 가득 찼는지 확인 (무제한이 아닐 때)
if (!unlimitedStorage && _totalResources.Value >= maxStorageCapacity)
return false;
// 플레이어가 자원을 가지고 있는지 확인
if (NetworkManager.Singleton != null &&
NetworkManager.Singleton.ConnectedClients.TryGetValue(playerId, out var client))
{
if (client.PlayerObject != null)
{
var playerInventory = client.PlayerObject.GetComponent<PlayerResourceInventory>();
if (playerInventory != null)
{
// 플레이어가 자원을 가지고 있어야 함
return playerInventory.CurrentResourceAmount > 0;
}
}
}
return false;
}
public void Interact(ulong playerId)
{
if (!CanInteract(playerId))
return;
DepositResourceServerRpc(playerId);
}
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
private void DepositResourceServerRpc(ulong playerId)
{
if (!CanInteract(playerId))
return;
// 플레이어 인벤토리 가져오기
var playerObject = NetworkManager.Singleton.ConnectedClients[playerId].PlayerObject;
if (playerObject == null)
return;
var playerInventory = playerObject.GetComponent<PlayerResourceInventory>();
if (playerInventory == null)
{
Debug.LogWarning($"플레이어 {playerId}에게 PlayerResourceInventory 컴포넌트가 없습니다.");
return;
}
int playerResourceAmount = playerInventory.CurrentResourceAmount;
if (playerResourceAmount <= 0)
{
Debug.Log($"플레이어 {playerId}가 건낼 자원이 없습니다.");
return;
}
int depositAmount;
if (depositAll)
{
// 전부 건네기
depositAmount = playerResourceAmount;
}
else
{
// 일부만 건네기
depositAmount = Mathf.Min(depositAmountPerInteraction, playerResourceAmount);
}
// 무제한 저장소가 아니면 용량 제한 확인
if (!unlimitedStorage)
{
int availableSpace = maxStorageCapacity - _totalResources.Value;
depositAmount = Mathf.Min(depositAmount, availableSpace);
}
if (depositAmount <= 0)
{
Debug.Log($"코어의 저장 공간이 부족합니다.");
return;
}
// 플레이어로부터 자원 차감
playerInventory.RemoveResourceServerRpc(depositAmount);
// 코어에 자원 추가
_totalResources.Value += depositAmount;
Debug.Log($"플레이어 {playerId}가 {depositAmount} 자원을 코어에 건넸습니다. 코어 총 자원: {_totalResources.Value}" +
(unlimitedStorage ? "" : $"/{maxStorageCapacity}"));
ShowDepositEffectClientRpc();
}
[Rpc(SendTo.ClientsAndHost)]
private void ShowDepositEffectClientRpc()
{
if (depositEffectPrefab != null && effectSpawnPoint != null)
{
GameObject effect = Instantiate(depositEffectPrefab, effectSpawnPoint.position, effectSpawnPoint.rotation);
Destroy(effect, 2f);
}
}
/// <summary>
/// 게임 시스템이 코어의 자원을 사용 (건물 건설 등)
/// </summary>
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
public void ConsumeResourceServerRpc(int amount)
{
if (amount <= 0) return;
int actualAmount = Mathf.Min(amount, _totalResources.Value);
_totalResources.Value -= actualAmount;
Debug.Log($"코어에서 {actualAmount} 자원을 사용했습니다. 남은 자원: {_totalResources.Value}");
}
/// <summary>
/// 자원을 사용할 수 있는지 확인
/// </summary>
public bool CanConsumeResource(int amount)
{
return _totalResources.Value >= amount;
}
/// <summary>
/// 코어에 자원 추가 (디버그/관리자 기능)
/// </summary>
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
public void AddResourceServerRpc(int amount)
{
if (amount <= 0) return;
if (!unlimitedStorage)
{
int availableSpace = maxStorageCapacity - _totalResources.Value;
amount = Mathf.Min(amount, availableSpace);
}
_totalResources.Value += amount;
Debug.Log($"코어에 {amount} 자원이 추가되었습니다. 현재: {_totalResources.Value}");
}
public string GetInteractionPrompt()
{
if (unlimitedStorage)
{
return depositAll ?
$"[E] 자원 모두 건네기" :
$"[E] 자원 건네기 ({depositAmountPerInteraction}개씩)";
}
if (_totalResources.Value >= maxStorageCapacity)
return "코어 저장소 가득 찼음";
return depositAll ?
$"[E] 자원 모두 건네기 ({_totalResources.Value}/{maxStorageCapacity})" :
$"[E] 자원 건네기 ({_totalResources.Value}/{maxStorageCapacity})";
}
public string GetInteractionAnimation()
{
return interactionAnimationTrigger;
}
public InteractionEquipmentData GetEquipmentData()
{
return equipmentData;
}
public Transform GetTransform()
{
return transform;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7c94274e2af2c8d4f827fe52b26c4410

View File

@@ -0,0 +1,67 @@
using Unity.Netcode;
using UnityEngine;
namespace Northbound
{
/// <summary>
/// Core의 자원을 관리하고 다른 시스템에서 접근할 수 있도록 하는 매니저
/// </summary>
public class CoreResourceManager : MonoBehaviour
{
private static CoreResourceManager _instance;
public static CoreResourceManager Instance => _instance;
[Header("References")]
public Core mainCore; // 메인 코어 참조
private void Awake()
{
if (_instance != null && _instance != this)
{
Destroy(gameObject);
return;
}
_instance = this;
}
/// <summary>
/// 자원을 사용할 수 있는지 확인
/// </summary>
public bool CanAfford(int cost)
{
if (mainCore == null)
{
Debug.LogWarning("메인 코어가 설정되지 않았습니다.");
return false;
}
return mainCore.CanConsumeResource(cost);
}
/// <summary>
/// 자원을 소비
/// </summary>
public void SpendResources(int amount)
{
if (mainCore == null)
{
Debug.LogWarning("메인 코어가 설정되지 않았습니다.");
return;
}
mainCore.ConsumeResourceServerRpc(amount);
}
/// <summary>
/// 현재 자원량 가져오기
/// </summary>
public int GetCurrentResources()
{
if (mainCore == null)
return 0;
return mainCore.TotalResources;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2ed03291507256a47913eae4dee429c7

View File

@@ -0,0 +1,212 @@
using UnityEngine;
using TMPro;
using Unity.Netcode;
namespace Northbound
{
/// <summary>
/// 코어와 플레이어의 자원을 화면에 표시하는 통합 UI
/// </summary>
public class GameResourceUI : MonoBehaviour
{
[Header("Core Resource")]
public TextMeshProUGUI coreResourceText;
public TMP_FontAsset coreFontAsset; // 코어 텍스트용 폰트
[Header("Player Resource")]
public TextMeshProUGUI playerResourceText;
public TMP_FontAsset playerFontAsset; // 플레이어 텍스트용 폰트
public bool showPlayerResource = true;
[Header("Display Settings")]
public string corePrefix = "코어: ";
public string playerPrefix = "보유: ";
public string separator = " / ";
[Header("Color Settings")]
public bool useColorCoding = true;
public Color normalColor = Color.white;
public Color fullColor = Color.yellow;
public Color emptyColor = Color.gray;
[Header("Update Settings")]
public float updateInterval = 0.1f;
private float _lastUpdateTime;
private int _cachedCoreResource = -1;
private int _cachedPlayerResource = -1;
private void Start()
{
// 폰트 애셋 적용
ApplyFontAssets();
}
private void ApplyFontAssets()
{
if (coreResourceText != null && coreFontAsset != null)
{
coreResourceText.font = coreFontAsset;
}
if (playerResourceText != null && playerFontAsset != null)
{
playerResourceText.font = playerFontAsset;
}
}
private void Update()
{
if (Time.time - _lastUpdateTime >= updateInterval)
{
UpdateUI();
_lastUpdateTime = Time.time;
}
}
private void UpdateUI()
{
UpdateCoreResourceDisplay();
if (showPlayerResource)
{
UpdatePlayerResourceDisplay();
}
}
private void UpdateCoreResourceDisplay()
{
if (coreResourceText == null)
return;
if (CoreResourceManager.Instance == null || CoreResourceManager.Instance.mainCore == null)
{
coreResourceText.text = corePrefix + "---";
if (useColorCoding)
coreResourceText.color = emptyColor;
return;
}
int currentResources = CoreResourceManager.Instance.GetCurrentResources();
if (currentResources != _cachedCoreResource)
{
_cachedCoreResource = currentResources;
var core = CoreResourceManager.Instance.mainCore;
if (core.unlimitedStorage)
{
coreResourceText.text = $"{corePrefix}{currentResources}";
}
else
{
coreResourceText.text = $"{corePrefix}{currentResources}{separator}{core.MaxStorageCapacity}";
// 색상 코딩
if (useColorCoding)
{
float fillPercentage = (float)currentResources / core.MaxStorageCapacity;
if (fillPercentage >= 1.0f)
coreResourceText.color = fullColor;
else if (fillPercentage <= 0.1f)
coreResourceText.color = emptyColor;
else
coreResourceText.color = normalColor;
}
}
}
}
private void UpdatePlayerResourceDisplay()
{
if (playerResourceText == null)
return;
var localPlayer = GetLocalPlayer();
if (localPlayer == null)
{
playerResourceText.text = playerPrefix + "---";
if (useColorCoding)
playerResourceText.color = emptyColor;
return;
}
var inventory = localPlayer.GetComponent<PlayerResourceInventory>();
if (inventory == null)
{
playerResourceText.text = playerPrefix + "---";
if (useColorCoding)
playerResourceText.color = emptyColor;
return;
}
int currentAmount = inventory.CurrentResourceAmount;
if (currentAmount != _cachedPlayerResource)
{
_cachedPlayerResource = currentAmount;
playerResourceText.text = $"{playerPrefix}{currentAmount}{separator}{inventory.MaxResourceCapacity}";
// 색상 코딩
if (useColorCoding)
{
float fillPercentage = (float)currentAmount / inventory.MaxResourceCapacity;
if (fillPercentage >= 1.0f)
playerResourceText.color = fullColor;
else if (fillPercentage <= 0.1f)
playerResourceText.color = emptyColor;
else
playerResourceText.color = normalColor;
}
}
}
private GameObject GetLocalPlayer()
{
if (NetworkManager.Singleton == null || !NetworkManager.Singleton.IsClient)
return null;
ulong localClientId = NetworkManager.Singleton.LocalClientId;
if (NetworkManager.Singleton.ConnectedClients.TryGetValue(localClientId, out var client))
{
return client.PlayerObject?.gameObject;
}
return null;
}
private void OnEnable()
{
ApplyFontAssets();
UpdateUI();
}
/// <summary>
/// 런타임에서 폰트를 변경할 때 사용
/// </summary>
public void SetCoreFontAsset(TMP_FontAsset fontAsset)
{
coreFontAsset = fontAsset;
if (coreResourceText != null)
{
coreResourceText.font = fontAsset;
}
}
/// <summary>
/// 런타임에서 폰트를 변경할 때 사용
/// </summary>
public void SetPlayerFontAsset(TMP_FontAsset fontAsset)
{
playerFontAsset = fontAsset;
if (playerResourceText != null)
{
playerResourceText.font = fontAsset;
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: e401fa73ad837e84dbe92d6f58d1ee3d

View File

@@ -1,141 +0,0 @@
using Unity.Netcode;
using UnityEngine;
namespace Northbound
{
/// <summary>
/// 상호작용 대상 - 광산 (채광하기)
/// </summary>
public class Mine : NetworkBehaviour, IInteractable
{
[Header("Mine Settings")]
public bool infiniteResources = false; // 무제한 자원
public int maxResources = 100;
public int resourcesPerMining = 10;
public float miningCooldown = 2f;
public string resourceName = "광석";
[Header("Animation")]
public string interactionAnimationTrigger = "Mining"; // 플레이어 애니메이션 트리거
[Header("Equipment")]
public InteractionEquipmentData equipmentData = new InteractionEquipmentData
{
socketName = "RightHand",
attachOnStart = true,
detachOnEnd = true
};
[Header("Visual")]
public GameObject miningEffectPrefab;
public Transform effectSpawnPoint;
private NetworkVariable<int> _currentResources = new NetworkVariable<int>(
100,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server
);
private float _lastMiningTime;
public override void OnNetworkSpawn()
{
if (IsServer)
{
_currentResources.Value = maxResources;
}
}
public bool CanInteract(ulong playerId)
{
// 무제한 자원이면 항상 채굴 가능
if (infiniteResources)
return Time.time - _lastMiningTime >= miningCooldown;
if (_currentResources.Value <= 0)
return false;
return Time.time - _lastMiningTime >= miningCooldown;
}
public void Interact(ulong playerId)
{
if (!CanInteract(playerId))
return;
MineResourceServerRpc(playerId);
}
[ServerRpc(RequireOwnership = false)]
private void MineResourceServerRpc(ulong playerId)
{
if (!CanInteract(playerId))
return;
int minedAmount = resourcesPerMining;
// 무제한이 아니면 자원 감소
if (!infiniteResources)
{
minedAmount = Mathf.Min(resourcesPerMining, _currentResources.Value);
_currentResources.Value -= minedAmount;
}
_lastMiningTime = Time.time;
Debug.Log($"플레이어 {playerId}가 {minedAmount} {resourceName}을(를) 채굴했습니다. " +
(infiniteResources ? "(무제한)" : $"남은 자원: {_currentResources.Value}"));
ShowMiningEffectClientRpc();
if (!infiniteResources && _currentResources.Value <= 0)
{
OnResourcesDepleted();
}
}
[ClientRpc]
private void ShowMiningEffectClientRpc()
{
if (miningEffectPrefab != null && effectSpawnPoint != null)
{
GameObject effect = Instantiate(miningEffectPrefab, effectSpawnPoint.position, effectSpawnPoint.rotation);
Destroy(effect, 2f);
}
}
private void OnResourcesDepleted()
{
Debug.Log("광산이 고갈되었습니다!");
}
public string GetInteractionPrompt()
{
if (infiniteResources)
{
return $"[E] {resourceName} 채굴 (무제한)";
}
if (_currentResources.Value > 0)
{
return $"[E] {resourceName} 채굴 ({_currentResources.Value}/{maxResources})";
}
return "고갈된 광산";
}
public string GetInteractionAnimation()
{
return interactionAnimationTrigger;
}
public InteractionEquipmentData GetEquipmentData()
{
return equipmentData;
}
public Transform GetTransform()
{
return transform;
}
}
}

View File

@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: e31364bc942ad7e41be627b7a00b206e

View File

@@ -121,12 +121,14 @@ namespace Northbound
return spawnPoints[spawnIndex].rotation;
}
private void OnDestroy()
override public void OnDestroy()
{
if (NetworkManager.Singleton != null)
{
NetworkManager.Singleton.OnClientConnectedCallback -= OnClientConnected;
}
base.OnDestroy();
}
}
}

View File

@@ -80,12 +80,14 @@ namespace Northbound
}
}
private void OnDestroy()
override public void OnDestroy()
{
if (_inputActions != null)
{
_inputActions.Dispose();
}
base.OnDestroy();
}
}
}

View File

@@ -235,12 +235,14 @@ namespace Northbound
GUI.Label(new Rect(Screen.width / 2 - 200, Screen.height - 100, 400, 50), prompt, style);
}
private void OnDestroy()
override public void OnDestroy()
{
if (_inputActions != null)
{
_inputActions.Dispose();
}
base.OnDestroy();
}
}
}

View File

@@ -0,0 +1,76 @@
using Unity.Netcode;
using UnityEngine;
namespace Northbound
{
/// <summary>
/// 플레이어의 자원 인벤토리 관리
/// </summary>
public class PlayerResourceInventory : NetworkBehaviour
{
[Header("Inventory Settings")]
public int maxResourceCapacity = 100; // 최대 자원 보유량
private NetworkVariable<int> _currentResourceAmount = new NetworkVariable<int>(
0,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server
);
public int CurrentResourceAmount => _currentResourceAmount.Value;
public int MaxResourceCapacity => maxResourceCapacity;
/// <summary>
/// 자원을 추가할 수 있는지 확인
/// </summary>
public bool CanAddResource(int amount)
{
return _currentResourceAmount.Value + amount <= maxResourceCapacity;
}
/// <summary>
/// 추가 가능한 최대 자원량 계산
/// </summary>
public int GetAvailableSpace()
{
return maxResourceCapacity - _currentResourceAmount.Value;
}
/// <summary>
/// 자원 추가 (서버에서만 호출)
/// </summary>
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
public void AddResourceServerRpc(int amount)
{
if (amount <= 0) return;
int actualAmount = Mathf.Min(amount, maxResourceCapacity - _currentResourceAmount.Value);
_currentResourceAmount.Value += actualAmount;
Debug.Log($"플레이어 {OwnerClientId} - 자원 추가: +{actualAmount}, 현재: {_currentResourceAmount.Value}/{maxResourceCapacity}");
}
/// <summary>
/// 자원 제거 (서버에서만 호출)
/// </summary>
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
public void RemoveResourceServerRpc(int amount)
{
if (amount <= 0) return;
int actualAmount = Mathf.Min(amount, _currentResourceAmount.Value);
_currentResourceAmount.Value -= actualAmount;
Debug.Log($"플레이어 {OwnerClientId} - 자원 사용: -{actualAmount}, 현재: {_currentResourceAmount.Value}/{maxResourceCapacity}");
}
/// <summary>
/// 자원 설정 (서버에서만 호출)
/// </summary>
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
public void SetResourceServerRpc(int amount)
{
_currentResourceAmount.Value = Mathf.Clamp(amount, 0, maxResourceCapacity);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3c64072402b0a3f46a674eb73c5541ac

190
Assets/Scripts/Resource.cs Normal file
View File

@@ -0,0 +1,190 @@
using Unity.Netcode;
using UnityEngine;
namespace Northbound
{
/// <summary>
/// 상호작용 대상 - 자원 채집
/// </summary>
public class Resource : NetworkBehaviour, IInteractable
{
[Header("Resource Settings")]
public int maxResources = 100;
public int resourcesPerGathering = 10;
public float gatheringCooldown = 2f;
public string resourceName = "광석";
[Header("Resource Recharge")]
public float rechargeInterval = 5f; // 충전 주기 (초)
public int rechargeAmount = 10; // 주기당 충전량
[Header("Animation")]
public string interactionAnimationTrigger = "Mining"; // 플레이어 애니메이션 트리거
[Header("Equipment")]
public InteractionEquipmentData equipmentData = new InteractionEquipmentData
{
socketName = "RightHand",
attachOnStart = true,
detachOnEnd = true
};
[Header("Visual")]
public GameObject gatheringEffectPrefab;
public Transform effectSpawnPoint;
private NetworkVariable<int> _currentResources = new NetworkVariable<int>(
0,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server
);
private float _lastGatheringTime;
private float _lastRechargeTime;
public override void OnNetworkSpawn()
{
if (IsServer)
{
_currentResources.Value = 0;
_lastRechargeTime = Time.time;
}
}
private void Update()
{
if (!IsServer)
return;
// 자원 충전 로직
if (Time.time - _lastRechargeTime >= rechargeInterval)
{
if (_currentResources.Value < maxResources)
{
int rechargeAmountToAdd = Mathf.Min(rechargeAmount, maxResources - _currentResources.Value);
_currentResources.Value += rechargeAmountToAdd;
Debug.Log($"{resourceName} {rechargeAmountToAdd} 충전됨. 현재: {_currentResources.Value}/{maxResources}");
}
_lastRechargeTime = Time.time;
}
}
public bool CanInteract(ulong playerId)
{
// 자원 노드에 자원이 없으면 상호작용 불가
if (_currentResources.Value <= 0)
return false;
// 쿨다운 확인
if (Time.time - _lastGatheringTime < gatheringCooldown)
return false;
// 플레이어 인벤토리 확인
if (NetworkManager.Singleton != null &&
NetworkManager.Singleton.ConnectedClients.TryGetValue(playerId, out var client))
{
if (client.PlayerObject != null)
{
var playerInventory = client.PlayerObject.GetComponent<PlayerResourceInventory>();
if (playerInventory != null)
{
// 플레이어가 받을 수 있는 공간이 없으면 상호작용 불가
if (playerInventory.GetAvailableSpace() <= 0)
return false;
}
}
}
return true;
}
public void Interact(ulong playerId)
{
if (!CanInteract(playerId))
return;
GatherResourceServerRpc(playerId);
}
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
private void GatherResourceServerRpc(ulong playerId)
{
if (!CanInteract(playerId))
return;
// 플레이어의 인벤토리 확인
var playerObject = NetworkManager.Singleton.ConnectedClients[playerId].PlayerObject;
if (playerObject == null)
return;
var playerInventory = playerObject.GetComponent<PlayerResourceInventory>();
if (playerInventory == null)
{
Debug.LogWarning($"플레이어 {playerId}에게 PlayerResourceInventory 컴포넌트가 없습니다.");
return;
}
// 플레이어가 받을 수 있는 최대량 계산
int playerAvailableSpace = playerInventory.GetAvailableSpace();
// 자원 노드가 줄 수 있는 양과 플레이어가 받을 수 있는 양 중 작은 값 선택
int gatheredAmount = Mathf.Min(
resourcesPerGathering,
_currentResources.Value,
playerAvailableSpace
);
if (gatheredAmount <= 0)
{
Debug.Log($"플레이어 {playerId}의 인벤토리가 가득 찼습니다.");
return;
}
// 자원 차감
_currentResources.Value -= gatheredAmount;
_lastGatheringTime = Time.time;
// 플레이어에게 자원 추가
playerInventory.AddResourceServerRpc(gatheredAmount);
Debug.Log($"플레이어 {playerId}가 {gatheredAmount} {resourceName}을(를) 채집했습니다. 남은 자원: {_currentResources.Value}");
ShowGatheringEffectClientRpc();
}
[Rpc(SendTo.ClientsAndHost)]
private void ShowGatheringEffectClientRpc()
{
if (gatheringEffectPrefab != null && effectSpawnPoint != null)
{
GameObject effect = Instantiate(gatheringEffectPrefab, effectSpawnPoint.position, effectSpawnPoint.rotation);
Destroy(effect, 2f);
}
}
public string GetInteractionPrompt()
{
if (_currentResources.Value <= 0)
return "자원 충전 중...";
return $"[E] {resourceName} 채집 ({_currentResources.Value}/{maxResources})";
}
public string GetInteractionAnimation()
{
return interactionAnimationTrigger;
}
public InteractionEquipmentData GetEquipmentData()
{
return equipmentData;
}
public Transform GetTransform()
{
return transform;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 13db2a1998ede61439aeb8b967160b5e