Reduce extra energy updates

This commit is contained in:
Imbris 2022-01-18 00:17:20 -05:00
parent fa42be75b8
commit cc40058ae2
4 changed files with 47 additions and 26 deletions

View File

@ -54,14 +54,31 @@ impl Energy {
/// Returns the fraction of energy an entity has remaining
pub fn fraction(&self) -> f32 { self.current() / self.maximum().max(1.0) }
/// Updates the maximum value for energy
pub fn update_maximum(&mut self, modifiers: comp::stats::StatsModifier) {
/// Calculates a new maximum value and returns it if the value differs from
/// the current maximum.
///
/// Note: The returned value uses an internal format so don't expect it to
/// be useful for anything other than a parameter to
/// [`Self::update_maximum`].
pub fn needs_maximum_update(&self, modifiers: comp::stats::StatsModifier) -> Option<u32> {
let maximum = modifiers
.compute_maximum(self.base_max())
.mul(Self::SCALING_FACTOR_FLOAT)
// NaN does not need to be handled here as rust will automatically change to 0 when casting to u32
.clamp(0.0, Self::MAX_SCALED_ENERGY as f32) as u32;
(maximum != self.maximum).then(|| maximum)
}
/// Updates the maximum value for energy.
///
/// Note: The accepted `u32` value is in the internal format of this type.
/// So attempting to pass values that weren't returned from
/// [`Self::needs_maximum_update`] can produce strange or unexpected
/// results.
pub fn update_maximum(&mut self, maximum: u32) {
self.maximum = maximum;
// Clamp the current health to enforce the current <= maximum invariant.
self.current = self.current.min(self.maximum);
}

View File

@ -90,13 +90,29 @@ impl Health {
/// Returns the fraction of health an entity has remaining
pub fn fraction(&self) -> f32 { self.current() / self.maximum().max(1.0) }
/// Updates the maximum value for health
pub fn update_maximum(&mut self, modifiers: comp::stats::StatsModifier) {
/// Calculates a new maximum value and returns it if the value differs from
/// the current maximum.
///
/// Note: The returned value uses an internal format so don't expect it to
/// be useful for anything other than a parameter to
/// [`Self::update_maximum`].
pub fn needs_maximum_update(&self, modifiers: comp::stats::StatsModifier) -> Option<u32> {
let maximum = modifiers
.compute_maximum(self.base_max())
.mul(Self::SCALING_FACTOR_FLOAT)
// NaN does not need to be handled here as rust will automatically change to 0 when casting to u32
.clamp(0.0, Self::MAX_SCALED_HEALTH as f32) as u32;
(maximum != self.maximum).then(|| maximum)
}
/// Updates the maximum value for health.
///
/// Note: The accepted `u32` value is in the internal format of this type.
/// So attempting to pass values that weren't returned from
/// [`Self::needs_maximum_update`] can produce strange or unexpected
/// results.
pub fn update_maximum(&mut self, maximum: u32) {
self.maximum = maximum;
// Clamp the current health to enforce the current <= maximum invariant.
self.current = self.current.min(self.maximum);

View File

@ -30,6 +30,7 @@ impl StatsModifier {
base_value * self.mult_mod + self.add_mod
}
// Note: unused for now
pub fn update_maximum(&self) -> bool {
self.add_mod.abs() > f32::EPSILON || (self.mult_mod - 1.0).abs() > f32::EPSILON
}

View File

@ -92,32 +92,19 @@ impl<'a> System<'a> for Sys {
}
let stat = stats;
let update_max_hp = {
stat.max_health_modifiers.update_maximum()
|| (health.base_max() - health.maximum()).abs() > Health::HEALTH_EPSILON
};
if update_max_hp {
health.update_maximum(stat.max_health_modifiers);
if let Some(new_max) = health.needs_maximum_update(stat.max_health_modifiers) {
health.update_maximum(new_max);
}
let (change_energy, energy_mods) = {
// Calculates energy scaling from stats and inventory
let energy_mods = StatsModifier {
add_mod: stat.max_energy_modifiers.add_mod
+ combat::compute_max_energy_mod(inventory),
mult_mod: stat.max_energy_modifiers.mult_mod,
};
(
energy_mods.update_maximum()
|| (energy.base_max() - energy.maximum()).abs() > Energy::ENERGY_EPSILON,
energy_mods,
)
// Calculates energy scaling from stats and inventory
let energy_mods = StatsModifier {
add_mod: stat.max_energy_modifiers.add_mod
+ combat::compute_max_energy_mod(inventory),
mult_mod: stat.max_energy_modifiers.mult_mod,
};
// If modifier sufficiently different, mutably access energy
if change_energy {
energy.update_maximum(energy_mods);
if let Some(new_max) = energy.needs_maximum_update(energy_mods) {
energy.update_maximum(new_max);
}
}