Sign in to follow this  
destructivArts

Managing Game States

Recommended Posts

destructivArts    205
Hello All!
I have recently completed Pong and Snake in Java from scratch. These were meant to be warm ups for bigger games.
They taught me how programming games works, and a lot about graphics.
One thing I did in both that I feel that there must be a better way of doing is keeping track of what part of the game the player is in.
For example, in both games, I simply created an integer variable called state.
0 = main menu
1 = in game
2 = game over
It's a pretty simple system. Both my run() and paintComponent() method checked it every frame and performed accordingly.

I was just wondering if there was a more effective way of doing this? I've been thinking for a while about it but I can't think of anything.
Any ideas?

Thanks,
Peter

Share this post


Link to post
Share on other sites
SiddharthBhat    358
yes, there is :] The state pattern - [url="http://en.wikipedia.org/wiki/State_pattern"]http://en.wikipedia.org/wiki/State_pattern[/url]. it's a pretty common one and it's used almost everywhere :) and I strongly suggest you check out enginuity - [url="http://www.gamedev.net/page/resources/_/technical/game-programming/enginuity-part-i-r1947"]http://www.gamedev.net/page/resources/_/technical/game-programming/enginuity-part-i-r1947[/url]. They're a series of fantastic articles written by richard fine that covers everything you need to write a game engine :)

Have fun!
P.S - can we have the enginuity articles and a link to the state pattern stickied or something? a lot of people ask questions about this :)

Share this post


Link to post
Share on other sites
marcjoel    113
Make a base class of the States, let's say class BaseState. then inherit every state in it. for example: class MainMenuState : public BaseState. then make a class that handles the state, i.e. class StateManager. This class will just have a pointer to a BaseState. Register your real states to this manager then act accordingly. Heres a sample code.

class BaseState
{
public:
virtual void Update() = 0;
};

class MainMenuState : BaseState
{
public:
void Update();
};

class StateManager
{
private:
BaseState* current_state;
public:
void SetState(BaseState* state)
{
current_state = state;
}

void UpdateCurrentState()
{
current_state->Update();
}
};


Something like that [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img] I hope it helped you [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]
Good day! Edited by marcjoel

Share this post


Link to post
Share on other sites
L. Spiro    25620
[quote name='marcjoel' timestamp='1332513156' post='4924636']
Don't forget the reputation button. ;)
Good day!
[/quote]
It is considered poor etiquette to request reputation.


L. Spiro

Share this post


Link to post
Share on other sites
Nanook    537
Great article YogurtEmperror..

I got something similar, but changing abit now with some new ideas from reading.. But where do you have your renderer? Do you store that in the base Game class so the Draw() can use it?

I think I might seperate it abit and have a Engine* where I store the engine resources and managers.. and a Game* for more game specific stuff.. that way I can use the Engine* in tools and have access to the resources without including game stuff..

Share this post


Link to post
Share on other sites
L. Spiro    25620
The best way to explain it is probably via a screenshot.
[attachment=7930:EngineOrg.png]
This screenshot has not been “posed” in any way. I simply started up my project and took a screenshot as it last appeared.
The file names across the top each begin with a prefix. LSG, LSI, etc. LSG = L. Spiro Graphics. LSI = L. Spiro Image, etc. The non-intuitive one is LSD, which stands for L. Spiro Models, since LSM (L. Spiro Math) was already taken.

On the right you see every module (library) that is compiled in order to build the actual engine. There are 15.

The Image library (LSI) handles images in a generic way. It doesn’t know what DirectX is or what OpenGL is. But it knows how to read a lot of formats and convert between formats. And resample, resize, etc.

This is an important separation because it allows tools to not know or care about DirectX or OpenGL etc.

LSE stands for L. Spiro Engine, and LSG stands for L. Spiro Graphics.
These are separate entities, each knowing about their own field of study.
LSE uses LSG, as does anything that needs to render itself (terrain and models only, basically).


So no, I do not store the renderer in the game class.
And CGame (from my post) is held within the “lse” namespace. It is part of the engine. Part of what binds all of the other modules together.

This acts as a better way to allow tools access to only what they need instead of having them rely on the entire engine for only a small engine feature.


L. Spiro

Share this post


