diff --git a/assets/models/point_of_interest.glb b/assets/models/point_of_interest.glb new file mode 100644 index 0000000..0def14d Binary files /dev/null and b/assets/models/point_of_interest.glb differ diff --git a/src/commands.rs b/src/commands.rs index 71091a8..c70d5e4 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -65,6 +65,7 @@ struct ParserState { is_clickable: bool, is_targeted_on_startup: bool, is_sun: bool, + is_point_of_interest: bool, has_physics: bool, has_ring: bool, wants_maxrotation: Option, @@ -114,6 +115,7 @@ impl Default for ParserState { is_clickable: true, is_targeted_on_startup: false, is_sun: false, + is_point_of_interest: false, has_physics: true, has_ring: false, wants_maxrotation: None, @@ -263,6 +265,9 @@ pub fn load_defs( ["ring", "yes"] => { state.has_ring = true; } + ["pointofinterest", "yes"] => { + state.is_point_of_interest = true; + } ["oxygen", amount] => { if let Ok(amount) = amount.parse::() { state.is_lifeform = true; @@ -687,6 +692,19 @@ fn spawn_entities( )); } + if state.is_point_of_interest { + commands.spawn(( + hud::IsPointOfInterestMarker(actor_entity), + world::DespawnOnPlayerDeath, + hud::ToggleableHudElement, + SceneBundle { + scene: asset_server.load(world::asset_name_to_path("point_of_interest")), + visibility: Visibility::Hidden, + ..default() + }, + )); + } + if state.has_ring { commands.spawn(( world::DespawnOnPlayerDeath, diff --git a/src/defs.txt b/src/defs.txt index 214e00f..2bba721 100644 --- a/src/defs.txt +++ b/src/defs.txt @@ -206,6 +206,7 @@ actor 0 0 0 moonlet orbit 221900e3 0.66 scale 50e3 angularmomentum 0 0.025 0 + pointofinterest yes actor 0 0 0 moonlet name Metis @@ -301,6 +302,7 @@ actor -3300 10 0 pizzeria relativeto player id pizzeria scale 40 + pointofinterest yes collider mesh rotationy 0.30 angularmomentum 0 0 0 @@ -371,6 +373,7 @@ actor 60 -15 -40 suit angularmomentum 0.4 0.2 0.1 rotationy 0.6 rotationx 1 + pointofinterest yes thrust 1.2 1 1 10 1.5 wants maxrotation 0.5 wants maxvelocity 0 @@ -382,6 +385,7 @@ actor -300 0 40 suit name "梓涵" chatid Drifter oxygen 0.08 + pointofinterest yes scale 2 collider handcrafted pronoun she @@ -391,6 +395,7 @@ actor 100 -18000 2000 "orb_busstop" id "busstop" name "StarTrans Bus Stop: Serenity Station" scale 100 + pointofinterest yes wants maxrotation 0 wants maxvelocity 0 actor 120 864 150 clippy @@ -438,6 +443,7 @@ actor -184971e3 149410e3 -134273e3 "orb_busstop" id "busstop2" name "StarTrans Bus Station 'Oscillation Station'" scale 100 + pointofinterest yes wants maxrotation 0 wants maxvelocity 0 actor 120 864 150 clippy @@ -475,6 +481,7 @@ actor 27643e3 -44e3 -124434e3 "orb_busstop" id "busstop3" name "StarTrans Bus Station 'Metis Prime'" scale 100 + pointofinterest yes wants maxrotation 0 wants maxvelocity 0 actor 120 864 150 clippy @@ -515,6 +522,7 @@ actor 110 -2000 0 whale density 100000 camdistance 4000 scale 300 + pointofinterest yes angularmomentum 0 0.015 0 thrust 2.45 0.48 0.33 1000000000000000 3 engine ion diff --git a/src/hud.rs b/src/hud.rs index fa0a0f5..ab09e09 100644 --- a/src/hud.rs +++ b/src/hud.rs @@ -42,6 +42,9 @@ impl Plugin for HudPlugin { update_ar_overlays .after(world::position_to_transform) .in_set(sync::SyncSet::PositionToTransform), + update_poi_overlays + .after(world::position_to_transform) + .in_set(sync::SyncSet::PositionToTransform), update_target_selectagon .after(PhysicsSet::Sync) .after(camera::apply_input_to_player) @@ -66,10 +69,11 @@ impl Plugin for HudPlugin { #[derive(Component)] struct NodeChoiceText; #[derive(Component)] struct NodeCurrentChatLine; #[derive(Component)] struct Reticule; -#[derive(Component)] struct ToggleableHudElement; +#[derive(Component)] pub struct ToggleableHudElement; #[derive(Component)] struct OnlyHideWhenTogglingHud; #[derive(Component)] struct Selectagon; #[derive(Component)] pub struct IsTargeted; +#[derive(Component)] pub struct IsPointOfInterestMarker(pub Entity); #[derive(Resource)] pub struct AugmentedRealityState { @@ -780,3 +784,29 @@ fn update_ar_overlays ( } } } + +fn update_poi_overlays ( + mut q_marker: Query<(&mut Transform, &IsPointOfInterestMarker)>, + q_parent: Query<&Transform, Without>, + q_camera: Query<&Transform, (With, Without)>, + settings: ResMut, +) { + if !settings.hud_active || q_camera.is_empty() { + return; + } + let camera_trans = q_camera.get_single().unwrap(); + for (mut trans, marker) in &mut q_marker { + if let Ok(parent_trans) = q_parent.get(marker.0) { + // Enlarge POI marker to a minimum angular diameter + trans.translation = parent_trans.translation; + trans.scale = Vec3::splat(1.0); + let (angular_diameter, _, _) = camera::calc_angular_diameter( + &trans, camera_trans); + let min_angular_diameter = 4.0f32.to_radians(); + if angular_diameter < min_angular_diameter { + trans.scale *= min_angular_diameter / angular_diameter; + } + trans.look_at(camera_trans.translation, camera_trans.up().into()); + } + } +} diff --git a/src/world.rs b/src/world.rs index 366d98f..47fcd54 100644 --- a/src/world.rs +++ b/src/world.rs @@ -53,6 +53,7 @@ pub fn asset_name_to_path(name: &str) -> &'static str { "clippy" => "models/clippy.glb#Scene0", "clippy_ar" => "models/clippy_ar.glb#Scene0", "whale" => "models/whale.glb#Scene0", + "point_of_interest" => "models/point_of_interest.glb#Scene0", _ => "models/error.glb#Scene0", } }