Skip to content

Commit

Permalink
extract snake into its own module, leaving main clean
Browse files Browse the repository at this point in the history
Signed-off-by: Agustín Ramiro Díaz <agustin.ramiro.diaz@gmail.com>
  • Loading branch information
AgustinRamiroDiaz committed Jan 7, 2024
1 parent e19b97b commit 0eb7123
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 217 deletions.
2 changes: 1 addition & 1 deletion src/ai.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use rand::prelude::*;

use crate::apple::Apple;
use crate::coordinate::Coordinate;
use crate::snake::Snake;
use crate::Direction;
use crate::Id;
use crate::ProposeDirection;
use crate::Snake;
use crate::HALF_LEN;

use rand;
Expand Down
8 changes: 6 additions & 2 deletions src/apple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ use bevy::prelude::*;
use rand::Rng;

use super::{
asset_loader::SceneAssets, coordinate::Coordinate, game_state::AppState, schedule::InGameSet,
Depth, MyColor, Snake, SnakeSegment, HALF_LEN, SIZE,
asset_loader::SceneAssets,
coordinate::Coordinate,
game_state::AppState,
schedule::InGameSet,
snake::{Depth, MyColor, Snake, SnakeSegment},
HALF_LEN, SIZE,
};

pub(crate) struct ApplePlugin;
Expand Down
2 changes: 1 addition & 1 deletion src/collision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use bevy::prelude::*;
use super::coordinate::Coordinate;

use super::game_state::AppState;
use super::Snake;
use super::snake::Snake;

use super::blink::{BlinkPlugin, Blinking};
use super::movement::Tick;
Expand Down
222 changes: 12 additions & 210 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
use std::collections::VecDeque;

use bevy::{prelude::*, window::WindowMode};
use movement::ProposeDirection;

mod coordinate;
use coordinate::Coordinate;

mod direction;
use direction::Direction;

mod main_menu;
use main_menu::MainMenu;
use main_menu::NumberOfPlayersSelected;

mod game_state;
use game_state::{AppState, GameStatePlugin};
use game_state::GameStatePlugin;

mod ai;
use ai::AIPlugin;
Expand All @@ -40,11 +36,21 @@ use collision::CollisionPlugin;
mod blink;

mod schedule;
use schedule::InGameSet;
use schedule::SchedulePlugin;

mod snake;
use snake::{Id, SnakePlugin};

use std::env;

const SIZE: f32 = 0.8;
const HALF_LEN: i32 = 7;
const BOARD_LEN: i32 = 2 * HALF_LEN;
const PADDING: f32 = 1.0;
const BOARD_VIEWPORT_IN_WORLD_UNITS: f32 = BOARD_LEN as f32 + 2.0 * PADDING;

const MAX_NUMBER_OF_PLAYERS: usize = 4;

fn main() {
let mut app = App::new();

Expand Down Expand Up @@ -84,207 +90,3 @@ fn main() {

app.run();
}

struct SnakePlugin;

const SIZE: f32 = 0.8;
const HALF_LEN: i32 = 7;
const BOARD_LEN: i32 = 2 * HALF_LEN;
const PADDING: f32 = 1.0;
const BOARD_VIEWPORT_IN_WORLD_UNITS: f32 = BOARD_LEN as f32 + 2.0 * PADDING;

const MAX_NUMBER_OF_PLAYERS: usize = 4;

impl Plugin for SnakePlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, setup)
.add_systems(
Update,
(
toroid_coordinates,
add_sprite_bundles,
// This is needed in order to render the sprites correctly, we need to flush the sprites into the world and then update their transforms
apply_deferred,
update_local_coordinates_to_world_transforms,
)
.chain()
.in_set(InGameSet::Last)
.run_if(in_state(AppState::InGame)),
)
.add_systems(
OnEnter(AppState::InGame),
(despawn_snakes, spawn_snakes).chain(),
);
}
}

fn setup(mut commands: Commands) {
let mut grid = vec![];

for x in -HALF_LEN..=HALF_LEN {
for y in -HALF_LEN..=HALF_LEN {
grid.push((
SpriteBundle {
sprite: Sprite {
custom_size: Some(Vec2 { x: SIZE, y: SIZE }),
color: Color::DARK_GRAY,
..Default::default()
},
..Default::default()
},
Coordinate(Vec2::new(x as f32, y as f32)),
Depth(-1.0),
));
}
}
commands.spawn_batch(grid);

commands.spawn(Camera2dBundle {
projection: OrthographicProjection {
far: 1000.,
near: -1000.,
scaling_mode: bevy::render::camera::ScalingMode::AutoMin {
min_width: BOARD_VIEWPORT_IN_WORLD_UNITS,
min_height: BOARD_VIEWPORT_IN_WORLD_UNITS,
},
..Default::default()
},
..default()
});
}

