Skip to: Site menu | Main content


Welcome to PSP-Programming.com, a place for developers to get together.

Welcome to the forums. Here you can find other user tutorials as well as homebrew releases and the source code repository. You can also ask for help with your code here and post your own homebrew!

PSP-Programming.com Forums
March 21, 2010, 02:13:28 PM *
Welcome, Guest. Please login or register.
Did you miss your activation email?

Login with username, password and session length

News: Join our IRC channel: ##psp-programming on freenode
Home Help Search Shop Login Register
Digg This!
Pages: [1] 2 3 ... 5
Print
Author Topic: [Tutorial] Full Game Part 1 - Menu  (Read 23752 times)
Insert_Witty_Name
Global Moderator
Hero Member
*

Karma: +148/-17
Offline Offline

Posts: 1602
1141.66 points

View Inventory
Send Money to Insert_Witty_Name

View Profile WWW
« on: June 02, 2006, 06:19:41 PM »

As promised I'll be posting up a mini series of tutorials on how to make a (simple) full game which will incorporate things like menus, animation, collision etc.

Part 1 - A Menu

A menu is an integral part of any game, they don't need to be complicated or fancy, just functional.

X will be our select/confirm button, O will be back/cancel.

We will have two menus within our game, a 'Start Game' menu, and a menu which allows you to choose the difficulty setting of the game.

I would recommend you having gone through all the tutorials on the main site before looking at this.

Create a new file named main.c

Let's start with the code, first our includes:

Code:

#include <pspkernel.h>
#include <pspdisplay.h>
#include <pspctrl.h>
#include "graphics.h"


You should know what most of these are by now; pspkernel.h is the base of all PSP programs, pspdisplay.h gives us access to the screen, pspctrl.h is for controls and graphics.h contains GU functions.

Code:

PSP_MODULE_INFO("Game Tutorial Part 1: Menu", 0, 1, 1);


Usual stuff, naming our program.

Code:

#define RGB(r, g, b) ((r)|((g)<<8)|((b)<<16))


This above line allows us to input our colors as RGB (Red/Green/Blue) values and it will convert them to native BGR (Blue/Green/Red) values.

Code:

/* Exit callback */
int exit_callback(int arg1, int arg2, void *common) {
          sceKernelExitGame();
          return 0;
}

/* Callback thread */
int CallbackThread(SceSize args, void *argp) {
          int cbid;

          cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
          sceKernelRegisterExitCallback(cbid);

          sceKernelSleepThreadCB();

          return 0;
}

/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void) {
          int thid = 0;

          thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0);
          if(thid >= 0) {
                    sceKernelStartThread(thid, 0, 0);
          }

          return thid;
}


Again, normal stuff, our callbacks.

Before I go into the next bit of code it's worth mentioning the scope of variables.

We'll be dealing with two types of variables, local and global.

If a variable is declared within a function (including main()), it is local to that function. Variables of the same name may be declared and used within other functions without any conflicts.

If a variable is declared outside of a function (and before all functions within that program) it is a global variable and can be accessed and altered by any of the functions.

If you don't understand that fully don't worry, re-read the above few paragraphs again. I'll talk about why we need this variable to be global in a later part.

Code:

//GLOBAL VARIABLES
int DifficultySetting = 1;


Now, we'll start our main() function:

Code:

int main(void) {
    SetupCallbacks();
    initGraphics();


Again, normal stuff; start our main() function, setup the callbacks and initialise the graphics.

Code:

    SceCtrlData pad, lastpad;

    sceCtrlReadBufferPositive(&lastpad, 1);
   
    Image* Background;
    Background = loadImage("./Images/Background.png");

    Color EasyColor = RGB(0, 0, 0);
    Color MediumColor = RGB(0, 0, 0);
    Color HardColor = RGB(0, 0, 0);
   
    int OnStartGameMenu = 1;
    int OnDifficultyMenu = 0;


The above are just our variable declarations, we will have two variables which hold our control input (pad & lastpad), then we read the controls and populate our lastpad variable (you'll see why we need the lastpad variable shortly), load an image for our menu background (Background) and declare three colors (EasyColor, MediumColor & HardColor) all black and finally we declare two integers (OnStartGameMenu & OnDifficultyMenu) which we will later use as checks for which 'part' of the menu we are on (1 equals on, 0 equals off). We could use a boolean or other variable to store this check, but I prefer integers.

Code:

    extern int DifficultySetting;


Ok ok, calm down - I can hear you saying 'What the hell is extern?'. Remember when we declared the global variable DifficultySetting earlier on? The above line just declares that we are going to be using it in this function. If we didn't have the 'extern' in and we just declared it as 'int DifficultySetting', it would be a local variable to main() only.

The reason why I've used 'extern' as opposed to other methods associated with global variables will become apparent in a later part.

Onto our loop.

Code:

    while(1) {


You should know what this does and why we have it by now. It creates our loop for reading controls, blitting images etc.

Code:

      sceCtrlReadBufferPositive(&pad, 1);


Reads our controls and puts the result in the 'pad' variable.

Because we don't want our controls to 'repeat' we check what the last button pressed was:

Code:

      if(pad.Buttons != lastpad.Buttons) {
      lastpad = pad;


This translates to 'if current button pressed is not the same as the last button pressed do this...' Then we set the lastpad variable to the last button pressed.

Code:

      if(pad.Buttons & PSP_CTRL_CROSS)
      {


We're checking to see if the X button has been pressed.

Code:

        if (OnStartGameMenu == 1)
           {
           OnStartGameMenu = 0;
           OnDifficultyMenu = 1;
           DifficultySetting = 1;
           }
        else if (OnDifficultyMenu == 1)
        {
         //HERE'S WHERE WE WOULD START THE ACTUAL GAME
        }
      }


Now we're seeing which menu we were on when X was pressed. if we are on the start game menu we turn it off, turn the difficulty menu on and make DifficultySetting = 1 (Easy). If however we were already on the difficulty menu, we would start the game (which we won't here as this is just the menu tutorial).

Code:

      if(pad.Buttons & PSP_CTRL_CIRCLE)
      {
        if (OnDifficultyMenu == 1)
           {
           OnStartGameMenu = 1;
           OnDifficultyMenu = 0;
           }
      }


Checking to see if the O button was pressed, if so we turn the difficulty menu off and the start game menu back on. Think of this as moving back an option as you would in a regular PSP game. Note how we don't have any code here for if O was pressed on the start menu - that's because we don't want the O button to do anything while we are on the start menu - just the difficulty menu.

Code:

      if(pad.Buttons & PSP_CTRL_UP)
      {
        if (OnDifficultyMenu == 1)
           {
           DifficultySetting--;
           if (DifficultySetting < 1)
           DifficultySetting = 1;
           }
      }


Checking to see if the UP button was pressed. If so, and again this only applies to the difficulty menu, we select the difficulty setting above. The difficulty settings are:

Easy = 1
Medium = 2
Hard = 3

We also have a check to make sure that if we have Easy (1) selected already when we press UP, we will still have it selected.

Code:

      if(pad.Buttons & PSP_CTRL_DOWN)
      {
       if (OnDifficultyMenu == 1)
           {
           DifficultySetting++;
           if (DifficultySetting > 3)
           DifficultySetting = 3;
           }
      }

    }


Similar to the check for UP, we are incrementing the difficulty setting now and also have a check to ensure that we cannot go further than Hard (3).

That's it for the controls, now onto displaying things on the screen.

Code:

    blitAlphaImageToScreen(0, 0 , 480, 272, Background, 0, 0);


Blitting our menu background image. We have this before the following checks as we want it to be displayed regardless of whether we are on the start menu or the difficulty menu.

Code:

    if (OnStartGameMenu == 1)
    {
    printTextScreen(170, 140, "Start Game", RGB(191, 0, 0));
    }


If we're on the start menu, the text 'Start Game' will be displayed in red.

Code:

    else if (OnDifficultyMenu == 1)
    {
      if (DifficultySetting == 1)
      {
       EasyColor = RGB(191, 0, 0);
       MediumColor = RGB(0, 0, 0);
       HardColor = RGB(0, 0, 0);
      }
      else if (DifficultySetting == 2)
      {
       EasyColor = RGB(0, 0, 0);
       MediumColor = RGB(191, 0, 0);
       HardColor = RGB(0, 0, 0);
      }
      else if (DifficultySetting == 3)
      {
       EasyColor = RGB(0, 0, 0);
       MediumColor = RGB(0, 0, 0);
       HardColor = RGB(191, 0, 0);
      }


We're defining the colors we're going to use for the difficulty menu here. All it's doing is saying 'if we selected Easy (1) then make Easy red, if we selected Medium (2) make Medium red etc. and making the other non-selected items black.

Code:

    printTextScreen(170, 140, "Easy", EasyColor);
    printTextScreen(170, 150, "Medium", MediumColor);
    printTextScreen(170, 160, "Hard", HardColor);
    }


The text for the difficulty menu is being displayed, coloured to what we declared above based on our current selection.

Code:

    sceDisplayWaitVblankStart();
    flipScreen();
    }


Waiting for the Vblank and then flipping the off-screen so it's displayed. Standard double-buffering stuff.

Let's wrap it up.

Code:

    sceKernelSleepThread();
    return 0;
}


