diff --git a/COMMENTARY.md b/COMMENTARY.md index 1808fa0..2006698 100644 --- a/COMMENTARY.md +++ b/COMMENTARY.md @@ -7,6 +7,8 @@ These cubes are interchangeable, solar panel plated, driven by strong reaction w The shape of a Clippy™ can change quickly to solve a variety of space problems. Off-the-shelf plug-and-play Clippy™ modules further enhance their agency with additional tools, such as propulsion modules, sensors, or manipulators. +A Clippy™ Convenience Companion will broadcast an Augmented Reality overlay that resembles a face, in the somewhat antiquated "kaomoji" style of the late 1900's, typically a friendly face to instill trust and kindness in viewers. How a unified persona with aligned intentions emerges from the interactions of the individual Clippy™ cubes is, as of writing, still subject to debate. + Clippy™ is inspired by [self-assembling cube robots](https://www.youtube.com/watch?v=hI5UDKaWJOo), by the [paperclip maximizer thought experiment](https://en.wikipedia.org/w/index.php?title=Instrumental_convergence&oldid=1210129297#Paperclip_maximizer) (which is also the source of the name), by [Star Gate's Replicators](https://stargate.fandom.com/wiki/Replicator), and finally, by [Fallout New Vegas' "Yes Man" robot](https://fallout.fandom.com/wiki/Yes_Man). ## MeteorAceGT™ Sports Racing Capsule diff --git a/assets/models/clippy_ar.glb b/assets/models/clippy_ar.glb new file mode 100644 index 0000000..5158dcc Binary files /dev/null and b/assets/models/clippy_ar.glb differ diff --git a/src/commands.rs b/src/commands.rs index 4a9980c..f102c72 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -67,6 +67,7 @@ struct ParserState { suit_integrity: f32, light_brightness: f32, light_color: Option, + ar_model: Option, // Chat fields delay: f64, @@ -121,6 +122,7 @@ impl Default for ParserState { suit_integrity: 1.0, light_brightness: 0.0, light_color: None, + ar_model: None, delay: 0.0, text: "".to_string(), @@ -453,6 +455,9 @@ pub fn load_defs( continue; } } + ["armodel", asset_name] => { + state.ar_model = Some(asset_name.to_string()); + } // Parsing chats ["chat", chat_name] => { @@ -571,6 +576,8 @@ fn spawn_entities( } } else if state.class == DefClass::Actor { + let actor_entity; + { let mut actor = commands.spawn_empty(); actor.insert(actor::Actor { id: state.id.clone(), @@ -699,6 +706,24 @@ fn spawn_entities( ..default() }); } + if let Some(_) = state.ar_model { + actor.insert(hud::AugmentedRealityOverlayBroadcaster); + } + actor_entity = actor.id(); + } + + if let Some(ar_asset_name) = &state.ar_model { + commands.spawn(( + hud::AugmentedRealityOverlay { + owner: actor_entity, + }, + SceneBundle { + scene: asset_server.load(world::asset_name_to_path(ar_asset_name)), + visibility: Visibility::Hidden, + ..default() + }, + )); + } } } } diff --git a/src/defs.txt b/src/defs.txt index b39bad4..5f1eace 100644 --- a/src/defs.txt +++ b/src/defs.txt @@ -176,6 +176,7 @@ actor -3300 10 0 pizzeria actor -33 0 4 clippy name "Clippy™ Convenience Companion" relativeto pizzeria + armodel clippy_ar angularmomentum 0 0 0 wants maxrotation 0 wants maxvelocity 0 diff --git a/src/hud.rs b/src/hud.rs index 3ae5c3d..bee64fb 100644 --- a/src/hud.rs +++ b/src/hud.rs @@ -24,6 +24,7 @@ impl Plugin for HudPlugin { app.add_systems(Startup, setup); app.add_systems(Update, ( update_hud, + update_ar_overlays, handle_input, handle_target_event, )); @@ -33,6 +34,9 @@ impl Plugin for HudPlugin { .after(camera::apply_input_to_player) .before(TransformSystem::TransformPropagate), )); + app.insert_resource(AugmentedRealityState { + overlays_visible: false, + }); app.insert_resource(Log { logs: VecDeque::with_capacity(LOG_MAX), needs_rerendering: true, @@ -52,6 +56,17 @@ impl Plugin for HudPlugin { #[derive(Component)] struct Selectagon; #[derive(Component)] pub struct IsTargeted; +#[derive(Resource)] +pub struct AugmentedRealityState { + pub overlays_visible: bool, +} + +#[derive(Component)] pub struct AugmentedRealityOverlayBroadcaster; +#[derive(Component)] +pub struct AugmentedRealityOverlay { + pub owner: Entity, +} + #[derive(Resource)] struct FPSUpdateTimer(Timer); @@ -645,3 +660,39 @@ fn update_target_selectagon( } } } + +fn update_ar_overlays ( + q_owners: Query<(Entity, &Transform, &Visibility), (With, Without)>, + mut q_overlays: Query<(&mut Transform, &mut Visibility, &mut AugmentedRealityOverlay)>, + settings: ResMut, + mut state: ResMut, +) { + let (need_activate, need_clean, need_update); + if settings.hud_active { + need_activate = !state.overlays_visible; + need_clean = false; + } + else { + need_activate = false; + need_clean = state.overlays_visible; + } + need_update = settings.hud_active; + state.overlays_visible = settings.hud_active; + + if need_update || need_clean || need_activate { + 'outer: for (mut trans, mut vis, ar) in &mut q_overlays { + for (owner_id, owner_trans, owner_vis) in &q_owners { + if owner_id == ar.owner { + *trans = *owner_trans; + if need_clean { + *vis = Visibility::Hidden; + } + else { + *vis = *owner_vis; + } + break 'outer; + } + } + } + } +} diff --git a/src/world.rs b/src/world.rs index ae84ba3..b022cbe 100644 --- a/src/world.rs +++ b/src/world.rs @@ -35,6 +35,7 @@ pub fn asset_name_to_path(name: &str) -> &'static str { "pizzasign" => "models/pizzasign.glb#Scene0", "selectagon" => "models/selectagon.glb#Scene0", "clippy" => "models/clippy.glb#Scene0", + "clippy_ar" => "models/clippy_ar.glb#Scene0", _ => "models/error.glb#Scene0", } }