# Before You Start

Hey! Before you start! Do you mind following me on Twitter? I really spent a lot of time working on this tutorial series, but a follow on Twitter and/or a shout-out really motivates me to continue making more.

If you haven’t done any of the previous tutorials, please be sure to do that before this one! Part 1, Part 2, Part 3, Part 4, Part 5, Part 6, and Part 7 .

# This Tutorial

This tutorial will be the first part of making a more complicated game than Pong. You’re going to make a game to challenge a player to find and destroy as many buildings as they can as a dinosaur in a given time limit, getting points as they do so. First, we need to learn about arrays and a few other things.

This is a HUGE tutorial, so I’m going to be breaking this down into smaller steps. Here’s what we’re going to cover in Part 8.

1. Upgrading our library to Arduboy2
2. Creating our sketch
4. Structuring our code
5. A moment about button presses
6. Creating a 1D array
7. Creating a 2D array

# 1. Creating our sketch

Okay, let’s start working on the game! In the Arduino IDE, go to File > New , then save the file to your computer. In the IDE, let’s use all this.

``````//DinoSmasher

#include <Arduboy2.h>
Arduboy2 arduboy;

void setup() {
arduboy.begin();
arduboy.setFrameRate(45);
arduboy.display();
arduboy.initRandomSeed();
arduboy.clear();
}

void loop() {
if(!(arduboy.nextFrame())) {
return;
}
arduboy.pollButtons();

arduboy.clear();

arduboy.setCursor(0, 0);
arduboy.print(F("HELLO!"));

arduboy.display();
}
``````

You should be able to understand most of this, but if there are some new things that you don’t recognize, don’t worry! Just save the file and transfer it to your Arduboy. It should simply say “HELLO” .

There are a few reasons to use functions in our code. One reason is organize your code, but another is to prevent you from having to repeat a lot of the same code over and over again. There’s another cool feature that helps with both of those things that uses the `#define` directive.

Pretend like you have the following code in your game to move your character around:

``````void move_left() {
player_x -= 5;
}
void move_right() {
player_x += 5;
}
void move_up() {
player_y -= 5;
}
void move_down() {
player_y += 5;
}
``````

If you used this code and found that your character moves too fast and wanted to change its speed, you would have to change it in 4 places. Instead, we could use the `#define` directive to create a keyword called `SPEED` , set it to `5` and then use that.

``````#define SPEED  5

void move_left() {
player_x -= SPEED;
}
void move_right() {
player_x += SPEED;
}
void move_up() {
player_y -= SPEED;
}
void move_down() {
player_y += SPEED;
}
``````

The way this works is that whenever you compile your code, the compiler will replace `SPEED` with `5` before it compiles.

Let’s use this knowledge to change our code!

# 3. Structuring our code

Our Pong code started to get a little crazy, so let’s make sure this game’s code is a bit easier to read. We have already have the standard `loop()` function that’s called many times. In our Pong game, that’s where we had a `switch` statement that handled which part of the game was happening.

We’re going to have to use a `switch` statement, as well, but let’s put it into its own function. Let’s make a `gameplay()` function a reference it near the end of our `loop()` function instead of printing “HELLO” . Remember, we want use `arduboy.display()` last, so let’s make sure it comes right before that.

When someone turns on the Arduboy, we want it to start at the title screen, then go to the gameplay screen, and then if they lose, we want them to go to the game over screen. However, if they beat the saved high score, we want to take them to the high score screen. From either of those, we want to go back to the title screen.

We need to create an `int` variable called `gamestate` to keep track of which state we’re in. The switch case should look something like this:

``````  switch(gamestate) {

case 0:
//Title screen stuff
break;

case 1:
//Gameplay stuff
break;

case 2:
//Game over screen
break;

case 3:
//High score screen
break;

}
``````

Putting that into our `gameloop()` function, our code now looks like this:

``````//DinoSmasher

#include <Arduboy2.h>
Arduboy2 arduboy;

int gamestate = 0;

