Thread: Game design question

  1. #1
    Registered User
    Join Date
    Oct 2006
    Location
    UK/Norway
    Posts
    485

    Game design question

    I am just wondering about "how global" I should make the different parts of my game.

    One of my lectures talked about making a class global, while making sure that only one instance of the class can be created. I think its called singleton design or something?

    Should I make all parts of my "game engine" like this? So the draw class is global, sound class, input class and so forth.

    Thanks

  2. #2
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    From my experience. No.

    Singletons are bad news.

    I was like, hey, sounds like a great idea!

    But then I realized that there are fundamental flaws with Singletons.

    they return a Static instance, which is still a global in disguise

    With a singleton, you will have to initialize, and deinitialize every time you use it. (for ALL of the data members, every single time)

    Without a singleton, you can new it, then delete it

    if you look 1 post down, I toiled over that issue for 2 hours only realizing that even testing in the global scope is unsafe, due to the fact that I was trying to do things that were being initialized in other classes/procedures that had not even occurred yet!

    I think a game engine should be just that, an engine, not a compilation of tools.

    Instead you may want to do something like this instead.
    Code:
    class engine
    {
    public:
    
    virtual game logic function
    
    engine(RenderStuff * See, PhysicsStuff * Feel, SoundStuff * Hear, IOStuff * Interact);
    private:
    rStuff * See; // methods for drawing stuff
    PhysicsStuff * Feel;   // methods for physics calcs
    SoundStuff * Hear;   // methods for playing sound and msuic
    IOStuff * Interact;    // methods for talking to your game, and methods for it to talk back.
    
    All the methods for connecting each of those game components, like tieing physics to what will actually be displayed on the screen.
    Like connecting sounds
    all the methods dealing with loading/unloading resources
    memory management
    
    protected:
    all the resources your engine will ever need in a game engine(in containers)
    };
    As you can probably tell that was pseudo pseudo code. Probably a few design issues with that even, but you get my drift, you can always work around a singleton, they have no use.

    Another thing to note:

    Ask yourself, do you really only need one?
    Think about internet play, when instead of Main or WinMain you have ServerMain
    And alluva sudden each connection needs a copy of these objects.
    Singletons will fail.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  3. #3
    Registered User
    Join Date
    Oct 2006
    Location
    UK/Norway
    Posts
    485
    Are they really that bad? Right now I have my Draw class as a singleton (loads and draws sprites)

    In the marking for the module you get points for good design, such as using singletons.

  4. #4
    Registered User
    Join Date
    Nov 2005
    Posts
    673
    I wouldn't say they are that bad, but there are better(much) ways than singleton.

  5. #5
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Sigh, schools.


    Bottom line. No, they aren't that bad, they're incredibly simple to code.

    Fine print: You can do things more efficiently without them, here was my experience.

    I was trying to create a game that utilized gamestates and a state manager.

    My initial thought was singletons for the gamestates.

    I could switch my gamestates by going StateManager.ChangeState(Playstate::Instance());

    I thought it was the most nifty and convenient thing ever.

    Until I started having trouble with switching between gamestates. Since the gamestates are singletons I had to make sure all the variables that are needed in that gamestate are loaded in the initialization

    ALSO I had to make sure I didn't re initialize stuff already created in other gamestates, take switching from a menu state to a playing state in a blackjack game.

    I could A, start a blackjack game without a profile (Quick game)
    or B, select a profile and play the game with that.

    If we were to select quick start we had to make sure that the play state initialized a kind of temporary profile.

    If we were to select a profile we had to make sure that this didn't happen.

    Leading to heavy nesting of if's and elses (or a long switch) in the initialization of the gamestate instance.

    Now we have to think about deinitializing our static gamestate, since we aren't starting from scratch (like we would without a singleton) I also have to make sure I deinitialize only the things I need deinitialized, I had to match the nested if's and elses and/or switches in the deinitilization function as well.

    without a static gamestate, I can switch my gamestates like this:

    state_manager->change_state(new Play_State(state_manager, game) );

    Then when we move to the next state, all we have to do is call the destructor.

    Now we have a uniform startup procedure.

    If you take notice, I also pass the gamestate a few variable now, unlike before.

    To get information between states I can refer back to my game engine.

    Code:
    class Play_State : public Gamestate
    {
    public:
    	Play_State(State_Manager * state_manager, Card_Game * game);
    	void update();
    	void print();
    	void handle_events();
    };
    #endif
    That is my non static gamestate. I create it, I delete it. I modify those 3 functions, done.

    This is my Engine class:

    Code:
    #ifndef GAME_H
    #define GAME_H
    #include <vector>
    #include "Player.h"
    #include "Hand.h"
    #include "Deck.h"
    #include "Setting.h"
    #include "Resource_Manager.h"
    
    
    class Card_Game
    {
    public:
    	Card_Game(){}
    	~Card_Game(){}
    
    	virtual void turn_logic(std::string player_id);
    	
    	
    protected:
    	int calculate_winnings();
    	void initialize_players();
    	// Give player id a new hand
    	void give_player_hand(std::string player_id);
    	void shuffle_deck(int deck_id);
    	// Draw how_many cards to player id's hand_id from deck_idntyd
    	void draw_card(std::string player_id, int hand_id, int deck_id, int how_many);
    	void place_bet(std::string player_id, int bet);
    	// Split player's active hand
    	void split_hand(std::string player_id, int hand_id);
    	// check if hand value > check_value
    	bool check_hand_value(std::string player_id, int hand_id, int check_value);	
    
    	Resource_Manager< Player > m_rPlayers;
    	Resource_Manager< std::vector<Hand*> > m_rHands;
    	Resource_Manager< int* > m_rBets;
    	Resource_Manager< Deck* > m_rDecks;
    	Resource_Manager< Setting > m_rSettings;
    	std::vector< Deck* > m_vDeck;	
    
    };
    Granted that I'm working in a console project, and there are no perty pictures, you don't see the pointers to the renderer or the sound or the physics, but the principle is the same.


    And this is what my Main function looks like:

    Code:
    				srand ( unsigned(time(NULL)) );
    				Blackjack_Game * game = new Blackjack_Game();
    				game->init();
    
    				State_Manager * state_manager = new State_Manager;
    				state_manager->change_state(new Play_State(state_manager, game) );
    				*/
    
    				/*
    				while ( state_manager->running() )
    				{
    					state_manager->update();
    					state_manager->print();
    					state_manager->handle_events();
    				}
    
    				game->cleanup();
    Look ma, no singletons!

    Here is a snippet of my playstate initialization function as of the singleton era:
    Code:
    void Play_State::init(Card_Game * game)
    {
    
    	if (game->m_betting_toggle == false)
    	{
    		// init Players
    		if( game->m_load_new_players == true )
    		{
    		}
    		// init hands
    		game->m_players[0].new_hand();
    		game->m_players[1].new_hand();
    	}
    	// init Deck
    	game->m_deck = new Deck;
    	// shuffle deck
    	game->m_deck->shuffle_deck();
    	// draw cards for players
    	game->m_players[0].draw(0, game->m_deck, 2);
    	game->m_players[1].draw(game->m_players[1].m_active_hand, game->m_deck, 2);
    
    }
    Now, that's not as bad as it was before when I was actually using that function, I think there was maybe twice as much code.

    And to make it work properly, and move easily to the next state I had to have an equally or even more complex deinitialization function. Considering that some of the data generated within the handle_events function of the play state had to carry over to the next state, things like winnings and such.

    Now we have this init function:

    Oh wait, there isn't one, only the constructor!

    All the pertinent information is stored in the game engine, so all states will have access to it.

    EDIT:

    To sum it up,
    Use globals only when the class or variable or function will be used EVERYWHERE (which happens almost never)
    Use Statics (or singletons) only when you're absolutely positive you will only need one instance in your project, even then I think the extra task of initialization /deinitialization for each singleton is too much hassle.
    Last edited by Shamino; 02-27-2008 at 04:46 PM.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

  6. #6
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I will disagree with the argument that Singleton's are bad. They are perfect for objects that manage other objects/resources. So they are great for classes that manage or wrap access to containers. The topic of Singleton's has been thoroughly researched and most of the pitfalls can be avoided by a few lines of code. It is difficult to guarantee your object will only have 1 instance in a multi-threaded application but if you use mutexes you can easily solve this rare race condition.

    A singleton is a global of sorts, however, it is still wrapped up in an object and therefore in my book does not violate object oriented code.

    The argument that you can't new or delete a Singleton doesn't stand up. Since Singleton's contain a static instance they are automatically cleaned up. Static's are guaranteed to be cleaned up by the compiler when the app exits. The 'new' in this case occurs when you call getInstance() for the first time (in some types of Singletons). Some Singletons do not use a new to create the instance. There are several different approaches to creating Singletons and instantiating them and I invite you to explore all options and choose which one best suits your particular situation.

    Going hogwild on Singletons is probably not the best idea or best design but that is a whole different topic. In your game engine you really want to separate the game data from the engine code that operates on the data. A good starting point is to look at your game using the doc/view architecture. The document is the data and the view is the graphics. The view is really just presenting a visual representation of the document. So when the document changes the view also changes. You would not want to alter the view and then alter the document to match.

  7. #7
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    The lesson is, like all design ideas/theories, they all have their place.
    Sometimes I forget what I am doing when I enter a room, actually, quite often.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. PC Game project requires c++ programmers
    By drallstars in forum Projects and Job Recruitment
    Replies: 2
    Last Post: 02-22-2006, 12:23 AM
  2. Game Designer vs Game Programmer
    By the dead tree in forum Game Programming
    Replies: 8
    Last Post: 04-28-2005, 09:17 PM
  3. another text game question
    By Unregistered in forum Game Programming
    Replies: 4
    Last Post: 03-09-2002, 11:02 PM
  4. Text Game Question
    By Unregistered in forum Game Programming
    Replies: 4
    Last Post: 03-08-2002, 04:55 AM
  5. Im a Newbie with a graphics design problem for my simple game
    By Robert_Ingleby in forum C++ Programming
    Replies: 1
    Last Post: 11-23-2001, 06:41 PM