Bevy All-in-One Documentation

A powerful 3D/2.5D game controller plugin for Bevy Engine.


Project maintained by yaskhan Hosted on GitHub Pages — Theme by mattgraham

Camera System Documentation

Table of Contents

  1. Overview
  2. Core Concepts
  3. Component Reference
  4. Camera Modes
  5. Advanced Features
  6. System Integration
  7. Usage Patterns
  8. Best Practices
  9. Troubleshooting

Overview

The Camera System is a comprehensive, modular camera controller designed for 3D/2.5D games built with Bevy 0.18. It provides sophisticated camera controls, physics-based collision detection, dynamic state management, and advanced cinematic features. The system is built with flexibility and performance in mind, supporting multiple camera modes, real-time effects, and seamless integration with other game systems.

Key Features

Architecture Overview

The Camera System follows a plugin-based architecture with clear separation of concerns:

Camera Plugin
├── Core Components (CameraController, CameraState)
├── Movement Systems (Follow, Rotation, Collision)
├── Effect Systems (Shake, Bob, FOV)
├── Targeting Systems (Marking, Locking)
├── Cinematic Systems (Waypoints, Zones, Bounds)
├── Advanced Features (Effects, Captures, Vehicles)
└── Integration Systems (State Offsets, Lean, Transparency)

The system integrates deeply with:


Core Concepts

Camera Coordinate System

The Camera System uses a right-handed 3D coordinate system with the following conventions:

Pivot Point System

The camera system operates on a pivot-based architecture where the camera position is calculated relative to a target pivot point:

  1. Base Pivot: Calculated from character transform + offset
  2. Dynamic Pivot: Modified by aiming, crouching, and state changes
  3. Collision Pivot: Adjusted based on physics collision detection
  4. Final Position: Pivot point + backward direction * distance + effects

State Machine Architecture

Camera states are managed through a sophisticated state machine that supports:

Smooth Interpolation

All camera movements use exponential smoothing for natural motion:

// Exponential smoothing formula
let alpha = 1.0 - (-speed * delta_time).exp();
current_value = current_value + (target_value - current_value) * alpha;

This provides frame-rate independent smoothing with configurable response curves.

Spatial Query Integration

The system heavily relies on Avian3D’s spatial query system for:


Component Reference

Core Camera Components

CameraController

The primary controller component that manages camera behavior and configuration:

#[derive(Component, Debug, Reflect)]
#[reflect(Component)]
pub struct CameraController {
    pub follow_target: Option<Entity>,
    pub mode: CameraMode,
    pub current_side: CameraSide,
    
    // Sensitivity Settings
    pub rot_sensitivity_3p: f32,
    pub rot_sensitivity_1p: f32,
    pub aim_zoom_sensitivity_mult: f32,
    
    // Angular Limits
    pub min_vertical_angle: f32,
    pub max_vertical_angle: f32,
    
    // Distance Settings
    pub distance: f32,
    pub min_distance: f32,
    pub max_distance: f32,
    
    // Smoothing Parameters
    pub smooth_follow_speed: f32,
    pub smooth_rotation_speed: f32,
    pub pivot_smooth_speed: f32,
    pub distance_smooth_speed: f32,
    
    // Dynamic Offsets
    pub side_offset: f32,
    pub default_pivot_offset: Vec3,
    pub aim_pivot_offset: Vec3,
    pub crouch_pivot_offset: Vec3,
    
    // Leaning Configuration
    pub lean_amount: f32,
    pub lean_angle: f32,
    pub lean_speed: f32,
    pub lean_raycast_dist: f32,
    pub lean_wall_angle: f32,
    
    // Field of View Settings
    pub default_fov: f32,
    pub aim_fov: f32,
    pub fov_speed: f32,
    
    // Collision Settings
    pub use_collision: bool,
    pub collision_radius: f32,
    
    // Targeting System
    pub target_lock: TargetLockSettings,
    
