Compare commits
No commits in common. "0f7882d3fb0ce0403887e0e3815300005ed9e3f1" and "895193778b3f7f63a5bce139da00518143a368f9" have entirely different histories.
0f7882d3fb
...
895193778b
4 changed files with 67 additions and 194 deletions
|
|
@ -1,53 +1,17 @@
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Component)]
|
||||||
pub struct Track {
|
pub struct Track{
|
||||||
pub start_point: Vec2,
|
pub start_point: Vec2,
|
||||||
pub start_direction: Vec2, // будет нормализовано при построении
|
pub start_direction: Vec2, // будет нормализовано при построении
|
||||||
pub segments: Vec<PathSegment>,
|
pub segments: Vec<PathSegment>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum SegementType{
|
|
||||||
Line,
|
|
||||||
Turn,
|
|
||||||
}
|
|
||||||
|
|
||||||
// линия всегда строится от точки старта по направлению
|
// линия всегда строится от точки старта по направлению
|
||||||
// направление изменяется сегментами поворота
|
// направление изменяется сегментами поворота
|
||||||
// left при истине - поворот против часовой стрелки, ложь - по часовой
|
// left при истине - поворот против часовой стрелки, ложь - по часовой
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub enum PathSegment {
|
pub enum PathSegment{
|
||||||
Line { length: f32 },
|
Line { length: f32 },
|
||||||
Turn { radius: f32, left: bool },
|
Turn { radius: f32, left: bool },
|
||||||
// TODO заменить перечисление на структуру с полем типа SegementType, чтоб был единый источник типа
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Resource)]
|
|
||||||
pub struct PrecalculatedTrack{
|
|
||||||
pub segments: Vec<PTSegment>
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct PTSegment {
|
|
||||||
pub t_start: f32,
|
|
||||||
pub t_end: f32,
|
|
||||||
pub segment_type: SegementType,
|
|
||||||
pub start_pos: Vec2,
|
|
||||||
pub direction: Vec2,
|
|
||||||
pub center: Vec2,
|
|
||||||
pub radius: f32,
|
|
||||||
pub start_angle: f32,
|
|
||||||
pub sweep_sign: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct ArcCalculation {
|
|
||||||
pub normal: Vec2,
|
|
||||||
pub center: Vec2,
|
|
||||||
pub start_angle: f32,
|
|
||||||
pub sweep_sign: f32,
|
|
||||||
pub end_pos: Vec2,
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use crate::states::AppState::LinearState;
|
use crate::states::AppState::LinearState;
|
||||||
use crate::states::level::GameOver;
|
|
||||||
use crate::states::linear::*;
|
use crate::states::linear::*;
|
||||||
|
|
||||||
pub struct LinearPlugin;
|
pub struct LinearPlugin;
|
||||||
|
|
@ -8,26 +7,16 @@ pub struct LinearPlugin;
|
||||||
impl Plugin for LinearPlugin {
|
impl Plugin for LinearPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app
|
app
|
||||||
.add_systems(OnEnter (LinearState), setup)
|
.add_systems(OnEnter (LinearState), (setup, setup_linear_track).chain())
|
||||||
.add_systems(Update, (draw_track_gizmos).run_if(in_state(LinearState)))
|
.add_systems(Update, (draw_track_gizmos).run_if(in_state(LinearState)))
|
||||||
.add_systems(OnExit (LinearState), cleanup);
|
.add_systems(OnExit (LinearState), cleanup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(mut commands: Commands) {
|
fn setup(mut commands: Commands) {}
|
||||||
let build_track = setup_linear_track();
|
|
||||||
let precalculated_track = precalculate_track(&build_track);
|
|
||||||
|
|
||||||
commands.insert_resource(build_track);
|
|
||||||
commands.insert_resource(precalculated_track);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cleanup(mut commands: Commands, query: Query<Entity, With<LinearStateMarker>>) {
|
fn cleanup(mut commands: Commands, query: Query<Entity, With<LinearStateMarker>>) {
|
||||||
// зачищаем сущности
|
|
||||||
for entity in query.iter() {
|
for entity in query.iter() {
|
||||||
commands.entity(entity).despawn();
|
commands.entity(entity).despawn();
|
||||||
}
|
}
|
||||||
|
|
||||||
// зачищаем ресурсы по типу
|
|
||||||
commands.remove_resource::<Track>();
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,43 +1,60 @@
|
||||||
use crate::states;
|
use crate::states;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use states::linear::*;
|
use states::linear::*;
|
||||||
use std::f32::consts::FRAC_PI_2;
|
use std::f32::consts::{FRAC_PI_2, PI};
|
||||||
|
|
||||||
const PINK: Color = Color::srgb_u8(250, 0, 155);
|
const PINK: Color = Color::srgb_u8(250, 0, 155);
|
||||||
const BLUE: Color = Color::srgb_u8(0, 0, 255);
|
const BLUE: Color = Color::srgb_u8(0, 0, 255);
|
||||||
const GREEN: Color = Color::srgb_u8(0, 255, 0);
|
const GREEN: Color = Color::srgb_u8(0, 255, 0);
|
||||||
|
|
||||||
pub fn draw_track_gizmos(track: Res<Track>, mut gizmos: Gizmos) {
|
pub fn draw_track_gizmos(query: Query<&Track>, mut gizmos: Gizmos) {
|
||||||
let mut current_pos = track.start_point;
|
println!("Рисуем трек из примитивов");
|
||||||
let mut current_dir = track.start_direction.normalize();
|
for track in &query {
|
||||||
|
let mut current_pos = track.start_point;
|
||||||
|
let mut current_dir = track.start_direction.normalize();
|
||||||
|
|
||||||
// точка старта
|
// точка старта
|
||||||
gizmos.circle_2d(current_pos, 5.0, BLUE);
|
gizmos.circle_2d(current_pos, 5.0, BLUE);
|
||||||
|
|
||||||
// рисуем сегменты
|
// рисуем сегменты
|
||||||
for segment in &track.segments {
|
for segment in &track.segments {
|
||||||
match segment {
|
match segment {
|
||||||
PathSegment::Line { length } => {
|
PathSegment::Line { length } => {
|
||||||
let end_pos = current_pos + current_dir * length;
|
let end_pos = current_pos + current_dir * length;
|
||||||
gizmos.line_2d(current_pos, end_pos, PINK);
|
gizmos.line_2d(current_pos, end_pos, PINK);
|
||||||
current_pos = end_pos
|
current_pos = end_pos
|
||||||
}
|
}
|
||||||
|
|
||||||
PathSegment::Turn { radius, left } => {
|
PathSegment::Turn { radius, left } => {
|
||||||
// вычисляем нормаль, центр, угол поворота арки и знак
|
// вычисляем направление поворота и знак для угла
|
||||||
let arc = helper_arc_calculator(current_pos, current_dir, *left, *radius);
|
let (normal, sign): (Vec2, f32) = if *left {
|
||||||
|
(Vec2::new(-current_dir.y, current_dir.x), -1.0)
|
||||||
gizmos.arc_2d(
|
} else {
|
||||||
Isometry2d::new(arc.center, Rot2::radians(arc.start_angle)),
|
(Vec2::new(current_dir.y, -current_dir.x), 1.0)
|
||||||
FRAC_PI_2,
|
};
|
||||||
*radius,
|
|
||||||
GREEN,
|
let center = current_pos + normal * radius;
|
||||||
);
|
let start_vec = current_pos - center;
|
||||||
current_pos = arc.end_pos;
|
let initial_vec = if *left {
|
||||||
current_dir = arc.normal;
|
-start_vec.perp()
|
||||||
|
} else {
|
||||||
|
-start_vec
|
||||||
|
};
|
||||||
|
|
||||||
|
gizmos.arc_2d(
|
||||||
|
Isometry2d::new(center, Rot2::radians(initial_vec.to_angle())),
|
||||||
|
FRAC_PI_2,
|
||||||
|
*radius,
|
||||||
|
GREEN,
|
||||||
|
);
|
||||||
|
// current_pos = center + current_dir * radius;
|
||||||
|
// current_pos = center + normal.perp() * radius;
|
||||||
|
current_pos = center + normal.perp() * radius * sign;
|
||||||
|
current_dir = normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// рисуем финиш
|
||||||
|
gizmos.circle_2d(current_pos, 5.0, Color::WHITE);
|
||||||
}
|
}
|
||||||
// рисуем финиш
|
|
||||||
gizmos.circle_2d(current_pos, 5.0, Color::WHITE);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
use std::f32::consts::FRAC_PI_2;
|
|
||||||
use crate::states::linear::*;
|
use crate::states::linear::*;
|
||||||
use crate::{FACTOR};
|
use crate::{FACTOR, HEIGHT, WIDTH};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::reflect::List;
|
|
||||||
|
|
||||||
pub const CENTER_X: f32 = 0.0;
|
pub const CENTER_X: f32 = 0.0;
|
||||||
pub const CENTER_Y: f32 = 0.0;
|
pub const CENTER_Y: f32 = 0.0;
|
||||||
|
|
@ -13,8 +11,10 @@ pub const STEP: f32 = FACTOR as f32 / SCALE;
|
||||||
pub const SCALE: f32 = 2.0;
|
pub const SCALE: f32 = 2.0;
|
||||||
|
|
||||||
|
|
||||||
pub fn setup_linear_track() -> Track {
|
pub fn setup_linear_track(mut commands: Commands) {
|
||||||
println!("Построение трека начато");
|
println!("Построение трека начато");
|
||||||
|
|
||||||
|
commands.spawn((
|
||||||
Track {
|
Track {
|
||||||
start_point: Vec2 {
|
start_point: Vec2 {
|
||||||
x: CENTER_X - FACTOR as f32 * 7.0,
|
x: CENTER_X - FACTOR as f32 * 7.0,
|
||||||
|
|
@ -22,120 +22,23 @@ pub fn setup_linear_track() -> Track {
|
||||||
},
|
},
|
||||||
start_direction: Vec2::X,
|
start_direction: Vec2::X,
|
||||||
segments: vec![
|
segments: vec![
|
||||||
PathSegment::Line { length: STEP * 6.0 },
|
PathSegment::Line { length: STEP * 2.0 },
|
||||||
PathSegment::Turn { radius: STEP, left: true },
|
PathSegment::Turn { radius: STEP, left: true },
|
||||||
PathSegment::Line { length: STEP },
|
PathSegment::Line { length: STEP },
|
||||||
PathSegment::Turn { radius: STEP, left: false },
|
PathSegment::Turn { radius: STEP, left: false },
|
||||||
PathSegment::Line { length: STEP * 18.0 },
|
|
||||||
PathSegment::Turn { radius: STEP, left: true },
|
|
||||||
PathSegment::Line { length: STEP * 4.0 },
|
|
||||||
PathSegment::Turn { radius: STEP, left: true },
|
|
||||||
PathSegment::Turn { radius: STEP, left: false },
|
|
||||||
PathSegment::Line { length: STEP * 4.0 },
|
|
||||||
PathSegment::Turn { radius: STEP, left: true },
|
|
||||||
PathSegment::Line { length: STEP * 20.0 },
|
|
||||||
PathSegment::Turn { radius: STEP, left: true },
|
|
||||||
PathSegment::Line { length: STEP * 5.0 },
|
|
||||||
PathSegment::Turn { radius: STEP, left: true },
|
|
||||||
PathSegment::Line { length: STEP * 10.0 },
|
PathSegment::Line { length: STEP * 10.0 },
|
||||||
|
PathSegment::Turn { radius: STEP, left: true },
|
||||||
|
PathSegment::Line { length: STEP * 4.0 },
|
||||||
|
PathSegment::Turn { radius: STEP, left: true },
|
||||||
PathSegment::Turn { radius: STEP, left: false },
|
PathSegment::Turn { radius: STEP, left: false },
|
||||||
PathSegment::Line { length: STEP * 2.0 },
|
PathSegment::Line { length: STEP * 2.0 },
|
||||||
|
PathSegment::Turn { radius: STEP, left: true },
|
||||||
|
PathSegment::Line { length: STEP * 6.0 },
|
||||||
|
PathSegment::Turn { radius: STEP, left: true },
|
||||||
|
PathSegment::Line { length: STEP * 1.0 },
|
||||||
|
PathSegment::Turn { radius: STEP, left: true },
|
||||||
],
|
],
|
||||||
}
|
},
|
||||||
|
LinearStateMarker,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn precalculate_track(track: &Track) -> PrecalculatedTrack {
|
|
||||||
let mut pt = PrecalculatedTrack { segments: vec![] };
|
|
||||||
let mut cumulative_length: Vec<f32> = vec![0.0];
|
|
||||||
|
|
||||||
let mut current_pos = track.start_point;
|
|
||||||
let mut current_dir = track.start_direction;
|
|
||||||
|
|
||||||
// на первом проходе заполняем все, кроме t_start и t_end,
|
|
||||||
// потому что мы не можем посчитать их без общей длины
|
|
||||||
for seg in track.segments.iter(){
|
|
||||||
match seg {
|
|
||||||
PathSegment::Line { length } => {
|
|
||||||
let calc_seg = PTSegment {
|
|
||||||
t_start: 0.0,
|
|
||||||
t_end: 0.0,
|
|
||||||
segment_type: SegementType::Line,
|
|
||||||
start_pos: current_pos,
|
|
||||||
direction: current_dir,
|
|
||||||
center: Vec2::ZERO,
|
|
||||||
radius: 0.0,
|
|
||||||
start_angle: 0.0,
|
|
||||||
sweep_sign: 0.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
pt.segments.push(calc_seg);
|
|
||||||
// сдвигаем позицию для следующего сегмента
|
|
||||||
current_pos = current_pos + length * current_dir;
|
|
||||||
// направление не меняем, пропуск
|
|
||||||
// накапливаем длину
|
|
||||||
cumulative_length.push(cumulative_length[cumulative_length.len() -1] + *length);
|
|
||||||
}
|
|
||||||
|
|
||||||
PathSegment::Turn {radius, left } => {
|
|
||||||
let arc = helper_arc_calculator(current_pos, current_dir, *left, *radius);
|
|
||||||
|
|
||||||
let calc_seg = PTSegment {
|
|
||||||
t_start: 0.0,
|
|
||||||
t_end: 0.0,
|
|
||||||
segment_type: SegementType::Turn,
|
|
||||||
start_pos: current_pos,
|
|
||||||
direction: current_dir,
|
|
||||||
center: arc.center,
|
|
||||||
radius: *radius,
|
|
||||||
start_angle: arc.start_angle,
|
|
||||||
sweep_sign: arc.sweep_sign,
|
|
||||||
};
|
|
||||||
pt.segments.push(calc_seg);
|
|
||||||
// сдвигаем позицию для следующего сегмента
|
|
||||||
current_pos = arc.end_pos;
|
|
||||||
current_dir = arc.normal;
|
|
||||||
// накапливаем длину
|
|
||||||
cumulative_length.push(cumulative_length[cumulative_length.len() -1] + (FRAC_PI_2 * radius));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let last_index = cumulative_length.len() - 1;
|
|
||||||
let total_length = cumulative_length[last_index];
|
|
||||||
|
|
||||||
// итерируемся уже по прекалькулированному вектору
|
|
||||||
// заполняем точки на треке в пересчете на общую длину
|
|
||||||
println!("Precalculated track:");
|
|
||||||
for (i, seg) in pt.segments.iter_mut().enumerate() {
|
|
||||||
seg.t_start = cumulative_length[i] / total_length;
|
|
||||||
if i < last_index {
|
|
||||||
seg.t_end = cumulative_length[i+1] / total_length;
|
|
||||||
} else {
|
|
||||||
seg.t_end = 1.0;
|
|
||||||
}
|
|
||||||
println!("{:?}", seg);
|
|
||||||
}
|
|
||||||
|
|
||||||
pt
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn helper_arc_calculator(pos: Vec2, dir: Vec2, turn_to: bool, radius: f32) -> ArcCalculation{
|
|
||||||
let (normal, sign): (Vec2, f32) = if turn_to {
|
|
||||||
(Vec2::new(-dir.y, dir.x), -1.0)
|
|
||||||
} else {
|
|
||||||
(Vec2::new(dir.y, -dir.x), 1.0)
|
|
||||||
};
|
|
||||||
|
|
||||||
let center = pos + normal * radius;
|
|
||||||
let start_vec = pos - center;
|
|
||||||
let initial_vec = if turn_to { -start_vec.perp() } else { -start_vec };
|
|
||||||
let angle = initial_vec.to_angle();
|
|
||||||
|
|
||||||
ArcCalculation{
|
|
||||||
normal,
|
|
||||||
center,
|
|
||||||
start_angle: angle,
|
|
||||||
sweep_sign: sign,
|
|
||||||
end_pos: center + normal.perp() * radius * sign,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue