traaains/editor/track/placing/
mod.rs1use bevy::{
8 app::{Plugin, Update},
9 ecs::{
10 component::Component,
11 entity::Entity,
12 query::With,
13 resource::Resource,
14 schedule::{IntoScheduleConfigs, common_conditions::not},
15 system::{Res, Single},
16 },
17 input::{common_conditions::input_just_pressed, mouse::MouseButton},
18 math::Vec2,
19 state::{
20 app::AppExtStates,
21 condition::in_state,
22 state::{OnEnter, OnExit, OnTransition, State},
23 },
24 ui::widget::Text,
25};
26
27use crate::{
28 editor::{StateText, track::TrackEditorState},
29 shape::Shapes,
30 ui::IsHoveringUi,
31};
32
33use self::{
34 gizmos::draw_virtual_segment_gizmos,
35 input_handlers::{advance_step, back_step, switch_shape},
36 move_to_cursor::{virtual_node_to_cursor, virtual_segment_to_cursor},
37 states::{
38 current_shape::CurrentShape,
39 current_step::{
40 CurrentStep, on_enter_constant, on_exit_constant, on_linear_to_quadratic,
41 on_quadratic_to_cubic, on_quadratic_to_linear,
42 },
43 current_step::{on_cubic_to_linear, on_cubic_to_quadratic},
44 final_step::place_segment,
45 final_step::{FinalStep, on_enter_final_step, on_exit_final_step},
46 on_enter_placing, on_leave_placing,
47 },
48};
49
50mod gizmos;
51mod input_handlers;
52mod move_to_cursor;
53mod observers;
54mod states;
55
56#[derive(Component)]
58struct Placing;
59
60#[derive(Component)]
62struct VirtualNode;
63
64#[derive(Default, PartialEq, Eq)]
67enum NodeType {
68 #[default]
69 Virtual,
70 Physical(Entity),
71}
72
73#[derive(Default, Resource)]
75struct FromNodeType(NodeType);
76
77#[derive(Component)]
79struct VirtualSegment {
80 pub shape: Shapes,
81 pub from: Entity,
82 pub to: NodeType,
83}
84
85#[derive(Default, Resource)]
88struct LastConnectedBlock(pub Option<Entity>);
89
90fn take_points<const N: usize>(shape: &Shapes) -> [Vec2; N] {
91 let mut coeffs = shape.coeffs().iter();
93 std::array::from_fn(|_| {
94 *coeffs
95 .next()
96 .expect("Failed to extract enough information from spline")
97 })
98}
99
100fn update_state_text(
101 mut text: Single<&mut Text, With<StateText>>,
102 current_shape: Res<State<CurrentShape>>,
103 current_step: Res<State<CurrentStep>>,
104) {
105 text.0 = format!(
106 "Placing tracks\n[J] Previous shape, [L] Next shape\n[9] Remove tracks\n[Esc] to exit\nCurrently placing: {}, Current step: {}",
107 current_shape.get(),
108 current_step.get(),
109 );
110}
111
112pub struct PlacingPlugin;
113
114fn register_state_handlers(app: &mut bevy::app::App) {
115 app.add_sub_state::<CurrentShape>()
116 .add_sub_state::<CurrentStep>()
117 .add_computed_state::<FinalStep>()
118 .add_systems(OnEnter(TrackEditorState::Placing), on_enter_placing)
119 .add_systems(OnExit(TrackEditorState::Placing), on_leave_placing)
120 .add_systems(OnEnter(CurrentStep::Zero), on_enter_constant)
121 .add_systems(OnExit(CurrentStep::Zero), on_exit_constant)
122 .add_systems(
123 OnTransition {
124 exited: CurrentStep::Linear,
125 entered: CurrentStep::Quadratic,
126 },
127 on_linear_to_quadratic,
128 )
129 .add_systems(
130 OnTransition {
131 exited: CurrentStep::Quadratic,
132 entered: CurrentStep::Linear,
133 },
134 on_quadratic_to_linear,
135 )
136 .add_systems(
137 OnTransition {
138 exited: CurrentStep::Quadratic,
139 entered: CurrentStep::Cubic,
140 },
141 on_quadratic_to_cubic,
142 )
143 .add_systems(
144 OnTransition {
145 exited: CurrentStep::Cubic,
146 entered: CurrentStep::Quadratic,
147 },
148 on_cubic_to_quadratic,
149 )
150 .add_systems(
151 OnTransition {
152 exited: CurrentStep::Cubic,
153 entered: CurrentStep::Linear,
154 },
155 on_cubic_to_linear,
156 )
157 .add_systems(OnEnter(FinalStep), on_enter_final_step)
158 .add_systems(OnExit(FinalStep), on_exit_final_step);
159}
160
161impl Plugin for PlacingPlugin {
162 fn build(&self, app: &mut bevy::app::App) {
163 register_state_handlers(app);
164
165 app.add_systems(Update, (virtual_node_to_cursor, virtual_segment_to_cursor))
166 .add_systems(
167 Update,
168 (update_state_text, switch_shape).run_if(in_state(TrackEditorState::Placing)),
169 )
170 .add_systems(
171 Update,
172 (
173 (
174 advance_step.run_if(not(in_state(FinalStep))),
175 place_segment.run_if(in_state(FinalStep)),
176 )
177 .run_if(input_just_pressed(MouseButton::Left)),
178 back_step.run_if(input_just_pressed(MouseButton::Right)),
179 )
180 .run_if(in_state(TrackEditorState::Placing))
181 .run_if(in_state(IsHoveringUi(false))),
182 )
183 .add_systems(Update, draw_virtual_segment_gizmos);
184 }
185}