    // State Management
    pub states: Vec<CameraStateInfo>,
    pub current_state_name: String,
    
    // Baseline Configuration
    pub base_mode: CameraMode,
    pub base_distance: f32,
    pub base_fov: f32,
    pub base_pivot_offset: Vec3,
    pub base_transition_speed: f32,
    pub enabled: bool,
}

Key Properties:

CameraState

Runtime camera state tracking component:

#[derive(Component, Debug, Default, Reflect)]
#[reflect(Component)]
pub struct CameraState {
    pub yaw: f32,
    pub pitch: f32,
    pub current_distance: f32,
    pub current_pivot: Vec3,
    pub current_side_interpolator: f32,
    pub current_lean: f32,
    pub noise_offset: Vec2,
    pub bob_offset: Vec3,
    pub is_aiming: bool,
    pub is_crouching: bool,
    pub fov_override: Option<f32>,
    pub fov_override_speed: Option<f32>,
}

Properties:

CameraTargetState

Target tracking and management component:

#[derive(Component, Debug, Default, Reflect)]
#[reflect(Component)]
pub struct CameraTargetState {
    pub marked_target: Option<Entity>,
    pub locked_target: Option<Entity>,
    pub is_locking: bool,
}

Properties:

Camera Modes

CameraMode Enum

#[derive(Debug, Clone, Copy, PartialEq, Eq, Reflect, Default)]
pub enum CameraMode {
    #[default]
    ThirdPerson,
    FirstPerson,
    Locked,
    SideScroller,
    TopDown,
}

Mode Characteristics:

Advanced Components

CameraZone

Trigger volumes that modify camera behavior:

#[derive(Component, Debug, Reflect)]
#[reflect(Component)]
pub struct CameraZone {
    pub settings: CameraZoneSettings,
    pub priority: i32,
}

CameraZoneSettings

Configuration for zone-based camera modifications:

#[derive(Debug, Clone, Reflect)]
pub struct CameraZoneSettings {
    pub mode: CameraMode,
    pub distance: Option<f32>,
    pub pivot_offset: Option<Vec3>,
    pub fov: Option<f32>,
    pub fixed_yaw: Option<f32>,
    pub fixed_pitch: Option<f32>,
    pub follow_rotation: bool,
    pub look_at_player: bool,
    pub transition_speed: f32,
}

CameraWaypoint and Track System

#[derive(Component, Debug, Reflect)]
#[reflect(Component)]
pub struct CameraWaypoint {
    pub wait_time: f32,
    pub movement_speed: Option<f32>,
    pub rotation_speed: Option<f32>,
    pub rotation_mode: WaypointRotationMode,
    pub look_at_target: Option<Entity>,
}

#[derive(Component, Debug, Default, Reflect)]
#[reflect(Component)]
pub struct CameraWaypointTrack {
    pub waypoints: Vec<Entity>,
    pub loop_track: bool,
}

Shake and Effect Components

#[derive(Component, Debug, Reflect)]
#[reflect(Component)]
pub struct CameraShakeInstance {
    pub camera_entity: Option<Entity>,
    pub name: String,
    pub timer: f32,
    pub duration: f32,
    pub intensity: f32,
    pub pos_amount: Vec3,
    pub rot_amount: Vec3,
    pub pos_speed: Vec3,
    pub rot_speed: Vec3,
    pub pos_smooth: f32,
    pub rot_smooth: f32,
    pub current_pos: Vec3,
    pub current_rot: Vec3,
    pub decrease_in_time: bool,
}

Bobbing System

#[derive(Component, Debug, Reflect)]
#[reflect(Component)]
pub struct CameraBobState {
    pub phase: f32,
    pub current_pos_offset: Vec3,
    pub current_rot_offset: Vec3,
    
    pub idle: BobPreset,
    pub walk: BobPreset,
    pub sprint: BobPreset,
    pub aim: BobPreset,
}

Transparency and Culling

