Skip to main content

Placing the Fruit

A freely moving snake is nice. But it get's a bit dull if that's all there is. To make it a bit more of a challenge, you'd need to add something to change the snake. The classic approach is to let the snake "eat" fruits. That's a good place to start.

To place (and eat) a fruit, you first need to define it in Game. Since it's simply a point on the grid, Point will do:

// src/game.rsuse crate::snake::{Point, Snake};use crate::wasm4;
pub struct Game {    snake: Snake,    frame_count: u32,    fruit: Point,}
impl Game {    pub fn new() -> Self {        Self {            snake: Snake::new(),            frame_count: 0,            fruit: Point { x: 0, y: 0 },        }    }}

Random Numbers#

There are several random random generators available on crates.io, including some that are cryptographically secure.

We don't need anything our snake game to be cryptographically secure so we'll use fastrand crate:

it provides fastrand::Rng, a simple seedable pseudo-random number generator.

Let's add fastrand to Cargo.toml:

[dependencies]buddy-alloc = { version = "0.4.1", optional = true }lazy_static = "1.4.0"fastrand = "1.6.0"

We'll then store an instance of fastrand::Rng in our Game and initialize fruit coordinates with Rng::i32:

a method that returns a random i32 number within the input range.

// src/game.rsuse crate::snake::{Point, Snake};use crate::wasm4;use fastrand::Rng;
pub struct Game {    rng: Rng,    snake: Snake,    frame_count: u32,    fruit: Point,}
impl Game {    pub fn new() -> Self {        let rng = Rng::with_seed(235);
        Self {            frame_count: 0,            snake: Snake::new(),            prev_gamepad: 0,            fruit: Point {                x: rng.i32(0..20),                y: rng.i32(0..20),            },            rng,        }    }}

Importing PNG Files#

Importing images in WASM-4 works a bit different compared to other game engines and Fantasy Consoles. Images have to meet certain criteria:

  • PNG only
  • Index only
  • 4 colors max

Indexed PNG files can be created by several image apps like Aseprite or GIMP.

The image we import is a 8x8 PNG file with exactly 4 colors:

Zoomed Fruit This image is zoomed by 800%.

Zoomed Fruit This is the original image. You can download it to proceed.

Now you need to import the image. For this, the WASM-4 CLI tool w4 comes with another tool: png2src. You can use it like this:

w4 png2src --rust fruit.png

This will output the following content in the terminal:

const FRUIT_WIDTH: u32 = 8;const FRUIT_HEIGHT: u32 = 8;const FRUIT_FLAGS: u32 = 1; // BLIT_2BPPconst FRUIT: [u8; 16] = [ 0x00,0xa0,0x02,0x00,0x0e,0xf0,0x36,0x5c,0xd6,0x57,0xd5,0x57,0x35,0x5c,0x0f,0xf0 ];

Let's copy FRUIT and add it to our project; we'll also rename it FRUIT_SPRITE.

// src/game.rsuse crate::snake::{Point, Snake};use crate::wasm4;use fastrand::Rng;
const FRUIT_SPRITE: [u8; 16] = [    0x00, 0xa0, 0x02, 0x00, 0x0e, 0xf0, 0x36, 0x5c, 0xd6, 0x57, 0xd5, 0x57, 0x35, 0x5c, 0x0f, 0xf0,];
pub struct Game {    rng: Rng,    snake: Snake,    frame_count: u32,    fruit: Point,}

Rendering a PNG File#

Rendering the sprite is rather simple. Just call the blit function of w4:

pub fn blit(sprite: &[u8], x: i32, y: i32, width: u32, height: u32, flags: u32);

In practice it looks like this:

// src/game.rs inside impl Game {} block    pub fn update(&mut self) {        self.frame_count += 1;
        if self.frame_count % 15 == 0 {            self.snake.update();        }        self.snake.draw();
        wasm4::blit(            &FRUIT_SPRITE,            self.fruit.x * 8,            self.fruit.y * 8,            8,            8,            wasm4::BLIT_2BPP,        );    }

But since you set the drawing colors, you need to change the drawing colors too:

// src/game.rs inside impl Game {} block    pub fn update(&mut self) {        self.frame_count += 1;
        if self.frame_count % 15 == 0 {            self.snake.update();        }        self.snake.draw();
        set_draw_color(0x4320);        wasm4::blit(            &FRUIT_SPRITE,            self.fruit.x * 8,            self.fruit.y * 8,            8,            8,            wasm4::BLIT_2BPP,        );    }

This way, w4 uses the color palette in its default configuration. Except for one thing: The background will be transparent.