Skip to main content

Animation

The framework plays montages when you have them and interpolates when you do not. Both paths reach the same states through the same events, so you can start with the second and move to the first without changing any code.

The procedural transition

With no animation set, or no montage matching the transition, the rider slides from the entry point to the seat: eased with a smoothstep, arced so the path does not go through the door frame, and computed in the seat's own frame — so the whole thing stays correct on a vehicle that is moving.

That last part is why the rider attaches at the start of a procedural get-in rather than at the end. The slide is a relative offset shrinking to zero; the car's motion is carried by the attachment, not fought by it.

SettingDefault
Duration0.55 s
Arc Height25 cmZero is a straight line through the door frame.
Easing CurvenoneA 0..1 curve. Without one, a smoothstep.
Interpolate RotationtrueTurn to face the seat over the same window.

This is not a consolation prize. For a prototype, a debug build, or a mount nobody has authored animations for, it reads as intentional — and it is what makes the framework testable with no content at all.

Animation sets

Create one — Content Browser → Miscellaneous → Data Asset → ED Mount Animation Set — and point your rider component at it.

Each entry matches on:

FieldEmpty means
Phase Tagnever matchesMount.Phase.Enter, .Exit, .Shuffle, .Seated. Required.
Entry Tagsany sideMount.Entry.Left and friends.
Role Tagsany roleMount.Role.Driver, or your own.
Context Queryalways passesA query against the rider's tags, the mount's, and the request's.

and carries:

FieldDefault
AnimationA montage, or a plain sequence. Soft, and preloaded when the mount spawns.
Start SectionnoneMontages only.
Play Rate1.0
Use Motion WarpingtrueOff for a montage authored in place.
Attach Fraction0.55When the rider attaches — only when the montage has no attach notify.
Priority0Breaks ties between equally specific entries.

A montage or a sequence

Either. A sequence is played into the slot as a dynamic montage, which is the same thing without the asset — so reach for a real montage when you want its sections or its notifies, and a sequence when you have neither. A get-in usually wants a montage. A seated pose never does.

How one gets chosen

Every entry whose conditions pass is scored on how specific it is: +8 for naming a side, +4 for a role, +2 for a context query. Highest wins; ties go to Priority, then to declaration order.

So fill the array in with one catch-all per phase first, then override what deserves it:

0  Mount.Phase.Enter                                AM_GetIn_Generic
1 Mount.Phase.Enter + Mount.Entry.Left AM_GetIn_LeftDoor
2 Mount.Phase.Enter + Mount.Entry.Right AM_GetIn_RightDoor
3 Mount.Phase.Enter + Mount.Entry.Left + Driver AM_GetIn_LeftDoor_Driver
4 Mount.Phase.Exit AM_GetOut_Generic
5 Mount.Phase.Shuffle AM_ShuffleAcross

A left-door driver gets 3. A left-door passenger gets 1. A rear-door anyone gets 0. Nothing is ever silently unhandled: a phase with no match falls to the procedural slide.

Which set is used

Most specific wins: the seat's override, then the mount's, then the rider's, then the project default.

Key sets on the character, not the vehicle. A game has a handful of ways of climbing into things and a great many things to climb into, so keying on the rider and overriding on the mount is far less duplication than the reverse.

Notifies

One notify class, ED Mount Event, carrying a gameplay tag. Put it on the frame the thing actually happens.

TagWhat the framework does
Mount.Event.AttachAttaches the rider. On the server, takes the seat.
Mount.Event.DetachDetaches, places the rider at the exit. On the server, frees the seat.
Mount.Event.FinishedEnds the transition early. Optional.
Mount.Event.DoorOpen / .DoorCloseCalls SetSeatDoorOpen on the mount.
anything elseBroadcast on OnMountEvent, on the rider and the mount. Yours.

ED Mount Event Window is the same idea with a duration: one tag when it opens, another when it closes. That is what a door is — mark the window from the frame the hand reaches the handle to the frame it lets go, and the vehicle's door follows the animation exactly, on every machine, with nothing replicated, because every machine is playing the same montage.

One notify class, not five

Systems that ship a class per moment fix the set of moments an animator can mark at whatever the plugin author thought of, and make adding a sixth a code change. A tag makes it an afternoon.

Doors, with or without a montage

Mount.Event.DoorOpen and .DoorClose are usually a windowed notify. When the transition has no montage — or the montage does not mark the door itself — the framework opens the door for the length of the transition and closes it at the end.

The same rule as the attach fraction, for the same reason: an authored notify must never be second-guessed, and its absence must not mean the feature quietly does nothing. A project with no animations still gets doors that open when somebody gets in, and a transition that is interrupted closes the door it opened.

When the notify is missing

Timing falls back to Attach Fraction. The framework checks once, when the transition starts, whether the montage actually carries the notify it needs — so an authored notify at 70% is never pre-empted by a fallback at 55%, and a montage with no notify at all still seats the rider.

If the montage is cut short entirely, a watchdog completes the transition shortly past its expected end. See The state machine.

Motion warping

Add a Motion Warping component to your rider. The framework writes two targets before the montage's first evaluated frame:

TargetWhere it points
EDMountEntryThe chosen entry point.
EDMountSeatThe seat.

In the montage, add a Motion Warping notify state over the section that should land and point it at one of those names. They are constants rather than settings so a montage authored in one project keeps working in the next — and so a mismatch is impossible rather than being an animation that plays and simply does not arrive.

Without a warping component everything still works; the montage plays as authored and the framework snaps the rider to the seat at the attach moment.

The seated pose

Mount.Phase.Seated is not a transition. An entry tagged with it plays for as long as the rider is sitting, looping, and stops when they are not.

It is driven from the phase rather than from the request, which is what makes it right in the case everybody forgets: a client that joins to find somebody already in a car never ran a transition for them, and would otherwise show a rider standing through the roof. Every machine starts and stops the pose off the replicated phase, so nothing about it is on the wire.

There is nothing to warp to and no notify to fire, so the entry needs little more than the animation:

Phase Tag           Mount.Phase.Seated
Animation AS_Sitting
Use Motion Warping false

Tag it with a role to sit a driver differently from a passenger, exactly as you would a transition.

The example generates one

Scripts/build_seated_pose.py in the example project writes a seated pose from six lines describing where each limb should point. It is worth reading if you have to make one and have no animator.

If the pose plays and nothing moves

Check that your anim graph's slot actually reaches the output pose. A montage plays into a slot by name, and if the node with that name sits on a branch the graph does not evaluate, everything reports success and the skeleton never changes: the montage is playing, IsSlotActive is true, and GetSlotMontageLocalWeight is 1.0. The engine's own ABP_Unarmed is like this, which is why the example project applies the pose itself instead — see The example.

ResolveSeatedPose on the rider component returns the pose the framework chose, so a project in that position can apply it whatever way suits its rig.

Seat anim layers

A seat can name a Seat Anim Layer. It is linked onto the rider's anim instance when they attach and unlinked when they leave — the exact class that was linked, so changing the property while somebody is sitting there cannot leave a layer behind.

This is how a rider gets hands-on-wheel behaviour, a lean into corners, or a different idle in the back seat, without the character's anim graph knowing what a vehicle is.

Reading state from an anim graph

Pure nodes that take an actor and need no cast:

Get Mount Phase       → None / Entering / Seated / Shuffling / Exiting
Is Seated
Is Driving Mount
Get Seat Role → the seat's role tag
Get Occupied Seat → the seat component, for anything else

A seated pose that differs between the driver and a passenger is one tag comparison, with no dependency from the animation on your game's classes.