#[derive(Resource, Reflect, Clone)]
#[reflect(Resource)]
pub struct TransparencySettings {
    pub enabled: bool,
    pub alpha_target: f32,
    pub fade_speed: f32,
    pub ray_radius: f32,
}

#[derive(Resource, Reflect, Clone)]
#[reflect(Resource)]
pub struct PlayerCullingSettings {
    pub enabled: bool,
    pub min_dist: f32,
    pub fade_speed: f32,
    pub min_alpha: f32,
}

Camera Modes

Third-Person Mode

The default camera mode providing a behind-shoulder perspective:

Characteristics:

Configuration:

camera.mode = CameraMode::ThirdPerson;
camera.distance = 4.0;
camera.min_distance = 1.5;
camera.max_distance = 8.0;
camera.side_offset = 0.5;

Dynamic Behavior:

First-Person Mode

Eye-level perspective with limited vertical rotation:

Characteristics:

Configuration:

camera.mode = CameraMode::FirstPerson;
camera.rot_sensitivity_1p = 0.1;
camera.min_vertical_angle = -85.0;
camera.max_vertical_angle = 85.0;
camera.use_collision = false; // Optional

Special Considerations:

Locked Mode

Fixed orientation camera that follows character movement:

Characteristics:

Configuration:

camera.mode = CameraMode::Locked;
camera.smooth_rotation_speed = 15.0;
camera.distance = 3.0;

Side-Scroller Mode

2D-style camera with limited depth:

Characteristics:

Configuration:

camera.mode = CameraMode::SideScroller;
camera.distance = 6.0;
camera.min_vertical_angle = 0.0;
camera.max_vertical_angle = 0.0;

Top-Down Mode

Overhead perspective with orthographic or perspective projection:

Characteristics:

Configuration:

camera.mode = CameraMode::TopDown;
camera.distance = 15.0;
camera.default_fov = 75.0;
camera.pivot_smooth_speed = 20.0;

Advanced Features

Target Locking System

The target locking system provides sophisticated enemy tracking:

TargetMarking

Automatic target highlighting based on:

Scoring Algorithm:

let score = dist * 0.5 + angle * 2.0;

Configuration:

camera.target_lock.enabled = true;
camera.target_lock.max_distance = 30.0;
camera.target_lock.fov_threshold = 45.0;
camera.target_lock.scan_radius = 2.0;

TargetLocking

Manual target acquisition with:

Locking Behavior:

Camera Collision System

Physics-based collision detection prevents camera clipping:

Collision Detection

pub fn handle_camera_collision(
    spatial_query: SpatialQuery,
    mut query: Query<(&CameraController, &CameraState, &mut Transform)>,
) {
    for (camera, state, mut transform) in query.iter_mut() {
        if !camera.use_collision { continue; }

        let start = state.current_pivot;
        let direction = transform.back();
        let max_dist = state.current_distance;
        let filter = SpatialQueryFilter::default();

        if let Some(hit) = spatial_query.cast_ray(start, direction, max_dist, true, &filter) {
            transform.translation = start + direction * (hit.distance - camera.collision_radius);
        }
    }
}

Wall Leaning

Camera leans against walls to maintain visibility:

Leaning Process:

  1. Raycast forward from camera position
  2. Detect wall proximity within lean distance
  3. Calculate lean angle based on wall angle
  4. Smoothly interpolate lean offset
  5. Apply lean to camera position and rotation

Configuration:

camera.lean_amount = 0.4;
camera.lean_angle = 15.0;
camera.lean_raycast_dist = 0.8;
camera.lean_wall_angle = 5.0;

Camera Zones

Area-based camera behavior modification:

Zone Detection

Uses spatial point intersections to detect player position within zones:

let intersections = spatial_query.point_intersections(player_pos, &filter);

Zone Priority System

Zones are evaluated by priority with the highest priority taking effect:

