Unity背包系统-2:数据库存储方法ScriptableObject和显示背包物品InventoryManager

在这里插入图片描述

1. 数据库脚本

1.1 元素(item)代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName ="New Item",menuName ="Inventory/New Item")]
public class Item : ScriptableObject
{
    
    
    public string itemName;//数据库物品名
    public Sprite image;//数据库物品图片
    public int itemHold;//数据库物品数量
    public bool equip;//数据库物品是否可装备
    public int objectIndex;//数据库物品序号(序号保持一致性)

    [TextArea]
    public string info;//数据库物品说明
}

1.2 数据库代码(ItemList)代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName ="New List",menuName ="Inventory/New List")]
public class ItemList : ScriptableObject
{
    
    
    public List<Item> itemList = new List<Item>();//item和itemscript的类名一样
}

2. 游戏世界物品

为了将sprite和数据库,元素连接我们需要在创建一个脚本挂在所有可收集的物品(item的)上

2.1 ItemOnWorld

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ItemOnWorld : MonoBehaviour
{
    
    
    public Item TheItem;//对每个世界物品都要将世界物品绑定在此脚本上
    public ItemList List;//绑定我们的数据库mybag
    private void OnTriggerEnter2D(Collider2D collision)
    {
    
    
        if (collision.gameObject.CompareTag("Player"))
        {
    
    
            AddNewItem();//添加物品到背包数据库
            Destroy(gameObject);//销毁物品
        }
    }

    //数据库操作
    private void AddNewItem()
    {
    
    
        if (!List.itemList.Contains(TheItem))//判断包不包含,首先要创建相应的item项然后绑定在ItemOnWorld中
        {
    
    
            List.itemList.Add(TheItem);//不在则添加到背包数据库
            InventoryManager.CreateNewItem(TheItem);//并创建预制件在背包UI显示
        }
        else
        {
    
    
            TheItem.itemHold++;//包含则数量加1
            InventoryManager.RefreshItem(TheItem);//刷新数量


        }
    }

}

3. 背包系统

3.1 Slot

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Slot : MonoBehaviour
{
    
    
    public Item slotItem;//背包物品对象
    public Image slotImage;//背包物品图像
    public Text slotNum;//背包物品数量
    public int objectIndex;//背包物品序号(序号保持一致性)

    public void onClick()
    {
    
    
        GameObject.Find("Canvas").SendMessage("UpdateItemInfo", slotItem.info);

    }
}

3.2 ListManager

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class InventoryManager : MonoBehaviour
{
    
    
    static InventoryManager instance;
    public ItemList myBag;//背包连接的数据库:mybag
    public Slot slotPrefab;//背包物品预制件(可以和所有物品对应)
    public Text itemInformation;//背包物品说明
    public GameObject slotGrid;//unity背包网格(在其下创建子物体,方便与背包格子对齐)

    //单例模式
    private void Awake()
    {
    
    
        if (instance != null)
        {
    
    
            Destroy(instance);
        }
        instance = this;
    }

    //每次进游戏刷新背包(根据背包数据库的内容创建预制件并在背包UI显示)
    private void OnEnable()
    {
    
    
        RefreshItem();
    }

    public static void CreateNewItem(Item item)
    {
    
    
        //克隆预制件
        Slot newitem = Instantiate(instance.slotPrefab, instance.slotGrid.transform.position, Quaternion.identity);
        //为克隆预制件赋值(方便在背包UI显示)
        newitem.gameObject.transform.SetParent(instance.slotGrid.transform);//设置父物体
        newitem.slotItem = item;
        newitem.slotImage.sprite = item.image;
        newitem.slotNum.text = item.itemHold.ToString();
        newitem.objectIndex = item.objectIndex;
    }

    //刷新背包物品数量,注意与下面的区别开来,其实是专业叫做重载
    public static void RefreshItem(Item item)
    {
    
    
        //利用transform遍历子对象
        foreach (Transform slot in instance.slotGrid.transform)
        {
    
    
            //获取Slot脚本组件中的objectIndex进行匹配
            if (slot.gameObject.GetComponent<Slot>().objectIndex == item.objectIndex)
            {
    
    
                slot.gameObject.GetComponent<Slot>().slotNum.text = item.itemHold.ToString();
            }
        }
    }




    public static void RefreshItem()
    {
    
    
        //数据库不为空,并且背包对象的子对象不为零(由于会获取到自身所以要<=1)
        if (instance.myBag.itemList.Count != 0 && instance.slotGrid.gameObject.GetComponentsInChildren<Transform>().Length <= 1)
        {
    
    
            //重新进游戏时重新创建预制件
            for (int i = 0; i < instance.myBag.itemList.Count; i++)
            {
    
    
                CreateNewItem(instance.myBag.itemList[i]);
            }
        }
    }

    //显示物品描述
    public void UpdateItemInfo(string info)
    {
    
    
        itemInformation.text = info;
    }
}



解释:

冒号在C#中表示继承,ScriptableObject (脚本对象)是一个可独立于类实例来保存大量数据的数据容器,

最常用的功能就是背包系统的实现,ScriptableObject的特点是在游戏结束后,数据不会清除,依旧会保留游戏中产生的数据。所以可以利用这一点来做背包系统

就像MonoBehaviour一样,ScriptableObject派生自基本Unity对象,但与MonoBehaviour不同,不能将ScriptableObject附加到游戏对象,只能将他们保存在项目中

