Files
Space-Game/apps/game/src/gameplay/in_system/operations.rs
francy51 98c2ba59df feat(gameplay): implement in-system gameplay with camera modes and flight controls
Add comprehensive in-system gameplay features including:

Camera System:
- Orbit mode for galaxy/inspection views
- Follow mode for tracking player ship during flight
- Cinematic mode for docked/cutscene views
- Smooth interpolation and orbit controls

In-System Gameplay:
- Docked state at stations with undock functionality
- Flight mode with velocity and target-based navigation
- Point-and-click movement via ground plane projection
- Target selection system for POIs

Flight Controls:
- Flight state tracking with speed monitoring
- Automatic camera transitions between modes
- Flight HUD with speed indicator and status panel
- Contextual action system for approach/dock/mining

UI Updates:
- Docked station panel with system information
- Flight mode controls and hints
- Dynamic population display

This implementation provides the foundation for tactical
space gameplay with smooth camera transitions and
intuitive point-and-click navigation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 20:02:19 -04:00

177 lines
4.9 KiB
Rust

//! Timed operation system for tactical navigation.
//!
//! Handles operations with durations like undocking, travel, docking, and mining.
//! Operations have progress tracking and fire completion events when done.
use bevy::prelude::*;
/// Active operation with timing information.
#[derive(Component, Debug, Clone)]
pub struct ActiveOperation {
pub kind: OperationKind,
pub started_at: f64,
pub duration_ms: f64,
pub target_name: String,
}
/// Kinds of operations that can be active.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OperationKind {
Undocking,
Travel,
Docking,
Mining,
Refining,
Fitting,
Combat,
}
/// Event fired when an operation completes.
#[derive(Event, Debug, Clone)]
pub struct OperationCompletedEvent {
pub kind: OperationKind,
pub entity: Entity,
}
/// Event fired when an operation is started.
#[derive(Event, Debug)]
pub struct OperationStartedEvent {
pub kind: OperationKind,
pub duration_ms: f64,
pub target_name: String,
}
/// Resource for operation duration constants.
#[derive(Resource, Debug, Clone)]
pub struct OperationDurations {
pub undock: f64,
pub local_travel: f64,
pub docking: f64,
pub mining: f64,
}
impl Default for OperationDurations {
fn default() -> Self {
Self {
undock: 3000.0, // 3 seconds
local_travel: 5000.0, // 5 seconds
docking: 4000.0, // 4 seconds
mining: 8000.0, // 8 seconds
}
}
}
/// Plugin for timed operation system.
pub struct TimedOperationPlugin;
impl Plugin for TimedOperationPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<OperationDurations>()
.add_event::<OperationCompletedEvent>()
.add_event::<OperationStartedEvent>()
.add_systems(
Update,
(
monitor_operations,
update_operation_progress,
).run_if(in_state(crate::state::AppState::InGame)),
);
}
}
/// Monitor active operations and fire completion events when done.
fn monitor_operations(
time: Res<Time>,
mut commands: Commands,
mut query: Query<(Entity, &mut ActiveOperation)>,
mut completed_events: EventWriter<OperationCompletedEvent>,
durations: Res<OperationDurations>,
) {
let now = time.elapsed_secs_f64() * 1000.0;
for (entity, mut operation) in query.iter_mut() {
let elapsed = now - operation.started_at;
if elapsed >= operation.duration_ms {
bevy::log::info!("Operation completed: {:?}", operation.kind);
// Fire completion event
completed_events.write(OperationCompletedEvent {
kind: operation.kind,
entity,
});
// Remove the operation component
commands.entity(entity).remove::<ActiveOperation>();
}
}
}
/// Update operation progress for UI display.
/// This updates any Progress components attached to operation entities.
fn update_operation_progress(
time: Res<Time>,
mut query: Query<(&ActiveOperation, &mut Progress)>,
) {
let now = time.elapsed_secs_f64() * 1000.0;
for (operation, mut progress) in query.iter_mut() {
let elapsed = now - operation.started_at;
let progress_value = (elapsed / operation.duration_ms).clamp(0.0, 1.0);
progress.value = progress_value as f32;
}
}
/// Start an undocking operation on the player ship.
pub fn start_undocking(
commands: &mut Commands,
player_entity: Entity,
durations: &OperationDurations,
mut events: &mut EventWriter<OperationStartedEvent>,
) {
commands.entity(player_entity).insert(ActiveOperation {
kind: OperationKind::Undocking,
started_at: 0.0, // Will be set by the system
duration_ms: durations.undock,
target_name: "Undocking".to_string(),
});
events.write(OperationStartedEvent {
kind: OperationKind::Undocking,
duration_ms: durations.undock,
target_name: "Undocking".to_string(),
});
}
/// Start a travel operation.
pub fn start_travel(
commands: &mut Commands,
player_entity: Entity,
target_name: String,
durations: &OperationDurations,
mut events: &mut EventWriter<OperationStartedEvent>,
) {
commands.entity(player_entity).insert(ActiveOperation {
kind: OperationKind::Travel,
started_at: 0.0,
duration_ms: durations.local_travel,
target_name: target_name.clone(),
});
events.write(OperationStartedEvent {
kind: OperationKind::Travel,
duration_ms: durations.local_travel,
target_name,
});
}
/// Progress bar component for showing operation progress.
#[derive(Component, Debug, Clone)]
pub struct Progress {
pub value: f32,
}
/// Marker for operation progress UI entities.
#[derive(Component)]
pub struct OperationProgressUi;