Various tweaks: moved radius determination to function on , comments, simplified server Destroy event code, debug assert modified components aren't removed in change tracking, etc

This commit is contained in:
Imbris 2019-12-19 22:31:41 -05:00
parent 0d763ab8ef
commit a16588a719
7 changed files with 54 additions and 29 deletions

View File

@ -33,6 +33,23 @@ impl Body {
_ => false, _ => false,
} }
} }
// Note: this might need to be refined to something more complex for realistic
// behavior with less cylindrical bodies (e.g. wolfs)
pub fn radius(&self) -> f32 {
// TODO: Improve these values (some might be reliant on more info in inner type)
match self {
Body::Humanoid(_) => 0.5,
Body::QuadrupedSmall(_) => 0.6,
Body::QuadrupedMedium(_) => 0.9,
Body::BirdMedium(_) => 0.5,
Body::FishMedium(_) => 0.5,
Body::Dragon(_) => 2.5,
Body::BirdSmall(_) => 0.2,
Body::FishSmall(_) => 0.2,
Body::BipedLarge(_) => 1.0,
Body::Object(_) => 0.3,
}
}
} }
impl Component for Body { impl Component for Body {

View File

@ -8,6 +8,9 @@ use std::{
marker::PhantomData, marker::PhantomData,
}; };
/// Implemented by type that carries component data for insertion and modification
/// The assocatied `Phantom` type only carries information about which component type is of
/// interest and is used to transmit deletion events
pub trait CompPacket: Clone + Debug + Send + 'static { pub trait CompPacket: Clone + Debug + Send + 'static {
type Phantom: Clone + Debug + Serialize + DeserializeOwned; type Phantom: Clone + Debug + Serialize + DeserializeOwned;

View File

@ -51,10 +51,9 @@ where
self.inserted.add(*id); self.inserted.add(*id);
} }
specs::storage::ComponentEvent::Modified(id) => { specs::storage::ComponentEvent::Modified(id) => {
// We don't care about modification if the component was just added or was // We don't care about modification if the component was just added
// removed if !self.inserted.contains(*id) {
// Could potentially remove since this should theoretically never occur... debug_assert!(!self.removed.contains(*id)); // Theoretically impossible
if !self.removed.contains(*id) && !self.inserted.contains(*id) {
self.modified.add(*id); self.modified.add(*id);
} }
} }

View File

