Sign in to follow this  

Organization of Global Variables for my game

This topic is 4583 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

INTRODUCTION _________________________________________________________________________ For my first game I am making a turn based strategy game in SDL , C++. To massivly simplify the idea, think archon (if you dont know this game a) shame on you b) then think chess) meets capture the flag. The gameboard is a 16x10 square board, each team has 10ish units, each unit occupies a square. I am at the stage in development where I can place a unit on a square, and move it to another square at the click of a mouse. Ive got the movement restricted to be confined within the square. I also have a fair amount of interface/structure coded out so I dont have to redo this as Im building the game. Ive spent 95% of the time on this part and think ive developed a fairly flexible system. PROBLEM ---------------------------------------------------------------------- Now my problem is for how to deal with global variables or "game state" variables. EG boolean to store if a unit is currently being selected or the mouse (X,Y)position after a mouse click has taken place. I have come up with two possible solutions , and both present their advantages/disadvantages. SOLUTION1 Keep global "game state"variables in the main file that contains both the event loop and the main method. PROS This is what I typically see on all the tutorials / sample coding that ive read (although their size pale in comparison to my games estimated size), it works easy enough and doesn't convulute the code. CONS since my event loop is in this file, I have a feeling its going to get quite massive in size already by the end of my game. I want to avoid code in this file as much as is reasonable. Also, if I want to call a method say from the "unit" file.. My "unit" wants access to a lot of these global states. I dont want to also store these wanted global states in the unit file because of the extra memory required. So when the game increases in size i'm going to have to keep altering the arguments for these methods in the "unit " file eg unit1->attack(int xPos,int yPos,bool hasFlag........) SOLUTION 2 This is the current solution I have implemented, Keep global "game state" variables in their own class, outside of the event loop and the main method. PROS Solves both the cons of the previous method If I want a method from the "unit" file to acess the game states, I set it up like unit1->attack(GameBoard *board) and I can then access all of the states in the game. Creates massive flexibility and barely any overhead. CONS MAKES THE CODE MASSIVLY CONVULUTED!!!! I instantiate the class like GameBoard * board = new GameBoard(.....); the effect is I have so many board->'s in my event loop its almost silly :( example of it at its worst: if ( event.type == SDL_MOUSEBUTTONDOWN && board->mouseOnBoard()) { if ((board->unitAtCurrentPos() > -1) && (board->selectedID() < 0)) board->setSelectedID(board->unitAtCurrentPos()) ; board->setOldMouseX(board->mouseX()); board->setOldMouseY(board->mouseY()); ----------------------------------------------------------------------------- Conclusion: Im kind of torn between the two, as it is right now the flexibility option number 2 provides seems hard to pass up.... Ive considered a hybrid between the two, but I feel it may confuse me in the future which variables are in the main file, and which are in the GameBoard. Any advice the gurus could offer me would be much apreciated

Share this post


Link to post
Share on other sites
well, I have always used the second method. It may end up with millions of 'board->'s but it keeps it neat and you know where you are going. Added to this, intellisense (if you have it) will bring up all the variables within the class which makes finding what you need a bit easier. It keeps everything within its neat little group. I look grouping things.
With the first method I just found it got really really messy and I kept having to refer back to make sure I spelt the bloody variable correctly.

You have no idea how many 'gConsole->[function/variable]' calls I have within my engines source.

But in the end, using the class system does make everything look far neater and easier to navigate. Well IMHO anyway.

I dunno, go with the one that feels the most comfortable.

Share this post


Link to post
Share on other sites
For some reason, having board->method(board->member...) smells a bit to me. If that method needs state information from the instance on which it is operating, it shouldn't need it as a parameter. If there's some case where it can be something else, then you might prefer to use default parameters.

That alone would make a lot of things tidier...

-Auron

Share this post


Link to post
Share on other sites
actually, yea i didn't notice that [smile]. It shouldn't need to call on its own instance to retrieve variables from itself if that makes any sense whatsoever [wink]

Share this post


Link to post
Share on other sites
Quote:
Original post by Auron
For some reason, having board->method(board->member...) smells a bit to me. If that method needs state information from the instance on which it is operating, it shouldn't need it as a parameter. If there's some case where it can be something else, then you might prefer to use default parameters.

