use crate::{ grid, snake::{self, SnakeHead}, }; use bevy::prelude::*; use rand::prelude::*; const Z_HEIGHT: f32 = snake::Z_HEIGHT / 2.; pub struct FruitPlugin; impl Plugin for FruitPlugin { fn build(&self, app: &mut App) { app.add_event::() .add_systems(Startup, spawn_fruit_system) .add_systems(FixedUpdate, eat_fruit_system) .add_systems( Update, ( despawn_fruit_system, spawn_fruit_system.run_if(eaten_event_sent), ), ); } } #[derive(Event)] pub struct EatenEvent(Option); #[derive(Component)] pub struct Fruit; pub fn eaten_event_sent(mut eaten_event_reader: EventReader) -> bool { eaten_event_reader.read().count() != 0 } fn spawn_fruit_system(mut commands: Commands, coordinate_query: Query<&grid::Coordinate>) { fn random_coordinate() -> grid::Coordinate { let mut rng = rand::thread_rng(); let coordinate_range = 0..grid::SIZE; grid::Coordinate( rng.gen_range(coordinate_range.clone()), rng.gen_range(coordinate_range), ) } let coordinate_in_other_element = |coordinate: grid::Coordinate| -> bool { coordinate_query .iter() .any(|&snake_coordinate| snake_coordinate == coordinate) }; let fruit_coordinate = std::iter::repeat_with(random_coordinate) .find(|&coordinate| !coordinate_in_other_element(coordinate)) .expect("Should always be found."); commands .spawn(SpriteBundle { sprite: Sprite { color: Color::GREEN, custom_size: Some(Vec2::splat(grid::SEGMENT_SIZE) * 0.6), ..Default::default() }, transform: Transform::from_translation(Vec2::from(fruit_coordinate).extend(Z_HEIGHT)), ..Default::default() }) .insert(fruit_coordinate) .insert(Fruit) .insert(crate::canvas::EmissiveTile { intensity: 1.0 }) .insert(Name::new("Fruit")); } fn eat_fruit_system( snake_head_query: Query<&grid::Coordinate, With>, fruit_query: Query<(Entity, &grid::Coordinate), With>, mut eaten_event_writer: EventWriter, ) { let &snake_head_coordinate = snake_head_query.single(); for (fruit, &fruit_coordinate) in fruit_query.iter() { if snake_head_coordinate == fruit_coordinate { eaten_event_writer.send(EatenEvent(Some(fruit))); } } } fn despawn_fruit_system(mut commands: Commands, mut event_reader: EventReader) { for &EatenEvent(fruit) in event_reader.read() { if let Some(fruit) = fruit { commands.entity(fruit).despawn(); } } }