Snake collision with itself

This commit is contained in:
2022-08-18 21:26:52 +02:00
parent 10daae1cf6
commit d1db542b16
6 changed files with 489 additions and 89 deletions

View File

@@ -1,21 +1,23 @@
use crate::grid;
use bevy::prelude::*;
pub struct ModPlugin;
pub struct CanvasPlugin;
impl Plugin for ModPlugin {
impl Plugin for CanvasPlugin {
fn build(&self, app: &mut App) {
app.add_startup_system(spawn_background);
}
}
fn spawn_background(mut commands: Commands) {
commands.spawn_bundle(SpriteBundle {
sprite: Sprite {
color: Color::DARK_GRAY,
custom_size: Some(Vec2::splat(grid::SEGMENT_SIZE * grid::SIZE as f32)),
commands
.spawn_bundle(SpriteBundle {
sprite: Sprite {
color: Color::DARK_GRAY,
custom_size: Some(Vec2::splat(grid::SEGMENT_SIZE * grid::SIZE as f32)),
..Default::default()
},
..Default::default()
},
..Default::default()
});
})
.insert(Name::new("Canvas"));
}

View File

@@ -6,13 +6,17 @@ pub type Index = i16;
pub const SIZE: Index = 17;
pub const SEGMENT_SIZE: f32 = 20.;
#[derive(Component, Clone, Copy, Default, Debug)]
#[derive(Component, Clone, Copy, Default, Debug, PartialEq, Eq)]
pub struct Coordinate(pub Index, pub Index);
impl Coordinate {
pub fn splat(v: Index) -> Self {
Self(v, v)
}
pub fn in_bounds(self) -> bool {
self.0 >= 0 && self.0 < SIZE && self.1 >= 0 && self.1 < SIZE
}
}
impl Add for Coordinate {
@@ -29,18 +33,17 @@ impl AddAssign for Coordinate {
}
}
impl From<Coordinate> for Transform {
impl From<Coordinate> for Vec2 {
fn from(grid_coordinate: Coordinate) -> Self {
(&grid_coordinate).into()
}
}
impl From<&Coordinate> for Transform {
impl From<&Coordinate> for Vec2 {
fn from(grid_coordinate: &Coordinate) -> Self {
Transform::from_xyz(
Vec2::new(
(grid_coordinate.0 - SIZE / 2) as f32 * SEGMENT_SIZE,
(grid_coordinate.1 - SIZE / 2) as f32 * SEGMENT_SIZE,
0.,
)
}
}

View File

@@ -1,5 +1,7 @@
use bevy::{prelude::*, render::camera::ScalingMode};
// use bevy_editor_pls::prelude::*;
use crate::{canvas::CanvasPlugin, snake::SnakePlugin};
use bevy_inspector_egui::WorldInspectorPlugin;
use grid::{SEGMENT_SIZE, SIZE};
use iyes_loopless::prelude::*;
@@ -31,9 +33,10 @@ fn main() {
})
.add_loopless_state(AppState::Begin)
.add_plugins(DefaultPlugins)
.add_plugin(WorldInspectorPlugin::new())
// .add_plugin(EditorPlugin)
.add_plugin(snake::ModPlugin)
.add_plugin(canvas::ModPlugin)
.add_plugin(SnakePlugin)
.add_plugin(CanvasPlugin)
.add_startup_system(setup_system)
.add_system(camera_move_system)
.add_system(bevy::window::close_on_esc)

View File

@@ -7,12 +7,16 @@ use std::time::Duration;
#[derive(Debug, Clone, PartialEq, Eq, Hash, StageLabel)]
struct FixedTimeStage;
pub struct ModPlugin;
pub struct SnakePlugin;
impl Plugin for ModPlugin {
impl Plugin for SnakePlugin {
fn build(&self, app: &mut App) {
let mut fixed_time_systems0 = SystemStage::parallel();
fixed_time_systems0.add_system(segments_movement_system.run_in_state(AppState::InGame));
fixed_time_systems0.add_system(
segments_movement_system
.run_in_state(AppState::InGame)
.run_if_not(about_to_lose),
);
let mut fixed_time_systems1 = SystemStage::parallel();
fixed_time_systems1
@@ -42,13 +46,15 @@ impl Plugin for ModPlugin {
}
}
const Z_HEIGHT: f32 = 10.;
#[derive(Component)]
struct SnakeSegment;
#[derive(Component)]
struct SnakeHead;
#[derive(Component)]
#[derive(Component, Copy, Clone)]
enum Direction {
Up,
Down,
@@ -92,7 +98,7 @@ fn create_snake_segment(commands: &mut Commands, grid_position: grid::Coordinate
custom_size: Some(Vec2::splat(grid::SEGMENT_SIZE) * 0.9),
..Default::default()
},
transform: grid_position.into(),
transform: Transform::from_translation(Vec2::from(grid_position).extend(Z_HEIGHT)),
..Default::default()
})
.insert(SnakeSegment)
@@ -139,7 +145,13 @@ fn add_tail_system(
let segment =
create_snake_segment(&mut commands, grid::Coordinate::splat(grid::Index::MIN / 2));
let (snake, mut snake_segments) = snake_query.single_mut();
let segment_number = snake_segments.0.len();
snake_segments.0.push(segment);
commands
.entity(segment)
.insert(Name::new(format!("Segment {}", segment_number)));
commands.entity(snake).add_child(segment);
}
}
@@ -167,19 +179,14 @@ fn grid_transform_system(
mut query: Query<(&mut Transform, &grid::Coordinate), With<SnakeSegment>>,
) {
for (mut transform, grid_coordinate) in query.iter_mut() {
*transform = grid_coordinate.into();
*transform = Transform::from_translation(Vec2::from(grid_coordinate).extend(Z_HEIGHT));
}
}
fn head_movement_system(mut query: Query<(&mut grid::Coordinate, &Direction), With<SnakeHead>>) {
let (mut grid_coordinate, direction) = query.single_mut();
let (mut grid_coordinate, &direction) = query.single_mut();
match direction {
Direction::Up => *grid_coordinate += grid::Coordinate(0, 1),
Direction::Down => *grid_coordinate += grid::Coordinate(0, -1),
Direction::Left => *grid_coordinate += grid::Coordinate(-1, 0),
Direction::Right => *grid_coordinate += grid::Coordinate(1, 0),
};
*grid_coordinate = next_grid_coordinate(*grid_coordinate, direction);
}
fn segments_movement_system(
@@ -197,18 +204,34 @@ fn segments_movement_system(
}
}
fn about_to_lose(query: Query<(&grid::Coordinate, &Direction), With<SnakeHead>>) -> bool {
const HIGH_BARRIER: grid::Index = grid::SIZE - 1;
fn about_to_lose(
head_query: Query<(&grid::Coordinate, &Direction), With<SnakeHead>>,
segment_query: Query<&grid::Coordinate, (With<SnakeSegment>, Without<SnakeHead>)>,
) -> bool {
let (&head_coordinate, &head_direction) = head_query.single();
let next_head_coordinate = next_grid_coordinate(head_coordinate, head_direction);
matches!(
query.single(),
(grid::Coordinate(_, 0), Direction::Down)
| (grid::Coordinate(_, HIGH_BARRIER), Direction::Up)
| (grid::Coordinate(0, _), Direction::Left)
| (grid::Coordinate(HIGH_BARRIER, _), Direction::Right)
)
let hit_border = !next_head_coordinate.in_bounds();
let hit_snake = !segment_query
.iter()
.all(|&coordinate| coordinate != next_head_coordinate);
hit_border || hit_snake
}
fn game_over_system(mut commands: Commands) {
commands.insert_resource(NextState(AppState::End));
}
fn next_grid_coordinate(
current_coordinate: grid::Coordinate,
direction: Direction,
) -> grid::Coordinate {
match direction {
Direction::Up => current_coordinate + grid::Coordinate(0, 1),
Direction::Down => current_coordinate + grid::Coordinate(0, -1),
Direction::Left => current_coordinate + grid::Coordinate(-1, 0),
Direction::Right => current_coordinate + grid::Coordinate(1, 0),
}
}