Is this a circular dependancy?

Started by
15 comments, last by Sevans 17 years, 9 months ago
THIS THREAD HAS CHANGED FROM A PREVIOUS ONE, PLEASE SCROLL DOWN TO MY NEXT POST THAT IS HEADED LIKE THIS ONE. ---------------------------------------------------------------------------- I am programming a small text based game. I have a Game class, which stores a list of GameCharacters. Each GameCharacter is assigned an ActionScript. The ActionScript object acts as an AI for the GameCharacter. Since the ActionScript needs to make informed decisions, it needs to know of the goings on in the Game, so it needs the game object to run method calls on. As of now, I have a circular dependency: Game--includes-->GameCharacter--includes-->ActionScript-->Game And it works, but I am not all to sure how lol... I am looking for a way to get rid of this dependancy. Here is one solution I thought of: When creating an ActionScript object, assign it pointers to all of the relavent Game information. Here is why I am not doing this: It would give each ActionScript full control of over other objects that (logically) only the Game object should be interfacing with, such as access to other GameCharacters information. This just seems like a violation of control logic. Another solution I thought of: When creating an ActionScript object, pass it a pointer to a Game member function, Game::GetGameStatus(). Here is why I am not doing this: 1) I am rather confused on how to implement it, and the compiler errors are not all to helpful. 2) This also seems like a C++ violation but I can place my finger on why... It just seems like poor design to me. Another solution I thought of: I could create a class ActionScriptInterface. And in this class have virtual functions which will return lists of information. I then would have the Game class extend the ActionScriptInterface, and have the ActionScript class know of the ActionScriptInterface. This would break the overall circular dependancy. But it also seems like poor design and it really shouldn't be needed. So my questions are, which options are good and bad and why? Is there a trick for doing something like this? Thanks, -sevans [Edited by - Sevans on July 20, 2006 8:53:34 PM]
-Sevans
Advertisement
The best solution I can think of is not between the ones you described. In my engine, all components are comunicating between them using messages. So there is a global Dispatcher that receives messages of all kinds (derived from a base class) and put them in a queue and there are subscribers that are subscribed at the Dispatcher for specific message types. Then the dispatcher takes all messages and send them to all it's subscribers, and there is also a subscriber interface that is implemented by each subscriber which contains a ProcessMessage function, so each one will know what to do with the message. Implementing such a system is pretty easy and you can use your ActionScripts as subscribers and you can call the ProcessMessage method from the Dispatcher for each subscriber and send it the message that could contain maybe the gamestate or some other usefull and more specific information, so you cand avoid overhead.
So, an example of this in action for one turn of the player would be:

(Let me note here that I have an Action class too which stores information about what action the ActionScript decideds to take. I failed to mention this earlier, because it was not relavent.)

So Game shoots a message to the MessageDispatcher saying its time for GameCharacter player1 to act. The MessageDispatcher then sends the message on to the GameCharacter player1 (because it is subscribing to this type of message) informing it that it is time to act, and has all of the needed information to act attached to the message. The GameCharacter player1 decides what Action it would like to take and then Sends a message back to the MessageDispatcher with the Action. The MessageDispatcher then sends that message off to the Game object because it is subscribing to that kind of message. The Game object decides what objects are affected and how, and then sends messages to the MessageDispatcher for each of the affected objects, containing how the are affected.

Does it seems like I have it down?

I do have a question though:
when a message is created, by lets say the Game class, does the Game class assign a type to this message? that would make sense so that way there can be different subscribers for different messages, but how are these message types stored? I was thinking in a hash within the MessageDispatcher, how did you do it?

This is where I was going towards with my original implementation, kind of, having the Game class being the MessageDispatcher and the messages be Action objects.

I really appreciate the input and I will most likely choose something like this, but I would love to hear more ideas yet.

EDIT: how does everyone else feel about meeshoo's implementation?

Thanks,

-sevans

[Edited by - Sevans on July 20, 2006 2:14:44 PM]
-Sevans
I don't think your original design is problematic. Sometimes, circular dependencies do arise in natural ways, and I'd consider this to be one of them. It's quite common in parent/child relationships that when the parent creates the child it will pass the child a pointer to itself so that it can be used as a service provider.

Richard "Superpig" Fine - saving pigs from untimely fates - Microsoft DirectX MVP 2006/2007/2008/2009
"Shaders are not meant to do everything. Of course you can try to use it for everything, but it's like playing football using cabbage." - MickeyMouse

Wow really? I mean that makes sense I have just never been told that, and despite the taboo on circular dependancies I do agree with you.

Anyone else have any ideas or suggestions?

oh and
@meeshoo I think your method is great, but it actually seems like a little much for a turn based game such as mine. I don't think that constant game updates and then screen refreshes are anything I should be getting into in text based. But I am still going to try and adapt the idea. I have one more question though, you have a Global message dispatcher? so you can just call Dispatch( Message msg ); without any object being referenced? how does this fair as far as style and security are concerned though?
-Sevans
In turns of style it is a good approach. In terms of security, why are you worrying about security? Security is not something you worry about in a game. If someone wants to break your code at the moment they can do it pretty easily.
We are what we do repeatedly. Excellence, then, is not an act, but a habit.
Well, I have always been taught not to use globals unless there is no other way. So I thought it good to question.

-Sevans
-Sevans
THIS IS THE BEGINNING OF THE NEW TOPIC OF THIS THREAD
----------------------------------------------------------------------------

I am confused as to whether the following is considered a circular dependancy:
When a game object is created it initializes a MessageDispatcher object that itself and other game objects subscribe to, to recieve messages. To recieve messages itself, Game implements the Subscriber interface so it must know of the MessageDispatcher. I want to know if the relationship between Subscriber, Game, and MessageDispatcher is still considered circular?
Here is a little chart I drew up when I was trying to plan this all out myself, please forgive any stupid mistakes, it wasnt meant for others eyes :)

Game object relation chart

Thanks,

-sevans
-Sevans
I think you're really over-engineering this. There's nothing wrong with objects dealing with each other, and the only major problem with circular dependencies is in getting them to compile properly. Once you've overcome that, if you're happy with the design, stick with it. Don't add in a load of extra classes and interfaces to get around it. Your initial plan - Game, Character, Actionscript - is fine. You don't need a load of intermediate classes. Give your scripts a pointer to the game, ensure that Game has the relevant accessors, and you're done.
Your diagram confuses me. How can Subscriber implement message processing methods if it does not know your message objects? And how can Game extend Subscriber without knowing its objects or including it?

And, for the record, I agree with Kylotan.

This topic is closed to new replies.

Advertisement