That alone would make a lot of things tidier...

-Auron


basically im equating one variable in my gameboard to another.
Since I am doing this from the main method and the variables are private, I have to use mutators/accessors.

eg

board->setX(board->getSomeOtherX());

which would be defined in GameBoard as
public:
void setX(int x); //{this-x = x;}
int getSomeOtherX(); //returns someOtherX

private:
int someOtherX;
int x;

If I was using my solution 1, I would basically just be doing
x = someOtherX;...

Do you have a suggestion that would alow me not to type
board->setX(board->getSomeOtherX());??

I guess I could create a new method equateX() which provides the same
functionality as board->setX(board->getSomeOtherX())
so I would just use board->equateX();
However, wont this require lots of additonal methods since I have a fair number of variables...

Man this is the first time ive ever had to organize this much code and its quite annoying :P

Share this post


Link to post
Share on other sites
I'm not sure If I understand your problem fully so this might not aply. Why not have a gamestate class that gameobjects have a pointer to. then in your game objects constructor set the pointer the the main and only instance of gamestate.

Share this post


Link to post
Share on other sites
This is the kind of thing that just takes experience to learn. It's also something hard to help you with without seeing to much code. Really it comes down to this. If your using to many set/gets your not writing object oriented code to begin with. Your just making cluttered and over verbose C.

The idea you should concentrate on when creating methods is encapsulation of functionality. A class should completely abstract a single part of your design. The interface to the class should be as simple as possible. Even if this means making "alot of methods."

I'll try to give an example based on the code you posted.


// in event loop
if ( event.type == SDL_MOUSEBUTTONDOWN)
board->onMouseDown();


// in board.cpp
Board::onMouseDown()
{
if (mouseOnBoard())
{
if (getUnit(mCurrentPos) > -1 && mSelectedID < 0)
selectUnit(getUnit(mCurrentPos));

storeMousePos();
}
}


Obviously this wont fit directly into your code, but thats roughly the idea. One thing you should definitely do whereever possible is use a struct for x,y position of units/mouse (like I did for my mCurrentPos), that way you only need to call one function when your passing around position info.

Share this post


Link to post
Share on other sites
A general rule of thumb is to avoid global variables as much as possible.

If you have a set of related variables which are at the program scope, group them together into a Singleton or a static class.

If you have a set of related variables which aren't at program scope, i.e. map, sprite, and weapon data, group them into a class, along with their associated operations.

Also, in general the fewer 'if's and 'switch's there are governing high-level program flow, the better. Illimuni's code example shows an example of what I mean.

Illimuni put it excellently. Pay heed to his post.

BTW: if you think pointer syntax looks ugly, wait till you start writing "true" low-level code, and when you start messing with templates. You ain't seen nothin' yet. Just take a look at the standard library files.

Share this post


Link to post
Share on other sites
First, it is a bad idea to use a class as a collection of unrelated variables. Don't create a class that simply contains global variables.

Second, global variables should be avoided. Do you actually need a global variables to contain the mouse position and the currently selected unit? That seems like something relevant to only an input or player module. Why does the renderer care where you clicked or which is the currently selected unit? And what do they have to do with the state of the game, BTW?

In my chess engine, I have a game state variable, but it isn't global at all. It is the current state of the game and what the players operate on to advance the game. Here is the game state class for my chess engine.
#pragma once


#include "Board.h"
#include "Move.h"
#include "ZHash.h"
#include "Sequence.h"

#include <vector>
#include <queue>

class PieceList;
class Move;
class Piece;