Your full code should look something like this:

Code:

#include <pspkernel.h>
#include <pspdisplay.h>
#include <pspctrl.h>
#include "graphics.h"

PSP_MODULE_INFO("Game Tutorial Part 1: Menu", 0, 1, 1);

#define RGB(r, g, b) ((r)|((g)<<8)|((b)<<16))

/* Exit callback */
int exit_callback(int arg1, int arg2, void *common) {
          sceKernelExitGame();
          return 0;
}

/* Callback thread */
int CallbackThread(SceSize args, void *argp) {
          int cbid;

          cbid = sceKernelCreateCallback("Exit Callback", exit_callback, NULL);
          sceKernelRegisterExitCallback(cbid);

          sceKernelSleepThreadCB();

          return 0;
}

/* Sets up the callback thread and returns its thread id */
int SetupCallbacks(void) {
          int thid = 0;

          thid = sceKernelCreateThread("update_thread", CallbackThread, 0x11, 0xFA0, 0, 0);
          if(thid >= 0) {
                    sceKernelStartThread(thid, 0, 0);
          }

          return thid;
}

//GLOBAL VARIABLES
int DifficultySetting = 1;

int main(void) {
    SetupCallbacks();
    initGraphics();

    SceCtrlData pad, lastpad;

    sceCtrlReadBufferPositive(&lastpad, 1);
   
    Image* Background;
    Background = loadImage("./Images/Background.png");

    Color EasyColor = RGB(0, 0, 0);
    Color MediumColor = RGB(0, 0, 0);
    Color HardColor = RGB(0, 0, 0);
   
    int OnStartGameMenu = 1;
    int OnDifficultyMenu = 0;
    extern int DifficultySetting;

    while(1) {
      sceCtrlReadBufferPositive(&pad, 1);

      if(pad.Buttons != lastpad.Buttons) {
      lastpad = pad;

      if(pad.Buttons & PSP_CTRL_CROSS)
      {
        if (OnStartGameMenu == 1)
           {
           OnStartGameMenu = 0;
           OnDifficultyMenu = 1;
           DifficultySetting = 1;
           }
        else if (OnDifficultyMenu == 1)
        {
         //HERE'S WHERE WE WOULD START THE ACTUAL GAME
        }
      }

      if(pad.Buttons & PSP_CTRL_CIRCLE)
      {
        if (OnDifficultyMenu == 1)
           {
           OnStartGameMenu = 1;
           OnDifficultyMenu = 0;
           }
      }


      if(pad.Buttons & PSP_CTRL_UP)
      {
        if (OnDifficultyMenu == 1)
           {
           DifficultySetting--;
           if (DifficultySetting < 1)
           DifficultySetting = 1;
           }
      }

      if(pad.Buttons & PSP_CTRL_DOWN)
      {
       if (OnDifficultyMenu == 1)
           {
           DifficultySetting++;
           if (DifficultySetting > 3)
           DifficultySetting = 3;
           }
      }

    }

    blitAlphaImageToScreen(0, 0 , 480, 272, Background, 0, 0);

    if (OnStartGameMenu == 1)
    {
    printTextScreen(170, 140, "Start Game", RGB(191, 0, 0));
    }
   
    else if (OnDifficultyMenu == 1)
    {
      if (DifficultySetting == 1)
      {
       EasyColor = RGB(191, 0, 0);
       MediumColor = RGB(0, 0, 0);
       HardColor = RGB(0, 0, 0);
      }
      else if (DifficultySetting == 2)
      {
       EasyColor = RGB(0, 0, 0);
       MediumColor = RGB(191, 0, 0);
       HardColor = RGB(0, 0, 0);
      }
      else if (DifficultySetting == 3)
      {
       EasyColor = RGB(0, 0, 0);
       MediumColor = RGB(0, 0, 0);
       HardColor = RGB(191, 0, 0);
      }

    printTextScreen(170, 140, "Easy", EasyColor);
    printTextScreen(170, 150, "Medium", MediumColor);
    printTextScreen(170, 160, "Hard", HardColor);
    }

    sceDisplayWaitVblankStart();
    flipScreen();

    }
    sceKernelSleepThread();
    return 0;
}



