Advertisement

Gamestate and Intro, Main Menu, Playing state

Started by March 29, 2016 06:47 AM
6 comments, last by L. Spiro 8 years, 8 months ago

Hi All,

I have added a game state FSM based on the 'Miner' Demo of Matt Bucklands 'Programming Game AI by Example'.

I would like some advice on how to link the Intro Splash Screen, Main menu (which just will have Play game, Settings, Quit), and then the actual Game with it. I am working with what will hopefully be a component based engine .

In my game::init() function I have

m_gameState.ChangeState(SplashScreen::Instance());

as I want the program to first display a quick logo.

game::update() function I will have

GameState state(m_gameState.getGameState());

if (state == GS_Playing)
{
// update game specifc systems here
}

First thing, how should I handle things like the splash screen and main menu? When should they get loaded / rendered? Should there be a specific system for them (MenuSystem)? Do they need to be updated in the game::update() loop, or just the game::render() loop?

I would love any advice on how to handle this, or links to a sample project that show this.

Thanks

I don't know the best answer to this but in my app I currently have a state machine and states. The state machine has a few methods:

Update(time)

Render

QueueState

PushState

PopState

and input type methods

The main loop just calls Update and Render. Update deals with changing any states (state changes don't happen straight away) and then calls update to the top most state, Render just checks which states need to be rendered and renders them (this allows me to have layers of states - e.g. a game menu on top of the game). State themselves deal with what state should be next e.g. pressing a 'new game' button on a main menu type state would create a n new game state and then push it on the state machine. State changes don't happen that loop since that would cause issues, they would happen start of next loop instead.

For s splash screen (which I haven't done yet but I'd like to). I would just initialise things, create a SplashScreen state, push it onto the state machine and then start the main loop. From there on it's the SplashState that decides what's happening, it would know how to render itself (or at least how to get itself rendered) and it would keep track of how long it has been displayed. Once that time is up it would then create a MainMenuState and queue that up to be the next state. During the next loop the state machine would check if it has any state changes queued and and apply it thus the main menu would then be current and would start rendering and updating itself. To further abstract things you could sue a factory to create your states (rather than a splash screen having to know what a main menu is).

My state machine has a stack of states so that I can have states on top of each other but I also just clear that stack at times too because you wouldn't want to keep a splash screen state on the stack for the duration of the game.

There's a lot of ways to do things but personally I think a few key points are: States should take care of their own rendering (either directly or by getting themselves into some draw/command lists to render themselves), they should update themselves and they should deal with input themselves. I also feel they should deal with setting the next state to transition to too. That way they are quite self contained and are very flexible. They can be a splash screen, a main menu, a game, in game menu it really doesn't matter. All I do in my main loop is call Update/Render on my finite state machine and nothing more.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

Advertisement

General Game/Engine Structure
Passing Data Between Game States




When should they get loaded / rendered?

Loaded on the next frame after being set.
Rendered every frame.

Should there be a specific system for them (MenuSystem)?

What does that mean?

Do they need to be updated in the game::update() loop, or just the game::render() loop?

These are not separate loops. There is only 1 game loop, which may update the game logic 0 or more times, and always renders one time.
Fixed-Time-Step Implementation

I am working with what will hopefully be a component based engine .

Why would you hope for an over-engineered misguided system that you can’t possibly use correctly/fully and doesn’t serve your needs best?

ECS is a buzzword and solves a specific domain of problems suitable only to marketed engines such as Unity. It’s not for you and doesn’t help you in any way. Stop doing things just because they are buzzwords.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

I like this article here on gamedev to give a nice start into the subject:

http://www.gamedev.net/page/resources/_/technical/game-programming/brain-dead-simple-game-states-r4262

chaos, panic and disorder - my work here is finished

I don't know the best answer to this but in my app I currently have a state machine and states. The state machine has a few methods:

Update(time)

Render

QueueState

PushState

PopState

and input type methods

Thanks, from what I have been reading down the track I will need to add a 'Stack' of states (just using a vector?) so I can have multiple screens or states open at once like you do. For now I just want to start simple and get the basics working.

The main loop just calls Update and Render.

Do you mean that in your game::update() loop all you call is gameState.update(), and let the gamestate class itself deal with all of the states, 'outside' of the main game loop?
Eg for each update step, instead of in game::update()

gameState.ChangeState(Intro),
gameState.ChangeState(Playing),

all you ever have called is

gameState.update()?

I would just initialise things, create a SplashScreen state, push it onto the state machine and then start the main loop. From there on it's the SplashState that decides what's happening,

Okay, so the state machine is the most 'outer layer' (besides the game loop), of the engine? Literally each update loop, the first thing the game engine does is check the state, and then executes the code only within that state?

States should take care of their own rendering (either directly or by getting themselves into some draw/command lists to render themselves), they should update themselves and they should deal with input themselves.

This is where I am a little stuck. From my reading and how I would like to go about things, I will have one 'RenderSystem' that just calls 'm_graphics->drawSprite(spriteData)'; each update loop. Previously I was using entitiyx ECS and would call it in the 'for (entityx::Entity entity : entities.entities_with_components(position, display))' loop, but I am moving away from ECS.

General Game/Engine Structure
Passing Data Between Game States

Thanks, I had actually read these articles already, the General Game Structure topic was great and got me started, but to be honest Passing Data Between Game States was a bit beyond me. I struggle to take programming concepts from just reading too... so am just trying to get stuck into it and then revisit things once I have a bit more of an idea.

Loaded on the next frame after being set.
Rendered every frame.

I think what I meant to ask is 'Where' should they get loaded / rendered. As in where about in the game engine. Should the gameState class itself handle all of this internally? Or should the main engine 'check' the game state class each loop and perform the relevant actions?

What does that mean?

My last attempt was using entityx ECS and game::update() called

void Game::update()
{
GameState state(m_gameManager.getGameState());

if (state == GS_Playing)
{
m_systemManager.update<PlayerControlSystem>(frameTime);
m_systemManager.update<MovementSystem>(frameTime);
}
}

so I am wondering do I use the same approach and have a

m_systemManager.update<MenuSystem>(frameTime);

that is controlled the same way the rest of the 'Game playing' Logic is, or are menus a separate thing?

These are not separate loops. There is only 1 game loop, which may update the game logic 0 or more times, and always renders one time.
Fixed-Time-Step Implementation

Sorry, by this I mean my game::run() loop, which looks like this (it is based on the game engine of Charles Kellys programming2dgames book:

void Game::run()
{

// calculate elapsed time of last frame, save in frameTime
QueryPerformanceCounter(&timeEnd);
frameTime = (float)(timeEnd.QuadPart - timeStart.QuadPart) / (float)timerFreq.QuadPart;
if (frameTime < MIN_FRAME_TIME)
{
sleepTime = (DWORD)((MIN_FRAME_TIME - frameTime) * 1000);
timeBeginPeriod(1); // Request 1mS resolution for windows timer
Sleep(sleepTime); // release cpu for sleepTime
timeEndPeriod(1); // End 1mS timer resolution
return;
}

if (frameTime > 0.0)
fps = (fps*0.99f) + (0.01f / frameTime); // average fps
if (frameTime > MAX_FRAME_TIME) // if frame rate is very slow
frameTime = MAX_FRAME_TIME; // limit maximum frameTime
timeStart = timeEnd;

update();
render();
}

Why would you hope for an over-engineered misguided system that you can’t possibly use correctly/fully and doesn’t serve your needs best?

ECS is a buzzword and solves a specific domain of problems suitable only to marketed engines such as Unity. It’s not for you and doesn’t help you in any way. Stop doing things just because they are buzzwords.

My bad, I am planning to use components as per http://gameprogrammingpatterns.com/component.html . My last attempt was an ECS engine and I should have listened to you guys and not gone down this track. I did find it quite 'convenient' but also did not find I was actually learning c++ game programming by using it, since the huge library was doing all of the heavy lifting for me. I was also having issues when it came to things that did not so obviously fit into the ECS pattern e.g. when I implemented a quadtree it was actually slower as I had to extract and pass in the entity ID's and do heaps of derefrencing rather than just filling it with all the objects and working on them directly. (which I think was the problem... I am not good enough at programming to say for sure...). One thing I did learn from ECS was how and why we want to separate out data and logic into these systems... so essentially I am trying to recreate that decoupling and flexibility but without some massive ECS library doing god knows what...

Thanks for all your comments guys.


Do you mean that in your game::update() loop all you call is gameState.update(), and let the gamestate class itself deal with all of the states, 'outside' of the main game loop?
Eg for each update step, instead of in game::update()

gameState.ChangeState(Intro),
gameState.ChangeState(Playing),

all you ever have called is

gameState.update()?

one method I have used is like this:
GameState *state;
...
while(state)
{
   GameState *nextState = state->update();
   state->render();
   if(nextState != state)
   {
      delete state;
      state = nextState;
   }
}
thus when the game should exit, state->update() returns nullptr
when the gamestate does not change, state->update() returns a pointer to the current game state
when the gamestate does change, state->update() constructs the next state and returns a pointer to the next game state
this works well for typical games, but sometimes you might not want to free the previous game state because you might go back; for example a classic RPG with out-of-map combat. In that case, I'd use reference counting rather than an explicit deletion.
Advertisement

Nanoha, on 29 Mar 2016 - 12:24 PM, said:
I don't know the best answer to this but in my app I currently have a state machine and states. The state machine has a few methods:

Update(time)
Render
QueueState
PushState
PopState
and input type methods

Thanks, from what I have been reading down the track I will need to add a 'Stack' of states (just using a vector?) so I can have multiple screens or states open at once like you do. For now I just want to start simple and get the basics working.


You could have a stack or a vector, it doesn't matter too much but a stack makes the most sense.


Nanoha, on 29 Mar 2016 - 12:24 PM, said:
The main loop just calls Update and Render.

Do you mean that in your game::update() loop all you call is gameState.update(), and let the gamestate class itself deal with all of the states, 'outside' of the main game loop?
Eg for each update step, instead of in game::update()

gameState.ChangeState(Intro),
gameState.ChangeState(Playing),

all you ever have called is

gameState.update()?


In effect yes (but I would call Update/Render on the state machine rather than directly on states). The states themselves deal with setting the next state or popping themselves of in the case of a menu.

Nanoha, on 29 Mar 2016 - 12:24 PM, said:
I would just initialise things, create a SplashScreen state, push it onto the state machine and then start the main loop. From there on it's the SplashState that decides what's happening,

Okay, so the state machine is the most 'outer layer' (besides the game loop), of the engine? Literally each update loop, the first thing the game engine does is check the state, and then executes the code only within that state?

Exactly this. Sometimes it might make sense to still update states that are in the background but I haven't had a need for that yet.

Nanoha, on 29 Mar 2016 - 12:24 PM, said:
States should take care of their own rendering (either directly or by getting themselves into some draw/command lists to render themselves), they should update themselves and they should deal with input themselves.

This is where I am a little stuck. From my reading and how I would like to go about things, I will have one 'RenderSystem' that just calls 'm_graphics->drawSprite(spriteData)'; each update loop. Previously I was using entitiyx ECS and would call it in the 'for (entityx::Entity entity : entities.entities_with_components(position, display))' loop, but I am moving away from ECS


You could just pass in your 'RenderSystem' into the state's Render function so every state will always be able to access it.

e.g.
FiniteStateMachine::Render(RenderSystem& renderSystem)
{
    m_CurrentState.Render(renderSystem);
}
I suspect you would need it else where too though (when states are initialised) so there might be a better method to for you.

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

Sorry, by this I mean my game::run() loop, which looks like this (it is based on the game engine of Charles Kellys programming2dgames book:

Then I suggest we put that book aside.
There does not exist a case in which it is remotely acceptable to return from the main loop without having drawn the scene.
I said the main game loop allows you to update 0 or more times and always draws once.
You may possibly enter into a 0-length loop for updating if not-enough time has passed for a logical update, but you cannot ever under any circumcisions leave the routine without a single render.
And this is without even mentioning the Sleep()’ing sin. We don’t do that. No.

My bad, I am [still doing weird things].

I wave my hand and erase from your mind the concept of ECS and now you have become a better programmer.
What you mean to say is, “I have studied how structures of arrays gave me the same performance as ECS, and how an adjustment to my quad-tree such that all the leaf-node children are sequential inside a pool of memory took care of caches misses, and have decided that learning ECS and considering myself happy with the results cheats me out of learning how to solve actual performance problems and teaches me that over-reaching solutions are always best. I will always be an inferior programmer and lose many job opportunities due to my inability to answer simple questions during interviews based on simple cache usage and understandings of basic programming principles.”

L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

This topic is closed to new replies.

Advertisement