Sharing Data Across GameStates

Started by
3 comments, last by Alberth 8 years, 3 months ago

I'm creating an RTS game where players can click on a missile pod. When selected, an upgrade menu shows to upgrade the missle pod with more missiles and at the same time they can right-click places on the map to shoot the missiles out of the selected missile pod. I'm trying to manage the best way to relate this data.

//base class

class GameState()

{

virtual void Run() = 0;

};

class GameState_Play // High level view of the running game.

class GameState_In_Game// Performs basic things like adding resources over time, performs input for GUI and world (this selects buildings)

class GameState_Upgrade_Menu // Drawing and Input for upgrade menu based on selected object

class GameState_Selected_Object_Actions // Shoot misiles, assign kill orders etc.

So I'm thinking of the best design here because there seem to be a lot of options. Right now all my gamestates can perform sub-tasking GameStates. GameState_Play can be running the GameState_Upgrade_Menu() while also drawing the GameState_Paused() etc.

#1: GameState_Play knows about the selected object and Invokes 2 new game_states: the upgrade menu and the selected objects action. Each of those states receives the selected instance so it knows what actions/menus to display.

#2: Selected object knows it is selected and in it's own update Loop, checks input itself to determine attack orders etc. The GameState_Play invokes the Upgrade Menu.

#3 Selected object knows it is selected and can shoot missiles as well as invoke the upgrade menu itself.

#4... other options.

I personally like #1. The upgrade menu is directy invoked by the game. The selected object knows nothing of the concept of being selected. It is simply given commands from the game.

Secondly though, I have a setup function where you have to place 3 bases before the RTS game starts. So I have GameState_Init and GameState_Play. Both have to render the world, and both have to be able to draw an item where the mouse is located before the player places the purchased item. I'm trying to figure out where to stick this function DrawPurchasedItem() so that either they both have the ability to use it, or figure out how they should interact if GameState_Play is the only one allowed to draw stuff.

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

Advertisement

I am not entirely sure where you are trying to go for this, it could just be wording. But it seems that you might be going about things the wrong way. Which will lead you to head ache after headache when you add new content. It's probably best if you go for an Object Oriented approach mentioned some time ago by L. Spiro on the forums. You will want to read this first, before looking ahead to the an academic explanation.

http://lspiroengine.com/?p=351

If you have ever done a bit of software engineering, you'll learn some efficient methods for UI that will work well in games. It will require quite a bit of set up to get it to function correctly. But by design, they are incredibly efficient and need very little code after set up.

So... theoretically for an RTS you will have multiple types of items the User will be able to select from. GUI, Friendly Units, Enemy Units,. And each one of those can have an infinite series of unique cascading events for what ever the user does.

Typically, you will break it up with that in mind. So... the class that controls what you select should not care about what each class can do. It's main job is to invoke.

Each object that can be selected, will have information about what it can and can not do, and will relay responsibilities to other systems.

So... We select an object with a Selection class.

This class has meta information installed to control details.
An Enum with information on what it is. So... if it is an Enemy Unit it needs to be known here.

Then any information that had been tacked on with a composite needs to be passed on from here.

When we enter the new game state... Upgrade Unit: you pass on your selected unit's class via pointer through the method mentioned on L. Spiro. And from here, you can do what you need to do.

For details such as pausing... pausing is a state... but it is a state that does not need any information about the game play. You only need to hold onto the previous frame, and relay. However... it won't do you any good if you threw away your old information. Even if we aren't pausing... you may wish for things to continue updating. So... you may want a processing stack.

In case you don't know the details of a stack. First in Last out. Like a deck of face down cards, the first one to come off of the stack is always the top.

Example

First:
Game Simulation.

Game is ticking. User selects soon selects a unit. When a unit is selected, a new state has been created with data being passed to the next state in the stack.

Second

Upgrade Unit
Game Simulation.

When the upgrade Unit state has been created, we create the GUI and create a plane in the game data to allow the mouse to interact. As this state is processed, it reads a pointer that had been given to it by the Game Simulation, and shows information and processes functions on it's turn. Also, being able to upgrade a unit on time is pretty critical in an RTS. Which means it needs to take priority in a stack. But as the Unit is selected in is in the upgrading screen, the game is allowed to continue.

