Lesson 07.1: Creating Monsters

In this lesson, we will create the game monsters.

Like most of the other game objects, we will use a factory class to create the monsters. When we create a monster object, we also need to give it random loot, for the player to collect after they defeat the monster.

We are also going to add images of the monsters, to display on the game screen.




Step 1: Create the new class Engine\Models\Monster.cs.

This class inherits from BaseNotificationClass, so it can update the UI when the monster’s CurrentHitPoints property changes.

The class also has an ImageName property, which is the image file we will add for the monster in Step 4.

Inside the constructor, we accept the parameters, and use them to populate the properties – including adding the location of the image file for the monster.



using System.Collections.ObjectModel;

namespace Engine.Models
    public class Monster : BaseNotificationClass
        private int _hitPoints;

        public string Name { get; private set; }
        public string ImageName { get; set; }
        public int MaximumHitPoints { get; private set; }
        public int HitPoints
            get { return _hitPoints; }
            private set
                _hitPoints = value;

        public int RewardExperiencePoints { get; private set; }
        public int RewardGold { get; private set; }

        public ObservableCollection<ItemQuantity> Inventory { get; set; }

        public Monster(string name, string imageName, 
            int maximumHitPoints, int hitPoints, 
            int rewardExperiencePoints, int rewardGold)
            Name = name;
            ImageName = string.Format("/Engine;component/Images/Monsters/{0}", imageName);
            MaximumHitPoints = maximumHitPoints;
            HitPoints = hitPoints;
            RewardExperiencePoints = rewardExperiencePoints;
            RewardGold = rewardGold;

            Inventory = new ObservableCollection<ItemQuantity>();


NOTE: If the monsters do not display in the UI, try changing the ImageName line to this:

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

In some environments (I don’t know which ones), the program has trouble finding the image resource. There is more information about Pack URIs here.


Step 2: Update Engine\Factories\ItemFactory.cs

We need to create some more items in the game world, to add to the monster’s inventory – for the player to loot from them.

For the monster loot items, I’m using a starting ID of 9001 – just to keep all these items grouped, and easier for us to find.



using System.Collections.Generic;
using System.Linq;
using Engine.Models;

namespace Engine.Factories
    public static class ItemFactory
        private static List<GameItem> _standardGameItems;

        static ItemFactory()
            _standardGameItems = new List<GameItem>();

            _standardGameItems.Add(new Weapon(1001, "Pointy Stick", 1, 1, 2));
            _standardGameItems.Add(new Weapon(1002, "Rusty Sword", 5, 1, 3));
            _standardGameItems.Add(new GameItem(9001, "Snake fang", 1));
            _standardGameItems.Add(new GameItem(9002, "Snakeskin", 2));
            _standardGameItems.Add(new GameItem(9003, "Rat tail", 1));
            _standardGameItems.Add(new GameItem(9004, "Rat fur", 2));
            _standardGameItems.Add(new GameItem(9005, "Spider fang", 1));
            _standardGameItems.Add(new GameItem(9006, "Spider silk", 2));

        public static GameItem CreateGameItem(int itemTypeID)
            GameItem standardItem = _standardGameItems.FirstOrDefault(item => item.ItemTypeID == itemTypeID);

            if(standardItem != null)
                return standardItem.Clone();

            return null;


Step 3: Create Engine\RandomNumberGenerator.cs

To make the monster loot random, we need a random number generator. The standard random class is not very random. So, we can add this version, which creates numbers more randomly.

If you don’t need a complex random number generator, or if you’re using a project that does not have access to System.Security.Cryptography, you can use the SimpleNumberBetween function, at the bottom of the class.



using System;
using System.Security.Cryptography;

namespace Engine
    // This is the more complex version
    public static class RandomNumberGenerator
        private static readonly RNGCryptoServiceProvider _generator = new RNGCryptoServiceProvider();

        public static int NumberBetween(int minimumValue, int maximumValue)
            byte[] randomNumber = new byte[1];


            double asciiValueOfRandomCharacter = Convert.ToDouble(randomNumber[0]);

            // We are using Math.Max, and substracting 0.00000000001,
            // to ensure "multiplier" will always be between 0.0 and .99999999999
            // Otherwise, it's possible for it to be "1", which causes problems in our rounding.
            double multiplier = Math.Max(0, (asciiValueOfRandomCharacter / 255d) - 0.00000000001d);

            // We need to add one to the range, to allow for the rounding done with Math.Floor
            int range = maximumValue - minimumValue + 1;

            double randomValueInRange = Math.Floor(multiplier * range);

            return (int)(minimumValue + randomValueInRange);

        // Simple version, with less randomness.
        // If you want to use this version, 
        // you can delete (or comment out) the NumberBetween function above,
        // and rename this from SimpleNumberBetween to NumberBetween
        private static readonly Random _simpleGenerator = new Random();

        public static int SimpleNumberBetween(int minimumValue, int maximumValue)
            return _simpleGenerator.Next(minimumValue, maximumValue + 1);


