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
parent 364890653f
commit 2a5e66400f
7 changed files with 86 additions and 21 deletions

View File

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

View File

@ -36,6 +36,8 @@ widget_ids! {
load_tips_button_label,
debug_button,
debug_button_label,
hitboxes_button,
hitboxes_button_label,
ch_title,
ch_transp_slider,
ch_transp_value,
@ -239,9 +241,33 @@ impl<'a> Widget for Interface<'a> {
.color(TEXT_COLOR)
.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
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_id(self.fonts.cyri.conrod_id)
.color(TEXT_COLOR)

View File

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

View File

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

View File

@ -44,6 +44,7 @@ use crate::{
window::{AnalogGameInput, Event, GameInput},
Direction, Error, GlobalState, PlayState, PlayStateResult,
};
use hashbrown::HashMap;
use settings_change::Language::ChangeLanguage;
/// The action to perform after a tick
@ -73,7 +74,7 @@ pub struct SessionState {
selected_entity: Option<(specs::Entity, std::time::Instant)>,
interactable: Option<Interactable>,
saved_zoom_dist: Option<f32>,
player_hitbox: DebugShapeId,
hitboxes: HashMap<specs::Entity, DebugShapeId>,
}
/// 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 walk_forward_dir = scene.camera().forward_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 {
scene,
@ -125,7 +122,7 @@ impl SessionState {
selected_entity: None,
interactable: None,
saved_zoom_dist: None,
player_hitbox,
hitboxes: HashMap::new(),
}
}
@ -145,16 +142,54 @@ impl SessionState {
span!(_guard, "tick", "Session::tick");
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];
self.scene
.debug
.set_pos_and_color(self.player_hitbox, pos, [1.0, 0.0, 0.0, 0.5]);
let ecs = client.state().ecs();
let mut current_entities = hashbrown::HashSet::new();
let scene = &mut self.scene;
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)? {
match event {

View File

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

View File

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