ScriptableObject简单使用

ScriptableObject

平时开发存在的一些问题:

  • 一个场景内有多个相同组件使用相同数值的时候,这个组件也在内存中多了一份实例,浪费内存空间。

  • static或者[Serializable]修饰的变量,在程序退出后会还原。编辑器模式运行时,只能通过Copy Component Values来临时保存调整好的数值。

  • 项目之间、场景之间数据很难共享。

  • 在runtime下要改变某个GameObject上组件的数值,就一定要获取到这个GameObject实例,使项目耦合度成倍提高,最后变成蜘蛛网。

  • 场景中总会有一些空的GameObject用来保存和共享数据,这个GameObject基本不会参与太多的游戏逻辑,但为了保存和共享场景内的数据就不得不碍眼的在场景中出现,逼死强迫症,也不利于模块抽象。

  • 同样,要通过UGUI Button中的On Click事件调用一个GameObject上的方法,也只能获取到GameObject实例来调用,数量太多的话也变成了蜘蛛网。

使用ScriptableObject如何解决

  • ScriptableObject是将数据存储在.asset文件中的,可以理解为类似material这样的文件,ScriptableObject中存储的数值在runtime中作出修改,在退出后也会被保存下来。
  • 同样,类似material文件,在多个地方需要用到同一个数据,只要把ScriptableObject生成的.asset文件拖入相应位置就可以,不必再指向某个单例或者实例。
  • 可以被任何场景引用,在项目之间、场景之间很容易的共享数据。
  • 不必为了保存数据在场景中放置一个空GameObject。让项目的复杂度和耦合度最大限度的降低,强迫症福音。
  • ScriptableObject是自定义的数据类型,应用非常灵活。
  • 通过UGUI Button中的On Click事件只需要指向某一个ScriptableObject文件,而响应事件的GameObject也只需要获取到这个ScriptableObject文件即可触发,不必让按钮指向GameObject实例。大幅度减少了项目逻辑和结构的复杂程度。

需求

  1. 通过ScriptableObject获取一个GameObject的实例。
  2. 不获取物体实例,通过ScriptableObject实现UnityEvent的执行。

角色:player,enemy;

场景内会在随机位置生成任意数量的敌人,敌人会追着player一直跑,player通过移动来躲避敌人,每次碰到敌人就会减少生命值。

开始实现

搭建场景和角色敌人:

image-20220606180524764

新建脚本FollowTransformSmooth,实现追踪功能,拖到enemy上面。

public class FollowTransformSmooth : MonoBehaviour
{
//[SerializeField] Transform target;
[SerializeField] TargetTransform target;
[SerializeField] Rigidbody selfRigidbody;
[SerializeField, Range(0f, 100f)] float moveSpeed = 10f;
Vector3 _destination;//目的地
Vector3 _direction;//方向
void LateUpdate()
{//LateUpdate 在调用所有 Update 函数后调用。
//_destination = target.position;//怪物追踪目的地
_destination = target.targetTrans.position;//怪物追踪目的地
_direction = (_destination - transform.position).normalized;//怪物前进方向
//AddForce,向刚体添加力,(vector3方向,ForceMode力类型)
selfRigidbody.AddForce(_direction * moveSpeed, ForceMode.Acceleration);
// ForceMode.Force 向此刚体添加连续力,使用其质量。
// ForceMode.Acceleration 向此刚体添加连续加速度,忽略其质量。
// ForceMode.Impulse 向此刚体添加瞬时力冲击,考虑其质量。
// ForceMode.VelocityChange 向此刚体添加瞬时速度变化,忽略其质量。
}
}

新建TargetTransform脚本,继承ScriptableObject,用来存储主角的位置信息

[CreateAssetMenu(menuName = "mySubMenu/TargetTransform ")]
public class TargetTransform : ScriptableObject
{
public Transform targetTrans;
}

编译完在文件夹新建TargetTransform,命名为Player

image-20220606181512646

新建SetTarget脚本,主角位置数据赋值给TargetTransform。拖到player上

public class SetTarget : MonoBehaviour
{
[SerializeField] TargetTransform target;
void Awake()
{
target.targetTrans = gameObject.transform;//当前位置数据传递给TargetTransform
}
}

预制体上的配置:

image-20220606181229495

image-20220606181237509