fn spawn_snakes(mut commands: Commands, number_of_players: Res<NumberOfPlayersSelected>) {
let mut spawn_snake =
|id, spawn_coord: Coordinate, direction: Direction, color: MyColor, name: String| {
let head_a = commands
.spawn((color, SnakeSegment, spawn_coord.clone()))
.id();

commands.spawn((
Snake {
segments: VecDeque::from([head_a]),
player_number: id,
direction: direction.clone(),
trail: Coordinate(
spawn_coord.0 - <direction::Direction as Into<Vec2>>::into(direction),
),
input_blocked: false,
inmortal_ticks: 0,
name,
},
color,
));
};

let snakes = [
(
Id(1),
Coordinate::from((-3.0, -3.0)),
Direction::Right,
MyColor(Color::LIME_GREEN),
"Ninja".to_string(),
),
(
Id(2),
Coordinate::from((3.0, 3.0)),
Direction::Left,
MyColor(Color::PINK),
"Panther".to_string(),
),
(
Id(3),
Coordinate::from((-3.0, 3.0)),
Direction::Down,
MyColor(Color::SALMON),
"Sushi".to_string(),
),
(
Id(4),
Coordinate::from((3.0, -3.0)),
Direction::Up,
MyColor(Color::TURQUOISE),
"Sonic".to_string(),
),
];

snakes
.into_iter()
.take(number_of_players.0)
.map(|(id, coord, direction, color, name)| spawn_snake(id, coord, direction, color, name))
.count();
}

fn despawn_snakes(mut commands: Commands, snakes: Query<(Entity, &Snake)>) {
snakes.iter().for_each(|(entity, snake)| {
snake
.segments
.iter()
.for_each(|&entity| commands.entity(entity).despawn_recursive());
commands.entity(entity).despawn_recursive();
});
}

#[derive(Component)]
pub(crate) struct Snake {
name: String,
segments: VecDeque<Entity>,
direction: Direction,
player_number: Id, // TODO: move into its own component
trail: Coordinate,
input_blocked: bool,
inmortal_ticks: u8,
}

#[derive(Component, Debug, PartialEq, Clone)]
struct Id(u8);

#[derive(Component)]
struct SnakeSegment;

#[derive(Component, Clone, Copy)]
struct MyColor(Color);

fn update_local_coordinates_to_world_transforms(
mut query: Query<
(&Coordinate, &mut Transform, Option<&Depth>),
Or<(Changed<Coordinate>, Changed<Transform>)>,
>,
) {
for (coordinate, mut transform, depth) in query.iter_mut() {
transform.translation = coordinate.0.extend(depth.map_or(0.0, |x| x.0))
}
}

#[derive(Component)]
struct Depth(f32);

// TODO: we assume that Transform == SpriteBundle
fn add_sprite_bundles(
mut query: Query<(Entity, &MyColor), (Changed<Coordinate>, Without<Transform>)>,
mut commands: Commands,
) {
for (entity, color) in query.iter_mut() {
commands.entity(entity).insert(SpriteBundle {
sprite: Sprite {
custom_size: Some(Vec2 { x: SIZE, y: SIZE }),
color: color.0,
..Default::default()
},

..Default::default()
});
}
}

fn toroid_coordinates(
mut query: Query<&mut Coordinate, (With<SnakeSegment>, Changed<Coordinate>)>,
) {
for mut coordinate in query.iter_mut() {
if coordinate.0.x.abs() > HALF_LEN as f32 {
coordinate.0.x = -coordinate.0.x.signum() * HALF_LEN as f32;
}
if coordinate.0.y.abs() > HALF_LEN as f32 {
coordinate.0.y = -coordinate.0.y.signum() * HALF_LEN as f32;
}
}
}
2 changes: 1 addition & 1 deletion src/movement.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bevy::prelude::*;
use leafwing_input_manager::prelude::*;

use crate::{coordinate::Coordinate, game_state, Direction, Id, Snake};
use crate::{coordinate::Coordinate, game_state, snake::Snake, Direction, Id};

const SNAKE_TICK_SECONDS: f32 = 0.1;

Expand Down
2 changes: 1 addition & 1 deletion src/score.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bevy::prelude::*;
use std::iter;

use crate::{game_state, main_menu::NumberOfPlayersSelected, MyColor, Snake};
use crate::{game_state, main_menu::NumberOfPlayersSelected, snake::MyColor, snake::Snake};

pub(crate) struct ScorePlugin;

Expand Down
Loading

0 comments on commit 0eb7123

Please sign in to comment.