implement player avatars

This commit is contained in:
yuni 2024-05-23 05:02:59 +02:00
parent 099e935e3e
commit efbb44a9fc
5 changed files with 93 additions and 0 deletions

View file

@ -674,6 +674,7 @@ fn spawn_entities(
if state.is_player { if state.is_player {
actor.insert(actor::Player); actor.insert(actor::Player);
actor.insert(actor::PlayerCamera); actor.insert(actor::PlayerCamera);
actor.insert(hud::AugmentedRealityOverlayBroadcaster);
} }
if state.is_sun { if state.is_sun {
let (r, g, b) = nature::star_color_index_to_rgb(0.656); let (r, g, b) = nature::star_color_index_to_rgb(0.656);
@ -812,6 +813,7 @@ fn spawn_entities(
let mut entitycmd = commands.spawn(( let mut entitycmd = commands.spawn((
hud::AugmentedRealityOverlay { hud::AugmentedRealityOverlay {
owner: actor_entity, owner: actor_entity,
scale: 1.0,
}, },
world::DespawnOnPlayerDeath, world::DespawnOnPlayerDeath,
SpatialBundle { SpatialBundle {

View file

@ -14,6 +14,7 @@ use crate::prelude::*;
use bevy::diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin}; use bevy::diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin};
use bevy::pbr::{NotShadowCaster, NotShadowReceiver}; use bevy::pbr::{NotShadowCaster, NotShadowReceiver};
use bevy::prelude::*; use bevy::prelude::*;
use bevy::scene::SceneInstance;
use bevy::transform::TransformSystem; use bevy::transform::TransformSystem;
use bevy_xpbd_3d::prelude::*; use bevy_xpbd_3d::prelude::*;
use std::collections::VecDeque; use std::collections::VecDeque;
@ -41,6 +42,13 @@ pub const DASHBOARD_DEF: &[(Dashboard, &str)] = &[
(Dashboard::Radioactivity, "radioactivity"), (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; pub struct HudPlugin;
impl Plugin for HudPlugin { impl Plugin for HudPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
@ -60,6 +68,7 @@ impl Plugin for HudPlugin {
PostUpdate, PostUpdate,
( (
update_overlay_visibility, update_overlay_visibility,
update_avatar.run_if(on_event::<UpdateAvatarEvent>()),
update_ar_overlays update_ar_overlays
.after(camera::position_to_transform) .after(camera::position_to_transform)
.in_set(sync::SyncSet::PositionToTransform), .in_set(sync::SyncSet::PositionToTransform),
@ -84,6 +93,7 @@ impl Plugin for HudPlugin {
TimerMode::Repeating, TimerMode::Repeating,
))); )));
app.add_event::<TargetEvent>(); app.add_event::<TargetEvent>();
app.add_event::<UpdateAvatarEvent>();
app.add_event::<UpdateOverlayVisibility>(); app.add_event::<UpdateOverlayVisibility>();
} }
} }
@ -92,6 +102,8 @@ impl Plugin for HudPlugin {
pub struct TargetEvent(pub Option<Entity>); pub struct TargetEvent(pub Option<Entity>);
#[derive(Event)] #[derive(Event)]
pub struct UpdateOverlayVisibility; pub struct UpdateOverlayVisibility;
#[derive(Event)]
pub struct UpdateAvatarEvent;
#[derive(Component)] #[derive(Component)]
struct NodeHud; struct NodeHud;
#[derive(Component)] #[derive(Component)]
@ -117,6 +129,8 @@ pub struct ToggleableHudMapElement;
#[derive(Component)] #[derive(Component)]
struct Selectagon; struct Selectagon;
#[derive(Component)] #[derive(Component)]
struct PlayerAvatar;
#[derive(Component)]
pub struct IsTargeted; pub struct IsTargeted;
#[derive(Component)] #[derive(Component)]
pub struct PointOfInterestMarker(pub Entity); pub struct PointOfInterestMarker(pub Entity);
@ -148,11 +162,18 @@ pub struct AugmentedRealityOverlayBroadcaster;
#[derive(Component)] #[derive(Component)]
pub struct AugmentedRealityOverlay { pub struct AugmentedRealityOverlay {
pub owner: Entity, pub owner: Entity,
pub scale: f32,
} }
#[derive(Resource)] #[derive(Resource)]
struct FPSUpdateTimer(Timer); struct FPSUpdateTimer(Timer);
pub enum Avatar {
None,
ChefHat,
Asteroid,
}
pub enum LogLevel { pub enum LogLevel {
Achievement, Achievement,
Always, Always,
@ -1154,6 +1175,9 @@ fn update_ar_overlays(
for (owner_id, owner_trans, owner_vis) in &q_owners { for (owner_id, owner_trans, owner_vis) in &q_owners {
if owner_id == ar.owner { if owner_id == ar.owner {
*trans = *owner_trans; *trans = *owner_trans;
if ar.scale != 1.0 {
trans.scale *= ar.scale;
}
if need_clean { if need_clean {
*vis = Visibility::Hidden; *vis = Visibility::Hidden;
} else { } else {
@ -1249,3 +1273,52 @@ fn update_overlay_visibility(
AMBIENT_LIGHT AMBIENT_LIGHT
}; };
} }
fn update_avatar(
mut commands: Commands,
mut settings: ResMut<Settings>,
asset_server: Res<AssetServer>,
q_avatar: Query<(Entity, &SceneInstance), With<PlayerAvatar>>,
q_player: Query<Entity, With<actor::Player>>,
mut scene_spawner: ResMut<SceneSpawner>,
) {
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);
}
}

View file

@ -65,6 +65,7 @@ pub enum DeathScreenEvent {
pub const MENUDEF: &[(&str, MenuAction)] = &[ pub const MENUDEF: &[(&str, MenuAction)] = &[
("", MenuAction::ToggleMap), ("", MenuAction::ToggleMap),
("", MenuAction::ToggleAR), ("", MenuAction::ToggleAR),
("", MenuAction::ChangeARAvatar),
("", MenuAction::ToggleSound), ("", MenuAction::ToggleSound),
("", MenuAction::ToggleMusic), ("", MenuAction::ToggleMusic),
("", MenuAction::ToggleCamera), ("", MenuAction::ToggleCamera),
@ -78,6 +79,7 @@ pub const MENUDEF: &[(&str, MenuAction)] = &[
pub enum MenuAction { pub enum MenuAction {
ToggleMap, ToggleMap,
ToggleAR, ToggleAR,
ChangeARAvatar,
ToggleSound, ToggleSound,
ToggleMusic, ToggleMusic,
ToggleCamera, ToggleCamera,
@ -467,6 +469,12 @@ pub fn update_menu(
let onoff = bool2string(settings.hud_active); let onoff = bool2string(settings.hud_active);
text.sections[i].value = format!("Augmented Reality: {onoff} [TAB]\n"); 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 => { MenuAction::ToggleMap => {
let onoff = bool2string(settings.map_active); let onoff = bool2string(settings.map_active);
text.sections[i].value = format!("Map: {onoff} [M]\n"); text.sections[i].value = format!("Map: {onoff} [M]\n");
@ -502,6 +510,7 @@ pub fn handle_input(
mut ew_playerdies: EventWriter<game::PlayerDiesEvent>, mut ew_playerdies: EventWriter<game::PlayerDiesEvent>,
mut ew_sfx: EventWriter<audio::PlaySfxEvent>, mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
mut ew_updatemenu: EventWriter<UpdateMenuEvent>, mut ew_updatemenu: EventWriter<UpdateMenuEvent>,
mut ew_updateavatar: EventWriter<hud::UpdateAvatarEvent>,
) { ) {
let last_menu_entry = MENUDEF.len() - 1; let last_menu_entry = MENUDEF.len() - 1;
@ -551,6 +560,11 @@ pub fn handle_input(
ew_game.send(GameEvent::SetAR(Toggle)); ew_game.send(GameEvent::SetAR(Toggle));
ew_updatemenu.send(UpdateMenuEvent); ew_updatemenu.send(UpdateMenuEvent);
} }
MenuAction::ChangeARAvatar => {
settings.ar_avatar += 1;
ew_updateavatar.send(hud::UpdateAvatarEvent);
ew_updatemenu.send(UpdateMenuEvent);
}
MenuAction::ToggleMusic => { MenuAction::ToggleMusic => {
ew_game.send(GameEvent::SetMusic(Toggle)); ew_game.send(GameEvent::SetMusic(Toggle));
ew_updatemenu.send(UpdateMenuEvent); ew_updatemenu.send(UpdateMenuEvent);

View file

@ -80,6 +80,7 @@ pub struct Settings {
pub hud_color_keybindings: Color, pub hud_color_keybindings: Color,
pub hud_color_version: Color, pub hud_color_version: Color,
pub chat_speed: f32, pub chat_speed: f32,
pub ar_avatar: usize,
pub flashlight_active: bool, pub flashlight_active: bool,
pub hud_active: bool, pub hud_active: bool,
pub map_active: bool, pub map_active: bool,
@ -208,6 +209,7 @@ impl Default for Settings {
hud_color_keybindings: Color::hex(COLOR_DIM).unwrap(), hud_color_keybindings: Color::hex(COLOR_DIM).unwrap(),
hud_color_version: Color::hex(COLOR_PRIMARY).unwrap(), hud_color_version: Color::hex(COLOR_PRIMARY).unwrap(),
chat_speed: DEFAULT_CHAT_SPEED * if dev_mode { 2.5 } else { 1.0 }, chat_speed: DEFAULT_CHAT_SPEED * if dev_mode { 2.5 } else { 1.0 },
ar_avatar: 0,
flashlight_active: false, flashlight_active: false,
hud_active: true, hud_active: true,
map_active: false, map_active: false,

View file

@ -359,8 +359,10 @@ fn handle_despawn(
fn handle_respawn( fn handle_respawn(
ew_spawn: EventWriter<cmd::SpawnEvent>, ew_spawn: EventWriter<cmd::SpawnEvent>,
mut ew_updateavatar: EventWriter<hud::UpdateAvatarEvent>,
mut achievement_tracker: ResMut<var::AchievementTracker>, mut achievement_tracker: ResMut<var::AchievementTracker>,
) { ) {
*achievement_tracker = var::AchievementTracker::default(); *achievement_tracker = var::AchievementTracker::default();
cmd::load_defs(ew_spawn); cmd::load_defs(ew_spawn);
ew_updateavatar.send(hud::UpdateAvatarEvent);
} }