void gameloop() {

switch(gamestate) {

case 0:
//Title screen stuff
break;

case 1:
//Gameplay stuff
break;

case 2:
//Game over screen
break;

case 3:
//High score screen
break;

}

}

void setup() {

arduboy.begin();
arduboy.setFrameRate(45);
arduboy.display();
arduboy.initRandomSeed();
arduboy.clear();

}

void loop() {

if(!(arduboy.nextFrame())) {
return;
}

arduboy.pollButtons();
arduboy.clear();
gameloop();
arduboy.display();
}
``````

COOL!

Instead of having 0, 1, 2, and 3 represent the different states in our game, let’s use `#define` to make the code easier to digest.

``````#define GAME_TITLE  0
#define GAME_PLAY  1
#define GAME_OVER  2
#define GAME_HIGH  3
``````

Now, any time we want to check the value of `gamestate` , we can simply compare `gamestate` to one of these defintions! We can even use it when defining/initializing varaibles! Take a look at how I’ve done it below:

``````//DinoSmasher

#include <Arduboy2.h>
Arduboy2 arduboy;

#define GAME_TITLE  0
#define GAME_PLAY  1
#define GAME_OVER  2
#define GAME_HIGH  3
int gamestate = GAME_TITLE;

void gameloop() {

switch(gamestate) {

case GAME_TITLE:
//Title screen stuff
break;

case GAME_PLAY:
//Gameplay stuff
break;

case GAME_OVER:
//Game over screen
break;

case GAME_HIGH:
//High score screen
break;
}

}

void setup() {

arduboy.begin();
arduboy.setFrameRate(45);
arduboy.display();
arduboy.initRandomSeed();
arduboy.clear();

}

void loop() {

if(!(arduboy.nextFrame())) {
return;
}

arduboy.pollButtons();
arduboy.clear();
gameloop();
arduboy.display();
}
``````

If we compile this, the code would run, but nothing would be displayed on the Arduboy screen. We should add some text to the screen to make sure this compiles and can be put onto the screen! However, I want to emphasize that we are going to make sure this program is easy to read, so let’s make sure we add it in sensibly!

Instead of putting a bunch of code into our `switch` statements, let’s simply add a single function to each case. These functions will be `titlescreen()` , `gameplay()` , `gameoverscreen()` , and `highscorescreen()` . Any time we want to add code into one of those states, we’ll simply put the code into those functions! This means we’ll add the text to those functions. Here’s the code for that:

``````//DinoSmasher

#include <Arduboy2.h>
Arduboy2 arduboy;

#define GAME_TITLE  0
#define GAME_PLAY  1
#define GAME_OVER  2
#define GAME_HIGH  3
int gamestate = GAME_TITLE;

void titlescreen() {
arduboy.setCursor(0, 0);
arduboy.print("Title Screen\n");
}

void gameplay() {
arduboy.setCursor(0, 0);
arduboy.print("Gameplay\n");
}

void gameoverscreen() {
arduboy.setCursor(0, 0);
arduboy.print("Game Over Screen\n");
}

void highscorescreen() {
arduboy.setCursor(0, 0);
arduboy.print("High Score Screen\n");
}

void gameloop() {

switch(gamestate) {
case GAME_TITLE:
titlescreen();
break;

case GAME_PLAY:
gameplay();
break;

case GAME_OVER:
gameoverscreen();
break;

case GAME_HIGH:
highscorescreen();
break;
}

}

void setup() {

arduboy.begin();
arduboy.setFrameRate(45);
arduboy.display();
arduboy.initRandomSeed();
arduboy.clear();

}

void loop() {

if(!(arduboy.nextFrame())) {
return;
}

arduboy.pollButtons();
arduboy.clear();
gameloop();
arduboy.display();
}
``````

ALRIGHTY! Compile this and put it onto your Arduboy to see what happens!

# 4. A moment about button presses

With the Arduboy2 library, we are able to check buttons 4 different ways:

