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为数据库类的成员变量(真正的数据库),只不过我们对这个成员变量进行了实例化。
- 跨脚本调用函数
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;
}
由于只存在一个实例所以常常用作管理器
- 判断标签:
//CompareTag()
//例子:
if (collision.gameObject.CompareTag("Player"))
{
AddNewItem();
Destroy(gameObject);
}
- list常用的方法
unity:List数据类型常用方法和属性 - 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”- 对象与世界轴或父轴完全对齐。
- 如何设置父对象
子对象.transform.SetParent(父对象.transform)
(好像关于父子对象都是用transform)
脚本也是一个组件,可以通过GetComponent<>()找到,所以想修改脚本或匹配脚本数据时可以用这样的方法
- 获取所有子元素
GetComponentsInChildren()
TestComponent[] trans = GetComponentsInChildren<Transform>();//这样可以获取到自身
- 获取子物体数量
Transform.childCount
- OnEnable()
当对象的激活时,并且脚本激活时(小勾勾)执行一次 - 静态变量可以跨场景传值。
快捷键:
Ctrl+K+D可以快事格式化代码
参考资料:
CreateAssetMenuAttributeUnity 数据存储方式之一:ScriptableObjectUnity中的SendMessage的用法Unity单例模式+例子Unity3d设计模式之单例模式Unity单例模式Quaternion.identityUnity3d GameObject.Instantiate函数理解(Unity)Instantiate粗略讲解nity从青铜 到 王者!只差这篇让你学会Unity中最重要的部分——脚本组件Unity3D——GetComponentsInChildren()方法详解获取子物体数量—Transform.childCountUnity中关于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 XXXXUnity报错之【NullReferenceException: Object reference not set to an instance of an object】nity The referenced script (Unknown) on this Behaviour is missing!