赞
踩
用来存储数据的一个资源文件,像是JSON、XML、文本文件这样的存储文件,可以用来存储数据。但是这里他在最开始的时候不需要再次读文件,就像是JSON在游戏开始时,我们需要加载JSON文件中的数据,我们就需要读取这个文件,然后在赋值给对象。他就可以直接使用其中的数据。因为他是资源文件,所以他有着资源文件的特性。
Enum的缺点:必须改代码,删改不方便,不能存储更多的数据
用法如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName ="TabSO",menuName ="ScriptableObject/NewTab",order = 1 )]
public class TabSO : ScriptableObject
{
//可以包含更多的数据,信息
}
当我们需要一个新的标志时,创建并命名一个SO即可
public class PlayerSo : MonoBehaviour { [SerializeField] TabSO myType; [SerializeField] TabSO t1; [SerializeField] TabSO t2; // Start is called before the first frame update void Start() { if (t1 == myType) { Debug.Log("Fire"); } if (t2 == myType) { Debug.Log("Go"); } } }
原因:对设计师友好,对Git友好,可以被别处监听,方便打包运输
数据监听:例.玩家的HP与UI血条通过Scriptable Object解耦
配置文件:例.玩家敌人的基础属性
如果默认的内容不足以满足我们的要求,可以自定义扩展
例:我们在创建了一个SO,上面携带了AudioClip,我们打算在编辑器上点击播放
using System.Collections; using System.Collections.Generic; using UnityEngine; [CreateAssetMenu(menuName = "Scriptable Object/NewAudioSO",order =1)] public class AudioSO : ScriptableObject { public AudioClip[] clips; [Range(0f, 1f)] public float minVolume; [Range(0f, 1f)] public float maxVolume; [Range(-2f, 2f)] public float minPitch; [Range(-2f, 2f)] public float maxPitch; public void Play(AudioSource source) { if (clips.Length <= 0) return; source.clip = clips[Random.Range(0,clips.Length)]; source.volume = Random.Range(minVolume, maxVolume); source.pitch = Random.Range(minPitch, maxPitch); source.Play(); } }
我们需要创建一个脚本,为这个ScriptObject服务
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEditor; [CustomEditor(typeof(AudioSO))] //声明自己为哪个类服务 public class AudioSOEditor : Editor { //服务的目标 private AudioSO _target; private AudioSource _previewAudioSource; private void OnEnable() { _target = target as AudioSO; //创建一个隐藏的AudioSource _previewAudioSource = EditorUtility.CreateGameObjectWithHideFlags( "AudioPreview",HideFlags.HideAndDontSave,typeof(AudioSource)).GetComponent<AudioSource>(); } //因为_previewAudioSource是HideAndDontSave,所以在OnDisable里必须销毁 private void OnDisable() { DestroyImmediate(_previewAudioSource); } //OnInspectorGUI上创建一个按钮播放它 public override void OnInspectorGUI() { base.OnInspectorGUI(); //在原来基础上加一个按钮 if(GUILayout.Button("PreviewAudio")) { _target.Play(_previewAudioSource); } } }
现在我们点击面板上新创建的PreviewAudio按钮即可播放开枪声
首先需要一个充当桥梁的ScriptObject
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
[CreateAssetMenu(menuName ="EventsSO/Event Channel")]
public class EventSO : ScriptableObject
{
public UnityAction action;
public void Raise()
{
action?.Invoke();
}
}
事件的发送者和接收者分别有一个EventSO字段,存放新建的SO
事件的接收者为SO内的action添加事件
public class Test : MonoBehaviour { [SerializeField] EventSO eso; void print() { Debug.Log("Button被点击"); } private void Start() { eso.action += print; } private void OnDisable() { eso.action -= print; } }
//事件的发送者 public class NewButtonScript : MonoBehaviour { Button b; [SerializeField] EventSO eso; // Start is called before the first frame update void Start() { b = this.GetComponent<Button>(); if (b == null) Debug.LogError("未找到Button"); b.onClick.AddListener(bOnclick); } private void OnDisable() { b.onClick.RemoveAllListeners(); } void bOnclick() { eso.Raise(); } }
例:当有n个敌人,其中一个死了后,其他敌人需要做出某行为(例如赶到死亡地点)
原始做法:创建一个单例类,包含一个List字段,将所有敌人登记进去,当某个敌人死亡后,删除它并遍历List中所有的敌人调用行为函数
ScriptObject做法:创建一个SO,内包含一个List字段,添加功能,删除功能,和遍历所有敌人调用行为函数功能,这样我们就不需要新建一个单例并额外挂载脚本到场景中了。
[CreateAssetMenu(fileName = "RuntimeSetSo",menuName = "ScriptableObjects/RuntimeSetSo",order = 1)] public class RuntimeSetSo:ScriptableObject { public List<Enemy> _ListEnemys = new List<Enemy>(); public Add(Enemy enemy) { if(!_ListEnemys.Contains(enemy)) _ListEnemys.Add(enemy); } public Remove(Enemy enemy) { if(_ListEnemys.Contains(enemy)) _ListEnemys.Remove(enemy); } //----遍历除死亡敌人外的所有敌人,并执行某一行为 public void OnEnemyDie(Enemy enemy,Vector3 location) { Remove(enemy); foreach(var _enemy in _ListEnemys) { _enemy.GotoLocation(location); } } }
public class Enemy:MonoBehaviour { [SerializeField] private RuntimeSetSo runtimeSetSo; private void Start() { if(runtimeSetSo!=null) { runtimeSetSo.Add(this); } } private void Update() { if(this.Die()) { runtimeSetSo.OnEnemyDie(this,this.transform.position); } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。