主题
Actor 系统
预警、粒子大小或首刀表现异常时,先核对挂载、资源依赖、scope 和缩放组成,见表现诊断。AutoScale 还可能使用半径和体积;不应按“大模型”统一关闭,也不应将隐藏多次预热作为所有预警的必需步骤。
Actor 系统管理游戏中所有视觉表现元素——3D 模型、粒子特效、光束、音效、材质覆盖、高光、文字等。Actor 由客户端创建和渲染,通过 ActorScope 管理生命周期和可见性同步。
需要取得具体表现的 Node、模型、动画、粒子或声音组件时,阅读GameCore 与 GameGraph 桥接。客户端表现节点与 ActorScope 的 replicated 绑定节点各有用途;Unit 与 Entity 也能通过共享接口直接访问动画能力。
核心类型
| 类型 | 说明 |
|---|---|
GameDataActor | Actor 数编基类(抽象),定义挂接、缩放、旋转等通用配置 |
Actor | Actor 运行时基类(抽象),所有视觉元素的公共基类 |
ActorScope | 管理一组 Actor 的生命周期(抽象) |
ActorScopePersist | 持久 Scope,与实体绑定,服务端创建并同步 |
ActorScopeTransient | 瞬态 Scope,客户端播放,服务端可请求可见客户端创建一次性表现 |
IActorScopeContext | Scope 上下文接口,提供目标、位置、缩放等参数 |
IActorScopeOwner | Scope 所有者接口,管理 Scope 的创建和子 Actor |
类型继承关系
GameDataActor (abstract)
├── GameDataActorModel → ActorModel 3D 模型
├── GameDataActorAdditionModel → ActorAdditionModel 附加模型
├── GameDataActorParticle → ActorParticle 粒子特效
├── GameDataActorBeam → ActorBeam 光束
├── GameDataActorGrid → ActorGrid 网格覆盖
├── GameDataActorSegmented → ActorSegmented 分段效果(抽象)
├── GameDataActorSound → ActorSound 音效
├── GameDataActorText → ActorText 世界文字
├── GameDataActorSite → ActorSite 位置标记(不可见)
└── GameDataActorHostModifier 宿主修改器基类
├── GameDataActorHighlight → ActorHighlight 高光/选中效果
├── GameDataActorMaterial → ActorMaterial 材质覆盖
└── GameDataActorAction → ActorAction 动作效果
ActorScope (abstract)
├── ActorScopePersist 持久 Scope(双端)
└── ActorScopeTransient 瞬态 Scope(客户端播放,服务端可请求创建)GameDataActor 通用配置
所有 Actor 数编共享的基类属性:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
IsTransient | bool | false | 是否为瞬态(播放完自动销毁) |
Socket | UTF8String? | null | 挂接点名称 |
Offset | Vector3? | null | 位置偏移 |
Rotation | Vector3? | null | 旋转偏移 |
InheritRotation | bool | true | 继承父级旋转 |
InheritScale | bool | false | 继承父级缩放 |
AutoScale | bool | true | 从 Scope 自动缩放 |
Scale | float? | null | 均匀缩放 |
ScaleVector | Vector3? | null | 非均匀缩放 |
AttachForwardOnce | bool | false | 仅使用父节点和挂点初始化一次位置与旋转,随后立即解除挂接并保持世界变换 |
MiniMapIcon | MiniMapIcon? | null | 小地图图标配置 |
ParentRemovalProcedure | ParentRemovalProcedure | — | 父级移除时的行为 |
创建 Actor(客户端):
csharp
#if CLIENT
Actor? actor = myActorLink.Data?.CreateActor(scope);
#endifActor 类型详解
ActorModel — 3D 模型
渲染 3D 模型,支持动画播放、骨骼链、挂接点。
数编配置(GameDataActorModel):
| 属性 | 类型 | 说明 |
|---|---|---|
Model | IGameLink<GameDataModel>? | 模型资源 |
运行时实现 IActorAnimationPlayable 接口(仅客户端),提供:
| 方法 | 说明 |
|---|---|
PlayAnimation(Animation, AnimationPlayParam?) | 播放动画 |
PlayAnimationSequence(IGameLink<GameDataAnimationSequence>, float) | 播放动画序列 |
PlayAnimationBracket(IGameLink<GameDataAnimationBracket>) | 播放括号动画 |
StopAnimationOfLayer(AnimationLogicLayer) | 停止指定层的动画 |
SetBirthStandDeathAnimation(UTF8String, UTF8String, UTF8String) | 设置生命周期动画 |
SetAnimationMapping(UTF8String, UTF8String) | 设置动画别名映射 |
CreateBoneChain(IEnumerable<ModelBoneWeight>) | 创建骨骼链(分体旋转) |
SetUpperBodyRootBone(UTF8String) | 设置上下半身动画分割 |
GetSocketPosition(UTF8String) | 获取挂接点世界坐标 |
ActorAdditionModel — 附加模型
在已有宿主上自动显示额外模型,例如手持物、背饰、披风、盾牌、头饰或整套外观覆盖。它使用 GameDataActorAdditionModel 配置,并可放入单位、物品、Buff、技能或效果的 ActorArray。
数编配置:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Model | IGameLink<GameDataModel>? | null | 要附加显示的模型资源 |
CullHostMesh | bool | false | 附加模型覆盖宿主主体时,可开启以减少宿主与附加模型重叠造成的穿插或重叠渲染 |
ActorAdditionModel 的对齐方式与普通 Actor 不同:它不通过 Socket、Offset、Rotation、Scale 等字段定位,资源应按宿主骨架制作。详细配方见 自动挂载模型表现。
ActorParticle — 粒子特效
播放粒子特效,实现 IActorPlayable。
数编配置(GameDataActorParticle):
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Particle | IGameLink<GameDataParticle>? | null | 粒子资源 |
AutoPlay | bool | true | 自动播放 |
Fade | bool | false | 结束时淡出 |
PlaySpeed | float? | null | 播放速率 |
CreationFilterLevel | int | 1 | 最低画质等级 |
运行时方法:
| 方法 | 说明 |
|---|---|
Play() | 开始播放 |
Stop(bool fade) | 停止,可选淡出 |
SetPlaySpeed(float) | 设置播放速率 |
Fade=true 时,停止会先停止发射并让已经发射的粒子按自身寿命完成;需要立即清理时使用 Stop(false) 或 Destroy(forceNoFade: true)。表现节点默认值由项目模板决定。
ActorSound — 音效
GameDataActorSound 没有 Actor 级 Fade 布尔字段。音效资源 GameDataSound.FadeTime 控制淡入淡出时长,普通音效模板通常使用 0.5 秒,音乐模板通常使用 2 秒。
ActorBeam — 光束
从一点延伸到另一点的效果(激光、闪电等)。运行时 ActorBeam 实现 IActorPlayable 和 IActorDualEndPoints,数编配置 GameDataActorBeam 实现 IGameDataActorDualEndPoints。
ActorBeam 与 GameGraph ParticleSystem 中的 Beam 发射器共享底层光束粒子能力。它通过 Beam 引用 GameDataParticle 资源,并由框架管理两端单位/挂点跟随、播放和生命周期。绑定后,框架每帧读取挂点位置并更新粒子端点;任一绑定端点失效时隐藏光束,端点重新有效时恢复播放。
如果需要纯代码构造光束,可使用 ParticleSystem.CreateRuntime()、AddBeamEmitter(...) 和 ParticleEmitterBeamBuilder。Builder 负责资源配置,Points(...) 只保存坐标,不绑定 Node;挂载到节点后,应通过运行时 ParticleEmitter.SetSourcePoint/SetEndPoint 更新端点,由项目代码管理跟随与清理。ActorBeam 本身不通过 C# Builder 实现。选型和跟随示例见 GameGraph 粒子与音频系统。
数编配置(GameDataActorBeam):
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Beam | IGameLink<GameDataParticle>? | null | 光束粒子资源 |
LaunchSocket | UTF8String? | null | 发射端挂接点 |
ImpactSocket | UTF8String? | null | 命中端挂接点 |
AutoPlay | bool | true | 自动播放 |
Fade | bool | false | 结束时淡出 |
Duration | TimeSpan | 1 秒 | 持续时间 |
ActorGrid — 网格覆盖
在地面显示网格状效果,每个格子可独立设置状态。
数编配置(GameDataActorGrid):
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
GridSize | float | 128 | 格子大小(世界单位) |
StateModels | List<IGameLink<GameDataModel>?> | [] | 各状态对应的模型(索引=状态值) |
运行时属性(仅客户端):
| 属性 | 类型 | 说明 |
|---|---|---|
Axis | GridAxis | X/Y 轴向量,定义方向和格子大小 |
Bounds | GridBounds | 覆盖范围,设置正值维度使网格可见 |
GridStates | GridState | 格子状态管理器,支持 [x, y] 索引器 |
StickToGround | bool | 是否贴合地形(默认 true) |
> 服务端的 ActorGrid 是轻量壳——仅用于消息传输,不含实际渲染逻辑。
ActorSegmented — 分段效果
从起点到终点的分段效果(闪电链、弹道轨迹、范围指示器),抽象基类。
运行时属性(仅客户端):
| 属性 | 类型 | 说明 |
|---|---|---|
Length | float? | 覆盖长度,null 表示自动计算 |
ActualLength | float | 计算后的实际长度 |
LaunchActor | Actor? | 起点效果 |
ImpactActor | Actor? | 终点效果 |
CenterActors | IReadOnlyList<Actor> | 中间段的 Actor 列表 |
调用 UpdateForward() 计算朝向和长度。
ActorSound — 音效
播放 3D/2D 音效,实现 IActorPlayable。
数编配置(GameDataActorSound):
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Sound | List<WeightedLink<IGameLink<GameDataSound>?>> | — | 带权重的音效列表 |
AutoPlay | bool | true | 自动播放 |
LoopCount | uint? | null | 循环次数,null 为无限 |
Is2D | bool | false | 2D 音频(无空间衰减) |
RolloffFactor | float | 4 | 3D 距离衰减系数 |
CutoffDistance | float | 500 | 完全静音的距离 |
运行时方法:Play(), Stop(bool), SetPlaySpeed(float), SetSoundVolume(float), IsMuted
ActorText — 世界文字
在 3D 空间渲染文字。
数编配置(GameDataActorText):
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Font | Font | firamono.ttf | 字体 |
FontSize | float | 50 | 字号 |
Text | string | "你好,星火" | 默认文字 |
Color | Color | Black | 颜色 |
WrapWidth | float? | null | 自动换行宽度 |
HorizontalAlignment | TextHorizontalAlignment | Center | 水平对齐 |
VerticalAlignment | TextVerticalAlignment | Center | 垂直对齐 |
运行时方法:SetText(string) / SetText(UTF8String)
ActorSite — 位置标记
不可见的位置标记,用作其他 Actor 的挂接/锚定点。
ActorHighlight — 高光效果
附加到宿主 Actor 上的颜色动画效果(选中、高亮),继承自 ActorHostModifier。
数编配置(GameDataActorHighlight):
| 属性 | 类型 | 说明 |
|---|---|---|
From | ArithmeticMixer<HdrColor>? | 起始颜色(null 使用宿主当前色) |
To | ArithmeticMixer<HdrColor> | 目标颜色 |
Duration | TimeSpan | 动画时长 |
AutoReverse | bool | 到达目标后反向 |
RepeatBehavior | RepeatBehavior | 重复次数 |
Weight | double | 与宿主颜色的混合权重 |
ActorMaterial — 材质覆盖
覆盖宿主 Actor 的材质,支持属性动画。继承自 ActorHostModifier,实现 IActorPlayable。
数编配置(GameDataActorMaterial):
| 属性 | 类型 | 说明 |
|---|---|---|
Material | Material | 材质资源 |
Priority | MaterialPriority | 覆盖优先级 |
AutoPlay | bool | 自动播放属性动画 |
PropertyAnimations | List<MaterialPropertyAnimation>? | 材质属性动画列表 |
IntroDuration / OutroDuration | TimeSpan | 入场/退场动画时长 |
ActorAction — 动作效果
附加到宿主 Actor 的动作效果,支持发射端和命中端挂接点。继承自 ActorHostModifier。
数编配置(GameDataActorAction):
| 属性 | 类型 | 说明 |
|---|---|---|
LaunchSocket | UTF8String? | 宿主上的发射挂接点 |
ImpactSocket | UTF8String? | 宿主上的命中挂接点 |
ActorScope 生命周期
ActorScope 管理一组 Actor 的创建、销毁和可见性。服务端现在可以基于 ActorScope 发起客户端表现创建,但表现仍由客户端实际渲染;同步边界始终是“表现从属于某个作用域”,而不是全局广播一段任意表现操作。
能力总览
| 能力 | 服务端入口 | 客户端行为 | 生命周期 | 典型用途 |
|---|---|---|---|---|
| 一次性表现 | IActorScope.PlayTransient(...) | 当前可见客户端创建一个 transient actor 并播放 | actor 自身 transient 配置,或调用时指定 Duration | 命中火花、爆炸、提示圈、短音效 |
| 持久作用域 | ActorScopePersist | 客户端创建一个可长期存在的 scope,并按作用域可见性创建/移除表现 | scope Kill() / Destroy() 或宿主生命周期 | 单位模型、持续光环、任务标记 |
| 持久子表现 slot | ActorScopePersist.SetActorSlot(...) | 客户端收到 slot 声明后本地创建 actor,并附着到 scope 自身的 AttachSite | slot 被清除或 scope 销毁 | 持续粒子、光环、可见性受控的服务端声明表现 |
| 高级 replicated Node 表现 | ActorScopePersist.EnsureNodeBinding(...) + binding.SetActorSlot(...) | 客户端收到绑定 node 和 slot 声明后本地创建 actor,并附着到指定 replicated node | slot 被清除、binding 被解绑或 scope 销毁 | hitbox、raycast target、GameGraph 组件、Node SyncVar 元数据 |
ActorScopePersist(持久 Scope)
- 与实体(Entity/Unit)或显式作用域上下文绑定,服务端创建并同步到客户端。
- 通过作用域上下文和底层可见性机制控制哪些客户端能看到该 scope。
- 拥有
Position(ScenePoint)和Scene,可作为服务端可同步表现的归属边界。 - 调用
Kill()/Destroy()会销毁该作用域及关联表现。 - 适合“服务端声明、客户端持续保持”的表现,例如单位模型、持续光环、可交互物标记、服务端创建的独立持久表现点。
ActorScopeTransient(瞬态 Scope)
- 客户端负责实际创建和播放,火并忘(fire-and-forget)。
- 服务端可通过已有
IActorScope.PlayTransient(...)请求可见客户端播放一次性表现。 - 构造时仍支持从
IActorScopeContext.Cache.ActorArray创建 Actor;PlayTransient额外允许服务端指定一个本次播放的 actor。 - 自动创建位置锚点(
StaticSite)和源锚点(SourceSite)。 - 播放完毕后自动销毁。
- 不做 late join replay。瞬时表现只面向当前可见客户端发送,后加入或当时不可见的客户端不会补播。
瞬态 vs 持久
| 特性 | 瞬态(Transient) | 持久(Persist / Slot) |
|---|---|---|
| 创建语义 | 服务端发起一次播放请求,客户端本地创建 | 服务端声明一个长期存在的作用域或 slot,客户端按声明保持 |
| 生命周期 | 自动销毁,不 replay | 持续存在,客户端 late join 或重新可见时可按当前状态创建 |
| 可见性 | 只发给当时能看到作用域的客户端 | 跟随 scope / node 当前可见性,重新可见会重建当前状态 |
| 典型用途 | 一次性特效、短音效、打击反馈 | 单位模型、持续光环、服务端创建的持久场景表现 |
服务端创建表现
从服务端创建一次性或持久客户端表现的完整说明见 服务端创建表现。该文档是这项能力的主入口,包含:
PlayTransient(...)一次性表现,明确不做 late join replay。ActorScopePersist + scope.SetActorSlot(...)普通持久表现,重新可见后按当前声明恢复。ActorScopeNodeBinding高级用法:需要真实 replicated Node 时再使用。- 固定场景点、已有单位、双端 GameData / ScopeData、slot version 和常见错误。
本页只保留 Actor 与 ActorScope 的基础概念。生成或评审“服务端创建表现”代码时,不要只看本页,应先看上面的专题文档。
IActorScopeOwner
实现此接口的对象(如 Unit、Ability)可以拥有和管理 ActorScope:
csharp
// 服务端:初始化 ActorScope
#if SERVER
var scope = (unit as IActorScopeOwner).InitializeActorScope();
#endif
// 客户端:创建默认子 Actor
#if CLIENT
(unit as IActorScopeOwner).CreateDefaultChildren();
#endif使用示例
在效果树中创建 Actor
Actor 通常通过数编配置在效果树中创建,绑定到实体的 Scope:
csharp
// 在 GameDataActorScope 中配置 ActorArray
// 当效果执行时,自动创建配置的 Actor手动创建 Actor
csharp
#if CLIENT
// 从数编创建
var model = myActorModelLink.Data?.CreateActor(scope);
// 操作粒子
if (actor is ActorParticle particle)
{
particle.Play();
particle.SetPlaySpeed(2.0f);
particle.Stop(fade: true);
}
// 设置网格状态
if (actor is ActorGrid grid)
{
grid.Bounds = new GridBounds(0, 0, 10, 10);
grid.GridStates[3, 5] = new GridState(1);
}
// 设置文字
if (actor is ActorText text)
{
text.SetText("Hello World");
}
// 播放音效
if (actor is ActorSound sound)
{
sound.Play();
sound.SetSoundVolume(0.5f);
}
#endif无 Model 仅 ActorArray 的单位
GameDataUnit 不设 Model 属性、仅配置 ActorArray 的单位同样有效。 框架会为单位创建隐含的场景 Node,ActorArray 中的 Actor(如粒子特效)会自动附着在该 Node 上。 适用于经验宝石、掉落物、纯视觉标记等不需要 3D 模型的场景实体。
csharp
// 定义粒子特效
var gemParticle = new GameLink<GameDataParticle, GameDataParticle>("ExpGem"u8);
_ = new GameDataParticle(gemParticle) { Asset = "effect/eff_arpg/arpg_tongyong/diaoluo_1/particle.effect"u8 };
// 定义粒子 Actor
var gemActor = new GameLink<GameDataActor, GameDataActorParticle>("ExpGemActor"u8);
_ = new GameDataActorParticle(gemActor) { AutoPlay = true, Particle = gemParticle };
// 定义单位:无 Model,仅 ActorArray
_ = new GameDataUnit(gemUnit)
{
Name = "经验宝石",
Filter = [UnitFilter.Item],
ActorArray = [gemActor], // 粒子特效附着在单位隐含 Node 上
};销毁 Actor
csharp
#if CLIENT
actor.Destroy();
#endif