Sign in to follow this  
PureSnowX

[Game] Problem with Object cumunication

Recommended Posts

In my current project I'm trying to create an text based rpg engine.
The main classes are: Engine.cs, World.cs, Entity.cs, Event.cs and Dialog.cs

The Engine contains Handlers for handling and processing Dialogs and Events that occures during the game as well as an World object that contains all game data as monsters, player status, rooms ect.
My problem is my Entity's aswell as the battle engine need to be able to push Events and Dialogs inside the queue so that they can be processed by the engine handlers.

So: Engine->World->Entitys->Events.
So I'v been thinking should i add an object refrence to EACH of the games entitys to the Engine object? So that they can access the methods to be able to push events and dialogs inside the queue? It seams quite inefficient :S

But i can't think of another way really...
The Handlers ( Input, Event, Dialog and well World object each gets a refrence to the owning Engine object. ) like InputHandler inputmanager = new InputHandler(this); inside the Engine objects constructor.
The world object also gets this refrence...


Any ideas or tips?

Share this post


Link to post
Share on other sites
What you want is the [url="http://www.dofactory.com/Patterns/PatternObserver.aspx"]Observer design pattern[/url], which allows one to many communications, while keeping the coupling to a minimum.

Here is a C++ [url="http://www.netobjectives.com/resources/books/design-patterns-explained/cpp-code-examples/chapter18"]example of an Observer[/url], but frankly I find the GoF example to be much easier to grok.

Share this post


Link to post
Share on other sites
I use a functor message system.

The uml shows it (my uml is a bit rusty so this might not be correct)
Basicly you have a message dispatcher class where you bind your subscribers.

Entity is a message dispatcher and your components that want to talk to each other are subscribers.
Now you define a message class for every message you want to send here the OnDamageMessage.
Now you bind a receiver function to the entity.
Then when sending a message to the entity its automaticly dispatched to the correct receiver. So that you only get messages with the type desired. This way you don't have to worry about the type of the message bc you already know it.

[img]http://img806.imageshack.us/img806/4596/diagramm1.png[/img]

Share this post


Link to post
Share on other sites
Uh I'm heavily confused :S
I think i need have it explained in context.
I'm programming it in the Console :S

Sorry D: I'm really trying! But i find it hard to wrap my head around design patterns :S recently took inspiration from the Command Design Pattern :3
( Event is an abstract class aswell as Dialog ) :3

Share this post


Link to post
Share on other sites
[quote name='Serapth' timestamp='1313333913' post='4848982']
That is essentially an implementation of the observer pattern. :)
[/quote]

I know but a absolute generic observer system. never said it isn't :)

Share this post


Link to post
Share on other sites
Sorry for my bad grammar! I haven't been on my home computer and my girlfriends desktop has a really small keyboard! :(
Anyways, as I said before this design patters is really hard to wrap my head around :S

So each of my Entities can dispatch ( send ) a message to a Subscriber ( Engine classes EventHandler and DialogHandler that holds the Queue and methods to process them. )
This way i still need to pass an object reference to the Subscribers ( EventHandler and DialogHandler which are components, I think).

This is quite possible in it's current state because InputHandler, EventHandler, DialogHandler and World Object gets an reference to the owner of them ( The Engine object that uses them ) by there constructors inside the Engine class constructor:
[code]
public Engine(GameState state)
{
inputmanager = new InputHandler(this);
dialogmanager = new DialogHandler(this);
eventmanager = new EventHandler(this);
world = new World(this);
}
[/code]

The world contains an Engine owner reference and thus might be able to pass It's registered Event and Dialog Handler to each Entity inside the World object? Rather than passing the whole Engine as an reference it just passes the necessary component as reference?

The Entities can then just access the EventHandler and DialogManager AddToQueue method ( for example: EventReciever.AddToQueue(new MoveEvent(this, "Lost Woods"));
Am i getting this anywhere near right? :)

Share this post


Link to post
Share on other sites
It is pretty common to pass an engine with all the subsytems encapsulated as a method. Hell its common enough for them to be global.

What you have implemented isn't exactly what I described, but it sounds like it should work. Instead of passing a literal string as a param in your AddToQueue, why not pass an object reference instead?

Share this post


Link to post
Share on other sites
Well I'm a beginner ;D so i don't really know whats common and not ( Sorry for being a total noob... ).
I have always thought that the herachy of objects should be in a straight line :S Like

Engine object holds the "World"(Game Data) object, and the "World" object holds the Entity data ( Managed in arrays ).