Makefile (Again, standard makefile stuff - nothing too advanced here)

Code:

TARGET = GameTutorial1
OBJS = main.o graphics.o framebuffer.o

CFLAGS = -O2 -G0 -Wall
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS)

LIBDIR =
LIBS = -lpspgu -lpng -lz -lm
LDFLAGS =

EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = Game Tutorial Part 1

PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak


Here's a link to the files needed for this tutorial (graphics.c, graphics.h, framebuffer.c, framebuffer.h, Background.png).

Place the whole 'Images' folder in the 'GameTutorial1' folder after you compile (the whole 'Images' folder - not just the Background.png!)

http://www.psp-programming.com/animate/GameTutorial1.rar

Next tutorial part will involve loading the game, animating the character and performing a few checks.

Part 2 in now up:

http://www.psp-programming.com/dev-forum/viewtopic.php?t=386

Stay tuned!
Logged

Coder formerly known as:

Check out my homebrew & C tutorials at http://insomniac.0x89.org
Last updated 6th Oct 06 - Tutorial 2 added.


Insert_Witty_Name
Global Moderator
Hero Member
*

Karma: +148/-17
Offline Offline

Posts: 1602
1141.66 points

View Inventory
Send Money to Insert_Witty_Name

View Profile WWW
« Reply #1 on: June 02, 2006, 06:32:01 PM »

A few screenshots. Yes the games name will be Blinky...  Rolling Eyes



Logged

Coder formerly known as:

Check out my homebrew & C tutorials at http://insomniac.0x89.org
Last updated 6th Oct 06 - Tutorial 2 added.
Yeldarb
Miinaturvat Rules!
Administrator
Hero Member
*

Karma: +16/-3
Offline Offline

Posts: 602
4160.65 points

View Inventory
Send Money to Yeldarb


View Profile WWW
« Reply #2 on: June 02, 2006, 06:57:00 PM »

Wow you guys are overwhelming me with all these tutorials, great work.

I think I'm going to have to put up a guideline for submitting HTMLized tutorials, cuz it's getting to be too much work to convert all of this (which is a good thing) Razz
Logged

SG57
Sr. Member
****

Karma: +7/-37
Offline Offline

Posts: 474
1140.80 points

View Inventory
Send Money to SG57


View Profile
« Reply #3 on: June 02, 2006, 09:29:20 PM »

Well...  I have just found a ton of USEFUL functions needing to be converted from almost every language... Im thinking of making my own lib...  What do you think?  There has got to be atleast 10 of them...
Logged
harleyg
Give miinaturvat Points!
Hero Member
*****

Karma: +11/-14
Offline Offline

Posts: 715
462.95 points

View Inventory
Send Money to harleyg


View Profile
« Reply #4 on: June 03, 2006, 01:40:33 AM »

Nice!
il be using this for sure; great work!
Logged
faati
Full Member
***

Karma: +0/-1
Offline Offline

Posts: 152
0.00 points

View Inventory
Send Money to faati


View Profile
« Reply #5 on: June 03, 2006, 05:46:44 AM »

Wow mate, That is nice.
Logged

faati
Full Member
***

Karma: +0/-1
Offline Offline

Posts: 152
0.00 points

View Inventory
Send Money to faati


View Profile
« Reply #6 on: June 03, 2006, 07:18:42 AM »

Insomaniac do you think you can make it in a single folder like

main.c
menu.c
menu.h

i have no idea how to make this in a single folder  Embarassed

so i can call the menu in my main.c if you understand  Rolling Eyes
Logged

soccerpmn
Newbie
*

Karma: +0/-0
Offline Offline

Posts: 33
0.00 points

View Inventory
Send Money to soccerpmn

View Profile WWW
« Reply #7 on: June 03, 2006, 07:20:58 AM »

Wow, nice job, I gotta try this out.  I haven't done much of a menu before, but couldn't you just enumerate the various buttons that you use, then set up a switch/case thing?  To me I think that would at least make the code itself easier to read. Razz
Logged

whazilla
Sr. Member
****

Karma: +2/-8
Offline Offline

Posts: 377
1793.33 points

View Inventory
Send Money to whazilla


View Profile
« Reply #8 on: June 03, 2006, 08:23:22 AM »

great work in the make

EDIT: but not in my make
Quote
REUS@bolabo-007 ~/projects/game01
$ make
make: *** /usr/local/pspdev/psp/sdk: Is a directory.  Stop.

