Sign in to follow this  
Sanctux

Repetitive Ctors in Game States

Recommended Posts

states.h
#ifndef STATES_H
#define STATES_H
#include <hgeresource.h>

class State abstract
{
public:
	State(HGE& hge, hgeResourceManager& resources) : hge(hge), resources(resources) {}
	virtual bool Logic() = 0;
	virtual bool Render() = 0;
	void Pause();
	void Resume();

private:
	HGE& hge;
	hgeResourceManager& resources;
	bool paused;
};

inline void State::Pause() { paused = true; }
inline void State::Resume() { paused = false; }

class PauseState : public State
{
public:
	PauseState(HGE& hge, hgeResourceManager& resources) : State(hge, resources) {}
	bool Logic();
	bool Render();
};


class IntroState : public State
{
public:
	IntroState(HGE& hge, hgeResourceManager& resources) : State(hge, resources) {}
	bool Logic();
	bool Render();
};

#endif




For my system of game states, I pass references to an HGE and an hgeResourceManager to use in the States. I was just wondering about the constructors; they seem a bit repetitive. Would I have to type a constructor with those same arguments and same initilization lists each time I write a new state? Also, is this an efficient method? Should I really pass a reference to the HGE and the hgeResourceManager to every State? Is there a better way? Thanks in advance! :) [Edited by - jpetrie on July 24, 2009 2:36:35 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Sanctux
Would I have to type a constructor with those same arguments and same initilization lists each time I write a new state?
Yes and no. Constructors can't be inherited so you will have to have constructors that take those arguments but that's not to say they'll be the only arguments, each derived class might need some addition construction parameters too don't forget.

Quote:
Also, is this an efficient method? Should I really pass a reference to the HGE and the hgeResourceManager to every State? Is there a better way?
Usually if you want to share ownership to something then you'd use shared smart pointers rather than references as it might be possible that the HGE system and resource manager are destroyed before the states, which would leave dangling references.

I would probably opt for a design that doesn't involve passing around those references in the first place, for example your Render function could return a list of the things it wants to render, that way it doesn't need to access the HGE system itself.

Share this post


Link to post
Share on other sites
Thank you for your speedy reply!

Quote:
Usually if you want to share ownership to something then you'd use shared smart pointers rather than references as it might be possible that the HGE system and resource manager are destroyed before the states, which would leave dangling references.

Oh, alright, thanks for the enlightenment.

Quote:
I would probably opt for a design that doesn't involve passing around those references in the first place, for example your Render function could return a list of the things it wants to render, that way it doesn't need to access the HGE system itself.

What if I need the hgeResourceManager in order to load resources in the state and manipulate them?

Here's what I have:
Game.h

#ifndef GAME_H
#define GAME_H
#include <hge.h>
#include <hgeresource.h>
#include <stack>
#include <boost/shared_ptr.hpp>
#include "States.h"

class Game
{
public:
Game();
~Game();
void Run();

private:
static bool FrameFunc();
static bool RenderFunc();
static Game* game;
bool Logic();
bool Render();
HGE* hge;
hgeResourceManager* resources;
std::stack<boost::shared_ptr<State>> states;
};

#endif



Game.cpp

#include "Game.h"
#include "States.h"

Game* Game::game = NULL;

Game::Game()
{
game = this;
hge = hgeCreate(HGE_VERSION);
hge->System_SetState(HGE_FRAMEFUNC, FrameFunc);
hge->System_SetState(HGE_RENDERFUNC, RenderFunc);
hge->System_SetState(HGE_WINDOWED, true);
hge->System_SetState(HGE_USESOUND, false);
hge->System_SetState(HGE_TITLE, "Bong");
hge->System_SetState(HGE_LOGFILE, "analysis.log");

hge->Resource_AttachPack("data.paq");
resources = new hgeResourceManager("resources.res");

boost::shared_ptr<State> intro(new IntroState);
states.push(intro);
}

Game::~Game()
{
hge->Release();
delete resources;
}

void Game::Run()
{
if (hge->System_Initiate())
{
hge->System_Start();
}
else
{
MessageBox(NULL, hge->System_GetErrorMessage(), "Error", MB_OK | MB_ICONERROR | MB_APPLMODAL);
hge->System_Log("%s", hge->System_GetErrorMessage());
hge->Release();
}
}

inline bool Game::FrameFunc()
{
return game->Logic();
}

inline bool Game::RenderFunc()
{
return game->Render();
}

bool Game::Logic()
{
return states.top()->Logic();
}

bool Game::Render()
{
return states.top()->Render();
}



In implementing your suggested method, in bool Game::Render(), should I get a vector of objects returned from states.top()->Render() and iterate through it, rendering each one? Or am I totally off here? :P

Share this post


Link to post
Share on other sites
Quote:
Original post by Sanctux
Quote:
I would probably opt for a design that doesn't involve passing around those references in the first place, for example your Render function could return a list of the things it wants to render, that way it doesn't need to access the HGE system itself.

What if I need the hgeResourceManager in order to load resources in the state and manipulate them?
I was ever so tired when I wrote that so it doesn't accurately express my intention.

Let's split the problem into two halves: One half is that you're passing in the manager itself, and the other is that you're then storing a reference to it whilst the object persists.

Now, if your system is small-ish then passing a resource manager is a perfectly fine solution - I'd do it too - and in that case you can stop here and skip this paragraph, the suggestion that follows would just add unneeded complexity. If designing a large-ish or OO-strict system then I would apply the Interface Segregation Principle (ISP), this requires you to ask the question "What resources does a state really require?". If the answer is, let's say, "it just needs sprites", then you make a ISpriteFactory interface class that provides just the interface for creating sprites and requests get sent back to the underlying resource manager. States then deal with the factory's slim and possibly more-friendly interface rather than the manager's fat and unrefined interface.

To tackle the second half of the problem, it seems likely that you can have the state constructor make requests for all its required resources from the manager/factory and hold on to those directly - no need to store the manager/factory at all. If resources need to be created dynamically during the lifetime of the state object then the manager/factory can be passed as a parameter to, say, the Logic function. In this this though, storing it by shared pointer wouldn't be an unreasonable solution either, just not the one I would pick. The ISP is likely to be applicable here too though: "Why does it need to request resource dynamically?", response: "When firing bullets", solution: Create an IBulletDispatcher to handle the mucky sprite aquisition and bullet registration.

Quote:
In implementing your suggested method, in bool Game::Render(), should I get a vector of objects returned from states.top()->Render() and iterate through it, rendering each one? Or am I totally off here? :P
Yes that's right, in this case you're using the return boundary of the Render function to hide the exact nature of rendering from your states and you're keeping the actual rendering work centralised somewhere else. That's just one way though. You could have the vector be passed in via reference, the difference is that the vector might already be partially populated with other stuff that needs rendering, and it might go onto be further populated with yet other things.

From there you can begin considering whether you actually need to have the render function re-submit what is largely the same stuff over and over from one frame to the next, perhaps you can build an abstraction around the vector and turn it into a registration system, only newly visible renderables are registered inside the render function, invisible renderables are unregistered and all other items simply persist from frame to frame. I don't know much about HGE though, perhaps something already exists that you could use for this purpose.

Share this post


Link to post
Share on other sites
Thank you so much for sharing your wisdom.

I am actually writing a Pong clone. I have already written one in the past, but it was absolutely terrible and it was flooded with globals (disgusting!); I didn't take advantage of the features that OOP can provide. I'm remaking it again so that I may learn from OOD. However, I think my game is obviously simple enough to pass my HGE object and resource manager by reference.

For the sake of knowledge, I decided to write a short bit in order to attempt to apply the Interface Segregation Principle. From what I can understand, multiple inheritance is usually the way to go?

If I have a Phone class, but for some reason, I would like to have it capable of self destructing, would something like this follow the Interface Segregation Principle?


class SelfDestructing abstract
{
public:
virtual void SelfDestruct(int milliseconds) = 0;
};

class Phone
{
public:
void Call();
};

class SelfDestructingPhone : public Phone, public SelfDestructing
{
public:
void SelfDestruct(int milliseconds)
};



As an aside, I've got a stylistic question. Prefixing type names is a form of Hungarian notation, but I disagree with the argued benefits of Hungarian notation, especially with, say, member variables. However, I think adopting Hungarian notation specifically for type names might actually be helpful after reading this post. The thing is, I don't think it's a good thing to be inconsistent, and it's either go full Hungarian notation or don't use it at all. I'm a bit conflicted; would it be wise to use Hungarian notation just for type names and not for anything else, or would that cause more harm than good? For example, would it be helpful if I named a class ISelfDestructing rather than SelfDestructing, so that I can instantly differentiate between
class SelfDestructingPhone : public Phone, public ISelfDestructing {};
// Obviously an interface

and
class SelfDestructingPhone : public Phone, public SelfDestructing {};
// Still obvious, but that's because of the way I named it, which brings me to another point:
// Rather than prefixing a type name with 'I', what about naming the classes as adjectives or adverbs?



HUGE thanks again for your great help!

I apologize if it seems like I'm just hurling questions; I'm a zombie and knowledge is my human flesh. :D

Share this post


Link to post
Share on other sites
On the issue of Hungarian-style prefixes, the common "microsoft-style" notation where Variables are prefixed with abbreviations for their built-in types, its actually a complete mis-use of how hungarian was originally intended, and adds no useful information that modern intellisense does not already provide.

In "microsoft-style" hungarian, you would see things like lpiCount -- a long pointer to an integer. Hungarian notation was originally intended not for this type notation, but to remind the programmer of how that variable was being used, where you would see something like spdPlayer or cntBaddies -- abbreviating speed and count, and its entirely likely that these variables might have the same underlying type (integer, for instance). Hungarian notation was intended to add another layer of information, beyond simple type, to help the programmer out. If you've ever done any physics or other scientific calculations, you can think of the proper use of hungarian notation as "units" (meters, kilograms) rather than "types" (integers, reals).

Personally, although hungarian notation has gotten a much worse wrap than it deserves due to this confusion, I believe that appropriately verbose variable names are probably a better solution; the few keystrokes it saves simply aren't worth the savings and potential confusion -- that said, I do use appropriate, common abbreviations often, eg ID instead of Identifier.

I also use some prefixes where they add clarity to my code -- I place an "I" in front of my interface classes (but no "C" in front of regular classes), I put an "E" in front of enumerations, etc. For variables, I prefix based on scope. For instance, member variables begin with a small "m" (mSomeVar), and the rare instance of a global is prefixed with a "g" (gGlobablVar). I don't prefix function parameters or local variables.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sanctux
For the sake of knowledge, I decided to write a short bit in order to attempt to apply the Interface Segregation Principle. From what I can understand, multiple inheritance is usually the way to go?
MI is one way to go, see the Separation Though Delegation section for another. MI is perhaps more common because it's often simpler to implement - simply derive from a base interface.

Quote:
If I have a Phone class, but for some reason, I would like to have it capable of self destructing, would something like this follow the Interface Segregation Principle?

*** Source Snippet Removed ***
Technically it does because SelfDestructingPhone's interface has been separated by the abstract SelfDestructing base class. Whilst Phone does add to the interface of any deriving classes they can't be substituted and used polymorphically as a Phone without slicing, which in turn may be a violation of the Liskov Substitution Principle (LSP). For this and other reasons it's generally a bad idea to inherit from a concrete (by this I mean a non-purely-virtual, so non-instantiatable) class. As a result the application of MI in this case counts for nothing and this is more an example of ISP via single inheritance (really a special case of MI anyway).

A more appropriate example of using the ISP for this might be:

class SelfDestructable // by the by 'abstract' is not a normal C++ keyword,
{ // it is a Microsoft C++/CLI extension.
public:
virtual void SelfDestruct(int milliseconds) = 0;
virtual ~SelfDestructable() = 0;
};

class Callable
{
public:
virtual void Call() = 0;
virtual ~Callable() = 0;
};

// A regular callable device: the phone
class Phone : public Callable
{
public:
void Call();
~Phone();
};

// A self destructing callable device: a self destructing phone
class SelfDestructingPhone : public Callable, public SelfDestructable
{
public:
void Call() { p.Call(); } // Calls just like a normal phone
void SelfDestruct(int milliseconds);
~SelfDestructingPhone();

private:
Phone p; // Inheritence != for code reuse; Composition == for code reuse
};


In this example we have segregated the interface using two abstract base classes, clients that deal with callable devices can use one interface, clients that deal in things that self destruct can use the other - this is the ISP.
Phone still remains a concrete class because we want to be able to make objects that are normal phones. Being a concrete class however means that self-destructing phones don't inherit directly from it because this would complicate matters, see Item 33 for a detailed explanation as to why. Not to mention that inheritance for the sake of code reuse isn't a good use of inheritance in the first place, composition is more appropriate for this.

Quote:
I don't think it's a good thing to be inconsistent, and it's either go full Hungarian notation or don't use it at all.
It may not be inconsistent if you use your chosen subset of Hungarian Notation in a consistent way.
I'm in partial agreement with your linked article, the I-prefix can be useful as can scope-based suffixing, the rest is entirely useless these days.

Quote:
For example, would it be helpful if I named a class ISelfDestructing rather than SelfDestructing
When making posts on the forums, in particular when it's to someone who is using Pascal/Camel case in code they've already provided - such as yourslf - I tend to switch and use the style they use, for their convenience. When doing that and introducing a new class name, not as code but as part of a sentence, I often use the I-prefix to more succinctly express what the class is meant to be by design.

In my own code I use the standard_library_naming_convention, so I barely use prefixes at all save for the rare occasion where I really want to name a member variable the same thing as a member function for some reason. I would have no problem writing code that uses the I-prefix and scope suffixes throughout the code base though. Anything more than that and I would probaly begin to get dizzy.

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