implement player avatars
This commit is contained in:
parent
099e935e3e
commit
efbb44a9fc
|
@ -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 {
|
||||||
|
|
73
src/hud.rs
73
src/hud.rs
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
14
src/menu.rs
14
src/menu.rs
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue