Action Over Time With Base Value

v1.0

This class extends ActionOverTime with restoration capabilities for actions that modify properties and need to return to original values (See examples: MoveAction, RotateAction, ScaleAction).

What to override

ExecuteInternal()

✅ Yes (required)

Implement the over-time behavior

Must begin with yield return base.ExecuteInternal();

SaveBaseValuesForTargets() (or equivalent hook)

⭕ Optional (recommended)

Cache per-target base/original values

Should run on fresh start only (guarded by base flags/keys)

LoadBaseValuesForTarget() (or equivalent)

⭕ Optional

Read cached base/original values

Use target-scoped keys; never execution scope

ComputeEndValueFromBase()(or goal builder)

⭕ Optional (recommended)

Compute end goal using cached base

Compute once at start, then interpolate

Tick(float t) (or per-frame apply)

⭕ Optional (recommended)

Apply interpolation each frame

Use normalized progress t 0→1

OnActionStart()

⭕ Optional

Run-level initialization

Don’t recache base here unless it’s guarded as “fresh only”

OnRestart()

⭕ Optional

Reset per-run progress

Must not overwrite base/original values

OnCleanupExecution()

⭕ Optional

Cleanup transient state

Base/original values typically remain cached

CanExecute()

⭕ Optional

Validation

Return false to skip

Target interface methods (GetTargets etc.)

⭕ Optional

If action operates on targets

Use standard selection helpers

Instead of manually managing contexts and base values, use the built-in helper methods:

CreateContext<TValue>() — Creates typed context with automatic Blackboard key initialization

var ctx = CreateContext(transform, t => t.position, "Position");
// Returns ActionContext<Vector3> with BaseValueKey, HasBaseValueKey, ShouldStopKey pre-initialized

StartAnimationOn<TTarget, TValue>() — Starts animation on a fresh (non-active) target

  • Automatically saves base value if not already saved

  • Sets ShouldStop = false

  • Delegates to your animation coroutine

RestartAnimationOn<TTarget, TValue>() — Restarts animation on active target

  • Sets ShouldStop = true to signal existing animation to stop

  • Waits one frame for graceful shutdown

  • Preserves original base value (doesn't re-save)

  • Resets ShouldStop = false and starts new animation

IsTargetActive<TTarget>() — Checks if target is currently being animated

Component Variants (For Non-Transform Targets)

For actions targeting components like Light, AudioSource, Image, etc., use the component-specific helpers:

  • CreateContextForComponent<TComponent, TValue>() — Same as CreateContextbut for any Component

  • StartAnimationOnComponent<TComponent, TValue>() — Same as StartAnimationOn for components

  • RestartAnimationOnComponent<TComponent, TValue>() — Same as RestartAnimationOn for components

Example

Critical Rules

DO use target-scoped keys for base values: CreateTargetKey<T>(targetId, "BasePosition")DO check HasBase flag before saving to preserve original base across loops ✅ DO use StartAnimationOn / RestartAnimationOn helpers for ActionsDO check ctx.ShouldStopKey each frame in your animation loop for graceful restarts

DON'T use execution-scoped keys for base values (they’re execution-namespaced and effectively disposable, but not automatically purged—don’t use them for long-lived base values). ❌ DON'T unconditionally save base values (overwrites original with animated values) ❌ DON'T clear base values in OnCleanupExecution() (they must persist across executions)

If you generate many unique execution keys, consider reusing keys or explicitly removing them when appropriate.

Last updated