From d064680d60a460372a69b608012ac7eb5c61184d Mon Sep 17 00:00:00 2001 From: hut Date: Wed, 10 Apr 2024 21:03:30 +0200 Subject: [PATCH] clippy: add AR face ^_^ --- COMMENTARY.md | 2 ++ assets/models/clippy_ar.glb | Bin 0 -> 15796 bytes src/commands.rs | 25 ++++++++++++++++++ src/defs.txt | 1 + src/hud.rs | 51 ++++++++++++++++++++++++++++++++++++ src/world.rs | 1 + 6 files changed, 80 insertions(+) create mode 100644 assets/models/clippy_ar.glb 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 0000000000000000000000000000000000000000..5158dccedece08006c65dbb1e276c78fdf592304 GIT binary patch literal 15796 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 literal 0 HcmV?d00001 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", } }