From 2aca53eec8059982fcc6b2af3bcc1b57621e6abf Mon Sep 17 00:00:00 2001 From: ghostly_zsh Date: Thu, 27 Nov 2025 15:30:17 -0600 Subject: [PATCH] feat: starguide camera rendering --- crates/unified/src/client/mod.rs | 7 +++- crates/unified/src/client/parts.rs | 3 +- .../src/client/planet/incoming_planets.rs | 2 + crates/unified/src/client/rendering/mod.rs | 11 ++++-- crates/unified/src/client/starfield.rs | 5 ++- crates/unified/src/client/starguide.rs | 17 ++++++++ crates/unified/src/client/ui.rs | 11 ++++-- crates/unified/src/client/zoom.rs | 39 ++++++++++++++----- crates/unified/src/ecs.rs | 10 ++++- 9 files changed, 84 insertions(+), 21 deletions(-) create mode 100644 crates/unified/src/client/starguide.rs diff --git a/crates/unified/src/client/mod.rs b/crates/unified/src/client/mod.rs index 6d6a5c2565aa789ce37f4e7a830500d030599ce5..ac2776d2fbf3967296fd85adef75ba0b7c9c5e20 100644 --- a/crates/unified/src/client/mod.rs +++ b/crates/unified/src/client/mod.rs @@ -4,13 +4,14 @@ use crate::client::planet::indicators::indicators_plugin; use crate::client::starfield::starfield_plugin; use crate::client::ui::ui_plugin; use crate::client::zoom::zoom_plugin; +use crate::client::starguide::starguide_plugin; use crate::ecs::{Hi, Part, Player}; use aeronet_websocket::client::WebSocketClient; use bevy::dev_tools::picking_debug::DebugPickingMode; use crate::prelude::*; use planet::incoming_planets::incoming_planets_plugin; use crate::client::ship::attachment::client_attachment_plugin; -use crate::ecs::Me; +use crate::ecs::{Me, STARGUIDE_LAYER}; pub mod colors; pub mod key_input; @@ -24,6 +25,7 @@ pub mod zoom; pub mod ship; pub mod rendering; pub mod input; +pub mod starguide; pub struct ClientPlugin { pub server: Option, @@ -53,6 +55,7 @@ impl Plugin for ClientPlugin { .add_plugins(ui_plugin) .add_plugins(zoom_plugin) .add_plugins(client_attachment_plugin) + .add_plugins(starguide_plugin) .insert_resource(DebugPickingMode::Disabled); // These are only needed if we're actually doing network things @@ -76,7 +79,7 @@ fn find_me( info!("^^^^^^^^^^^ IGNORE THESE WARNINGS ^^^^^^^^^^^^^^"); info!("they are normal! and are from the world state being replicated as it is sent over the network"); info!(?msg, "finding me: got hello from server"); - commands.entity(msg.you_are).insert(Me); + commands.entity(msg.you_are).insert(Me).insert(STARGUIDE_LAYER); /*let mut heart_sprite = Sprite::from_image(asset_server.load("sprites/hearty_heart.png")); diff --git a/crates/unified/src/client/parts.rs b/crates/unified/src/client/parts.rs index d8ccd947b8865007205fe78b55a9a7f063cbacf4..c6a4d03240e8fcadb8c0949e9e9b0d104c080828 100644 --- a/crates/unified/src/client/parts.rs +++ b/crates/unified/src/client/parts.rs @@ -3,7 +3,7 @@ use std::f32::consts::PI; use crate::attachment::{Joint, JointOf, Joints, PartInShip, Peer, SnapOf, SnapOfJoint}; use crate::ecs::Me; use crate::client::colors::GREEN; -use crate::ecs::{DragRequestEvent, Part}; +use crate::ecs::{DragRequestEvent, Part, MAIN_LAYER}; use crate::client::input::CursorWorldCoordinates; use bevy::color::palettes::css::{ORANGE, PURPLE, RED, YELLOW}; use crate::client::ship::attachment::AttachmentDebugRes; @@ -42,6 +42,7 @@ fn handle_incoming_parts( commands .entity(new_entity) + .insert(MAIN_LAYER) .insert(sprite) .insert(Pickable::default()) .observe(on_part_click); diff --git a/crates/unified/src/client/planet/incoming_planets.rs b/crates/unified/src/client/planet/incoming_planets.rs index cd75f9b32ab315bc57c81f2bdfb501a3403e1f72..6c387e395256d83ed22744c04913d47cbf315ec9 100644 --- a/crates/unified/src/client/planet/incoming_planets.rs +++ b/crates/unified/src/client/planet/incoming_planets.rs @@ -1,5 +1,6 @@ use crate::config::planet::{Planet, SpecialSpriteProperties}; use crate::prelude::*; +use crate::ecs::{MAIN_STAR_LAYERS}; pub fn incoming_planets_plugin(app: &mut App) { app.add_systems(Update, (handle_incoming_planets, handle_updated_planets)); @@ -22,6 +23,7 @@ fn handle_incoming_planets( commands //.insert(AdditionalMassProperties::Mass(new_planet.mass)) + .insert(MAIN_STAR_LAYERS.clone()) .insert(sprite); trace!(?new_planet, "prepared new planet"); diff --git a/crates/unified/src/client/rendering/mod.rs b/crates/unified/src/client/rendering/mod.rs index 881b1eb7fbd29c0aacd2cda1188f113694b03dd7..b1bdd091a54b80d35f454163b4c740d678832850 100644 --- a/crates/unified/src/client/rendering/mod.rs +++ b/crates/unified/src/client/rendering/mod.rs @@ -2,7 +2,7 @@ use bevy::anti_alias::fxaa::Fxaa; use bevy::app::{App, Startup}; use bevy::core_pipeline::tonemapping::DebandDither; use bevy::post_process::bloom::Bloom; -use crate::ecs::{MainCamera, Me}; +use crate::ecs::{MainCamera, StarguideCamera, Me, MAIN_LAYER}; use crate::prelude::*; pub fn render_plugin(app: &mut App) { @@ -12,13 +12,14 @@ pub fn render_plugin(app: &mut App) { } -fn setup_graphics(mut commands: Commands) { +pub fn setup_graphics(mut commands: Commands) { commands .spawn(Camera2d) .insert(Camera { clear_color: ClearColorConfig::Custom(Color::BLACK), ..default() }) + .insert(MAIN_LAYER) .insert(Bloom::default()) .insert(DebandDither::Enabled) .insert(Fxaa::default()) @@ -27,11 +28,15 @@ fn setup_graphics(mut commands: Commands) { fn follow_camera( mut camera: Query<&mut Transform, (With, Without)>, + mut starguide_camera: Query<&mut Transform, (With, Without, Without)>, player: Query<&Transform, With>, ) { let mut camera = camera.single_mut().unwrap(); + let mut starguide_camera = starguide_camera.single_mut().unwrap(); let Ok(player) = player.single() else { return; }; camera.translation = player.translation; -} \ No newline at end of file + starguide_camera.translation = player.translation; + +} diff --git a/crates/unified/src/client/starfield.rs b/crates/unified/src/client/starfield.rs index 2d413da2b7ff73ce2704e5cc248eaa0a0752d07a..7043cde5132e13184d27450cab571961c978b2aa 100644 --- a/crates/unified/src/client/starfield.rs +++ b/crates/unified/src/client/starfield.rs @@ -18,7 +18,7 @@ use bevy::{ use crate::{ ecs::Me, - ecs::{MainCamera, StarfieldBack, StarfieldFront, StarfieldMid}, + ecs::{MainCamera, MAIN_LAYER, STARGUIDE_LAYER, StarfieldBack, StarfieldFront, StarfieldMid}, }; pub const BACK_STARFIELD_SIZE: f32 = 256.0; @@ -54,6 +54,7 @@ pub fn set_up_starfield( }, ..Default::default() }) + .insert(MAIN_LAYER) .insert(Transform::from_xyz(0.0, 0.0, 5.0)) .insert(Visibility::Inherited) .insert(StarfieldBack); @@ -68,6 +69,7 @@ pub fn set_up_starfield( }, ..Default::default() }) + .insert(MAIN_LAYER) .insert(Transform::from_xyz(0.0, 0.0, 4.5)) .insert(Visibility::Inherited) .insert(StarfieldMid); @@ -82,6 +84,7 @@ pub fn set_up_starfield( }, ..Default::default() }) + .insert(MAIN_LAYER) .insert(Transform::from_xyz(0.0, 0.0, 4.0)) .insert(Visibility::Inherited) .insert(StarfieldFront); diff --git a/crates/unified/src/client/starguide.rs b/crates/unified/src/client/starguide.rs new file mode 100644 index 0000000000000000000000000000000000000000..60c365cfbb7288a5beb8ea3884f19a10cf46ad5e --- /dev/null +++ b/crates/unified/src/client/starguide.rs @@ -0,0 +1,17 @@ +use crate::prelude::*; +use crate::ecs::{StarguideCamera, STARGUIDE_LAYER}; +use crate::config::planet::SpecialSpriteProperties; +use crate::config::planet::Planet; + +pub fn starguide_plugin(app: &mut App) { + app.add_systems(Startup, init_starguide); +} + +pub fn init_starguide(mut commands: Commands) { + commands.spawn((Camera2d::default(), Camera { + is_active: false, + ..default() + })) + .insert(STARGUIDE_LAYER) + .insert(StarguideCamera); +} diff --git a/crates/unified/src/client/ui.rs b/crates/unified/src/client/ui.rs index 141c9d12972e86a1db8cc0b5ec6460b77e76b957..0a9ee3b9eb9aea9c7fcf81c238bbaed0c4953495 100644 --- a/crates/unified/src/client/ui.rs +++ b/crates/unified/src/client/ui.rs @@ -2,21 +2,25 @@ use crate::prelude::*; use crate::{ client::colors, - ecs::{FuelText, Player, PlayerStorage, PowerText}, + ecs::{FuelText, Player, PlayerStorage, PowerText, MainCamera, MAIN_LAYER}, }; +use crate::client::rendering::setup_graphics; pub fn ui_plugin(app: &mut App) { - app.add_systems(Startup, setup_ui) + app.add_systems(Startup, setup_ui.after(setup_graphics)) .add_systems(Update, update_ui); } -fn setup_ui(mut commands: Commands) { +fn setup_ui(camera: Single, With)>, mut commands: Commands) { let ui_id = commands.spawn(( + UiTargetCamera(camera.into_inner()), Node { width: Val::Percent(100.0), height: Val::Percent(100.0), ..Default::default() }, + Transform::from_xyz(0.0, 0.0, 25.0), + MAIN_LAYER, children![( Node { display: Display::Flex, @@ -27,6 +31,7 @@ fn setup_ui(mut commands: Commands) { right: Val::Px(5.0), ..Default::default() }, + MAIN_LAYER, BorderRadius::all(Val::Px(5.0)), BackgroundColor(colors::MANTLE), children![ diff --git a/crates/unified/src/client/zoom.rs b/crates/unified/src/client/zoom.rs index 30214682d9b8c9db60033a7fd1d376ff114ec8d4..6b45e08f397fbef4160b345005fb4bc596172dbb 100644 --- a/crates/unified/src/client/zoom.rs +++ b/crates/unified/src/client/zoom.rs @@ -6,6 +6,7 @@ use bevy::{ use crate::{ client::starfield::{BACK_STARFIELD_SIZE, FRONT_STARFIELD_SIZE, MID_STARFIELD_SIZE, StarfieldSize}, ecs::{MainCamera, Me, StarfieldBack, StarfieldFront, StarfieldMid} }; +use crate::ecs::StarguideCamera; pub fn zoom_plugin(app: &mut App) { app.add_systems(Update, on_scroll); @@ -38,10 +39,22 @@ fn on_scroll( Without, ), >, + mut starguide_camera: Single< + (&mut Camera, &mut Transform), + ( + With, + Without, + Without, + Without, + Without, + Without, + ), + >, mut camera: Single< - &mut Transform, + (&mut Camera, &mut Transform), ( With, + Without, Without, Without, Without, @@ -68,11 +81,15 @@ fn on_scroll( match event.unit { MouseScrollUnit::Line | MouseScrollUnit::Pixel => { if event.y > 0.0 { - camera.scale *= 0.97; + camera.1.scale *= 0.97; + starguide_camera.1.scale *= 0.97; } else { - camera.scale *= 1.03; + camera.1.scale *= 1.03; + starguide_camera.1.scale *= 1.03; } - if camera.scale.z > 50.0 { + if camera.1.scale.z > 30.0 { + camera.0.is_active = false; + starguide_camera.0.is_active = true; starfield_back.image_mode = SpriteImageMode::Auto; starfield_mid.image_mode = SpriteImageMode::Auto; starfield_front.image_mode = SpriteImageMode::Auto; @@ -80,6 +97,8 @@ fn on_scroll( *visibility_mid = Visibility::Hidden; *visibility_front = Visibility::Hidden; } else { + camera.0.is_active = true; + starguide_camera.0.is_active = false; if matches!(*visibility_back, Visibility::Hidden) { if let Some(size_back) = size_back { starfield_back.image_mode = SpriteImageMode::Tiled { @@ -108,15 +127,15 @@ fn on_scroll( *visibility_front = Visibility::Inherited; } starfield_back.custom_size = - Some(window.size() * camera.scale.z + Vec2::splat(BACK_STARFIELD_SIZE * 2.0)); + Some(window.size() * camera.1.scale.z + Vec2::splat(BACK_STARFIELD_SIZE * 2.0)); starfield_mid.custom_size = - Some(window.size() * camera.scale.z + Vec2::splat(MID_STARFIELD_SIZE * 2.0)); + Some(window.size() * camera.1.scale.z + Vec2::splat(MID_STARFIELD_SIZE * 2.0)); starfield_front.custom_size = - Some(window.size() * camera.scale.z + Vec2::splat(FRONT_STARFIELD_SIZE * 2.0)); + Some(window.size() * camera.1.scale.z + Vec2::splat(FRONT_STARFIELD_SIZE * 2.0)); starfield_back_pos.translation = player.translation + (-player.translation / 3.0) % BACK_STARFIELD_SIZE + (Vec3::new(window.resolution.width(), -window.resolution.height(), 0.0) - * camera.scale.z + * camera.1.scale.z / 2.0) % BACK_STARFIELD_SIZE + Vec3::new(0.0, BACK_STARFIELD_SIZE, 0.0) @@ -124,7 +143,7 @@ fn on_scroll( starfield_mid_pos.translation = player.translation + (-player.translation / 2.5) % MID_STARFIELD_SIZE + (Vec3::new(window.resolution.width(), -window.resolution.height(), 0.0) - * camera.scale.z + * camera.1.scale.z / 2.0) % MID_STARFIELD_SIZE + Vec3::new(0.0, MID_STARFIELD_SIZE, 0.0) @@ -132,7 +151,7 @@ fn on_scroll( starfield_front_pos.translation = player.translation + (-player.translation / 2.0) % FRONT_STARFIELD_SIZE + (Vec3::new(window.resolution.width(), -window.resolution.height(), 0.0) - * camera.scale.z + * camera.1.scale.z / 2.0) % FRONT_STARFIELD_SIZE + Vec3::new(0.0, FRONT_STARFIELD_SIZE, 0.0) diff --git a/crates/unified/src/ecs.rs b/crates/unified/src/ecs.rs index 0ea640e159b0ad1485104e20941b607260ed0dd0..609e40a67d6d46b19a25ee8e7d6b2a7cf19cbdc2 100644 --- a/crates/unified/src/ecs.rs +++ b/crates/unified/src/ecs.rs @@ -3,14 +3,22 @@ pub mod thruster; use crate::config::part::PartConfig; use bevy::ecs::entity::MapEntities; use bevy::math::{Quat, Vec2}; +use bevy::camera::visibility::RenderLayers; use crate::prelude::*; use bevy_replicon::prelude::Replicated; use serde::{Deserialize, Serialize}; use avian2d::prelude::*; use crate::thrust::ThrustSolution; +use std::sync::LazyLock; + +pub const MAIN_LAYER: RenderLayers = RenderLayers::layer(0); +pub const STARGUIDE_LAYER: RenderLayers = RenderLayers::layer(1); +pub static MAIN_STAR_LAYERS: LazyLock = LazyLock::new(|| RenderLayers::from_layers(&[0, 1])); #[derive(Component)] pub struct MainCamera; +#[derive(Component)] +pub struct StarguideCamera; #[derive(Component)] pub struct StarfieldFront; @@ -80,4 +88,4 @@ pub struct Me; pub struct Hi { #[entities] pub you_are: Entity -} \ No newline at end of file +}