栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 游戏开发 > Unity3D

Unity2021 Inventory(背包)系统学习记录

Unity3D 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Unity2021 Inventory(背包)系统学习记录

Unity2021 Inventory(背包)系统学习记录

最近学习了Unity背包系统设计的基本设计。学习资料主要参考了B站up主:M_Studio的教学视频。学习完后,在Assets Store上重新下载了一套GUI对学习到的知识进行了一次复盘。现在,对复盘的过程进行一次记录。这个背包系统主要实现了基本的背包功能,Player(玩家)在场景中拾取得到物品,然后物品能够在背包上出现,背包中的物品也能够进行移动以及交换位置。

​ 使用的资源都是在Asset Store上下载得到的免费资源,本次使用的UI主要是GUI_Parts、Simple Fantasy GUI、Tiny RPG Forest。

1. 设置UI
  • 在场景中按照以下父子关系的顺序,创建UI。

  • 然后,对UI组件对象进行重新命名。

  • 把Slot设置为预制体,Slot表示一个装备栏,装备栏里有对应的游戏物品,这个装备栏显示的是物品的图片和物品的数量。

  • 设置好Slot预制体后,可以在游戏场景中删除Slot的UI对象。

  • UI的图片可以按照自己的喜好设置,这里需要注意的是Grid对象需要添加一个Grid Layout Group组件,使Grid做成网格布局。

  • 通过上述的UI组件设置,其在场景中生成的效果如下图所示。

2.设置ScriptableObject

ScriptableObject可以把数据存储在资源文件中,当退出运行时也一样会保持修改。这里把物品和背包设置成ScriptableObject对象。

  • 新建一个C#脚本Item.cs,用于创建物体的ScriptableObject对象。

    using UnityEngine;
    
    [CreateAssetMenu(fileName = "New Item", menuName = "Inventory/New Item")]//右键菜单快速创建
    public class Item : ScriptableObject
    {
        public string itemName;//设置物品的名称
        public Sprite itemImage;//设置物品的图片
        public int itemHeld;//设置物品的数量
        [TextArea]
        public string itemInfo;//设置物品的描述
    
        public bool equip;//设置物品可否装备
    }
    

  • 新建一个C#脚本Inventory.cs,用于创建背包的ScriptableObject对象。
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "New Inventory", menuName = "Inventory/New Inventory")]
public class Inventory : ScriptableObject
{
    public List itemList = new List();//设置背包里面物品的列表
}

3.在背包UI对象添加一个InventoryManger.cs脚本,用于控制物品栏里面的物品显示。
sing System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class InventoryManger : MonoBehaviour
{
   private static InventoryManger instance;

   public Inventory myBag; // 获取背包的信息
   public GameObject slotGrid;//获取Grid网格对象
   //public Slot SlotPrefab;
   public GameObject emptySlot;//slot预制体
   public Text itemInformation;//物品描述
   public List slots = new List();//物品栏中的物品对象
   void Awake()//单例模式,保证只有一个实例
   {
      if (instance!=null)
      {
         Destroy(this);
      }

      instance = this;
   }

   private void OnEnable()
   {
      RefreshItem();//每次启动程序时,刷新背包里的物品
      instance.itemInformation.text = "";//物品描述设置为空
   }

   public static void UpdateItemInfo(string itemDes)
   {
      instance.itemInformation.text = itemDes;//设置物品描述信息
   }


   public static void RefreshItem()
   {
       //先删除物品栏中的所有游戏对象,遍历Grid挂载的子对象
      for (int i = 0; i < instance.slotGrid.transform.childCount; i++)
      {
          
         if (instance.slotGrid.transform.childCount==0)//如果Grid没有挂载子对象
         {
            break;
         }
          //每遍历一个就删除一个子对象
         Destroy(instance.slotGrid.transform.GetChild(i).gameObject);
         instance.slots.Clear();
      }
       //重新加载Invetory中的物品对象。
      for (int j = 0; j < instance.myBag.itemList.Count; j++)
      {
           instance.slots.Add(Instantiate(instance.emptySlot));
           instance.slots[j].transform.SetParent(instance.slotGrid.transform, false);
           instance.slots[j].GetComponent().slotID = j;
           instance.slots[j].GetComponent().SetupSlot(instance.myBag.itemList[j]);
      }
      
   }
   
}
  • 场景中的Bag物体对象,按以下组件设置。

  • Bag组件中的MoveBag.cs脚本主要时控制背包窗口的拖拽。

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.EventSystems;
    
    public class MoveBag : MonoBehaviour,IDragHandler
    {
        public Canvas canvas;
    
        private RectTransform currentRect;
        // Start is called before the first frame update
        void Awake()
        {
            currentRect = GetComponent();
        }
    
        public void OnDrag(PointerEventData eventData)
        {
    
            currentRect.anchoredPosition += eventData.delta;
        }
    }
    
