From efbb44a9fc6b27a2abef1e0b21850203d730fab9 Mon Sep 17 00:00:00 2001 From: yuni Date: Thu, 23 May 2024 05:02:59 +0200 Subject: [PATCH] implement player avatars --- src/cmd.rs | 2 ++ src/hud.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/menu.rs | 14 ++++++++++ src/var.rs | 2 ++ src/world.rs | 2 ++ 5 files changed, 93 insertions(+) diff --git a/src/cmd.rs b/src/cmd.rs index f896505..914d586 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -674,6 +674,7 @@ fn spawn_entities( if state.is_player { actor.insert(actor::Player); actor.insert(actor::PlayerCamera); + actor.insert(hud::AugmentedRealityOverlayBroadcaster); } if state.is_sun { let (r, g, b) = nature::star_color_index_to_rgb(0.656); @@ -812,6 +813,7 @@ fn spawn_entities( let mut entitycmd = commands.spawn(( hud::AugmentedRealityOverlay { owner: actor_entity, + scale: 1.0, }, world::DespawnOnPlayerDeath, SpatialBundle { diff --git a/src/hud.rs b/src/hud.rs index c6e20b4..4e6ea32 100644 --- a/src/hud.rs +++ b/src/hud.rs @@ -14,6 +14,7 @@ use crate::prelude::*; use bevy::diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin}; use bevy::pbr::{NotShadowCaster, NotShadowReceiver}; use bevy::prelude::*; +use bevy::scene::SceneInstance; use bevy::transform::TransformSystem; use bevy_xpbd_3d::prelude::*; use std::collections::VecDeque; @@ -41,6 +42,13 @@ pub const DASHBOARD_DEF: &[(Dashboard, &str)] = &[ (Dashboard::Radioactivity, "radioactivity"), ]; +// Player avatars: [(Avatar, model name, scale, in-game name)] +pub const PLAYER_AR_AVATARS: &[(Avatar, &str, f32, &str)] = &[ + (Avatar::None, "", 1.0, "No Avatar"), + (Avatar::ChefHat, "suit_ar_chefhat", 1.0, "Chef Hat"), + (Avatar::Asteroid, "asteroid2", 1.2, "Asteroid"), +]; + pub struct HudPlugin; impl Plugin for HudPlugin { fn build(&self, app: &mut App) { @@ -60,6 +68,7 @@ impl Plugin for HudPlugin { PostUpdate, ( update_overlay_visibility, + update_avatar.run_if(on_event::()), update_ar_overlays .after(camera::position_to_transform) .in_set(sync::SyncSet::PositionToTransform), @@ -84,6 +93,7 @@ impl Plugin for HudPlugin { TimerMode::Repeating, ))); app.add_event::(); + app.add_event::(); app.add_event::(); } } @@ -92,6 +102,8 @@ impl Plugin for HudPlugin { pub struct TargetEvent(pub Option); #[derive(Event)] pub struct UpdateOverlayVisibility; +#[derive(Event)] +pub struct UpdateAvatarEvent; #[derive(Component)] struct NodeHud; #[derive(Component)] @@ -117,6 +129,8 @@ pub struct ToggleableHudMapElement; #[derive(Component)] struct Selectagon; #[derive(Component)] +struct PlayerAvatar; +#[derive(Component)] pub struct IsTargeted; #[derive(Component)] pub struct PointOfInterestMarker(pub Entity); @@ -148,11 +162,18 @@ pub struct AugmentedRealityOverlayBroadcaster; #[derive(Component)] pub struct AugmentedRealityOverlay { pub owner: Entity, + pub scale: f32, } #[derive(Resource)] struct FPSUpdateTimer(Timer); +pub enum Avatar { + None, + ChefHat, + Asteroid, +} + pub enum LogLevel { Achievement, Always, @@ -1154,6 +1175,9 @@ fn update_ar_overlays( for (owner_id, owner_trans, owner_vis) in &q_owners { if owner_id == ar.owner { *trans = *owner_trans; + if ar.scale != 1.0 { + trans.scale *= ar.scale; + } if need_clean { *vis = Visibility::Hidden; } else { @@ -1249,3 +1273,52 @@ fn update_overlay_visibility( AMBIENT_LIGHT }; } + +fn update_avatar( + mut commands: Commands, + mut settings: ResMut, + asset_server: Res, + q_avatar: Query<(Entity, &SceneInstance), With>, + q_player: Query>, + mut scene_spawner: ResMut, +) { + if settings.ar_avatar >= PLAYER_AR_AVATARS.len() { + settings.ar_avatar = settings.ar_avatar % PLAYER_AR_AVATARS.len(); + } + let ava = if let Some(ava) = PLAYER_AR_AVATARS.get(settings.ar_avatar) { + ava + } else { + error!("Avatar index out of bounds!"); + return; + }; + let model_name = ava.1; + let model_scale = ava.2; + + for (entity, sceneinstance) in &q_avatar { + commands.entity(entity).despawn(); + scene_spawner.despawn_instance(**sceneinstance); + } + + if model_name.is_empty() { + // No avatar selected. + return; + } + + if let Ok(player_entity) = q_player.get_single() { + let mut entitycmd = commands.spawn(( + hud::AugmentedRealityOverlay { + owner: player_entity, + scale: model_scale, + }, + world::DespawnOnPlayerDeath, + PlayerAvatar, + SpatialBundle { + visibility: bool2vis(settings.hud_active), + ..default() + }, + NotShadowCaster, + NotShadowReceiver, + )); + load_asset(model_name, &mut entitycmd, &*asset_server); + } +} diff --git a/src/menu.rs b/src/menu.rs index af8ed06..190d166 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -65,6 +65,7 @@ pub enum DeathScreenEvent { pub const MENUDEF: &[(&str, MenuAction)] = &[ ("", MenuAction::ToggleMap), ("", MenuAction::ToggleAR), + ("", MenuAction::ChangeARAvatar), ("", MenuAction::ToggleSound), ("", MenuAction::ToggleMusic), ("", MenuAction::ToggleCamera), @@ -78,6 +79,7 @@ pub const MENUDEF: &[(&str, MenuAction)] = &[ pub enum MenuAction { ToggleMap, ToggleAR, + ChangeARAvatar, ToggleSound, ToggleMusic, ToggleCamera, @@ -467,6 +469,12 @@ pub fn update_menu( let onoff = bool2string(settings.hud_active); text.sections[i].value = format!("Augmented Reality: {onoff} [TAB]\n"); } + MenuAction::ChangeARAvatar => { + if let Some(ava) = hud::PLAYER_AR_AVATARS.get(settings.ar_avatar) { + let avatar_title = ava.3; + text.sections[i].value = format!("Avatar: {avatar_title}\n"); + } + } MenuAction::ToggleMap => { let onoff = bool2string(settings.map_active); text.sections[i].value = format!("Map: {onoff} [M]\n"); @@ -502,6 +510,7 @@ pub fn handle_input( mut ew_playerdies: EventWriter, mut ew_sfx: EventWriter, mut ew_updatemenu: EventWriter, + mut ew_updateavatar: EventWriter, ) { let last_menu_entry = MENUDEF.len() - 1; @@ -551,6 +560,11 @@ pub fn handle_input( ew_game.send(GameEvent::SetAR(Toggle)); ew_updatemenu.send(UpdateMenuEvent); } + MenuAction::ChangeARAvatar => { + settings.ar_avatar += 1; + ew_updateavatar.send(hud::UpdateAvatarEvent); + ew_updatemenu.send(UpdateMenuEvent); + } MenuAction::ToggleMusic => { ew_game.send(GameEvent::SetMusic(Toggle)); ew_updatemenu.send(UpdateMenuEvent); diff --git a/src/var.rs b/src/var.rs index eb06760..8500a77 100644 --- a/src/var.rs +++ b/src/var.rs @@ -80,6 +80,7 @@ pub struct Settings { pub hud_color_keybindings: Color, pub hud_color_version: Color, pub chat_speed: f32, + pub ar_avatar: usize, pub flashlight_active: bool, pub hud_active: bool, pub map_active: bool, @@ -208,6 +209,7 @@ impl Default for Settings { hud_color_keybindings: Color::hex(COLOR_DIM).unwrap(), hud_color_version: Color::hex(COLOR_PRIMARY).unwrap(), chat_speed: DEFAULT_CHAT_SPEED * if dev_mode { 2.5 } else { 1.0 }, + ar_avatar: 0, flashlight_active: false, hud_active: true, map_active: false, diff --git a/src/world.rs b/src/world.rs index b4582ff..0c7cd34 100644 --- a/src/world.rs +++ b/src/world.rs @@ -359,8 +359,10 @@ fn handle_despawn( fn handle_respawn( ew_spawn: EventWriter, + mut ew_updateavatar: EventWriter, mut achievement_tracker: ResMut, ) { *achievement_tracker = var::AchievementTracker::default(); cmd::load_defs(ew_spawn); + ew_updateavatar.send(hud::UpdateAvatarEvent); }