use bevy::prelude::*;
pub(crate) struct BatteryPlugin;
impl Plugin for BatteryPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, discharge_battery);
}
}
const DISCHARGE_RATE: f64 = 30_000.;
const DEFAULT_CAPACITY: f64 = 100_000_000.; #[derive(Component, Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Battery {
capacity: f64,
energy: f64,
}
impl Default for Battery {
fn default() -> Self {
Self::new(DEFAULT_CAPACITY, DEFAULT_CAPACITY)
}
}
impl Battery {
fn new(capacity: f64, energy: f64) -> Self {
debug_assert!(capacity.is_finite());
debug_assert!(capacity > 0.);
debug_assert!(energy.is_finite());
debug_assert!(energy >= 0.);
debug_assert!(energy <= capacity);
Self { capacity, energy }
}
pub fn capacity(&self) -> f64 {
self.capacity
}
pub fn energy(&self) -> f64 {
self.energy
}
fn change(&mut self, delta: f64) {
debug_assert!(delta.is_finite());
self.energy = (self.energy + delta).clamp(0., self.capacity);
}
}
pub(crate) fn discharge_battery(time: Res<Time>, mut battery: Query<&mut Battery>) {
let delta = time.delta_seconds();
let discharge_delta = DISCHARGE_RATE * delta as f64;
for mut battery in battery.iter_mut() {
let energy = battery.energy();
if energy == 0. {
continue;
}
battery.change(-discharge_delta);
}
}
#[cfg(test)]
mod tests {
use std::time::Duration;
use bevy::prelude::*;
use super::*;
use crate::battery::{Battery, DEFAULT_CAPACITY, DISCHARGE_RATE};
#[test]
fn test_discharge() {
let mut app = App::new();
let entity = app
.world
.spawn((
Battery::default(), ))
.id();
app.init_resource::<Time>();
app.add_plugins(BatteryPlugin);
app.update();
app.world
.get_resource_mut::<Time>()
.unwrap()
.advance_by(Duration::from_secs(1));
app.update();
let battery = app.world.get::<Battery>(entity).unwrap();
println!("battery: {:?}", battery);
assert!(battery.energy() == DEFAULT_CAPACITY - DISCHARGE_RATE);
}
}