From ae18dbac3d1ab7ea5e95338a493b38f6ada50e6d Mon Sep 17 00:00:00 2001 From: Jarrod Doyle Date: Thu, 1 Feb 2024 11:36:11 +0000 Subject: [PATCH] Move systems to own module --- src/falling_sand/mod.rs | 109 ++---------------------------------- src/falling_sand/systems.rs | 109 ++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 104 deletions(-) create mode 100644 src/falling_sand/systems.rs diff --git a/src/falling_sand/mod.rs b/src/falling_sand/mod.rs index 2642600..c09d31d 100644 --- a/src/falling_sand/mod.rs +++ b/src/falling_sand/mod.rs @@ -1,5 +1,6 @@ mod element; mod rules; +mod systems; use bevy::{ app::{Plugin, Startup}, @@ -18,10 +19,7 @@ use rand::Rng; use crate::util::DirtyRect; -use self::{ - element::Element, - rules::{to_rule_state, FallingSandRules}, -}; +use self::{element::Element, rules::FallingSandRules}; pub struct FallingSandPlugin; @@ -31,9 +29,9 @@ impl Plugin for FallingSandPlugin { app.add_systems( Update, ( - place_sand_system, - simulate_chunk_system, - update_chunk_texture_system, + systems::place_sand, + systems::simulate_chunk, + systems::update_chunk_texture, ) .chain(), ); @@ -129,100 +127,3 @@ impl Chunk { Some(self.cells[x + y * self.width]) } } - -pub fn place_sand_system(mut query: Query<&mut Chunk>) { - for mut chunk in &mut query { - let frac = chunk.width / 2; - let x = (chunk.width - frac) / 2 + rand::thread_rng().gen_range(0..frac); - let y = chunk.height - 1; - chunk.set_cell(x, y, Element::Sand); - } -} - -pub fn simulate_chunk_system(rules: Res, mut query: Query<&mut Chunk>) { - for mut chunk in &mut query { - // Determine which Margolus neighbourhood offset we're using this update - let offset = if chunk.step == 0 { - (0, 0) - } else if chunk.step == 1 { - (1, 1) - } else if chunk.step == 2 { - (0, 1) - } else { - (1, 0) - }; - chunk.step = (chunk.step + 1) % 4; - - // We're operating on 2x2 blocks of cells - for block_y in 0..(chunk.height / 2) { - let y = block_y * 2 + offset.1; - for block_x in 0..(chunk.width / 2) { - let x = block_x * 2 + offset.0; - - // Get all the cells in our block and convert them to a rule state for lookup - // Because our offset can cause cell look-ups to go ourside of the grid we have - // a default `Element::None` - // Cells are obtained in the order top-left, top-right, bottom-left, bottom-right - let start_state = to_rule_state(( - chunk.get_cell(x, y + 1).unwrap_or(Element::None), - chunk.get_cell(x + 1, y + 1).unwrap_or(Element::None), - chunk.get_cell(x, y).unwrap_or(Element::None), - chunk.get_cell(x + 1, y).unwrap_or(Element::None), - )); - let end_state = rules.get_result(start_state); - - // We only need to actually update things if the state changed - // Same ordering as above. - if start_state != end_state { - if (start_state & 0xFF000000) != (end_state & 0xFF000000) { - chunk.set_cell(x, y + 1, Element::from((end_state >> 24) & 0xFF)); - } - if (start_state & 0x00FF0000) != (end_state & 0x00FF0000) { - chunk.set_cell(x + 1, y + 1, Element::from((end_state >> 16) & 0xFF)); - } - if (start_state & 0x0000FF00) != (end_state & 0x0000FF00) { - chunk.set_cell(x, y, Element::from((end_state >> 8) & 0xFF)); - } - if (start_state & 0x000000FF) != (end_state & 0x000000FF) { - chunk.set_cell(x + 1, y, Element::from(end_state & 0xFF)); - } - } - } - } - } -} - -pub fn update_chunk_texture_system( - mut images: ResMut>, - mut query: Query<(&mut Chunk, &Handle)>, -) { - for (mut chunk, image_handle) in &mut query { - if !chunk.dirty_rect.is_dirty() { - return; - } - - if let Some(image) = images.get_mut(image_handle) { - for y in chunk.dirty_rect.range_y() { - for x in chunk.dirty_rect.range_x() { - let mut colour = (0, 0, 0); - if let Some(element) = chunk.cells.get(x + y * chunk.width) { - match element { - Element::Air => colour = (25, 24, 26), - Element::Sand => colour = (255, 216, 102), - Element::Water => colour = (120, 220, 232), - _ => {} - } - } - - let index = (x + y * chunk.width) * 4; - image.data[index] = colour.0; - image.data[index + 1] = colour.1; - image.data[index + 2] = colour.2; - image.data[index + 3] = 255; - } - } - } - - chunk.dirty_rect.reset(); - } -} diff --git a/src/falling_sand/systems.rs b/src/falling_sand/systems.rs new file mode 100644 index 0000000..68a0ecf --- /dev/null +++ b/src/falling_sand/systems.rs @@ -0,0 +1,109 @@ +use bevy::{ + asset::{Assets, Handle}, + ecs::system::{Query, Res, ResMut}, + render::texture::Image, +}; +use rand::Rng; + +use super::{ + element::Element, + rules::{to_rule_state, FallingSandRules}, + Chunk, +}; + +pub fn place_sand(mut query: Query<&mut Chunk>) { + for mut chunk in &mut query { + let frac = chunk.width / 2; + let x = (chunk.width - frac) / 2 + rand::thread_rng().gen_range(0..frac); + let y = chunk.height - 1; + chunk.set_cell(x, y, Element::Sand); + } +} + +pub fn simulate_chunk(rules: Res, mut query: Query<&mut Chunk>) { + for mut chunk in &mut query { + // Determine which Margolus neighbourhood offset we're using this update + let offset = if chunk.step == 0 { + (0, 0) + } else if chunk.step == 1 { + (1, 1) + } else if chunk.step == 2 { + (0, 1) + } else { + (1, 0) + }; + chunk.step = (chunk.step + 1) % 4; + + // We're operating on 2x2 blocks of cells + for block_y in 0..(chunk.height / 2) { + let y = block_y * 2 + offset.1; + for block_x in 0..(chunk.width / 2) { + let x = block_x * 2 + offset.0; + + // Get all the cells in our block and convert them to a rule state for lookup + // Because our offset can cause cell look-ups to go ourside of the grid we have + // a default `Element::None` + // Cells are obtained in the order top-left, top-right, bottom-left, bottom-right + let start_state = to_rule_state(( + chunk.get_cell(x, y + 1).unwrap_or(Element::None), + chunk.get_cell(x + 1, y + 1).unwrap_or(Element::None), + chunk.get_cell(x, y).unwrap_or(Element::None), + chunk.get_cell(x + 1, y).unwrap_or(Element::None), + )); + let end_state = rules.get_result(start_state); + + // We only need to actually update things if the state changed + // Same ordering as above. + if start_state != end_state { + if (start_state & 0xFF000000) != (end_state & 0xFF000000) { + chunk.set_cell(x, y + 1, Element::from((end_state >> 24) & 0xFF)); + } + if (start_state & 0x00FF0000) != (end_state & 0x00FF0000) { + chunk.set_cell(x + 1, y + 1, Element::from((end_state >> 16) & 0xFF)); + } + if (start_state & 0x0000FF00) != (end_state & 0x0000FF00) { + chunk.set_cell(x, y, Element::from((end_state >> 8) & 0xFF)); + } + if (start_state & 0x000000FF) != (end_state & 0x000000FF) { + chunk.set_cell(x + 1, y, Element::from(end_state & 0xFF)); + } + } + } + } + } +} + +pub fn update_chunk_texture( + mut images: ResMut>, + mut query: Query<(&mut Chunk, &Handle)>, +) { + for (mut chunk, image_handle) in &mut query { + if !chunk.dirty_rect.is_dirty() { + return; + } + + if let Some(image) = images.get_mut(image_handle) { + for y in chunk.dirty_rect.range_y() { + for x in chunk.dirty_rect.range_x() { + let mut colour = (0, 0, 0); + if let Some(element) = chunk.cells.get(x + y * chunk.width) { + match element { + Element::Air => colour = (25, 24, 26), + Element::Sand => colour = (255, 216, 102), + Element::Water => colour = (120, 220, 232), + _ => {} + } + } + + let index = (x + y * chunk.width) * 4; + image.data[index] = colour.0; + image.data[index + 1] = colour.1; + image.data[index + 2] = colour.2; + image.data[index + 3] = 255; + } + } + } + + chunk.dirty_rect.reset(); + } +}