A powerful 3D/2.5D game controller plugin for Bevy Engine.
The Weapon System is a highly modular and data-driven framework for creating FPS/TPS combat mechanics in Bevy. It supports everything from simple hitscan pistols to complex projectile-based launchers, featuring a robust attachment system, procedural recoil, realistic ballistics, and a flexible inventory system organized by “pockets”.
The Weapon component is the heart of the system, defining all stats and behaviors for a specific gun.
#[derive(Component, Debug, Reflect)]
pub struct Weapon {
pub weapon_name: String,
pub weapon_type: WeaponType, // Pistol, Rifle, Shotgun, etc.
// Core Stats
pub damage: f32,
pub range: f32,
pub fire_rate: f32, // Shots per second
pub ammo_capacity: i32,
// Mechanics
pub firing_mode: FiringMode, // SemiAuto, FullAuto, Burst
pub projectile_speed: f32, // 0.0 = Hitscan
pub spread: f32,
// ... extensive configuration fields
}
The WeaponManager handles the player’s inventory, weapon switching, and input processing. It acts as the central hub for the player’s arsenal.
#[derive(Component, Debug, Reflect)]
pub struct WeaponManager {
pub weapons_list: Vec<Entity>,
pub current_index: usize,
// Dual Wielding
pub using_dual_weapon: bool,
pub dual_weapons_enabled: bool,
// State Flags
pub reloading_with_animation: bool,
pub aiming_in_first_person: bool,
// Inventory Organization
pub weapon_pockets: Vec<WeaponPocket>,
}
Weapons are organized into “Pockets” (e.g., Primary, Secondary, Melee, Grenades). This allows for structured inventory management rather than a flat list.
damage: Base damage per hit.fire_rate: Delay between shots (calculated as 1.0 / fire_rate).range: Maximum effective distance.projectiles_per_shot: Number of bullets per trigger pull (e.g., Shotguns use > 1).Recoil is procedural and affects the camera/aim.
pub struct RecoilSettings {
pub kick_back: f32, // Z-axis visual kick
pub vertical_recoil: f32, // Upward aim rise
pub horizontal_recoil: f32,// Side-to-side aim jitter
pub recovery_speed: f32, // How fast aim recenters
pub ads_multiplier: f32, // Recoil reduction when aiming
}
idle_anim, shoot_anim, reload_anim, etc.).burst_settings.amount) with a specific cycle rate per trigger pull.The system supports both hitscan (instant) and physical projectiles seamlessly.
projectile_speed to 0.0. Uses raycasting for instant hits. Best for standard bullets in fast-paced games.projectile_speed > 0.0. Spawns a physical Projectile entity with velocity, gravity (use_gravity), and drag (projectile_drag_coeff). Best for rocket launchers, arrows, or “realistic” shooters.Accuracy is dynamic. Firing increases “Bloom”, which adds random deviation to shots.
Handles both “reload with ammo” (tactical reload) and “empty reload” (dry).
current_ammo < ammo_capacity.ReloadWithAmmo or ReloadWithoutAmmo.reload_time elapses.Weapons can have multiple Attachment Places (e.g., Scope, Muzzle, Magazine, Underbarrel). Each place can hold one active attachment from a list of available options.
Attachments use AttachmentStatModifiers to dynamically alter weapon performance:
ammo_capacity, slightly increases reload time.To edit attachments, the WeaponManager can toggle an “Attachment Editor” mode (open_attachment_editor). This allows UI systems to display available payloads and modify the weapon in real-time.
SwaySettings) and bob while walking (WeaponIkSettings).The WeaponBuilder provides a fluent API for constructing complex weapons in code.
let rifle = WeaponBuilder::new("Assault Rifle")
.with_fire_rate(600.0) // RPM
.with_firing_mode(FiringMode::FullAuto)
.with_ammo(30)
.with_recoil(0.5, 0.2, 5.0) // Vert, Horz, Recovery
.with_accuracy(0.1, 1.5, 0.1) // Base, Max, Bloom
.with_visuals(true, true) // Muzzle flash, Shells
.with_attachment_slot("scope", "Optic")
.with_attachment_slot("muzzle", "Barrel")
.spawn(&mut commands);
The system includes built-in support for unique weapon behaviors:
BowSettings), arrow physics.GravityGunSettings), pick up/throw objects.BeamSettings).Homing component).WeaponManager is added to your player entity.create_default_pockets).WeaponBuilder.// In your player spawn logic
commands.entity(player_entity).insert(WeaponManager::default());
// Spawning a weapon
let pistol = WeaponBuilder::new("M9 Pistol")
.with_firing_mode(FiringMode::SemiAuto)
.with_ammo(15)
.spawn(&mut commands);
// Adding to inventory
if let Ok(mut manager) = weapon_manager_query.get_mut(player_entity) {
manager.weapons_list.push(pistol);
manager.add_weapon_to_pocket("M9 Pistol", "secondary");
}