Game bootstrap/template


(Agent6) #1

Has anyone thought about making a game bootstrap? @Pharap shared Game Programming Patterns with me and it got me thinking about the overall structure on my program. I started a Arduboy-Bootstrap sketch and would love to hear ways you structure your program. As I read more from Game Programming Patterns I will modify my template but for now I have simple GameState handling.


(Simon) #2

I pretty much do it the way you do it!

Until recently, I was adding some ‘phantom’ states that would allow me to do initialisation steps prior to changing states.

An example:

enum class GameState : uint8_t
{
  stateMenuIntro,
  stateMenuMain_Init,
  stateMenuMain,
  stateMenuHelp,
  ...
};

switch(currentState)
  {
    ...
    case GameState::stateMenuMain_Init:
      <do whatever I need to initialise things once>
      changeState(GameState::stateMenuMain);

    case GameState::stateMenuMain:
      stateMenuMain();
      break;
   ...

  }

Note that in the case for the stateMenuMain_Init I do not close it with a break;. Once the initialisation code has run, it immediately changes state and falls into the next case statement. Hence the initialisation code runs exactly once.

In my latest game - for the Jam! - I am using a class system developed by @pharap which formalises the initialisation on class instantiation.


(Agent6) #3

I would have liked to join this Jam but I don’t think I am ready just yet. I want to be a little more ambitious for my next game though… I did TicTacToe for my first but now I think I will do ardubike (NES excitebike). I can get more comfortable with bitmaps and work with sounds among other things… I don’t know, the best way for me to learn something is have a project that challenges me.


(Simon) #4

Its a balance between a challenge and an insurmountable task! A framework like that you are developing will pay huge dividends over time.


#5

Yes, you are using it EXTENSIVELY recently.
Smart.
although I would do this:

void main() {

  if (/*conditionA*/) {
    //initialize stuff
    while (/*conditionA*/) {
      if (arduboy.nextFrame()) {
        //do local-variable stuff
      }
    }
  }

}

The above code make the variables local, and initialize them properly before jumping into the loop.
But this structure also means that you would be extra careful when trying to use return or break inside the loops.
Advantage of this was simply the initialize of things before the loop kick in.


(Pharap) #6

I’m not sure ‘bootstrap’ really fits here. I’m guessing you’re trying to draw a parallel with the ‘bootstrap’ phase of loading an operating system?

I think a ‘program template’ would probably be a better name (not to be confused with C++ templates of course).


I tend to spend more time theorising and advising than actually making games (or I start making a game and end up not finishing it because I get sidetracked).

But of the two games where I’ve been the main programmer I’ve used the same class-oriented state system (the one @filmote is now using as a basis for his jam game).

It’s evolved slightly over time.

The latest version allows the states to be mutually exclusive without the need for malloc by preallocating a static buffer large enough to hold the largest state (by shoving all the classes in a union and taking the size of the union - which will be the size of the largest class by definition).

Code

https://github.com/Pharap/Minesweeper/blob/master/Minesweeper/Game.h#L39-L59

https://github.com/Pharap/Minesweeper/blob/master/Minesweeper/Game.cpp#L96-L111

(If you don’t understand what’s going on here, fear not, I’m doing some seriously advanced magic.)


Look into the Sprites class.
Most people I’ve worked with don’t bother with arduboy.drawBitmap anymore because the Sprites frame feature is really useful for saving memory.


I wouldn’t recommend this unless you know how Arduino implements main and you know exactly what you’re doing, because it’s not as straightforward as you think.

Here is how Arduino implements main:

You need to know for definite whether you can avoid calling init, initVariant, USBDevice.attach and serialEventRun.

Also a main marked as void is not standards compliant, despite the fact several compilers will allow it.


#7

OOPS! I meant void loop(). Sorry for that…

void loop() {

  if (/*conditionA*/) {
    //initialize stuff
    while (/*conditionA*/) {
      if (arduboy.nextFrame()) {
        //do local-variable stuff
      }
    }
  }
}

(Pharap) #8

That still has no advantage over the idiomatic:

void loop(void)
{
	if(!arduboy.nextFrame())
		return;
		
	arduboy.pollButtons();
	
	// Update logic
	
	arduboy.clear();
	
	// Draw things
	
	arduboy.display();
}

Initialisation is best done either at point of declaration or in setup if the values only need to be initialised once.