Lesson 12.2: Creating the AttackWithWeapon command

In this lesson, we’ll build the first class that uses the Command Design Pattern – a class to handle the player attacking the current monster.

 

 

 

Lesson Steps

Step 1: Create Engine\Actions\AttackWithWeapon.cs

In the Engine project, create a new Actions folder and create a new class in it named AttackWithWeapon.cs. This will be a “command” class, from the Command design pattern.

 

Add the public event “OnActionPerformed” (line 12). We’ll use this event to notify the UI of any messages that result from executing this command object. The “ReportResult” function (lines 51-54) is the function that raises the event notification – if anything subscribed to the OnActionPerformed event.

 

In the constructor, we check that the parameters are valid and then save them to private variables.

 

The “Execute” function (lines 36-49) is the code to run when we want to execute this command. It accepts two parameters – the “actor” (who is performing the action) and the “target” (who is having the action done to them).

The code inside Execute is basically the combat code we had in the GameSession class when the player attacked the CurrentMonster.

 

We have some unused parameters in this class: “weapon” in the constructor and “actor” in the Execute function. We’ll use those in the future, as we make the combat logic more complex.

 

NOTE: On line 46, we raise the event that the UI will eventually display – before applying the damage to the monster. This is another one of those situations to watch for when usng events. The TakeDamage function could result in killing the monster, which raises an OnKilled event.

We want to be sure our “You hit the monster for X damage” message gets to the UI before the OnKilled event does. That’s why we do the action’s ReportResult notification before applying the damage to the monster.

 

AttackWithWeapon.cs

 

 

Step 2: Modify Engine\Models\GameItem.cs

Remove the MinimumDamage and MaximumDamage properties from the class – including from the constructor and Clone function.

Add a new “Action” property whose datatype is “AttackWithWeapon”. Add this new property to the constructor and Clone function.

Add the new PerformAction function (lines 31-34). When the player uses their CurrentWeapon, this is the function we will call.

 

GameItem.cs

 

 

Step 3: Modify Engine\Factories\ItemFactory.cs

Since we changed the constructor for the GameItem class, we need to change the ItemFactory.

First, on line 38, we’ll remove the minimumDamage and maximumDamage parameters from the constructor call and store the GameItem in a variable.

On line 40, we’ll create an AttackWithWeapon object and set it to the weapon’s Action property. We need to have these on two separate lines because the AttackWithWeapon constructor needs the weapon passed in as a parameter.

 

NOTE: To use the AttackWithWeapon class, you need to add the “using Engine.Actions” statement on line 3.

 

ItemFactory.cs

 

 

Step 4: Modify Engine\Models\LivingEntity.cs

First, we’ll add an “OnActionPerformed” event on line 101. The UI will watch this event for any messages that are raised when the LivingEntity performs an action. The LivingEntity watches the AttackWithWeapon class for any messages. If it sees one, LivingEntity will raise an event that passes the AttackWithWeapon message to anything subscribed to the LivingEntity’s OnActionPerformed event.

You can think of this as an employee notifying their manager of something, and the manager notifying their boss.

 

Next, because we are changing the program to use The AttackWIthWeapon “Action” property on the GameItem class, we need to let the monsters have a weapon. This means we need to move the CurrentWeapon from the GameSession class (where it only applies to the CurrentPlayer) into the LivingEntity class. This way, Monsters and Traders will also have use the a CurrentWeapon.

Add the “_currentWeapon” backing variable on line 17. Then, add the CurrentWeapon property setter and getter on lines 69-88. Inside the setter, subscribe to (and unsubscribe from) the current weapon’ action message event. This is where the player (or monster/trader) watches for events raised by their weapon’s action.

Create the “RaiseActionPerformedEvent” function on lines 214-218, to pass the weapon’s message up to the UI – which is only watching for events on the LivingEntity, not the LivingEntity’s CurrentWeapon.

 

Finally, create the “UseCurrentWeaponOn” function on lines 117-120. This is just a simple wrapper function that the ViewModel will use to initiate an attack. We could eliminate this function, and have the ViewModel directly call CurrentPlayer.CurrentWeapon.PerformAction(CurrentPlayer, CurrentMonster). But, I think this makes the code a little cleaner.

 

LivingEntity.cs

 

 

Step 5: Modify Engine\ViewModels\GameSession.cs

Remove the CurrentWeapon property from line 101 (in the original code).

 

Because we now watch for action results as LivingEntity OnActionPerformed events, we need to subscribe to the event and create a handler in the ViewModel.

Create OnCurrentPlayerPerformedAction (lines 279-282). Subscribe to it on line 38 and unsubscribe from it on line 29.

 

Change the AttackCurrentMoster function to use the new action.

Change line 249 to check CurrentPlayer.CurrentWeapon – since it is not a property in GameSession.

Change the existing code that handles the player attacking the monster (lines 255-266, in the original code) to the new line 255.

 

GameSession.cs

 

 

Step 6: Modify WPFUI\MainWindow.xaml

Update the player’s weapon combobox to bind its SelectedItem to “CurrentPlayer.CurrentWeapon” (line 234), instead of the “CurrentWeapon” that used to exist in the GameSession class.

 

MainWindow.xaml (lines 232-236)

 

 

Step 7: Run the test and the game, to ensure it still works.

In the next lesson, we’ll make changes to allow us to handle more actions and make the AttackWithWeapon action more flexible – so the monsters can use it too.

 

Return to main page

Leave a Reply

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