Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411594 Posts in 69387 Topics- by 58444 Members - Latest Member: YomiKu_0

May 08, 2024, 02:34:17 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Object-oriented "responsibility"
Pages: [1]
Print
Author Topic: Object-oriented "responsibility"  (Read 2128 times)
HannesP
Level 0
***


View Profile WWW
« on: March 15, 2009, 08:10:27 AM »

In an object-oriented design, there's always one object that's responsible for something to happen. I often get stuck when trying to figure out which object is most suited for executing the code of a specific task. Let me give you some examples:

1) A shot hitting an enemy. Which object is responsible for carrying out the consequences of this event, the shot or the enemy? In a very simple game it probably wouldn't matter which object hosted the code. It could either look something like this:
Code:
function Shot:handleCollision(o)
if o:getType() == "enemy" then
o:makeDamage(10)
playSound("shot_hit.wav")
self:destroy()
end
end
or:
Code:
function Enemy:handleCollision(o)
if o:getType() == "shot" then
self:makeDamage(10)
playSound("shot_hit.wav")
o:destroy()
end
end
This looks simple and good and all, but what if you decide to implement an enemy which gets hurt when being hit by the shot, but letting the it through itself, continuing in the same direction? Or what if you want an enemy where the sound isn't played if it gets hit in its left leg? These are quite silly scenarios, but I hope they make my wonderings clear.

2) Moving platforms. One easy way to implement it is to make the platform move every object whose positions correspond with the position of an object standing on the platform the same length that the platform is moved, but it could also be implemented the other way round: make each movable object search for moving platforms in its own update() method, and move itself if the position of the platform relative to its own position is right. Problems like the ones in the collison case can arise regardless of which method is chosen, for example: what if certain objects shouldn't be moved by moving platforms? And what if the platforms only want to move objects standing on it upon certain conditions?



So, what I want to know is simply your own views and experiences with issues like these. How do you normally decide which object to make responsible for which actions?

I can also imagine a third place to put the logic: some kind of "manager" that handles interaction between objects, for example a "moving platform manager" to which both the objects that want to be moved and the platforms register, and then special cases are handled by the manager alone. I can see this being a dangerous solution though, moving out logic from the classes into a hardcoded hive mind, which could make the code less maintainable and readable.

So, please bombard me with your thoughts about this! And please be indulgent with the quality of my writing, my mother tongue is Swedish and I have some difficulties with expressing my ideas in English.

Thanks!
« Last Edit: March 15, 2009, 09:35:44 AM by HannesP » Logged
BorisTheBrave
Level 10
*****


View Profile WWW
« Reply #1 on: March 15, 2009, 08:23:52 AM »

Not everything fits the OO idiom. Games have this problem a lot.
My answers:
1) http://en.wikipedia.org/wiki/Double_dispatch. This avoid any calls to getType(), which have a bad code smell.

2) Depends on whether you allow stacking in your game. If so, then a global manager (as stacking frequently requires a global solution to avoid odd behaviour). Otherwise, each object should know what it is standing on, and update it's own velocity to match that of the floor (or model friction, or whatever).
Logged
hexageek
Level 0
***



View Profile
« Reply #2 on: March 15, 2009, 08:46:54 AM »

Quote
A shot hitting an enemy. Which object is responsible for carrying out the consequences of this event, the shot or the enemy

as it's some kind of collision detection I would make the collision detection object responsible of it.
Logged
increpare
Guest
« Reply #3 on: March 15, 2009, 08:51:08 AM »

as for 1, if the function doesn't use private member functions/variables of either, there's a school (effective c++) that would say you should have it as a non-member, non-friend function.  The other suggestions here sound fine also, though.
Logged
Lynx
Level 5
*****


Upstart Feline Miscreant


View Profile WWW
« Reply #4 on: March 15, 2009, 09:17:56 AM »

My take:

Shot takes an 'I impacted something' call.  It destroys itself and sends its target a 'you were shot here for this much damage' message.

Enemy takes an 'I was shot here' call.  It can handle the logic of whether to explode, be wounded, etc.

For the moving platform issue, I'd implement that by having the objects store the object they were directly on.  Each update, objects track whatever they were sitting on and move with it, then implement any additional logic such as 'no longer supported by this other object, fall over'.  You have less messiness to get through that way.
Logged

Currently developing dot sneak - a minimalist stealth game
rogerlevy
Guest
« Reply #5 on: March 15, 2009, 11:57:00 AM »