Link to post
Share on other sites
Burnt_Fyr    1665
I think your on the right track Nanook, FWIW, my code is built much like L.Spiro's, and that kind of separation has taken me a while to really get to where i'm liking it(though still hating some parts). My games/demos themselves usually contain a main menu state, an options state, and a gamestate, everything else is either data or part of the engine itself.

Share this post


Link to post
Share on other sites
Nanook    537
Ah yes I also have it seperated like that.. I dont have that many though.. I have a core library, graphics library, physics library and engine library.. but I also have it devided into sections by namespaces.. I used to have lots of libraries too but I found it got pretty hard to maintain them all.. I also have low level renderers (OpenGL, DirectX) and a high level one..

Still abit confused from your reply though.. I mean.. where do you set up the scene for each state? Atm. I'm doing that in the Init of my states(Or actualy in my editor, but I load it from file in the Init).. I pass a Engine* to all the functions of the state (Init, Draw, ...) .. then when I call Draw on the state I do engine->GetRenderer()->Draw(m_scene); ..

So I store an instance of my renderer in the Engine class..

Share this post


Link to post
Share on other sites
L. Spiro    25620
I used to have one CSceneManager which was created by the CGame class, but then I had to make hacks to get multiple cameras working in the same scene when we wanted to draw one 3D scene and then another on top of it. Some objects were tagged to one camera and some to the other.
It didn’t make sense so in my new engine I let users create their own CSceneManager instances and as many of them as they please. This is a lot more elegant and efficient.

The scene is set up in the Init() class on CState.

As for how they are rendered, you have it backwards.
A rendered should never know what a scene is.
A scene knows what a scene is and it should render itself using the abstract and general-purpose functions provided to it by the renderer.

m_smScene.Draw().

The scene culls objects, selects the active camera, applies the projection matrices and other render states that need to be set, and eventually tells objects to draw themselves.
Objects set shaders for themselves, activate vertex and index buffers for themselves, and perform a render.


[quote name='Nanook' timestamp='1332957606' post='4926074']
Btw. do you have to open up your projects? Aren't they always open? [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img]
[/quote]
Not this week. I am watching Avatar: The Last Airbender by recommendation from a friend. But only 2 more left to watch.


L. Spiro

Share this post


Link to post
Share on other sites
Nanook    537
Ah I see.. I only have the root node in my state and then pass that to the renderer.. so I guess my renderer is kind of acting as my scenemanager.. even though I'm still doing the traversal and culling in the scene nodes themself though.. sceneNode.GetRenderablesCulled().. I'll redesign it so I'll move stuff into a scenemanager..

Im not sure where I should put my templated resource managers.. the manager that make sure there is only one instance of each loaded resource at one time.. Right now I've put the resource managers related to the renderer in the renderer.. so the user would do:

[CODE]
void MyState::Init()
{
VertexBuffer vBuffer("vertexbuffer.file");
int handlevBuffer = m_renderer->Register(vBuffer);
IndexBuffer iBuffer("indexbuffer.file");
int handleiBuffer = m_renderer->Register(iBuffer);
// more setup
Renderable renderable(handlevBuffer, handleiBuffer, handleShader, ...);
m_scene->addNode(renderable);
}
[/CODE]

So if I try to register a vertex buffer with a filename that is already registered it will return a handle to the one already registered instead of storing the new one.

Been thinking of having a ResourceManagerManager, but even the name of that sounds wrong [img]http://public.gamedev.net//public/style_emoticons/default/tongue.png[/img] If I put it in the scenemanager I wont be able to use the same resource managers for the different scenes..

Share this post


Link to post
Share on other sites
L. Spiro    25620
You generally don’t load “vertex files” and “index files”.
You load models. Any sharing between vertex and index buffers can be predetermined offline, since it is unlikely any vertex buffers will ever be shared between models.
Trying to share all vertex buffers on a system-wide scale is over-engineering.

This is how mine looks:[CODE]
LSVOID LSE_CALL CModelTest::Init( CGame * _pgGame, LSINT32 _ui32State, LSINT32 _ui32PrevState, LSUINTPTR _uptrUser ) {
m_dmipInstance = m_sgpScene->CreateDrawableModelInstance( "KinoGirl.lsm" );
m_sgpScene->CreateDrawableModelInstance( "Ground.lsm" )->SetCastsShadow( false );
}
[/CODE]

