composite design question

Started by
0 comments, last by Gorbstein 12 years, 11 months ago
[font="Verdana"]So, I'm trying to use a composite design for my current game project, versus the traditional inheritance hierarchy. While I believe I have a solid grasp on composite design down, there are still a few things that are slipping my understanding. My example is specific, but I think it will answer many future questions once this problem is solved. Well, what I have so far is this: let's say we have a projectile class and a enemy class (to simplify this). The projectile has a damage component, e.g. it can cause damage to other objects, typically upon a collision event. Now when the other object is hit, the projectile would send the collision event to the enemy, then the enemy would react once the event listener is ran (probably with an onCollision method). A. should the damage component call the enemies onCollision directly? Anyway, In the mean while, the projectile's onCollision method was already ran, checked to see if the enemy was damageable and then since it was, it called the "takeDamage" method. That's my understanding anyway.

Well, now I create a explosive barrel entity. It too is damageable and has a certain "health" before it explodes. Both the barrel and enemy have essentially the exact same interaction with the projectile. The barrel should implement the "takeDamage" method of course. However, the thing is, takeDamage really will be exactly the same for both the enemy and the barrel, so I'm thinking that "Damageable" interface, should be a component instead, maybe called "TakeDamage" and then both the enemy and the barrel would implement a "health" interface which may have get/set health, isdead, etc. However, where should the health variable come from? Maybe make a component such as "Living"? isDead would be another common method, it would need to check some var or at least return a isDead flag...so I figured it could also be part of the "Living" component as well...it makes sense. Something about thinking of barrels as being "living" however...eh..

What are your thoughts on this? Do I need to go back to the drawing board? [/font]
Advertisement
When it comes to collisions between entities, and how to deal with those in components, I found the best way personally was to keep the system as generic as possible.

If a projectile collides with an entity, then specifically calls that entity's takedamage method, then you're hardwiring the rule that a collision will always give damage. What if later you decide to add a shield to that entity, or want to make it invincible to certain projectiles? If the code is hardwired into the projectile then you don't have flexibility.

There's also the possibility that the entity which was hit by the projectile does not have health or a damagable component (an indestructable wall?) , therefore it wouldn't have a takedamage method.

Here's the way I do it.

My Entity does very little, it simply holds an array of Components, either one or zero of each type being allowed. All components regardless of type have a standard init, deinit, move, update, render, and handleEvent. Each update, the entity simply loops through its components and passes through the init, move, update, render information for that frame, and on a message being sent, just passes it through to all components' handleEvent method.

I currently have about 7 component types, but the ones relevant here are CollisionComponent and LifeComponent. These are just abstract classes/interfaces, the ones which do the actual work will subclass these.

Bullets have a BulletCollisionComponent. On each update, it asks the world to give it a list of all colliding Entities. If any, it generates a takeDamage event containing the bullet id, the bullet type, the damage factor, and also the id of the entity which fired the bullet originally. It posts that event out to each Entity and then forgets about it.

The receiving Entity will pass this event through to all components which will eventually reach the LifeComponent. The LifeComponent, depending on its type, can hold information about the entity's strength, or shields, or how long it has left until self destruct (ie: bullets have a lifetime).

In this case, it's a ShipLifeComponent since I'm working with spaceships here. In it's handleEvent method, it'll respond to takeDamage events by working out if the bullet is a type which damages this ship, work out the damage after shields are taken into account, etc, then decrement the strength if necessary. When strength reaches zero it'll spawn a nice particle explosion and tell the parent entity that it's time to deinit.

If I have a PowerUpLifeComponent I'd simply ignore takedamage events, unless I want to be able to shoot them down.

As for your question about the barrel vs. enemy collision code being exactly the same.. in the above example the receiving entity's collision code is never called so it's not a problem.. only the entities which perform actions do any work in their collision code. The ones which respond to actions do the work in their lifecomponent. In this case, the enemy lifecomponent would simply decrement the life until it reaches zero. The barrel lifecomponent would do the same, but upon reaching zero would send out its own takedamage event to all entities in range. (I assume the explosive barrel is going to hurt things when it dies).

D

This topic is closed to new replies.

Advertisement