优点:
1.unity内置的一种储存容器(不用作为组件挂载在物体上,也可以被序列化)
2.可以以asset形式储存(不需要其他额外的文件解析转换之类的,同时可跨项目使用)
3.可以在PlayMode储存数据更改(再也不怕更改数据没保存了)
4.可以储存大量数据(其他对象都可以调用,有效避免产生冗余数据,这一点太有用了)
5.可以添加引用到脚本中
缺点:
1.需要扩展Editor
2.不可以在unity外操作
3.这是用来储存开发数据的,而不是储存玩家数据的。
什么时候用?
1.就如优点所展示的那样,当有一些数据被同时大量使用,为了避免数据冗余,可以使用。同时应该注意,因物而异的变量不应该声明在此处。
2.作为唯一的资源交给版本控制器。例如,本地化数据、清单目录、表格、敌人配置等
3.ScriptableObject除了可以存储数据外,我们还可以在ScriptableObject中定义一些方法。。这类似于插槽设计模式,ScriptableObject提供一些槽,MonoBehaviour可以把自己插进去。适用于AI类型、回血的buff或debuffs等(回血例子见结尾)
如何实现?
step1.创建你用于共享数据的类(例如EnemyData)
using UnityEngine;
public class EnemyData: ScriptableObject
{
public string name;
public Color thisColor;
public Vector3[] spawnPoints;
}
step2.新建一个脚本扩展Editor,使编辑器能够创建自定义的ScriptableObject对象
using UnityEngine;
using UnityEditor;
//新建一个Editor文件夹,放在里面
public class MakeEnemyData{
[MenuItem("Assets/Editor/Scriptable Object")] //定义了如何新建的路径
public static void CreateMyAsset()
{
//将EnemyData创建为asset
EnemyData asset = ScriptableObject.CreateInstance<EnemyData>();
//设置新创建的NewScripableObject文件的初始路径
AssetDatabase.CreateAsset(asset, "Assets/NewScripableObject.asset");
AssetDatabase.SaveAssets();
EditorUtility.FocusProjectWindow();
Selection.activeObject = asset;
}
}
step3. 在需要引用的脚本中引用
using UnityEngine;
public class EnemyAI : MonoBehaviour {
public EnemyData data; //data配置的数据就可以被所有相同种类的怪物共享,节省内存
...........
}
另外注意:每次新建项名称都相同,这意味着不及时改名就会被覆盖。请及时归类或重命名
到第三步为止,是 ScriptableObject最基础的用法,或许它的优点还不明显,接下来再举例第四步
further step. 创建区域化控制脚本(可以是GameManager这种)
public class GameManager:MonoBehaviour{
public EnemyAI enemy; //相同类型的enemy
public EnemyData[] leveData; //不同的配置信息
[Range(1,5)] //五个不同的关卡
public int levels;
void Start(){
if(levels > levelData.Length)
levels = levelData.Length;
//自动根据当前关卡给enemy配置信息,一劳永逸
enemy.data = levelData[ levels-1 ];
}
.......
}
回血buff例子
abstract class PowerupEffect : ScriptableObject {
public abstract void ApplyTo(GameObject go);
}
[CreateAssetMenu ...]
class HealthBooster : PowerupEffect {
public int Amount;
public override void ApplyTo(GameObject go) {
go.GetComponent<Health>().currentValue += Amount;
}
}
class Powerup : MonoBehaviour {
public PowerupEffect effect; //这样就不用每个人物身上挂多个相同的buff脚本了
public void OnTriggerEnter(Collider other) {
effect.ApplyTo(other.gameObject);
}
}