Thinking outside the strict OO model isn't a sin.  You could implement a simple event system; create a task or procedure that continually monitors collisions.  Making this a class that you could make different types of monitoring tasks out of might not be a bad idea, but to start with just keep it simple and do something "global". Code the event that should occur (sound fx, score increase, messages to send to the objects), on a collision between these, as a special case or an entry in a table of "A collides with B" actions.  The messages that you send to the objects involved in a collision could be "you've been hit by a bullet" or "you hit X object".  It depends on the design of your game how specific or general you want to be.

Good luck man!
Logged
bateleur
Level 10
*****



View Profile
« Reply #6 on: March 15, 2009, 12:39:43 PM »

Not everything fits the OO idiom.

Listen to the BorisTheBrave, for he is wise! Wizard

If you happen to be writing in a very object oriented language, often the best thing to do is to split the processing between more than one object (and hence more than one method).

For example to implement a throw interaction in a fighting game you might have a method on one character for performing the throw and a method on the opponent for getting thrown.

The most complex cases are often those where one object has all the data but it's another object that undergoes state change. So, for example, if I take a moose-shaped cookie cutter and press in into my rolled out cookie dough I get a moose shaped cookie. This can't be implemented entirely in the cookie class because it doesn't know what shape is being cut out of it. But nor can it be implemented entirely in the cutter class unless it directly manipulates the internal data of the cookie class (which is poor style because it breaks modularity).
Logged

nihilocrat
Level 10
*****


Full of stars.


View Profile WWW
« Reply #7 on: March 16, 2009, 11:36:31 AM »

Have a global manager of some sort perform the actual collisions. It will trigger an event, or pass messages, or whatever, when a collision occurs. The responsible bodies pick up these messages and act accordingly. Other components, like a score-keeper or the audio system, can also pick up these messages and perform the correct actions based on the data that's passed along with the event.

It's a little harder this way to figure out "what all happens when event X is triggered?" but I honestly haven't ever wondered that, I am often more interested in "what does object Y do when event X is triggered?", which is an easy question to answer and leads to a piece of code which is easy to modify (a method of some class), because all it knows is the state of its object and the state of the event.
« Last Edit: March 16, 2009, 11:40:50 AM by nihilocrat » Logged

mirosurabu
Guest
« Reply #8 on: March 16, 2009, 12:11:14 PM »

When one event causes multiple objects to undergo the change, the worst kind of solution would be to try and find the responsible object. The reason is simple - these events are not object-oriented, but rather scene-oriented. It gets even more complicated when different objects can have different roles at different times. (as in fighting games, or sports games in general)

Either you should implement some event dispatching system (manager) with roles assignment to participating objects and everything or just make critical code specific to layout/room/scene/object-container. It's not dangerous, as far as my experience goes and it's fairly easy to maintain.
« Last Edit: March 16, 2009, 12:25:03 PM by Miroslav Malešević » Logged
Mikademus
Level 10
*****


The Magical Owl


View Profile
« Reply #9 on: March 16, 2009, 12:42:35 PM »

I have my objects send messages to all listeners that have hooked the object on an event. Then they can decide whether to do anything about or with the event. It is called the "observer pattern", and I think very useful in this situation.
Logged

\\\"There\\\'s a tendency among the press to attribute the creation of a game to a single person,\\\" says Warren Spector, creator of Thief and Deus Ex. --IGN<br />My compilation of game engines for indies
lithander
Level 3
***


View Profile WWW
« Reply #10 on: March 18, 2009, 06:45:43 AM »

I didn't read all replies but here's my take on the original questions:

OOP approach to Collision: you should have some common base class (e.g. gameObject) introducing an interface for collision-handling by declaring a (abstract?) method like "collideWith(gameObject obj)". If a collision between A and B occurs you call A.collideWith(B) and also B.collideWith(A). Both bullet and enemy should derive from gameObject and implement the collideWith() method. Now you could have an reflectiveEnemy class that is a gameObject and reflects the bullet on a collision while another type of enemy implements the same method differently and lets the bullet pass. Your collision detection code is agnostic of these details and just works with generic gameObjects and calls collideWith while you can use polymorphy to add custom behavior in the sub-classes of gameObject.

Moving Blatform stuff: Google for "Scene Graph". It's a common approach to handle positioning of entities in a scene. The idea is that you don't work with absolute positions but relative positions to a parent. In your example you could use that idea to solve the problem like this: Introduce a "Root" node at (0,0). The moving platform has a Position relative to that root. The character on the platform has a relative position to it's parent which is not the "root" but the platform he's standing on. The absolute position of the character is the sum of the (relative) positions of Root + Platform + Character, thus moving the platfrom will cause the character to move and vice versa. When you jump from one platform to another you just swap parents and change the relative positions appropriately.
« Last Edit: March 18, 2009, 06:51:43 AM by lithander » Logged

Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic