a bit more collision detection logic
This commit is contained in:
30
game_core/src/field/field.rs
Normal file
30
game_core/src/field/field.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub enum Tile {
|
||||
Empty,
|
||||
Wall,
|
||||
Food,
|
||||
}
|
||||
|
||||
pub struct Field {
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub tiles: Vec<Tile>,
|
||||
}
|
||||
|
||||
impl Field {
|
||||
pub fn new(width: usize, height: usize) -> Self {
|
||||
Self {
|
||||
width,
|
||||
height,
|
||||
tiles: vec![Tile::Empty; width * height],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_tile(&self, x: usize, y: usize) -> Tile {
|
||||
self.tiles[y * self.width + x]
|
||||
}
|
||||
|
||||
pub fn set_tile(&mut self, x: usize, y: usize, tile: Tile) {
|
||||
self.tiles[y * self.width + x] = tile;
|
||||
}
|
||||
}
|
||||
1
game_core/src/field/mod.rs
Normal file
1
game_core/src/field/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod field;
|
||||
15
game_core/src/game_handler/game_handler.rs
Normal file
15
game_core/src/game_handler/game_handler.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use crate::{field::field::Field, snake::snake::SnakeHandler};
|
||||
|
||||
pub struct GameData {
|
||||
field: Field,
|
||||
snakes: Vec<SnakeHandler>,
|
||||
}
|
||||
|
||||
impl GameData {
|
||||
pub fn new(field: Field, snakes: Vec<SnakeHandler>) -> Self {
|
||||
Self {
|
||||
field,
|
||||
snakes,
|
||||
}
|
||||
}
|
||||
}
|
||||
2
game_core/src/game_handler/mod.rs
Normal file
2
game_core/src/game_handler/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod game_handler;
|
||||
pub mod states;
|
||||
33
game_core/src/game_handler/states.rs
Normal file
33
game_core/src/game_handler/states.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::{game_handler::game_handler::GameData, inputs::Inputs};
|
||||
|
||||
|
||||
pub trait GameManagerState {
|
||||
fn update(&mut self, delta: Duration, inputs: &Inputs, game_data: &mut GameData) -> Option<Box<dyn GameManagerState>>;
|
||||
}
|
||||
|
||||
|
||||
pub struct PlayingState {
|
||||
dt_accumulator: Duration,
|
||||
}
|
||||
|
||||
impl PlayingState {
|
||||
pub fn new() -> Self {
|
||||
Self { dt_accumulator: Duration::ZERO }
|
||||
}
|
||||
}
|
||||
|
||||
impl GameManagerState for PlayingState {
|
||||
fn update(&mut self, delta: Duration, inputs: &Inputs, game_data: &mut GameData) -> Option<Box<dyn GameManagerState>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PausedState;
|
||||
|
||||
impl GameManagerState for PausedState {
|
||||
fn update(&mut self, _delta: Duration, _inputs: &Inputs, _game_data: &mut GameData) -> Option<Box<dyn GameManagerState>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ pub mod inputs;
|
||||
pub mod snake;
|
||||
pub mod common;
|
||||
pub mod traits;
|
||||
pub mod field;
|
||||
pub mod game_handler;
|
||||
|
||||
pub fn add(left: u64, right: u64) -> u64 {
|
||||
left + right
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use std::time::Duration;
|
||||
use crate::common::position::Position;
|
||||
use crate::inputs::Inputs;
|
||||
use crate::field::field::{Field, Tile};
|
||||
use crate::snake::states::SnakeState;
|
||||
|
||||
pub struct Node {
|
||||
@@ -43,10 +44,46 @@ impl Snake {
|
||||
false
|
||||
}
|
||||
|
||||
// TODO: implement this once we have wall data
|
||||
// pub fn is_colliding_against_wall(other_snake: &Snake) {
|
||||
pub fn is_colliding_against_itself(&self) -> bool {
|
||||
let head_pos = self.body.position;
|
||||
let mut current_node = self.body.next.as_deref();
|
||||
|
||||
// }
|
||||
while let Some(node) = current_node {
|
||||
if node.position == head_pos {
|
||||
return true;
|
||||
}
|
||||
current_node = node.next.as_deref();
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn is_reaching_field_boundaries(&self, field: &Field) -> bool {
|
||||
// TODO: implement logic to teleport snake's head to the other side
|
||||
let pos = self.body.position;
|
||||
if pos.x < 0 || pos.x >= field.width as isize || pos.y < 0 || pos.y >= field.height as isize {
|
||||
return true;
|
||||
}
|
||||
false
|
||||
|
||||
}
|
||||
|
||||
pub fn is_colliding_against_wall(&self, field: &Field) -> bool {
|
||||
let pos = self.body.position;
|
||||
if pos.x < 0 || pos.x >= field.width as isize || pos.y < 0 || pos.y >= field.height as isize {
|
||||
return false;
|
||||
}
|
||||
|
||||
field.get_tile(pos.x as usize, pos.y as usize) == Tile::Wall
|
||||
}
|
||||
|
||||
pub fn is_eating(&self, field: &Field) -> bool {
|
||||
let pos = self.body.position;
|
||||
if pos.x < 0 || pos.x >= field.width as isize || pos.y < 0 || pos.y >= field.height as isize {
|
||||
return false;
|
||||
}
|
||||
|
||||
field.get_tile(pos.x as usize, pos.y as usize) == Tile::Food
|
||||
}
|
||||
|
||||
pub fn do_move(&mut self) {
|
||||
// probably a more optimal way of approaching this is just
|
||||
@@ -65,6 +102,16 @@ impl Snake {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn grow(&mut self) {
|
||||
let mut tail = &mut self.body;
|
||||
while let Some(ref mut next_node) = tail.next {
|
||||
tail = next_node;
|
||||
}
|
||||
tail.next = Some(Box::new(Node {
|
||||
position: tail.position,
|
||||
next: None,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SnakeHandler {
|
||||
@@ -153,4 +200,49 @@ mod tests {
|
||||
let first_body = snake.body.next.as_ref().unwrap();
|
||||
assert_eq!(first_body.position, Position{x: 10, y: 10});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_grow() {
|
||||
// Setup: Snake with just a head at (10, 10)
|
||||
let mut snake = Snake::new(Position { x: 10, y: 10 }, Position { x: 1, y: 0 }, 1.0);
|
||||
assert!(snake.body.next.is_none());
|
||||
|
||||
snake.grow();
|
||||
|
||||
let first_body = snake.body.next.as_ref().unwrap();
|
||||
assert!(first_body.next.is_none());
|
||||
assert_eq!(first_body.position, Position { x: 10, y: 10 });
|
||||
|
||||
snake.grow();
|
||||
|
||||
let first_body = snake.body.next.as_ref().unwrap();
|
||||
let second_body = first_body.next.as_ref().unwrap();
|
||||
assert_eq!(second_body.position, Position { x: 10, y: 10 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_colliding_against_itself() {
|
||||
// Snake head at (5, 5)
|
||||
let mut snake = Snake::new(Position { x: 5, y: 5 }, Position { x: 1, y: 0 }, 1.0);
|
||||
|
||||
// Body at (5, 5) -> (5, 6) -> (5, 5)
|
||||
snake.body.next = Some(Box::new(Node {
|
||||
position: Position { x: 5, y: 6 },
|
||||
next: Some(Box::new(Node {
|
||||
position: Position { x: 5, y: 5 },
|
||||
next: None,
|
||||
})),
|
||||
}));
|
||||
|
||||
assert!(snake.is_colliding_against_itself());
|
||||
|
||||
// Snake with no self-collision
|
||||
let mut safe_snake = Snake::new(Position { x: 5, y: 5 }, Position { x: 1, y: 0 }, 1.0);
|
||||
safe_snake.body.next = Some(Box::new(Node {
|
||||
position: Position { x: 6, y: 5 },
|
||||
next: None,
|
||||
}));
|
||||
|
||||
assert!(!safe_snake.is_colliding_against_itself());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user