Files
XCEngine/docs/api/XCEngine/Scripting/ScriptComponent/ScriptComponent.md

5.2 KiB
Raw Blame History

ScriptComponent

命名空间: XCEngine::Scripting

类型: class

头文件: XCEngine/Scripting/ScriptComponent.h

描述: 挂在 GameObject 上的脚本绑定组件,负责保存脚本类标识、组件 UUID 和字段覆盖存储。

概览

ScriptComponent 是脚本系统的数据入口。它本身不执行托管代码,而是保存三类关键信息:

  • 这个组件绑定的是哪个程序集、命名空间和类。
  • 这个脚本组件自己的稳定 UUID。
  • 这份脚本实例的可持久化字段缓存 ScriptFieldStorage

这和 Unity 场景里“脚本槽位”的定位很接近,但当前实现更明确地区分了:

  • 原生场景数据
  • 运行时活体实例

也正因为如此,ScriptComponent 既可以在 Mono 未初始化时参与序列化和 Inspector 编辑,又可以在运行时作为 ScriptEngine 的实例描述对象。

生命周期与绑定语义

  • 构造时会生成一个非零随机 scriptComponentUUID
  • 默认程序集名是 GameScripts
  • 首次从“无脚本类”切到“有脚本类”时,会通知 ScriptEngine::OnScriptComponentEnabled()
  • 已绑定脚本类发生变化时,会通知 ScriptEngine::OnScriptComponentClassChanged(),触发当前运行时实例停机并按新类重建。
  • ClearScriptClass() 会保留当前 assemblyName,只清空命名空间和类名。
  • 启用、禁用、销毁回调会直接转发给 ScriptEngine
  • 序列化 / 反序列化会持久化 UUID、脚本类绑定和字段存储内容。

这里有两个容易误判的实现细节:

  • HasScriptClass() 当前只检查 className 是否非空。
  • SetScriptClass() / ClearScriptClass() 是会触发运行时链路的高层 APISetAssemblyName() / SetNamespaceName() / SetClassName() 只是裸字段写入。

如果你只是改三个字符串,运行时并不会自动知道“类绑定已经变了”。

为什么它不是“托管实例本身”

很多脚本系统文档都会把“脚本组件”和“脚本实例”混着讲,但当前实现刻意没这么做。原因很现实:

  • 场景资产在未运行时也要保存脚本绑定和字段覆盖值。
  • 反序列化或拷贝场景对象时,不应该强依赖托管运行时已经启动。
  • 编辑器大量操作只想读写字段和类名,不想立即创建 Mono 对象。

因此 ScriptComponent 更像“脚本实例描述与持久化容器”,而不是托管对象本体。

字段存储语义

ScriptFieldStorageScriptComponent 的内嵌成员,不单独分配。它承担的是“本地持久化覆盖值”这一层语义。

当前需要特别注意:

  • ClearScriptClass() 不会清空字段存储;只是清空类绑定。
  • SetFieldStorage() 是整体覆盖本地缓存,不会自动把当前活体托管实例同步成完全相同的状态。
  • 运行时字段回写也是经由 ScriptEngine -> IScriptRuntime::SyncManagedFieldsToStorage() 完成,而不是 ScriptComponent 自己主动驱动。

所有权

  • ScriptComponent 本身由 GameObject 所有。
  • ScriptFieldStorage 作为成员对象直接内嵌,不单独分配。

当前实现边界

  • 只有 SetScriptClass() / ClearScriptClass() 会通知 ScriptEngineSetAssemblyName()SetNamespaceName()SetClassName() 是纯字段写入,不会自动触发重绑定。
  • 反序列化使用引擎私有的分号分隔文本格式,不是通用 JSON / YAML。
  • ClearScriptClass() 清空的是命名空间和类名,不会重置程序集名,也不会删除字段缓存。

常用访问器

  • GetAssemblyName() / SetAssemblyName()
  • GetNamespaceName() / SetNamespaceName()
  • GetClassName() / SetClassName()
  • GetScriptComponentUUID()

这些访问器大多是简单内联函数,因此文档重点放在会影响运行时重建、字段语义或序列化行为的方法上。

公开方法

方法 说明
Constructor 创建组件并生成 UUID。
SetScriptClass 设置脚本类绑定。
ClearScriptClass 清空脚本类绑定。
HasScriptClass 判断当前是否已经绑定脚本类。
GetFullClassName 返回带命名空间的完整类名。
GetFieldStorage 访问持久化字段缓存。
OnEnable 通知 ScriptEngine 组件启用。
OnDisable 通知 ScriptEngine 组件禁用。
OnDestroy 通知 ScriptEngine 组件销毁。
Serialize 把组件状态写出到文本流。
Deserialize 从文本流恢复组件状态。

真实行为依据

  • engine/include/XCEngine/Scripting/ScriptComponent.h
  • engine/src/Scripting/ScriptComponent.cpp
  • tests/Scripting/test_script_component.cpp
  • tests/Scripting/test_script_engine.cpp

相关文档