You can probably agree that this would be more preferable for anyone using your engine, including yourself.

There is no need for a global general-purpose resource manager. Resources don’t have enough in common to warrant such a thing.
As far as anything managing resources goes, there are unique ones for the scene, models, etc.
And all of these are handled at a high level. For example you are proposing to share all vertex buffers period. What if I want to load the same one again so I can make changes to it?
A more common example of the same thing is textures. I very easily might want to apply some filter that is expensive if done in a shader, so I want to modify the original. But that would change all instances of it, so I need to be able to load multiple copies of it.

However I know that within my model library I am not modifying those textures. They are shared between each other and only each other. No other system is involved, so while it may be wasteful if a sprite were to later reload the same file, it is the lesser of evils and in practice never happens. And textures within the sprite system are shared amongst each other as well.


L. Spiro

Share this post


Link to post
Share on other sites
Nanook    537
Yes the plan has been to load a renderable from file and the code loading the renderable will be loading vertex and index buffer like that.. so I would have

/renderables/Cube01/indexbuffer
/renderables/Cube01/vertexbuffer
/renderables/Cube01/shader
/renderables/Cube01/renderable
/textures/sometexture.png

The user would do something like loadRenderable('/meshes/Cube01/') and it would find the renderable file which have info on how stuff should be set up.. I got a dat archive file and a gui tool I've created and it exports any format with the assimp library and puts the files like that. hum.. maybe I should change it and put it all into my own model format.. Its easy to work with it when its like that though.. so I wasn't realy thinking of sharing the vertex buffers between different renderables as it is identified by the path in the dat file..

But you're saying that I should share renderables/textures, but still make it possible to load a seperate instance of it?

Share this post


Link to post
Share on other sites
popsoftheyear    2194
[quote name='YogurtEmperor' timestamp='1333110537' post='4926652']
...
What if I want to load the same one again so I can make changes to it?
...
[/quote]
Seems to me the best way to handle this would be to have a system which only loads resources once (from disk, DVD, internet, whatever) but employ copy-on-write semantics on your shared resources.

Share this post


Link to post
Share on other sites
L. Spiro    25620
[quote name='Nanook' timestamp='1333114938' post='4926678']
But you're saying that I should share renderables/textures, but still make it possible to load a seperate instance of it?
[/quote]
Basically. The below reply provides a reason as to why.


[quote name='achild' timestamp='1333116499' post='4926686']
[quote name='YogurtEmperor' timestamp='1333110537' post='4926652']
...
What if I want to load the same one again so I can make changes to it?
...
[/quote]
Seems to me the best way to handle this would be to have a system which only loads resources once (from disk, DVD, internet, whatever) but employ copy-on-write semantics on your shared resources.
[/quote]
I saw a video about some game that allowed slicing enemies in half and I wanted to support such an ability in my own, and the best way I thought to do that was via copy-on-write.

But later I realized that the problem with copy-on-write is that it is hidden overhead. People might be doing it and incurring a significant amount of overhead without understanding why.
When it comes to game engines, this isn’t acceptable. Users should know what actions they are doing to cause performance issues and be pushed towards a more performant way of accomplishing the same thing.

But this is a perspective unique to myself—not everyone here is planning on making a business out of middleware.
My original mindset allowed copy-on-write because I wasn’t considering other people using my engine (even though that was my goal and I should have been). If you are just making your own personal engine, copy-on-write is a very elegant solution to this problem.


L. Spiro

Share this post


Link to post
Share on other sites
Hiiri    113
Wouldn't some sort of stack of states work pretty well. You throw in the topmost of the stack the state you're showing currently, and once you're done with it, you pop it out. Then use some boolean value when creating state to determine, if the state manager goes further in the state stack. Like lets say you have following stack:

Options - state
Main game - state
The bottom - state

So looking this way, the control needs to go on the topmost object, but the logic update needs to go through whole stack. At least this would be the way how I would start implementing the controller, but probably other people have better ideas.

Maybe you could pass some values like, canDrawUnder and capturesController, or something like that to determine how far of the stack you must go.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this