Skip to content

Commit

Permalink
ArcadeRS: Various fixes while going through the tutorials
Browse files Browse the repository at this point in the history
  • Loading branch information
akien-mga committed Nov 4, 2016
1 parent 4524803 commit 8fb2d61
Show file tree
Hide file tree
Showing 18 changed files with 119 additions and 74 deletions.
2 changes: 1 addition & 1 deletion _posts/2015-10-30-arcaders-1-9.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
25 changes: 16 additions & 9 deletions _posts/2015-12-08-arcaders-1-10.md
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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<T> {
Expand Down Expand Up @@ -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<f64>()` returns a value between 0 and 1.
//? `abs()` returns an absolute value
self.sprite.set_fps(::rand::random::<f64>().abs() * 20.0 + 10.0);
self.sprite.set_fps(::rand::random::<f64>() * 20.0 + 10.0);

// rect.y in the screen vertically
self.rect = Rectangle {
w: ASTEROID_SIDE,
h: ASTEROID_SIDE,
x: w,
y: ::rand::random::<f64>().abs() * (h - ASTEROID_SIDE),
y: ::rand::random::<f64>() * (h - ASTEROID_SIDE),
};

// vel in [50.0, 150.0)
self.vel = ::rand::random::<f64>().abs() * 100.0 + 50.0;
// vel in [50.0, 150.0]
self.vel = ::rand::random::<f64>() * 100.0 + 50.0;
}

fn get_sprite(phi: &mut Phi, fps: f64) -> AnimatedSprite {
Expand Down Expand Up @@ -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<Vec<Sprite>>,

//? ...
}

impl AnimatedSprite {
/// Creates a new animated sprite initialized at time 0.
pub fn new(sprites: Vec<Sprite>, frame_delay: f64) -> AnimatedSprite {
Expand Down
8 changes: 4 additions & 4 deletions _posts/2016-01-03-arcaders-1-11.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<Self> {
let (w, _) = phi.output_size();
self.rect.x += BULLET_SPEED * dt;
Expand Down Expand Up @@ -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
Expand Down
82 changes: 60 additions & 22 deletions _posts/2016-01-16-arcaders-1-12.md
Original file line number Diff line number Diff line change
Expand Up @@ -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::<f64>().abs() * 20.0 + 10.0);
// FPS in [10.0, 30.0]
let mut sprite = self.sprite.clone();
sprite.set_fps(::rand::random::<f64>() * 20.0 + 10.0);

Asteroid {
sprite: sprite,
Expand All @@ -253,11 +253,11 @@ impl AsteroidFactory {
w: ASTEROID_SIDE,
h: ASTEROID_SIDE,
x: w,
y: ::rand::random::<f64>().abs() * (h - ASTEROID_SIDE),
y: ::rand::random::<f64>() * (h - ASTEROID_SIDE),
},

// vel in [50.0, 150.0)
vel: ::rand::random::<f64>().abs() * 100.0 + 50.0,
// vel in [50.0, 150.0]
vel: ::rand::random::<f64>() * 100.0 + 50.0,
}
}
}
Expand All @@ -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<Box<Bullet>>,
asteroids: Vec<Asteroid>,
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() {
//? ...
Expand Down Expand Up @@ -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!
Expand Down Expand Up @@ -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:

Expand All @@ -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,
}
Expand Down Expand Up @@ -574,7 +600,7 @@ struct ExplosionFactory {

impl ExplosionFactory {
fn at_center(&self, center: (f64, f64)) -> Explosion {
//? ...
//? TODO
}
}
```
Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -953,14 +982,23 @@ impl Player {
}
}

//? Make sure to reflect the constant name change here.
fn spawn_bullets(&self) -> Vec<Box<Bullet>> {
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;

//? ...
}

//? ...
}
```

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) {
Expand Down Expand Up @@ -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!() };
}
}
Expand Down
6 changes: 3 additions & 3 deletions _posts/2016-03-22-arcaders-1-13.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion code/arcaders-1-10/src/phi/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl Rectangle {
assert!(self.w >= 0.0 && self.h >= 0.0);

// SdlRect::new : `(i32, i32, u32, u32) -> Result<Option<SdlRect>>`
// 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()
}
Expand Down
10 changes: 5 additions & 5 deletions code/arcaders-1-10/src/views/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<f64>().abs() * 20.0 + 10.0);
// FPS in [10.0, 30.0]
self.sprite.set_fps(::rand::random::<f64>() * 20.0 + 10.0);

// rect.y in the screen vertically
self.rect = Rectangle {
w: ASTEROID_SIDE,
h: ASTEROID_SIDE,
x: w,
y: ::rand::random::<f64>().abs() * (h - ASTEROID_SIDE),
y: ::rand::random::<f64>() * (h - ASTEROID_SIDE),
};

// vel in [50.0, 150.0)
self.vel = ::rand::random::<f64>().abs() * 100.0 + 50.0;
// vel in [50.0, 150.0]
self.vel = ::rand::random::<f64>() * 100.0 + 50.0;
}

fn get_sprite(phi: &mut Phi, fps: f64) -> AnimatedSprite {
Expand Down
2 changes: 1 addition & 1 deletion code/arcaders-1-11/src/phi/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl Rectangle {
assert!(self.w >= 0.0 && self.h >= 0.0);

// SdlRect::new : `(i32, i32, u32, u32) -> Result<Option<SdlRect>>`
// 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()
}
Expand Down
10 changes: 5 additions & 5 deletions code/arcaders-1-11/src/views/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<f64>().abs() * 20.0 + 10.0);
// FPS in [10.0, 30.0]
self.sprite.set_fps(::rand::random::<f64>() * 20.0 + 10.0);

// rect.y in the screen vertically
self.rect = Rectangle {
w: ASTEROID_SIDE,
h: ASTEROID_SIDE,
x: w,
y: ::rand::random::<f64>().abs() * (h - ASTEROID_SIDE),
y: ::rand::random::<f64>() * (h - ASTEROID_SIDE),
};

// vel in [50.0, 150.0)
self.vel = ::rand::random::<f64>().abs() * 100.0 + 50.0;
// vel in [50.0, 150.0]
self.vel = ::rand::random::<f64>() * 100.0 + 50.0;
}

fn get_sprite(phi: &mut Phi, fps: f64) -> AnimatedSprite {
Expand Down
2 changes: 1 addition & 1 deletion code/arcaders-1-12-preclean/src/phi/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ impl Rectangle {
assert!(self.w >= 0.0 && self.h >= 0.0);

// SdlRect::new : `(i32, i32, u32, u32) -> Result<Option<SdlRect>>`
// 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()
}
Expand Down
Loading

0 comments on commit 8fb2d61

Please sign in to comment.