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>
177 lines
4.9 KiB
Rust
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;
|