第三部分:背包——背包功能实现

        包含世界物品的拾取,UI物品的拖拽,交换(后续扩充额外内容:使用,掉落等等)

        1:物品拾取 ItemPickUp:为每个世界上的物品添加此脚本和Trigger碰撞体

        根据物体类型选择加入到哪个背包,附带刷新背包+刷新物品+删除世界物品操作。

public class ItemPickUp : MonoBehaviour
{
    public ItemData_SO itemData;

    private void OnTriggerEnter(Collider other)
    {
        if(other.CompareTag("Player"))
        {
            //往背包中加入物品  + 刷新背包 + 删除物品  (判断背包是否已满)
            bool add = false;
            switch (itemData.itemType)
            {
                case ItemType.Consumable:
                    add = InventoryManager.Instance.consumableInventory.AddItem(itemData);
                    InventoryManager.Instance.consumableContainer.RefreshContainerUI();
                    break;
                case ItemType.PrimaryWeapon:
                case ItemType.SecondaryWeapon:
                    add = InventoryManager.Instance.euqipmentsInventory.AddItem(itemData);
                    InventoryManager.Instance.equipmentsContainer.RefreshContainerUI();
                    break;
            }
            if (add) Destroy(gameObject);
        }
    }
}

        2:物品的拖拽,交换功能

        相关内容定义:在InventoryManager中定义拖拽相关功能

        每次拖动其实是拖动方格SlotHolder下的图片ItemUI,我们将要拖动的ItemUI单独放在一个DragCanvas下(实现在其他UI的上面突出显示)。

        dragOriginalSlot定义了拖拽的原始信息:被拖拽物品的原始方格。


    [Header("拖拽相关")]
    public Canvas dragCanvas;

    public SlotHolder dragOriginalSlot;

        DragItem类:挂载在ItemUI上

要点:使用三个接口 IBeginDragHandler, IDragHandler, IEndDragHandler实现拖拽功能。

类中数据和Awake初始化

    private ItemUI currentItemUI;

    private SlotHolder currentSlot;

    private SlotHolder targetSlot;

    private void Awake()
    {
        currentItemUI = GetComponent<ItemUI>();
        currentSlot = GetComponentInParent<SlotHolder>();
    }

1:IBeginDragHandler:开始拖拽,设置原始方格,设置父物体到 Drag Canvas上。

    public void OnBeginDrag(PointerEventData eventData)
    {
        //记录原始数据
        InventoryManager.Instance.dragOriginalSlot = currentSlot;

        transform.SetParent(InventoryManager.Instance.dragCanvas.transform);
    }

2:IDragHandler:拖拽中途,设置transform的位置为鼠标的位置即可。

    public void OnDrag(PointerEventData eventData)
    {
        //跟随鼠标位置移动
        transform.position = eventData.position;
    }

3:IEndDragHandler:结束拖拽,首先检测下方是否是UI物体,再通过CheckSlot()函数判断鼠标位置是否指向了一个SlotHolder。如果都通过了的话,设置targetSlot(注意,如果对应方格上没有物品,则Slot在最上方,否则ItemUI在最上方),接着检查targetSlot的类型,如果类型匹配,则进行交换Swap(交换的是内含的InventoryItem)操作。完成之后进行更新两个方格,并且将当前DragItem重新回到原始方格,并且设置anchor(防止没有准确放回原位)。

Check函数:遍历所有指定背包中的所有方格Slot即可。

具体的检测方法使用到了RectTransformUtility.RectangleContainsScreenPoint 方法,可以判断指定的位置是否在某一RectTransform内。

    #region 检查当前鼠标位置是否位于一个SlotHoler之内 (用于实现拖拽和交换)
    public bool CheckSlot(Vector3 position)
    {
        bool mouseInSlot = false;
        mouseInSlot |= CheckInSpecifiedInventory(actionContainer, position);
        mouseInSlot |= CheckInSpecifiedInventory(playerEquipmentContainer, position);
        if (currentShowContainer.gameObject.activeInHierarchy)
            mouseInSlot |= CheckInSpecifiedInventory(currentShowContainer, position);
        return mouseInSlot;
    }

    private bool CheckInSpecifiedInventory(ContainerUI specifiedInventory,Vector3 position)
    {
        for(int i=0;i< specifiedInventory.slotHolders.Length;i++)
        {
            RectTransform t = specifiedInventory.slotHolders[i].transform as RectTransform;
            if (RectTransformUtility.RectangleContainsScreenPoint(t, position))
                return true;
        }
        return false;
    }

    #endregion
public void OnEndDrag(PointerEventData eventData)
    {
        //放下物品 交换数据
        //判断鼠标下方是否指向的是UI物体
        if(EventSystem.current.IsPointerOverGameObject())
        {
            if(InventoryManager.Instance.CheckSlot(eventData.position))
            {
                if (eventData.pointerEnter.gameObject.GetComponent<SlotHolder>())
                    targetSlot = eventData.pointerEnter.gameObject.GetComponent<SlotHolder>();
                else
                    targetSlot = eventData.pointerEnter.gameObject.GetComponentInParent<SlotHolder>();
                //根据目标格子的类型进行交换
                switch (targetSlot.slotType)
                {
                    case SlotType.ConsumableBag:
                        if (currentItemUI.itemData.itemType == ItemType.Consumable) SwapItem();
                        break;
                    case SlotType.EquipmentBag:
                        if (currentItemUI.itemData.itemType != ItemType.Consumable) SwapItem();
                        break;
                    case SlotType.PrimaryWeapon:
                        if(currentItemUI.itemData.itemType== ItemType.PrimaryWeapon) SwapItem();
                        break;
                    case SlotType.SecondaryWeapon:
                        if (currentItemUI.itemData.itemType == ItemType.SecondaryWeapon) SwapItem();
                        break;
                    case SlotType.Action:
                        if (currentItemUI.itemData.itemType == ItemType.Consumable) SwapItem();
                        break;
                }
                currentSlot.UpdateItem();
                targetSlot.UpdateItem();
            }
        }
        transform.SetParent(InventoryManager.Instance.dragOriginalSlot.transform);
        RectTransform t = transform as RectTransform;
        t.offsetMax = Vector2.zero;
        t.offsetMin = Vector2.zero;
    }

4:Swap:Swap交换的是背包数据库InventorItem数据(要处理自我交换的情况),通过Slot下的ItemUI下的背包数据库以及下标获取对应的实际物品,对于可堆叠和不可堆叠的情况分开处理。

    private void SwapItem()
    {
        //对自我交换进行处理
        if (targetSlot == currentSlot) return;

        //得到背包中实际的物品
        InventoryItem targetItem = targetSlot.itemUI.GetItemByItemUI();
        InventoryItem tmpItem = currentSlot.itemUI.GetItemByItemUI();

        //处理可叠加的情况 (同一种物品 + 物品可堆叠 )
        if(targetItem.itemData==tmpItem.itemData && targetItem.itemData.statckable)
        {
            targetItem.itemAmount += tmpItem.itemAmount;
            tmpItem.itemData = null; tmpItem.itemAmount = 0;
        }
        //不可叠加 进行交换
        else
        {
            targetSlot.itemUI.Bag.items[targetSlot.itemUI.Index] = tmpItem;
            currentSlot.itemUI.Bag.items[currentSlot.itemUI.Index] = targetItem;
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值