Rebuild the camera around a single persistent MainCamera and the Camera System design-doc model: two framing modes (Orbit = inspection/ docked tactical, Follow = track the ship) plus Cinematic as a boolean overlay (free rotation + HUD hide + live gameplay), not a third mode. Critical fixes (gap analysis A1-A3): - A1: scenes now *reconfigure* the one startup camera instead of spawning a second one; despawn_in_system_scene no longer destroys MainCamera, so the session never loses its camera. .single_mut() on MainCamera now succeeds during flight. - A2: Cinematic is a real overlay — toggle (KeyC), free-look rotation in any framing, HUD hidden while active, gameplay keeps running. - A3: removed dead FollowCamera component + setup_follow_camera; tracking is unified in track_camera_target. Gaps B1-B6: - B1: adopted doc model (Cinematic overlay, not exclusive mode). - B2: canonical isometric tactical_rotation() baseline. - B3: smooth reframing via OrbitFocusGoal exponential-damp tween. - B4: non-zero CameraState defaults. - B5: consolidated the three orbit-control impls into one (dropped the starting_base local control + its Euler variant). - B6: track_camera_target keeps OrbitCamera.target synced to the focus entity every frame. Docked view now frames the actual station at a tactical iso distance. cargo check + clippy clean for all newly-authored code; net -10 lines (more dead code removed than added). 42 tests pass.
100 lines
2.7 KiB
Rust
100 lines
2.7 KiB
Rust
//! Starting base selection scene.
|
|
//!
|
|
//! After character creation, the player chooses a starting base from generated
|
|
//! outer-galaxy systems. The choice is kept in a resource until persistence is
|
|
//! wired into the game client.
|
|
|
|
mod scene;
|
|
mod ui;
|
|
|
|
use bevy::prelude::*;
|
|
|
|
use crate::gameplay::galaxy::{StartingBaseCandidate, orbits};
|
|
use crate::state::AppState;
|
|
|
|
// Public exports for POI spawning
|
|
pub use scene::{SpawnedPoiSystem, StartingBasePoi};
|
|
|
|
pub struct StartingBasePlugin;
|
|
|
|
impl Plugin for StartingBasePlugin {
|
|
fn build(&self, app: &mut App) {
|
|
app.init_resource::<StartingBaseDraft>()
|
|
.init_resource::<scene::SpawnedPoiSystem>()
|
|
.add_systems(
|
|
OnEnter(AppState::StartingBaseSelection),
|
|
(scene::setup_starting_base_scene, ui::setup_starting_base_ui).chain(),
|
|
)
|
|
.add_systems(
|
|
OnExit(AppState::StartingBaseSelection),
|
|
(despawn_starting_base_ui, scene::despawn_pois_on_exit).chain(),
|
|
)
|
|
.add_systems(
|
|
Update,
|
|
(
|
|
escape_to_character_creation,
|
|
ui::candidate_button_handler,
|
|
scene::focus_starting_base_camera,
|
|
scene::animate_starting_base_selection,
|
|
ui::scroll_starting_base_panels,
|
|
ui::refresh_starting_base_ui,
|
|
ui::action_button_handler,
|
|
scene::spawn_selected_pois,
|
|
orbits::advance_orbital_paths,
|
|
)
|
|
.chain()
|
|
.run_if(in_state(AppState::StartingBaseSelection)),
|
|
);
|
|
}
|
|
}
|
|
|
|
#[derive(Resource, Default)]
|
|
pub struct StartingBaseDraft {
|
|
pub candidates: Vec<StartingBaseCandidate>,
|
|
pub selected_index: Option<usize>,
|
|
}
|
|
|
|
#[derive(Resource, Debug, Clone)]
|
|
pub struct StartingBaseSelection {
|
|
pub system_id: String,
|
|
pub system_name: String,
|
|
pub faction: &'static str,
|
|
pub security: f32,
|
|
}
|
|
|
|
#[derive(Resource, Debug, Clone, Copy)]
|
|
pub struct StartingBaseFocusRequest {
|
|
pub candidate_index: usize,
|
|
}
|
|
|
|
#[derive(Component)]
|
|
pub struct StartingBaseSpawned;
|
|
|
|
#[derive(Component)]
|
|
pub struct StartingBaseInputBlocker;
|
|
|
|
#[derive(Component, Clone, Copy)]
|
|
pub enum StartingBaseButton {
|
|
Candidate(usize),
|
|
Confirm,
|
|
Back,
|
|
}
|
|
|
|
fn despawn_starting_base_ui(
|
|
mut commands: Commands,
|
|
query: Query<Entity, With<StartingBaseSpawned>>,
|
|
) {
|
|
for entity in &query {
|
|
commands.entity(entity).despawn();
|
|
}
|
|
}
|
|
|
|
fn escape_to_character_creation(
|
|
keys: Res<ButtonInput<KeyCode>>,
|
|
mut next_state: ResMut<NextState<AppState>>,
|
|
) {
|
|
if keys.just_pressed(KeyCode::Escape) {
|
|
next_state.set(AppState::CharacterCreation);
|
|
}
|
|
}
|