for &zone_ent in tracker.active_zones.iter() {
    if let Ok(zone) = zone_query.get(zone_ent) {
        if zone.priority > max_priority {
            max_priority = zone.priority;
            best_zone = Some(zone_ent);
        }
    }
}

Transition Smoothing

Zone transitions use exponential smoothing:

let alpha = 1.0 - (-speed * dt).exp();
controller.distance = controller.distance + (target_dist - controller.distance) * alpha;

Cinematic Camera System

Waypoint System

Complex camera movements through predefined paths:

Waypoint Configuration:

let waypoint = CameraWaypoint {
    wait_time: 2.0,
    movement_speed: Some(5.0),
    rotation_speed: Some(10.0),
    rotation_mode: WaypointRotationMode::LookAtTarget,
    look_at_target: Some(player_entity),
};

Rotation Modes:

Cutscene Integration

Camera cutscenes integrate with:

Shake and Effect System

Camera Shake

Procedural camera movement for impact feedback:

Shake Types:

Shake Parameters:

let shake = CameraShakeInstance {
    duration: 0.5,
    intensity: 1.0,
    pos_amount: Vec3::new(0.05, 0.05, 0.05),
    rot_amount: Vec3::new(2.0, 2.0, 2.0),
    pos_speed: Vec3::new(15.0, 15.0, 15.0),
    rot_speed: Vec3::new(15.0, 15.0, 15.0),
    decrease_in_time: true,
};

Camera Bobbing

Movement-based camera simulation:

Bob Presets:

Bob Calculation:

let target_pos = Vec3::new(
    (t * preset.pos_speed.x).sin() * preset.pos_amount.x,
    (t * preset.pos_speed.y).sin() * preset.pos_amount.y,
    (t * preset.pos_speed.z).cos() * preset.pos_amount.z,
);

Field of View Management

Dynamic FOV changes based on:

State-Based FOV

Override System

state.fov_override = Some(target_fov);
state.fov_override_speed = Some(speed);

FOV Transition

let alpha = 1.0 - (-speed * time.delta_secs()).exp();
p.fov = p.fov + (target_rad - p.fov) * alpha;

System Integration

Input System Integration

The camera system integrates with the Input System for:

Mouse Input

Keyboard Input

Input Configuration

pub struct InputState {
    pub look: Vec2,              // Mouse input
    pub aim_pressed: bool,       // Aim state
    pub switch_camera_mode_pressed: bool,
    pub side_switch_pressed: bool,
    pub lock_on_pressed: bool,
}

Character System Integration

Movement State Synchronization

Character Movement States

pub struct CharacterMovementState {
    pub current_speed: f32,
    pub is_sprinting: bool,
    pub is_crouching: bool,
    pub is_climbing: bool,
    // ... additional states
}

Physics System Integration

Spatial Query Usage

Collision Handling

Combat System Integration

Target Marking Integration

Target Lock Integration

UI System Integration

Crosshair System

Camera UI Overlays

Audio System Integration

Camera-Based Audio


Usage Patterns

Basic Camera Setup

Player Camera Initialization

// Spawn camera with player tracking
let camera_entity = commands.spawn((
    Camera3d::default(),
    CameraController {
        follow_target: Some(player_entity),
        mode: CameraMode::ThirdPerson,
        distance: 4.0,
        ..default()
    },
    CameraState::default(),
    CameraTargetState::default(),
    CameraBobState::default(),
    Transform::from_xyz(0.0, 5.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y),
)).id();

Advanced Camera Configuration

Custom Camera State

let custom_state = CameraStateInfo {
    name: "Combat Mode".to_string(),
    cam_position_offset: Vec3::new(0.0, 0.0, 0.0),
    pivot_position_offset: Vec3::new(0.5, 1.5, 0.0),
    initial_fov: 50.0,
    max_fov: 80.0,
    lean_enabled: false,
    ..default()
};

camera_controller.states.push(custom_state);

Zone-Based Camera Areas