1. The button is currently being held down using `arduboy.pressed()` like before
2. The button was just pressed in using `arduboy.justPressed()`
3. The button was just released using `arduboy.justReleased()`
4. A button is not being pressed using `aduboy.notPressed()`

In order to check if a button was pressed this frame, but don’t repeat, we can use `arduboy.justPressed()` . Changing the `gamestate` with the A button with something like the following would be easy.

``````if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_PLAY;
}
``````

Try adding code like this to `titlescreen()` , `gameplay()` , `gameoverscreen()` , and `highscorescreen()` to cycle through all of the states. If you want to double-check your work, see my code below:

``````//DinoSmasher

#include <Arduboy2.h>
Arduboy2 arduboy;

#define GAME_TITLE  0
#define GAME_PLAY  1
#define GAME_OVER  2
#define GAME_HIGH  3
int gamestate = GAME_TITLE;

void titlescreen() {
arduboy.setCursor(0, 0);
arduboy.print("Title Screen\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_PLAY;
}
}

void gameplay() {
arduboy.setCursor(0, 0);
arduboy.print("Gameplay\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_OVER;
}
}

void gameoverscreen() {
arduboy.setCursor(0, 0);
arduboy.print("Game Over Screen\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_HIGH;
}
}

void highscorescreen() {
arduboy.setCursor(0, 0);
arduboy.print("High Score Screen\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_TITLE;
}
}

void gameloop() {

switch(gamestate) {

case GAME_TITLE:
titlescreen();
break;

case GAME_PLAY:
gameplay();
break;

case GAME_OVER:
gameoverscreen();
break;

case GAME_HIGH:
highscorescreen();
break;
}

}

void setup() {

arduboy.begin();
arduboy.setFrameRate(45);
arduboy.display();
arduboy.initRandomSeed();
arduboy.clear();

}

void loop() {

if(!(arduboy.nextFrame())) {
return;
}

arduboy.pollButtons();
arduboy.clear();
gameloop();
arduboy.display();

}
``````

I suggest running this on your Arduboy and seeing how the states do not flicker too fast.

(OH, YEAH! Did you notice that `A_BUTTON` is a defined keyword?! It’s just a number!)

# 5. Creating a 1D array

Remember back in Part 6 when I told you about arrays? I told you that they were just groups of variables. Let’s talk a little more about them. They can be super helpful!

Let’s pretend that you have 5 cars in your game and you wanted to store how fast each one can drive. You could do something like this.

``````int car_one = 4;
int car_two = 5;
int car_three = 7;
int car_four = 8;
int car_five = 3;
``````

But what if you wanted to add 5 more cars?? That’s a lot of typing!! Well, there’s a quicker way to write this with arrays!

``````int cars[5] = { 4, 5, 7, 8, 3 };
``````

Using the above code, you would be creating an `int array` with all the car data in it. Let’s break this down.

`int` : This is the type of data you want a list of.
`cars` : This is the name of the array. Since you want to store many cars into it, you call it ‘cars.’
`[5]` : This is how many `int` 's you want in your array.
`{ 4, 5, 7, 8, 3 }` : This is the data that you’re storing. Notice that there’s 1 number for each car.

To increase the number of cars, you increase the size of the array and simply add another value to the end of the list, which is a lot easier!

``````int cars[10] = { 4, 5, 7, 8, 3, 6, 3, 1, 7, 9 };
``````

Now, what if we wanted to figure out the speed of one of the cars? Earlier, we would use `car_one` to access the number `4` .

``````track_distance = car_four;
``````

When using an array, we access using brackets like this:

``````track_distance = cars[4];
``````

Does the above make sense to you? GOOD! Because there’s one important thing that I need to tell you about arrays.

The index is the number that you use to access the data inside of the array at a given location. In the above code, `4` would be the index since you’re seemingly trying to get the fourth car’s speed.

However, when counting indexes, you don’t start with 1, 2, 3, … etc. Counting indexes actually starts at 0! What does this mean?? This means that the first car’s speed is actually stored at `cars[0]` . The second’s car’s speed is stored at `cars[1]` . The third is at `cars[2]` , etc, etc.

