1use audio_code::prelude::*;
10
11const MAP: &str = "
12 ####################
13 #P.......#........G#
14 #........#.........#
15 #...######...####..#
16 #..................#
17 #..T...........#...#
18 ####################
19";
20
21struct Town {
22 car: BodyId,
23 truck: BodyId,
24 driving: BodyId,
25 garage: BodyId,
26}
27
28impl Town {
29 fn new(ctx: &mut Context) -> Self {
30 let engine = Synth::saw(55.0).length(1.0).attack(0.0).release(0.0).volume(0.25)
32 .with(Synth::square(110.0).length(1.0).attack(0.0).release(0.0).volume(0.08));
33 ctx.audio.register("engine", engine);
34 ctx.audio.register("horn", Synth::square(415.0).length(0.5).volume(0.25).with(Synth::square(523.0).length(0.5).volume(0.2)));
35 ctx.audio.register("shift", Synth::noise().length(0.04).decay(90.0).volume(0.3));
36 ctx.audio.register("crash", Synth::noise().length(0.4).decay(10.0).volume(0.8).with(Synth::sine(80.0).sweep_to(30.0).length(0.3)));
37 ctx.audio.register("start", Synth::saw(40.0).sweep_to(55.0).length(0.6).volume(0.3));
38 ctx.audio.register("garage", Synth::sine(880.0).length(0.15).decay(10.0));
39
40 let level = ctx.physics.build_level(MAP, 6.0);
41 let sounds = |v: Vehicle| {
42 v.with_engine_sound("engine")
43 .with_horn_sound("horn")
44 .with_shift_sound("shift")
45 .with_crash_sound("crash")
46 .with_start_sound("start")
47 };
48 let car_start = level.point('P').unwrap_or(Vec3::ZERO);
49 let car = ctx.physics.add(Body::car(car_start).with_facing(90.0).with_vehicle(sounds(Vehicle::car().with_fuel(5.0, 8.0))));
50 let truck_start = level.point('T').unwrap_or(Vec3::ZERO);
51 let truck = ctx.physics.add(
52 Body::truck(truck_start).with_facing(90.0).with_vehicle(sounds(Vehicle::truck()).engine_off()),
53 );
54 let garage_at = level.point('G').unwrap_or(Vec3::ZERO);
55 let garage = ctx.physics.add(Body::sensor(garage_at).with_box(6.0, 6.0, 3.0).with_tag("garage"));
56 ctx.loop_on(garage, "garage");
57 ctx.follow(car);
58 Self { car, truck, driving: car, garage }
59 }
60
61 fn name(&self) -> &'static str {
62 if self.driving == self.car { "car" } else { "truck" }
63 }
64}
65
66impl Scene for Town {
67 fn start(&mut self, ctx: &mut Context) {
68 ctx.speak("You sit in the car. Up drives, down brakes. Drive to the garage in the north east. F1 for help.");
69 }
70
71 fn update(&mut self, ctx: &mut Context) {
72 let id = self.driving;
73 ctx.drive(id);
74
75 if ctx.pressed(Key::H) {
76 ctx.horn(id);
77 }
78 if ctx.pressed(Key::E) {
79 let running = ctx.physics.vehicle(id).is_some_and(|v| v.is_engine_on());
80 if running {
81 ctx.stop_engine(id);
82 ctx.speak("Engine off");
83 } else if !ctx.start_engine(id) {
84 ctx.speak("The tank is empty");
85 }
86 }
87 if ctx.pressed(Key::Tab) {
88 if let Some(v) = ctx.physics.vehicle_mut(id) {
89 v.throttle = 0.0;
90 v.brake = 0.0;
91 v.handbrake = true;
92 }
93 self.driving = if id == self.car { self.truck } else { self.car };
94 ctx.follow(self.driving);
95 let text = format!("You switch to the {}. E starts the engine.", self.name());
96 ctx.speak(text);
97 }
98 if ctx.pressed(Key::L) && self.driving == self.truck {
99 let speed = ctx.physics.vehicle(self.truck).map_or(0.0, |v| v.speed().abs());
100 if speed > 0.5 {
101 ctx.speak("Stop first");
102 } else if let Some(v) = ctx.physics.vehicle_mut(self.truck) {
103 let load = if v.load > 0.0 { 0.0 } else { v.max_load };
104 v.set_load(load);
105 let text = format!("Load {} tons, total weight {} tons", load / 1000.0, ctx.physics.weight(self.truck) / 1000.0);
106 ctx.speak(text);
107 }
108 }
109 if ctx.pressed(Key::F)
110 && let Some(v) = ctx.physics.vehicle(id)
111 {
112 let mut text = format!("{}, gear {}", v.describe_speed(), v.gear_name());
113 if let Some(fuel) = v.fuel() {
114 text.push_str(&format!(", {fuel:.1} liters left"));
115 }
116 ctx.speak(text);
117 }
118 if ctx.pressed(Key::G) {
119 let text = ctx.physics.describe(id, self.garage);
120 ctx.speak(text);
121 }
122 if ctx.pressed(Key::F1) {
123 ctx.speak("Up gas, down brake and reverse, left and right steer, space handbrake, H horn, E engine, Tab switch vehicle, L load the truck, F speed, G garage.");
124 }
125
126 if let Some(gear) = ctx.physics.gear_changed(id)
127 && gear == -1
128 {
129 ctx.speak("Reverse");
130 }
131 if let Some((_, speed)) = ctx.physics.crashed(id)
132 && speed > 5.0
133 {
134 let text = format!("Crash at {:.0} kilometers per hour", speed * 3.6);
135 ctx.speak(text);
136 }
137 if ctx.physics.entered_tag(id, "garage").is_some() {
138 let text = format!("You parked the {} in the garage. Well done!", self.name());
139 ctx.speak(text);
140 ctx.quit();
141 }
142 if ctx.pressed(Key::Escape) {
143 ctx.quit();
144 }
145 }
146}
147
148fn main() -> audio_code::Result<()> {
149 Engine::new("Driving").run_with(Town::new)
150}