By passing itself it kinda breaks the straight line of inheritance but i guess that this is not bad practice since it's so common? :o
Oh well by only passing the EventHandler and DialogHandler to the Entities ( By Method or Properties ( Get in C# )) I can at least withhold some kind of encapsulation :)
But Isn't that method kinda memory intensive since all Entities creates an reference object? :o

And how would your method be? Care to elaborate :3?



PS. The AddToQueue was a fictional example i actually pass an location object-reference :)

Share this post


Link to post
Share on other sites
This is one of those things that is nearly impossible to explain in a post, or hell, short of a small book.

But generally ( and yes, there are exceptions, thousands and thousands of exceptions ) you want to decouple your objects from each other as greatly as possible. You also want to keep code as self contained as possible, again, with thousands of exceptions.



A lot of the time when you are designing your classes ask yourself "If I changed this class, how many other aspects would need to be changed as well?" Then go about breaking those dependencies where possible. If two classes don't really need to know about each other, break that dependency. If two classes share 90% of their functionality, derive from a common base class.


On the other hand, you have to let common sense be a factor. One really common reason to abstract away your classes into engines and various components is so you can make switches later. For example, if you are using SDL, but want to be able to switch over to SFML at a later date, it's common to make a Renderer class, and an intermediary class over all the various objects like Bitmaps and Sprites, that both SDL and SFML provide so you can transparently change Renderers without making a code change. Reality is though, for 90+% of projects, this is just an added layer of complication and work that will never ever be used. This is where common sense has to come into play. Yes, from a purely object-orriented perspective, it is a very "pure" design that implementation details are abstracted away. From a practical and getting shit done sense, it's just a stupid waste of time.

This is where we get to the next sticking point and another area where new developers ( and experienced developers! ) get it really wrong most of the time. Global variables. See, when a new developer learns about global variables they seem like a godsend, as then you frankly don't have to design classes at all, just make everything globally available! This in a very short while makes extremely unreadable and maintainable code. Other new ( and experienced developers ) have heard about this and had it drilled into their heads that GLOBALS ARE BAD!!!! and react accordingly. Ironically enough, 9 times out of 10 this seems to always result in the same discovery... the Singleton. If you haven't yet, some day you will discover the singleton pattern and you will think it is the answer to your prayers. It's not a global, it's an object!!! Actually no, it really is just a global with a pretty layer of object orriented goop wrapped around it(**). Then you will encounter another group of people that will yell from the mountains SINGLETONS ARE BAD!!!! Which in the end leads you to engineering half a hundred "Manager" or "Adapter" classes to eliminate your dependencies on global variable and singletons. All the while, no work is getting done on your game.

Now it's time to let you in on a dirty little secret. Globals aren't bad, they are actually pretty frigging useful and important. The most important thing is, DO NOT ABUSE THEM. That is it. Chances are, you are going to have some form of global object, like perhaps a Game, App or World class, this is completely reasonable. On top of that you are going to run into code that needs to be globally accessed, such as your Audio clas or Event class, which is also quite reasonable. It simply does not make sense to pass in an Audio class to say, a GameEvent, because that game event might on occassion need to play a sound. There are quite literally only a handful of things that should be made globally available but if it makes sense to be globally available, make it globally available.

But here is where the design gets tricky again, if you are making something globally available, do not make the relationship two-way, or at least not unless the two-way relationship is completely generic or via an interface. For example, if you have a game engine ( globally available ), and that game engine has a (globally available ) event queue, that at some point a game object needs to add events to, make sure that the event queue has the most absolutely minimal requirement to know anything about the game object and that the game engine itself needs to know absolutely NOTHING about the game object, as this is where your design can start to fall on it's face.

One last general rule of thumb when dealing with globally available classes, make them static whenever possible, it will lead to less potential hazards. Additionally, when make global objects provide access to other global object ( for example Game::SoundManager ), use accessor methods and const whenever possible. Keep all allocation and deallocation specifically in the realm of the containing object.












(**) There are actually more to singletons than just object oriented globals. Yes, Singletons are global in scope but they have a couple very important properties. First of which is deferred allocation, meaning the Singleton isn't using memory until the first time it is used, unlike a traditional static variable. Additionally, a Singleton can be subclassed as a mechanism of providing a single interface to potential disparate code bases, so for example you could have a Renderer::GetInstance(), which is subclassed as OpenGLRenderer or DirectXRenderer, which will provide your code with a single global runtime determined instance. If you don't understand this paragraph, thats completely fine, I'm just throwing it out there as a caveat so my over simplification of a Singleton isn't misleading... they do have their uses.

Share this post


Link to post
Share on other sites
That post was beautiful.... I'll bookmark it!
In short I'm guessing you are trying to say "Just make the damn game and don't worry so freaking much about how you design it, because there is no perfect design"

Thank you so much :3 I'll make sure to re-read it every time before i start to program ;D <3

Share this post


Link to post
Share on other sites
[quote name='Moonkis' timestamp='1313439557' post='4849538']
That post was beautiful.... I'll bookmark it!
In short I'm guessing you are trying to say "Just make the damn game and don't worry so freaking much about how you design it, because there is no perfect design"

Thank you so much :3 I'll make sure to re-read it every time before i start to program ;D <3
[/quote]

Don't read me the wrong way, design is important, but to a point. To a new developer that point is a lot earlier.

Nothing makes a programmer better than writing a ton of shitty code.

Share this post


Link to post
Share on other sites
[quote name='Serapth' timestamp='1313440808' post='4849551']
Nothing makes a programmer better than writing a ton of shitty code.
[/quote]

There is great truth in that statement. I would add "and having to maintain/re-use that shitty code later on."

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