So, accessing the 4th car’s speed with `cars[4]` is actually wrong. We need to use `cars[3]` !!

``````track_distance = car_four; //This is lame
...
track_distance = cars[3]; //This is cool
``````

This isn’t hard to remember and I’ll try to make sure I remind you! Besides, there are benefits to this!!

OKAY! Enough talking! Let’s code an array!

Let’s make an array called `world` . This will eventually hold our game’s map! For now, we’ll just have it hold random numbers. Let’s make it have length of 20.

`int world[20] = { 9, 5, 7, 2, 8, 3, 1, 7, 9, 3, 2, 1, 6, 4, 7, 8, 4, 3, 1, 4 };`

We can also display some values from it in the `titlescreen()` function to test it! Add this!

``````  arduboy.print(world[0]);
arduboy.print(world[1]);
arduboy.print(world[2]);
arduboy.print(world[3]);
``````

Here’s my full code:

``````//DinoSmasher

#include <Arduboy2.h>
Arduboy2 arduboy;

#define GAME_TITLE  0
#define GAME_PLAY  1
#define GAME_OVER  2
#define GAME_HIGH  3
int gamestate = GAME_TITLE;

int world[20] = { 9, 5, 7, 2, 8, 3, 1, 7, 9, 3, 2, 1, 6, 4, 7, 8, 4, 3, 1, 4 };

void titlescreen() {
arduboy.setCursor(0, 0);
arduboy.print("Title Screen\n");

arduboy.print(world[0]);
arduboy.print(world[1]);
arduboy.print(world[2]);
arduboy.print(world[3]);

if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_PLAY;
}
}

void gameplay() {
arduboy.setCursor(0, 0);
arduboy.print("Gameplay\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_OVER;
}
}

void gameoverscreen() {
arduboy.setCursor(0, 0);
arduboy.print("Game Over Screen\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_HIGH;
}
}

void highscorescreen() {
arduboy.setCursor(0, 0);
arduboy.print("High Score Screen\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_TITLE;
}
}

void gameloop() {

switch(gamestate) {

case GAME_TITLE:
titlescreen();
break;

case GAME_PLAY:
gameplay();
break;

case GAME_OVER:
gameoverscreen();
break;

case GAME_HIGH:
highscorescreen();
break;
}

}

void setup() {

arduboy.begin();
arduboy.setFrameRate(45);
arduboy.display();
arduboy.initRandomSeed();
arduboy.clear();

}

void loop() {

if(!(arduboy.nextFrame())) {
return;
}

arduboy.pollButtons();
arduboy.clear();
gameloop();
arduboy.display();
}
``````

Isn’t it annoying that you still have to specificy that you want to print each individual value? What if you wanted to print all the values of the `world` array?? Would you copy/paste the code 20 times? NO! We have `for` loops that can help us!

Remember, if we want to use a `for` loop to go through something 20 times, we’d do something like this:

``````for (int i = 0; i < 20; i++) {
arduboy.print(i);
}
``````

If we use the above code, the numbers 0~19 would be printed out to the screen. Instead, we want to print the 20 values inside of `world` , starting at index 0.

``````for (int i = 0; i < 20; i++) {
arduboy.print( world[i] );
}
``````

Put this code into your title screen function and run it! Full code, here:

``````//DinoSmasher

#include <Arduboy2.h>
Arduboy2 arduboy;

#define GAME_TITLE  0
#define GAME_PLAY  1
#define GAME_OVER  2
#define GAME_HIGH  3
int gamestate = GAME_TITLE;

int world[20] = { 9, 5, 7, 2, 8, 3, 1, 7, 9, 3, 2, 1, 6, 4, 7, 8, 4, 3, 1, 4 };

void titlescreen() {
arduboy.setCursor(0, 0);
arduboy.print("Title Screen\n");

for (int i = 0; i < 20; i++) {
arduboy.print(world[i]);
}

if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_PLAY;
}
}

void gameplay() {
arduboy.setCursor(0, 0);
arduboy.print("Gameplay\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_OVER;
}
}

