Compare commits
3 Commits
e57300e673
...
b4166d9e63
| Author | SHA1 | Date | |
|---|---|---|---|
| b4166d9e63 | |||
| f75ab1ac47 | |||
| 33db0eaaef |
Vendored
+45
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "Debug unit tests in library 'game_core'",
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"--package=game_core"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug executable 'game_cli_frontend'",
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"run",
|
||||||
|
"--bin=game_cli_frontend",
|
||||||
|
"--package=game_cli_frontend"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"args": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Debug unit tests in executable 'game_cli_frontend'",
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"--bin=game_cli_frontend",
|
||||||
|
"--package=game_cli_frontend"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Generated
+17
@@ -57,6 +57,7 @@ name = "game_cli_frontend"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"game_core",
|
"game_core",
|
||||||
|
"termion",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -149,6 +150,12 @@ version = "2.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "numtoa"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prettyplease"
|
name = "prettyplease"
|
||||||
version = "0.2.37"
|
version = "0.2.37"
|
||||||
@@ -259,6 +266,16 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "termion"
|
||||||
|
version = "4.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f44138a9ae08f0f502f24104d82517ef4da7330c35acd638f1f29d3cd5475ecb"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"numtoa",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.24"
|
version = "1.0.24"
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ edition = "2024"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
game_core = { path = "../game_core" }
|
game_core = { path = "../game_core" }
|
||||||
|
termion = "4.0.6"
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
pub fn reset_cursor() {
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
termion::cursor::Goto(1, 1),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,14 +1,19 @@
|
|||||||
use game_core::field::field::{Field, Tile};
|
use game_core::field::field::{Field, Tile};
|
||||||
|
|
||||||
|
|
||||||
const BOUNDARY_TILE: &'static str = "#";
|
const BOUNDARY_TILE: &'static str = "#";
|
||||||
const WALL_TILE: &'static str = "█";
|
const WALL_TILE: &'static str = "█";
|
||||||
const EMPTY_TILE : &'static str = " ";
|
const EMPTY_TILE : &'static str = " ";
|
||||||
const FOOD_TILE : &'static str = "o";
|
const FOOD_TILE : &'static str = "o";
|
||||||
|
|
||||||
pub fn draw_field(field: &Field) {
|
pub fn draw_field(field: &Field, color: &dyn termion::color::Color) {
|
||||||
println!("{}", BOUNDARY_TILE.repeat(field.width + 2));
|
print!(
|
||||||
|
"{}",
|
||||||
|
termion::cursor::Goto(1, 1),
|
||||||
|
);
|
||||||
|
print!("{}{}\r\n", termion::color::Fg(color), BOUNDARY_TILE.repeat(field.width + 2));
|
||||||
for y in 0..field.height {
|
for y in 0..field.height {
|
||||||
print!("{}", BOUNDARY_TILE);
|
print!("{}{}", termion::color::Fg(color), BOUNDARY_TILE);
|
||||||
for x in 0..field.width {
|
for x in 0..field.width {
|
||||||
let tile = field.tiles[y * field.width + x];
|
let tile = field.tiles[y * field.width + x];
|
||||||
let char = match tile {
|
let char = match tile {
|
||||||
@@ -16,9 +21,9 @@ pub fn draw_field(field: &Field) {
|
|||||||
Tile::Wall => WALL_TILE,
|
Tile::Wall => WALL_TILE,
|
||||||
Tile::Food => FOOD_TILE,
|
Tile::Food => FOOD_TILE,
|
||||||
};
|
};
|
||||||
print!("{}", char);
|
print!("{}{}", termion::color::Fg(color), char);
|
||||||
}
|
}
|
||||||
println!("{}", BOUNDARY_TILE);
|
print!("{}{}\r\n", termion::color::Fg(color), BOUNDARY_TILE);
|
||||||
}
|
}
|
||||||
println!("{}", BOUNDARY_TILE.repeat(field.width + 2));
|
println!("{}{}\r\n", termion::color::Fg(color), BOUNDARY_TILE.repeat(field.width + 2));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
pub mod field;
|
pub mod field;
|
||||||
|
pub mod snake;
|
||||||
|
pub mod common;
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
use game_core::snake::snake::Snake;
|
||||||
|
|
||||||
|
const HEAD_TILE: &'static str = "@";
|
||||||
|
const BODY_TILE: &'static str = "@";
|
||||||
|
|
||||||
|
pub fn draw_snake(snake: &Snake, color: &dyn termion::color::Color, x_offset: isize, y_offset: isize) {
|
||||||
|
println!(
|
||||||
|
"{}{}{}",
|
||||||
|
termion::cursor::Goto(
|
||||||
|
(x_offset + snake.body.position.x).try_into().unwrap(),
|
||||||
|
(y_offset + snake.body.position.y).try_into().unwrap()
|
||||||
|
),
|
||||||
|
termion::color::Fg(color),
|
||||||
|
HEAD_TILE,
|
||||||
|
);
|
||||||
|
let mut current_node = snake.body.next.as_deref();
|
||||||
|
while let Some(node) = current_node {
|
||||||
|
println!(
|
||||||
|
"{}{}{}",
|
||||||
|
termion::cursor::Goto(
|
||||||
|
(x_offset + node.position.x).try_into().unwrap(),
|
||||||
|
(y_offset + node.position.y).try_into().unwrap()
|
||||||
|
),
|
||||||
|
termion::color::Fg(color),
|
||||||
|
BODY_TILE,
|
||||||
|
);
|
||||||
|
current_node = node.next.as_deref();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
use game_core::inputs::{InputKey, Inputs};
|
||||||
|
use std::io::{Write, Read, stdout, stdin};
|
||||||
|
|
||||||
|
extern crate termion;
|
||||||
|
|
||||||
|
use termion::event::{Key, Event, MouseEvent};
|
||||||
|
use termion::input::{TermRead, MouseTerminal};
|
||||||
|
use termion::raw::IntoRawMode;
|
||||||
|
|
||||||
|
|
||||||
|
fn map_to_input_key(key_event: termion::event::Key) -> Option<InputKey> {
|
||||||
|
match key_event {
|
||||||
|
termion::event::Key::Up => Some(InputKey::Up),
|
||||||
|
termion::event::Key::Down => Some(InputKey::Down),
|
||||||
|
termion::event::Key::Left => Some(InputKey::Left),
|
||||||
|
termion::event::Key::Right => Some(InputKey::Right),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_events<R: Read>(reader: &mut R, inputs: &mut Inputs) {
|
||||||
|
inputs.clear();
|
||||||
|
|
||||||
|
for c in reader.events() {
|
||||||
|
if let Ok(Event::Key(key_pressed)) = c {
|
||||||
|
if let Some(input_key) = map_to_input_key(key_pressed) {
|
||||||
|
inputs.set_pressed(input_key, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
mod drawers;
|
mod drawers;
|
||||||
mod renderers;
|
mod renderers;
|
||||||
|
mod input_mapping;
|
||||||
|
|
||||||
use crate::renderers::renderer::main_loop;
|
use crate::renderers::renderer::main_loop;
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,23 @@
|
|||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use game_core::common::position::Position;
|
||||||
use game_core::field::loader::loader::FieldLoader;
|
use game_core::field::loader::loader::FieldLoader;
|
||||||
use game_core::field::loader::plain_text_loader::PlainTextFieldLoader;
|
use game_core::field::loader::plain_text_loader::PlainTextFieldLoader;
|
||||||
|
use game_core::game_handler::game_handler::{GameData, GameManager};
|
||||||
|
use game_core::game_handler::states::{PausedState, PlayingState};
|
||||||
|
use game_core::inputs::Inputs;
|
||||||
|
use game_core::snake::snake::{Node, Snake, SnakeHandler};
|
||||||
|
use game_core::snake::states::{MovingState, StoppedState};
|
||||||
use game_core::timer::Timer;
|
use game_core::timer::Timer;
|
||||||
|
use termion::async_stdin;
|
||||||
|
use termion::raw::IntoRawMode;
|
||||||
|
use crate::drawers::common::reset_cursor;
|
||||||
use crate::drawers::field::draw_field;
|
use crate::drawers::field::draw_field;
|
||||||
use std::{thread, time};
|
use crate::drawers::snake::draw_snake;
|
||||||
|
use crate::input_mapping::process_events;
|
||||||
|
use std::io::{Read, stdout, stdin};
|
||||||
|
|
||||||
fn clear_screen() {
|
fn clear_screen() {
|
||||||
// Clear the entire screen and move cursor to top-left
|
// Clear the entire screen and move cursor to top-left
|
||||||
@@ -14,22 +26,81 @@ fn clear_screen() {
|
|||||||
io::stdout().flush().unwrap();
|
io::stdout().flush().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main_loop() {
|
pub fn initialize_main_game() -> GameManager {
|
||||||
|
|
||||||
let path = env::current_dir().unwrap();
|
let path = env::current_dir().unwrap();
|
||||||
let field_loader = PlainTextFieldLoader{};
|
let field_loader = PlainTextFieldLoader{};
|
||||||
let full_path = format!("{}{}", path.display(), "/game_data/fields/maze1");
|
let full_path = format!("{}{}", path.display(), "/game_data/fields/maze1");
|
||||||
let field = field_loader.load(full_path);
|
let field = field_loader.load(full_path);
|
||||||
|
|
||||||
|
|
||||||
|
let snake = Snake {
|
||||||
|
speed: 5.0,
|
||||||
|
moving_direction: Position { x: 1, y: 0 },
|
||||||
|
body: Node {
|
||||||
|
position: Position {
|
||||||
|
x: 4, y: 4,
|
||||||
|
},
|
||||||
|
next: Some(Box::new(Node {
|
||||||
|
position: Position {
|
||||||
|
x: 4, y: 3,
|
||||||
|
},
|
||||||
|
next: Some(Box::new(Node {
|
||||||
|
position: Position {
|
||||||
|
x: 4, y: 2,
|
||||||
|
},
|
||||||
|
next: None,
|
||||||
|
})),
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let snake_handler = SnakeHandler {
|
||||||
|
snake: snake,
|
||||||
|
state: Box::new(MovingState::new()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut game_data = GameData {
|
||||||
|
field: field,
|
||||||
|
snakes: vec![snake_handler],
|
||||||
|
};
|
||||||
|
let mut playing_state = PlayingState::new();
|
||||||
|
playing_state.spawn_food(&mut game_data);
|
||||||
|
let game_manager = GameManager {
|
||||||
|
game_data: game_data,
|
||||||
|
state: Box::new(playing_state),
|
||||||
|
};
|
||||||
|
return game_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main_loop() {
|
||||||
|
let mut game_manager = initialize_main_game();
|
||||||
|
|
||||||
|
let mut stdout = stdout().into_raw_mode().unwrap();
|
||||||
|
let mut reader = async_stdin();
|
||||||
let mut timer = Timer::new(120);
|
let mut timer = Timer::new(120);
|
||||||
|
let mut inputs = Inputs::new();
|
||||||
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
timer.start();
|
timer.start();
|
||||||
|
|
||||||
|
process_events(&mut reader, &mut inputs);
|
||||||
|
|
||||||
|
game_manager.update(timer.get_delta_time(), &inputs);
|
||||||
|
|
||||||
|
// TODO: define a "Draw" function?
|
||||||
clear_screen();
|
clear_screen();
|
||||||
draw_field(&field);
|
reset_cursor();
|
||||||
|
draw_field(&game_manager.game_data.field, &termion::color::White);
|
||||||
|
for snake_handler in &game_manager.game_data.snakes {
|
||||||
|
draw_snake(&snake_handler.snake, &termion::color::Cyan, 2, 2);
|
||||||
|
}
|
||||||
|
reset_cursor();
|
||||||
|
|
||||||
|
stdout.flush().unwrap();
|
||||||
|
|
||||||
timer.limit_fps();
|
timer.limit_fps();
|
||||||
timer.end();
|
timer.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,4 +27,11 @@ impl Field {
|
|||||||
pub fn set_tile(&mut self, x: usize, y: usize, tile: Tile) {
|
pub fn set_tile(&mut self, x: usize, y: usize, tile: Tile) {
|
||||||
self.tiles[y * self.width + x] = tile;
|
self.tiles[y * self.width + x] = tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear_food(&mut self, x: usize, y: usize) {
|
||||||
|
let current_tile = self.tiles[y * self.width + x];
|
||||||
|
if current_tile == Tile::Food {
|
||||||
|
self.tiles[y * self.width + x] = Tile::Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ impl FieldLoader for PlainTextFieldLoader {
|
|||||||
let mut tiles = vec![Tile::Empty; width * height];
|
let mut tiles = vec![Tile::Empty; width * height];
|
||||||
|
|
||||||
for (y, line) in lines.iter().enumerate() {
|
for (y, line) in lines.iter().enumerate() {
|
||||||
|
println!("y: {}", y);
|
||||||
for (x, ch) in line.chars().enumerate() {
|
for (x, ch) in line.chars().enumerate() {
|
||||||
|
println!("x: {}", x);
|
||||||
let tile = match ch {
|
let tile = match ch {
|
||||||
'x' => Tile::Wall,
|
'x' => Tile::Wall,
|
||||||
_ => Tile::Empty,
|
_ => Tile::Empty,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
|
|
||||||
use crate::{field::field::{Field, Tile}, game_handler::states::GameManagerState, snake::snake::SnakeHandler};
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use crate::{field::field::{Field, Tile}, game_handler::states::GameManagerState, inputs::Inputs, snake::snake::{Snake, SnakeHandler}};
|
||||||
|
|
||||||
pub struct GameData {
|
pub struct GameData {
|
||||||
pub field: Field,
|
pub field: Field,
|
||||||
@@ -22,6 +24,16 @@ impl GameData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct GameManager {
|
pub struct GameManager {
|
||||||
game_data: GameData,
|
pub game_data: GameData,
|
||||||
game_manager_state: Box<dyn GameManagerState>,
|
pub state: Box<dyn GameManagerState>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GameManager {
|
||||||
|
|
||||||
|
pub fn update(&mut self, delta: Duration, inputs: &Inputs) {
|
||||||
|
let new_state = self.state.update(delta, inputs, &mut self.game_data);
|
||||||
|
if let Some(new_state) = new_state {
|
||||||
|
self.state = new_state;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ impl PlayingState {
|
|||||||
Self { dt_accumulator: Duration::ZERO }
|
Self { dt_accumulator: Duration::ZERO }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_food(&mut self, game_data: &mut GameData) {
|
pub fn spawn_food(&mut self, game_data: &mut GameData) {
|
||||||
let mut empty_positions = Vec::new();
|
let mut empty_positions = Vec::new();
|
||||||
|
|
||||||
// Get all empty tiles from the field
|
// Get all empty tiles from the field
|
||||||
@@ -51,10 +51,14 @@ impl GameManagerState for PlayingState {
|
|||||||
|
|
||||||
fn update(&mut self, delta: Duration, inputs: &Inputs, game_data: &mut GameData) -> Option<Box<dyn GameManagerState>> {
|
fn update(&mut self, delta: Duration, inputs: &Inputs, game_data: &mut GameData) -> Option<Box<dyn GameManagerState>> {
|
||||||
let mut should_spawn_food = false;
|
let mut should_spawn_food = false;
|
||||||
|
let mut is_food_available = game_data.get_food_count() >= 1;
|
||||||
let all_snakes: Vec<Snake> = game_data.snakes.iter().map(|sh| sh.snake.clone()).collect();
|
let all_snakes: Vec<Snake> = game_data.snakes.iter().map(|sh| sh.snake.clone()).collect();
|
||||||
for (current_snake_index, snake_handler) in game_data.snakes.iter_mut().enumerate() {
|
for (current_snake_index, snake_handler) in game_data.snakes.iter_mut().enumerate() {
|
||||||
if snake_handler.snake.is_eating(&game_data.field) {
|
if snake_handler.snake.is_eating(&game_data.field) {
|
||||||
|
snake_handler.snake.grow();
|
||||||
should_spawn_food = true;
|
should_spawn_food = true;
|
||||||
|
game_data.field.clear_food(snake_handler.snake.body.position.x as usize, snake_handler.snake.body.position.y as usize);
|
||||||
|
is_food_available = false;
|
||||||
}
|
}
|
||||||
let other_snakes = all_snakes
|
let other_snakes = all_snakes
|
||||||
.iter()
|
.iter()
|
||||||
@@ -68,7 +72,7 @@ impl GameManagerState for PlayingState {
|
|||||||
.collect();
|
.collect();
|
||||||
snake_handler.update(delta, inputs, &other_snakes, &game_data.field);
|
snake_handler.update(delta, inputs, &other_snakes, &game_data.field);
|
||||||
}
|
}
|
||||||
if should_spawn_food {
|
if should_spawn_food && !is_food_available {
|
||||||
self.spawn_food(game_data);
|
self.spawn_food(game_data);
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
|
|||||||
@@ -29,4 +29,8 @@ impl Inputs {
|
|||||||
pub fn set_pressed(&mut self, input: InputKey, value: bool) {
|
pub fn set_pressed(&mut self, input: InputKey, value: bool) {
|
||||||
self.inputs_state.insert(input, value);
|
self.inputs_state.insert(input, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.inputs_state.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ impl Snake {
|
|||||||
pub fn is_colliding_against_itself(&self) -> bool {
|
pub fn is_colliding_against_itself(&self) -> bool {
|
||||||
let head_pos = self.body.position;
|
let head_pos = self.body.position;
|
||||||
let mut current_node = self.body.next.as_deref();
|
let mut current_node = self.body.next.as_deref();
|
||||||
|
|
||||||
while let Some(node) = current_node {
|
while let Some(node) = current_node {
|
||||||
if node.position == head_pos {
|
if node.position == head_pos {
|
||||||
return true;
|
return true;
|
||||||
@@ -96,13 +95,29 @@ impl Snake {
|
|||||||
field.get_tile(pos.x as usize, pos.y as usize) == Tile::Food
|
field.get_tile(pos.x as usize, pos.y as usize) == Tile::Food
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn keep_within_boundaries(&mut self, width: isize, height: isize) {
|
||||||
|
if self.body.position.x >= width {
|
||||||
|
self.body.position.x = 0;
|
||||||
|
} else if self.body.position.x < 0 {
|
||||||
|
self.body.position.x = width - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.body.position.y >= height {
|
||||||
|
self.body.position.y = 0;
|
||||||
|
} else if self.body.position.y < 0 {
|
||||||
|
self.body.position.y = height - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn do_move(&mut self) {
|
pub fn do_move(&mut self) {
|
||||||
|
println!("moving?");
|
||||||
// probably a more optimal way of approaching this is just
|
// probably a more optimal way of approaching this is just
|
||||||
// moving the tail node to head.next, but Rust's borrow checking
|
// moving the tail node to head.next, but Rust's borrow checking
|
||||||
// system doesn't allow for that in an easy way
|
// system doesn't allow for that in an easy way
|
||||||
|
|
||||||
let mut last_position = self.body.position;
|
let mut last_position = self.body.position;
|
||||||
|
println!("prev pos: {:?}", self.body.position);
|
||||||
self.body.position += self.moving_direction; // the first node in body is always the head
|
self.body.position += self.moving_direction; // the first node in body is always the head
|
||||||
|
println!("next pos: {:?}", self.body.position);
|
||||||
let mut current_node = self.body.next.as_deref_mut();
|
let mut current_node = self.body.next.as_deref_mut();
|
||||||
while let Some(node) = current_node {
|
while let Some(node) = current_node {
|
||||||
let temp = node.position;
|
let temp = node.position;
|
||||||
@@ -127,7 +142,7 @@ impl Snake {
|
|||||||
|
|
||||||
pub struct SnakeHandler {
|
pub struct SnakeHandler {
|
||||||
pub snake: Snake,
|
pub snake: Snake,
|
||||||
state: Box<dyn SnakeState>,
|
pub state: Box<dyn SnakeState>,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,18 +55,22 @@ impl SnakeState for MovingState {
|
|||||||
self.dt_accumulator -= interval;
|
self.dt_accumulator -= interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snake.keep_within_boundaries(field.width as isize, field.height as isize);
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SnakeState for StoppedState {
|
impl SnakeState for StoppedState {
|
||||||
fn update(&mut self, _delta: Duration, _inputs: &Inputs, _snake: &mut Snake, _other_snakes: &Vec<Snake>, _field: &Field) -> Option<Box<dyn SnakeState>> {
|
fn update(&mut self, _delta: Duration, _inputs: &Inputs, _snake: &mut Snake, _other_snakes: &Vec<Snake>, _field: &Field) -> Option<Box<dyn SnakeState>> {
|
||||||
|
println!("stopped?");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SnakeState for DeadState {
|
impl SnakeState for DeadState {
|
||||||
fn update(&mut self, _delta: Duration, _inputs: &Inputs, _snake: &mut Snake, _other_snakes: &Vec<Snake>, _field: &Field) -> Option<Box<dyn SnakeState>> {
|
fn update(&mut self, _delta: Duration, _inputs: &Inputs, _snake: &mut Snake, _other_snakes: &Vec<Snake>, _field: &Field) -> Option<Box<dyn SnakeState>> {
|
||||||
|
println!("dead?");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user