diff --git a/_posts/2015-10-30-arcaders-1-9.md b/_posts/2015-10-30-arcaders-1-9.md index 63983d8..a708b65 100644 --- a/_posts/2015-10-30-arcaders-1-9.md +++ b/_posts/2015-10-30-arcaders-1-9.md @@ -182,7 +182,7 @@ impl<'window> Phi<'window> { } ``` -Notice how we used both `and_then` and `render` in this example. Both take in an +Notice how we used both `and_then` and `map` in this example. Both take in an option as `self`, and a closure. If the option is `Some(value)`, then they call the function with the given value; otherwise, they return `None` without further computation. diff --git a/_posts/2015-12-08-arcaders-1-10.md b/_posts/2015-12-08-arcaders-1-10.md index 719f6c7..44a7af1 100644 --- a/_posts/2015-12-08-arcaders-1-10.md +++ b/_posts/2015-12-08-arcaders-1-10.md @@ -183,7 +183,7 @@ definition so that `Sprite` is now `Renderable`: ```rust pub trait CopySprite { - fn copy_sprite(&mut self, sprite: &Renderable, dest: Rectangle); + fn copy_sprite(&mut self, renderable: &Renderable, dest: Rectangle); } impl<'window> CopySprite for Renderer<'window> { @@ -194,7 +194,7 @@ impl<'window> CopySprite for Renderer<'window> { ``` This is a valid approach, but remember that trait objects have a (here mostly -negligeable) runtime cost. We could instead add a type parameter to `CopySprite`: +negligible) runtime cost. We could instead add a type parameter to `CopySprite`: ```rust pub trait CopySprite { @@ -436,21 +436,20 @@ impl Asteroid { fn reset(&mut self, phi: &mut Phi) { let (w, h) = phi.output_size(); - // FPS in [10.0, 30.0) + // FPS in [10.0, 30.0] //? `random()` returns a value between 0 and 1. - //? `abs()` returns an absolute value - self.sprite.set_fps(::rand::random::().abs() * 20.0 + 10.0); + self.sprite.set_fps(::rand::random::() * 20.0 + 10.0); // rect.y in the screen vertically self.rect = Rectangle { w: ASTEROID_SIDE, h: ASTEROID_SIDE, x: w, - y: ::rand::random::().abs() * (h - ASTEROID_SIDE), + y: ::rand::random::() * (h - ASTEROID_SIDE), }; - // vel in [50.0, 150.0) - self.vel = ::rand::random::().abs() * 100.0 + 50.0; + // vel in [50.0, 150.0] + self.vel = ::rand::random::() * 100.0 + 50.0; } fn get_sprite(phi: &mut Phi, fps: f64) -> AnimatedSprite { @@ -516,9 +515,17 @@ else's noses. The change is pretty simple and does not affect any other part of the code. In fact, because an `Rc` _automatically derefs to a reference_, that is, it behaves as though it were a reference whenever the context requires it, the change only -takes one line: +takes a couple lines: ```rust +#[derive(Clone)] +pub struct AnimatedSprite { + /// The frames that will be rendered, in order. + sprites: Rc>, + + //? ... +} + impl AnimatedSprite { /// Creates a new animated sprite initialized at time 0. pub fn new(sprites: Vec, frame_delay: f64) -> AnimatedSprite { diff --git a/_posts/2016-01-03-arcaders-1-11.md b/_posts/2016-01-03-arcaders-1-11.md index bf1f754..59b8bcd 100644 --- a/_posts/2016-01-03-arcaders-1-11.md +++ b/_posts/2016-01-03-arcaders-1-11.md @@ -19,8 +19,8 @@ create a bunch of somewhat-interesting bullets. The first step in designing the default bullet will be to define the attributes that compose it. In this case, it's pretty simple: all bullets will have the -same velocity, so there is no need to store it every one; we only need to know -its bounding box. +same velocity, so there is no need to store it in every one of them; we only +need to know its bounding box. ```rust //? The velocity shared by all bullets, in pixels per second. @@ -49,7 +49,7 @@ impl RectBullet { /// Update the bullet. /// If the bullet should be destroyed, e.g. because it has left the screen, /// then return `None`. - /// Otherwise, return `Some(update_bullet)`. + /// Otherwise, return `Some(updated_bullet)`. fn update(mut self, phi: &mut Phi, dt: f64) -> Option { let (w, _) = phi.output_size(); self.rect.x += BULLET_SPEED * dt; @@ -198,7 +198,7 @@ Here's how it looks: ![The ship shooting bullets in straight lines](/images/arcade-16.png) -I would like to direct your intention to two things. First, consider the way in +I would like to direct your attention to two things. First, consider the way in which we iterate over the bullets to render them: ```rust diff --git a/_posts/2016-01-16-arcaders-1-12.md b/_posts/2016-01-16-arcaders-1-12.md index 7029f17..33b6726 100644 --- a/_posts/2016-01-16-arcaders-1-12.md +++ b/_posts/2016-01-16-arcaders-1-12.md @@ -240,9 +240,9 @@ impl AsteroidFactory { fn random(&self, phi: &mut Phi) -> Asteroid { let (w, h) = phi.output_size(); - // FPS in [10.0, 30.0) - let sprite = self.sprite.clone(); - sprite.set_fps(::rand::random::().abs() * 20.0 + 10.0); + // FPS in [10.0, 30.0] + let mut sprite = self.sprite.clone(); + sprite.set_fps(::rand::random::() * 20.0 + 10.0); Asteroid { sprite: sprite, @@ -253,11 +253,11 @@ impl AsteroidFactory { w: ASTEROID_SIDE, h: ASTEROID_SIDE, x: w, - y: ::rand::random::().abs() * (h - ASTEROID_SIDE), + y: ::rand::random::() * (h - ASTEROID_SIDE), }, - // vel in [50.0, 150.0) - vel: ::rand::random::().abs() * 100.0 + 50.0, + // vel in [50.0, 150.0] + vel: ::rand::random::() * 100.0 + 50.0, } } } @@ -267,6 +267,32 @@ Now, all we have to do is to add it to our view and use it, say, just after we create the bullets shot by the player. ```rust +pub struct GameView { + player: Ship, + bullets: Vec>, + asteroids: Vec, + asteroid_factory: AsteroidFactory, + bg: BgSet, +} + +impl GameView { + //? ... + + pub fn with_backgrounds(phi: &mut Phi, bg: BgSet) -> GameView { + //? ... + + GameView { + //? ... + + bullets: vec![], + asteroids: vec![], + asteroid_factory: Asteroid::factory(phi), + + //? ... + } + } +} + impl View for GameView { fn render() { //? ... @@ -486,7 +512,7 @@ if phi.events.now.key_space == Some(true) { ![Bullets are destroyed upon impact and spawn randomly](/images/arcade-19.png) -You should now be able to destroy asteroids with you bullets. The only problem +You should now be able to destroy asteroids with your bullets. The only problem is that, well, it's not very impressive. Fortunately, as Michael Bay has taught us, when something is boring, you just gotta add explosions to it. Let's do that right now! @@ -522,7 +548,7 @@ we create an explosion, we will use the same technique. This time, however, we will not position the explosion depending on the size of the window, but instead we will say that its center is the same as that of the asteroid. This might seem a bit overkill, considering that explosions and asteroids have the same size, -but this approach can be easily extends to more enemies. +but this approach can be easily extended to more enemies. Here's how we might implement the factory: @@ -531,7 +557,7 @@ struct Explosion { sprite: AnimatedSprite, rect: Rectangle, - //? Keep how long its been arrived, so that we destroy the explosion once + //? Keep how long it's been alive, so that we destroy the explosion once //? its animation is finished. alive_since: f64, } @@ -574,7 +600,7 @@ struct ExplosionFactory { impl ExplosionFactory { fn at_center(&self, center: (f64, f64)) -> Explosion { - //? ... + //? TODO } } ``` @@ -587,6 +613,10 @@ functionality of our `phi` library. In `phi/gfx.rs`, insert the following: ```rust +use phi::Phi; + +//? ... + /// A bunch of options for loading the frames of an animation from a spritesheet /// stored at `image_path`. //? You might notice the lifetime annotation. As always, this means: the file's @@ -719,8 +749,7 @@ explosion factory, we must tell it how to generate an instance: ```rust impl ExplosionFactory { fn at_center(&self, center: (f64, f64)) -> Explosion { - // FPS in [10.0, 30.0) - let mut sprite = self.sprite.clone(); + let sprite = self.sprite.clone(); Explosion { sprite: sprite, @@ -953,6 +982,15 @@ impl Player { } } + //? Make sure to reflect the constant name change here. + fn spawn_bullets(&self) -> Vec> { + let cannons_x = self.rect.x + 30.0; + let cannon1_y = self.rect.y + 6.0; + let cannon2_y = self.rect.y + PLAYER_H - 10.0; + + //? ... + } + //? ... } ``` @@ -960,7 +998,7 @@ impl Player { Then, add an `update` method that takes care of event handling: ```rust -impl Ship { +impl Player { //? ... pub fn update(&mut self, phi: &mut Phi, elapsed: f64) { @@ -1027,15 +1065,15 @@ impl Ship { // Select the appropriate sprite of the ship to show. self.current = - if dx == 0.0 && dy < 0.0 { ShipFrame::UpNorm } - else if dx > 0.0 && dy < 0.0 { ShipFrame::UpFast } - else if dx < 0.0 && dy < 0.0 { ShipFrame::UpSlow } - else if dx == 0.0 && dy == 0.0 { ShipFrame::MidNorm } - else if dx > 0.0 && dy == 0.0 { ShipFrame::MidFast } - else if dx < 0.0 && dy == 0.0 { ShipFrame::MidSlow } - else if dx == 0.0 && dy > 0.0 { ShipFrame::DownNorm } - else if dx > 0.0 && dy > 0.0 { ShipFrame::DownFast } - else if dx < 0.0 && dy > 0.0 { ShipFrame::DownSlow } + if dx == 0.0 && dy < 0.0 { PlayerFrame::UpNorm } + else if dx > 0.0 && dy < 0.0 { PlayerFrame::UpFast } + else if dx < 0.0 && dy < 0.0 { PlayerFrame::UpSlow } + else if dx == 0.0 && dy == 0.0 { PlayerFrame::MidNorm } + else if dx > 0.0 && dy == 0.0 { PlayerFrame::MidFast } + else if dx < 0.0 && dy == 0.0 { PlayerFrame::MidSlow } + else if dx == 0.0 && dy > 0.0 { PlayerFrame::DownNorm } + else if dx > 0.0 && dy > 0.0 { PlayerFrame::DownFast } + else if dx < 0.0 && dy > 0.0 { PlayerFrame::DownSlow } else { unreachable!() }; } } diff --git a/_posts/2016-03-22-arcaders-1-13.md b/_posts/2016-03-22-arcaders-1-13.md index 18261ca..ed525bf 100644 --- a/_posts/2016-03-22-arcaders-1-13.md +++ b/_posts/2016-03-22-arcaders-1-13.md @@ -2,7 +2,7 @@ layout: series_arcaders title: "ArcadeRS 1.13: « Boom! »" categories: arcaders -nth: "twelfth" +nth: "thirteenth" --- In the previous article, we finally allowed our player to fight its foes: a @@ -14,8 +14,8 @@ least _sounds_ intense. Then, we'll make our API more _functional_ and learn what the compiler _cannot_ do (because, y'know, it can't always be all rainbows and unicorns! For now at -least. Don't worry, well nail that one day... hopefully... eh, let's just start -already...) +least. Don't worry, we'll nail that one day... hopefully... eh, let's just +start already...) ## The last dependency diff --git a/code/arcaders-1-10/src/phi/data.rs b/code/arcaders-1-10/src/phi/data.rs index a3dc8e0..6c95737 100644 --- a/code/arcaders-1-10/src/phi/data.rs +++ b/code/arcaders-1-10/src/phi/data.rs @@ -18,7 +18,7 @@ impl Rectangle { assert!(self.w >= 0.0 && self.h >= 0.0); // SdlRect::new : `(i32, i32, u32, u32) -> Result>` - // Will panic if the width of the height is negative. + // Will panic if the width or the height is negative. SdlRect::new(self.x as i32, self.y as i32, self.w as u32, self.h as u32) .unwrap() } diff --git a/code/arcaders-1-10/src/views/game.rs b/code/arcaders-1-10/src/views/game.rs index b11261c..986761a 100644 --- a/code/arcaders-1-10/src/views/game.rs +++ b/code/arcaders-1-10/src/views/game.rs @@ -71,19 +71,19 @@ impl Asteroid { fn reset(&mut self, phi: &mut Phi) { let (w, h) = phi.output_size(); - // FPS in [10.0, 30.0) - self.sprite.set_fps(::rand::random::().abs() * 20.0 + 10.0); + // FPS in [10.0, 30.0] + self.sprite.set_fps(::rand::random::() * 20.0 + 10.0); // rect.y in the screen vertically self.rect = Rectangle { w: ASTEROID_SIDE, h: ASTEROID_SIDE, x: w, - y: ::rand::random::().abs() * (h - ASTEROID_SIDE), + y: ::rand::random::() * (h - ASTEROID_SIDE), }; - // vel in [50.0, 150.0) - self.vel = ::rand::random::().abs() * 100.0 + 50.0; + // vel in [50.0, 150.0] + self.vel = ::rand::random::() * 100.0 + 50.0; } fn get_sprite(phi: &mut Phi, fps: f64) -> AnimatedSprite { diff --git a/code/arcaders-1-11/src/phi/data.rs b/code/arcaders-1-11/src/phi/data.rs index a3dc8e0..6c95737 100644 --- a/code/arcaders-1-11/src/phi/data.rs +++ b/code/arcaders-1-11/src/phi/data.rs @@ -18,7 +18,7 @@ impl Rectangle { assert!(self.w >= 0.0 && self.h >= 0.0); // SdlRect::new : `(i32, i32, u32, u32) -> Result>` - // Will panic if the width of the height is negative. + // Will panic if the width or the height is negative. SdlRect::new(self.x as i32, self.y as i32, self.w as u32, self.h as u32) .unwrap() } diff --git a/code/arcaders-1-11/src/views/game.rs b/code/arcaders-1-11/src/views/game.rs index 2c77e90..5a543d3 100644 --- a/code/arcaders-1-11/src/views/game.rs +++ b/code/arcaders-1-11/src/views/game.rs @@ -298,19 +298,19 @@ impl Asteroid { fn reset(&mut self, phi: &mut Phi) { let (w, h) = phi.output_size(); - // FPS in [10.0, 30.0) - self.sprite.set_fps(::rand::random::().abs() * 20.0 + 10.0); + // FPS in [10.0, 30.0] + self.sprite.set_fps(::rand::random::() * 20.0 + 10.0); // rect.y in the screen vertically self.rect = Rectangle { w: ASTEROID_SIDE, h: ASTEROID_SIDE, x: w, - y: ::rand::random::().abs() * (h - ASTEROID_SIDE), + y: ::rand::random::() * (h - ASTEROID_SIDE), }; - // vel in [50.0, 150.0) - self.vel = ::rand::random::().abs() * 100.0 + 50.0; + // vel in [50.0, 150.0] + self.vel = ::rand::random::() * 100.0 + 50.0; } fn get_sprite(phi: &mut Phi, fps: f64) -> AnimatedSprite { diff --git a/code/arcaders-1-12-preclean/src/phi/data.rs b/code/arcaders-1-12-preclean/src/phi/data.rs index 2728de6..93becde 100644 --- a/code/arcaders-1-12-preclean/src/phi/data.rs +++ b/code/arcaders-1-12-preclean/src/phi/data.rs @@ -18,7 +18,7 @@ impl Rectangle { assert!(self.w >= 0.0 && self.h >= 0.0); // SdlRect::new : `(i32, i32, u32, u32) -> Result>` - // Will panic if the width of the height is negative. + // Will panic if the width or the height is negative. SdlRect::new(self.x as i32, self.y as i32, self.w as u32, self.h as u32) .unwrap() } diff --git a/code/arcaders-1-12-preclean/src/views/game.rs b/code/arcaders-1-12-preclean/src/views/game.rs index 85d974c..dadb414 100644 --- a/code/arcaders-1-12-preclean/src/views/game.rs +++ b/code/arcaders-1-12-preclean/src/views/game.rs @@ -299,7 +299,7 @@ impl Asteroid { } } - fn update(mut self, phi: &mut Phi, dt: f64) -> Option { + fn update(mut self, dt: f64) -> Option { self.rect.x -= dt * self.vel; self.sprite.add_time(dt); @@ -333,9 +333,9 @@ impl AsteroidFactory { fn random(&self, phi: &mut Phi) -> Asteroid { let (w, h) = phi.output_size(); - // FPS in [10.0, 30.0) + // FPS in [10.0, 30.0] let mut sprite = self.sprite.clone(); - sprite.set_fps(::rand::random::().abs() * 20.0 + 10.0); + sprite.set_fps(::rand::random::() * 20.0 + 10.0); Asteroid { sprite: sprite, @@ -346,11 +346,11 @@ impl AsteroidFactory { w: ASTEROID_SIDE, h: ASTEROID_SIDE, x: w, - y: ::rand::random::().abs() * (h - ASTEROID_SIDE), + y: ::rand::random::() * (h - ASTEROID_SIDE), }, - // vel in [50.0, 150.0) - vel: ::rand::random::().abs() * 100.0 + 50.0, + // vel in [50.0, 150.0] + vel: ::rand::random::() * 100.0 + 50.0, } } } @@ -579,7 +579,7 @@ impl View for GameView { self.asteroids = ::std::mem::replace(&mut self.asteroids, vec![]) .into_iter() - .filter_map(|asteroid| asteroid.update(phi, elapsed)) + .filter_map(|asteroid| asteroid.update(elapsed)) .collect(); // Update the explosions diff --git a/code/arcaders-1-12/src/phi/data.rs b/code/arcaders-1-12/src/phi/data.rs index 2728de6..93becde 100644 --- a/code/arcaders-1-12/src/phi/data.rs +++ b/code/arcaders-1-12/src/phi/data.rs @@ -18,7 +18,7 @@ impl Rectangle { assert!(self.w >= 0.0 && self.h >= 0.0); // SdlRect::new : `(i32, i32, u32, u32) -> Result>` - // Will panic if the width of the height is negative. + // Will panic if the width or the height is negative. SdlRect::new(self.x as i32, self.y as i32, self.w as u32, self.h as u32) .unwrap() } diff --git a/code/arcaders-1-12/src/views/game.rs b/code/arcaders-1-12/src/views/game.rs index e7e10ff..60e6a30 100644 --- a/code/arcaders-1-12/src/views/game.rs +++ b/code/arcaders-1-12/src/views/game.rs @@ -237,9 +237,9 @@ impl AsteroidFactory { fn random(&self, phi: &mut Phi) -> Asteroid { let (w, h) = phi.output_size(); - // FPS in [10.0, 30.0) + // FPS in [10.0, 30.0] let mut sprite = self.sprite.clone(); - sprite.set_fps(::rand::random::().abs() * 20.0 + 10.0); + sprite.set_fps(::rand::random::() * 20.0 + 10.0); Asteroid { sprite: sprite, @@ -250,11 +250,11 @@ impl AsteroidFactory { w: ASTEROID_SIDE, h: ASTEROID_SIDE, x: w, - y: ::rand::random::().abs() * (h - ASTEROID_SIDE), + y: ::rand::random::() * (h - ASTEROID_SIDE), }, - // vel in [50.0, 150.0) - vel: ::rand::random::().abs() * 100.0 + 50.0, + // vel in [50.0, 150.0] + vel: ::rand::random::() * 100.0 + 50.0, } } } diff --git a/code/arcaders-1-13/src/phi/data.rs b/code/arcaders-1-13/src/phi/data.rs index 2728de6..93becde 100644 --- a/code/arcaders-1-13/src/phi/data.rs +++ b/code/arcaders-1-13/src/phi/data.rs @@ -18,7 +18,7 @@ impl Rectangle { assert!(self.w >= 0.0 && self.h >= 0.0); // SdlRect::new : `(i32, i32, u32, u32) -> Result>` - // Will panic if the width of the height is negative. + // Will panic if the width or the height is negative. SdlRect::new(self.x as i32, self.y as i32, self.w as u32, self.h as u32) .unwrap() } diff --git a/code/arcaders-1-13/src/views/game.rs b/code/arcaders-1-13/src/views/game.rs index 1204856..1609e86 100644 --- a/code/arcaders-1-13/src/views/game.rs +++ b/code/arcaders-1-13/src/views/game.rs @@ -239,9 +239,9 @@ impl AsteroidFactory { fn random(&self, phi: &mut Phi) -> Asteroid { let (w, h) = phi.output_size(); - // FPS in [10.0, 30.0) + // FPS in [10.0, 30.0] let mut sprite = self.sprite.clone(); - sprite.set_fps(::rand::random::().abs() * 20.0 + 10.0); + sprite.set_fps(::rand::random::() * 20.0 + 10.0); Asteroid { sprite: sprite, @@ -252,11 +252,11 @@ impl AsteroidFactory { w: ASTEROID_SIDE, h: ASTEROID_SIDE, x: w, - y: ::rand::random::().abs() * (h - ASTEROID_SIDE), + y: ::rand::random::() * (h - ASTEROID_SIDE), }, - // vel in [50.0, 150.0) - vel: ::rand::random::().abs() * 100.0 + 50.0, + // vel in [50.0, 150.0] + vel: ::rand::random::() * 100.0 + 50.0, } } } diff --git a/code/arcaders-1-7/src/phi/data.rs b/code/arcaders-1-7/src/phi/data.rs index a3dc8e0..6c95737 100644 --- a/code/arcaders-1-7/src/phi/data.rs +++ b/code/arcaders-1-7/src/phi/data.rs @@ -18,7 +18,7 @@ impl Rectangle { assert!(self.w >= 0.0 && self.h >= 0.0); // SdlRect::new : `(i32, i32, u32, u32) -> Result>` - // Will panic if the width of the height is negative. + // Will panic if the width or the height is negative. SdlRect::new(self.x as i32, self.y as i32, self.w as u32, self.h as u32) .unwrap() } diff --git a/code/arcaders-1-8/src/phi/data.rs b/code/arcaders-1-8/src/phi/data.rs index a3dc8e0..6c95737 100644 --- a/code/arcaders-1-8/src/phi/data.rs +++ b/code/arcaders-1-8/src/phi/data.rs @@ -18,7 +18,7 @@ impl Rectangle { assert!(self.w >= 0.0 && self.h >= 0.0); // SdlRect::new : `(i32, i32, u32, u32) -> Result>` - // Will panic if the width of the height is negative. + // Will panic if the width or the height is negative. SdlRect::new(self.x as i32, self.y as i32, self.w as u32, self.h as u32) .unwrap() } diff --git a/code/arcaders-1-9/src/phi/data.rs b/code/arcaders-1-9/src/phi/data.rs index a3dc8e0..6c95737 100644 --- a/code/arcaders-1-9/src/phi/data.rs +++ b/code/arcaders-1-9/src/phi/data.rs @@ -18,7 +18,7 @@ impl Rectangle { assert!(self.w >= 0.0 && self.h >= 0.0); // SdlRect::new : `(i32, i32, u32, u32) -> Result>` - // Will panic if the width of the height is negative. + // Will panic if the width or the height is negative. SdlRect::new(self.x as i32, self.y as i32, self.w as u32, self.h as u32) .unwrap() }