Lesson 12.3: Making the Action class more flexible with an interface

In this lesson, we’ll make changes to let us create different types of actions that we can assign to different items.

 

 

Lesson Steps

Step 1: Create the interface file Engine\Actions\IAction.cs

To create an interface, right-click on the Actions folder in Solution Explorer. Select Add -> New Item -> Visual C# Items -> Code -> Interface. Name the interface IAction.cs (that first letter is an upper-case “i”). Interfaces are not required to start with a capital “I” – but it’s a common practice.

 

Create an interface in Visual Studio

 

Currently, the datatype of the GameItem.Action property is “AttackWithWeapon” – our only action class. However, we want to create other actions for different GameItems.

All the action classes will have two things in common:

  1. An Execute function that accepts actor and target parameters
  2. An OnActionPerformed event to report the action’s results

We need a way to put any action object into the GameItem’s Action property. We’ll do this by defining an “interface”.

In this situation, “interface” is not related to a user interface. Instead, it is like a contract, or set of requirements. It says, “all action classes must have these properties, events, and functions”.

We can use this interface as a datatype. We can store any object that implements an interface into a variable/property/parameter that uses the interface as its datatype.

So, instead of having an Action property whose datatype is “AttackWithWeapon”, we’ll set its datatype to “IAction” – the interface that defines what an action class needs to have and do.

 

On lines 8 and 9, we add the two things that must exist in every action class: the OnActionPerformed event and the Execute function. Notice that they do not have a scope. That’s because everything defined in an interface must be public – at least, in C# interfaces.

 

IAction.cs

 

 

Step 2: Modify Engine\Actions\AttackWithWeapon.cs

On line 6, add “: IAction”, to the class. This declares that the AttackWithWeapon class implements all the properties/events/functions listed in the IAction interface – which it already does.

Now, just like with a base class, the datatype of any AttackWithWeapon object is either “AttackWithWeapon” or “IAction”.

 

AttackWithWeapon.cs

 

 

Step 3: Modify Engine\Models\GameItem.cs

Change the Action property’s datatype to “IAction” (line 8) and change the datatype of the constructor’s “action” parameter to “IAction”.

This means we can pass in any object that implements the IAction interface and store it in the Action property. For weapons, we’ll pass in AttackWithWeapon. When we add healing objects, we’ll create a new Heal action class that implements IAction, and we can pass in a Heal action object.

 

GameItem.cs

 

 

 

Step 4: Run the unit tests and game, to ensure it still works.

 

 

Return to main page

4 thoughts on “Lesson 12.3: Making the Action class more flexible with an interface

  1. Hey Scott!  Great lesson!  I like how you are demonstrating design patterns and Object Oriented Programming techniques.  I like how structured it is.  I was hoping you would throw in some more interfaces!  I’ve been wanting learn more about interfaces in OOP and how they compare to using abstract base classes.  What advantages are we gaining here by using an interface versus an abstract base class?  Do interfaces provide for better extendability over base classes?  I can see now where you are headed with the actions, numerous actions can be derived as we go!

    1. Thanks Gary,

      Generally, an interface is good for the class/function that is using/consuming objects that implement the interface(s). It lets the consuming class deal with any type of object – as long as it implements the correct interface. Sometimes interfaces are used in combination with base classes, so the objects can share behavior. We’ll do this when we create our second Action class.

      As an example, we may want to make a change in the future to have chests at a location that can be broken open by the Player. Once the Player breaks the chest, they receive the loot in it. We may create interfaces IHaveHitPoints (which would include the OnKilled event and the TakeDamage function) and IContainItems (which would have an Inventory property). In C#, a class can implement multiple interfaces, but cannot inherit from multiple base classes. As long as we create chests (or other attackable/inventory-containing GameItems) as a class that implements those interfaces, we can pass them into the attack Action object. We’d change the “LivingEntity target” parameter on the Execute function to “IHaveHitPoints target”.

  2. Hey Scott, I just want to say Great lessons, I been learning many new things, and finally getting a hold of some of the Design Patterns, thanks to you and your other Design Lessons. I want to say, I would keep the videos , I watched everyone of them. I am the type of person that absorbs information verbally faster then reading. I tried as an experiment doing the last two Lessons just reading and making adjustments and I botched the lesson, got almost everything working but at the end could not attack a Monsters as it said there was no current weapon, even though you could select it in the ComboBox on the UI, So I went back and watched the video and spotted where I messed up rather quick, also got some other ideas to work with listening to your comments and how you verbally explained everything. So I would say having both the written lessons and the video lessons are important to many people. So Keep up the good work, I am enjoying the series, and learning from you.

Leave a Reply

Your email address will not be published. Required fields are marked *