Moving from AG1
AG2 is a different graph system, not a new skin for the old editor. Reuse your animation sources and the intent of your old graph, but rebuild its behavior using the new resources and nodes.
Start with one character and one working behavior. Keep the old setup available for comparison while you migrate.
What changes?
| In AG1 | In AG2 |
|---|---|
.vanmgrph graph |
.ag graph |
| Model sequence name used by an animation node | Separate .anim clip bound to a .skel |
| Model-authored weightlists | Bone masks authored on the .skel |
Sandbox.AnimationGraph / renderer AnimationGraph |
Sandbox.Animation.Graph / renderer Animation.Graph |
Renderer Set(...) or Parameters.Set(...) |
Animation.Parameters.Set(...) |
SceneModel.SetAnimParameter(...) |
SceneModel.Animation.Parameters.Set(...) |
| Auto-reset action/gesture parameters | Explicitly clear action bools after an animation update |
| Direct Playback node and API | An authored action state, or an External Graph slot for runtime-selected behavior |
Assigning an .ag does not redirect old API calls to it. Legacy setters still target AG1.
Migrate the assets first
Create or reuse one skeleton, then import a small set of clips against it. Start with idle and movement before adding actions, aiming, or IK.
Preserve the old source settings that affect the result: scale, take, trim range, duration, and additive subtraction source/frame. Use skeletons and clips to prepare the assets.
Build a one-clip graph and check it on the actual renderer before recreating the rest of the character.
Update the parameter calls
For a graph declaring a Float named speed, change:
Renderer.Set( "speed", speed );
to:
Renderer.Animation.Parameters.Set( "speed", speed );
Update reads as well as writes. The old renderer getters and SceneModel.GetFloat/GetBool do not read AG2 parameters.
Do not assume every legacy integer parameter should remain an integer. AG2 uses ID parameters for named choices. For example, a graph with an ID named holdtype can receive:
Renderer.Animation.Parameters.Set( "holdtype", "rifle" );
Audit the components writing parameters too. CitizenAnimationHelper still uses the legacy API. The standard PlayerController has an AG2 path, but a custom driver needs updating explicitly.
Rebuild behavior, not the old wiring
| Behavior | A simple AG2 approach |
|---|---|
| Idle/walk/run from speed | Blend 1D |
| Jump, land, or play an action | States and transitions |
| Reload or wave while moving | State Machine Layer with a bone mask |
| Smooth a value used by several branches | A Spring inside a virtual parameter |
| Choose one idle variation on entry | Selector |
| Change the current animation when a parameter changes | State Machine, not an entry-only Selector |
Leave independent actions unsynchronized with locomotion. Synchronizing a reload layer to the walk cycle changes its timing; it is not a general "make blending smoother" switch.
Use Overlay for ordinary poses and Additive for correctly authored additive clips. An old additive setup may depend on a particular subtraction frame, not simply on a layer checkbox.
Replace Direct Playback deliberately
For a known action such as a wave, use a state and a request parameter. This keeps its blending and interruption rules visible in the graph.
For behavior chosen at runtime, add External Graph with a unique slot name such as action. Connect an idle or movement pose to Fallback, and put its output where the selected animation should appear.
Locomotion ---> External Graph (action).Fallback
External Graph.Result ---> Graph Output
Create a separate .ag containing your action clip. Both graphs must use the same .skel resource. For an available, empty slot:
Renderer.Animation.ExternalGraphs.Connect(
"action",
Sandbox.Animation.Graph.Load( "graphs/wave.ag" )
);
When the action is finished, return to the fallback:
Renderer.Animation.ExternalGraphs.Disconnect( "action" );
These are start/stop operations, not per-frame calls. Connecting to an occupied slot throws; disconnect it before replacing or restarting the action.
The switch is immediate, not an automatic crossfade. Author blending with states or layers. A non-looping clip holds its last pose until you disconnect it; completion does not empty the slot for you.
External graphs do not inherit matching parent control-parameter values. Keep this simple child graph self-contained. Connections are runtime-only and can be lost when a model or animation resource reload recreates the controller.
External Pose is not Direct Playback. It is for externally computed poses, not selecting an animation clip.
You do not need to author a separate .ag for every runtime-selected clip. The external-graph guide includes a complete clip player that builds a child graph in C#, checks evaluated playback completion, and disconnects it. The runtime state-machine guide also shows an explicit one-shot bool driver.
Check the differences that are easy to miss
Check movement while stationary, accelerating, stopping, and changing direction. Check action entry, completion, repeated requests, and interruptions. Check both the graph preview and the running character.
IK targets also need migrating: legacy SetIk calls do not drive AG2. Use the new target parameters and the coordinate space expected by their consuming nodes. A world-space position, a model-space transform, and a direction are not interchangeable.
Do not assume complete feature parity just because a parameter has the same name. In particular, the legacy procedural hit-reaction inputs (hit, hit_bone, hit_offset, hit_direction, and hit_strength) do not currently provide an equivalent AG2 effect.
Migrate one behavior at a time, with a graph small enough to understand before adding the next layer.