// Create a stealth zone with different camera behavior
commands.spawn((
    Collider::cuboid(10.0, 5.0, 10.0),
    Transform::from_xyz(0.0, 2.5, 0.0),
    CameraZone {
        settings: CameraZoneSettings {
            mode: CameraMode::FirstPerson,
            distance: Some(1.0),
            fov: Some(70.0),
            pivot_offset: Some(Vec3::new(0.0, 1.8, 0.0)),
            transition_speed: 3.0,
            ..default()
        },
        priority: 10,
    },
));

Cinematic Camera Path

// Create waypoints for a cutscene
let mut waypoints = Vec::new();

// Waypoint 1: Wide shot
let wp1 = commands.spawn((
    Transform::from_xyz(10.0, 8.0, 10.0),
    CameraWaypoint {
        wait_time: 0.0,
        movement_speed: Some(2.0),
        rotation_speed: Some(5.0),
        rotation_mode: WaypointRotationMode::LookAtTarget,
        look_at_target: Some(player_entity),
        ..default()
    },
)).id();
waypoints.push(wp1);

// Waypoint 2: Close-up
let wp2 = commands.spawn((
    Transform::from_xyz(2.0, 2.0, 2.0),
    CameraWaypoint {
        wait_time: 3.0,
        movement_speed: Some(1.0),
        rotation_speed: Some(8.0),
        rotation_mode: WaypointRotationMode::LookAtTarget,
        look_at_target: Some(player_entity),
        ..default()
    },
)).id();
waypoints.push(wp2);

// Create the track
commands.spawn((
    CameraWaypointTrack {
        waypoints,
        loop_track: false,
    },
    CameraWaypointFollower {
        current_track: Some(track_entity),
        current_waypoint_index: 0,
        waiting_timer: 0.0,
        is_moving: false,
    },
));

Camera Shake Triggers

Explosion Shake

// Queue a shake for an explosion
let shake_request = ShakeRequest {
    name: "Explosion".to_string(),
    intensity: 1.5,
    duration: Some(0.8),
};

commands.insert_resource(ShakeQueue(vec![shake_request]));

Point Shake Source

// Create a persistent shake source
commands.spawn((
    Transform::from_xyz(explosion_x, explosion_y, explosion_z),
    PointShake {
        name: "Grenade Explosion".to_string(),
        radius: 15.0,
        intensity: 2.0,
        active: true,
        shake_using_distance: true,
    },
));

Target Lock Integration

Manual Target Selection

// Programmatic target locking
let mut camera_target_state = camera_target_state_query.get_mut(camera_entity).unwrap();
if let Some(target_entity) = find_target_in_crosshair() {
    camera_target_state.locked_target = Some(target_entity);
    camera_target_state.is_locking = true;
}

Target Lock Callbacks

// Listen for target lock events
fn on_target_locked(mut event_reader: EventReader<TargetLockEvent>) {
    for event in event_reader.read() {
        info!("Locked onto target: {:?}", event.target_entity);
        // Trigger UI updates, audio cues, etc.
    }
}

Camera Effect Integration

Dynamic FOV Changes

// Scope aiming effect
let mut camera_state = camera_state_query.get_mut(camera_entity).unwrap();
camera_state.fov_override = Some(25.0); // Sniper scope
camera_state.fov_override_speed = Some(15.0);

Camera Transparency

// Enable camera transparency for nearby objects
commands.insert_resource(TransparencySettings {
    enabled: true,
    alpha_target: 0.3,
    fade_speed: 8.0,
    ray_radius: 0.3,
});

Best Practices

Performance Optimization

Spatial Query Efficiency

// Efficient spatial query usage
let filter = SpatialQueryFilter::from_excluded_entities([player_entity]);
if let Some(hit) = spatial_query.cast_ray(start, direction, max_dist, true, &filter) {
    // Process collision
}

Component Update Optimization

// Optimized query pattern
pub fn optimized_camera_update(
    time: Res<Time>,
    mut camera_query: Query<(&CameraController, &mut CameraState), With<MainCamera>>,
    // ... other filtered queries
) {
    // System implementation
}

