views:

96

answers:

3

I have a class called "Entity," with two child classes: "Creature" and "Item." (I'm making a game.) Creature has two functions called "Attack," one for attacking Creatures, and one for attacking Items. So far, everything works well.

Now I'm working on the shooting bit, so I have a function called SelectTarget(). It takes all of the Entities (both Creatures and Items) in the player's view that the player can shoot and lets the player choose one.

So here lies the problem: SelectTarget() returns an Entity, but I need some code to figure out whether that Entity is a Creature or an Item, and process it appropriately.

Since this question looks kind of empty without any code, and I'm not 100% sure my explanation is good enough, here's where I'm at:

if (Input.Check(Key.Fire)) {
    Entity target = Game.State.SelectTarget.Run();
    this.Draw();
    if (target != null) {     
        //Player.Attack(target);
        // This won't work, because I have:
        //   Player.Attack((Creature)Target)
        //   Player.Attack((Item)Target)
        // but nothing for Entity, the parent class to Creature and Item.
        return true;
    }
}

(If the way the game is laid out seems weird, it's a roguelike.)

+3  A: 

try something like:

if(target is Creature)
      player.Attack(target as Creature);
else if(target is Item)
      player.Attack(target as Item);
Oskar Kjellin
Redundant cast is redundant.
dtb
True, could've checked for nulls instead
Oskar Kjellin
Thanks! I had no idea "is" and "as" even existed. Neat feature, and thanks for the quick reply!
Unniloct
You can also create an overload that accepts Entity and there do the above thing and call the correct overload.
Oskar Kjellin
This sounds like a problem for interfaces - always think twice before you implement a if/else chain or switch - there is almost always a better OOP approach
Christopherous 5000
This works of course, however I think thats not a very desirable design. That is one of those cases where interfaces come in handy, instead of doing unnecessary things like checking and casting and handle special cases. Did you take a look at my answer?
Philip Daubmeier
@Oskar: Yes you could move that to another overload of the method, but after all it will be the same ugly check and cast thing like before, in an other place.
Philip Daubmeier
Depending on how many different types of entites you intend on having, this code block could end up huge... I would have went for an `IAttackable` interface as suggested by @Philip
James
+9  A: 

You're looking for the Visitor pattern.

SLaks
So an Entity would have a method `GetAttackedBy(Player)` which invokes the right overload of `Player.Attack`? Weird, but +1.
dtb
+9  A: 

What about introducting an interface IAttackable that both Creature and Item implement. Player.Attack would have the new signature Player.Attack(IAttackable target). Every object implementing IAttackable could get methods for substracting health, or retrieving defense values (for calculation of healthpoints to be reducted), and so on...

Philip Daubmeier
Ah, could've done this too... I'm new-ish to C#, and am still working out interfaces. Actually, this example cleared things up quite a bit, thanks!
Unniloct