#62365 - psycorpse - Wed Nov 30, 2005 4:07 am
How does everyone go about doing a title screen and then a menu and then to the game itself? Do you make functions for each of those? Then in the while loop of main do you check to see if the title function is done and then show the menu? All the tutorials that I see just show how to go straight into gameplay. I am new to C and C++ so I am not 100% sure that this is how it is done. Anyway if you understand what I am asking and can give any input I would greatly appreciate it.
Thanks,
Mike
#62367 - gauauu - Wed Nov 30, 2005 6:01 am
I don't know about the "best" way, but for GBA games, I often give the title screen and/or menu screens their own game loop.
Something like (this is oversimplified)
Code: |
while(true)
{
doTitleScreen();
setupGameState();
while(waitForExitGame())
{
checkControls();
updateGameState();
frameTick(); //frametick waits for vblank,
//does sound worker function,
//etc - stuff that has to happen every frame
//no matter which loop you are in....
updateBG();
updateSprites();
}
}
void doTitleScreen()
{
setupTitleScreen();
while(waitForStartButton())
{
processTitleScreenAnimations();
frameTick();
updateBG();
}
unsetupTitleScreen();
}
|
By keeping all the real code from the loops in functions, it's pretty easy to just grab the functionality you need for each different type of loop. In my current game, I actually have a different loop for each of:
title screen
main menu
game play
stats screen
Since the stuff that has to happen in EACH of them in all wrapped up in the frameTick() function, I can just handle the appropriate controls/updates in each loop, instead of having one big loop and a bunch of conditionals to figure out which things I'm supposed to be doing depending on what's happening on the screen.
Of course, I'm not saying this is anywhere near the best, or a recommended way. Just the way I've been doing it recently. But I've also done it with just one master loop, and keeping track of state. It was just enough of a pain in the butt that I decided to try this method. And so far, it's much easier.
#62368 - psycorpse - Wed Nov 30, 2005 6:06 am
Cool. Thanks for the input. I just wasn't sure on how anyone did this.
Mike
#62379 - SittingDuck - Wed Nov 30, 2005 11:20 am
Just to note, while waiting for VBlank, remember to turn off the CPU (the best way to do it is to use a BIOS function) otherwise the battery will be wasted very quickly.
#62407 - expos1994 - Wed Nov 30, 2005 6:35 pm
The way I go about it is to have a big case statement that goes from state to state.
something like:
Code: |
//In your main() loop...
switch (gamemode)
{
case TITLE_MODE:
{
dotitlestuff();
if (titlestuffdone)
gamemode = MENU_MODE;
break;
}
case MENU_MODE:
{
domenustuff();
if (menustuffdone)
gamemode = GAME_MODE;
break;
}
case GAME_MODE:
{
dogamestuff();
if(gameover)
gamemode = TITLE_MODE; //or GAME_OVER_MODE
if(startpressed)
gamemode = PAUSE_MODE;
break;
}
case PAUSE_MODE:
{
dopausestuff();
if(startpressed)
gamemode = GAME_MODE;
break;
}
}
//Do your standard checking for key presses and wait for vblank stuff here
|
That's the structure I always use for GBA games. This way will keep your game in a certain state until you put it in a different state.
I threw that PAUSE_MODE in there to show you where you can go with this. I also usually have an INIT_MODE for more complex states. Like PAUSE_MODE_INIT might fade out the game screen. Do a pause animation, and then move the gamemode to PAUSE_MODE. Pause_mode might just sit there and spin it's wheels until you push "start".
In even a small game, I could have some 20 or so different states (VIEW_HIGH_SCORE_MODE, FADE_IN_MODE, ENTER_INITIALS_MODE, NEXT_LEVEL_MODE.... you name it.)
#62409 - SittingDuck - Wed Nov 30, 2005 6:46 pm
It's best to create seperate game loops. Get rid of the switch statement. This is executed sixty times per second and includes unnessecary jumps. Every little less time helps in a GBA game! ;)
#62411 - thegamefreak0134 - Wed Nov 30, 2005 6:56 pm
My solution to this issue, to make it easier on yourself, is to have the different parts of the game in different program.c files. Then, create a never ending main loop in your main.c (/whatever you call it) and create a nesting system of some sort to take you through the game. My system, since I am pouring my heart and soul into a puzzle type game, will take my users first to the title screen, then to the menu. From the menu, they can navigate to different sections or press B to go back to the title. When they start a game, it's a totally different loop, but when the game ends it returns a variable so the menu comes back up at the same place. It's pretty easy to put different modes of play in like this. You can also use this type of nesting in games for things like battle systems or stat menus. And since the different parts are files of their own, you don't have to go code hunting.
_________________
What if the hokey-pokey really is what it's all about?
[url=http:/www.darknovagames.com/index.php?action=recruit&clanid=1]Support Zeta on DarkNova![/url]
#62412 - kusma - Wed Nov 30, 2005 6:58 pm
SittingDuck wrote: |
It's best to create seperate game loops. Get rid of the switch statement. This is executed sixty times per second and includes unnessecary jumps. Every little less time helps in a GBA game! ;) |
yes, optimize code that takes ~0.00001065552234649658 of your total time pr frame. i'll be hearing from you around christmas 2090.
#62415 - poslundc - Wed Nov 30, 2005 7:27 pm
Google "finite state machines", then implement your game as one.
(This is basically what expos1994 is doing.)
Dan.
#62419 - expos1994 - Wed Nov 30, 2005 8:06 pm
A nice thing about having a "gamemode" type variable that tracks the state of your game is that it can be easily monitored in VBA by using the memory viewer.
This can really aid in debugging. You'll always know where you're game is sitting. Or where your game is flying off its track.
I have tried creating multiple loops and multiple waits for vblank, but I found it got too complicated and didn't work as I expected it. Which is why I went to using one Case statement. For me, it's a lot easier to manage one loop than to manage a whole bunch of em.
But, that's just me. As with any kind of programming, there are 100 different ways to do everything.
#62531 - Touchstone - Thu Dec 01, 2005 9:56 pm
I've used sort of a "context" system before with function pointers. Code: |
typedef struct SContext
{
void(*pfnInit)(void);
void(*pfnProcess)(void);
void(*pfnRender)(void);
void(*pfnDestroy)(void);
} |
Then you create a couple of contexts (I've only created one here). Code: |
void menuInit(void)
{
}
void menuProcess(void)
{
}
void menuRender(void)
{
}
void menuDestroy(void)
{
}
SContext menuContext =
{
menuInit,
menuProcess,
menuRender,
menuDestroy,
} |
And then in the main function I have a pointer to the current context to be updated and rendered. Code: |
SContext* pCurrentContext;
void main(void)
{
pCurrentContext = &menuContext;
pCurrentContext->pfnInit();
while(GameIsRunning)
{
pCurrentContext->pfnProcess();
pCurrentContext->pfnRender();
}
pCurrentContext->pfnDestroy();
} |
Uhm, yeah, something like that. If you have a couple of contexts you can switch between them by running the pfnPestroy() on the current context, change the context to the new one, perform the pfnInit() and then back into the main loop.
_________________
You can't beat our meat