Code Organization

Modular Camera States

Organize camera behavior into logical state modules:

pub struct CameraStateModule {
    pub name: String,
    pub enter_fn: fn(&mut CameraController),
    pub update_fn: fn(&mut CameraController, &CameraState, f32),
    pub exit_fn: fn(&mut CameraController),
}

Component Separation

Keep camera concerns separate:

State Management

Smooth Transitions

Always use smooth interpolation for camera movements:

let alpha = 1.0 - (-speed * delta_time).exp();
current_value = current_value + (target_value - current_value) * alpha;

State Persistence

Maintain camera state across scene transitions:

// Save camera state before level change
let saved_state = camera_controller.serialize();

// Restore after level load
camera_controller.deserialize(saved_state);

Input Handling

Input Buffering

Implement input buffering for responsive camera controls:

pub struct CameraInputBuffer {
    pub look_input: Vec2,
    pub buffered_look: Vec2,
    pub input_buffer_time: f32,
}

Sensitivity Scaling

Scale sensitivity appropriately for different frame rates:

let frame_rate_multiplier = 60.0 / actual_frame_rate;
let scaled_sensitivity = base_sensitivity * frame_rate_multiplier;

Collision and Physics

Collision Optimization

// Optimized collision checking
let collision_mask = CollisionGroups::new(
    Group::GROUP_1, // Camera collision group
    Group::GROUP_2 | Group::GROUP_3, // Environment collision groups
);

Transparency Management

Implement efficient transparency sorting:

pub struct TransparencyManager {
    pub sorted_surfaces: Vec<TransparentSurface>,
    pub update_frequency: f32,
    pub last_update_time: f32,
}

Memory Management

Component Pooling

Pool frequently created/destroyed camera components:

pub struct CameraComponentPool {
    pub shake_instances: Vec<CameraShakeInstance>,
    pub target_states: Vec<CameraTargetState>,
    pub available_entities: Vec<Entity>,
}

Resource Management

Properly manage camera resources:

impl Drop for CameraEffectManager {
    fn drop(&mut self) {
        // Cleanup effects, audio, resources
        self.cleanup_active_effects();
        self.stop_all_audio();
    }
}

Testing and Debugging

Camera Debug Visualization

Implement debug visualization for camera state:

#[cfg(debug_assertions)]
pub fn debug_camera_state(
    gizmos: Gizmos,
    camera_query: Query<(&CameraController, &CameraState, &Transform)>,
) {
    for (controller, state, transform) in camera_query.iter() {
        // Draw pivot point
        gizmos.circle(state.current_pivot, 0.2, Color::YELLOW);
        
        // Draw camera frustum
        draw_camera_frustum(gizmos, transform, state.current_distance);
        
        // Draw target lock
        if let Some(target) = state.locked_target {
            draw_target_lock(gizmos, target, Color::RED);
        }
    }
}

Logging and Metrics

Implement comprehensive logging:

pub struct CameraMetrics {
    pub frame_time: f32,
    pub spatial_queries_per_frame: u32,
    pub collision_checks_per_frame: u32,
    pub active_zones: u32,
    pub active_effects: u32,
}

Troubleshooting

Common Issues and Solutions

Camera Jitter or Stuttering

Symptoms:

Possible Causes:

Solutions:

// Increase smoothing speeds
camera.smooth_follow_speed = 20.0;
camera.smooth_rotation_speed = 25.0;
camera.pivot_smooth_speed = 15.0;

// Check system ordering
.add_systems(Update, (
    update_camera_state_offsets,
    update_target_marking,
    update_target_lock,
).chain())

// Optimize spatial queries
let filter = SpatialQueryFilter::from_excluded_entities([player_entity]);

Camera Collision Issues

Symptoms:

Possible Causes:

Solutions:

// Adjust collision settings
camera.use_collision = true;
camera.collision_radius = 0.3;

