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>
This commit is contained in:
2026-06-15 20:02:19 -04:00
parent 07316dbcd7
commit 98c2ba59df
14 changed files with 1338 additions and 43 deletions

View File

@@ -4,8 +4,13 @@
//! within their selected starting system. This is the entry point to actual
//! gameplay after onboarding.
mod actions;
mod docked;
mod flight;
mod flight_ui;
mod operations;
mod scene;
mod target;
mod ui;
use bevy::prelude::*;
@@ -13,7 +18,11 @@ use bevy::prelude::*;
use crate::state::AppState;
pub use docked::{DockedState, UndockEvent};
pub use flight::{FlightState, FlightControlsPlugin};
pub use scene::ActiveSystem;
pub use target::{Targetable, TargetKind, SelectedTarget, TargetSelectionPlugin};
pub use actions::{ContextualActionPlugin, ActionType, ActionTriggeredEvent};
pub use operations::{TimedOperationPlugin, OperationKind, ActiveOperation};
pub struct InSystemPlugin;
@@ -22,14 +31,23 @@ impl Plugin for InSystemPlugin {
app.init_resource::<DockedState>()
.init_resource::<ActiveSystem>()
.add_event::<UndockEvent>()
.add_plugins(FlightControlsPlugin)
.add_plugins(TargetSelectionPlugin)
.add_plugins(ContextualActionPlugin)
.add_plugins(TimedOperationPlugin)
.add_systems(
OnEnter(AppState::InGame),
(scene::setup_in_system_view, ui::setup_docked_ui).chain(),
(
scene::setup_in_system_view,
ui::setup_docked_ui,
add_targetable_to_pois,
).chain(),
)
.add_systems(
OnExit(AppState::InGame),
(
ui::despawn_docked_ui,
flight_ui::despawn_flight_ui,
scene::despawn_in_system_scene,
).chain(),
)
@@ -38,9 +56,78 @@ impl Plugin for InSystemPlugin {
(
ui::refresh_docked_ui,
ui::undock_button_handler,
flight_ui::update_flight_ui,
handle_action_triggered,
)
.chain()
.run_if(in_state(AppState::InGame)),
);
}
}
/// Handle action triggered events from the action buttons.
fn handle_action_triggered(
mut commands: Commands,
mut events: EventReader<ActionTriggeredEvent>,
player_query: Query<Entity, With<scene::PlayerShip>>,
durations: Res<operations::OperationDurations>,
mut operation_events: EventWriter<operations::OperationStartedEvent>,
selected_target_query: Query<&SelectedTarget, With<scene::PlayerShip>>,
) {
let Ok(player_entity) = player_query.single() else {
return;
};
for event in events.read() {
bevy::log::info!("Action triggered: {:?}", event.action_type);
match event.action_type {
ActionType::Undock => {
operations::start_undocking(&mut commands, player_entity, &durations, &mut operation_events);
}
ActionType::Approach => {
// Get selected target
if let Ok(selected) = selected_target_query.single() {
operations::start_travel(&mut commands, player_entity, selected.name.clone(), &durations, &mut operation_events);
}
}
ActionType::Dock => {
// TODO: Implement docking operation
bevy::log::info!("Dock action triggered");
}
ActionType::StartMining => {
// TODO: Implement mining operation
bevy::log::info!("Start mining action triggered");
}
_ => {
bevy::log::info!("Other action: {:?}", event.action_type);
}
}
}
}
/// Add Targetable components to spawned POIs (stations and asteroid belts)
/// so they can be selected by the target selection system.
fn add_targetable_to_pois(
mut commands: Commands,
station_query: Query<(Entity, &crate::gameplay::galaxy::Identifiable), (With<crate::gameplay::galaxy::Station>, Without<Targetable>)>,
belt_query: Query<(Entity, &crate::gameplay::galaxy::Identifiable), (With<crate::gameplay::galaxy::AsteroidBelt>, Without<Targetable>)>,
) {
// Add Targetable to stations
for (entity, identifiable) in station_query.iter() {
bevy::log::debug!("Adding Targetable component to station: {}", identifiable.display_name);
commands.entity(entity).insert(Targetable {
kind: TargetKind::Station,
name: identifiable.display_name.clone(),
});
}
// Add Targetable to asteroid belts
for (entity, identifiable) in belt_query.iter() {
bevy::log::debug!("Adding Targetable component to asteroid belt: {}", identifiable.display_name);
commands.entity(entity).insert(Targetable {
kind: TargetKind::AsteroidBelt,
name: identifiable.display_name.clone(),
});
}
}