Files
bevy-snake/src/fruit.rs
2024-02-18 12:48:34 +01:00

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();
}
}
}