// Verify spatial query setup
let direction = transform.back(); // Ensure correct direction
let max_dist = state.current_distance;

// Check collision layers
let filter = SpatialQueryFilter::default();
// Ensure proper collision groups

Target Lock Problems

Symptoms:

Possible Causes:

Solutions:

// Adjust target lock settings
camera.target_lock.max_distance = 50.0;
camera.target_lock.fov_threshold = 60.0;
camera.target_lock.scan_radius = 3.0;

// Verify target components
for (entity, target_gt, health, name) in target_query.iter() {
    if health.current <= 0.0 { continue; } // Ensure health > 0
    // Check other required components
}

FOV Transition Issues

Symptoms:

Possible Causes:

Solutions:

// Increase FOV transition speed
camera.fov_speed = 15.0;

// Clear existing overrides
state.fov_override = None;

// Ensure projection component exists
if let Projection::Perspective(ref mut p) = *projection {
    // FOV updates should work correctly
}

Zone Transition Problems

Symptoms:

Possible Causes:

Solutions:

// Check zone collision setup
commands.spawn((
    Collider::cuboid(10.0, 5.0, 10.0), // Ensure proper collider
    CameraZone { /* ... */ },
));

// Adjust priority and transition speed
CameraZone {
    priority: 10, // Higher priority
    settings: CameraZoneSettings {
        transition_speed: 10.0, // Faster transitions
        // ...
    }
}

Performance Issues

Symptoms:

Possible Causes:

Solutions:

// Optimize queries
Query<(&CameraController, &mut CameraState), With<MainCamera>>

// Use query filtering
Query<&Transform, (With<CameraController>, Without<Player>)>

// Implement query caching
fn system_with_cached_query(
    cached_transforms: QueryCache<(&Transform, &CameraController)>,
    // ...
) {
    // Use cached results
}

Debug Techniques

Camera State Debugging

Enable Debug Visualization:

#[cfg(debug_assertions)]
fn debug_camera_systems(
    mut commands: Commands,
    camera_query: Query<(&CameraController, &CameraState)>,
) {
    for (controller, state) in camera_query.iter() {
        println!("Camera Mode: {:?}", controller.mode);
        println!("Distance: {}", state.current_distance);
        println!("Pivot: {:?}", state.current_pivot);
        println!("Yaw: {}, Pitch: {}", state.yaw, state.pitch);
    }
}

Spatial Query Debugging

Visualize Spatial Queries:

fn debug_spatial_queries(
    spatial_query: SpatialQuery,
    gizmos: Gizmos,
    camera_query: Query<(&CameraState, &Transform)>,
) {
    for (state, transform) in camera_query.iter() {
        // Draw collision ray
        let direction = transform.back();
        gizmos.ray(
            state.current_pivot,
            direction * state.current_distance,
            Color::RED,
        );
    }
}

Performance Profiling

Frame Timing Analysis:

struct CameraProfiler {
    last_frame_time: Instant,
    frame_times: Vec<f32>,
}

fn profile_camera_performance(
    mut profiler: ResMut<CameraProfiler>,
    time: Res<Time>,
) {
    let frame_time = time.delta_secs();
    profiler.frame_times.push(frame_time);
    
    if profiler.frame_times.len() > 100 {
        let avg_frame_time: f32 = profiler.frame_times.iter().sum::<f32>() / 100.0;
        println!("Average camera frame time: {:.3}ms", avg_frame_time * 1000.0);
        profiler.frame_times.clear();
    }
}

Integration Issues

Input System Integration

Common Problems:

Debug Steps:

fn debug_input_integration(
    input: Res<InputState>,
    mut camera_query: Query<&mut CameraController>,
) {
    println!("Look input: {:?}", input.look);
    println!("Aim pressed: {}", input.aim_pressed);
    
    for mut controller in camera_query.iter_mut() {
        println!("3P Sensitivity: {}", controller.rot_sensitivity_3p);
        println!("1P Sensitivity: {}", controller.rot_sensitivity_1p);
    }
}

