主题
Entity 与 Actor 的分工
本文针对 SCE Unit/技能体系。需要选整个游戏的实现路线时,先看游戏架构路线:GameGraph 场景图和 Canvas 也可以承担游戏功能。
各自提供什么
| 对象 | 用途 | 创建与同步边界 |
|---|---|---|
Entity / Unit | 单位位置、属性、技能、战斗等运行时状态 | 游戏单位由服务端创建,框架按同步和可见性规则向客户端复制 |
Actor | 模型、粒子、音效、光束、文字等表现 | 实际表现由客户端创建和渲染;通过 ActorScope 管理生命周期与可见性 |
ActorScopePersist | 管理依附实体等宿主的持久表现 | 服务端创建并同步 Scope,客户端据此创建表现 |
ActorScopeTransient | 一次性表现 | 客户端播放;服务端可请求可见客户端播放 |
“持久 Scope”描述的是局内生命周期,不代表保存到 CloudData。同步到客户端的属性范围、可见性和频率也不能概括成“所有状态自动同步”。
常用接线
- 单位主体模型、武器或状态表现:先检查单位、技能、Buff 等定义中的
Model、ActorArray与 Scope 配置,复用框架的创建与销毁流程。 - 客户端本地预览:在客户端使用 Actor 或 GameGraph,并管理退出预览时的清理。
- 服务端触发一次爆炸、提示音等表现:通过瞬态 Scope 的播放流程请求客户端显示,见 Actor 系统。
- 服务端管理固定场景标记或单位持续光环:通过持久 Scope 的
SetActorSlot(...)声明,见服务端创建表现。 - 直接 GameGraph 的多人对象:使用服务端创建的复制场景图/节点并
Publish(player),见架构路线。
这些选择取决于需要的能力。单纯“有逻辑”或“需要同步”不足以推导出必须使用 Entity;Actor 也可以有客户端表现逻辑,但不因此获得服务端权威的伤害、货币或存档状态。
容易写错的地方
在服务端直接构造 Actor
csharp
#if SERVER
// 错误:ActorModel 的服务端构造路径没有实现实际 Actor 创建。
var actor = new ActorModel(actorLink, false, scope);
#endif部分 Actor 类型在服务端声明中仍可见,但 Actor 的服务端构造实现会抛出 NotImplementedException。通过编译不能证明这条路径可用。
应根据用途配置宿主的 ActorArray,或通过 Scope 的 PlayTransient(...) / SetActorSlot(...) 发起表现,见服务端创建表现。客户端本地直接创建的形式是:
csharp
#if CLIENT
// actorLink 为已有 Actor 定义,scope 为本次表现的有效 Scope。
Actor? actor = actorLink.Data?.CreateActor(scope);
#endif把显示状态当成权威状态
隐藏或销毁 Actor 不等同于击杀单位;移动表现也不等同于改变服务端单位位置。战斗和状态变化通过单位/效果等对应系统执行,表现随结果更新。
反过来,单位和 Entity 也提供动画桥接能力,不能把“所有动画调用都必须写在 Actor 类里”当成框架要求。见 GameCore 与 GameGraph 桥接。
重复创建或未清理表现
框架已通过 Model / ActorArray 创建表现时,再手工创建一套可能产生重叠模型、重复音效。附着效果先检查 Scope、挂点和跟随配置;表现退出时检查宿主级联销毁与瞬态播放结束流程。
没有附着到正确 Scope 的表现,不能仅凭位置与单位相同就认为它会随单位销毁。详细生命周期与播放方式见 Actor 系统。