diff --git a/src/game.rs b/src/game.rs index 1e4acd2..9e9e340 100644 --- a/src/game.rs +++ b/src/game.rs @@ -4,7 +4,6 @@ pub mod resources; pub mod systems; use crate::despawn_screen; -use crate::prelude::*; use crate::GameState; use bevy::input::common_conditions::input_just_pressed; use bevy::prelude::*; @@ -29,16 +28,7 @@ pub struct GamePlugin; impl Plugin for GamePlugin { fn build(&self, app: &mut App) { app.add_plugins(ShapePlugin) - .add_systems( - OnEnter(GameState::Game), - ( - control::init_diplopod, - control::init_wall, - control::init_food, - control::init_poison, - ) - .chain(), - ) + .add_systems(OnEnter(GameState::Game), control::setup_game) .add_systems( Update, ( @@ -92,7 +82,6 @@ impl Plugin for GamePlugin { .add_systems(OnExit(GameState::Game), despawn_screen::) .insert_resource(DiplopodSegments::default()) .insert_resource(LastSpecialSpawn::default()) - .insert_resource(FreePositions::new(CONSUMABLE_WIDTH, CONSUMABLE_HEIGHT)) .insert_resource(Time::::from_seconds(0.075)) .add_event::() .add_event::() diff --git a/src/game/resources.rs b/src/game/resources.rs index 016f6fd..f7fd24b 100644 --- a/src/game/resources.rs +++ b/src/game/resources.rs @@ -1,62 +1,8 @@ use bevy::prelude::*; -use rand::seq::SliceRandom; -use rand::thread_rng; - -use crate::game::components::Position; #[derive(Default, Resource)] pub struct DiplopodSegments(pub Vec); -#[derive(Clone, Resource)] -pub struct FreePositions { - pub positions: Vec, - width: i32, - height: i32, -} - -impl FreePositions { - pub fn new(width: i32, height: i32) -> Self { - let positions = Self::new_positions(width, height); - Self { - positions, - width, - height, - } - } - - fn new_positions(width: i32, height: i32) -> Vec { - let mut positions = Vec::new(); - - for x in 0..width { - for y in 0..height { - positions.push(Position { x, y }); - } - } - - positions.shuffle(&mut thread_rng()); - - positions - } - - pub fn shuffle(&mut self) { - self.positions.shuffle(&mut thread_rng()); - } - - pub fn remove(&mut self, position: &Position) { - self.positions.retain(|&p| p != *position); - } - - pub fn remove_all(&mut self, positions: &Vec) { - for position in positions { - self.remove(position); - } - } - - pub fn reset(&mut self) { - self.positions = Self::new_positions(self.width, self.height); - } -} - #[derive(Default, Resource)] pub struct LastSpecialSpawn(pub u32); diff --git a/src/game/systems/control.rs b/src/game/systems/control.rs index a37f00d..76b256b 100644 --- a/src/game/systems/control.rs +++ b/src/game/systems/control.rs @@ -1,3 +1,4 @@ +use rand::seq::SliceRandom; use rand::{thread_rng, Rng}; use bevy::prelude::*; @@ -206,106 +207,73 @@ impl Command for SpawnAntidote { } } -pub fn init_diplopod(mut commands: Commands) { +pub fn setup_game(mut commands: Commands) { commands.queue(SpawnDiplopodSegment); -} -pub fn init_wall(mut commands: Commands, mut free_positions: ResMut) { for x in 0..CONSUMABLE_WIDTH + 1 { let position = Position { x, y: 0 }; commands.queue(SpawnWall { position }); - free_positions.remove(&position); let position = Position { x, y: CONSUMABLE_HEIGHT, }; commands.queue(SpawnWall { position }); - free_positions.remove(&position); } for y in 1..CONSUMABLE_HEIGHT { let position = Position { x: 0, y }; commands.queue(SpawnWall { position }); - free_positions.remove(&position); let position = Position { x: CONSUMABLE_WIDTH, y, }; commands.queue(SpawnWall { position }); - free_positions.remove(&position); } -} -pub fn init_food(mut commands: Commands, mut free_positions: ResMut) { - spawn_food(&mut commands, &mut free_positions); -} + let mut position_candidates: Vec = + Vec::with_capacity(((CONSUMABLE_WIDTH - 1) * (CONSUMABLE_HEIGHT - 1)) as usize); -fn spawn_food(commands: &mut Commands, free_positions: &mut ResMut) { - let segment_positions = vec![DiplopodPosition { + for x in 1..CONSUMABLE_WIDTH { + for y in 1..CONSUMABLE_HEIGHT { + position_candidates.push(Position { x, y }); + } + } + + let segment_position = DiplopodPosition { x: ARENA_WIDTH / 2, y: ARENA_HEIGHT / 2, } - .to_position()]; + .to_position(); + position_candidates.retain(|&p| p != segment_position); - let mut position_candidates = free_positions.clone(); - position_candidates.remove_all(&segment_positions); + position_candidates.shuffle(&mut thread_rng()); - spawn_random_food( - AMOUNT_OF_FOOD, - commands, - &mut position_candidates, - free_positions, - ); + spawn_random_food(AMOUNT_OF_FOOD, &mut commands, &mut position_candidates); + spawn_random_poison(AMOUNT_OF_POISON, &mut commands, &mut position_candidates); } fn spawn_random_food( amount: u32, commands: &mut Commands, - position_candidates: &mut FreePositions, - free_positions: &mut ResMut, + position_candidates: &mut Vec, ) { for _ in 0..amount { - if let Some(position) = position_candidates.positions.pop() { + if let Some(position) = position_candidates.pop() { commands.queue(SpawnFood { position }); - free_positions.remove(&position); } } } -pub fn init_poison(mut commands: Commands, mut free_positions: ResMut) { - spawn_poison(&mut commands, &mut free_positions); -} - -fn spawn_poison(commands: &mut Commands, free_positions: &mut ResMut) { - let segment_positions = vec![DiplopodPosition { - x: ARENA_WIDTH / 2, - y: ARENA_HEIGHT / 2, - } - .to_position()]; - - let mut position_candidates = free_positions.clone(); - position_candidates.remove_all(&segment_positions); - - spawn_random_poison( - AMOUNT_OF_POISON, - commands, - &mut position_candidates, - free_positions, - ); -} - fn spawn_random_poison( amount: u32, commands: &mut Commands, - position_candidates: &mut FreePositions, - free_positions: &mut ResMut, + position_candidates: &mut Vec, ) { for _ in 0..amount { - if let Some(position) = position_candidates.positions.pop() { + if let Some(position) = position_candidates.pop() { commands.queue(SpawnPoison { position }); - free_positions.remove(&position); } } } @@ -315,39 +283,39 @@ pub fn spawn_consumables( mut commands: Commands, segments: ResMut, mut spawn_consumables_reader: EventReader, - mut diplopod_positions: Query<&mut DiplopodPosition>, + diplopod_positions: Query<&DiplopodPosition>, positions: Query<&Position>, superfood: Query>, antidotes: Query>, - mut free_positions: ResMut, mut last_special_spawn: ResMut, sounds: Res, ) { if let Some(spawn_event) = spawn_consumables_reader.read().next() { - let segment_positions = segments - .0 - .iter() - .map(|e| *diplopod_positions.get_mut(*e).unwrap()) - .map(|p| p.to_position()) - .collect::>(); + let mut position_candidates: Vec = + Vec::with_capacity(((CONSUMABLE_WIDTH - 1) * (CONSUMABLE_HEIGHT - 1)) as usize); - let mut position_candidates = free_positions.clone(); - position_candidates.remove_all(&segment_positions); + for x in 1..CONSUMABLE_WIDTH { + for y in 1..CONSUMABLE_HEIGHT { + position_candidates.push(Position { x, y }); + } + } + + for position in positions.iter() { + position_candidates.retain(|&p| p != *position); + } + + for segment in segments.0.iter() { + if let Ok(diplopod_position) = diplopod_positions.get(*segment) { + let position = diplopod_position.to_position(); + position_candidates.retain(|&p| p != position); + } + } + + position_candidates.shuffle(&mut thread_rng()); if spawn_event.regular { - spawn_random_food( - 1, - &mut commands, - &mut position_candidates, - &mut free_positions, - ); - - spawn_random_poison( - 1, - &mut commands, - &mut position_candidates, - &mut free_positions, - ); + spawn_random_food(1, &mut commands, &mut position_candidates); + spawn_random_poison(1, &mut commands, &mut position_candidates); } let new_size = segments.0.len() as u32 + spawn_event.new_segments as u32; @@ -355,29 +323,21 @@ pub fn spawn_consumables( last_special_spawn.0 = (new_size / SPECIAL_SPAWN_INTERVAL) * SPECIAL_SPAWN_INTERVAL; for ent in superfood.iter() { - let position = positions.get(ent).unwrap(); - free_positions.positions.push(*position); commands.entity(ent).despawn(); } - free_positions.shuffle(); if last_special_spawn.0 % (SPECIAL_SPAWN_INTERVAL * 2) == 0 { for ent in antidotes.iter() { - let position = positions.get(ent).unwrap(); - free_positions.positions.push(*position); commands.entity(ent).despawn(); } - free_positions.shuffle(); - if let Some(position) = position_candidates.positions.pop() { + if let Some(position) = position_candidates.pop() { commands.queue(SpawnAntidote { position }); - free_positions.remove(&position); } } - if let Some(position) = position_candidates.positions.pop() { + if let Some(position) = position_candidates.pop() { commands.queue(SpawnSuperfood { position }); - free_positions.remove(&position); } commands.spawn(( @@ -433,15 +393,12 @@ pub fn eat( antidote_positions: Query<(Entity, &Position), With>, mut heads: Query<(&mut DiplopodHead, &DiplopodPosition)>, wall_positions: Query<(Entity, &Position), With>, - mut free_positions: ResMut, sounds: Res, ) { for (mut head, head_pos) in heads.iter_mut() { for (ent, food_pos) in food_positions.iter() { if *food_pos == head_pos.to_position() { commands.entity(ent).despawn(); - free_positions.positions.push(*food_pos); - free_positions.shuffle(); growth_writer.send(Growth(1)); spawn_consumables_writer.send(SpawnConsumables { @@ -459,8 +416,6 @@ pub fn eat( for (ent, superfood_pos) in superfood_positions.iter() { if *superfood_pos == head_pos.to_position() { commands.entity(ent).despawn(); - free_positions.positions.push(*superfood_pos); - free_positions.shuffle(); let new_segments = thread_rng().gen_range(2..10); growth_writer.send(Growth(new_segments)); @@ -484,7 +439,6 @@ pub fn eat( for (ent, antidote_pos) in antidote_positions.iter() { if *antidote_pos == head_pos.to_position() { commands.entity(ent).despawn(); - free_positions.positions.push(*antidote_pos); let remaining = head.immunity.remaining_secs(); head.immunity = Timer::from_seconds(10.0 + remaining, TimerMode::Once); @@ -502,8 +456,6 @@ pub fn eat( if *poison_pos == head_pos.to_position() { if !head.immunity.finished() { commands.entity(ent).despawn(); - free_positions.positions.push(*poison_pos); - free_positions.shuffle(); growth_writer.send(Growth(1)); commands.spawn(( @@ -597,7 +549,6 @@ pub fn game_over( mut commands: Commands, mut reader: EventReader, mut segments: ResMut, - mut free_positions: ResMut, mut last_special_spawn: ResMut, sounds: Res, mut game_state: ResMut>, @@ -616,8 +567,6 @@ pub fn game_over( highscore.0 = lastscore.0; } - free_positions.reset(); - last_special_spawn.0 = 0; segments.0 = Vec::new();