Skip to main content

traaains/editor/train/placing/states/
hovering.rs

1use 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    // this is Some
62    let hovering_track = hovering_track.get().0.unwrap();
63
64    for carriage in &current_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}