2 Commits e8025cd25d ... 0b82fe8cea

Author SHA1 Message Date
  Getty Ritter 0b82fe8cea avoid spawning food on the snake tail 2 years ago
  Getty Ritter fdae473d9f fix the quick-turning bug 2 years ago
3 changed files with 31 additions and 10 deletions
  1. 3 1
      src/components.rs
  2. 22 5
      src/main.rs
  3. 6 4
      src/snake.rs

+ 3 - 1
src/components.rs

@@ -25,7 +25,7 @@ impl GridSize {
     }
 }
 
-#[derive(PartialEq, Copy, Clone)]
+#[derive(PartialEq, Copy, Clone, Debug)]
 pub enum Direction {
     Left,
     Up,
@@ -55,7 +55,9 @@ pub struct Materials {
 pub struct Food;
 
 // snake-related components
+#[derive(Debug)]
 pub struct SnakeHead {
+    pub intention: Direction,
     pub direction: Direction,
 }
 

+ 22 - 5
src/main.rs

@@ -72,17 +72,34 @@ fn setup(mut commands: Commands, mut materials: ResMut<Assets<ColorMaterial>>) {
     });
 }
 
-fn food_spawner(mut commands: Commands, materials: Res<c::Materials>) {
+fn food_spawner(
+    mut commands: Commands,
+    materials: Res<c::Materials>,
+    segments: Query<&c::Position, With<c::SnakeSegment>>,
+) {
+    let snake_positions = segments.iter().collect::<Vec<&c::Position>>();
+    // try three times, giving up if we still haven't found a free spot
+    let mut x;
+    let mut y;
+    let mut attempts = 3;
+    loop {
+        x = (random::<f32>() * c::ARENA_WIDTH as f32) as i32;
+        y = (random::<f32>() * c::ARENA_HEIGHT as f32) as i32;
+        if !snake_positions.contains(&&c::Position {x, y}) {
+            break;
+        }
+        attempts -= 1;
+        if attempts == 0 {
+            return;
+        }
+    }
     commands
         .spawn_bundle(SpriteBundle {
             material: materials.food_material.clone(),
             ..Default::default()
         })
         .insert(c::Food)
-        .insert(c::Position {
-            x: (random::<f32>() * c::ARENA_WIDTH as f32) as i32,
-            y: (random::<f32>() * c::ARENA_HEIGHT as f32) as i32,
-        })
+        .insert(c::Position { x, y })
         .insert(c::GridSize::square(0.8));
 }
 

+ 6 - 4
src/snake.rs

@@ -31,6 +31,7 @@ pub fn spawn(
             })
             .insert(c::SnakeHead {
                 direction: c::Direction::Up,
+                intention: c::Direction::Up,
             })
             .insert(c::SnakeSegment)
             .insert(c::Position { x: 3, y: 3 })
@@ -55,10 +56,10 @@ pub fn input(keyboard_input: Res<Input<KeyCode>>, mut heads: Query<&mut c::Snake
         } else if keyboard_input.pressed(KeyCode::Right) {
             c::Direction::Right
         } else {
-            head.direction
+            head.intention
         };
         if dir != head.direction.opposite() {
-            head.direction = dir;
+            head.intention = dir;
         }
     }
 }
@@ -67,16 +68,17 @@ pub fn movement(
     segments: ResMut<c::SnakeSegments>,
     mut last_tail_position: ResMut<c::LastTailPosition>,
     mut game_over_writer: EventWriter<c::GameOverEvent>,
-    mut heads: Query<(Entity, &c::SnakeHead)>,
+    mut heads: Query<(Entity, &mut c::SnakeHead)>,
     mut positions: Query<&mut c::Position>,
 ) {
-    if let Some((head_entity, head)) = heads.iter_mut().next() {
+    if let Some((head_entity, mut head)) = heads.iter_mut().next() {
         let segment_positions = segments
             .segments
             .iter()
             .map(|e| *positions.get_mut(*e).unwrap())
             .collect::<Vec<c::Position>>();
         let mut head_pos = positions.get_mut(head_entity).unwrap();
+        head.direction = head.intention;
         match &head.direction {
             c::Direction::Left => head_pos.x -= 1,
             c::Direction::Right => head_pos.x += 1,