@ -147,8 +147,11 @@ impl<'a> System<'a> for Sys {
if target_stats.is_dead { if target_stats.is_dead {
choose_new = true; choose_new = true;
} else if dist < 0.001 { } else if dist < 0.001 {
// TODO: move back? (probably can only happen when entities are at a // Probably can only happen when entities are at a different z-level
// different z-level due to repulsion) // since at the same level repulsion would keep them apart.
// Distinct from the first if block since we may want to change the
// behavior for this case.
choose_new = true;
} else if dist < MIN_ATTACK_DIST { } else if dist < MIN_ATTACK_DIST {
// Fight (and slowly move closer) // Fight (and slowly move closer)
inputs.move_dir = inputs.move_dir =

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
comp::{ comp::{
ActionState::*, CharacterState, Controller, HealthChange, HealthSource, Item, ItemKind, ActionState::*, Body, CharacterState, Controller, HealthChange, HealthSource, Item,
Ori, Pos, Scale, Stats, ItemKind, Ori, Pos, Scale, Stats,
}, },
event::{EventBus, LocalEvent, ServerEvent}, event::{EventBus, LocalEvent, ServerEvent},
state::DeltaTime, state::DeltaTime,
@ -30,8 +30,9 @@ impl<'a> System<'a> for Sys {
ReadStorage<'a, Ori>, ReadStorage<'a, Ori>,
ReadStorage<'a, Scale>, ReadStorage<'a, Scale>,
ReadStorage<'a, Controller>, ReadStorage<'a, Controller>,
ReadStorage<'a, Body>,
ReadStorage<'a, Stats>,
WriteStorage<'a, CharacterState>, WriteStorage<'a, CharacterState>,
WriteStorage<'a, Stats>,
); );
fn run( fn run(
@ -46,15 +47,16 @@ impl<'a> System<'a> for Sys {
orientations, orientations,
scales, scales,
controllers, controllers,
mut character_states, bodies,
stats, stats,
mut character_states,
): Self::SystemData, ): Self::SystemData,
) { ) {
let mut server_emitter = server_bus.emitter(); let mut server_emitter = server_bus.emitter();
let mut _local_emitter = local_bus.emitter(); let mut _local_emitter = local_bus.emitter();
// Attacks // Attacks
for (entity, uid, pos, ori, scale_maybe, _, stat) in ( for (entity, uid, pos, ori, scale_maybe, _, attacker_stats) in (
&entities, &entities,
&uids, &uids,
&positions, &positions,
@ -68,7 +70,7 @@ impl<'a> System<'a> for Sys {
let recover_duration = if let Some(Item { let recover_duration = if let Some(Item {
kind: ItemKind::Tool { kind, .. }, kind: ItemKind::Tool { kind, .. },
.. ..
}) = stat.equipment.main }) = attacker_stats.equipment.main
{ {
kind.attack_recover_duration() kind.attack_recover_duration()
} else { } else {
@ -96,7 +98,7 @@ impl<'a> System<'a> for Sys {
if deal_damage { if deal_damage {
if let Some(Attack { .. }) = &character_states.get(entity).map(|c| c.action) { if let Some(Attack { .. }) = &character_states.get(entity).map(|c| c.action) {
// Go through all other entities // Go through all other entities
for (b, uid_b, pos_b, ori_b, scale_b_maybe, character_b, stat_b) in ( for (b, uid_b, pos_b, ori_b, scale_b_maybe, character_b, stats_b, body_b) in (
&entities, &entities,
&uids, &uids,
&positions, &positions,
@ -104,6 +106,7 @@ impl<'a> System<'a> for Sys {
scales.maybe(), scales.maybe(),
&character_states, &character_states,
&stats, &stats,
&bodies,
) )
.join() .join()
{ {
@ -115,19 +118,18 @@ impl<'a> System<'a> for Sys {
// Scales // Scales
let scale = scale_maybe.map_or(1.0, |s| s.0); let scale = scale_maybe.map_or(1.0, |s| s.0);
let scale_b = scale_b_maybe.map_or(1.0, |s| s.0); let scale_b = scale_b_maybe.map_or(1.0, |s| s.0);
// TODO: don't do this here let rad_b = body_b.radius() * scale_b;
let rad_b = 0.5 * scale_b;
// Check if it is a hit // Check if it is a hit
if entity != b if entity != b
&& !stat_b.is_dead && !stats_b.is_dead
// Spherical wedge shaped attack field // Spherical wedge shaped attack field
&& pos.0.distance_squared(pos_b.0) < (rad_b + scale * ATTACK_RANGE).powi(2) && pos.0.distance_squared(pos_b.0) < (rad_b + scale * ATTACK_RANGE).powi(2)
&& ori2.angle_between(pos_b2 - pos2) < ATTACK_ANGLE.to_radians() / 2.0 + (rad_b / pos2.distance(pos_b2)).atan() && ori2.angle_between(pos_b2 - pos2) < ATTACK_ANGLE.to_radians() / 2.0 + (rad_b / pos2.distance(pos_b2)).atan()
{ {
// Weapon gives base damage // Weapon gives base damage
let mut dmg = if let Some(ItemKind::Tool { power, .. }) = let mut dmg = if let Some(ItemKind::Tool { power, .. }) =
stat.equipment.main.as_ref().map(|i| &i.kind) attacker_stats.equipment.main.as_ref().map(|i| &i.kind)
{ {
*power as i32 *power as i32
} else { } else {

View File

@ -413,21 +413,25 @@ impl Server {
} }
} }
// This sucks let mut remove = true;
let mut remove = false;
if let Some(client) = state.ecs().write_storage::<Client>().get_mut(entity) { if let Some(client) = state.ecs().write_storage::<Client>().get_mut(entity) {
let _ = state remove = false;
state
.ecs() .ecs()
.write_storage() .write_storage()
.insert(entity, comp::Vel(Vec3::zero())); .insert(entity, comp::Vel(Vec3::zero()))
let _ = state .err()
.map(|err| error!("Failed to set zero vel on dead client: {:?}", err));
state
.ecs() .ecs()
.write_storage() .write_storage()
.insert(entity, comp::ForceUpdate); .insert(entity, comp::ForceUpdate)
.err()
.map(|err| {
error!("Failed to insert ForceUpdate on dead client: {:?}", err)
});
client.force_state(ClientState::Dead); client.force_state(ClientState::Dead);
} else {
remove = true;
} }
if remove { if remove {

View File

@ -756,10 +756,7 @@ impl Ui {
} }
fn default_scissor(renderer: &Renderer) -> Aabr<u16> { fn default_scissor(renderer: &Renderer) -> Aabr<u16> {
let (screen_w, screen_h) = renderer let (screen_w, screen_h) = renderer.get_resolution().into_tuple();
.get_resolution()
.map(|e| (e as u16).max(1))
.into_tuple();
Aabr { Aabr {
min: Vec2 { x: 0, y: 0 }, min: Vec2 { x: 0, y: 0 },
max: Vec2 { max: Vec2 {