class GameState
{
public:

union CastleStatus
{
struct
{
uint8 castled : 4; // Which castles have occurred
uint8 unavailable : 4; // Which castles are no longer possible
};
uint8 status;
};

GameState() {}
GameState( GameState const & old_state, Color color, Move const & move );
GameState( Board const & board, Move const & move, int value, CastleStatus castleStatus );

// Resets the game
void Initialize( PieceList const & white_pieces, PieceList const & black_pieces );

// Equality operator
bool operator==( GameState const & y ) const;

// Returns true if a castle is allowed
bool CastleIsAllowed( Color c ) const;

// Returns true if a king-side castle is allowed
bool KingSideCastleIsAllowed( Color c ) const;

// Returns true if a queen-side castle is allowed
bool QueenSideCastleIsAllowed( Color c ) const;

// Updates the game state with the specified move
void MakeMove( Color color, Move const & move );

// Returns the hash code for the state
ZHash GetHashCode() const;

Board m_Board; // The board
Move m_Move; // The move that resulted in this state
int m_Value; // Value of the game
int8 m_Quality; // Quality of the value
int8 m_Priority; // Priority of this state (determines sorting order)
CastleStatus m_castleStatus; // Which side has castled and which castles are still possible
bool m_bInCheck; // True if the king is in check

private:

// Updates the game state with a normal move
void MakeNormalMove( Color color, Move const & move );

// Updates the game state with a castle move
void MakeCastleMove( Color color, Move const & move );

// Updates the game state with a pawn promotion (after moving). Returns the new piece.
Piece const * Promote( Color color, Position const & position );

ZHash m_HashCode; // Hash code for this state

// Returns the queen of the specified color
static Piece const * GetQueen( Color color );

static Piece const * m_pWhiteQueen;
static Piece const * m_pBlackQueen;
};

Share this post


Link to post
Share on other sites
Quote:
Original post by Kryodus
Do you have a suggestion that would alow me not to type
board->setX(board->getSomeOtherX());??

I guess I could create a new method equateX() which provides the same
functionality as board->setX(board->getSomeOtherX())
so I would just use board->equateX();
However, wont this require lots of additonal methods since I have a fair number of variables...

Man this is the first time ive ever had to organize this much code and its quite annoying :P


the equateX() method should be a good idea. Consider the advantages:

1) reading the code which use this function is easier, because equateX() contains more semantic value then obj.setX(obj.getAnotherX()).
2) nothing forbids you to write obj.setX(obj.getY()), which is wrong. Don't trust the programmer which will use your library; even if you are this programmer. You don't know if you'll be able to understand this code next year.
3) the code equateX() is correctly encapsulated. You can do whatever you want in equateX(), you can even completely change the way it works. You can do setX(getAnotherX()/2) for example, without needing to modify neither setX() not getAnotherX().

A good encapsulation of data is a good base for a proper OO design.

Regards,

Share this post


Link to post
Share on other sites
Thanks you guys have been a major help, never truly had to structuce large amounts of code before so a lot of this stuff never arose..

I havent really read any tutorials on how to structure a games code, ive basically been doing it from general principles and have found myself getting into a web i never envisioned myself in.

How did you guys learn to structure your code?
You know of any full game source code avaiable that you think would be a good learning tool?

All the tutorials ive read dont really focus on organization of an entire game. Just little parts of one.

[Edited by - Kryodus on May 26, 2005 11:28:19 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Kryodus
basically im equating one variable in my gameboard to another.
Since I am doing this from the main method and the variables are private, I have to use mutators/accessors.

eg

board->setX(board->getSomeOtherX());

which would be defined in GameBoard as
public:
void setX(int x); //{this-x = x;}
int getSomeOtherX(); //returns someOtherX

private:
int someOtherX;
int x;

If I was using my solution 1, I would basically just be doing
x = someOtherX;...

Do you have a suggestion that would alow me not to type
board->setX(board->getSomeOtherX());??


Not only do I have a suggestion, but I have a claim that fixing this exact problem is one of the fundamental concepts of OO design.


// in GameBoard
public:
void setXToSomeOtherX; // { x = someOtherX; }


However, you need to be able to give this method a name that describes the real purpose, as opposed to just the mechanics. Otherwise, there is something wrong with your abstraction somewhere else.

Quote:
I guess I could create a new method equateX() which provides the same
functionality as board->setX(board->getSomeOtherX())
so I would just use board->equateX();
However, wont this require lots of additonal methods since I have a fair number of variables...


Oh, I should read ahead ;s Basically, it sounds like you're worried about creating O(n^2) methods all for setting one variable to another. What are these settings supposed to accomplish, exactly? Something seems to be seriously wrong with your design and abstractions. Please post some of your code so that I can tell you something more meaningful.

Quote:
Man this is the first time ive ever had to organize this much code and its quite annoying :P


The solution to this is to organize as you go. Now you've learned your lesson. ;)

Share this post


Link to post
Share on other sites

This topic is 4583 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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