Gameplay kit
The engine crates a NEO game is built from (character, input, gameplay camera, audio and the kit plugin) and how to get a playable character in a few lines.
On this page
The gameplay kit is the set of engine crates that make a third-person game: the character, its controls, its camera and its sound, plus a plugin that assembles them into a running app. The GASP template's starter game is the kit playing a level, and every project made from the template uses it. Because the kit lives in the engine rather than in your project, your project picks up engine fixes without copying code.
This page is for creators who write Rust game code. If you build with the Studio and scripts, you already have all of this; see Samples and templates.
The crates#
| Crate | Plugin id (name) | What it provides |
|---|---|---|
neo_character | neo_character (Character kit) | The character simulation: a level and its agents, stepped deterministically; capsule movement; box-collision levels; motion-matched animation; foot placement and leg IK; traversal (vault, mantle, hurdle); pair interactions; physical animation and active ragdolls with get-ups; and foley events (footsteps, landings, slides, impacts). |
neo_input_kit | neo_input_kit (Input kit) | Keyboard, mouse and gamepad turned into character input (move, look, zoom, walk and crouch toggles, sprint, strafe, jump, interact, takedown, ragdoll), as a function and as a system. InputGate blocks it (for menus, or an unfocused Studio viewport). ControlSettings holds invert Y, sensitivities and the stick dead zone. |
neo_gameplay_camera | neo_gameplay_camera (Gameplay camera) | The third-person orbit camera, OrbitCamera (yaw, pitch, zoom and a damped pivot), and the GameplayCamera marker. OrbitCamera::follow(target, dt) gives the camera's transform. |
neo_audio_kit | neo_audio_kit (Audio kit) | One mixed output stream (voices, loops, fades, reverb), a WAV decoder, synthesized UI sounds, a foley bank picked by tag and surface, and its player, which plays the simulation's foley events with attenuation and panning. |
neo_gameplay_kit | GameplayKitPlugin (a Bevy plugin) | The app side, assembled: creating and stepping the simulation, the authored scene and Studio edits, the level and character renderers, the gameplay camera, the default controls (mouse capture on a click and Esc, Studio viewport focus, Backspace to reset), foley and ambience, a standalone game's window and content setup, multiplayer, and a smoke test. |
The gameplay kit also brings in neo_anim_ecs, which exposes motion matching, leg IK, rigs and physical animation as ECS components, for games that want those pieces on their own entities.
A playable character in ten lines#
This is the kit's own example (examples/third_person.rs, with the content folder pointed at your game's), a complete third-person game: the template's character and animation library, a floor, controls, the orbit camera and a sun.
use bevy::prelude::*;
use neo_gameplay_kit::{AuthoredScene, GameplayKitPlugin};
fn main() {
let assets = concat!(env!("CARGO_MANIFEST_DIR"), "/assets"); // your game's content folder
App::new()
.add_plugins(DefaultPlugins.set(AssetPlugin {
file_path: assets.into(),
..default()
}))
.add_plugins(GameplayKitPlugin::default().with_scene(AuthoredScene::default()))
.run();
}Run it from the engine workspace with cargo run -p neo_gameplay_kit --example third_person.
Configuring the kit#
| Builder | What it does |
|---|---|
with_scene(scene) | The scene to play: the level and the spawn points. |
with_level(level) | A level, with the player at the origin. |
with_assets(KitAssets { .. }) | The animation library, character model, physics asset, foley notifies and foley bank. |
game_clock() | Your game plans the simulation steps (for pause, slow motion or fixed steps) instead of one step per frame. |
game_input() | Your game writes the simulation's input instead of the default controls. |
without_lighting() | No sun or ambient light, for a game with its own look. |
GameplayKitPlugin also has fields for the parts it adds by default: frame_clock, input, camera, lighting, audio and multiplayer. With multiplayer on (the default), remote players in a platform session become characters too; without a session it does nothing. See Multiplayer.
A standalone game's app#
A game that runs on its own builds its app with neo_gameplay_kit::app, which sets up the window, the engine's default plugins and the project's content layers (its own assets/ over the template's).
SmokeTestPlugin(SmokeConfig::parse(&args)), from neo_gameplay_kit::smoke, adds a --smoke <dir> flag: once the simulation is up, scripted input drives the player through idle, walk, run and a sprint with a jump, logs its position every second, writes <dir>/smoke.png and <dir>/smoke.txt, and exits with an error if the player moved less than a metre. Projects made from the template have it.
Building it yourself#
To use the kits without GameplayKitPlugin:
Depend on them in the game crate's
Cargo.toml:TOMLneo_character = { workspace = true } neo_input_kit = { workspace = true } neo_gameplay_camera = { workspace = true } neo_audio_kit = { workspace = true } # optionalThey're enabled by default once linked; list them in the project's
neo.tomlto be explicit:TOML[plugins] neo_character = true neo_input_kit = true neo_gameplay_camera = true neo_audio_kit = trueAlso list them in your game plugin's descriptor
dependenciesso they're built before it. See Plugins and neo.toml.Build a simulation from a level and an animation library, and step it with the input kit's controls:
Rustuse bevy::prelude::*; use neo_character::{CharacterSim, level::Level}; use neo_gameplay_camera::{GameplayCamera, OrbitCamera}; use neo_input_kit::{CharacterControls, InputKitSystems}; #[derive(Resource)] struct Game { sim: CharacterSim, lib: bevy_motion_matching::library::Library } fn step(mut g: ResMut<Game>, controls: Res<CharacterControls>, time: Res<Time>) { let Game { sim, lib } = &mut *g; sim.step(lib, &controls.input, time.delta_secs()); } fn follow(g: Res<Game>, mut cam: ResMut<OrbitCamera>, time: Res<Time>, mut q: Single<&mut Transform, With<GameplayCamera>>) { let target = g.sim.character.position + Vec3::Z * 133.0; // capsule centre + boom **q = cam.follow(target, time.delta_secs()); } // app.add_systems(Update, (step.after(InputKitSystems), follow.after(step)));CharacterSim::new(&lib, level)takes your level (boxes with surfaces);with_physicsadds a physics asset for physical animation and ragdolls;spawn_npcadds more characters.Foley:
sim.foleycollects each frame's events (footsteps, landings, slides, hand plants, impacts). SettingKitAssets::foley_bankmakes the kit play them; a game with its own sound design plays them throughneo_audio_kit::foley::FoleyPlayer.
The player's model#
The player wears the game's character model unless the character kit's settings say otherwise. Set them in [plugin.neo_character] in neo.toml, in the Plugins panel, or with plugins.settings.set:
| Setting | What it does |
|---|---|
player_model | A glTF model for the player. On the animation library's skeleton, its joints take the poses by bone name. |
player_retarget | A .neoretarget file, for a model on a different skeleton: every frame, the player's pose is retargeted onto it. |
The model keeps its own materials, other characters keep the game's model, and a model that fails to load falls back to the game's. character.player_model reports the state. The player's platform avatar works the same way; see How avatars work in games.
Guarantees#
The simulation is deterministic: the same inputs give bit-identical results on every run, which is what lets a game replay or compare runs.