void gameoverscreen() {
arduboy.setCursor(0, 0);
arduboy.print("Game Over Screen\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_HIGH;
}
}

void highscorescreen() {
arduboy.setCursor(0, 0);
arduboy.print("High Score Screen\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_TITLE;
}
}

void gameloop() {

switch(gamestate) {

case GAME_TITLE:
titlescreen();
break;

case GAME_PLAY:
gameplay();
break;

case GAME_OVER:
gameoverscreen();
break;

case GAME_HIGH:
highscorescreen();
break;

}

}

void setup() {

arduboy.begin();
arduboy.setFrameRate(45);
arduboy.display();
arduboy.initRandomSeed();
arduboy.clear();

}

void loop() {

if(!(arduboy.nextFrame())) {
return;
}

arduboy.pollButtons();
arduboy.clear();
gameloop();
arduboy.display();

}
``````

This is what you should get after compiling!

Alright, now that you have a good understanding of what arrays are, let’s talk about 2D arrays!

# 6. Creating a 2D array

Arrays can store all sorts of data; You can have an array of `int` 's… an array of `boolean` 's… These are all called 1D arrays because they store data in 1 dimension. It’s basically just a single list of variables all grouped together.

But, you can take arrays a step further! You can even have an array of arrays!! WHAT?! These are called 2D arrays because they store data in 2 dimensions… This means that instead of just a list of information, you can have a whole grid of it!

Here’s a neat way to visualize the difference between a 1D array and a 2D array.

We can make a 2D array and store numbers into it and then print the numbers out like we did with a 1D array! Lemme show you how by starting by modifying our `world` array.

``````int world[4][20] = {
{ 9, 5, 7, 2, 8, 3, 1, 7, 9, 3, 2, 1, 6, 4, 7, 8, 4, 3, 1, 4 },
{ 8, 7, 2, 5, 6, 1, 4, 6, 6, 2, 6, 3, 5, 4, 2, 4, 3, 1, 5, 2 },
{ 7, 2, 6, 3, 5, 4, 0, 2, 3, 5, 9, 2, 3, 5, 4, 2, 5, 4, 1, 9 },
{ 6, 4, 5, 2, 6, 4, 5, 1, 2, 5, 4, 3, 2, 4, 6, 5, 4, 2, 4, 5 }
};
``````

Notice that our `world` array now has 2 lengths given to it. `[4]` refers to the the amount 1D arrays that will be stored. `[20]` is how long the 1D arrays will be. When creating this grid, you can think of the first number as the height of the grid and the second as the width.

In order to read one of the `int` values, we need to give two different indexes. Something like this: `world[2][6]` The first number is the row, and the second is the column. This would return the value `0` .

Now, how would you loop through all of these numbers to print them out? Well, we could write 4 separate `for` loops, but that would cause the same problem as before. Like in Part 6, we can have a `for` loop for the height and a `for` loop for the width!!

We can print the `world` by adjusting our `for` loop to look like this:

``````  for (int y = 0; y < 4; y++) {
for (int x = 0; x < 20; x++) {
arduboy.print(world[y][x]);
}
arduboy.print("\n");
}
``````

Remember from Part 5 that `arduboy.print("\n")` is supposed to create a new line of text! Compile and test the completed code:

``````//DinoSmasher

#include <Arduboy2.h>
Arduboy2 arduboy;

#define GAME_TITLE  0
#define GAME_PLAY  1
#define GAME_OVER  2
#define GAME_HIGH  3
int gamestate = GAME_TITLE;

int world[4][20] = {
{ 9, 5, 7, 2, 8, 3, 1, 7, 9, 3, 2, 1, 6, 4, 7, 8, 4, 3, 1, 4 },
{ 8, 7, 2, 5, 6, 1, 4, 6, 6, 2, 6, 3, 5, 4, 2, 4, 3, 1, 5, 2 },
{ 7, 2, 6, 3, 5, 4, 6, 2, 3, 5, 9, 2, 3, 5, 4, 2, 5, 4, 1, 9 },
{ 6, 4, 5, 2, 6, 4, 5, 1, 2, 5, 4, 3, 2, 4, 6, 5, 4, 2, 4, 5 }
};