Step 4: Add monster images to Engine\Images\Monsters folder.

Create the new folder, download the images (using the link below), and add the image files to the new folder.



Rat.png   Snake.png   GiantSpider.png

All images, in a zip file (right-click and save)

After adding the image files to the solution, right-click on each one, select “Properties”, and set:

Build Action = Resource

Copy to Output Directory = Do not copy



Step 5: Create Engine\Factories\MonsterFactory.cs

Now that we have all the pieces, we can create monster objects.

We are going to use a factory to create a new monster object for each battle. By creating a new monster object each time, each monster will have its own random loot.

We want a new Monster object, each time we call the MonsterFactory – like how we need a new, unique Item object, each time we call the ItemFactory.

In the ItemFactory, we created a list of standard items. When we needed a new Item, the factory found the standard Item and called the Clone function, to create the new, unique object.

For the MonsterFactory, I’m using a “switch” statement, so you can see how that works.

The “switch” line (line 10) looks at the monsterID value that was passed in to GetMonster. Then, it looks for the “case” line with a matching value (lines 12, 20, and 28). When it finds the matching value, it runs the code after it, until it gets to a “return” (which returns a value, and does not run any more code in that function), or a “break” line (which goes to the first line of code after the closing line for the “switch” statement – line 38, here).

On line 36, we have “default”. This is the code that should run if there is no “case” statement with a matching value. For this function, that should never happen – because we are passing in the monsterID value. But, if it does happen, we create an ArgumentException object, with a message about the invalid monsterID.

On line 41, we have a function “AddLootItem”. This function accepts parameters of the monster object, the ID of the loot item, and the percentage change that the monster has that loot item.

To make the monster loot random, this function will pick a random number between 1 and 100. If that number is less than, or equal to, the “percentage” parameter, the item will be added to the monster’s Inventory. If the random number is higher than the “percentage” parameter, the item is not added.



using System;
using Engine.Models;

namespace Engine.Factories
    public static class MonsterFactory
        public static Monster GetMonster(int monsterID)
            switch (monsterID)
                case 1:
                    Monster snake = 
                        new Monster("Snake", "Snake.png", 4, 4, 5, 1);

                    AddLootItem(snake, 9001, 25);
                    AddLootItem(snake, 9002, 75);

                    return snake;

                case 2:
                    Monster rat = 
                        new Monster("Rat", "Rat.png", 5, 5, 5, 1);

                    AddLootItem(rat, 9003, 25);
                    AddLootItem(rat, 9004, 75);

                    return rat;

                case 3:
                    Monster giantSpider = 
                        new Monster("Giant Spider", "GiantSpider.png", 10, 10, 10, 3);

                    AddLootItem(giantSpider, 9005, 25);
                    AddLootItem(giantSpider, 9006, 75);

                    return giantSpider;

                    throw new ArgumentException(string.Format("MonsterType '{0}' does not exist", monsterID));

        private static void AddLootItem(Monster monster, int itemID, int percentage)
            if (RandomNumberGenerator.NumberBetween(1, 100) <= percentage)
                monster.Inventory.Add(new ItemQuantity(itemID, 1));


In lesson 7.2, we will add monsters to locations, and let the player encounter them, when they move to a location that has a monster. After that, in lesson 7.3, we will add combat – letting the player fight monsters.


Return to main page

