pub const fn vec3(x: f32, y: f32, z: f32) -> Vec3Expand description
Creates a 3-dimensional vector.
Examples found in repository?
examples/bell_catcher.rs (line 176)
175 fn bell_position(&self) -> Vec3 {
176 vec3((self.bell_lane - self.lane) as f32 * LANE_WIDTH, 2.0, 0.0)
177 }
178
179 fn ring(&mut self, ctx: &mut Context) {
180 // 0.0 when the bell starts falling, 1.0 when it lands.
181 let progress = 1.0 - self.left / self.fall;
182 let position = self.bell_position();
183 ctx.audio.sound("bell").at(position).pitch(1.0 + progress * 0.6).play();
184 self.next_ring = 0.12 + 0.45 * (1.0 - progress);
185 }
186
187 fn land(&mut self, ctx: &mut Context) {
188 if self.lane == self.bell_lane {
189 self.score += 1;
190 self.fall = (self.fall * 0.93).max(FASTEST_FALL);
191 ctx.play("catch");
192 if self.score.is_multiple_of(5) {
193 ctx.speak(format!("{} bells!", self.score));
194 }
195 } else {
196 self.lives -= 1;
197 ctx.play("miss");
198 match self.lives {
199 0 => return self.game_over(ctx),
200 1 => ctx.speak("Missed! Last life."),
201 n => ctx.speak(format!("Missed! {n} lives left.")),
202 }
203 }
204 // A short break before the next bell.
205 self.left = -0.8;
206 }
207
208 fn game_over(&mut self, ctx: &mut Context) {
209 self.over = true;
210 let best: u32 = ctx.storage.get_or("best", 0);
211 let text = if self.score > best {
212 ctx.storage.set("best", self.score);
213 format!("Game over. {} bells, a new best score!", self.score)
214 } else {
215 format!("Game over. {} bells. Your best is {best}.", self.score)
216 };
217 ctx.ui.message("over", text);
218 }
219}
220
221impl Scene for Game {
222 fn start(&mut self, ctx: &mut Context) {
223 ctx.speak("Catch the bells! Left and right to move.");
224 // Give the player a moment to listen to the first bell.
225 self.left = -1.5;
226 }
227
228 fn update(&mut self, ctx: &mut Context) {
229 if self.over {
230 if ctx.ui.closed("over") {
231 ctx.switch_scene(Title);
232 }
233 return;
234 }
235 if ctx.pressed(Key::Escape) {
236 ctx.switch_scene(Title);
237 return;
238 }
239 if ctx.pressed(Key::S) {
240 ctx.speak(format!("{} bells, {} lives", self.score, self.lives));
241 }
242 for (key, step) in [(Key::Left, -1), (Key::Right, 1)] {
243 if ctx.input.repeating(key, 0.3, 0.15) {
244 let lane = (self.lane + step).clamp(-LANES, LANES);
245 if lane == self.lane {
246 ctx.play("edge");
247 } else {
248 self.lane = lane;
249 ctx.audio.sound("step").at(vec3(step as f32 * 0.5, 0.0, 0.0)).random_pitch(0.9, 1.1).play();
250 }
251 }
252 }
253
254 let dt = ctx.time.delta();
255 if self.left < 0.0 {
256 self.left += dt;
257 if self.left >= 0.0 {
258 self.drop_bell();
259 }
260 return;
261 }
262 self.left -= dt;
263 self.next_ring -= dt;
264 if self.left <= 0.0 {
265 self.land(ctx);
266 } else if self.next_ring <= 0.0 {
267 self.ring(ctx);
268 }
269 }More examples
examples/flight.rs (line 17)
16const BIRDS: [Vec3; 4] = [
17 vec3(10.0, 15.0, 8.0), // high up in the north east
18 vec3(-12.0, 5.0, 1.0), // just above the floor in the west
19 vec3(0.0, -14.0, 14.0), // under the roof in the south
20 vec3(14.0, -10.0, 4.0),
21];
22
23struct Flight {
24 drone: BodyId,
25 birds: usize,
26 /// Whether the last move was blocked, so the bump plays once and not every frame.
27 blocked: bool,
28}
29
30impl Flight {
31 fn new(ctx: &mut Context) -> Self {
32 ctx.audio.register("bird", Synth::sine(2200.0).sweep_to(3200.0).length(0.07).then(Synth::silence(0.05)).then(Synth::sine(2600.0).length(0.06)).then(Synth::silence(0.7)));
33 ctx.audio.register("hum", Synth::saw(70.0).length(1.0).volume(0.08));
34 ctx.audio.register("bump", Synth::sine(80.0).length(0.15).decay(25.0).volume(0.8));
35 ctx.audio.register("found", Synth::triangle(660.0).sweep_to(1320.0).length(0.4).decay(6.0).volume(0.3));
36
37 // A hall of 40 x 40 meters and 16 meters high: floor, roof and four walls.
38 // A box is given by its center and its full width (x), depth (y) and height (z).
39 let physics = &mut ctx.physics;
40 physics.add(Body::fixed(vec3(0.0, 0.0, -0.5)).with_box(40.0, 40.0, 1.0).with_tag("floor"));
41 physics.add(Body::fixed(vec3(0.0, 0.0, 16.5)).with_box(40.0, 40.0, 1.0).with_tag("roof"));
42 physics.add(Body::fixed(vec3(0.0, 20.5, 8.0)).with_box(40.0, 1.0, 16.0).with_tag("north wall"));
43 physics.add(Body::fixed(vec3(0.0, -20.5, 8.0)).with_box(40.0, 1.0, 16.0).with_tag("south wall"));
44 physics.add(Body::fixed(vec3(20.5, 0.0, 8.0)).with_box(1.0, 40.0, 16.0).with_tag("east wall"));
45 physics.add(Body::fixed(vec3(-20.5, 0.0, 8.0)).with_box(1.0, 40.0, 16.0).with_tag("west wall"));
46
47 // The drone starts in the middle, 2 meters above the floor. No gravity: it hovers.
48 let drone = ctx.physics.add(Body::kinematic(vec3(0.0, 0.0, 2.0)).with_sphere(0.5).with_tag("drone"));
49 ctx.follow(drone); // the ears use the drone's position, facing and pitch
50 ctx.audio.play_looped("hum");
51
52 for spot in BIRDS {
53 let bird = ctx.physics.add(Body::sensor(spot).with_sphere(1.0).with_tag("bird"));
54 ctx.loop_on(bird, "bird");
55 }
56 Self { drone, birds: BIRDS.len(), blocked: false }
57 }examples/platformer.rs (line 29)
19 fn new(ctx: &mut Context) -> Self {
20 let audio = &mut ctx.audio;
21 audio.register("jump", Synth::square(300.0).sweep_to(700.0).length(0.15).decay(10.0).volume(0.2));
22 audio.register("land", Synth::noise().length(0.1).decay(40.0).with(Synth::sine(90.0).length(0.1).decay(30.0)));
23 audio.register("coin", Synth::triangle(988.0).length(0.08).then(Synth::triangle(1319.0).length(0.17).decay(15.0)));
24 audio.register("run", Synth::noise().length(0.06).decay(60.0).volume(0.3).then(Synth::silence(0.09)));
25 audio.register("lift", Synth::saw(55.0).length(1.0).volume(0.1));
26 audio.register("push", Synth::noise().length(0.3).volume(0.15));
27
28 let physics = &mut ctx.physics;
29 physics.add(Body::fixed(vec3(0.0, 0.0, -0.5)).with_box(200.0, 4.0, 1.0).with_tag("ground"));
30 for (x, z) in [(8.0, 2.0), (14.0, 4.0), (20.0, 2.5)] {
31 physics.add(Body::fixed(vec3(x, 0.0, z)).with_box(4.0, 4.0, 0.5).with_tag("platform"));
32 }
33 // A lift going up and down at x = 40, and a heavy crate at x = 30.
34 let lift = physics.add(Body::kinematic(vec3(40.0, 0.0, 0.0)).with_box(3.0, 4.0, 0.5).with_tag("lift"));
35 physics.add(Body::dynamic(vec3(30.0, 0.0, 0.5)).with_box(1.0, 1.0, 1.0).with_mass(5.0).with_tag("crate"));
36 // Facing north, so x maps to left and right in the ears.
37 let player = physics
38 .add(Body::dynamic(vec3(0.0, 0.0, 1.0)).with_box(0.8, 0.8, 1.6).with_max_speed(25.0).with_tag("player"));
39
40 ctx.follow(player);
41 ctx.loop_on(lift, "lift");
42 // Coins are sensors with a looping sound, so you can hear where they are.
43 for (x, z) in [(5.0, 1.0), (14.0, 5.5), (25.0, 1.0), (40.0, 8.0)] {
44 let coin = ctx.physics.add(Body::sensor(vec3(x, 0.0, z)).with_sphere(0.6).with_tag("coin"));
45 ctx.loop_on(coin, "coin").set_volume(0.3);
46 }
47
48 let run_sound = ctx.audio.sound("run").looped().volume(0.0).play();
49 Self { player, lift, run_sound, score: 0 }
50 }
51}
52
53impl Scene for Platformer {
54 fn start(&mut self, ctx: &mut Context) {
55 ctx.speak("Collect the coins. Left and right to run, space to jump, S for score, escape to quit.");
56 }
57
58 fn update(&mut self, ctx: &mut Context) {
59 if ctx.pressed(Key::Escape) {
60 ctx.quit();
61 }
62
63 // The lift goes up for 4 seconds and down for 4 seconds.
64 let lift_up = (ctx.time.elapsed() % 8.0) < 4.0;
65 ctx.physics.set_velocity(self.lift, vec3(0.0, 0.0, if lift_up { 2.0 } else { -2.0 }));
66
67 let run = ctx.input.axis(Key::Left, Key::Right);
68 let mut velocity = ctx.physics.velocity(self.player);
69 velocity.x = run * 6.0;
70 ctx.physics.set_velocity(self.player, velocity);
71 if ctx.pressed(Key::Space) && ctx.physics.jump(self.player, 2.5) {
72 ctx.play("jump");
73 }
74 let running = ctx.physics.on_ground(self.player) && run != 0.0;
75 self.run_sound.set_volume(if running { 0.6 } else { 0.0 });
76
77 if let Some(speed) = ctx.physics.landed(self.player) {
78 ctx.audio.sound("land").volume((speed / 12.0).clamp(0.2, 1.0)).play();
79 if speed > 15.0 {
80 ctx.speak("Ouch!");
81 }
82 }
83 if let Some((other, _)) = ctx.physics.collided(self.player)
84 && ctx.physics.tag(other) == "crate"
85 {
86 ctx.play_on(other, "push");
87 }
88 if let Some(coin) = ctx.physics.entered_tag(self.player, "coin") {
89 ctx.physics.remove(coin); // its looping sound stops by itself
90 self.score += 1;
91 ctx.audio.sound("coin").pitch(1.5).play();
92 ctx.speak(format!("{} of {COINS} coins", self.score));
93 if self.score == COINS {
94 ctx.ui.message("won", "You collected every coin! Press enter to quit.");
95 }
96 }
97 if ctx.ui.closed("won") {
98 ctx.quit();
99 }
100
101 if ctx.pressed(Key::S) {
102 let x = ctx.physics.position(self.player).x;
103 ctx.speak(format!("Score {}, position {x:.0}", self.score));
104 }
105 }