void titlescreen() {
arduboy.setCursor(0, 0);
arduboy.print("Title Screen\n");

for (int y = 0; y < 4; y++) {
for (int x = 0; x < 20; x++) {
arduboy.print(world[y][x]);
}
arduboy.print("\n");
}

if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_PLAY;
}
}

void gameplay() {
arduboy.setCursor(0, 0);
arduboy.print("Gameplay\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_OVER;
}
}

void gameoverscreen() {
arduboy.setCursor(0, 0);
arduboy.print("Game Over Screen\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_HIGH;
}
}

void highscorescreen() {
arduboy.setCursor(0, 0);
arduboy.print("High Score Screen\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_TITLE;
}
}

void gameloop() {

switch(gamestate) {

case GAME_TITLE:
titlescreen();
break;

case GAME_PLAY:
gameplay();
break;

case GAME_OVER:
gameoverscreen();
break;

case GAME_HIGH:
highscorescreen();
break;
}

}

void setup() {

arduboy.begin();
arduboy.setFrameRate(45);
arduboy.display();
arduboy.initRandomSeed();
arduboy.clear();

}

void loop() {

if(!(arduboy.nextFrame())) {
return;
}

arduboy.pollButtons();
arduboy.clear();
gameloop();
arduboy.display();

}
``````

Cool, huh? Alright, let’s try something very dangerous. Something that you may have even wondered on your own!! Our `world` array is current `4` tall and `20` wide, but what happens if we try to print out the 5th line of numbers? Or 6th line? Could we do it? What if those values don’t exist? What will be printed out??? Replace the `for` loops with this and see for yourself!!

``````  for (int y = 0; y < 6; y++) {
for (int x = 0; x < 20; x++) {
arduboy.print(world[y][x]);
}
arduboy.print("\n");
}
``````

On my Arduboy, this is what it looks like!

Where did those exact numbers come from?? Shouldn’t those be 0’s?? Why does this happen? Well, whenever the Arduboy stores variables and things into memory, it puts them all into one big list. If you read outside of the array, you will be reading other variables. If you try to change the value that is outside of the array, you may accidentally change a random variable somewhere else in memory. This can cause all sorts of random stuff to happen that we don’t want right now. We can experiment with this later, but for now, let’s prevent this using our `#define` directive!

Let’s define the height and width of `world` and then use those numbers in our definitions and `for` loops! OH, let’s also change all the values to 0’s or 1’s just to check something.

``````#define WORLD_WIDTH    20
#define WORLD_HEIGHT  4
int world[WORLD_HEIGHT][WORLD_WIDTH] = {
{ 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1 },
{ 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0 },
{ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }
};

void titlescreen() {
arduboy.setCursor(0, 0);
arduboy.print("Title Screen\n");

for (int y = 0; y < WORLD_HEIGHT; y++) {
for (int x = 0; x < WORLD_WIDTH; x++) {
arduboy.print(world[y][x]);
}
arduboy.print("\n");
}

if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_PLAY;
}
}
``````

This Let’s move the for loops to their own function called `drawworld()` and reference it inside of the `gameplay()` function. Here’s the completed code:

``````//DinoSmasher

#include <Arduboy2.h>
Arduboy2 arduboy;

#define GAME_TITLE  0
#define GAME_PLAY  1
#define GAME_OVER  2
#define GAME_HIGH  3
int gamestate = GAME_TITLE;

#define WORLD_WIDTH    20
#define WORLD_HEIGHT  4
int world[WORLD_HEIGHT][WORLD_WIDTH] = {
{ 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1 },
{ 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0 },
{ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 }
};

void drawworld() {
for (int y = 0; y < WORLD_HEIGHT; y++) {
for (int x = 0; x < WORLD_WIDTH; x++) {
arduboy.print(world[y][x]);
}
arduboy.print("\n");
}
}