18 thoughts on “Lesson 07.1: Creating Monsters

  1. thanks again for your videos! After watching your video, this part of the code puzzles me. I understand what it means, but I wonder… Why the property Inventory isn’t initialized in the constructor as a parameters as the other 6 properties/parameters? I mean…initialised with a lowercase and included at the top of the constructor. What makes it different compared to hitPoints, rewardGold, etc? Best regards Scott!

    public ObservableCollection Inventory { get; set; }

    public Monster(string name, string imageName,
    int maximumHitPoints, int hitPoints,
    int rewardExperiencePoints, int rewardGold)
    Name = name;
    ImageName = string.Format(“/Engine;component/Images/Monsters/{0}”, imageName);
    MaximumHitPoints = maximumHitPoints;
    HitPoints = hitPoints;
    RewardExperiencePoints = rewardExperiencePoints;
    RewardGold = rewardGold;

    Inventory = new ObservableCollection();

    1. You’re welcome!

      You can have a parameter whose datatype is a List of objects. However, I personally don’t like to do that because most people would then create a temporary List variable that had a very short “life”. Here’s some code that shows you how I prefer to add items to a List property: https://gist.github.com/ScottLilly/717fba395154c445237011058c809c5b

      Of course, there may be times where you already have the List from something else. In that situation, I might use a List parameter.

  2. I had to change the three images “Copy to output directory” property in the Solution Explorer from “Do not copy” to “Copy if newer” and rebuild the app before the monster pictures showed up.

    Scott, I have been in web development for many years and recently decided to learn some C# out of boredom. I am finding your tutorials very fun to follow, as I am an old RPG lover myself (both old in age and in the RPGs I love) and I appreciate your approach, showing different patterns and object handling techniques from simple examples.

    I did your previous RPG tutorial, and when I complete this one I’ll start thinking about building the skeleton for a game I’ve had in mind for years. Thanks for your time and everything else!

    1. You’re welcome, Wei!

      Which version of Visual Studio are you using, and do you know what version of the .NET Framework you’re using (it would be in the project’s Properties screen)? I think some of the build processes might have changed recently. A few other people have had problems with the images, but I haven’t figured out what is different.

  3. Hi Scott. Thanks for the reply.

    I am using Visual Studio Community 2017 with Microsoft .NET framework 4.7.03056

    I hope you go on with the tutorials. I need to have a closer look tonight as I am having trouble displaying messages in my skeleton-game.

    Can you give me some hints/links about the “game loop” and how to approach that in C#?

    Again, thanks for your help.

    1. You’re welcome.

      I haven’t done anything with a game loop. But, they are common in real-time games, where actions happen even when the player is not making any moves. For example, if you want to cook a steak in a campfire that will take 10 “ticks”. The game needs to have a game loop that counts each tick and manages everything in the world that depends on the time passed (like the food in the campfire). The player can stand next to the campfire, doing nothing, but the game loop will eventually know the required time has passed and it will change the “raw steak” to a “cooked steak” item.

      If you want to create that type of game, you might start looking here: https://gameprogrammingpatterns.com/game-loop.html. I’ve read this book, and it looks to be good for people who want to develop more-detailed games than the one in these lessons.

      1. I had a quick look at that link and looks like a good read to start trying stuff around.

        For now I am happy with coding a bunch of classes and make them work “by turns” by pressing a “Next turn” button, but you got my point with the “game loop”, so the RPG takes “real time” to cook recipes or potions, repair items or to improve weapons and the like.

        Thanks again for your time and patience!

  4. Hi Scott Lilly. Thanks for the tutorial! I am learning a lot. The code works perfectly, but I think I encountered some sort of “undead” monster bug, where if I kill a monster, it has a chance to go into minus hitpoints. Is there a way to make it so that despite going over the monster’s hit points limit that it ensures the enemy dies?


    1. You’re welcome, Sima.

      The monster shouldn’t be able to have negative hit points. It sounds like the event handler for the monster killed event isn’t firing, or being caught.

      Can you upload your solution (including the directories under it, and all the files in those directories) to GitHub or Dropbox, so I can look at it?

      1. Hi again Scott. I figured out the problem! Turns out, I had written == and not <= in the if monster is at 0 health, which caused the code to be a little bit confused. It would sometimes kill the enemy, sometimes go into minus-negative health rendering it undead. So yes, it was me not creating a proper event handler. Thanks so much for the help!

  5. Hello Scott,

    First of all thank you for your tutorial! It really is great.

    I am currently having an issue in the MonsterFactory.
    In the switch statement for returning the different monsters I get an error.
    The error I get is : Compiler Error CS0029 cannot implicitly convert type ‘Engine.Mondels.Monsters’ to ‘Engine.Factories.MonsterFactory’

    I’m not sure where to turn to find an answer

    Thank you so much for your time!

  6. Hi,

    I’m really sorry, I don’t think I quite figured out how to use github yet, here is a link to a dropbox folder with the project in it.


    Sorry for the trouble!

  7. Hello Scott,

    I have finally figured out how to upload my code to Github, and at the same time I have solved my issue.
    In the Monster Factory class my GetMonster() method returned a monster, but I had initialized it as returning a MonsterFactory. I just had to change that.

    sorry for all the hastle and thank you again for all the work you do 🙂

    1. Great! Just like in a video game, you “leveled up” by learning GitHub and figuring out how to solve a bug!

      You’re welcome. It was not a problem at all. 🙂

Leave a Reply

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