Skip to content

Commit 5197d42

Browse files
committed
refactor(bevy_city): refactor traffic + toggle
1 parent 40ae58c commit 5197d42

6 files changed

Lines changed: 58 additions & 77 deletions

File tree

examples/large_scenes/bevy_city/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ publish = false
66
license = "MIT OR Apache-2.0"
77

88
[features]
9-
trace_tracy = ["bevy/trace_tracy"]
109
traffic = []
1110

1211
[dependencies]

examples/large_scenes/bevy_city/src/assets.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ pub struct CityAssets {
2727
pub tree_large: Handle<Scene>,
2828
pub path_stones_long: Handle<Scene>,
2929
pub fence: Handle<Scene>,
30-
#[cfg(feature = "traffic")]
3130
pub traffic_light: Handle<Scene>,
3231
}
3332

@@ -221,7 +220,6 @@ pub fn load_assets(
221220
GltfAssetLabel::Scene(0).from_asset(format!("{base_url}/city-kit-suburban/fence.glb"))
222221
);
223222

224-
#[cfg(feature = "traffic")]
225223
let traffic_light: Handle<Scene> =
226224
load_asset!(GltfAssetLabel::Scene(0).from_asset("traffic_assets/traffic_light.glb"));
227225

@@ -238,7 +236,6 @@ pub fn load_assets(
238236
tree_large,
239237
path_stones_long,
240238
fence,
241-
#[cfg(feature = "traffic")]
242239
traffic_light,
243240
});
244241
}

examples/large_scenes/bevy_city/src/generate_city.rs

Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ use bevy::prelude::*;
22
use noise::{NoiseFn, OpenSimplex};
33
use rand::{rngs::SmallRng, RngExt, SeedableRng};
44

5-
use crate::{assets::CityAssets, Car, Road};
6-
#[cfg(feature = "traffic")]
7-
use crate::{traffic, CarAtStopState, CarState};
5+
use crate::{assets::CityAssets, traffic, Car, CarAtStopState, CarState, Road};
86
#[derive(Component)]
97
pub struct CityRoot;
108

@@ -88,30 +86,25 @@ fn spawn_roads_and_cars<R: RngExt>(
8886
let x = offset.x;
8987
let z = offset.z;
9088

91-
#[cfg_attr(not(feature = "traffic"), allow(unused_variables))]
9289
let crossroad = commands
9390
.spawn((
9491
SceneRoot(assets.crossroad.clone()),
9592
Transform::from_xyz(x, 0.0, z),
96-
#[cfg(feature = "traffic")]
9793
traffic::TrafficLight::new((x * 7.3 + z * 3.7).rem_euclid(traffic::CYCLE_DURATION)),
9894
))
9995
.id();
10096

101-
#[cfg(feature = "traffic")]
102-
{
103-
// 2 traffic lights at diagonal corners,
104-
for (dx, dz, y_rot) in [
105-
(-0.5_f32, -0.5_f32, 0.0_f32), // NW corner
106-
(0.5_f32, -0.5_f32, -std::f32::consts::FRAC_PI_2), // NE corner
107-
] {
108-
commands.spawn((
109-
SceneRoot(assets.traffic_light.clone()),
110-
Transform::from_translation(Vec3::new(x + dx, 0.0, z + dz))
111-
.with_rotation(Quat::from_rotation_y(y_rot))
112-
.with_scale(Vec3::splat(0.3)),
113-
));
114-
}
97+
// 2 traffic lights at diagonal corners
98+
for (dx, dz, y_rot) in [
99+
(-0.5_f32, -0.5_f32, 0.0_f32),
100+
(0.5_f32, -0.5_f32, std::f32::consts::FRAC_PI_2),
101+
] {
102+
commands.spawn((
103+
SceneRoot(assets.traffic_light.clone()),
104+
Transform::from_translation(Vec3::new(x + dx, 0.0, z + dz))
105+
.with_rotation(Quat::from_rotation_y(y_rot))
106+
.with_scale(Vec3::splat(0.3)),
107+
));
115108
}
116109

117110
let max_car_density = 0.4;
@@ -130,7 +123,6 @@ fn spawn_roads_and_cars<R: RngExt>(
130123
Road {
131124
start: Vec3::new(0.75, 0.0, 0.0),
132125
end: Vec3::new(0.75 + (0.5 * car_count as f32), 0.0, 0.0),
133-
#[cfg(feature = "traffic")]
134126
intersection: crossroad,
135127
},
136128
))
@@ -157,11 +149,8 @@ fn spawn_roads_and_cars<R: RngExt>(
157149
distance_traveled: i as f32 * 0.5,
158150
dir: -1.0,
159151
offset: Vec3::new(4.25, 0.0, -0.15),
160-
#[cfg(feature = "traffic")]
161152
car_state: CarState::Driving,
162-
#[cfg(feature = "traffic")]
163153
car_at_stop_state: CarAtStopState::Default,
164-
#[cfg(feature = "traffic")]
165154
next_lane: None,
166155
},
167156
));
@@ -180,11 +169,8 @@ fn spawn_roads_and_cars<R: RngExt>(
180169
distance_traveled: i as f32 * 0.5,
181170
dir: 1.0,
182171
offset: Vec3::new(-0.25, 0.0, 0.15),
183-
#[cfg(feature = "traffic")]
184172
car_state: CarState::Driving,
185-
#[cfg(feature = "traffic")]
186173
car_at_stop_state: CarAtStopState::Default,
187-
#[cfg(feature = "traffic")]
188174
next_lane: None,
189175
},
190176
));
@@ -201,7 +187,6 @@ fn spawn_roads_and_cars<R: RngExt>(
201187
Road {
202188
start: Vec3::new(0.0, 0.0, 0.75),
203189
end: Vec3::new(0.0, 0.0, 0.75 + (0.5 * car_count as f32)),
204-
#[cfg(feature = "traffic")]
205190
intersection: crossroad,
206191
},
207192
))
@@ -225,11 +210,8 @@ fn spawn_roads_and_cars<R: RngExt>(
225210
distance_traveled: i as f32 * 0.5,
226211
dir: 1.0,
227212
offset: Vec3::new(-0.15, 0.0, -0.25),
228-
#[cfg(feature = "traffic")]
229213
car_state: CarState::Driving,
230-
#[cfg(feature = "traffic")]
231214
car_at_stop_state: CarAtStopState::Default,
232-
#[cfg(feature = "traffic")]
233215
next_lane: None,
234216
},
235217
));
@@ -245,11 +227,8 @@ fn spawn_roads_and_cars<R: RngExt>(
245227
distance_traveled: i as f32 * 0.5,
246228
dir: -1.0,
247229
offset: Vec3::new(0.15, 0.0, 2.75),
248-
#[cfg(feature = "traffic")]
249230
car_state: CarState::Driving,
250-
#[cfg(feature = "traffic")]
251231
car_at_stop_state: CarAtStopState::Default,
252-
#[cfg(feature = "traffic")]
253232
next_lane: None,
254233
},
255234
));

