Lesson 07.2: Adding Monsters to Locations

In this lesson, we will add the monsters to the locations.




Step 1: Create \Engine\Models\MonsterEncounter.cs

We want to have the ability to have different types of monsters at a Location, and different odds of encountering each type of monster. This will let us have “rare” monsters, that are difficult to find.

We will use this class to hold the ID of the monster, and the chance of encountering it. The “ChanceOfEncountering” values do not need to total up to a specific value. You can put in any numbers, and our “get random monster” function will handle it,





Step 2: Modify \Engine\Models\Location.cs

To store the MonsterEncounter objects, we add a new MonstersHere property – which is a List of MonsterEncounter objects.

I created an AddMonster function, to populate this property.

We could directly add values to the property. However, this function lets us check if the monster has already been added to the list. If it has, we change its ChanceOfEncountering value to the new value. If the monster has not already been added to the list, we create a new MonsterEncounter object, and add it to MonstersHere.


The GetMonster function will determine which monster the location has, and instantiate a new Monster object for the Player to fight.

If there are not any objects in the MonstersHere list, the function returns null.

Otherwise, if adds up all the ChancesOfEncountering, for the MonsterEncounter objects. It gets a random number between 1 and the total ChancesOfEncountering. Then, it loops through the MonsterEncounter objects until it finds the monster to select.

When it determines the random monster, it instantiates a new Mosnter object, through the MonsterFactory, and returns that object.

If the function hasn’t selected a monster, the final line of the function will return a Monster from the last MonsterEncounter object. This is just in case there is a problem. We want to make sure this function always returns a monster, if there are monsters at the location.





Step 3: Modify \Engine\Factories\WorldFactory.cs

Now we can add monsters to the locations, inside the CreateWorld function.

We will add rats (MonsterID = 2) to the farmer’s field (at coordinates -2, -1), snakes (MonsterID = 1) to the herbalist’s garden (at coordinates 0, 2), and spiders (MonsterID = 3) to the Spider Forest (at coordinates 2, 0).

For now, these will be the only locations with monsters, and they will only have one monster each.





Step 4: Modify \Engine\ViewModels\GameSession.cs

When the player moves to a new location, we want to see if the location has monsters. If so, we will get a monster object and display its information (and image) on the UI.

We’ll start by adding a new CurrentMonster property to hold the Monster object in the ViewModel. We want to use a property with a backing variable, so we can raise an OnPropertyChanged function – to notify the UI that there is a new monster (or no monster).

We also will add a boolean HasMonster property, so we can easily hide and show controls in the UI, depending on whether or not there is a monster for the player to fight.

Instead of using a “set” and “get” for this property, we will use an “expression body”. This is a calculated value – in this case, true (if CurrentMonster is not null) or false (if CurrentMonster is null).

Because this property does not have a backing variable, we need to raise its OnPropertyChanged event inside the CurrentMonster “set” code – like we did for the HasLocationTo<direction> properties.


When the player moves to a new location, the CurrentLocation “set” code already calls GivePlayerQuestsAtLocation(). We will add a new function “GetMonsterAtLocation”.

This new function only needs to call the GetMonster function on the CurrentLocation. If the location does not have any monsters, the function will return “null”, CurrentMonster will be set to “null”, and HasMonster will be “false”. If there are monsters at the location, GetMonster will instantiate a new Monster object, which will go into GameSession’s CurrentMonster property. When the CurrentMonster is set to a monster, HasMonster will be “true”.





Step 5: Modify \WPFUI\MainWindow.xaml

The last step of this lesson is to display the monster information on the screen.

Beneath the Location section, we will display the CurrentMonster’s name, image, and current hit points. We do this by creating a grid (like the one for the location section).

The StackPanel control lets us display multiple values on the same line, or in the same column. To display the monster’s current hit points, we want a label that says “Current Hit Points” on the same line (horizontally) as the monster’s current hit points. The StackPanel lets us easily display the two TextBlocks on the same line.


To make it easier to identify the different sections of the XAML file, I added comments. A XAML comment starts with “<!–” and ends with “à” (that’s two hyphens/dashes in there).


I also added two new lines in the “Window” section, at the top of the page.

The line with “xmlns:ViewModels” tells the Window that we are using objects in the Engine project (assembly), and in the Engine.ViewModels namespace (folder structure).

The line with “d:DataContext” lets the XAML editor know what type of object is in this window’s DataContext. With this line, we can use IntelliSense, when binding properties.





Now, if you run the game, you should see monsters when the player moves to a location with a monster.

In the next lesson, we will let the player fight the monster and (hopefully) collect loot from them.



Return to main page

