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 make a variable for this. Since it's simply a point on the grid, `Point` will do:
const snake = new Snake()let fruit: Pointlet prevState: u8let frameCount = 0

Random Numbers#

AssemblyScript provides us with the Math.random function. It returns a floating point value between 0 and 0.999999999. But since we only deal with integer values, it's a good idea to create a helper function:

function rnd(n: i32 = 20): u16 {    return u16(Math.floor(Math.random() * n))}

This allows you to call rnd(20) to get a number between 0 and 19. Now you can change the fruit declaration:

const snake = new Snake()const fruit = new Point(rnd(20), rnd(20))let prevState: u8let frameCount = 0

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 --assemblyscript fruit.png

This will output the following content in the terminal:

const fruitWidth = 8;const fruitHeight = 8;const fruitFlags = 1; // BLIT_2BPPconst fruit = memory.data<u8>([ 0x00,0xa0,0x02,0x00,0x0e,0xf0,0x36,0x5c,0xd6,0x57,0xd5,0x57,0x35,0x5c,0x0f,0xf0 ]);

To get it into a an existing file, use the >> operator. Like this:

w4 png2src --assemblyscript fruit.png >> main.ts

This will add the previous lines to your main.ts and causes an error because "fruit" already exists. Just rename the new fruit to fruitSprite and move it somewhere else. Also: You can remove the other stuff added, you won't need it for this project:

const snake = new Snake()const fruit = new Point(rnd(20), rnd(20))let frameCount = 0let prevState: u8const fruitSprite = memory.data<u8>([ 0x00,0xa0,0x02,0x00,0x0e,0xf0,0x36,0x5c,0xd6,0x57,0xd5,0x57,0x35,0x5c,0x0f,0xf0 ])

With that out of the way, it's time to actually render the newly imported sprite.

Rendering a PNG File#

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

// Blit draws a sprite at position `x`, `y` and uses DRAW_COLORS accordinglyfunction blit(spritePtr: usize, x: i32, y: i32, width: u32, height: u32, flags: u32): void;

In practice it looks like this:

export function update(): void {    frameCount++
    input()
    if (frameCount % 15 == 0) {        snake.update()    }    snake.draw()
    w4.blit(fruitSprite, fruit.x * 8, fruit.y * 8, 8, 8, w4.BLIT_2BPP)}

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

    snake.draw()
    store<u16>(w4.DRAW_COLORS, 0x4320)    w4.blit(fruitSprite, fruit.x * 8, fruit.y * 8, 8, 8, w4.BLIT_2BPP)

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