traaains/editor/train/placing/states/
hovering.rs1use bevy::{
2 asset::Assets,
3 ecs::{
4 entity::Entity,
5 query::With,
6 system::{Commands, Query, Res, ResMut},
7 },
8 mesh::{Mesh, Mesh2d},
9 picking::Pickable,
10 shape::Rectangle,
11 sprite_render::MeshMaterial2d,
12 state::state::{ComputedStates, State, SubStates},
13 transform::components::Transform,
14};
15
16use crate::{
17 AssetType, AssetsManager,
18 editor::train::{
19 TrainEditorState,
20 placing::{
21 CurrentPlacingDir, CurrentPlacingTrain, Virtual, VirtualBogie, VirtualCarriage,
22 VirtualTrain, templates::CarriageBogiesTemplate,
23 },
24 },
25 sim::{
26 track::pos::{IgnoreTrackPosUpdate, TrackPos},
27 train::CarriageBogies,
28 },
29 utils::linked_list::LinkedListItem,
30};
31
32#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, SubStates)]
33#[source(TrainEditorState = TrainEditorState::PlacingTrain)]
34pub struct HoveringTrack(pub Option<Entity>);
35
36#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
37pub struct IsHoveringTrack;
38
39impl ComputedStates for IsHoveringTrack {
40 type SourceStates = HoveringTrack;
41
42 fn compute(sources: Self::SourceStates) -> Option<Self> {
43 match sources {
44 HoveringTrack(Some(_)) => Some(IsHoveringTrack),
45 _ => None,
46 }
47 }
48}
49
50pub fn on_enter_hovering(
51 mut cmd: Commands,
52 hovering_track: Res<State<HoveringTrack>>,
53 current_dir: Res<CurrentPlacingDir>,
54 current_train: Res<CurrentPlacingTrain>,
55 mut meshes: ResMut<Assets<Mesh>>,
56 assets_manager: Res<AssetsManager>,
57) {
58 let mut carriages = Vec::new();
59 let mut last_carriage = None;
60
61 let hovering_track = hovering_track.get().0.unwrap();
63
64 for carriage in ¤t_train.carriages {
65 let carriage_bogies = match &carriage.bogies {
66 CarriageBogiesTemplate::Single => {
67 let spawned_bogie = cmd
68 .spawn((
69 TrackPos {
70 segment: hovering_track,
71 idx: 0.0,
72 dir: None,
73 },
74 Transform::default(),
75 VirtualBogie,
76 Virtual,
77 ))
78 .id();
79
80 CarriageBogies::Single(spawned_bogie)
81 }
82 CarriageBogiesTemplate::Double => {
83 let spawned: [Entity; 2] = std::array::from_fn(|_| {
84 cmd.spawn((
85 TrackPos {
86 segment: hovering_track,
87 idx: 0.0,
88 dir: None,
89 },
90 Transform::default(),
91 VirtualBogie,
92 Virtual,
93 ))
94 .id()
95 });
96
97 CarriageBogies::Double {
98 front: spawned[0],
99 back: spawned[1],
100 }
101 }
102 };
103
104 let spawned_carriage = cmd
105 .spawn((
106 VirtualCarriage {
107 length: carriage.length,
108 bogies: carriage_bogies,
109 },
110 Virtual,
111 LinkedListItem {
112 prev: last_carriage,
113 next: None,
114 },
115 Pickable::IGNORE,
116 Transform::default(),
117 Mesh2d(meshes.add(Rectangle::new(carriage.length, carriage.width))),
118 MeshMaterial2d(
119 assets_manager
120 .materials
121 .get(&AssetType::CarriageNormal)
122 .cloned()
123 .unwrap(),
124 ),
125 ))
126 .id();
127
128 if let Some(last_carriage) = last_carriage {
129 cmd.entity(last_carriage)
130 .entry::<LinkedListItem>()
131 .and_modify(move |mut item| item.next = Some(spawned_carriage));
132 }
133
134 carriages.push(spawned_carriage);
135 last_carriage = Some(spawned_carriage);
136 }
137
138 cmd.spawn((
139 VirtualTrain { carriages },
140 Virtual,
141 TrackPos {
142 segment: hovering_track,
143 idx: 0.0,
144 dir: Some(current_dir.0),
145 },
146 IgnoreTrackPosUpdate,
147 ));
148}
149
150pub fn on_exit_hovering(mut cmd: Commands, q_virtual: Query<Entity, With<Virtual>>) {
151 for e in q_virtual {
152 cmd.entity(e).despawn();
153 }
154}