use std::ops::RangeBounds;
use bevy::{
ecs::component::{ComponentHooks, StorageType},
prelude::*,
};
use rand::{Rng, RngCore};
use crate::{
ecs::CommandsExt,
event::OnScore,
scoring::{Score, ScoreRange},
};
pub struct RandomScore {
pub rng: Box<dyn RngCore + Send + Sync + 'static>,
pub range: ScoreRange,
}
impl RandomScore {
pub fn new(rng: impl RngCore + Send + Sync + 'static) -> Self {
Self {
rng: Box::new(rng),
range: ScoreRange::FULL,
}
}
pub fn with_range(rng: impl RngCore + Send + Sync + 'static, range: impl RangeBounds<Score>) -> Self {
Self {
rng: Box::new(rng),
range: ScoreRange::from_bounds(range),
}
}
pub fn rng_mut(&mut self) -> &mut (impl RngCore + Send + Sync + 'static) {
&mut self.rng
}
pub fn set_rng(&mut self, rng: impl RngCore + Send + Sync + 'static) {
self.rng = Box::new(rng);
}
fn observer(trigger: Trigger<OnScore>, mut target: Query<(&mut Score, &mut RandomScore)>) {
let Ok((mut actor_score, mut settings)) = target.get_mut(trigger.entity()) else {
return;
};
let range = settings.range.min_f32()..=settings.range.max_f32();
let value = settings.rng_mut().gen_range(range);
actor_score.set(value);
}
}
impl Component for RandomScore {
const STORAGE_TYPE: StorageType = StorageType::Table;
fn register_component_hooks(hooks: &mut ComponentHooks) {
hooks.on_add(|mut world, _entity, _component| {
#[derive(Resource, Default)]
struct RandomScoreObserverSpawned;
world
.commands()
.once::<RandomScoreObserverSpawned>()
.observe(Self::observer);
});
}
}