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

View file

@ -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::<UpdateAvatarEvent>()),
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::<TargetEvent>();
app.add_event::<UpdateAvatarEvent>();
app.add_event::<UpdateOverlayVisibility>();
}
}
@ -92,6 +102,8 @@ impl Plugin for HudPlugin {
pub struct TargetEvent(pub Option<Entity>);
#[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<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)] = &[
("", 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<game::PlayerDiesEvent>,
mut ew_sfx: EventWriter<audio::PlaySfxEvent>,
mut ew_updatemenu: EventWriter<UpdateMenuEvent>,
mut ew_updateavatar: EventWriter<hud::UpdateAvatarEvent>,
) {
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);

View file

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

View file

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