clippy: add AR face ^_^

This commit is contained in:
yuni 2024-04-10 21:03:30 +02:00
parent 817a5e2a96
commit d064680d60
6 changed files with 80 additions and 0 deletions

View file

@ -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

BIN
assets/models/clippy_ar.glb Normal file

Binary file not shown.

View file

@ -67,6 +67,7 @@ struct ParserState {
suit_integrity: f32,
light_brightness: f32,
light_color: Option<Color>,
ar_model: Option<String>,
// 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()
},
));
}
}
}
}

View file

@ -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

View file

@ -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<AugmentedRealityOverlayBroadcaster>, Without<AugmentedRealityOverlay>)>,
mut q_overlays: Query<(&mut Transform, &mut Visibility, &mut AugmentedRealityOverlay)>,
settings: ResMut<settings::Settings>,
mut state: ResMut<AugmentedRealityState>,
) {
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;
}
}
}
}
}

View file

@ -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",
}
}