Spaces:
Running
Running
| use crate::grain::GrainType; | |
| use crate::utils::constants::{GAME_RESOLUTION_X, GAME_RESOLUTION_Y}; | |
| use bevy::prelude::*; | |
| /* | |
| 🦀 Resources and Components. Learn more: https://bevy-cheatbook.github.io/programming/res.html | |
| */ | |
| pub struct Grid { | |
| data: [[Option<GrainType>; GAME_RESOLUTION_X]; GAME_RESOLUTION_Y], | |
| spatial_hash: Vec<Vec<GridPosition>>, // For faster neighbor lookups | |
| dirty_cells: Vec<GridPosition>, // Track cells that need updating | |
| } | |
| pub struct GridPosition { | |
| pub current_x: i32, | |
| pub current_y: i32, | |
| pub prev_x: Option<i32>, | |
| pub prev_y: Option<i32>, | |
| } | |
| impl GridPosition { | |
| pub fn new(x: i32, y: i32) -> Self { | |
| GridPosition { | |
| current_x: x, | |
| current_y: y, | |
| prev_x: None, | |
| prev_y: None, | |
| } | |
| } | |
| pub fn is_moving(&self) -> bool { | |
| match (self.prev_x, self.prev_y) { | |
| (Some(prev_x), Some(prev_y)) => { | |
| prev_x != self.current_x || prev_y != self.current_y | |
| } | |
| _ => false, | |
| } | |
| } | |
| pub fn reset_prev(&mut self) { | |
| self.prev_x = None; | |
| self.prev_y = None; | |
| } | |
| } | |
| impl Grid { | |
| pub fn new() -> Grid { | |
| let spatial_hash = vec![vec![]; (GAME_RESOLUTION_X * GAME_RESOLUTION_Y) / 64]; // Simple spatial partitioning | |
| Grid { | |
| data: [[None; GAME_RESOLUTION_X]; GAME_RESOLUTION_Y], | |
| spatial_hash, | |
| dirty_cells: Vec::new(), | |
| } | |
| } | |
| pub fn get(&self, x: usize, y: usize) -> Option<GrainType> { | |
| if x < GAME_RESOLUTION_X && y < GAME_RESOLUTION_Y { | |
| self.data[y][x] | |
| } else { | |
| None | |
| } | |
| } | |
| pub fn get_checked(&self, x: i32, y: i32) -> Option<GrainType> { | |
| if x >= 0 && x < GAME_RESOLUTION_X as i32 && y >= 0 && y < GAME_RESOLUTION_Y as i32 { | |
| self.data[y as usize][x as usize] | |
| } else { | |
| None | |
| } | |
| } | |
| pub fn set(&mut self, x: usize, y: usize, value: GrainType) { | |
| if x < GAME_RESOLUTION_X && y < GAME_RESOLUTION_Y { | |
| self.data[y][x] = Some(value); | |
| self.dirty_cells.push(GridPosition::new(x as i32, y as i32)); | |
| } | |
| } | |
| pub fn clear(&mut self, x: usize, y: usize) { | |
| if x < GAME_RESOLUTION_X && y < GAME_RESOLUTION_Y { | |
| self.data[y][x] = None; | |
| self.dirty_cells.push(GridPosition::new(x as i32, y as i32)); | |
| } | |
| } | |
| pub fn swap(&mut self, x1: usize, y1: usize, x2: usize, y2: usize) { | |
| if x1 < GAME_RESOLUTION_X && y1 < GAME_RESOLUTION_Y && | |
| x2 < GAME_RESOLUTION_X && y2 < GAME_RESOLUTION_Y { | |
| self.data[y1][x1].swap(&mut self.data[y2][x2]); | |
| self.dirty_cells.push(GridPosition::new(x1 as i32, y1 as i32)); | |
| self.dirty_cells.push(GridPosition::new(x2 as i32, y2 as i32)); | |
| } | |
| } | |
| pub fn get_neighbors(&self, x: i32, y: i32) -> [Option<GrainType>; 8] { | |
| [ | |
| self.get_checked(x - 1, y - 1), self.get_checked(x, y - 1), self.get_checked(x + 1, y - 1), | |
| self.get_checked(x - 1, y), self.get_checked(x + 1, y), | |
| self.get_checked(x - 1, y + 1), self.get_checked(x, y + 1), self.get_checked(x + 1, y + 1), | |
| ] | |
| } | |
| pub fn take_dirty_cells(&mut self) -> Vec<GridPosition> { | |
| std::mem::take(&mut self.dirty_cells) | |
| } | |
| } | |
| pub struct GridPosition { | |
| pub current_x: i32, | |
| pub current_y: i32, | |
| pub prev_x: Option<i32>, | |
| pub prev_y: Option<i32>, | |
| } | |
| /* | |
| 🦀 Systems. Learn more: https://bevy-cheatbook.github.io/programming/systems.html | |
| */ | |
| pub fn update_grid_data(mut query: Query<(&GrainType, &mut GridPosition)>, mut grid_data: ResMut<Grid>) { | |
| for (grain_type, mut grid_position) in query.iter_mut() { | |
| // Clear the previous position from the grid | |
| if let (Some(prev_x), Some(prev_y)) = (grid_position.prev_x, grid_position.prev_y) { | |
| if prev_x >= 0 && prev_y >= 0 && prev_x < GAME_RESOLUTION_X as i32 && prev_y < GAME_RESOLUTION_Y as i32 { | |
| grid_data.data[prev_y as usize][prev_x as usize] = None; | |
| } | |
| } | |
| // Boundary checks for current positions | |
| if grid_position.current_x >= 0 | |
| && grid_position.current_x < GAME_RESOLUTION_X as i32 | |
| && grid_position.current_y >= 0 | |
| && grid_position.current_y < GAME_RESOLUTION_Y as i32 | |
| { | |
| // Update the grid with the new position | |
| grid_data.set( | |
| grid_position.current_x as usize, | |
| grid_position.current_y as usize, | |
| *grain_type, | |
| ); | |
| } | |
| // Update prev for next frame | |
| grid_position.prev_x = Some(grid_position.current_x); | |
| grid_position.prev_y = Some(grid_position.current_y); | |
| } | |
| } | |