Tutorial 9: Simon explained

By now you should have the skills needed to start coding or modifying small games and utilities. In this Wii programming tutorial we will go through the Simon game and give a brief explanation of what things do. In this tutorial we focus on how to use the code we know to achieve certain the things that we are after. You can grab the PDF of this tutorial here: codemii-tutorial-9

Lets begin by firstly downloading the simon source code and opening up main.c. This version of Simon is intended to run on gcube. You can load the dol file with gcube and have a little play around.

Simon is a basic game; you have 4 colours and the computer generates a sequence of colours which you need to press correctly to win. The computer shows you one colour and when you press the correct colour the computer then shows you the next colour and so on.

A quick summary of this Simon game would be:

[sourcecode language=’c’]Show current sequence colour
If sequence_counter is less than level_counter then increment sequence_counter
If sequence_counter equals level_counter then wait for user input

Wait for user input
If colour correct, increment user_counter
If user_count equals level_counter then increment level_counter and show new sequence
If colour incorrect, return to main menu
If user_counter equals sequence_length, game won[/sourcecode]

As usual we start off with our standard includes and also our graphical files. These graphic files were made with a program called bmp2gc which converts .bmp images to .h files which can be used with the gamecube/Wii. I would recommend you stick with using JPEGs instead of using bmp2gc.For the purpose of understanding the Simon game as it was coded, I’ve left most things as it was.

[sourcecode language=’c’]#include

#include “main.h”

// Graphics
#include “simon.h”
…[/sourcecode]

Next up we define how long we want the sequence to be, in this case 15. So the user will have to get the colours right until they reach 15 colours in a row.

[sourcecode language=’c’]#define SEQ_LENGTH 15[/sourcecode]

Our standard video variables

[sourcecode language=’c’]// 2D Video Globals
static u32 *xfb;
static GXRModeObj *rmode; [/sourcecode]

Now we declare our global variables. Firstly we define an array of characters that is 15 elements long. The next variable defined is the different colours; there are 4 colours. Red is 0, Green is 1, Blue is 2 and Yellow is 3.

Next up we have the sequence counters, the first seqnum is used when we are animating simon to show the user and seqlevel stores the ‘level’ the user is on. If the user has a sequence to play back of 210, they are up to level 3. If the sequence is up to 2102, they are up to level 4, etc.

Userseqnum stores where the user is up to in the sequence. The next booleans are to be used when we allow the user to press a button – userinput, if the user entered the correct input – correctinput and if the user is in the game – ingame.

[sourcecode language=’c’]// Vars
char seq [SEQ_LENGTH];
char color [4] = “0123”;
int seqnum, seqlevel, userseqnum;
bool userinput, correctinput, ingame; [/sourcecode]

We then have the usual initialise function.

[sourcecode language=’c’]void Initialise() {

}[/sourcecode]

We have a SetScreen function which just flushes everything we wrote to the framebuffer to the screen. Note that in this Simon game things aren’t done as correctly as they should be. Generally you should clear the screen and then write to the framebuffer and display it but since there aren’t any cursors or moving objects it’s not really needed.

[sourcecode language=’c’]void SetScreen() {
VIDEO_SetNextFramebuffer(xfb);
VIDEO_Flush();
VIDEO_WaitVSync();
}[/sourcecode]

Now we’ll jump right down the bottom to the main function which is quite short. We call initialise, initialise the controller and call another function which handles restarting our gamecube but as we aren’t running this on a gamecube it doesn’t really matter.

Below that we have our drawpic function which has a similar concept as display_jpeg in tutorial 5. drawpic takes the x position (93), y position (0), the images height (48), the images width (120) and the actual picture to display (simontext) which is the title screen image. After that we call our game function and return 0 if the user ever decides to quit.

[sourcecode language=’c’]int main () {

Initialise();
PAD_Init();
SYS_SetResetCallback (reset_cb);

drawpic(93, 0, 48, 120, simontext);

game();

return 0;
}[/sourcecode]

Before exploring the game function we need to animate the title screen and initialise our variables. In the first run of the game function all our ingame variable is false so it skips all the code in game() and runs animate_simon().

