Skip to main content

traaains/sim/train/
mod.rs

1//! Trains.
2//!
3//! Trains are position-less entities, simply storing a vector of references to their carriages (and, currently, an acceleration and velocity).
4//!
5//! Carriages are also track position-less entities. Each has a certain length, width and mass. They have a system of bogies,
6//! to which they position themselves.
7//!
8//! Bogies have both a track position and a world transform. On each frame, after bogie world transforms are updated based on their track
9//! positions, carriages are aligned respective to their bogies.
10
11use bevy::{
12    ecs::{
13        component::Component,
14        entity::Entity,
15        event::EntityEvent,
16        observer::On,
17        query::With,
18        system::{Query, ResMut},
19    },
20    picking::events::PointerPress,
21    shape::Rectangle,
22    state::state::NextState,
23};
24
25use crate::{sim::track::STANDARD_GAUGE, ui::UiState, utils::Meshable};
26
27pub mod commands;
28pub mod systems;
29
30/// Where should the single bogie be mounted. This should become a modifiable property in the future.
31pub const SINGLE_BOGIE_IDX: f32 = 0.5;
32/// Where should the double bogie be mounted. This should become a modifiable property in the future.
33pub const DOUBLE_BOGIE_IDX: (f32, f32) = (0.1, 0.9);
34/// Default coupler length. This should become a modifiable property in the future.
35pub const COUPLER_LENGTH: f32 = 0.1;
36
37// TODO: This should be different per train
38pub const BRAKING_COEFF: f32 = 0.2;
39
40/// Defines the behaviour of the related train. Unfinished.
41#[derive(Clone, Default)]
42pub enum TrainMode {
43    /// The train won't do anything and will wait for the player's control.
44    /// Driver components won't do anything.
45    #[default]
46    Manual,
47    /// The train will pathfind and try to reach the node specified by the player.
48    /// Will respond to signals and change switches accordingly.
49    SemiAutomatic,
50    /// The train will go on a pre-defined route, assuming it is present (like a train schedule, for example).
51    Automatic,
52}
53
54#[derive(Clone, Component, Default)]
55pub struct Train {
56    pub carriages: Vec<Entity>,
57    /// in kilograms
58    pub total_mass: f32,
59    // in watts
60    pub total_power: f32,
61    // unimplemented
62    pub mode: TrainMode,
63}
64
65/// Component of a carriage, pointing to its parent train.
66#[derive(Component)]
67pub struct TrainMember {
68    pub parent: Entity,
69}
70
71// #[derive(Clone)]
72// /// Describes a bogie mount at a carriage
73// pub struct BogieMount {
74//     /// The target bogie
75//     pub bogie: Entity,
76//     /// Index of the location of the mount, front to back (0.0 means front).
77//     pub idx: f32,
78// }
79
80#[derive(Clone)]
81/// Describes which shape a carriage's bogies can take.
82/// For simplicity sake, it is assumed that bogies are mounted at the same location on each carriage.
83pub enum CarriageBogies {
84    Single(Entity),
85    Double { front: Entity, back: Entity },
86}
87
88/// A single carriage in a train, defined by its length, width and mass.
89#[derive(Clone, Component)]
90pub struct Carriage {
91    /// in meters
92    pub length: f32,
93    /// in meters
94    pub width: f32,
95    /// in kilograms
96    pub mass: f32,
97    // in watts
98    pub power: f32,
99    pub bogies: CarriageBogies,
100}
101
102impl Meshable for Carriage {
103    type Props = ();
104
105    fn mesh(&self, _: Self::Props) -> bevy::mesh::Mesh {
106        Rectangle::new(self.length, self.width).into()
107    }
108}
109
110/// A [bogie](https://en.wikipedia.org/wiki/Bogie).
111///
112/// Simply an entity with a track position and a transform, to which a carriage refers to for its tranform updates.
113/// For simplicity sake, it is assumed that the same force is applied to each bogie of a carriage, no matter its
114/// orientation with respect to the force. If one would like to simulate forces at the bogie level one would have
115/// to figure out how to model the relationship between the bogies and the carriage itself, since at that point each
116/// of the bogies might move a different amount and thus the simple model of drawing a line through the center of each
117/// of the bogies and aligning the carriage with it no longer works.
118#[derive(Component)]
119pub struct Bogie {
120    /// in meters
121    pub length: f32,
122}
123
124impl Meshable for Bogie {
125    type Props = ();
126
127    fn mesh(&self, _: Self::Props) -> bevy::mesh::Mesh {
128        Rectangle::new(self.length, STANDARD_GAUGE).into()
129    }
130}
131
132/// Observer that runs on left click on carriages and opens the train window
133pub fn on_carriage_press_window(
134    e: On<PointerPress>,
135    q_carriages: Query<&TrainMember, With<Carriage>>,
136    mut next_state: ResMut<NextState<UiState>>,
137) {
138    if let Ok(carriage) = q_carriages.get(e.event_target()) {
139        next_state.set(UiState::TrainWindow {
140            target: carriage.parent,
141        });
142    }
143}