Third:

Pause
Upgrade Unit
Game Simulation

Pause is holding onto a pointer for your game data. We may wish to save and continue at a later date. But it's also holding onto the last frame, and rendering an overlay on top of it. Because Pause is an interuption, it prevents all previous data from being processed, and force the game to loop back without updating anything below it.

Fourth

Main Menu | Initiated
Pause | Deleted
Upgrade Unit | Deleted
Game Simulation | Deleted

While the game is paused, the user wanted to go back to the main menu without saving. Everything below the state in the stack is now deleted, and we are back to the main menu. You may also wish to create a fade in.

For details such as pausing... pausing is a state... but it is a state that does not need any information about the game play.

Well think in Call of Duty or any shooter game where you have an options menu. It doesn't pause the game, the game keeps running and you can die. So would you treat that as a separate state, where both states draw the world, or would you treat the options menu as simply a sub-state that runs during the Play state.

Well my problem that I explained not so well would be to recreate this scenario:

You have a GameState that makes you place 3 bases before any gameplay starts and you can't purchase items or anything.

So I have a function that can show you the placement of a building called "DrawPurchasedItem()". Now given in this example I have a GameState_Play and GameState_PlaceBases. Both states DrawPurchasedItems, one does it at the beginning and purchases 3 bases for the player upfront. THe Play state just waits for GUI stuff to happen and notify something was purchased.

I have 2 options:

#1.) Have GameState_BasePlacement and GameState_Play run at the same time. Where GameState_PlaceBases simply manipulates some data that the GameState_Play state picks up: IE a pointer to an item that was purchased.

or

#2.) Allow only one state to run at a time. Both states need to draw the world and also to DrawPurchasedItems().

I feel like only the actual running game state "Play" should be allowed to DrawPurchasedItems. What do you think?

NBA2K, Madden, Maneater, Killing Floor, Sims http://www.pawlowskipinball.com/pinballeternal

It's easier if you think of it like this. Game states will not run at the same time. They just run in a sequence. When you wish to run something at the same time, the states exist in a line up for the update. So... you are technically doing both. It's just Number 1 is the option you want for your situation.

So... when the game starts you need to place bases at the start. If you are trying to avoid a lot of if statements, the BasePlacement will remain a state. But because it also effects the game world, you need to think about your states and data a bit more. And what each state is doing.

GameState_Play in this case is handling most of your simulation behind the screen. And it also handles rendering queries... so it needs to exist as well. Just have a flag that prevents this state from doing any updates outside of certain animations.

If we create data at the very start of the game, we can just pass that data onto our states, and it will be edited as needed.

So... here's what it looks like

First
GameState_BasePlacement :This continues to loop till the game is ready to be played. Handles the Base Placement phase. Logic, and UI will probably be in here.

GameState_Play: Handles Rendering of game assets and Animations while it waits for the game to start. It continues to recieve data from the previous state. and passes it on for the next loop.

Second: The game is now starting.
GameState_BasePlacement: Now finalizing and deleting it's self from the stack.
GameState_Play: Noticed it's pause_simulation flag is off, and lets the game tick.


I feel like only the actual running game state "Play" should be allowed to DrawPurchasedItems. What do you think?

Don't draw from the game states. You can submit rendering queries... but don't let the state themselves draw anything. This is completely outside of the scope of what they are supposed to handle.

You -can- run a rendering state. But that is redundant as it's not a state in logic. It's just part of a sequential process. This will be built into your main loop and be more determined.

In my current set up, my states are ran in a manner similar to what I've told you, after getting rid of singleton hell. The Simulation State is handles most of the game logic.

But I have states for things like inventory, pausing, saving, and menus for organizational reasons. Their main purpose is handling logic. But they do also submit items to the rendering queue to be sorted for later. Anything other than Simulation, only handles UI when submitting to the rendering backend.

What exactly is "GameState" to you? Is it a thread?

A "state" is, in general, a current activity or mode, eg "paused game", or "playing game", or "selecting game from missions".

You do this as the only activity, while your "states" all seem to run at the same time.

This topic is closed to new replies.

Advertisement