From 037107f882e16ccb4942a16e8f0bc513bd3ade88 Mon Sep 17 00:00:00 2001 From: Alexander Baranov Date: Thu, 4 Jun 2026 18:52:52 +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/debug.rs | 6 ++ snake-game/src/domain.rs | 36 +++++------- snake-game/src/gameplay.rs | 113 ++++++++++++++++++------------------- 3 files changed, 73 insertions(+), 82 deletions(-) diff --git a/snake-game/src/debug.rs b/snake-game/src/debug.rs index efb6a2a..8bfa433 100644 --- a/snake-game/src/debug.rs +++ b/snake-game/src/debug.rs @@ -42,6 +42,12 @@ pub fn time_speed(input: Res>, mut time: ResMut Vec<(f32, f32)> { + let result = crate::tools::split_by_grid(src, dst, grid); + trace!("\tsplit_by_grid({:?}, {:?}, {:?}) -> {:?}", src, dst, grid, result); + result +} + /// Координатная сетка #[derive(Component)] pub struct Grid; diff --git a/snake-game/src/domain.rs b/snake-game/src/domain.rs index 5d887fd..a1c1269 100644 --- a/snake-game/src/domain.rs +++ b/snake-game/src/domain.rs @@ -86,6 +86,18 @@ impl Direction { Direction::Left | Direction::Right => vec.translation.x = value, } } + + /// Получить следующую по направлению координатную позицию + pub fn next_pos(&self, transform: &Transform) -> Position { + let mut pos = Position::from(transform); + match self { + Direction::Up => pos.y += 1, + Direction::Left => pos.x -= 1, + Direction::Down => pos.y -= 1, + Direction::Right => pos.x += 1, + }; + pos + } } impl Default for Direction { @@ -103,31 +115,9 @@ pub struct Velocity(pub f32); pub struct Inert(pub Direction); /// Путь змеи -#[derive(Resource, Default, Debug)] +#[derive(Resource, Default, Debug, Deref, DerefMut)] pub struct SnakePath(HashMap); -impl SnakePath { - pub fn push(&mut self, transform: &Transform, direction: Direction) -> (Position, Direction) { - let key = transform.into(); - self.0.insert(key, direction.clone()); - (key, direction.clone()) - } - - pub fn pick(&self, transform: &Transform) -> Option<(Position, Direction)> { - let key = transform.into(); - self.0.get(&key).cloned().map(|d| (key, d)) - } - - pub fn drop(&mut self, transform: &Transform) -> Option<(Position, Direction)> { - let key = transform.into(); - self.0.remove(&key).map(|d| (key, d)) - } - - pub fn debug(&self) -> impl Debug { - &self.0 - } -} - #[cfg(test)] mod test { use crate::domain::*; diff --git a/snake-game/src/gameplay.rs b/snake-game/src/gameplay.rs index d0bbc25..2accd67 100644 --- a/snake-game/src/gameplay.rs +++ b/snake-game/src/gameplay.rs @@ -1,75 +1,70 @@ use bevy::prelude::*; use crate::{ - domain::{Direction, GRID_SIZE, GridBarier, Head, Inert, SnakePath, Velocity}, - tools::split_by_grid, + domain::{Direction, End, GRID_SIZE, Head, SnakePath, Tail, Velocity}, + tools::{Position, split_by_grid}, }; /// Система поворота головы змеи -pub fn head_rotation(input: Res>, query: Single<(&mut Transform, &mut Direction), With>, mut snake_path: ResMut) { +pub fn head_rotation( + input: Res>, // + query: Single<(&mut Transform, &Direction), With>, + mut snake_path: ResMut, +) { use core::f32::consts::PI; - let (mut transform, mut direction) = query.into_inner(); - - let mut append_snake_path = |transform: &Transform, direction: &Direction| { - snake_path.push(&transform, direction.clone()); - trace!("append snake_path: {:?}", snake_path); - }; - if input.just_pressed(KeyCode::ArrowLeft) { - transform.rotate_z(PI / 2.0); + let (mut transform, direction) = query.into_inner(); + let next_pos = direction.next_pos(&*transform); + let mut direction = direction.clone(); direction.rotate_left(); - append_snake_path(&transform, &direction); - } - if input.just_pressed(KeyCode::ArrowRight) { - transform.rotate_z(-PI / 2.0); - direction.rotate_right(); - append_snake_path(&transform, &direction); - } -} - -/// Система движения для всех движущихся сущностей -pub fn moving(time: Res>, query: Query<(&mut Transform, &mut Inert, Option<&Direction>, &Velocity, Entity)>, mut commands: Commands) { - // для всех сущностей, обладающих позицией, инерцией, направлением (опционально) и скоростью - for (mut transform, mut inert, direction, Velocity(velocity), entity) in query.into_iter() { - // используя скорость и время получаем величину перемещения - let delta = velocity * time.delta_secs(); - // используя направление инерции получаем получаем исходное значение изменяемой координаты и знак изменения ('+' или '-') - let src = inert.0.get_coord(&transform); - let sign = inert.0.get_change_sign(); - // используя полученные данные получаем целевое значение координаты - let dst = src + sign * delta; - // разбиваем путь от исходного до целевого значения координаты по границам сетки - let mut splited = split_by_grid(src, dst, GRID_SIZE as f32).into_iter(); - // берем первый сегмент разбитого пути и обновляем позицию - let first = splited.next().unwrap_or((0.0, 0.0)); - inert.0.set_coord(&mut transform, first.0); - // если разбивка содержит дополнительный сегмент то обрабатываем его - if let Some(second) = splited.next() { - // из дополнительного сегмента берем величину изменения - let delta = second.1.abs(); - if let Some(direction) = direction { - inert.0 = *direction; - } else { - todo!("получить обновленное направление инерции из SnakePath") + if let Some(prev_direction) = snake_path.insert(next_pos, direction) { + if direction != prev_direction { + transform.rotate_z(PI); } - let src = inert.0.get_coord(&transform); - let sign = inert.0.get_change_sign(); - let dst = src + sign * delta; - inert.0.set_coord(&mut transform, dst); - let transform = transform.clone(); - commands.trigger(GridBarier::new(entity, (&transform).into())); - let direction = direction.clone(); - commands.queue(move |world: &mut World| { - let mut snake_path = world.resource_mut::(); - snake_path.push(&transform, direction); - }); + } else { + transform.rotate_z(PI / 2.0); + } + } else if input.just_pressed(KeyCode::ArrowRight) { + let (mut transform, direction) = query.into_inner(); + let next_pos = direction.next_pos(&*transform); + let mut direction = direction.clone(); + direction.rotate_right(); + if let Some(prev_direction) = snake_path.insert(next_pos, direction) { + if direction != prev_direction { + transform.rotate_z(-PI); + } + } else { + transform.rotate_z(-PI / 2.0); } } } -fn _split_by_grid_tracing(src: f32, dst: f32, grid: f32) -> Vec<(f32, f32)> { - let result = split_by_grid(src, dst, grid); - trace!("\tsplit_by_grid({:?}, {:?}, {:?}) -> {:?}", src, dst, grid, result); - result +/// Система движения змеи +pub fn snake_moving( + time: Res>, + snake_path: Res, + query: Query<(&mut Transform, &mut Direction, &Velocity), Or<(With, With, With)>>, +) { + for (mut transform, mut direction, Velocity(velocity)) in query.into_iter() { + let delta = velocity * time.delta_secs(); + let src = direction.get_coord(&transform); + let sign = direction.get_change_sign(); + let dst = src + sign * delta; + let mut splited = split_by_grid(src, dst, GRID_SIZE as f32).into_iter(); + let first = splited.next().unwrap_or((0.0, 0.0)); + direction.set_coord(&mut transform, first.0); + if let Some(second) = splited.next() { + let delta = second.1.abs(); + let pos = Position::from(&*transform); + if let Some(dir) = snake_path.get(&pos) { + trace!("set new direction in {pos:?} --> {dir:?}"); + *direction = dir.clone(); + } + let src = direction.get_coord(&*transform); + let sign = direction.get_change_sign(); + let dst = src + sign * delta; + direction.set_coord(&mut transform, dst); + } + } }