void titlescreen() {
arduboy.setCursor(0, 0);
arduboy.print("Title Screen\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_PLAY;
}
}

void gameplay() {
arduboy.setCursor(0, 0);
arduboy.print("Gameplay\n");

drawworld();

if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_OVER;
}
}

void gameoverscreen() {
arduboy.setCursor(0, 0);
arduboy.print("Game Over Screen\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_HIGH;
}
}

void highscorescreen() {
arduboy.setCursor(0, 0);
arduboy.print("High Score Screen\n");
if (arduboy.justPressed(A_BUTTON)) {
gamestate = GAME_TITLE;
}
}

void gameloop() {

switch(gamestate) {

case GAME_TITLE:
titlescreen();
break;

case GAME_PLAY:
gameplay();
break;

case GAME_OVER:
gameoverscreen();
break;

case GAME_HIGH:
highscorescreen();
break;

}

}

void setup() {

arduboy.begin();
arduboy.setFrameRate(45);
arduboy.display();
arduboy.initRandomSeed();
arduboy.clear();

}

void loop() {

if(!(arduboy.nextFrame())) {
return;
}

arduboy.pollButtons();
arduboy.clear();
gameloop();
arduboy.display();

}
``````

Let’s test this code and see what happens! Don’t the numbers in the gameplay screen kinda resemble a map? In fact, a lot of older games do something similar to draw the maps for their games.

But, we don’t want that. We want to actually draw a map using the techniques we talked about in Part 6.

# Next Tutorial

You’ve learned a lot this tutorial, so let’s wait until the next tutorial to add graphics to make it look cool!
You’ll also learn how to move around the map like in Zelda or Pokemon.

# Credits

I wrote this tutorial in order to give back to the programming community that taught me to get into it about 10 years ago. If you’d like to follow me on Twitter, please do so at http://www.twitter.com/crait . I’d greatly appreciate that.

7 Likes

Don’t you mean ‘Let’s make a `gameplay()` function and reference it near the end of our `loop()` function instead of printing “HELLO” .’?

Also, love the tutorials, keep it up!

P.S:

1 Like

for anyone still searching here is the link to part nine Make Your Own Arduboy Game: Part 9 - Mapping DinoSmasher

2 Likes

Working through this one now and I have a couple more questions so far.

In the last tutorial we inserted the code to prevent the game from running too fast. THe code for that looked like this:

``````if (!arduboy.nextFrame())
``````

In this tutorial it looks slightly different:

``````if (!(arduboy.nextFrame()))
``````

Does it work the same either way? Is one prefered over the other?

In the printing text tutorial we printed hello like this:

``````arduboy.print("Hello");
``````

At the start of this tutorial we insert this code:

``````arduboy.print(F("HELLO!"));
``````

Later when we print it just uses the original format. What’s the purpose of the ‘F’ in this one?

You can put extra brackets around clauses to help clarify the intent of the code if it’s not clear. You can also ensure that the compiler dies the calculations I. The order you intended. For example ‘a + b / c’ will give different results to ‘(a + b) / c’ just like it does in regular maths.

The F macro is an Arduino / Arduboy/ ARM trick that stores the string in program memory rather than RAM. For programs that are not using much of the RAM it doesn’t really matter but as your programs get bigger and closer to the RAM limit you can free up memory with this little trick.

2 Likes

Small correction: AVR, not ARM.

Also, despite being needed because of the limitations of AVR, the ‘trick’ itself is part of the Arduino library rather than the underlying avr-libc (i.e. AVR implementation of the C library).

Personally I prefer the former: `if (!arduboy.nextFrame())`.

To me, using `if (!(arduboy.nextFrame()))` implies that the author doesn’t know that unary operators like `!` have lower precedence than function calls. Function calls always evaluate before unary operators in nearly every language.

But on the other hand, using extra brackets with binary operators can be useful because languages do sometimes have different rules in regards to which operators are evaluated first.

