A modern multiplayer first-person shooter built from scratch with Rust and Bevy Engine
Features โข Architecture โข Getting Started โข Tech Stack
Multiplayer FPS is a modern take on classic maze-based first-person shooters, inspired by Maze Wars. Built entirely in Rust using the Bevy game engine, this project demonstrates advanced game development concepts including real-time networking, 3D physics, and multiplayer synchronization.
- โ Learn Rust Game Development: Master Rust's ownership system in a game context
- โ Multiplayer Networking: Implement client-server architecture with UDP
- โ 3D Physics: Integrate Rapier3D for realistic collisions and movement
- โ Real-time Gameplay: Achieve 50+ FPS with low-latency networking
- โ Modern Game Architecture: Use Bevy's ECS (Entity Component System)
-
First-Person Shooter Mechanics:
- Smooth camera control with mouse look
- WASD movement with collision detection
- Shooting system with bullet physics
- Health system and player elimination
-
3D Maze Navigation:
- Procedurally generated or JSON-loaded mazes
- Dynamic lighting system
- Wall collisions with Rapier3D physics
- Multiple spawn points for players
-
UDP Networking:
- Low-latency client-server architecture
- Asynchronous networking with Tokio
- 20 Hz update rate for smooth synchronization
- Supports up to 10 concurrent players
-
Real-time Synchronization:
- Player position and rotation updates
- Enemy player rendering and tracking
- Death state synchronization
- Automatic game start when lobby is full
-
In-Game HUD:
- Real-time FPS counter (green overlay)
- Minimap with player position
- Player information display
- Connection status
-
Audio System:
- Footstep sounds during movement
- Shooting sound effects
- Spatial audio (3D positioning)
-
Bevy Rendering:
- 3D mesh rendering for players and environment
- Dynamic lighting and shadows
- Material system with color customization
- Camera system with configurable sensitivity
-
Rapier3D Physics:
- Rigid body dynamics
- Collider detection (walls, bullets, players)
- Gravity-free player movement
- Locked rotation axes for FPS controls
| Technology | Version | Purpose |
|---|---|---|
| 1.70+ | Primary language (98.8%) | |
| 0.15.1 | Game engine & ECS | |
| 0.23.0 | Physics engine | |
| 1.x | Async runtime |
[dependencies]
bevy = "0.15.1" # Game engine
rapier3d = "0.23.0" # Physics simulation
bevy_rapier3d = "0.28.0" # Bevy-Rapier integration
tokio = { version = "1", features = ["full"] } # Async networking
serde = "1.0.217" # Serialization
bincode = "1.3.3" # Binary encoding
serde_json = "1.0.137" # JSON parsing
thiserror = "2.0.11" # Error handling
lazy_static = "1.5.0" # Static variables
bevy_dev_tools = "0.15.2" # Development utilitiesmultiplayer-fps/
โโโ src/
โ โโโ bin/
โ โ โโโ client.rs # Client entry point
โ โ โโโ server.rs # Server entry point
โ โโโ client/ # Client-side code
โ โ โโโ components/ # ECS Components
โ โ โ โโโ player_component.rs
โ โ โ โโโ enemy_component.rs
โ โ โ โโโ camera_component.rs
โ โ โ โโโ bullet.rs
โ โ โ โโโ world_component.rs
โ โ โโโ systems/ # ECS Systems
โ โ โ โโโ player/ # Player mechanics
โ โ โ โ โโโ setup_player.rs
โ โ โ โ โโโ move_player.rs
โ โ โ โ โโโ rotate_player.rs
โ โ โ โ โโโ shooting.rs
โ โ โ โ โโโ send_update_player.rs
โ โ โ โ โโโ step.rs (audio)
โ โ โ โโโ enemy/ # Enemy synchronization
โ โ โ โ โโโ setup_enemy.rs
โ โ โ โ โโโ receiving_update_enemy.rs
โ โ โ โ โโโ move_enemy.rs
โ โ โ โ โโโ handle_animation_enemy.rs
โ โ โ โโโ world/ # World generation
โ โ โ โ โโโ load_json_world.rs
โ โ โ โ โโโ spawn_map.rs
โ โ โ โ โโโ models_world.rs
โ โ โ โโโ common/ # Shared systems
โ โ โ โโโ fps_display_system.rs
โ โ โ โโโ window_config_system.rs
โ โ โ โโโ light_system.rs
โ โ โโโ plugins/ # Bevy Plugins
โ โ โ โโโ player_plugin.rs
โ โ โ โโโ enemy_plugin.rs
โ โ โ โโโ world_plugin.rs
โ โ โโโ resources/ # Bevy Resources
โ โ โ โโโ network_resource.rs
โ โ โ โโโ player_resource.rs
โ โ โ โโโ enemy_resource.rs
โ โ โ โโโ world_resource.rs
โ โ โ โโโ animation_resource.rs
โ โ โโโ udp.rs # Client networking
โ โโโ server/ # Server-side code
โ โ โโโ udp.rs # Server networking
โ โ โโโ utils/ # Server utilities
โ โ โโโ exception.rs
โ โโโ common/ # Shared code
โ โ โโโ types/
โ โ โ โโโ protocol.rs # Network protocol
โ โ โ โโโ game_state.rs
โ โ โโโ utils/
โ โ โโโ socket_utils.rs
โ โโโ lib.rs # Library root
โโโ assets/ # Game assets
โ โโโ sounds/
โ โ โโโ running.ogg
โ โ โโโ shoot.ogg
โ โโโ models/
โโโ Cargo.toml # Project dependencies
โโโ README.md
Components - Data containers:
Player,Enemy,Bullet,Camera,Wall
Systems - Logic functions:
- Movement, Rotation, Shooting, Collision, Networking
Resources - Global state:
NetworkResource,PlayerResource,EnemyResource,MazeResource
Plugins - Feature modules:
PlayerPlugin,EnemyPlugin,WorldPlugin
- Rust 1.70 or higher
- Cargo (comes with Rust)
- Git
git clone https://github.com/mamadbah2/multiplayer-fps.git
cd multiplayer-fpscargo build --releaseThis will compile both client and server binaries.
cargo run --bin server --release./target/release/serverServer Configuration:
Enter the number of players: (default 2)
> 4
The server will:
- Start listening on
0.0.0.0:8080 - Wait for the specified number of players to connect
- Automatically start the game when lobby is full
cargo run --bin client --release./target/release/clientClient Configuration:
Enter your name:
> Player1
Enter the server address (default: 192.168.1.100:8080):
> localhost:8080
The client will:
- Connect to the server
- Wait in lobby until all players join
- Start rendering the game when ready
- W - Move forward
- A - Move left
- S - Move backward
- D - Move right
- Mouse - Look around / Aim
- Left Click - Shoot
- Spacebar - Jump (if enabled)
- ESC - Exit game
- F3 - Toggle debug info (FPS, position)
Message Types:
pub enum Message {
Join { name: String },
PlayerUpdateSending {
position: Vec3,
rotation: Quat,
all_dead_players: Vec<String>,
},
PlayerUpdateReceiving {
name: String,
position: Vec3,
rotation: Quat,
all_dead_players: Vec<String>,
},
StartGame {
player: CommonPlayer,
enemies: Vec<CommonPlayer>,
},
Leave,
}Server:
- UDP socket binding on port 8080
- Broadcast system for player updates
- 20 Hz tick rate
- Player state management with
RwLock
Client:
- Asynchronous message receiving
- 20 Hz update sending
- Non-blocking socket operations
- Client-side prediction
Uses Bincode for efficient binary serialization:
- Compact message size (~64 bytes per update)
- Fast encoding/decoding
- Zero-copy deserialization where possible
-
Setup Phase:
- Load 3D models and materials
- Spawn entities (player, enemies, world)
- Setup camera and lighting
-
Update Phase (60 FPS target):
- Process input
- Update physics
- Network synchronization
- Animation updates
-
Render Phase:
- Frustum culling
- Shadow mapping
- Material rendering
- UI overlay
Colliders:
Collider::cuboid(0.7, 0.1, 0.7) // Player
Collider::cuboid(2.0, 5.0, 2.0) // Wall
Collider::ball(0.1) // BulletPhysics Configuration:
RigidBody::Dynamic // Player & bullets
RigidBody::Fixed // Walls & floor
GravityScale(0.0) // Disabled for FPS
LockedAxes::ROTATION_LOCKED // Prevent player tipping- Footsteps: Looped during movement
- Gunshots: Triggered on fire
- Impacts: Bullet hit sounds
Implementation:
AudioPlayer::new(asset_server.load("sounds/running.ogg"))Playback controlled by movement state.
Compile-time:
[profile.dev]
opt-level = 1 # Basic optimization
[profile.dev.package."*"]
opt-level = 3 # Full optimization for dependencies
[profile.release]
lto = true # Link-time optimization
codegen-units = 1 # Single codegen unitRuntime:
- Entity pooling for bullets
- Spatial partitioning for collision
- LOD system for distant players
- Update rate limiting (20 Hz networking)
- 60 FPS minimum (client rendering)
- < 50ms network latency
- < 100ms input response time
- 10 concurrent players supported
Bevy Dev Tools:
bevy_dev_tools = "0.15.2"Features:
- FPS overlay (green, top-right)
- Entity inspector
- Resource browser
- System profiler
Rapier Debug Rendering:
RapierDebugRenderPlugin::default()Visualizes:
- Colliders (wireframe)
- Rigid bodies (colored)
- Contact points
- Player Limit: Maximum 10 concurrent players
- Lag Compensation: Basic interpolation only
- Collision: Occasional bullet pass-through at high speeds
- Audio: No spatial audio attenuation yet
- ๐ฏ Raycast-based shooting (hitscan)
- ๐ Scoreboard and kill/death tracking
- ๐จ Character models and animations
- ๐บ๏ธ Multiple map support
- ๐ Spatial 3D audio
- ๐ฎ Gamepad support
- ๐ Matchmaking system
- ๐พ Save/load game state
- ๐ Achievement system
- ๐ฅ Spectator mode
- Lag compensation with server reconciliation
- Client-side prediction improvements
- Anti-cheat measures
- Better error handling and recovery
- Performance profiling and optimization
- Cross-platform testing (Windows, Linux, macOS)
Contributions are welcome! Here's how you can help:
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
- Write idiomatic Rust code
- Follow Bevy's ECS best practices
- Add documentation for public APIs
- Include tests for new features
- Keep commits atomic and well-described
This project is available for educational purposes.
Mamadou Bah - @mamadbah2
Project Link: https://github.com/mamadbah2/multiplayer-fps
- Bevy Engine Team - For the amazing game engine
- Rapier Physics - For the robust physics library
- Tokio Team - For async runtime
- Rust Community - For excellent documentation and support