Skip to main content

traaains/sim/track/
pos.rs

1use std::f32::consts::PI;
2
3use bevy::{
4    ecs::{component::Component, entity::Entity, query::Without, system::Query},
5    math::Quat,
6    transform::components::Transform,
7};
8use shapes::{Derivable, lerp::Lerp};
9
10use crate::{sim::track::segment::TrackSegment, utils::Dir};
11
12/// Position of an object along some track segment.
13#[derive(Component, Clone, Copy, Debug)]
14pub struct TrackPos {
15    /// The track segment in question.
16    pub segment: Entity,
17    /// Position index, treated as a ratio of how far along the segment it is. In range [0.0; 1.0].
18    pub idx: f32,
19    /// Encodes which direction the object is facing along the segment. Positive means it is going from 0.0 to 1.0.
20    /// Some objects can be directionally independent, thus an Option.
21    pub dir: Option<Dir>,
22}
23
24/// Entities marked with this component will be ignored when updating transform of `TrackPos` entities.
25/// Use when you want to implement your own sync logic (like with signals).
26#[derive(Component)]
27pub struct IgnoreTrackPosUpdate;
28
29// System which takes oll entities that have a track position and moves their transform in accordance with the track segment
30pub fn update_on_track_pos(
31    on_track: Query<(&TrackPos, &mut Transform), Without<IgnoreTrackPosUpdate>>,
32    segment: Query<(&TrackSegment, &Transform), Without<TrackPos>>,
33) {
34    for (track_pos, mut transform) in on_track {
35        if let Ok((segment, segment_transform)) = segment.get(track_pos.segment) {
36            transform.translation =
37                segment.shape.lerp(track_pos.idx).extend(1.0) + segment_transform.translation;
38
39            // z axis is the one perpendicular to the screen in 2D
40            let tangent = segment.shape.derivative().lerp(track_pos.idx);
41            let mut angle = f32::atan2(tangent.y, tangent.x);
42            if track_pos.dir == Some(Dir::Positive) {
43                angle += PI;
44            }
45            transform.rotation = Quat::from_rotation_z(angle);
46        }
47    }
48}