Skip to main content

Seats and entry points

A seat is a UEDMountPointComponent: a scene component, so it has a transform you drag and a parent it follows.

Placing a seat

Add the component and drag it. The box is the seat; the arrow is the direction the rider faces.

Parent it to a bone when the seat moves. A seat attached to a skeletal mesh socket follows that socket every frame, with no code and no tick — the transform comes from the attachment. That is how

  • a saddle stays on a horse that is breathing and galloping,
  • a turret gunner turns with the gun,
  • a seat inside a door swings out with the door.

Attach Socket Override covers the case where you cannot parent the component but still need to follow a socket. Parenting is better whenever it is available, because then the transform you see in the viewport is exactly the transform the rider gets.

Properties

PropertyDefaultWhat it is for
Seat Namethe component's nameLogs, the editor, and one lookup at setup. Not for gameplay.
Role TagMount.Role.PassengerMount.Role.Driver is the only one the framework acts on.
Sort Priority0Higher seats are offered first when a rider asks for "any seat".
EnabledtrueTakes a seat out of service without deleting it.
Required Rider TagsemptyA query against the rider's tags. See Access rules.
Allow Shuffle IntotrueOff makes a seat reachable only from outside.
Prefer Same Side On ExittruePut the rider down on the side they came in on.
Animation Set OverridenoneFor the seat that genuinely animates differently.
Seat Anim LayernoneAn anim layer linked onto the rider while they occupy this seat.
Seat CameranoneA component your camera system can ask about.
Rider Policyproject defaultCollision, movement, mesh and pose handling while seated.
Possession Policyproject defaultWhether the controller possesses the mount.

Addressing a seat

FEDSeatHandle, and nothing else. A stable id issued when the seat registers, valid on every machine, unchanged when seats are added or removed at runtime.

// Once, at setup:
const FEDSeatHandle GunnerSeat = Mountable->FindSeatByName(TEXT("Gunner"));

// Then, forever:
Rider->RequestChangeSeat(GunnerSeat);
Why one way and not three

Mounting systems commonly address seats by index and by id and by name, and therefore ship three variants of every seat function. Worse than the size: index and id drift apart the first time a seat is removed, and nothing in the type system stops you passing one where the other belongs, because both are int32.

Entry points

Each seat carries any number of entry points: the places a rider stands to get in, and can be put down when they get out. A car door is one. A roof hatch is one.

An entry point is a transform relative to the seat — so it moves when you move the seat — a side tag, and a capsule describing how much room a rider needs there.

PropertyDefaultWhat it is for
Side Tagderived from geometryMount.Entry.Left, .Right, .Front, .Rear, .Top. Picks an animation.
Relative TransformidentityWhere the rider stands, and which way they face.
Priority0Higher wins among usable points. Ties break on distance.
Allow Entry / Allow ExittrueA hatch you can climb in through but not out of.
Clearance Radius / Half Height34 / 88The capsule swept against the world. Matches the engine's character.
Require Ground On ExittrueOff for a hatch over open air.
Max Ground Drop200How far below the point ground still counts as a floor.

Leaving them empty

A seat with no entry points is a valid state: the framework derives a left/right pair from the mount's bounds. They are drawn dashed, because they are a preview rather than data.

Press Generate Entry Points to write them into the array, then drag them.

How one gets chosen

  1. Skip it if it does not allow the direction being asked for.
  2. Sweep its clearance capsule against the world, ignoring the mount and the rider. Skip it if something is in the way.
  3. For an exit, trace down for ground when the point asks for it.
  4. Score it: Priority × 1000 − distance to the rider, plus 500 when it matches the side the caller asked for or the side the rider came in on.

Highest score wins. Priority dominates by design — the spread is wide enough that no realistic distance crosses it, so "priority 1 beats priority 0" is a promise rather than a tendency.

If nothing is usable, entering fails with NoEntryPoint.

When every exit is blocked

Project setting Allow Unsafe Exit Fallback, on by default. On, the rider is placed at the seat and left to the movement component's own depenetration, which reads as squeezing out of a wedged car. Off, the dismount is refused with NoExitPoint, which is right for games where being trapped is a state rather than a bug.

ForceDismount() ignores this entirely. It exists for the vehicle exploding.

The visualizer

ColourMeaning
Blue boxA free seat. Grey when disabled.
Green capsuleA rider fits here, both in and out.
Amber capsuleA rider fits, but there is no ground for an exit.
Red capsuleBlocked.
YellowSelected — drag it with the move gizmo.
Dashed lineA derived entry point, not real data yet.

The capsule drawn is the capsule actually swept, so "it says clear but the rider clips the door frame" is impossible to misread. The check runs live: push a wall against a door and watch it change.

Dragging an entry point re-derives its side tag from where it ends up. Fix Side Tags does the same to every point at once, which is the repair for a layout copied from another vehicle.

Adding seats at runtime

UEDMountPointComponent* Seat = NewObject<UEDMountPointComponent>(MountActor);
Seat->SetupAttachment(MountActor->GetRootComponent());
Seat->SeatName = TEXT("JumpSeat");
Seat->RegisterComponent(); // registers itself, and gets a handle

Removing a seat under an occupant force-dismounts them rather than leaving them attached to a component that no longer exists.