Game Dev Best Practices
Scalable, performant, testable game code in Rust and Bevy.
How to Use This List
- Apply A-B at project start when scaffolding schedules and folders.
- Walk C-D before milestone demos and publisher builds.
- Revisit E after perf regressions or content scale-up.
A - ECS Design
- Keep components small and data-only. Behavior stays in systems, not methods on god structs.
- Use marker components for query filters.
With<Enemy>beats string tags. - Order systems explicitly when sharing mutable access. Scheduler conflicts serialize unexpectedly otherwise.
- Despawn hierarchies on scene exit. Leaked entities cause ghost collisions and memory creep.
- Prefer
Commandsfor spawns/despawns. Structural changes batch safely in schedule.
B - Timing and Simulation
- Run physics in
FixedUpdateonly. Variabledelta_secsin physics causes jitter and tunneling. - Interpolate render transforms between fixed states. High FPS displays need smooth visuals.
- Cap fixed catch-up steps after hitches. Prevent spiral of death freezing gameplay.
- Sample input in
Update, consume in fixed step via buffer if needed. Consistent control feel. - Pause with virtual time, not busy loops. Menus should not advance simulation accidentally.
C - Assets and Content
- Consistent lowercase asset paths for Linux builds. Case mismatch passes on macOS, fails in CI.
- Wait for
LoadState::Loadedbefore spawning gameplay. Placeholder pink textures signal missing gate. - Compress audio and textures appropriately. OGG and GPU-compressed formats reduce load and VRAM.
- Version scene files with game releases. Old scenes with removed components need migration.
- Organize
assets/by domain (sprites,audio,scenes). Content creators navigate faster.
D - Performance and Shipping
- Profile Tracy/Puffin on min-spec hardware. Steam Deck and integrated GPU tell truth.
- Avoid per-frame allocations in hot systems. Reuse buffers in resources.
- Use diagnostics plugins in dev, not spam in release.
println!inUpdatekills FPS. - Release build with LTO for shipping. Debug builds misrepresent performance utterly.
- Test headless or minimal plugins in CI for logic. Not every test needs GPU window.
E - Team and Maintenance
- Pin Bevy to exact minor version. Read migration guide before bumping.
- Document control bindings and gamepad deadzones. QA reproduces bugs faster.
- Feature-flag debug overlays (collider draw, FPS). Ship clean player builds.
- Separate
gamecrate fromenginecrate if scope grows. Reuse engine across titles. - Record known Bevy/plugin version pairs in README. Onboarding avoids dependency hell.
FAQs
Biggest beginner mistake?
Putting physics in Update with variable delta - move to FixedUpdate immediately.
When to leave Bevy abstractions?
When render doc shows material batching limit and you need custom wgpu pass - not day one.
Networking?
Plan tick rate and state sync early; retrofitting multiplayer is expensive - outside this list but plan architecture.
Testing?
Unit test pure functions; integration test schedules with App::update() and minimal plugins.
ECS vs OOP?
ECS wins on cache and parallelism for many entities; accept learning curve on queries.
Audio polish?
Event-driven one-shots; loop music on separate entity; cap polyphony - see physics/audio page.
Scope control?
Vertical slice one mechanic with assets loaded, physics, audio, menu before content explosion.
Modding?
Data-driven RON/TOML for stats; keep code modding advanced stretch goal.
Accessibility?
Remappable keys, colorblind palettes, UI scale - plan in Input & Events.
Learn loop?
Game Dev Basics then Bevy Engine.
Related
- Bevy Engine - core patterns
- Game Loops & Timing - fixed step
- Performance for Games - profiling
- Game Dev Basics - orientation
Stack versions: This page was written for Rust 1.97.0 (edition 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, and Polars 0.46+.