[sourcecode language=’c’]void game() {
u32 button = 0;

while (1) {
while (ingame == true) {

// First run or Game over? Then go back to menu
animate_simon();
restart_game();
}[/sourcecode]

Animate simon makes the lights spin on Simon and it acts as a menu screen waiting for the user to press A to begin. So we firstly need to know what colour light is currently lit, a variable which we can use to make the spinning go faster or slower and if this menu screen is running.

[sourcecode language=’c’]// Animate the “spinning” lights on simon
void animate_simon() {
int count = 0;
int multipler = 0;
bool running = true;
u32 button = 0; [/sourcecode]

We display our starting text which says “Press A to start” and begin our while loop. We use our light counter (count) and if it’s 0 we show the red light, if it’s 1 we should the green light, etc. We then increment this counter and when it reaches a count of 3 it will be reset to -1 which then is incremented immediately to 0.

[sourcecode language=’c’]
drawpic(96, 410, 27, 120, starttext);

while (running == true) {
if (count == 0) {
drawpic(60, 60, 336, 192, simonred);
}
if (count == 1) {
drawpic(60, 60, 336, 192, simongreen);
}
if (count == 2) {
drawpic(60, 60, 336, 192, simonyellow);
}
if (count == 3) {
drawpic(60, 60, 336, 192, simonblue);
count = -1;
}

count++;[/sourcecode]

Now when we are animating Simon we need a pause between each light and we can do this using the usleep function. Usleep sleeps for x amount of microseconds. Now when we are sleeping it’s basically just pausing our whole program. But what if the user presses the A button when the program is sleeping? Nothing would happen.

We can avoid this in two ways, either use threads or possibly make the sleep times shorter and then query the user input in-between sleeps. I went with the easier second option. You can see below that we sleep in 20 short times. We have our multiplier which can speed up the animation if it’s increased and we query if the A button was pressed.

[sourcecode language=’c’]
// Sleep a little bit in the for loop so we can grab user input
int i = 0;
for (i = 0; i< 20; i++) { usleep(25000 - (multipler * 100)); PAD_ScanPads(); button = PAD_ButtonsDown(0); if (button == PAD_BUTTON_A) { running = false; }[/sourcecode] After that we have the controller input code which works for either joystick, if it’s pushed up the animation speeds up and if pushed down the animation decreases. [sourcecode language='c'] // Go faster or slower according to user input else if ((PAD_StickY(0) > 18 || PAD_SubStickY(0) > 18) && multipler <= 245) { multipler++; } else if ((PAD_StickY(0) < -18 || PAD_SubStickY(0) < -18) && multipler >= 1) {
multipler–;
}
}[/sourcecode]

We then have our normal handling reboot/poweroff code which isn’t important and then we display what we have in our framebuffer with SetScreen().

[sourcecode language=’c’] // Handle reboot/poweroff
if (event == 1) {
printf(“POWER!\n”);
reload();
} else if (event == 2) {
printf(“RESET!\n”);
reload();
}
if (button == PAD_BUTTON_START)
reload();

//printf(“multipler = %i \n”,multipler);

SetScreen();
}
}[/sourcecode]

So lets say that the user now wants to play, they press A and then running variable turns false which causes us to end the animate_simon function and move on to the restart_game function.

The restart game function just initialises all of our variables, sets the userinput to false as we will firstly show the user the sequence, set the correctinput to true and when they get the colour wrong we’ll set it to false and they are in the game so we ingame to true.

As you might remember we don’t clear the screen so and we don’t want to display the Press A to start text anymore so what we show is a blank black image and then show a Simon image which doesn’t have any lights showing.

[sourcecode language=’c’]// Reset the variables and text
void restart_game() {
seqnum = 0;
seqlevel = 0;
userseqnum = 0;
userinput = false;
correctinput = true;
ingame = true;

drawpic(96, 410, 28, 120, blanktext);
drawpic(60, 60, 336, 192, simon); [/sourcecode]

Now we need to make the sequence that the user has to copy, it’s not something that we want to hardcode so we need to randomise it instead. We can use the current time to provide us with a ‘key’ and we’ll use the rand feature to generate us a random number from 0 to 3 which is our colours (rand() % 4).

Our sequences needs to be a of type char because we can’t have a sequence like 01230102321 because it starts with a 0 and it would be hard to say give me the second digit of this number without converting this number to a char. So we add ‘0’ to our rand() % 4 so that it will convert the 0 to 3 number into type char. We’ll then generate 15 of these numbers and add the number to the sequence.

[sourcecode language=’c’]
// Randomise the sequence
srand((unsigned)time(0));

int q;
for(q=0; q= seqlevel) {
userseqnum = 0;
seqlevel++;
userinput = false;

// Wait a little while
usleep(500000);

// If user has won
if (seqlevel == SEQ_LENGTH) {

}
}
}[/sourcecode]

We show the new sequence to the user and then wait for their input again. This time around the if statement (userseqnum < seqlevel) is true so we increment userseqnum and wait for the user’s next input if they were correct. We’ll assume that one time that they were incorrect, we need to find what the correct colour was and show that to the user. So we compare seq[userseqnum] with 0, 1, 2, 3 until we find the right colour and then display that colour light. We then display the “You Lost” text, pause for a while and then show the blank simon and set ingame to false so we go back to the menu screen. [sourcecode language='c'] // Incorrect sequence else if (correctinput == FALSE) { //printf("Sorry wrong key.... \n"); usleep(1000000); //printf("Right key was %c \n",seq[userseqnum]); //printf("You lost! \n"); if (seq[userseqnum] == '0') { drawpic(60, 60, 336, 192, simonred); } if (seq[userseqnum] == '1') { drawpic(60, 60, 336, 192, simongreen); } if (seq[userseqnum] == '2') { drawpic(60, 60, 336, 192, simonblue); } if (seq[userseqnum] == '3') { drawpic(60, 60, 336, 192, simonyellow); } drawpic(96, 410, 27, 120, youlost); usleep(15000000); SetScreen(); drawpic(60, 60, 336, 192, simon); drawpic(96, 410, 28, 118, blanktext); usleep(500000); SetScreen(); ingame = false; }[/sourcecode] Lets assume that the user has won the game by getting all the sequence correct. We check this by comparing seqlevel to SEQ_LENGTH (15) and if equal they have won. We display the “You Won” text and display the winning square by comparing the last level in the sequence with 0, 1, 2, and 3. We have a for loop to display the winning square, sleep a bit and then display the blank Simon image a few times so it’s shown as a blinking colour light. We pause for a while and then show the blank simon and set ingame to false so we go back to the menu screen. [sourcecode language='c'] // If user has won if (seqlevel == SEQ_LENGTH) { //printf("You win! \n"); drawpic(96, 410, 27, 120, youwin); // Blink the winning square int a; for (a = 0; a < 10; a++) { if (seq[SEQ_LENGTH-1] == '0') { drawpic(60, 60, 336, 192, simonred); } if (seq[SEQ_LENGTH-1] == '1') { drawpic(60, 60, 336, 192, simongreen); } if (seq[SEQ_LENGTH-1] == '2') { drawpic(60, 60, 336, 192, simonblue); } if (seq[SEQ_LENGTH-1] == '3') { drawpic(60, 60, 336, 192, simonyellow); } usleep(100000); SetScreen(); drawpic(60, 60, 336, 192, simon); usleep(100000); SetScreen(); } drawpic(96, 410, 28, 120, blanktext); usleep(500000); SetScreen(); //printf("Press A to play again \n"); ingame = false; }[/sourcecode] And there we have it, the Simon game explained in detail. All together it looks like a lot but there’s a few repeated if statements, functions, etc. It’s about programming in small components; you might start off with making the colour light up when you press a key. Then you might move on to comparing the key pressed to a certain colour and then move on to comparing the key pressed to a certain position in a character array, etc. I hoped this tutorial has helped you understand the Simon game and how things were done. There are plenty of ways that this Simon game can be improved so feel free to modify the code and show us how you’ve improved the game. I didn’t expect this tutorial to be this long but what can you do. If you have any questions or comments feel free to post them.

17 Responses to “Tutorial 9: Simon explained”

  1. Slimmmmmm says:

    Good stuff as usual, will need to build this when I get a min.

    Hope you had a good christmas and thanks for the web pointers too on another site 😉

  2. craebby says:

    Hi,

    thanks for the great tutorials. I wrote my first wii game based on these tutorials. It’s a memory for the wii. Thank u for explaining so much.

  3. wplaat says:

    hi, can you write a small manual how to enable the external lan ethernet device. my own tcp library does only support the internal wifi device. some people would really like lan support in my games. looking forward to your response

    • teknecal says:

      There isn’t anything special that I’m doing. The only thing is I initialise the network before initialising the storage device. joedj told me this and it seemed to work fine for users who tried it.

  4. wplaat says:

    Hi Teknecal, Is it possible that i can receive the source code of the homebrew browser. Will not distributed it to someone else. Maybe i can find the issue in my source code by comparing our code with my code.

  5. Danilo says:

    Hi, I’ve been following these tutorials and I managed to do everything that was explained, but when going to a custom code of mine I have no idea on how to add jpg images… how do I create the files I need? There’s nothing in your tutorial that can help me doing it, as it only makes you use files that you did in advance…

    Then, a tutorial on how to use pngs wuold be great, as pointers with jpgs are horrible (and jpgs suck anyway…)

    Hope you can help me explaining how I can use images..

    (Sorry for the bad english but I’m italian :D)

  6. Danilo says:

    I managed to put some images in, but they look like they’ve been cut… and if I put a return the game goes back to the loader. I’ll keep on working on it ^^

  7. Mechaelvis says:

    Great tutorial! I have a problem though. When i try to compile the program i get

    make[1]: *** No rule to make target `c:/devkitPro/examples/gamecube/tutorial8/source/main.c’, needed by `main.o’. Stop.
    “make”: *** [build] Error 2

    > Process Exit Code: 2
    > Time Taken: 00:00

    • teknecal says:

      Can you make sure you have all the files from the zip correctly?
      Also can you press Alt + 2 once you loaded up tutorial8.pnproj in Programmers Notepad?

  8. Dont Panic says:

    Thanks a lot for these tutorials, they are great! I am attempting to use what i have learned to port this game for the Wii… any pointers?

    • teknecal says:

      Only thing I can think of is that you should use a better graphics library than I did. Other than that you should be fine, just remember to keep testing.

  9. Dont Panic says:

    I got it working with the same graphics library, even added the loop from tut. 12, i have a question… when i try to call the nunchuk “z” button it seems to scan for the wpad_button_2… whats the deal with that

  10. wheredapng? says:

    Hi! i love these tutorials and i was jsut wondering if you had one on how to use png images. Because most games will need png images eventually.

Leave a Reply for Mechaelvis