From 29dc570b701f68fd62987cdfd559cd5ef7a26909 Mon Sep 17 00:00:00 2001 From: Alexander Baranov Date: Fri, 5 Jun 2026 23:03:13 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=BD?= =?UTF-8?q?=D0=B0=D1=8F=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=20-=20WIP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- snake-game/src/domain/position.rs | 11 +++++- snake-game/src/domain/snake_path.rs | 52 +++++++++++++++++++++++++++-- snake-game/src/gameplay.rs | 30 +++++++++++------ 3 files changed, 78 insertions(+), 15 deletions(-) diff --git a/snake-game/src/domain/position.rs b/snake-game/src/domain/position.rs index 9e41236..82e5c36 100644 --- a/snake-game/src/domain/position.rs +++ b/snake-game/src/domain/position.rs @@ -2,7 +2,7 @@ use std::{fmt::Display, ops::Deref}; use bevy::transform::components::Transform; -use crate::domain::GRID_SIZE; +use crate::domain::{Direction, GRID_SIZE}; #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Position { @@ -14,6 +14,15 @@ impl Position { pub fn new(x: i8, y: i8) -> Self { Self { x, y } } + + pub fn change(&mut self, direction: &Direction) { + match direction { + Direction::Up => self.y += 1, + Direction::Left => self.x -= 1, + Direction::Down => self.y -= 1, + Direction::Right => self.x += 1, + } + } } impl Display for Position { diff --git a/snake-game/src/domain/snake_path.rs b/snake-game/src/domain/snake_path.rs index 8f053a3..92156db 100644 --- a/snake-game/src/domain/snake_path.rs +++ b/snake-game/src/domain/snake_path.rs @@ -1,8 +1,54 @@ use bevy::prelude::*; -use std::{collections::HashMap, fmt::Debug}; +use std::collections::HashMap; use crate::domain::{Direction, Position}; /// Путь змеи -#[derive(Resource, Default, Debug, Deref, DerefMut)] -pub struct SnakePath(HashMap); +#[derive(Resource)] +pub struct SnakePath { + positions: HashMap, + fresh: Option, +} + +impl SnakePath { + pub fn new() -> Self { + SnakePath { + positions: HashMap::with_capacity(16), + fresh: None, + } + } + + pub fn push(&mut self, position: Position, direction: Direction) -> bool { + if let Some(_) = self.positions.get(&position) { + if let Some(fresh) = self.fresh { + if position == fresh { + self.positions.insert(position, direction); + return true; + } + } + return false; + } + self.positions.insert(position, direction); + self.fresh = Some(position); + return true; + } + + pub fn peek(&mut self, position: &Position) -> Option { + if let Some(fresh) = self.fresh { + if fresh == *position { + self.fresh = None; + } + } + self.positions.get(position).cloned() + } + + pub fn drop(&mut self, position: &Position) { + self.positions.remove(position); + } +} + +impl Default for SnakePath { + fn default() -> Self { + Self::new() + } +} diff --git a/snake-game/src/gameplay.rs b/snake-game/src/gameplay.rs index 7eeafc6..276e6f9 100644 --- a/snake-game/src/gameplay.rs +++ b/snake-game/src/gameplay.rs @@ -15,20 +15,32 @@ pub fn head_rotation( let (mut transform, direction) = query.into_inner(); let translation = transform.translation.clone(); let cur_pos = Position::from(&*transform); - let dst_pos = direction.dst_pos(&*transform); + let mut dst_pos = direction.dst_pos(&*transform); let mut new_direction = direction.clone(); new_direction.rotate_left(); - snake_path.insert(dst_pos, new_direction); + if !snake_path.push(dst_pos, new_direction) { + trace!("try 1 failed: cannot push [{dst_pos} => {new_direction}] into SnakePath"); + dst_pos.change(&direction); + if !snake_path.push(dst_pos, new_direction) { + trace!("try 2 failed: cannot push [{dst_pos} => {new_direction}] into SnakePath"); + } + } transform.rotation = new_direction.orientation(); trace!("running {direction} at {cur_pos} {translation}: go {new_direction} on {dst_pos}"); } else if input.just_pressed(KeyCode::ArrowRight) { let (mut transform, direction) = query.into_inner(); let translation = transform.translation.clone(); let cur_pos = Position::from(&*transform); - let dst_pos = direction.dst_pos(&*transform); + let mut dst_pos = direction.dst_pos(&*transform); let mut new_direction = direction.clone(); new_direction.rotate_right(); - snake_path.insert(dst_pos, new_direction); + if !snake_path.push(dst_pos, new_direction) { + trace!("try 1 failed: cannot push [{dst_pos} => {new_direction}] into SnakePath"); + dst_pos.change(&direction); + if !snake_path.push(dst_pos, new_direction) { + trace!("try 2 failed: cannot push [{dst_pos} => {new_direction}] into SnakePath"); + } + } transform.rotation = new_direction.orientation(); trace!("running {direction} at {cur_pos} {translation}: go {new_direction} on {dst_pos}"); } @@ -37,7 +49,7 @@ pub fn head_rotation( /// Система движения змеи pub fn snake_moving( time: Res>, - snake_path: Res, + mut snake_path: ResMut, query: Query<(&mut Transform, &mut Direction, &Velocity, Entity, Has), Or<(With, With, With)>>, mut commands: Commands, ) { @@ -55,7 +67,7 @@ pub fn snake_moving( if let Some(second) = splited.next() { let delta = second.1.abs(); let pos = Position::from(&*transform); - if let Some(dir) = snake_path.get(&pos) { + if let Some(dir) = snake_path.peek(&pos) { trace!("set new direction for {entity} in {pos} --> {dir}"); *direction = dir.clone(); } @@ -69,11 +81,7 @@ pub fn snake_moving( // если это кончик хвоста, то нужно очистить [SnakePath] за собой if has_end { - commands.queue(move |world: &mut World| { - if let Some(mut snake_path) = world.get_resource_mut::() { - snake_path.remove(&pos); - } - }); + snake_path.drop(&pos); } } }