95 lines
2.8 KiB
Rust
95 lines
2.8 KiB
Rust
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::<EatenEvent>()
|
|
.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<Entity>);
|
|
|
|
#[derive(Component)]
|
|
pub struct Fruit;
|
|
|
|
pub fn eaten_event_sent(mut eaten_event_reader: EventReader<EatenEvent>) -> 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<SnakeHead>>,
|
|
fruit_query: Query<(Entity, &grid::Coordinate), With<Fruit>>,
|
|
mut eaten_event_writer: EventWriter<EatenEvent>,
|
|
) {
|
|
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<EatenEvent>) {
|
|
for &EatenEvent(fruit) in event_reader.read() {
|
|
if let Some(fruit) = fruit {
|
|
commands.entity(fruit).despawn();
|
|
}
|
|
}
|
|
}
|