Add galaxy parameter UI, star selection, and movement/physics scaffolding

Galaxy creation scene (Bevy 0.16):
- Split into module folder: params.rs, mod.rs (generation + spawn), ui.rs,
  selection.rs
- GalaxyParams resource (seed, count, arms, vertical_arms, size, twist,
  vertical_twist) with generation counter for change detection
- Control panel: 7 +/- slider rows + Regenerate button, no native Bevy slider
  widget so uses label + icon buttons
- Info panel: live-refreshes on selection change via despawn_related::<Children>
- Click-to-select: screen-space picking (project each star to viewport, closest
  within 18px threshold wins); selected star lerps scale to 2.2x
- Generation faithfully ports the docs TS reference including vertical arms
- Regeneration system: despawns GalaxyScene root only, preserves UI panels

Camera:
- Camera2d -> Camera3d + OrbitCamera (left-drag yaw/pitch, scroll zoom,
  pitch/distance clamped to avoid gimbal)
- Orbit drag suppressed when cursor over UI

New plugins (scaffolding):
- movement/: Velocity, MaxSpeed, TurnRate, Drag, MoveTarget, Player components
  + click-to-move (no player spawned yet)
- physics/: pure-data geometry (ray_vs_sphere, overlaps, separate,
  segment_vs_sphere) with 7 passing unit tests; no systems wired yet
- star_map/: plugin skeleton gated on AppState::InGame

Shared:
- ui/util.rs: cursor_over_ui helper for UI-hover detection
- docs: ARCH-9 decision record (custom movement & collision, no physics engine)
This commit is contained in:
2026-06-04 12:29:33 -04:00
parent a7796a1394
commit c14f684b09
20 changed files with 1798 additions and 23 deletions

View File

@@ -0,0 +1,52 @@
use bevy::prelude::*;
/// Which plane the orbit lies on.
#[derive(Debug, Clone, Copy, Default)]
pub enum OrbitPlane {
/// XZ plane (Y up). Typical for planets around a star viewed from above.
#[default]
Horizontal,
/// XY plane (Z up). Useful for UI elements or top-down 2D-style orbits.
Vertical,
}
/// An entity that orbits around its parent's origin.
/// Attach as a child of the orbit center; local Transform is updated each frame.
#[derive(Component, Debug, Clone, Copy)]
pub struct Orbit {
pub angle: f32,
pub angular_velocity: f32,
pub radius: f32,
pub plane: OrbitPlane,
}
impl Default for Orbit {
fn default() -> Self {
Self {
angle: 0.0,
angular_velocity: 0.5,
radius: 10.0,
plane: OrbitPlane::Horizontal,
}
}
}
/// Advance each Orbit's angle and recompute local translation.
/// The orbit center is the parent entity (via Bevy's parent-child hierarchy).
pub fn update_orbits(
mut query: Query<(&mut Orbit, &mut Transform)>,
time: Res<Time>,
) {
let dt = time.delta_secs();
for (mut orbit, mut transform) in &mut query {
orbit.angle += orbit.angular_velocity * dt;
let (sin, cos) = orbit.angle.sin_cos();
let (x, y, z) = match orbit.plane {
OrbitPlane::Horizontal => (cos * orbit.radius, 0.0, sin * orbit.radius),
OrbitPlane::Vertical => (cos * orbit.radius, sin * orbit.radius, 0.0),
};
transform.translation.x = x;
transform.translation.y = y;
transform.translation.z = z;
}
}