examples/large_scenes/bevy_city/src/main.rs

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ mod assets;
2727
mod generate_city;
2828
mod settings;
2929

30-
#[cfg(feature = "traffic")]
3130
mod traffic;
3231

3332
#[derive(FromArgs, Resource, Clone)]
@@ -70,7 +69,6 @@ fn main() {
7069
}),
7170
..default()
7271
}),
73-
#[cfg(feature = "traffic")]
7472
traffic::TrafficPlugin,
7573
FreeCameraPlugin,
7674
FeathersPlugins,
@@ -96,7 +94,6 @@ fn main() {
9694
.add_observer(on_city_assets_ready)
9795
.add_observer(setup_settings_ui);
9896

99-
#[cfg(feature = "traffic")]
10097
app.add_systems(Update, apply_traffic_rules.before(simulate_cars));
10198

10299
app.run();
@@ -243,7 +240,6 @@ fn on_city_assets_ready(
243240
struct Road {
244241
start: Vec3,
245242
end: Vec3,
246-
#[cfg(feature = "traffic")]
247243
intersection: Entity,
248244
}
249245

@@ -252,15 +248,11 @@ struct Car {
252248
offset: Vec3,
253249
distance_traveled: f32,
254250
dir: f32,
255-
#[cfg(feature = "traffic")]
256251
car_state: CarState,
257-
#[cfg(feature = "traffic")]
258252
car_at_stop_state: CarAtStopState,
259-
#[cfg(feature = "traffic")]
260253
next_lane: Option<Entity>,
261254
}
262255

263-
#[cfg(feature = "traffic")]
264256
#[derive(PartialEq, Eq, Default)]
265257
pub enum CarState {
266258
Accelerating,
@@ -270,7 +262,6 @@ pub enum CarState {
270262
Stopped,
271263
}
272264

273-
#[cfg(feature = "traffic")]
274265
#[derive(PartialEq, Eq, Default)]
275266
pub enum CarAtStopState {
276267
#[default]
@@ -298,7 +289,6 @@ fn simulate_cars(
298289
continue;
299290
};
300291

301-
#[cfg(feature = "traffic")]
302292
if matches!(car.car_state, CarState::Stopped) {
303293
continue;
304294
}
@@ -316,8 +306,8 @@ fn simulate_cars(
316306
}
317307
}
318308

319-
#[cfg(feature = "traffic")]
320309
fn apply_traffic_rules(
310+
settings: Res<Settings>,
321311
roads: Query<(&Road, &Children), Without<Car>>,
322312
mut cars: Query<&mut Car>,
323313
traffic_lights: Query<&traffic::TrafficLight>,
@@ -336,12 +326,15 @@ fn apply_traffic_rules(
336326
};
337327
let road_len = (road.end - road.start).length();
338328
let remaining = road_len - car.distance_traveled;
339-
car.car_state = if remaining < stop_distance && phase == traffic::TrafficLightPhase::Red
340-
{
341-
CarState::Stopped
342-
} else {
343-
CarState::Driving
344-
};
329+
car.car_state =
330+
if settings.traffic_enabled
331+
&& remaining < stop_distance
332+
&& phase == traffic::TrafficLightPhase::Red
333+
{
334+
CarState::Stopped
335+
} else {
336+
CarState::Driving
337+
};
345338
}
346339
}
347340
}

examples/large_scenes/bevy_city/src/settings.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::{assets::CityAssets, CitySpawned};
1919
#[derive(Resource)]
2020
pub struct Settings {
2121
pub simulate_cars: bool,
22+
pub traffic_enabled: bool,
2223
pub shadow_maps_enabled: bool,
2324
pub contact_shadows_enabled: bool,
2425
pub wireframe_enabled: bool,
@@ -29,6 +30,7 @@ impl Default for Settings {
2930
fn default() -> Self {
3031
Self {
3132
simulate_cars: true,
33+
traffic_enabled: true,
3234
shadow_maps_enabled: true,
3335
contact_shadows_enabled: true,
3436
wireframe_enabled: false,
@@ -77,6 +79,15 @@ pub fn setup_settings_ui(_: On<CitySpawned>, mut commands: Commands) {
7779
}
7880
)
7981
),
82+
(
83+
checkbox(Checked, Spawn((Text::new("Simulate traffic"), ThemedText))),
84+
observe(checkbox_self_update),
85+
observe(
86+
|change: On<ValueChange<bool>>, mut settings: ResMut<Settings>| {
87+
settings.traffic_enabled = change.value;
88+
}
89+
)
90+
),
8091
(
8192
checkbox(
8293
Checked,

examples/large_scenes/bevy_city/src/traffic.rs

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use bevy::{prelude::*, scene::SceneInstanceReady};
22

3+
use crate::settings::Settings;
4+
35
pub const RED_DURATION: f32 = 5.0;
46
pub const YELLOW_DURATION: f32 = 2.0;
57
pub const GREEN_DURATION: f32 = 5.0;
@@ -36,7 +38,7 @@ impl TrafficLight {
3638
}
3739
}
3840

39-
// Component/material for bulb
41+
// Component for each bulb on a traffic light, which is updated based on light's current phase
4042
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4143
pub enum TrafficLightColor {
4244
Red,
@@ -134,34 +136,34 @@ fn on_traffic_light_scene_ready(
134136
});
135137
}
136138
}
137-
138139
fn update_bulb_materials(
139-
mut bulbs: Query<(Entity, &mut TrafficLightBulb)>,
140+
settings: Res<Settings>,
141+
mut bulbs: Query<(&mut TrafficLightBulb, &mut MeshMaterial3d<StandardMaterial>)>,
140142
traffic_lights: Query<&TrafficLight>,
141143
time: Res<Time>,
142144
materials: Res<TrafficLightMaterials>,
143-
mut commands: Commands,
144145
) {
146+
if !settings.traffic_enabled {
147+
return;
148+
}
145149
let elapsed = time.elapsed_secs();
146-
for (entity, mut bulb) in bulbs.iter_mut() {
147-
let Ok(light) = traffic_lights.get(bulb.light_entity) else {
148-
continue;
150+
for (mut bulb, mut material) in bulbs.iter_mut() {
151+
let Ok(light) = traffic_lights.get(bulb.light_entity) else {
152+
continue;
153+
};
154+
let phase = light.phase(elapsed);
155+
if bulb.last_phase == Some(phase) {
156+
continue;
157+
}
158+
bulb.last_phase = Some(phase);
159+
material.0 = match (bulb.color, phase) {
160+
(TrafficLightColor::Red, TrafficLightPhase::Red) => materials.red_on.clone(),
161+
(TrafficLightColor::Red, _) => materials.red_off.clone(),
162+
(TrafficLightColor::Yellow, TrafficLightPhase::Yellow) => materials.yellow_on.clone(),
163+
(TrafficLightColor::Yellow, _) => materials.yellow_off.clone(),
164+
(TrafficLightColor::Green, TrafficLightPhase::Green) => materials.green_on.clone(),
165+
(TrafficLightColor::Green, _) => materials.green_off.clone(),
149166
};
150-
let phase = light.phase(elapsed);
151-
if bulb.last_phase == Some(phase) {
152-
continue;
153-
}
154-
bulb.last_phase = Some(phase);
155-
let handle = match (bulb.color, phase) {
156-
(TrafficLightColor::Red, TrafficLightPhase::Red) => &materials.red_on,
157-
(TrafficLightColor::Red, _) => &materials.red_off,
158-
(TrafficLightColor::Yellow, TrafficLightPhase::Yellow) => &materials.yellow_on,
159-
(TrafficLightColor::Yellow, _) => &materials.yellow_off,
160-
(TrafficLightColor::Green, TrafficLightPhase::Green) => &materials.green_on,
161-
(TrafficLightColor::Green, _) => &materials.green_off,
162-
};
163-
commands
164-
.entity(entity)
165-
.insert(MeshMaterial3d(handle.clone()));
166167
}
167168
}
169+

0 commit comments

Comments
 (0)