Gameplay packages
Each package is a set of components and services that a game, or a level manifest, attaches by name.
Characters (character)#
spawnCharacter makes an entity with CharacterMovement: a capsule moving against static geometry, with walk, run, crouch, jump, steps, slopes and acceleration. Its parameters follow Unreal's Character Movement Component, in metres and seconds (CharacterParams).
PlayerController turns input actions into movement and camera: it reads the action names you give it (PlayerActions) and ignores the ones you leave out. CameraRig is first or third person, switchable at run time.
Animation (animation)#
An Animator plays an animation graph (GraphDef) on an entity: state machines, blend spaces driven by speed or direction, layers, Montages for one-shot actions, and notifies at named times in a clip. locomotionGraph is a ready-made walk / run / jump graph. retargetGroup moves a clip from one skeleton to another, and buildPuppet makes a stand-in skinned character, so a game runs before its real models exist. A state can also play random motion ({ random: { entries } }, Unreal's Random Player): it picks an entry by weight, loops it a random number of times at a random rate, then cross-fades to the next pick; the pick is seeded, so it replays the same in a test or a replicated game, and the Unreal exporter's animbp.mjs turns Random Player nodes into it.
The graph does not use Babylon's animation clock: poses are requested and applied each fixed step, so animation is deterministic with the rest of the world.
AI (ai)#
NavService builds or loads a NavMesh (recast-navigation, WebAssembly, loaded once by initNavigation) and answers path and point queries. NavAgent moves an entity over it in the crowd. Small ready behaviours: Roam (walk to random points near home), Follow, Attention (stop and face the player who comes near). BehaviorTree is there for more.
Interaction (interaction)#
Interactor on the player picks the usable thing in front of it each step and shows its prompt; Interactable is the base. On top: Door, LevelDoor, Lever (flips and toggles the doors it points at), Pickup and Inventory. installInteraction(world) registers them so manifests can name them.
Zones (zones)#
ZoneService keeps named zones on a grid and knows who is in which one (a member is in exactly one zone at a time). It emits enter and exit events. zoneHash gives the name a backend sees, so zone names in a game's data can stay private.
Transformation (transform)#
Transformer swaps what an entity looks like and how it animates (mesh, skeleton, graph, movement values), keeping position and AI state, with an Effect around the swap: particleBurst, scalePulse, or combine of several. ZoneTransform does it on entering a zone. ProximityTransform does it from a record shared between clients: every client with a player in range posts "form" each tick, every client reads the record and shows the form while it is fresh, so all players see the same state (an NPC teacher stands up for whoever is near). Where the record lives is a RecordStore: MemoryRecordStore in-process, or PresenceRecordStore of net on the presence server.
Combat (combat)#
Fighter and Duel run a melee fight by rules that the clips set: the player and FighterAI give the same commands, weapon sweeps meet hit capsules, blocks, parries, stamina, health and reactions decide the rest. See Melee combat.
Media (media)#
AudioService has a master gain and four buses (music, sfx, ambient, voice); AmbientZones maps zones to ambient sounds. VideoScreen plays HLS or MP4 on a plane in the world; HtmlScreen draws a web page onto a plane as a texture. Every media component implements the same MediaPlayer interface. SceneRecorder records the scene to a video file (MP4 where the browser writes it, else WebM) with the sound the player hears once the audio is unlocked.
captureFrames captures the scene frame by frame on simulated time rather than the wall clock: before each frame the world moves exactly 1/fps seconds and the engine's frame time reads 1/fps, so nothing is dropped however slowly a frame is drawn, physics and animation stay in step, and a turntable loop closes exactly. Frames can be drawn at up to four times the size and scaled down (supersample), and come out as one WebM file (encoded in the browser with WebCodecs: VP9, else VP8; writeWebm is the container writer) or as PNG pictures one by one. beforeFrame(i, t) moves a camera along. The inspector command capture does the same from the console or an agent.
const clip = await captureFrames(game.engine, game.scene, game.world, {
seconds: 5, fps: 30, width: 1920, height: 1080, supersample: 2,
beforeFrame: (i, t) => { camera.alpha = start + (2 * Math.PI * t) / 5; }, // one turn in five seconds
});
// clip.blob: video/webm, clip.frames === 150
View (view)#
SectionView is a section (cutaway) view: meshes, or every mesh under a model's root, are cut by one to six planes in their materials on the GPU, and the cut faces are filled with a flat hatched colour, so a closed solid reads as cut through. Mode all cuts away only what lies beyond every plane (one plane is a half section, two planes take out a quarter); mode any cuts away what lies beyond any plane (a slice, a box). Planes can be given in a node's frame and move with it; exclude keeps chosen parts whole; active switches the cut on and off. The cut materials are copies, so a material shared with uncut meshes is untouched, and dispose() gives every mesh its own material back. Shadows and picking still see whole meshes. The gearbox of the showcase sample uses it for its cutaway.
const cut = new SectionView(scene, {
targets: [housingNode],
planes: [{ point: [0, 0, 0], normal: [0, 1, 0] }, { point: [0, 0, 0], normal: [0, 0, -1] }], // the upper front quarter
mode: 'all', frame: modelRoot,
});
cut.active = false; // whole again