4.Slot预制体的设置
  • Slot预制体挂载一个Slot.cs脚本,这个脚本主要时控制物品的图片和物品的数量。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class Slot : MonoBehaviour
    {
        public int slotID;
        public Item SlotItem;
        public Image SlotImage;//物品图片
        public Text slotNum;//物品数量
        public GameObject itemInslot;
        public string slotInfo;
        public void ItemOnClick()
        {
            InventoryManger.UpdateItemInfo(slotInfo);//点击该物品时,物品描述将会更新
        }
    
        public void SetupSlot(Item item)
        {
            if (item==null)//如果物品不存在,物品栏并不会激活
            {
                itemInslot.SetActive(false);
                return;
            }
    
            SlotImage.sprite = item.itemImage;
            slotNum.text = item.itemHeld.ToString();
            slotInfo = item.itemInfo;
        }
    }
    
    
  • Slot预制体中组件的设置如下

5.物品的拖拽
  • 在Slot预制体中的Item物体中挂载ItemOnDrag.cs组件

    using UnityEngine;
    using UnityEngine.EventSystems;
    
    public class ItemOnDrag : MonoBehaviour,IBeginDragHandler,IDragHandler,IEndDragHandler
    {
        public Transform orignalParent;
        private RectTransform m_RT;
        public Inventory myBag;
        private int currentItemID;
        //开始拖拽
        public void OnBeginDrag(PointerEventData eventData)
        {
            orignalParent = transform.parent;//记录物体原先的位置
            currentItemID = orignalParent.GetComponent().slotID;
            transform.SetParent(transform.parent.parent);//把物体从父节点中分离,使其能够在最上层显示
            transform.position = eventData.position;
            GetComponent().blocksRaycasts = false;
        }
    	//拖拽
        public void OnDrag(PointerEventData eventData)
        {
            //transform.position = eventData.position;
            Vector3 pos;
            m_RT = gameObject.GetComponent();
            RectTransformUtility.ScreenPointToWorldPointInRectangle(m_RT,eventData.position,eventData.enterEventCamera,out pos);
            m_RT.position = pos;
            //Debug.Log(eventData.pointerCurrentRaycast.gameObject.name);
        }
    	//放开拖拽
        public void OnEndDrag(PointerEventData eventData)
        {
            //使用射线来检测物体下方是不是有物品,如果有物品则交换位置
            if (eventData.pointerCurrentRaycast.gameObject.name=="Item Image")
            {
                transform.SetParent(eventData.pointerCurrentRaycast.gameObject.transform.parent.parent);
                transform.position = eventData.pointerCurrentRaycast.gameObject.transform.parent.parent.position;
                
                //itemList的物品存储位置改变。
                var temp = myBag.itemList[currentItemID];
                myBag.itemList[currentItemID] =
                    myBag.itemList[eventData.pointerCurrentRaycast.gameObject.GetComponentInParent().slotID];
                myBag.itemList[eventData.pointerCurrentRaycast.gameObject.GetComponentInParent().slotID] = temp;
                
                eventData.pointerCurrentRaycast.gameObject.transform.parent.position = orignalParent.position;
                eventData.pointerCurrentRaycast.gameObject.transform.parent.SetParent(orignalParent);
                
                GetComponent().blocksRaycasts = true;
                
                return;
            }
            //如果放开位置没有物品,则直接放下。
            transform.SetParent(eventData.pointerCurrentRaycast.gameObject.transform);
            transform.position = eventData.pointerCurrentRaycast.gameObject.transform.position;
            myBag.itemList[eventData.pointerCurrentRaycast.gameObject.GetComponentInParent().slotID] = myBag.itemList[currentItemID];
            myBag.itemList[currentItemID] = null;
            GetComponent().blocksRaycasts = true;
        }
        
    }
    
  • Item物体的组件设置情况如下。

6.Player(玩家)组件的设置

  • Player上挂载一个PlayerMovement.cs脚本,用于控制Player的移动,以及控制背包的打开。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PlayerMovement : MonoBehaviour
    {
        Rigidbody2D rb;
        Collider2D coll;
        Animator anim;
        public GameObject myBag;
        private bool isOpen;
        public float speed;
        Vector2 movement;
    
        private void Awake()
        {
            rb = GetComponent();
            coll = GetComponent();
            anim = GetComponent();
        }
    
        private void Update()
        {
            Movement();
            SwitchAnim();
            OpenMyBag();
        }
    
        void Movement()//移动
        {
            movement.x = Input.GetAxisRaw("Horizontal");
            movement.y = Input.GetAxisRaw("Vertical");
            rb.MovePosition(rb.position + movement * speed * Time.deltaTime);
    
        }
    
        void SwitchAnim()//切换动画
        {
            if (movement != Vector2.zero)//保证Horizontal归0时,保留movment的值来切换idle动画的blend tree
            {
                anim.SetFloat("horizontal", movement.x);
                anim.SetFloat("vertical", movement.y);
            }
            anim.SetFloat("speed", movement.magnitude);//magnitude 也可以用 sqrMagnitude 具体可以参考Api 默认返回值永远>=0
        }
    
        void OpenMyBag()
        {
            if (Input.GetKeyDown(KeyCode.O))
            {
                myBag.SetActive(!myBag.activeSelf);
            }
        }
    }
    
7.效果演示
  • 背包初始状态

  • 物品转移到背包里面

  • 交换物品

  • 拖拽物品
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/900551.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号