Проектная работа - 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)]
|
#[derive(Component)]
|
||||||
pub struct Head;
|
pub struct Head;
|
||||||
|
|
||||||
|
/// Сегмент змеиного хвоста
|
||||||
|
#[derive(Component)]
|
||||||
|
pub struct Tail(pub u16);
|
||||||
|
|
||||||
/// Направление движения
|
/// Направление движения
|
||||||
#[derive(Component, PartialEq, Clone, Copy)]
|
#[derive(Component, PartialEq, Clone, Copy)]
|
||||||
pub enum Direction {
|
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)> {
|
fn split_by_grid(src: f32, dst: f32, grid: f32) -> Vec<(f32, f32)> {
|
||||||
if grid <= 0.0 {
|
if grid <= 0.0 {
|
||||||
@@ -114,46 +78,6 @@ fn split_by_grid(src: f32, dst: f32, grid: f32) -> Vec<(f32, f32)> {
|
|||||||
mod test {
|
mod test {
|
||||||
use crate::gameplay::*;
|
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]
|
#[test]
|
||||||
fn test_split_by_grid() {
|
fn test_split_by_grid() {
|
||||||
// движение вправо
|
// движение вправо
|
||||||
|
|||||||
@@ -42,4 +42,4 @@ mod gameplay;
|
|||||||
mod startup;
|
mod startup;
|
||||||
|
|
||||||
pub use gameplay::{head_rotation, moving};
|
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 bevy::prelude::*;
|
||||||
use snake_game::{head_rotation, moving, startup};
|
use snake_game::{head_rotation, moving, setup_frame_rate, startup};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
@@ -18,7 +18,7 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.insert_resource(bevy::winit::WinitSettings::desktop_app())
|
.insert_resource(bevy::winit::WinitSettings::desktop_app())
|
||||||
.insert_resource(ClearColor(Color::srgb(0.3, 0.6, 0.8)))
|
.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))
|
.add_systems(Update, (head_rotation, moving))
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-10
@@ -1,17 +1,29 @@
|
|||||||
use std::time::Duration;
|
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>) {
|
pub fn setup_frame_rate(mut winit: ResMut<WinitSettings>) {
|
||||||
use crate::domain::{HEAD_SIZE, Head};
|
use crate::domain::FRAMES_PER_SECOND;
|
||||||
|
|
||||||
winit.focused_mode =
|
winit.focused_mode =
|
||||||
bevy::winit::UpdateMode::reactive(Duration::from_secs_f32(1. / FRAMES_PER_SECOND as f32));
|
bevy::winit::UpdateMode::reactive(Duration::from_secs_f32(1. / FRAMES_PER_SECOND as f32));
|
||||||
winit.unfocused_mode =
|
winit.unfocused_mode =
|
||||||
bevy::winit::UpdateMode::reactive(Duration::from_secs_f32(1. / FRAMES_PER_SECOND as f32));
|
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
|
let head = commands
|
||||||
.spawn((
|
.spawn((
|
||||||
@@ -24,7 +36,7 @@ pub fn startup(mut commands: Commands, mut winit: ResMut<WinitSettings>) {
|
|||||||
vec2(HEAD_SIZE as f32, HEAD_SIZE as f32),
|
vec2(HEAD_SIZE as f32, HEAD_SIZE as f32),
|
||||||
),
|
),
|
||||||
Transform {
|
Transform {
|
||||||
translation: vec3(0., 0., 0.),
|
translation: vec3(0.0, 0.0, 1.0),
|
||||||
..Default::default()
|
..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),
|
vec2(HEAD_SIZE as f32 * 0.3, HEAD_SIZE as f32 * 0.3),
|
||||||
),
|
),
|
||||||
Transform {
|
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()
|
..Default::default()
|
||||||
},
|
},
|
||||||
ChildOf(head),
|
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),
|
vec2(HEAD_SIZE as f32 * 0.2, HEAD_SIZE as f32 * 0.2),
|
||||||
),
|
),
|
||||||
Transform {
|
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()
|
..Default::default()
|
||||||
},
|
},
|
||||||
ChildOf(head),
|
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 {
|
for x in -20..=20 {
|
||||||
commands.spawn((
|
commands.spawn((
|
||||||
Sprite::from_color(Color::srgb(1.0, 1.0, 0.5), vec2(1.0, 2000.0)),
|
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