linear track plugin

This commit is contained in:
nquidox 2026-04-15 23:02:14 +03:00
parent c1e53bdab0
commit 68c895ec14
6 changed files with 160 additions and 0 deletions

View file

@ -0,0 +1,4 @@
use bevy::prelude::*;
#[derive(Component)]
pub struct LinearStateMarker;

View file

@ -0,0 +1,17 @@
use bevy::prelude::*;
#[derive(Component)]
pub struct Track{
pub start_point: Vec2,
pub start_direction: Vec2, // будет нормализовано при построении
pub segments: Vec<PathSegment>,
}
// линия всегда строится от точки старта по направлению
// направление изменяется сегментами поворота
// left при истине - поворот против часовой стрелки, ложь - по часовой
#[derive(Clone, Copy)]
pub enum PathSegment{
Line { length: f32 },
Turn { radius: f32, left: bool },
}

13
src/states/linear/mod.rs Normal file
View file

@ -0,0 +1,13 @@
pub mod plugin;
mod components;
pub use components::*;
mod systems;
pub use systems::*;
mod components_track;
pub use components_track::*;
mod systems_track;
pub use systems_track::*;

View file

@ -0,0 +1,22 @@
use bevy::prelude::*;
use crate::states::AppState::LinearState;
use crate::states::linear::*;
pub struct LinearPlugin;
impl Plugin for LinearPlugin {
fn build(&self, app: &mut App) {
app
.add_systems(OnEnter (LinearState), (setup, setup_linear_track).chain())
.add_systems(Update, (draw_track_gizmos).run_if(in_state(LinearState)))
.add_systems(OnExit (LinearState), cleanup);
}
}
fn setup(mut commands: Commands) {}
fn cleanup(mut commands: Commands, query: Query<Entity, With<LinearStateMarker>>) {
for entity in query.iter() {
commands.entity(entity).despawn();
}
}

View file

@ -0,0 +1,60 @@
use crate::states;
use bevy::prelude::*;
use states::linear::*;
use std::f32::consts::{FRAC_PI_2, PI};
const PINK: Color = Color::srgb_u8(250, 0, 155);
const BLUE: Color = Color::srgb_u8(0, 0, 255);
const GREEN: Color = Color::srgb_u8(0, 255, 0);
pub fn draw_track_gizmos(query: Query<&Track>, mut gizmos: Gizmos) {
println!("Рисуем трек из примитивов");
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);
// рисуем сегменты
for segment in &track.segments {
match segment {
PathSegment::Line { length } => {
let end_pos = current_pos + current_dir * length;
gizmos.line_2d(current_pos, end_pos, PINK);
current_pos = end_pos
}
PathSegment::Turn { radius, left } => {
// вычисляем направление поворота и знак для угла
let (normal, sign): (Vec2, f32) = if *left {
(Vec2::new(-current_dir.y, current_dir.x), -1.0)
} else {
(Vec2::new(current_dir.y, -current_dir.x), 1.0)
};
let center = current_pos + normal * radius;
let start_vec = current_pos - center;
let initial_vec = if *left {
-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);
}
}

View file

@ -0,0 +1,44 @@
use crate::states::linear::*;
use crate::{FACTOR, HEIGHT, WIDTH};
use bevy::prelude::*;
pub const CENTER_X: f32 = 0.0;
pub const CENTER_Y: f32 = 0.0;
// pub const FACTOR_RADIUS: f32 = FACTOR as f32 / 2.0;
pub const STEP: f32 = FACTOR as f32 / SCALE;
pub const SCALE: f32 = 2.0;
pub fn setup_linear_track(mut commands: Commands) {
println!("Построение трека начато");
commands.spawn((
Track {
start_point: Vec2 {
x: CENTER_X - FACTOR as f32 * 7.0,
y: CENTER_Y - FACTOR as f32 * 4.0,
},
start_direction: Vec2::X,
segments: vec![
PathSegment::Line { length: STEP * 2.0 },
PathSegment::Turn { radius: STEP, left: true },
PathSegment::Line { length: STEP },
PathSegment::Turn { radius: STEP, left: false },
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::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,
));
}