Physics Integration

Common Problems:

Debug Steps:

fn debug_physics_integration(
    spatial_query: SpatialQuery,
    gizmos: Gizmos,
    camera_query: Query<(&CameraState, &Transform)>,
) {
    for (state, transform) in camera_query.iter() {
        // Visualize raycast
        let ray_origin = state.current_pivot;
        let ray_direction = transform.back();
        let ray_length = state.current_distance;
        
        gizmos.ray(ray_origin, ray_direction * ray_length, Color::BLUE);
        
        // Test actual collision
        if let Some(hit) = spatial_query.cast_ray(
            ray_origin,
            ray_direction,
            ray_length,
            true,
            &SpatialQueryFilter::default()
        ) {
            gizmos.circle(hit.point, 0.1, Color::GREEN);
        }
    }
}

Advanced Troubleshooting

Memory Issues

Detection:

Investigation:

fn debug_memory_usage(
    entities: Res<Entities>,
    camera_shakes: Query<&CameraShakeInstance>,
) {
    let active_shakes = camera_shakes.iter().count();
    let total_entities = entities.iter().count();
    
    println!("Active camera shakes: {}", active_shakes);
    println!("Total entities: {}", total_entities);
    
    if active_shakes > 100 {
        warn!("High number of active camera shakes!");
    }
}

System Conflicts

Detection:

Investigation:

fn debug_system_conflicts(
    system_order: Res<SystemExecutionOrder>,
) {
    for (system_name, order) in system_order.iter() {
        println!("System '{}' runs at order {}", system_name, order);
    }
}

// Check for conflicting updates
fn check_component_updates(
    camera_query: Query<&CameraController>,
    previous_states: Query<&CameraController>,
) {
    // Compare states to detect unexpected changes
}

Performance Monitoring

Real-Time Metrics

Implementation:

struct CameraPerformanceMetrics {
    spatial_queries_per_frame: HashMap<String, u32>,
    component_updates_per_frame: HashMap<String, u32>,
    memory_usage_per_frame: f32,
}

fn collect_performance_metrics(
    mut metrics: ResMut<CameraPerformanceMetrics>,
    spatial_queries: Query<(&SpatialQuery, &CameraController)>,
) {
    metrics.spatial_queries_per_frame.insert(
        "spatial_query_count".to_string(),
        spatial_queries.iter().count() as u32,
    );
}

Historical Analysis

Data Collection:

struct CameraMetricsHistory {
    frame_time_history: Vec<f32>,
    spatial_query_history: Vec<u32>,
    max_history_size: usize,
}

fn update_metrics_history(
    mut history: ResMut<CameraMetricsHistory>,
    current_metrics: &CameraPerformanceMetrics,
) {
    history.frame_time_history.push(current_metrics.avg_frame_time);
    history.spatial_query_history.push(current_metrics.spatial_queries);
    
    if history.frame_time_history.len() > history.max_history_size {
        history.frame_time_history.remove(0);
    }
}

Conclusion

The Camera System provides a comprehensive, modular solution for 3D game camera management in Bevy. With its extensive feature set, performance optimizations, and integration capabilities, it serves as a robust foundation for various game genres and camera requirements.

Key Strengths

Future Enhancements

The system is designed for extensibility, with potential future additions including:

Getting Started

  1. Basic Setup: Add the Camera Plugin to your Bevy application
  2. Configure Controller: Set up CameraController with desired parameters
  3. Add Components: Include CameraState and related components
  4. Test Integration: Verify input, physics, and character system integration
  5. Customize Features: Enable specific camera features based on game needs

The Camera System documentation provides the foundation for implementing sophisticated camera behaviors in your Bevy-based game projects, with the flexibility to adapt to diverse gameplay requirements and performance constraints.


This documentation covers the Camera System as of the latest version. For updates and additional resources, refer to the main project repository and related documentation.