Проектная работа - WIP
This commit is contained in:
@@ -9,6 +9,10 @@ pub const SNAKE_VELOCITY: u8 = (GRID_SIZE as f32 / 1.0) as u8;
|
||||
#[derive(Component)]
|
||||
pub struct Head;
|
||||
|
||||
/// Сегмент змеиного хвоста
|
||||
#[derive(Component)]
|
||||
pub struct Tail(pub u16);
|
||||
|
||||
/// Направление движения
|
||||
#[derive(Component, PartialEq, Clone, Copy)]
|
||||
pub enum Direction {
|
||||
|
||||
@@ -40,42 +40,6 @@ pub fn moving(time: Res<Time>, query: Query<(&mut Transform, &mut Inert, &Direct
|
||||
}
|
||||
}
|
||||
|
||||
fn get_overflow(grid: f32, coord: f32, delta: f32) -> f32 {
|
||||
let rem = coord % grid;
|
||||
let rem = if rem < 0.0 { grid + rem } else { rem };
|
||||
let new = rem + delta;
|
||||
if new >= 0.0 && new <= grid {
|
||||
0.0
|
||||
} else {
|
||||
new % grid
|
||||
}
|
||||
}
|
||||
|
||||
/// Найти значение значение на границе сетки, если она находится между значениями old и new
|
||||
fn find_grid_bound(old: f32, new: f32, grid: f32) -> f32 {
|
||||
use std::f32::NAN;
|
||||
|
||||
if grid <= 0.0 {
|
||||
return NAN;
|
||||
};
|
||||
|
||||
let old_grid = old / grid;
|
||||
let new_grid = new / grid;
|
||||
|
||||
let old_grid_left = old_grid.floor();
|
||||
let old_grid_right = old_grid.ceil();
|
||||
let new_grid_left = new_grid.floor();
|
||||
let new_grid_right = new_grid.ceil();
|
||||
|
||||
if old_grid_right == new_grid_left {
|
||||
old_grid_right * grid
|
||||
} else if old_grid_left == new_grid_right {
|
||||
old_grid_left * grid
|
||||
} else {
|
||||
NAN
|
||||
}
|
||||
}
|
||||
|
||||
/// Разбиение изменения координаты по границам сетки
|
||||
fn split_by_grid(src: f32, dst: f32, grid: f32) -> Vec<(f32, f32)> {
|
||||
if grid <= 0.0 {
|
||||
@@ -114,46 +78,6 @@ fn split_by_grid(src: f32, dst: f32, grid: f32) -> Vec<(f32, f32)> {
|
||||
mod test {
|
||||
use crate::gameplay::*;
|
||||
|
||||
#[test]
|
||||
fn test_get_overflow() {
|
||||
assert_eq!(get_overflow(5.0, -6.0, 3.0), 2.0);
|
||||
assert_eq!(get_overflow(5.0, 6.0, 3.0), 0.0);
|
||||
assert_eq!(get_overflow(5.0, -6.0, -3.0), 0.0);
|
||||
assert_eq!(get_overflow(5.0, 6.0, -3.0), -2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_grid_bound() {
|
||||
// проверка с положительными значениями old и new
|
||||
assert!(find_grid_bound(1.0, 4.0, 5.0).is_nan());
|
||||
assert!(find_grid_bound(4.0, 1.0, 5.0).is_nan());
|
||||
assert_eq!(find_grid_bound(4.0, 6.0, 5.0), 5.0);
|
||||
assert_eq!(find_grid_bound(6.0, 4.0, 5.0), 5.0);
|
||||
assert!(find_grid_bound(1.0, 11.0, 5.0).is_nan());
|
||||
assert!(find_grid_bound(11.0, 1.0, 5.0).is_nan());
|
||||
|
||||
// проверка с отрицательными значениями old и new
|
||||
assert!(find_grid_bound(-1.0, -4.0, 5.0).is_nan());
|
||||
assert!(find_grid_bound(-4.0, -1.0, 5.0).is_nan());
|
||||
assert_eq!(find_grid_bound(-4.0, -6.0, 5.0), -5.0);
|
||||
assert_eq!(find_grid_bound(-6.0, -4.0, 5.0), -5.0);
|
||||
assert!(find_grid_bound(-1.0, -11.0, 5.0).is_nan());
|
||||
assert!(find_grid_bound(-11.0, -1.0, 5.0).is_nan());
|
||||
|
||||
// проверка перехода через 0
|
||||
assert_eq!(find_grid_bound(-1.0, 1.0, 5.0), 0.0);
|
||||
assert_eq!(find_grid_bound(1.0, -1.0, 5.0), 0.0);
|
||||
assert_eq!(find_grid_bound(-1.0, 1.0, 10.0), 0.0);
|
||||
assert_eq!(find_grid_bound(1.0, -1.0, 10.0), 0.0);
|
||||
assert!(find_grid_bound(-1.0, 10.0, 5.0).is_nan());
|
||||
assert!(find_grid_bound(-10.0, 1.0, 5.0).is_nan());
|
||||
|
||||
// проверка при grid <= 0
|
||||
assert!(find_grid_bound(1.0, 2.0, 0.0).is_nan());
|
||||
assert!(find_grid_bound(1.0, 2.0, -0.0).is_nan());
|
||||
assert!(find_grid_bound(1.0, 2.0, -0.1).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_by_grid() {
|
||||
// движение вправо
|
||||
|
||||
@@ -42,4 +42,4 @@ mod gameplay;
|
||||
mod startup;
|
||||
|
||||
pub use gameplay::{head_rotation, moving};
|
||||
pub use startup::startup;
|
||||
pub use startup::{setup_frame_rate, startup};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use bevy::prelude::*;
|
||||
use snake_game::{head_rotation, moving, startup};
|
||||
use snake_game::{head_rotation, moving, setup_frame_rate, startup};
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
@@ -18,7 +18,7 @@ fn main() {
|
||||
)
|
||||
.insert_resource(bevy::winit::WinitSettings::desktop_app())
|
||||
.insert_resource(ClearColor(Color::srgb(0.3, 0.6, 0.8)))
|
||||
.add_systems(Startup, startup)
|
||||
.add_systems(Startup, (startup, setup_frame_rate))
|
||||
.add_systems(Update, (head_rotation, moving))
|
||||
.run();
|
||||
}
|
||||
|
||||
+41
-10
@@ -1,17 +1,29 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use bevy::{ecs::spawn, prelude::*, winit::WinitSettings};
|
||||
use bevy::{prelude::*, winit::WinitSettings};
|
||||
|
||||
use crate::domain::{Direction, FRAMES_PER_SECOND, GRID_SIZE, Inert, SNAKE_VELOCITY, Velocity};
|
||||
use crate::domain::Tail;
|
||||
|
||||
/// Инициализация игрового мира
|
||||
pub fn startup(mut commands: Commands, mut winit: ResMut<WinitSettings>) {
|
||||
use crate::domain::{HEAD_SIZE, Head};
|
||||
/// Настройка частоты кадров
|
||||
pub fn setup_frame_rate(mut winit: ResMut<WinitSettings>) {
|
||||
use crate::domain::FRAMES_PER_SECOND;
|
||||
|
||||
winit.focused_mode =
|
||||
bevy::winit::UpdateMode::reactive(Duration::from_secs_f32(1. / FRAMES_PER_SECOND as f32));
|
||||
winit.unfocused_mode =
|
||||
bevy::winit::UpdateMode::reactive(Duration::from_secs_f32(1. / FRAMES_PER_SECOND as f32));
|
||||
}
|
||||
|
||||
/// Инициализация игрового мира
|
||||
pub fn startup(mut commands: Commands) {
|
||||
spawn_snake(&mut commands);
|
||||
spawn_grid(&mut commands);
|
||||
commands.spawn(Camera2d);
|
||||
}
|
||||
|
||||
/// Создать голову змеи
|
||||
fn spawn_snake(commands: &mut Commands) {
|
||||
use crate::domain::{Direction, HEAD_SIZE, Head, Inert, SNAKE_VELOCITY, Velocity};
|
||||
|
||||
let head = commands
|
||||
.spawn((
|
||||
@@ -24,7 +36,7 @@ pub fn startup(mut commands: Commands, mut winit: ResMut<WinitSettings>) {
|
||||
vec2(HEAD_SIZE as f32, HEAD_SIZE as f32),
|
||||
),
|
||||
Transform {
|
||||
translation: vec3(0., 0., 0.),
|
||||
translation: vec3(0.0, 0.0, 1.0),
|
||||
..Default::default()
|
||||
},
|
||||
))
|
||||
@@ -35,7 +47,7 @@ pub fn startup(mut commands: Commands, mut winit: ResMut<WinitSettings>) {
|
||||
vec2(HEAD_SIZE as f32 * 0.3, HEAD_SIZE as f32 * 0.3),
|
||||
),
|
||||
Transform {
|
||||
translation: vec3(HEAD_SIZE as f32 * -0.25, HEAD_SIZE as f32 * 0.25, 0.),
|
||||
translation: vec3(HEAD_SIZE as f32 * -0.25, HEAD_SIZE as f32 * 0.25, 0.0),
|
||||
..Default::default()
|
||||
},
|
||||
ChildOf(head),
|
||||
@@ -46,12 +58,33 @@ pub fn startup(mut commands: Commands, mut winit: ResMut<WinitSettings>) {
|
||||
vec2(HEAD_SIZE as f32 * 0.2, HEAD_SIZE as f32 * 0.2),
|
||||
),
|
||||
Transform {
|
||||
translation: vec3(HEAD_SIZE as f32 * 0.25, HEAD_SIZE as f32 * 0.25, 0.),
|
||||
translation: vec3(HEAD_SIZE as f32 * 0.25, HEAD_SIZE as f32 * 0.25, 0.0),
|
||||
..Default::default()
|
||||
},
|
||||
ChildOf(head),
|
||||
));
|
||||
|
||||
commands.spawn((
|
||||
Tail(0),
|
||||
Direction::default(),
|
||||
Inert::default(),
|
||||
Velocity(0.0),
|
||||
Sprite::from_color(
|
||||
Color::srgb(0.7, 0.7, 0.7),
|
||||
vec2(HEAD_SIZE as f32 * 0.8, HEAD_SIZE as f32 * 0.8),
|
||||
),
|
||||
Transform {
|
||||
translation: vec3(0.0, 0.0, 0.0),
|
||||
..Default::default()
|
||||
},
|
||||
// ChildOf(head),
|
||||
));
|
||||
}
|
||||
|
||||
/// Создать координатную сетку
|
||||
fn spawn_grid(commands: &mut Commands) {
|
||||
use crate::domain::GRID_SIZE;
|
||||
|
||||
for x in -20..=20 {
|
||||
commands.spawn((
|
||||
Sprite::from_color(Color::srgb(1.0, 1.0, 0.5), vec2(1.0, 2000.0)),
|
||||
@@ -70,6 +103,4 @@ pub fn startup(mut commands: Commands, mut winit: ResMut<WinitSettings>) {
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
commands.spawn(Camera2d);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user