Inheritance
In this section of the chapter we're going to take a look at how we can use inheritance to create specialized derivatives of the original Combatant class. For example, we might want to create a particular type of combatant that cannot move, such as an automated turret or a stationary cannon. Another kind we might want to create might be combatants that get an extra attack because they are so quick. Finally, we might want to create something completely unusual, such as a drunken attacker who never hits for more than one point of damage at a time.
Figure 3.1 shows the class hierarchy diagram that we want to create from the existing Combatant class. As you can see, we want to create three new classes:
- ReallyDangerousCombatant
- StationaryCombatant
- DrunkenCombatant
Figure 3.1 Class inheritance hierarchy diagram.
Building these classes in either C# or Objective-C is pretty straightforward. C# gives us a bit more fine-grained control over what the inheriting types can do and see, so we'll make more use of the access modifiers than we do in Objective-C.
In Listings 3.10 and 3.11, I show a sample derivative class called ReallyDangerousCombatant, written in Objective-C, that does double damage. This is inheritance in its most basic form—creating a child class that provides behavior that supersedes that of the parent.
Listing 3.10. ReallyDangerousCombatant.h
#import "Combatant.h" @interface ReallyDangerousCombatant : Combatant { } @end
And the implementation of the "really dangerous" combatant class:
Listing 3.11. ReallyDangerousCombatant.m
#import "ReallyDangerousCombatant.h" @implementation ReallyDangerousCombatant - (void)attack:(Combatant *)target { [super attack:target]; target.currentHitPoints -= 12; }
In Listing 3.11, you can see that the really dangerous combatant first asks its parent class (indicated by the super keyword) to attack the target. Then it does its own damage to the target. This really dangerous implementation will always do 12 more damage than a regular combatant would do because of the inheritance hierarchy.
In the interest of saving space and spending more time focusing on the C# implementations of these classes, I won't include the listings for DrunkenCombatant.h, DrunkenCombatant.m, StationaryCombatant.h, and StationaryCombatant.m. The following three listings show the C# implementations for the new derived classes.
Listing 3.12. ReallyDangerousCombatant.cs
namespace Chapter3 { public class ReallyDangerousCombatant : Combatant { public override void Attack(Combatant target) { base.Attack(target); // attack again for good measure! base.Attack(target); } } }
Listing 3.13 shows how we can use inheritance and child classes to make a combatant that is so drunk it can't possibly win a fight and has an incredibly hard time moving where the game tells it to move:
Listing 3.13. DrunkenCombatant.cs
using System; using System.Windows; namespace Chapter3 { public class DrunkenCombatant : Combatant { public override void Attack(Combatant target) { target.CurrentHitPoints -= 1; // never do any real damage } public override void MoveTo(Point newLocation) { Random r = new Random(); Point realLocation = new Point(r.NextDouble() * 30, r.NextDouble() * 30); this.Location = realLocation; } } }
And now let's take a look at using inheritance to create a combatant that refuses to move at all (such as a stationary turret gun):
Listing 3.14. StationaryCombatant.cs
using System.Windows; namespace Chapter3 { public class StationaryCombatant : Combatant { public override void MoveTo(Point newLocation) { // do nothing } } }
No matter how many times the game engine might ask this combatant to move, it will do nothing in response.