Show hitbox cylinders based on actual ECS data, and add a settings toggle in voxygen for it.

This commit is contained in:
Avi Weinstock 2021-05-04 16:12:26 -04:00 committed by Imbris
parent 7b04599a3b
commit cf6717ac90
7 changed files with 86 additions and 21 deletions

View File

@ -10,6 +10,7 @@
"hud.settings.press_behavior.hold": "Hold", "hud.settings.press_behavior.hold": "Hold",
"hud.settings.help_window": "Help Window", "hud.settings.help_window": "Help Window",
"hud.settings.debug_info": "Debug Info", "hud.settings.debug_info": "Debug Info",
"hud.settings.show_hitboxes": "Show hitboxes",
"hud.settings.tips_on_startup": "Tips-On-Startup", "hud.settings.tips_on_startup": "Tips-On-Startup",
"hud.settings.ui_scale": "UI-Scale", "hud.settings.ui_scale": "UI-Scale",
"hud.settings.relative_scaling": "Relative Scaling", "hud.settings.relative_scaling": "Relative Scaling",

View File

@ -36,6 +36,8 @@ widget_ids! {
load_tips_button_label, load_tips_button_label,
debug_button, debug_button,
debug_button_label, debug_button_label,
hitboxes_button,
hitboxes_button_label,
ch_title, ch_title,
ch_transp_slider, ch_transp_slider,
ch_transp_value, ch_transp_value,
@ -239,9 +241,33 @@ impl<'a> Widget for Interface<'a> {
.color(TEXT_COLOR) .color(TEXT_COLOR)
.set(state.ids.debug_button_label, ui); .set(state.ids.debug_button_label, ui);
// Hitboxes
let show_hitboxes = ToggleButton::new(
self.global_state.settings.interface.toggle_hitboxes,
self.imgs.checkbox,
self.imgs.checkbox_checked,
)
.w_h(18.0, 18.0)
.down_from(state.ids.debug_button, 8.0)
.hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
.press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
.set(state.ids.hitboxes_button, ui);
if self.global_state.settings.interface.toggle_hitboxes != show_hitboxes {
events.push(ToggleHitboxes(show_hitboxes));
}
Text::new(&self.localized_strings.get("hud.settings.show_hitboxes"))
.right_from(state.ids.hitboxes_button, 10.0)
.font_size(self.fonts.cyri.scale(14))
.font_id(self.fonts.cyri.conrod_id)
.graphics_for(state.ids.hitboxes_button)
.color(TEXT_COLOR)
.set(state.ids.hitboxes_button_label, ui);
// Ui Scale // Ui Scale
Text::new(&self.localized_strings.get("hud.settings.ui_scale")) Text::new(&self.localized_strings.get("hud.settings.ui_scale"))
.down_from(state.ids.debug_button, 20.0) .down_from(state.ids.hitboxes_button, 20.0)
.font_size(self.fonts.cyri.scale(18)) .font_size(self.fonts.cyri.scale(18))
.font_id(self.fonts.cyri.conrod_id) .font_id(self.fonts.cyri.conrod_id)
.color(TEXT_COLOR) .color(TEXT_COLOR)

View File

@ -1,6 +1,4 @@
use super::{ use super::super::{AaMode, Bound, Consts, GlobalsLayouts, Vertex as VertexTrait};
super::{AaMode, Bound, Consts, GlobalsLayouts, Vertex as VertexTrait},
};
use bytemuck::{Pod, Zeroable}; use bytemuck::{Pod, Zeroable};
use std::mem; use std::mem;
use vek::*; use vek::*;

View File

@ -1,6 +1,5 @@
use crate::render::{ use crate::render::{
Bound, Consts, DebugLocals, DebugVertex, FirstPassDrawer, Mesh, Bound, Consts, DebugLocals, DebugVertex, FirstPassDrawer, Mesh, Model, Quad, Renderer, Tri,
Model, Quad, Renderer, Tri,
}; };
use hashbrown::{HashMap, HashSet}; use hashbrown::{HashMap, HashSet};
use vek::*; use vek::*;

View File

@ -44,6 +44,7 @@ use crate::{
window::{AnalogGameInput, Event, GameInput}, window::{AnalogGameInput, Event, GameInput},
Direction, Error, GlobalState, PlayState, PlayStateResult, Direction, Error, GlobalState, PlayState, PlayStateResult,
}; };
use hashbrown::HashMap;
use settings_change::Language::ChangeLanguage; use settings_change::Language::ChangeLanguage;
/// The action to perform after a tick /// The action to perform after a tick
@ -73,7 +74,7 @@ pub struct SessionState {
selected_entity: Option<(specs::Entity, std::time::Instant)>, selected_entity: Option<(specs::Entity, std::time::Instant)>,
interactable: Option<Interactable>, interactable: Option<Interactable>,
saved_zoom_dist: Option<f32>, saved_zoom_dist: Option<f32>,
player_hitbox: DebugShapeId, hitboxes: HashMap<specs::Entity, DebugShapeId>,
} }
/// Represents an active game session (i.e., the one being played). /// Represents an active game session (i.e., the one being played).
@ -101,10 +102,6 @@ impl SessionState {
let hud = Hud::new(global_state, &client.borrow()); let hud = Hud::new(global_state, &client.borrow());
let walk_forward_dir = scene.camera().forward_xy(); let walk_forward_dir = scene.camera().forward_xy();
let walk_right_dir = scene.camera().right_xy(); let walk_right_dir = scene.camera().right_xy();
let player_hitbox = scene.debug.add_shape(DebugShape::Cylinder {
radius: 0.4,
height: 1.75,
});
Self { Self {
scene, scene,
@ -125,7 +122,7 @@ impl SessionState {
selected_entity: None, selected_entity: None,
interactable: None, interactable: None,
saved_zoom_dist: None, saved_zoom_dist: None,
player_hitbox, hitboxes: HashMap::new(),
} }
} }
@ -145,16 +142,54 @@ impl SessionState {
span!(_guard, "tick", "Session::tick"); span!(_guard, "tick", "Session::tick");
let mut client = self.client.borrow_mut(); let mut client = self.client.borrow_mut();
if let Some(player_pos) = client
.state()
.ecs()
.read_component::<Pos>()
.get(client.entity())
{ {
let pos = [player_pos.0.x, player_pos.0.y, player_pos.0.z, 0.0]; let ecs = client.state().ecs();
self.scene let mut current_entities = hashbrown::HashSet::new();
.debug let scene = &mut self.scene;
.set_pos_and_color(self.player_hitbox, pos, [1.0, 0.0, 0.0, 0.5]); let hitboxes = &mut self.hitboxes;
if global_state.settings.interface.toggle_hitboxes {
let positions = ecs.read_component::<Pos>();
let colliders = ecs.read_component::<comp::Collider>();
let groups = ecs.read_component::<comp::Group>();
for (entity, pos, collider, group) in
(&ecs.entities(), &positions, &colliders, groups.maybe()).join()
{
if let comp::Collider::Box {
radius,
z_min,
z_max,
} = collider
{
current_entities.insert(entity);
let shape_id = hitboxes.entry(entity).or_insert_with(|| {
scene.debug.add_shape(DebugShape::Cylinder {
radius: *radius,
height: *z_max - *z_min,
})
});
let hb_pos = [pos.0.x, pos.0.y, pos.0.z + *z_min, 0.0];
let color = if group == Some(&comp::group::ENEMY) {
[1.0, 0.0, 0.0, 0.5]
} else if group == Some(&comp::group::NPC) {
[0.0, 0.0, 1.0, 0.5]
} else {
[0.0, 1.0, 0.0, 0.5]
};
scene.debug.set_pos_and_color(*shape_id, hb_pos, color);
}
}
}
let mut to_remove = Vec::new();
hitboxes.retain(|k, v| {
let keep = current_entities.contains(k);
if !keep {
to_remove.push(*v);
}
keep
});
for shape_id in to_remove.into_iter() {
scene.debug.remove_shape(shape_id);
}
} }
for event in client.tick(self.inputs.clone(), dt, crate::ecs::sys::add_local_systems)? { for event in client.tick(self.inputs.clone(), dt, crate::ecs::sys::add_local_systems)? {
match event { match event {

View File

@ -96,6 +96,7 @@ pub enum Interface {
SpeechBubbleIcon(bool), SpeechBubbleIcon(bool),
ToggleHelp(bool), ToggleHelp(bool),
ToggleDebug(bool), ToggleDebug(bool),
ToggleHitboxes(bool),
ToggleTips(bool), ToggleTips(bool),
CrosshairTransp(f32), CrosshairTransp(f32),
@ -446,6 +447,9 @@ impl SettingsChange {
Interface::ToggleDebug(toggle_debug) => { Interface::ToggleDebug(toggle_debug) => {
settings.interface.toggle_debug = toggle_debug; settings.interface.toggle_debug = toggle_debug;
}, },
Interface::ToggleHitboxes(toggle_hitboxes) => {
settings.interface.toggle_hitboxes = toggle_hitboxes;
},
Interface::ToggleTips(loading_tips) => { Interface::ToggleTips(loading_tips) => {
settings.interface.loading_tips = loading_tips; settings.interface.loading_tips = loading_tips;
}, },

View File

@ -10,6 +10,7 @@ use vek::*;
#[serde(default)] #[serde(default)]
pub struct InterfaceSettings { pub struct InterfaceSettings {
pub toggle_debug: bool, pub toggle_debug: bool,
pub toggle_hitboxes: bool,
pub sct: bool, pub sct: bool,
pub sct_player_batch: bool, pub sct_player_batch: bool,
pub sct_damage_batch: bool, pub sct_damage_batch: bool,
@ -44,6 +45,7 @@ impl Default for InterfaceSettings {
fn default() -> Self { fn default() -> Self {
Self { Self {
toggle_debug: false, toggle_debug: false,
toggle_hitboxes: false,
sct: true, sct: true,
sct_player_batch: false, sct_player_batch: false,
sct_damage_batch: false, sct_damage_batch: false,