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<Item> itemList = new List<Item>();//设置背包里面物品的列表
}

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<GameObject> slots = new List<GameObject>();//物品栏中的物品对象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<Slot>().slotID = j;instance.slots[j].GetComponent<Slot>().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 updatevoid Awake(){currentRect = GetComponent<RectTransform>();}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<Slot>().slotID;transform.SetParent(transform.parent.parent);//把物体从父节点中分离,使其能够在最上层显示transform.position = eventData.position;GetComponent<CanvasGroup>().blocksRaycasts = false;}//拖拽public void OnDrag(PointerEventData eventData){//transform.position = eventData.position;Vector3 pos;m_RT = gameObject.GetComponent<RectTransform>();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<Slot>().slotID];myBag.itemList[eventData.pointerCurrentRaycast.gameObject.GetComponentInParent<Slot>().slotID] = temp;eventData.pointerCurrentRaycast.gameObject.transform.parent.position = orignalParent.position;eventData.pointerCurrentRaycast.gameObject.transform.parent.SetParent(orignalParent);GetComponent<CanvasGroup>().blocksRaycasts = true;return;}//如果放开位置没有物品,则直接放下。transform.SetParent(eventData.pointerCurrentRaycast.gameObject.transform);transform.position = eventData.pointerCurrentRaycast.gameObject.transform.position;myBag.itemList[eventData.pointerCurrentRaycast.gameObject.GetComponentInParent<Slot>().slotID] = myBag.itemList[currentItemID];myBag.itemList[currentItemID] = null;GetComponent<CanvasGroup>().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<Rigidbody2D>();coll = GetComponent<Collider2D>();anim = GetComponent<Animator>();}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.效果演示

  • 背包初始状态

  • 物品转移到背包里面

  • 交换物品

  • 拖拽物品

Unity2021 Inventory(背包)系统学习记录相关推荐

  1. 【稀疏向量技术是什么?】差分隐私系统学习记录(六)

    The Algorithmic Foundations of Differential Privacy (六) 写在前面的话 Remarks on composition Weak Quantific ...

  2. 【差分隐私入门】差分隐私系统学习记录 (一)

    The Algorithmic Foundations of Differential Privacy (一) 写在前面的话 The Promise of Differential Privacy B ...

  3. yii验证系统学习记录,基于yiicms(一)写的太长了,再写一篇(二)

    项目地址:https://gitee.com/templi/yiicms 感谢七觞酒大神的付出,和免费分享.当然也感谢yii2的开发团队们. 项目已经安全完毕,不知道后台密码,这种背景下,后台无法进去 ...

  4. 【线性查询之间存在相关性误差】差分隐私系统学习记录(七)

    The Algorithmic Foundations of Differential Privacy (七) 写在前面的话 Releasing Linear Queries with Correla ...

  5. 【高斯和拉普拉斯为什么分别对应L2和L1?】差分隐私系统学习记录(五)

    The Algorithmic Foundations of Differential Privacy (五) 写在前面的话 Laplace versus Gauss 什么是先验分布?后验分布?似然估 ...

  6. SpringBoot 微信点餐系统学习记录六-订单表和订单详情表的后端开发

    在dataobject文件夹创建订单表和订单详情表的实体类 package com.imooc.dataobject;import com.imooc.enums.OrderStatusEnum; i ...

  7. 【差分隐私的Advanced composition到底是什么?】差分隐私系统学习记录(四)

    The Algorithmic Foundations of Differential Privacy (四) 写在前面的话 Composition: some technicalities Adva ...

  8. 【差分隐私的指数机制该怎么理解?】差分隐私系统学习记录(三)

    The Algorithmic Foundations of Differential Privacy (三) 写在前面的话 The exponential mechanism 写在前面的话 纯属个人 ...

  9. 【数学工具?拉普拉斯机制?随机响应?】差分隐私系统学习记录(二)

    The Algorithmic Foundations of Differential Privacy (二) 写在前面的话 Basic Techniques and Composition Theo ...

最新文章

  1. perl学习之(not install YAML)解决
  2. 【原创视频教程】学生信息管理系统6--学员信息管理(完结篇)
  3. 【体验干货】产品经理必知:产品体验报告如何写的全而精
  4. postgres循环sql
  5. 树状数组(Binary Indexed Tree)
  6. eclipse juno_放弃Eclipse Juno
  7. 走心!北京语言大学教授毕业致辞:在人生的道路上,一定要把自己当回事儿...
  8. 玩转微服务日志框架Logback
  9. html div 水平垂直居中显示,利用CSS实现div水平垂直居中
  10. Python+ZeroMQ使用REQ/REP模式快速实现消息收发
  11. Zabbix(一)安装zabbix监控服务配置与添加agent主机的三种方式
  12. shell 日期格式化输出
  13. Android Studio躲避小球小游戏(一界面布局)
  14. 使用Chrome谷歌浏览器打开Axure原型图
  15. 求三角形外接圆圆心坐标的算法
  16. 【编程题 】年会抽奖(详细注释 易懂)
  17. RS232串口线连接方法
  18. 程序员的思维(转载于伯乐在线-author:水流年)
  19. linux dd 克隆很慢,使用dd命令进行SD卡克隆
  20. 亿道丨三防手机丨手持终端丨零售行业如何选择手持工业终端设备?

热门文章

  1. 婚礼这天你是公主,你的婚礼你做主
  2. 台式计算机启动时 每次按f1,开机按f1的解决方法_电脑开机每次都要按F1,怎么解决...
  3. vue父与子组件,子与子组件间的方法调用和通信
  4. C语言 键盘编码 及 用法
  5. what is the mes (mes系统是什么)
  6. 修改服务端监听器端口号为1526
  7. 年龄和收入对数的线性回归_金融计算收益率的时候为什么大部分用对数收益率 (Log Return) 而不是用算数收益率?...
  8. 一枚普通前端平淡无奇的一年 - 2021年终总结
  9. python opencv 读取mov文件
  10. 写paper之ppt画图——不定期更新