About a state machine

Started by
7 comments, last by JWColeman 5 years, 4 months ago

I am a beginning game developer, using Linux and C/C++. I am interested in organizing my game engine around a state machine, that let's me jump from a start screen, into the game and then back out during gameplay. Where the player would be able to set options such as sound or video settings.

I have never created a state machine, but found out that it is what I should be looking for. Does anyone have any suggestions on how to develop an SFML or SDL2 project around that concept. Some basic example code would help. Or some project where the source code is available and it's not too difficult to go through.

Advertisement

"State machine" is just the concept that you remember what you were doing.

The simplest form of a state machine is a function for each state. Conceptually, the function is your game loop while you are in the state. You can jump to other (different) states by calling its function. Return value of such a function could be how it exited, eg did the user press "play" or "exit"? The receiving state that called the function should decide what to do next, given the returned value.

Within each of these function, you have variables that describe what you're doing. Each of these function access the SFML or SDL2 library. They do so in much the same way, so you can refactor the common code out and share it between the functions.

 

The above works if you have a "tree" of screens, a screen can have sub-screens that you visit (and the sub-screen can have sub-sub-screens etc), but the only way out of a screen is going back to the previous screen.

If you have a lot of data associated with a screen, or you want to jump around more dynamically (not sure this is a good idea btw, but ymmv), you may want to wrap the function in a class, and create an object for each screen. Each object handles one screen. Jumping around can again be done like before, create a new instance of a screen, and call it, but that doesn't help much in flexibility.

You can also create a separate screen-dispatcher object, that controls which screen is the "current" screen (much like you have the concept "current state" in an active state machine). The dispatcher just constructs the screen objects, and "calls" them like the functions above so the screen object can "do" the screen. On return, the dispatcher then decides what to do with the returned value.

Have you read State Machines in Games?

- Jason Astle-Adams

jbadams - I am going to read that today

 

alberth - I'm getting a better understanding

 

I also found a short tutorial on lazyfoo.net. There is a good chance I will select SDL2 either way, to set this up.

Hi @zoink I've been game programming for a few years and here is my opinion.

@here is another resource from "Game Programming Patterns" by Robert Nystrom
http://gameprogrammingpatterns.com/state.html

Regarding the question "Does anyone have any suggestions on how to develop an SFML or SDL2 project around that concept." SFML and SDL2 are mainly about platform independence which is a lower level concern than the StateMachine. Get things rendering and a screen etc. then use your state machine to manage scenes.
UI flow is a good place to start because the state pattern is fairly common and for temp UI you can just use really basic colored rectangles which are simple to create.

I hope this helps.


 

Here is a resource that I am using currently.

 

http://gamedevgeek.com/tutorials/managing-game-states-in-c/

 

There is source code for this article at the bottom. 

 

I don't have it all figured out yet, but there are 3 major components

 

A base class from which you can virtualize all the functionality of your states from

 


#pragma once
class GameState
{
public:
	virtual void Initialize() = 0;		// Load resources here
	virtual void Start() = 0;			// Make gamestate objects here, register with renderer and physics
	virtual void Stop() = 0;			// Remove gamestate objects here, unregister with renderer and physics
	virtual void Update(float dt) = 0;			// Update game objects here
	virtual void Pause() = 0;			// Stop performing updates 
	virtual void Unpause() = 0;			// Continue performing updates
	virtual void Render() = 0;			// Update renderer here
	virtual void Destroy() = 0;			// destroy everything
};

 

A couple States:

 


class MainMenu : public GameState
{
public:
	MainMenu(Renderer * renderer, ResourceManager * resourcemanager);
	void Initialize() override;				// Load resources here
	void Start() override;					// Make gamestate objects here, register with renderer and physics
	void Stop() {}							// Remove gamestate objects here, unregister with renderer and physics
	void Update(float dt) override {}		// Update game objects here
	void Pause() override {}				// Stop performing updates 
	void Unpause() override {}				// Continue performing updates
	void Render() override {}				// Update renderer here
	void Destroy() {}						// destroy everything
private:
	Renderer * renderer;
	ResourceManager * resourcemanager;
	std::vector<GameObject*> menuobjects;
};

 

And...

 


class Game : public GameState
{
public:
	Game(Renderer * renderer, Physics * physics);
	void Initialize() override;				// Load resources here
	void Start() override {}					// Make gamestate objects here, register with renderer and physics
	void Stop() override {}					// Remove gamestate objects here, unregister with renderer and physics
	void Update(float dt) override;			// Update game objects here
	void Pause() override {}					// Stop performing updates 
	void Unpause() override {}				// Continue performing updates
	void Render() override {}				// Update renderer here
	void Destroy() override {}				// destroy everything
private:
	void RegisterGameObject();
	void RemoveGameObject(GameObject * object);
	std::function<void(PhysicalObject& a, PhysicalObject& b)> OnIntersect;
	Renderer * renderer;
	Physics * physics;
	std::vector<GameObject*> gameobjects;
};

 

Finally, a state manager:

 


class StateManager
{
public:
	void Initialize();
	void Cleanup();

	void ChangeState(GameState* state);
	void PushState(GameState* state);
	void PopState();

	void HandleEvents();
	void Update(float dt);
	void Draw();

	bool Running() { return m_running; }
	void Quit() { m_running = false; }

private:
	// the stack of states
	std::vector<GameState*> states;

	bool m_running;
};

 

I am still working on figuring out how to implement the various functions in this framework, but once I do, I think I'll have a working state machine.

The concept of a state machine does not need to be nearly that complex. 

You can implement a state machine with large objects and virtual functions like that, but it is big enough to be a bad fit in the general case.

You can implement a state machine with a switch statement, each state is a different case label. You can implement a state machine with an if/else tree. Even a bool value is enough to be a state machine, albeit with a single binary state.  State machines are EVERYWHERE in code, and they take many different forms.

 

14 hours ago, frob said:

The concept of a state machine does not need to be nearly that complex. 

You can implement a state machine with large objects and virtual functions like that, but it is big enough to be a bad fit in the general case.

You can implement a state machine with a switch statement, each state is a different case label. You can implement a state machine with an if/else tree. Even a bool value is enough to be a state machine, albeit with a single binary state.  State machines are EVERYWHERE in code, and they take many different forms.

 

This is absolutely true, before attempting what I'm doing currently I have an if/else to determine whether I was in the menu or not. I then just made my game loop update accordingly based on that simple boolean. I would recommend starting this way, but quickly observe how messy things can get when implementing it this way.

This topic is closed to new replies.

Advertisement