我正在制作一个拖放系统,其中每次单击都会从堆栈中将 1 个项目放到鼠标上,但它会占用堆栈并留下 1 个项目,而不是相反。项目行为屏幕...
我正在制作一个拖放系统,每次单击都会从堆栈中取出 1 个项目到鼠标上,但它会占用堆栈并留下 1 个项目,而不是相反
物品行为脚本使物品跟随鼠标光标。库存管理器脚本从库存槽中添加和移除物品,并允许堆叠
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using TMPro;
public class ItemBehaviour : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
[Header("UI")]
[SerializeField]
private Image image;
public TMP_Text countText;
[HideInInspector]
public Items item;
[HideInInspector]
public int count = 1;
[HideInInspector]
public Transform parentAfterDrag;
private ItemBehaviour clone;
private void Start()
{
InitialiseItem(item);
}
public void RefreshCount()
{
if (count > 1)
{
countText.text = count.ToString();
}
else
{
countText.text = "";
}
}
public void InitialiseItem(Items newItem)
{
item = newItem;
image.sprite = newItem.sprite;
RefreshCount();
}
public void OnBeginDrag(PointerEventData eventData)
{
bool isShiftPressed = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
if (!isShiftPressed)
{
// Drag only one item
if (count > 1)
{
// Create a clone of the item
clone = Instantiate(this, transform.parent);
clone.count = 1;
clone.InitialiseItem(item);
clone.RefreshCount();
// Update the count of the original item
count--;
RefreshCount();
}
}
else
{
// Drag the whole stack
clone = this;
}
// Update UI
image.raycastTarget = false;
parentAfterDrag = transform.parent;
transform.SetParent(transform.root);
RefreshCount();
}
public void OnDrag(PointerEventData eventData)
{
transform.position = Input.mousePosition;
}
public void OnEndDrag(PointerEventData eventData)
{
image.raycastTarget = true;
transform.SetParent(parentAfterDrag);
// Handle dropping the item
if (clone != this)
{
// If dragging a clone (one item), the original stack is left with updated count
if (count <= 0)
{
Destroy(gameObject);
}
}
else
{
// Otherwise, the item is left behind with updated count
RefreshCount();
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InventoryManager : MonoBehaviour
{
public InventorySlot[] inventorySlots;
public GameObject inventoryItemPrefab;
[SerializeField]
private int maxitems;
[SerializeField]
private int currentItems;
private void Update()
{
UpdateCurrentItems();
}
public bool AddItem(Items item)
{
if (currentItems < maxitems)
{
// Check if the item can be stacked in an existing slot
for (int i = 0; i < inventorySlots.Length; i++)
{
InventorySlot slot = inventorySlots[i];
ItemBehaviour itemInSlot = slot.GetComponentInChildren<ItemBehaviour>();
if (itemInSlot != null && itemInSlot.item == item && itemInSlot.item.stackable == true)
{
itemInSlot.count++;
itemInSlot.RefreshCount();
currentItems++;
return true;
}
}
// Check for an empty slot to place the new item
for (int i = 0; i < inventorySlots.Length; i++)
{
InventorySlot slot = inventorySlots[i];
ItemBehaviour itemInSlot = slot.GetComponentInChildren<ItemBehaviour>();
if (itemInSlot == null)
{
SpawnItem(item, slot);
currentItems++;
return true;
}
}
return false;
}
else
{
Debug.Log("Storage is full");
return false;
}
}
// Spawns item in inventory
void SpawnItem(Items item, InventorySlot slot)
{
GameObject newItemGO = Instantiate(inventoryItemPrefab, slot.transform);
ItemBehaviour itemBehaviour = newItemGO.GetComponent<ItemBehaviour>();
itemBehaviour.InitialiseItem(item);
}
void UpdateCurrentItems()
{
currentItems = 0;
foreach (InventorySlot slot in inventorySlots)
{
ItemBehaviour[] itemsInSlot = slot.GetComponentsInChildren<ItemBehaviour>();
foreach (ItemBehaviour item in itemsInSlot)
{
currentItems += item.count;
}
}
}
// Check if the inventory has the specified item and quantity
public bool HasItem(Items item, int quantity)
{
foreach (InventorySlot slot in inventorySlots)
{
ItemBehaviour itemInSlot = slot.GetComponentInChildren<ItemBehaviour>();
if (itemInSlot != null && itemInSlot.item == item && itemInSlot.count >= quantity)
{
return true;
}
}
return false;
}
// Remove the specified quantity of an item from the inventory
public void RemoveItem(Items item, int quantity)
{
foreach (InventorySlot slot in inventorySlots)
{
ItemBehaviour itemInSlot = slot.GetComponentInChildren<ItemBehaviour>();
if (itemInSlot != null && itemInSlot.item == item)
{
if (itemInSlot.count > quantity)
{
itemInSlot.count -= quantity;
itemInSlot.RefreshCount();
return;
}
else
{
quantity -= itemInSlot.count;
Destroy(itemInSlot.gameObject);
if (quantity <= 0)
{
return;
}
}
}
}
}
}
来自 Unity 脚本 API :
当脚本加载或 Inspector 中的值发生变化时,Unity 调用的仅限编辑器的函数。
OnValidate 仅对 脚本本身的变化做出反应,而不会对其他组件的变化做出反应(例如 , Transform
在您的“移动对象”示例中)。
目前没有针对发生在您自己的脚本之外的更改的回调。您可以使用(如果您每帧都执行复杂的操作,速度会很慢!)来临时实现 [ExecuteAlways]
在场景保存之前手动 EditorSceneManager.sceneSaving
运行的 OnValidate()
事件