Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/state.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::collections::HashMap;
use std::sync::atomic::AtomicUsize;
use std::sync::{Arc, RwLock};

use crate::dijkstra::{GlobePoints, GridPoint};
Expand Down Expand Up @@ -44,14 +45,15 @@ impl Default for Config {
}
}

#[derive(PartialEq, Eq, Hash)]
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
pub struct Rail {
pub from: GridPoint,
pub to: GridPoint,
}

pub struct RailInfo {
pub entity: Entity,
pub counter: AtomicUsize,
// Other details such as how frequently the rail is used can come here.
}

Expand All @@ -67,4 +69,5 @@ pub struct State {
pub rails: Rails,
pub rng: rand::rngs::StdRng,
pub create_new_city_next: bool,
pub max_rail_usage: AtomicUsize,
}
37 changes: 33 additions & 4 deletions src/train.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::state::{Rail, State};
use bevy::prelude::*;
use std::sync::atomic::Ordering;

#[derive(Component)]
pub struct Train {
pub transforms: Vec<Transform>,
pub transforms: Vec<(Transform, Rail)>,
pub idx: usize,
pub next_idx: usize,
pub forward: bool,
Expand All @@ -14,7 +16,7 @@ pub struct Train {
pub struct SelectedTrain;

impl Train {
pub fn new(transforms: Vec<Transform>) -> Option<Self> {
pub fn new(transforms: Vec<(Transform, Rail)>) -> Option<Self> {
if transforms.len() < 2 {
return None;
}
Expand All @@ -29,7 +31,7 @@ impl Train {
}

fn transform_at(&self, idx: i32) -> Transform {
self.transforms[idx.clamp(0, self.transforms.len() as i32 - 1) as usize]
self.transforms[idx.clamp(0, self.transforms.len() as i32 - 1) as usize].0
}

fn duration_between(&self, start: &Transform, end: &Transform) -> f32 {
Expand Down Expand Up @@ -107,7 +109,14 @@ impl Train {
}
}

pub fn update(&mut self, transform: &mut Transform, time_passed_seconds: f32) {
pub fn update(
&mut self,
transform: &mut Transform,
time_passed_seconds: f32,
state: &State,
commands: &mut Commands,
materials: &mut Assets<StandardMaterial>,
) {
if self.segment_duration.is_none() {
self.compute_segment_duration();
}
Expand All @@ -117,6 +126,26 @@ impl Train {
// Move to the next segment.
self.idx = self.next_idx;

let rail_info = state.rails.rails.get(&self.transforms[self.idx].1).unwrap();

let count = rail_info.counter.fetch_add(1, Ordering::Relaxed) + 1;

let max_rail_usage =
count.max(state.max_rail_usage.fetch_max(count, Ordering::Relaxed));

let color = (((max_rail_usage - count) as f32 / max_rail_usage as f32) * 255.) as u8;

let material = materials.add(StandardMaterial {
base_color: Color::srgb_u8(255, color, color),
perceptual_roughness: 0.0,
metallic: 0.0,
..default()
});

commands
.entity(rail_info.entity)
.insert((MeshMaterial3d(material),));

// Account for the remaining time.
self.seconds_spent_within_segment =
self.segment_duration.unwrap() - self.seconds_spent_within_segment;
Expand Down
79 changes: 41 additions & 38 deletions src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub fn init() {
crate::state::Config::default().perlin_config.seed as u64,
),
create_new_city_next: true,
max_rail_usage: 0.into(),
})
.insert_resource(SelectedCity::default())
.add_systems(Update, draw_pointer)
Expand Down Expand Up @@ -200,7 +201,7 @@ fn create_path_if_dijkstra_ready(
meshes: Res<Meshes>,
custom_materials: Res<Materials>,
) {
let Some(task) = dijkstra_communication.task else {
let Some(_) = dijkstra_communication.task else {
return;
};
let Ok(dijkstra_result) = dijkstra_communication.receiver.try_recv() else {
Expand All @@ -214,19 +215,11 @@ fn create_path_if_dijkstra_ready(
// Clear task to signal Dijkstra is ready for another task.
dijkstra_communication.task = None;

let start = task.0;
let end = task.1;

let path_mesh = meshes.path.clone();
let train_mesh = meshes.train.clone();

// Create a custom color for the path based on start and end points.
let r = ((27 * (start.1 + end.1)) % 256) as u8;
let g = ((51 * (start.2 + end.2)) % 256) as u8;
let b = ((11 * (start.1 + end.2)) % 256) as u8;

let material = materials.add(StandardMaterial {
base_color: Color::srgb_u8(r, g, b),
base_color: Color::srgb_u8(255, 255, 255),
perceptual_roughness: 0.0,
metallic: 0.0,
..default()
Expand Down Expand Up @@ -283,36 +276,27 @@ fn create_path_if_dijkstra_ready(
let rotation =
Quat::from_mat3(&Mat3::from_cols(Vec3::cross(dir_norm, up), dir_norm, up));

train_transforms
.push(Transform::from_translation(mid_point * 1.005).with_rotation(rotation));

// If this piece of rail already exists, just change its material
// corresponding to the current path.
// We don't _really_ need this, but this demonstrates how to update
// existig rail piece entities.
if let Some(rail_info) = state.rails.rails.get(&rail) {
commands
.entity(rail_info.entity)
.insert((MeshMaterial3d(material.clone()),));
continue;
}
// Otherwise, create a new entity for the rail and store it in the
// Rails resource.
//
// We first create an empty entity in order to already have its ID
// which we can key the RailInfo with.
//
// We'll update it with all the details the same way as we've updated
// the existing rail piece above.
let entity = commands.spawn_empty().id();
state.rails.rails.insert(
rail,
RailInfo {
entity,
// Other details can be added here.
},
);

if let std::collections::hash_map::Entry::Vacant(e) = state.rails.rails.entry(rail) {
// Otherwise, create a new entity for the rail and store it in the
// Rails resource.
//
// We first create an empty entity in order to already have its ID
// which we can key the RailInfo with.
//
// We'll update it with all the details the same way as we've updated
// the existing rail piece above.
let entity = commands.spawn_empty().id();
e.insert(
RailInfo {
entity,
counter: 0.into(),
Comment thread
lukacslacko marked this conversation as resolved.
// Other details can be added here.
},
);
commands.entity(entity).insert((
Mesh3d(path_mesh.clone()),
MeshMaterial3d(material.clone()),
Expand All @@ -325,6 +309,13 @@ fn create_path_if_dijkstra_ready(
.with_rotation(rotation),
PointerInteraction::default(),
));
}

train_transforms.push((
Transform::from_translation(mid_point * 1.005).with_rotation(rotation),
rail,
));

}
}
}
Expand Down Expand Up @@ -686,11 +677,23 @@ fn highlight_city(
}
}

fn move_trains(time: Res<Time>, mut trains: Query<(&mut Train, &mut Transform), With<Train>>) {
fn move_trains(
mut commands: Commands,
state: Res<State>,
time: Res<Time>,
mut trains: Query<(&mut Train, &mut Transform), With<Train>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let time_passed_seconds = time.delta().as_secs_f32();

for (mut train, mut transform) in trains.iter_mut() {
train.update(&mut transform, time_passed_seconds);
train.update(
&mut transform,
time_passed_seconds,
&state,
&mut commands,
&mut materials,
);
}
}

Expand Down
Loading