利用ScriptableObject实现数据持久化
Monobehavior:每次重新打开游戏时,数据都会初始化为一开始的状态,而不会保存上一次游玩的数据。
ScriptableObject可以保存数据(在本地),即实现存档。而且它无需挂载在任何节点上,就可以生效。
本节课的内容
- 创建管理物品的脚本Item
- 创建管理背包的脚本Inventory(因为除了主角,npc也会有背包)
- 创建管理场景中物品的脚本ItemOnWorld,当角色碰到场景中的item,将该item的数据存入背包
Step1
增加菜单栏的选项,代码如下:
[CreateAssetMenu(fileName ="New Item",menuName ="Inventory/New Item")]
filename
指的是文件的默认名称,menuname
则是菜单栏中显示的选项名。
在Unity中,右键,就可以看见菜单栏中多了一项:
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 itemImage;//物品图片
public int itemHeld;//物品数量
[TextArea]
public string itemInfo;//详细信息
}
现在创建一把剑,
inspector中就可以设置参数:(如果后续想增加参数,修改脚本即可)
小知识点:[TextArea]
即显示一段文字区域。
若没有[TextArea]
,是这样的:
Step2
现在创建Inventory的脚本,希望它是一个列表,将所有的物品都存在该列表中。这样就可以利用这个脚本创建不同角色的背包。
Inventory代码如下:
using System.Collections;
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>();
}
创建一个玩家的背包:
首先,我们设置背包中默认的物品是1把剑:
注意:这里的Size指的是种类的多少(即占据了多少格子)。
Step3
接下来,在场景中放上这把剑。当游戏角色碰到剑时,能识别到剑在数据库里的信息,并将它保存进背包中。
对于场景中放置好的物体,我们需要知道两个信息:(1)它属于数据库里的哪个item(2)该物体应该存入哪个背包
脚本如下:
public class ItemOnWorld : MonoBehaviour
{
public Item thisItem;
public Inventory playerInventory;
}
场景中放置剑:
public class ItemOnWorld : MonoBehaviour
{
public Item thisItem;
public Inventory playerInventory;
private void OnTriggerEnter2D(Collider2D other)
{
if(other.gameObject.CompareTag("Player"))
{
AddNewItem();
Destroy(gameobject);
}
}
void AddNewItem()
{
//如果背包中没有该物品,添加
if(!playerInventory.itemList.Contains(thisItem))
{
playerInventory.itemList.Add(thisItem);
}
//反之,增加物品数量
else
{
thisItem.itemHeld += 1;
}
}
}
注意:compareTag里的Player要首字母大小!否则会出现报错:
这里不要写成Destroy(this)!
脚本拖给场景中的剑:
运行游戏
当角色吃掉场景中的剑时,可以看见数量增加。
【评论区大佬】
首先感谢Up主辛苦制作了这么多精品视频,但是对于ScriptableObject,UP主的讲解有些问题,我来解释一下:
1、游戏数据根据可变性分成两种:不可变数据和可变数据,前者主要对应于配置数据(也就是策划配表,比如视频中的Item的名字、描述),而后者就是玩家的自身数据(比如视频中Item的数量)
2、这两者在(商业化)游戏开发中是要独立开来的,最好不要混在一起,以视频为例,玩家真正存盘时,实际上只存储物品Id和数量。至于物品名称、描述,都是在表格中的,不需要处理。
3、ScriptObject这个东西有这么个特点:1、如果使用Editor运行,那么Editor运行期的变化会被保持下来(也即持久化);2、而一旦版本发布后(也即安装到设备上),运行期的变化时不会被保存的!!!(官方原文:如果使用 Editor,可以在编辑时和运行时将数据保存到 ScriptableObjects,因为 ScriptableObjects 使用 Editor 命名空间和 Editor 脚本。但是,在已部署的构建中,不能使用 ScriptableObjects 来保存数据,但可以使用在开发期间设置的 ScriptableObject 资源中保存的数据。 从 Editor 工具作为资源保存到 ScriptableObjects 的数据将写入磁盘,因此将在会话之间一直保留。可以看官方文档:https://docs.unity3d.com/cn/current/Manual/class-ScriptableObject.html)
一句话总结:ScriptObject不能这么直接使用,因为它在Edtor期间会修改本来不应该去修改的“不可变数据”;而在部署构建期间又没有做本职工作,去持久化应该去改变的“可变数据”。
所以,就本视频来说,按照上述第2/3条的观念,首先需要把Item进行拆分,例如:ItemConfig和ItemData(也即配表和玩家数据),前者作为不可变数据(可以使用ScriptableObject),后者作为可变数据进行持久化(当然仍然可以使用ScriptableObject,但是需要额外去持久化操作)
好了,下一步就是让增加的数量显示在背包中就好啦!