unity中[]表示具有特殊功能的标记。

[CreateAssetMenuAttribute]对 ScriptableObject 派生类型进行标记,使其自动列在 Assets/Create 子菜单中,以便能够轻松创建该类型的实例并将其作为“.asset”文件存储在项目中。

fileName: 此类型的新建实例使用的默认文件名。
menuName: Assets/Create 菜单中显示的此类型的显示名称。
order: Assets/Create 菜单中菜单项的位置。

效果图:
在这里插入图片描述

ItemOnWorld脚本中成员变量 的类型和Item和ItemList脚本的类相对应

[TextArea]为文本区域

List.itemList.Contains(TheItem)

List为对应的数据库类的实例,而itemList为数据库类的成员变量(真正的数据库),只不过我们对这个成员变量进行了实例化。

  1. 跨脚本调用函数
GameObject.Find("Canvas").SendMessage("UpdateItemInfo", slotItem.info)

对象.SendMeesage(函数名,参数,SendMessageOptions)

第三个参数的意义:
SendMessageOptions.RequireReceiver //如果没有找到相应函数,会报错(默认是这个状态)
SendMessageOptions.DontRequireReceiver //即使没有找到相应函数,也不会报错,自动忽略

static也可以跨脚本调用

单例模式:
单例模式(Singleton),也叫单子模式,是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在

实现单例模式(monobehavior):

public static test2 instance;
    // Use this for initialization
    void Awake () {
    
    
        instance = this;
    }

由于只存在一个实例所以常常用作管理器

  1. 判断标签:
//CompareTag()
//例子:
 if (collision.gameObject.CompareTag("Player"))
        {
    
    
            AddNewItem();
            Destroy(gameObject);
        }
  1. list常用的方法
    unity:List数据类型常用方法和属性

  2. Instantiate

Instantiate(Object original):克隆物体original,其Position和Rotation取默认值,何为默认值呢?就是预制体的position,这里的position是世界坐标,无父物体

Instantiate(Object original, Transform parent):克隆物体original,拥有父物体,其Position和Rotation取默认值,这里的position是localposition,也就是相对于父物体的坐标,父物体为坐标原点

Instantiate(Object original, Transform parent, bool instantiateInWorldSpace):
若instantiateInWorldSpace=false,代表克隆的物体的坐标是localposition,则与Instantiate(Object original, Transform parent)的结果一样。
若instantiateInWorldSpace=true,则代表克隆的物体的坐标为世界坐标

Instantiate(Object original, Vector3 position, Quaternion rotation, Transform parent):这个比较好理解了,克隆物体original,拥有父物体,其Position和Rotation由人为设置,而且这里设置的坐标是世界坐标,不是localposition

Slot newitem = Instantiate(instance.slotPrefab, instance.slotGrid.transform.position, Quaternion.identity);

其中Quaternion.identity:该四元数对应于“no rotation”- 对象与世界轴或父轴完全对齐。

  1. 如何设置父对象
    子对象.transform.SetParent(父对象.transform)
    (好像关于父子对象都是用transform)

脚本也是一个组件,可以通过GetComponent<>()找到,所以想修改脚本或匹配脚本数据时可以用这样的方法

  1. 获取所有子元素
    GetComponentsInChildren()
TestComponent[] trans = GetComponentsInChildren<Transform>();//这样可以获取到自身
  1. 获取子物体数量
Transform.childCount
  1. OnEnable()
    当对象的激活时,并且脚本激活时(小勾勾)执行一次

  2. 静态变量可以跨场景传值。

快捷键:
Ctrl+K+D可以快事格式化代码

参考资料:

CreateAssetMenuAttribute
Unity 数据存储方式之一:ScriptableObject
Unity中的SendMessage的用法
Unity单例模式+例子
Unity3d设计模式之单例模式
Unity单例模式
Quaternion.identity
Unity3d GameObject.Instantiate函数理解
(Unity)Instantiate粗略讲解
nity从青铜 到 王者!只差这篇让你学会Unity中最重要的部分——脚本组件
Unity3D——GetComponentsInChildren()方法详解
获取子物体数量—Transform.childCount
Unity中关于transform.root和transform.parent的区别和联系?
unity实例化物体到父物体之下
使用Unity获取所有子对象及拓展方法的使用
Unity获取未激活游戏对象的方法
【Unity3D 灵巧小知识点】 ☀️ | 获取某个游戏对象下的所有子物体
【Unity3D日常开发】如何获取所有的子对象(child)
Unity3D如何获取对象和子对象
Unity开发备忘录000021:如何判断某一个对象是否有子对象
Unity Awake() OnEnable() Start()三个函数理解
Awake/Start/OnEnable 辨析
【Unity 05】C# static类及其使用方法
C# 静态类 静态变量 静态方法 在Unity中的使用
unity, 什么时候用静态类,什么时候用单例
c#中get set 的使用
C#中{get;set;}
【C#学习笔记】C#中set和get用法
Unity之背包系统(一):物品类的生成和背包的制作
unity开发背包系统
unity 背包系统之美

常见报错情况:
【解决】NullReferenceException: Object reference not set to an instance of an object XXXX
Unity报错之【NullReferenceException: Object reference not set to an instance of an object】
nity The referenced script (Unknown) on this Behaviour is missing!

猜你喜欢

转载自blog.csdn.net/m0_53438035/article/details/124003743
今日推荐