unity ScriptableObject案例学习

案例来源

案例是老师在教学时提供的,应该是官方的案例。项目名为Game Architecture with Scriptable Objects。

粒子效果播放

播放效果

GIF 2024-6-25 10-57-50

这个粒子效果的播放是SO(ScriptableObject)管理事件播放的案例。

层次结构

image-20240625105957783

Button

image-20240625110033778

  • Button单击事件调取的是GameEvent脚本生成的OnButtonPressed(ScriptableObject)。

EventListener

image-20240625110112367

脚本

GameEventListener

image-20240625110432728

GameEvent

image-20240625110232218

分析

GameEventListener和GameEvent两者都相互引用,直接看脚本是有些困难的,要结合他场景的用法来。

  • GameEvent可以认为是事件的“播放器”。其继承了ScriptableObject,不用传统的Mono实现,而是直接生成SO。

  • GameEvent中只有一个GameEventListener的List参数,可以认为,这个List是GameEvent的“播放列表”。

  • GameEventListener可以认为是事件的监听器,说白了就是在某个条件下,要做什么都添加到这里面。这里的层次结构设计也对应了这个想法:

    image-20240625111244546

    这个EventListener挂载了GameEventListener,监听其子物体的播放事件。

    比如这个粒子系统,要播放粒子效果,就直接将粒子效果的播放函数拖入即可(粒子系统提供的调用函数)。

    image-20240625111039690

  • GameEventListener里面还有一个参数是GameEvent类型。OnButtonPressed是GameEvent类型(SO)。

  • 可以认为,GameEventListener里的GameEvent参数是用来播放的播放器。GameEventListener生成使用时,只需要向播放器注册(增加)自己的播放事件。在失活/销毁时,只需要让播放器取消自己的播放事件。而这个OnButtonPressed就是GameEventListener选择的“播放器”。

总结

运行时,GameEventListener下的子物体的函数全部记录在GameEventListener中。GameEventListener再将需要执行的事件注册到OnButtonPressed的播放列表中。场景中的Button调用OnButtonPressed中的播放函数,播放事件。

正方体(物体)管理

这个案例中,也有用到前面的GameEvent和GameEventListener,这里就不多加解释了。

播放效果

GIF 2024-6-25 12-19-36

效果有两个:随机失活一个正方体、失活所有正方体。

层次结构

image-20240625122347858

这里的层次结构很简单,五个正方体是直接放在了场景里的。

脚本

RuntimeSet

image-20240625122436528

  • 抽象类RuntimeSet其实是给所有XX物体的一个“模板”,List参数就是管理所有物体的物体列表。

ThingRuntimeSet

image-20240625122506294

  • ThingRuntimeSet就是正方体管理器,其可以生成SO。
  • 调用这个生成的SO,就可以对其注册在列表中的正方体进行处理。

Thing

image-20240625123145143

  • Thing挂载在每个正方体上。
  • ThingRuntimeSet类型的参数就是正方体们的管理器。
  • 每一个正方体都可以在正方体管理器里注册和移除自己。

ThingDisabler

image-20240625123535421

  • ThingDisabler是在MonoBehaviour主程序运行的脚本。
  • 通过绑定的正方体管理器,就可以对注册在列表中的正方体进行一些操作。

剪刀石头布

播放效果

GIF 2024-6-25 13-40-10

运行前都是一样的元素,运行后分配元素。

石头剪刀布的规则就不多说。败的元素消失。

层次结构

场景里放了六个一样的物体,每个物体中都有挂载Elemental脚本。这里就懒得放了。

脚本

AttackElement

image-20240625134809681

其SO:

GIF 2024-6-25 13-53-48

  • AttackElement表示元素,不同元素会有与其相对应的一些其他元素。比如这里的List变量DefeatedElements,就是用来记录与其比较会失败/输的元素。案例提供的是石头剪刀布,那么就互相只有一个。用List主要是方便后续拓展。

Elemental

image-20240625134803896

  • AttackElement生成SO,记录了静态的元素之间的关系信息。Elemental脚本在Mono主循环中,实现动态的元素直接关系的变化处理。

总结

  • Scriptable Object其实最主要是要抓住它“静态数据”的特点。
  • 个人理解中,“静态”和“动态”是相对于Mono主循环而言的。动态数据是指其能够自己在主循环中变化的,而静态则相反。
  • 所有的案例研究下来就会发现,Scriptable Object最主要的优点就是它的“静态”和省内存。除此之外,Scriptable Object的脚本也是独立开其他动态脚本的,更加适合团队协作的样子。