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, a struct point will do:

struct snake snake;int frame_count = 0;uint8_t prev_state = 0;struct point fruit;

Random Numbers#

C provides us with pretty much everything we could need to create random numbers. Since we have already included stdlib.h we can use the rand function to generate random numbers. rand() returns and int between 0 and RAND_MAX which is guaranteed to be at least a 16-bit value. To limit the value returned by rand() to the screen grid coordinates we can divide it by 20 and use the remainder as our value using the modulus operator:

fruit.x = rand()%20;fruit.y = rand()%20;

As we can not use the system time to seed our random function, we need to explore some other ways of randomizing our fruit placement: as it stands every time we run the game the fruit will always appear at the same locations and the same sequence. In order to seed the random number generator we need a value that will be different every time the game starts, unfortunately we do not have access to any but once the game starts we can use a combination of the frame_count and user input to seed the randomness as the user will not always press the button at the exact same time.

To set the seed when the user inputs something, add the following line of code at the start of the input function in main.c:

void input(){    srand(frame_count);        ...

The initial fruit placement will be the same every run, but subsequent placements will be based off of this seed which should hopefully be unique each time.

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

This will output some code ending in the following to the terminal:

const uint8_t fruit_sprite[] = {    0x00,0xa0,0x02,0x00,0x0e,0xf0,0x36,0x5c,0xd6,0x57,0xd5,0x57,0x35,0x5c,0x0f,0xf0};

We need to add that array to the top of our main.c file:

#include "wasm4.h"#include "snake.h"#include <stdlib.h>
struct snake snake;int frame_count = 0;uint8_t prev_state = 0;struct point fruit;const uint8_t fruit_sprite[] = {    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 accordinglyvoid blit (const uint8_t* data, int32_t x, int32_t y, uint32_t width, uint32_t height, uint32_t flags);

In practice it looks like this:

void update () {    frame_count++;
    input();
    if (frame_count % 15 == 0)    {        snake_update(&snake);    }
    snake_draw(&snake);
    blit(fruit_sprite,fruit.x*8,fruit.y*8,8,8,BLIT_2BPP);}

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

    snake_draw(&snake);
    *DRAW_COLORS = 0x4320;    blit(fruit_sprite,fruit.x*8,fruit.y*8,8,8,BLIT_2BPP);

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