107 lines
4.0 KiB
C#
107 lines
4.0 KiB
C#
using Unity.Netcode;
|
|
using UnityEngine;
|
|
|
|
public class DroppedItem : NetworkBehaviour, IInteractable
|
|
{
|
|
[SerializeField] private MeshFilter myFilter; // 자식의 MeshFilter 연결
|
|
[SerializeField] private MeshRenderer myRenderer; // 자식의 MeshRenderer 연결
|
|
[SerializeField] private float dropScale = 0.3f;
|
|
|
|
private Rigidbody _rb;
|
|
[SerializeField] private float jumpForce = 5f; // 위로 솟구치는 힘
|
|
[SerializeField] private float spreadForce = 2f; // 옆으로 퍼지는 힘
|
|
[SerializeField] private float rotationSpeed = 100f; // 빙글빙글 도는 속도
|
|
|
|
private NetworkVariable<int> _itemDataID = new NetworkVariable<int>();
|
|
private bool _isProcessed = false; // 중복 획득 방지 (서버용)
|
|
|
|
private void Awake()
|
|
{
|
|
_rb = GetComponent<Rigidbody>();
|
|
}
|
|
|
|
public override void OnNetworkSpawn()
|
|
{
|
|
UpdateVisuals();
|
|
_itemDataID.OnValueChanged += (oldVal, newVal) => UpdateVisuals();
|
|
|
|
if (IsServer)
|
|
{
|
|
ApplyInitialPop();
|
|
}
|
|
}
|
|
|
|
private void ApplyInitialPop()
|
|
{
|
|
// 위쪽 방향 + 무작위 주변 방향으로 힘을 줍니다.
|
|
Vector3 force = Vector3.up * jumpForce + Random.insideUnitSphere * spreadForce;
|
|
_rb.AddForce(force, ForceMode.Impulse);
|
|
|
|
// 무작위 회전력(Torque)을 주어 던져지는 느낌을 냅니다.
|
|
_rb.AddTorque(Random.insideUnitSphere * spreadForce, ForceMode.Impulse);
|
|
}
|
|
|
|
public void Initialize(int id)
|
|
{
|
|
if (IsServer) _itemDataID.Value = id;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
// 비주얼만 빙글빙글 돌게 하고 싶다면 (선택 사항)
|
|
transform.Rotate(Vector3.up * rotationSpeed * Time.deltaTime);
|
|
}
|
|
|
|
private void UpdateVisuals()
|
|
{
|
|
ItemData data = ItemDatabase.Instance.GetItemByID(_itemDataID.Value);
|
|
|
|
if (data != null && data.originalBlockPrefab != null)
|
|
{
|
|
// 원본 프리팹(큰 블록)에서 비주얼 컴포넌트를 찾습니다.
|
|
MeshFilter sourceFilter = data.originalBlockPrefab.GetComponentInChildren<MeshFilter>();
|
|
MeshRenderer sourceRenderer = data.originalBlockPrefab.GetComponentInChildren<MeshRenderer>();
|
|
|
|
if (sourceFilter != null && myFilter != null)
|
|
myFilter.sharedMesh = sourceFilter.sharedMesh;
|
|
|
|
if (sourceRenderer != null && myRenderer != null)
|
|
myRenderer.sharedMaterial = sourceRenderer.sharedMaterial;
|
|
|
|
// 크기를 작게 줄여서 아이템처럼 보이게 합니다.
|
|
transform.localScale = Vector3.one * dropScale;
|
|
}
|
|
}
|
|
|
|
// 플레이어의 OnInteractTap에서 호출될 함수입니다.
|
|
public void Interact(GameObject interactor)
|
|
{
|
|
Debug.Log("<color=yellow>[DroppedItem] 상호작용 시도됨</color>");
|
|
// 1. 상호작용한 플레이어가 본인(Owner)인지 확인합니다.
|
|
if (interactor.TryGetComponent<NetworkObject>(out var playerNetObj) && playerNetObj.IsOwner)
|
|
{
|
|
// 2. 서버에 이 아이템을 줍겠다고 요청합니다.
|
|
RequestPickupServerRpc(playerNetObj.NetworkObjectId);
|
|
Debug.Log("<color=yellow>[DroppedItem] 아이템 획득 요청 서버 RPC 호출됨</color>");
|
|
}
|
|
}
|
|
|
|
[Rpc(SendTo.Server, InvokePermission = RpcInvokePermission.Everyone)]
|
|
private void RequestPickupServerRpc(ulong playerNetId)
|
|
{
|
|
if (_isProcessed) return;
|
|
|
|
// 서버에서 아이템 데이터를 가져오고 플레이어 인벤토리에 추가합니다.
|
|
if (NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(playerNetId, out var playerObj))
|
|
{
|
|
if (playerObj.TryGetComponent<PlayerInventory>(out var inventory))
|
|
{
|
|
_isProcessed = true;
|
|
inventory.AddItemRpc(_itemDataID.Value, 1); // 인벤토리에 추가
|
|
|
|
// 3. 획득 성공 시 네트워크 상에서 제거합니다.
|
|
GetComponent<NetworkObject>().Despawn();
|
|
}
|
|
}
|
|
}
|
|
} |