From 33db0eaaef264582c1878a8465746fb6b5ee5c41 Mon Sep 17 00:00:00 2001 From: Franco Colmenarez Date: Tue, 10 Mar 2026 12:13:21 -0500 Subject: [PATCH] draw snake --- Cargo.lock | 17 ++++++++++++ game_cli_frontend/Cargo.toml | 1 + game_cli_frontend/src/drawers/field.rs | 13 ++++----- game_cli_frontend/src/drawers/mod.rs | 3 ++- game_cli_frontend/src/drawers/snake.rs | 29 ++++++++++++++++++++ game_cli_frontend/src/renderers/renderer.rs | 30 ++++++++++++++++++--- game_core/src/snake/snake.rs | 1 - 7 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 game_cli_frontend/src/drawers/snake.rs diff --git a/Cargo.lock b/Cargo.lock index 2848605..0ca0ba5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,7 @@ name = "game_cli_frontend" version = "0.1.0" dependencies = [ "game_core", + "termion", ] [[package]] @@ -149,6 +150,12 @@ version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +[[package]] +name = "numtoa" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f" + [[package]] name = "prettyplease" version = "0.2.37" @@ -259,6 +266,16 @@ dependencies = [ "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]] name = "unicode-ident" version = "1.0.24" diff --git a/game_cli_frontend/Cargo.toml b/game_cli_frontend/Cargo.toml index 2f10788..688019a 100644 --- a/game_cli_frontend/Cargo.toml +++ b/game_cli_frontend/Cargo.toml @@ -5,3 +5,4 @@ edition = "2024" [dependencies] game_core = { path = "../game_core" } +termion = "4.0.6" diff --git a/game_cli_frontend/src/drawers/field.rs b/game_cli_frontend/src/drawers/field.rs index 07cbfed..557aa03 100644 --- a/game_cli_frontend/src/drawers/field.rs +++ b/game_cli_frontend/src/drawers/field.rs @@ -1,14 +1,15 @@ use game_core::field::field::{Field, Tile}; + const BOUNDARY_TILE: &'static str = "#"; const WALL_TILE: &'static str = "█"; const EMPTY_TILE : &'static str = " "; const FOOD_TILE : &'static str = "o"; -pub fn draw_field(field: &Field) { - println!("{}", BOUNDARY_TILE.repeat(field.width + 2)); +pub fn draw_field(field: &Field, color: &dyn termion::color::Color) { + println!("{}{}", termion::color::Fg(color), BOUNDARY_TILE.repeat(field.width + 2)); for y in 0..field.height { - print!("{}", BOUNDARY_TILE); + print!("{}{}", termion::color::Fg(color), BOUNDARY_TILE); for x in 0..field.width { let tile = field.tiles[y * field.width + x]; let char = match tile { @@ -16,9 +17,9 @@ pub fn draw_field(field: &Field) { Tile::Wall => WALL_TILE, Tile::Food => FOOD_TILE, }; - print!("{}", char); + print!("{}{}", termion::color::Fg(color), char); } - println!("{}", BOUNDARY_TILE); + println!("{}{}", termion::color::Fg(color), BOUNDARY_TILE); } - println!("{}", BOUNDARY_TILE.repeat(field.width + 2)); + println!("{}{}", termion::color::Fg(color), BOUNDARY_TILE.repeat(field.width + 2)); } diff --git a/game_cli_frontend/src/drawers/mod.rs b/game_cli_frontend/src/drawers/mod.rs index 921dcee..3eb20b8 100644 --- a/game_cli_frontend/src/drawers/mod.rs +++ b/game_cli_frontend/src/drawers/mod.rs @@ -1 +1,2 @@ -pub mod field; \ No newline at end of file +pub mod field; +pub mod snake; \ No newline at end of file diff --git a/game_cli_frontend/src/drawers/snake.rs b/game_cli_frontend/src/drawers/snake.rs new file mode 100644 index 0000000..4b59746 --- /dev/null +++ b/game_cli_frontend/src/drawers/snake.rs @@ -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(); + } +} diff --git a/game_cli_frontend/src/renderers/renderer.rs b/game_cli_frontend/src/renderers/renderer.rs index 0b00257..4975bf8 100644 --- a/game_cli_frontend/src/renderers/renderer.rs +++ b/game_cli_frontend/src/renderers/renderer.rs @@ -1,11 +1,13 @@ use std::io::{self, Write}; use std::env; +use game_core::common::position::Position; use game_core::field::loader::loader::FieldLoader; use game_core::field::loader::plain_text_loader::PlainTextFieldLoader; +use game_core::snake::snake::{Node, Snake}; use game_core::timer::Timer; use crate::drawers::field::draw_field; -use std::{thread, time}; +use crate::drawers::snake::draw_snake; fn clear_screen() { // Clear the entire screen and move cursor to top-left @@ -23,13 +25,35 @@ pub fn main_loop() { let mut timer = Timer::new(120); + let snake = Snake { + speed: 1.0, + moving_direction: Position { x: 1, y: 0 }, + body: Node { + position: Position { + x: 4, y: 4, + }, + next: Some(Box::new(Node { + position: Position { + x: 5, y: 4, + }, + next: Some(Box::new(Node { + position: Position { + x: 5, y: 5, + }, + next: None, + })), + })), + } + }; + loop { timer.start(); clear_screen(); - draw_field(&field); + draw_field(&field, &termion::color::White); + draw_snake(&snake, &termion::color::Cyan, 1, 1); timer.limit_fps(); timer.end(); } -} \ No newline at end of file +} diff --git a/game_core/src/snake/snake.rs b/game_core/src/snake/snake.rs index bbabaad..835255d 100644 --- a/game_core/src/snake/snake.rs +++ b/game_core/src/snake/snake.rs @@ -58,7 +58,6 @@ impl 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;