粒子参数驱动:可编辑时间线不应直接变成永久Tick

自动关联目录:粒子参数驱动:可编辑时间线不应直接变成永久Tick

核心判断:创作层的 Setter、关键帧和随机区间适合表达意图,不适合原样成为每个对象的运行时执行图。先编译通道,再按活跃集合调度,才能同时守住正确性和规模成本。

一、业务问题:让创作者驱动特效参数,又不能把成本乘到每个实例

特效需要随时间改变颜色、向量和浮点参数,也需要一定随机性。把关键帧和参数绑定暴露给脚本,能快速支持可编辑效果;但场景中大量特效对象存在时,即使不播放,组件 Tick、UObject 遍历和参数写入仍可能成为固定成本。

二、实际实现:功能路径直接,运行时契约不完整

实际代码有两类 ActorComponent:一类逐帧在区间内随机并调用粒子组件的参数接口;另一类累加时间、换算到 [0,1),逐组插值关键帧并写入参数。两者都禁止 DS Tick,这是正确的角色裁剪;关键帧游标会从上次位置继续搜索,循环回绕时重置,也避免了每帧从头扫描。

但实现仍有五个明确边界:

  1. 组件永久允许 Tick,只在 Tick 内判断数组是否为空;
  2. Setter、时间组和时间线用无 Outer 的 NewObject 创建,虽然数组属性能保活,运行时子对象的归属仍不清晰;
  3. 目标粒子组件是普通裸指针,IsValid 只判断非空,GC 或组件销毁不会自动置空;
  4. 关键帧按输入顺序追加,没有排序、范围校验和同时间点冲突规则,插值算法却假设时间单调;
  5. 随机 Setter 默认每帧重采样,语义是高频噪声,而不是常见的“每次激活取一个随机值”。

三、目标方案:Authoring Graph 编译为 Param Program

struct FCompiledChannel {
    FName Parameter;
    EValueType Type;
    ESamplePolicy Policy; // OnActivate / FixedRate / EveryFrame
    TArray<FKey> SortedKeys;
};

struct FEffectBinding {
    uint32 Generation;
    TWeakObjectPtr<UParticleSystemComponent> Target;
    TSharedPtr<const FParamProgram> Program;
    double StartTime;
};

CompileResult Compile(const FAuthoringGraph& Source) {
    ValidateDurationAndRanges(Source);
    auto Keys = StableSortAndResolveDuplicateTimes(Source.Keys);
    return BuildImmutableProgram(Keys, Source.SamplePolicy);
}

void TickActive(FEffectBinding& B, double Now) {
    if (!B.Target.IsValid() || !IsCurrent(B.Generation)) return Remove(B);
    EvaluateAndApply(*B.Program, Now - B.StartTime, *B.Target);
}

若仍保留 UObject 子节点,应以组件为 Outer,并在 EndPlay、回池和重新绑定时显式 Stop、清空目标和提升 BindingGeneration。组件默认关闭 Tick,在 Start 时注册到集中调度器,在 Stop 时注销;不可见特效可按重要度降采样。只有明确选择 EveryFrame 的通道才逐帧写值,其他通道按激活或固定频率采样。

四、为什么不是一律改用引擎 Curve

FRichCurve 能解决有序键、插值和编辑器支持,但不能替代绑定生命周期、随机采样策略、活跃调度和参数批量提交。实例很少时,每组件 Tick 也更简单;优化触发条件应是实际组件数、活跃比例和参数写入成本,而不是抽象偏好。

验证应覆盖乱序键、重复时间、零时长、空参数名、目标组件销毁、停播与回池、相同种子重放,以及大量已创建但未激活实例。指标至少拆出 RegisteredDrivers、ActiveDrivers、EvaluatedChannels、ParameterWrites、InvalidBindingDrops。

五、反思

现有实现把“创作者能配置”快速打通了,也正确地排除了 DS;下一步不应继续给 Setter 增加分支,而应建立编辑表达与运行执行之间的编译边界。可编辑性需要对象图,规模化运行需要紧凑程序和活跃工作集。