views:

67

answers:

3

I am writing a game in ActionScript where I've got multiple classes that should be "hitable" by shots.

The most generic class that all other in-game entities inherit from is CombatObject; The classes CombatShip, CombatAsteroid and various others inherit from it. The classes CombatAi and CombatPlayer both inherit from CombatShip.

Now I want to make CombatAi, CombatPlayer and CombatAsteroid hitable by shots, but I don't want them to inherit it (later there might be CombatShips that shouldn't be hitable).

My idea now was to have these three implement an Interface, IHitable, so that when they collide with a shot, I can ask if(hitObject is IHitable) and if true, have the shot destroyed and do damage.

Now the question is, would it be best to have each of these classes

  1. Implement all the needed code to take damage (such as checking shields, calculating damage percentages, etc.) themselves
  2. Have them all own an instance of the class DamageManager and implement a function getDamageManager():DamageManager, that returns a class that handles all damage related functionality
  3. One disadvantage of (2.) would be that each CombatShip, CombatAsteroid, etc would have to own an Instance of DamageManager. Would it perhaps be even better to have DamageManager be a Singleton and just have a reference to the ship and the shot given to it and let it handle the rest?
+1  A: 

Option 1 would result in a lot of repetitive code, and that's bad for obvious reasons.

Option 3 would mean that all your collision code goes into a single class. From an encapsulation standpoint, this is bad because you'll end-up with a behemoth class that handles everything.

That leaves Option 2 as the best option. Option 2 is better than option 3 because you can extend the DamageManager class for different types of ships and asteroids.

However, I would also like to present an option 4: mixins

Mixins are a language-level feature that allow you to add common functionality to multiple classes without inheritance. Although the ActionScript 3 language doesn't support mixins, AS3 is flexible enough that you can simulate it. http://stackoverflow.com/questions/2577574/mixin-or-trait-implementation-in-as3

geofflee
Option 3 was only meant to be called upon after the hit detection (in the Shot) had assesed that the shot had in fact hit and the object is hittable. Then it would do damage calculation based on some algorithm and pass the damage on to the hit object.
EyeSeeEm
A: 

What about implementing an isHitable getter , in the IHitable interface, this could allow more flexibility if you want to make changes in certain classes later in the game, because with a IHitable instance "is IHitable" will always return true.

Depending on the type of calculations & resulting modifications, DamageManager doesn't really have to be a Singleton, you could call a static method that would handle the damage assessment and return your modified object.

PatrickS
Well the idea was to only give those classes IHitable interfaces that are "hitable", i.e. CombatPlayer, CombatAi, CombatAsteroid; but not CombatShip. What would be the advantage of having a static method instead of a Singleton? Isn't a singleton just a class with one instance with static methods?
EyeSeeEm
Just following on you stating that some CombatShips may not be hitable, later on in the game. As for the Singleton, no not really... a single static method is not comparable to a Singleton class.
PatrickS
+1  A: 

Mixins are a good idea, but its support in AS3 is, well, simulated.

Option 2 will work, but exposing the instance of DamageManager breaks the encapsulation. You could solve this by adding a hit method in your IHitable interface. This method will be called by your game when something hits this object. The implementation of this method is up to the object. You could implement it differently for each object (option 1) but you could also create a generic DamageManager class and use it to calculate the damage.

class DamageManager {
    public function calculateDamage(...){
        // implement your damage logic...
    } 
}

interface IHitable {
    function hit(by:GameObject);
}

And for exemple in CombatPlayer

class CombatPlayer implements IHitable
{
    private var _damage:DamageManager;

    public function CombatPlayer(){
         _damage = new DamageManager();
    }

    public function hit(by:GameObject):void {
        _damage.calculateDamage(...);
    }
}

I've left the implementation on DamageManager open since I don't know how your objects are implemented neither how you want to calculate the damage.

I think that ideally, the DamageManager should not modify directly your object. You could pass a Stat object (which holds the object's health and shield information) along with another object describing the properties of the "hitter" and the DamageManager will return another Stat object which you can use to update the "hittee"'s stats.

Hope it makes some senses!

Subb
You are totally right about the encapsulation, that looks like pretty bad practice and I never even noticed. Your idea about the stat object is interesting: So the idea is that you want to manipulate multiple values of the "hitee" but you dont want to pass a reference to itself (i.e. manipulate it directly), so you use a stat object as container to pass the information back and forth and keep encapsulation intact? Another question: Is this general best practice when returning multiple values?
EyeSeeEm
Yes this is exactly it. For you're other question, I'm not sure there's another way to return multiple values than returning an object with those values, at least in AS3.
Subb