26 thoughts on “Lesson 07.2: Adding Monsters to Locations

  1. I am having issues getting the images and monster names to show up in the game. It has text for current hp but does not show number, image or text for names… I copied all the text as shown from the 7.1 and this one, and still no luck. Not sure what to do now.

  2. I keep getting an error, it may have not been this lession but the previous one. Just noticed the error now though.
    http://prntscr.com/iveda2 It says that World.cs returns a null? I have not strayed off from what you did at all, how could I have gotten this error?

    1. It’s the LocationAt() function that is having a problem. On line 16, the location being created is at “-2, -1”. Line 20 is looking for a location at “-2, 1” (the Y coordinate needs to be “-1”). Because there is no location with those coordinates, LocationAt returns null – causing the error when trying to call the AddMonster function on the expected Location object.

  3. Hi Scott,

    Thanks for the Tut, it’s awesome.
    I have an issue I’m not able to get my head around.

    When creating a monster at a location the ‘CurrentMonster.ImageName’ fails to convert from a string with the error:


    This only happens for the monster image name. I have tried not formatting the string within creating the object and just loading file names the same way as we do in the location info, but it still doesn’t work. I’ve inspected the properties for both image blocks and there are no differences. I’m really stuck with this one…


  4. I suggest you add a two pixel margin to each of the textboxes inside the StackPanel, so that the number and the colon aren’t attached to each other (it actually looks like there’s a space character between them, so I’m rather pleased with the result).
    It’s probably a bit OCD, but I really can’t stand when two strings aren’t separated by a whitespace.

    The revised code is

    Current Hit Points:

    1. Luciano,

      You code was cut off. XAML (and HTML) is usually automatically removed from WordPress comments. If you want to share your changes, https://gist.github.com/ is a good way.

      There are some UI lessons I’m going to do soon. In those, I plan to create a DataTemplate for the Player data and use some styles for the controls. Those will include margins and other formatting for the labels.

  5. Hi Scott,

    I have a similar problem that i’m unable to resolve, the monster’s images aren’t showing correctly :

    System.Windows.Data Error: 6 : ‘TargetDefaultValueConverter’ converter failed to convert value ‘/Engine;component/Images/Monsters/Snake.png’ (type ‘String’); fallback value will be used, if available. BindingExpression:Path=CurrentMonster.ImageName; DataItem=’GameSession’ (HashCode=9866279); target element is ‘Image’ (Name=”); target property is ‘Source’ (type ‘ImageSource’) IOException:’System.IO.IOException: Impossible de trouver la ressource ‘images/monsters/snake.png’.


    I love c# so far, thank you for this project.

    1. Hello Seikha,

      It looks like sometimes .NET has trouble finding the resource. In Monster.cs, change line 32 to the line below. This worked when I tested the change with your version of the program.

      ImageName = string.Format("pack://application:,,,/Engine;component/Images/Monsters/{0}", imageName);

      Here is more information about this: Pack URIs in WPF

      Please tell me if that does not solve the problem.

  6. For anyone having trouble with the images not showing, and followed all the above directions, I had the same difficulty and solved my issue. Perhaps you did the same thing as me and would like to solve it. Here’s the mistake I made:

    When I unpacked the zip files, I put them in a Monsters folder inside of the project engine location. This is the same location where the files end up being added. This made it so the images would not appear. After deleting the folder and unzipping the files into another location, and following the lesson steps the images appeared in the UI as they should.

    Thank you Mr. Lilly for this project, and the old rpg project. They have been so helpful to me in understanding some of the ways to apply C# fundamentals in a game design.

  7. Hi Scott. I am following your lecture so far and I am beyond impressed.
    I cannot thank you enough for your hard work and passion.
    Mostly I am watching at Youtube but I just started to use text version of your lecture.
    I have a question though.
    I see in MonsterFactory class, there is a function public static Monster GetMonster(int monsterID). (It’s called function right? correct me if I am wrong please.)
    And also in Location class there is public Monster GetMonster() function too.

    And inside the GetMonster() of Location class, it is using GetMonster(int monsterID).
    These two functions have same name as GetMonster and both are public.
    How can they be not conflict to each other?
    Did they have to have same name?

    Code runs smoothly so I am sure this is right way but
    I am a bit confused.

    1. Hi SungJune,

      The computer knows which GetMonster function to call because we always have to call GetMonster from a class or object. When we want to call the GetMonster function from the factory, we would run: “MonsterFactory.GetMonster()”. When we want to run GetMonster for a location, we need a Locaiton object (I’ll pretend we have one in a variable named “myLocation”), and we would run: “myLocation.GetMonster()”.

      Out program cannot just have “GetMonster()”, It always needs the static class or object in front of it – and that lets the program know which GetMonster to run.

      Is that clear?

  8. Hi Scott,
    In Location.cs in line 21 you use MonstersHere.Exists(…). Is there any difference to Any() other than Any() being an extension method?

    1. Internally, they probably use different code, because Exists() is for List and Any is for IEnumerable(). But, for our use, they both provide the same results – whether or not there is a matching object.

  9. Hello Scott Lilly Can you help me with what, like how I can find some information about this method or technique.

    (x => m.Something == something)

    1. Hi Anatolio. You can learn more about that by reading about “lambdas” and “delegates” https://docs.microsoft.com/en-us/dotnet/standard/delegates-lambdas.

      You can think of if like a “foreach” loop, for the items in the list or collection. The LINQ function (like “Where” or “Count”) will take each object in the list, assign it to the variable on the left of the lambda “=>”. Then it will use that variable in the equation to the right of the lambda. Putting that variable into the equation returns a true or false, which determines if that object is included in the LINQ function or not.

    1. Check that the images “Copy to Output Directory” property is set to “Copy Always”.

      If they are, try copying the Images folder (and its sub-folders and files) into the WPFUI project. Remember to set them to “Copy Always” in the WPFUI project. If you created the Engine project as .NET Standard or .NET Core, it does things different from .NET Framework.

      1. Thanks Scott. It started working when I deleted images, recopied them, cleaned and rebuilt the solution. Not sure why that worked but it did!

  10. I noticed when displaying the monster hit points the number is next to the colon.
    Is there a way to put a space between the colon and the hit point number in the XML file?


    1. Hey James,

      I think you also asked about a solution on Discord. But, for anyone who’s just checking here, you can add Padding to the TextBlock to add some space, like this:
      <TextBlock Padding="0,0,5,0">

Leave a Reply

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