Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: parallelize food loops #6

Merged
merged 2 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions src/cell/mouth.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use bevy::prelude::*;

use crate::{neighbor::VecExt as _, organism::Organism, CellTree, GameState};
use crate::{neighbor::VecExt as _, organism::Belly, CellTree, GameState};

use super::Food;

Expand All @@ -19,7 +19,7 @@ fn consume_food(
mut commands: Commands,
locations: Res<CellTree>,
mouths: Query<(&GlobalTransform, &Parent), With<MouthCell>>,
mut organisms: Query<&mut Organism>,
mut organisms: Query<&mut Belly>,
food: Query<&Food>,
) {
for (mouth, mouth_parent) in &mouths {
Expand All @@ -40,10 +40,7 @@ fn consume_food(
}

if food_eaten > 0 {
organisms
.get_mut(mouth_parent.get())
.unwrap()
.ate_food(food_eaten);
organisms.get_mut(mouth_parent.get()).unwrap().0 += food_eaten;
}
}
}
47 changes: 35 additions & 12 deletions src/cell/producer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,48 @@ pub struct ProducerPlugin;

impl Plugin for ProducerPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, produce_food.run_if(in_state(GameState::Playing)));
app.add_systems(
Update,
(
tick_producers.run_if(in_state(GameState::Playing)),
produce_food.run_if(in_state(GameState::Playing)),
),
);
}
}

pub fn produce_food(
mut commands: Commands,
locations: Res<CellTree>,
#[derive(Component)]
pub struct MakeFood;

pub fn tick_producers(
par_commands: ParallelCommands,
settings: Res<EnvironmentSettings>,
mut producers: Query<(&mut ProducerCell, &GlobalTransform)>,
mut producers: Query<(Entity, &mut ProducerCell)>,
) {
for (mut producer, global_location) in &mut producers {
producers.par_iter_mut().for_each(|(pe, mut producer)| {
producer.counter += 1;
let translation = global_location.translation();
if producer.counter >= settings.producer_threshold {
if let Some(free_space) = translation.get_free_space(&locations) {
commands.spawn(FoodBundle::at(free_space));
}

//(&commands).entity(pe).insert(MakeFood);
par_commands.command_scope(|mut c| {
c.entity(pe).try_insert(MakeFood);
});
producer.counter = 0;
}
}
});
}

pub fn produce_food(
par_commands: ParallelCommands,
locations: Res<CellTree>,
producers: Query<(Entity, &GlobalTransform), With<MakeFood>>,
) {
producers.par_iter().for_each(|(pe, producer_location)| {
let translation = producer_location.translation();
if let Some(free_space) = translation.get_free_space(&locations) {
par_commands.command_scope(|mut commands| {
commands.spawn(FoodBundle::at(free_space));
commands.entity(pe).remove::<MakeFood>();
});
}
});
}
4 changes: 2 additions & 2 deletions src/environment/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pub use bevy::prelude::*;
use mouse_hover::hover_over_organism;

use crate::cell::CellType;
use crate::{cell::CellType, organism::Belly};

use super::{
organism::{Organism, OrganismPlugin},
Expand Down Expand Up @@ -121,5 +121,5 @@ fn clear_background(mut color: ResMut<ClearColor>) {
/// Creates the first organism. [`Organism::insert_at`] is used to unify spawning of the organism in the ECS
/// as well as placing itself in the [`OccupiedLocations`] hashmap.
fn spawn_first_organism(mut commands: Commands) {
Organism::first_organism().insert_at(&mut commands, Vec2::new(10., 10.));
Organism::first_organism().insert_at(&mut commands, Vec2::new(10., 10.), Belly(3));
}
62 changes: 19 additions & 43 deletions src/organism/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ pub use plugin::*;
mod reproduction;
use reproduction::*;

#[derive(Component, Clone)]
pub struct Belly(pub u64);

#[derive(Component)]
pub struct Age(pub u64);

#[derive(Component)]
pub struct StarvedAt(pub u64);

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum BrainType {
Predator,
Expand All @@ -23,17 +32,12 @@ pub struct Organism {
genome: Genome,
brain: Option<BrainType>,
can_move: bool,
belly: u64,
/// in millis
time_born: u64,
offspring: u64,
/// in millis
last_starved: u64,
can_reproduce_at: u64,
}

impl Organism {
fn new(genome: Genome, belly: u64, time_born: u64) -> Self {
fn new(genome: Genome) -> Self {
let mut has_producer = false;
let mut has_eye = false;
let mut has_mover = false;
Expand Down Expand Up @@ -69,15 +73,11 @@ impl Organism {
genome,
brain: brain_type,
can_move: has_mover && !has_producer,
belly,
time_born,
offspring: 0,
last_starved: 0,
can_reproduce_at,
}
}
pub fn ready_to_reproduce(&self) -> bool {
self.belly >= self.can_reproduce_at
pub fn ready_to_reproduce(&self, belly: &Belly) -> bool {
belly.0 >= self.can_reproduce_at
}

/// returns the number of cells this organism takes up based on its genome
Expand All @@ -102,47 +102,20 @@ impl Organism {
self.can_move
}

pub fn reproduce(&mut self, current_tick: u64) -> Option<Organism> {
//always lose half of one's belly
self.belly /= 2;
pub fn reproduce(&self) -> Option<Organism> {
let child_genome = self.genome.reproduce();
if child_genome.num_cells() < 2 {
return None;
}
self.offspring += 1;
Some(Self::new(child_genome, self.belly, current_tick))
Some(Self::new(child_genome))
}

pub fn first_organism() -> Self {
Self::new(Genome::first_organism(), 3, 0)
}
pub fn ate_food(&mut self, amt: u64) {
if self.belly < self.can_reproduce_at {
self.belly += amt;
}
}

pub fn lost_food(&mut self, amt: u64, time: u64) {
self.belly = self.belly.saturating_sub(amt);
self.last_starved = time;
//info!("Organism lost food, belly is at {}", self.belly)
}

/// returns the millisecond last starved
pub fn time_last_starved(&self) -> u64 {
self.last_starved
}

pub fn time_born(&self) -> u64 {
self.time_born
}

pub fn belly(&self) -> u64 {
self.belly
Self::new(Genome::first_organism())
}

/// Uses both the ECS and the global positioning hashmap to insert itself.
pub fn insert_at(self, commands: &mut Commands, location: impl VecExt) {
pub fn insert_at(self, commands: &mut Commands, location: impl VecExt, belly: Belly) {
/*info!(
"\nInserting Organism into the world:\nLocation: {:?}\nto insert:{:#?}",
global_location, self
Expand All @@ -157,6 +130,9 @@ impl Organism {
..Default::default()
},
self,
belly,
Age(0),
StarvedAt(0),
))
.with_children(|child_builder| {
genome.spawn_cells(child_builder);
Expand Down
Loading