REUS@bolabo-007 ~/projects/game01


bummer
Logged
Insert_Witty_Name
Global Moderator
Hero Member
*

Karma: +148/-17
Offline Offline

Posts: 1602
1141.66 points

View Inventory
Send Money to Insert_Witty_Name

View Profile WWW
« Reply #9 on: June 03, 2006, 11:47:17 AM »

Quote from: "soccerpmn"
Wow, nice job, I gotta try this out.  I haven't done much of a menu before, but couldn't you just enumerate the various buttons that you use, then set up a switch/case thing?  To me I think that would at least make the code itself easier to read. Razz


There are several options on how to do it. I just chose one which illustrates it best.
Logged

Coder formerly known as:

Check out my homebrew & C tutorials at http://insomniac.0x89.org
Last updated 6th Oct 06 - Tutorial 2 added.
Insert_Witty_Name
Global Moderator
Hero Member
*

Karma: +148/-17
Offline Offline

Posts: 1602
1141.66 points

View Inventory
Send Money to Insert_Witty_Name

View Profile WWW
« Reply #10 on: June 03, 2006, 11:48:21 AM »

Quote from: "faati"
Insomaniac do you think you can make it in a single folder like

main.c
menu.c
menu.h

i have no idea how to make this in a single folder  Embarassed

so i can call the menu in my main.c if you understand  Rolling Eyes


Yes I understand you. You want multiple files.

Hang around for part 2 Faati, the game itself will me held in another file, should give you a good reference for what to do.
Logged

Coder formerly known as:

Check out my homebrew & C tutorials at http://insomniac.0x89.org
Last updated 6th Oct 06 - Tutorial 2 added.
Insert_Witty_Name
Global Moderator
Hero Member
*

Karma: +148/-17
Offline Offline

Posts: 1602
1141.66 points

View Inventory
Send Money to Insert_Witty_Name

View Profile WWW
« Reply #11 on: June 03, 2006, 11:49:28 AM »

Quote from: "whazilla"
great work in the make

EDIT: but not in my make
Quote
REUS@bolabo-007 ~/projects/game01
$ make
make: *** /usr/local/pspdev/psp/sdk: Is a directory.  Stop.

REUS@bolabo-007 ~/projects/game01


bummer


Sorry I don't understand what you're trying to say.
Logged

Coder formerly known as:

Check out my homebrew & C tutorials at http://insomniac.0x89.org
Last updated 6th Oct 06 - Tutorial 2 added.
faati
Full Member
***

Karma: +0/-1
Offline Offline

Posts: 152
0.00 points

View Inventory
Send Money to faati


View Profile
« Reply #12 on: June 03, 2006, 11:55:52 AM »

Okey No Problemo, when do you think you can release it ?
Logged

whazilla
Sr. Member
****

Karma: +2/-8
Offline Offline

Posts: 377
1793.33 points

View Inventory
Send Money to whazilla


View Profile
« Reply #13 on: June 03, 2006, 12:08:05 PM »

Insomniac ... i mean my compiler halts @ make: *** /usr/local/pspdev/psp/sdk is a ditectivo. Stop

while it compiles flamez or anything else just great(just verified)
and it's the newest in a Line of errors i got

EDIT:solved ... was indeed in make ... in Makefile
there's a space on the end of eatch line in u'r Makefile ... made my cygwin crash on dir ...  

thanks anywayz 4 the kool snippet ... maybe the game itself is even more ... Very Happy  happy happy joy joy
Logged
Insert_Witty_Name
Global Moderator
Hero Member
*

Karma: +148/-17
Offline Offline

Posts: 1602
1141.66 points

View Inventory
Send Money to Insert_Witty_Name

View Profile WWW
« Reply #14 on: June 03, 2006, 12:21:48 PM »

Not sure whazilla, compiles fine on my machine, anyone else having any issues?

Next part will be available pretty soon, it takes longer than you would imagine to write all the code from scratch, optimise it, then post as a tutorial  Very Happy
Logged

Coder formerly known as:

Check out my homebrew & C tutorials at http://insomniac.0x89.org
Last updated 6th Oct 06 - Tutorial 2 added.
Pages: [1] 2 3 ... 5
Print
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.11 | SMF © 2006-2009, Simple Machines LLC Valid XHTML 1.0! Valid CSS!
Page created in 0.279 seconds with 36 queries.
Sister Sites: Guitar Hero 4   BrokeniTouch.com