If nothing else, it makes the intent clearer. Too many binary operators in one line can start to get confusing.

@filmote has already explained the bulk of it, but a few caveats…

Firstly, using `F` only works with `print` and `println`. If you try to do it in other situations you’ll probably end up with some compiler errors.

It’s possible to create other functions that will work with the `F` macro, but that’s some fairly advanced voodoo so not many people know how to do it.

Secondly, if you wrap the same string in the `F` macro twice, you’ll end up with two copies of the same string. E.g.

``````arduboy.print(F("Hello"));
arduboy.print(F("Hello"));
``````

Would cause two copies of `"Hello"` to be stored in progmem.

Most of the time that isn’t an issue, but if you ever get to the point where you’re really pushing the memory limit, it’s worth being aware of. There are tricks to get around this so you only end up with one copy of each string, but again that’s a bit more advanced.

The RAM/progmem dichotomy really deserves an entirely separate post, but I think there should be several explanations floating around the forum by now. I had a quick look and managed to dig up two: 1, 2.

2 Likes

Could you not just make a variable instead of using #define? That way you can use an enum class to organize all of your case variables?

1 Like

Yes, you could. In fact using a `constexpr` variable is better than using a macro (a “`#define`”). Macros are generally best avoided.

See:

An `enum class` (proper name: scoped enumeration) works slightly differently, but that’s also a much better option than using macros (`#define`s), and it’s actually a better option than using `constexpr` `int` variables too.

With a scoped enumeration, that part of the Dino Smasher code would look more like this:

``````#include <Arduboy2.h>

Arduboy2 arduboy;

// Creates a new type called 'GameState'
enum class GameState : uint8_t
{
// Enumerator values
// to represent the different game states
Titlescreen,
Gameplay,
GameOver,
Highscore,
};

// A variable of type 'GameState' used to
// track the current game state
GameState gameState = GameState::Titlescreen;

void updateGame()
{
switch(gameState)
{
case GameState::Titlescreen:
// Title screen
break;

case GameState::Gameplay:
// Gameplay
break;

case GameState::GameOver:
// Game over screen
break;

case GameState::Highscore:
// High score screen
break;
}
}

void setup()
{
arduboy.begin();
}

void loop()
{
if(!arduboy.nextFrame())
return;

arduboy.pollButtons();
arduboy.clear();

updateGame();

arduboy.display();
}
``````

Scoped enumerations are better because:

• They’re type safe. That means you can’t accidentally do `gameState = 10;`, because `10` is an integer, not a `GameState`. If you were using `int`s then `gameState = 11;` would compile and suddenly you’d have a horrible bug in your code that might be difficult to track down. (Especially if you only meant to type `1` but hit the key twice by accident.)
• You can specify how large they should be. Granted you can do this with integers too (by using `uint8_t` instead of `int`/`int16_t`), but it’s good that you can control this.
• They automatically produce unique values for each ‘enumerator’ (that’s the fancy name for the values like `GameState::Titlescreen` and `GameState::Gameplay`), so you don’t have to worry about manually choosing an integer value for each unique ‘thing’ you want to create a distinct value for.

Secretly, enumerations are actually integers ‘under the hood’ (in the above code, `GameState::Titlescreen` has a value of `0`, `GameState::Gameplay` has a value of `1`, `GameState::GameOver` has a value of `2`, et cetera), so they’re just as efficient and produce more or less the same code as using raw integer. They’re effectively just a clever way to make the compiler do a lot of the heavy lifting (i.e. assigning disticnt values) and prevent you from making mistakes.

(Note: Compiler errors are actually a good thing. They warn you about problems before you actually run your code rather than forcing you to hunt down the bugs manually while the code is running.)

(Note 2: You can actually convert enumeration types to and from integers if you want to override the safety, and there are rare occasions where this is useful. Particularly in defining functions that deal with enumeration types. E.g. you could make a `Direction` enumeration and a `turnLeft` function that would change `Direction::North` into `Direction::West` and so forth, which could be done more efficiently by manipulating the underlying integer values.)

1 Like