Lesson 05.1: Creating the Game Item Factory


In this lesson, we are going to create a class for the game items, a sub-class (for game weapons) and a factory class to create instances of those items.



Step 1: Create a new class: GameItem.cs, in Engine\Models.

This class will have three properties: ItemTypeID, Name, and Price.

The ItemTypeID will be a unique value for each type of item. For example, we will use 1001 for a “pointy stick” object. We will use 1002 for the “rusty sword” object.

In this class, we have a constructor. This is a function that is called when we instantiate a new object.

In this class, the constructor has three parameters: itemTypeID, name, and price. These parameters have the same name as the properties – except that the first characters are lower-case. This is not a requirement, but is a common way that programmers name parameters in a constructor.

Inside the constructor, we set the properties to the values that were passed in as the parameters.




Step 2: Create a new class: Weapon.cs, in Engine\Models.

This is a sub-class of GameItem. It uses the properties from GameItem, and adds two new properties: MinimumDamage and MaximumDamage.

In the constructor for Weapon, we have the parameters we will pass in when we instantiate a new Weapon object. It has the three parameters we used in GameItem, plus the new damage parameters.

Because Weapon is a sub-class of GameItem, and GameItem has three parameters in its constructor, we need to pass values into the GameItem constructor.Part of instantiating a sub-class is to call the constructor of its “base class” – if its base class has a constructor.

We do that with the line “: base(itemTypeID, name, price)”. That means, “To instantiate a Weapon object, we pass in five parameters. We will take three of those parameters (itemTypeID, name, and price) and pass them into the constructor of the base class (GameItem)”.




Step 3: Create a new class: ItemFactory.cs, in Engine\Factories.

When the game needs a new item, we will use this class to create the object.

Because this is a factory, this will be a static class – a class we do not need to instantiate.

We’re going to build this factory a little differently than how we built the WorldFactory class.

First, we are going to build a collection of all the possible items in the game. We’ll store these items in a List variable, which is how you often store a collection of several items that are the same datatype.

This is the _standardGameItems variable. It’s static, because we’re using it in a static class, with static methods. Its datatype is “List<GameItem>”, which means it can store several objects whose datatype is “GameItem”.


The first time we use the ItemFactory class, we are going to populate this list with all the game items. We’ll do this in code, for now. In the future, we will be able to populate this list from a database, or file.

Static classes do not have constructors, because they are never “constructed” (instantiated). Fortunately, we can create a function that is run the first time a static class is used. That is where we will populate the list of game items.

This is the “static ItemFactory()” function. The first time anything is used in ItemFactory, this function will run and populate our _standardGameItems variable with all the items in the game.

Notice that we are instantiating Weapon objects, and adding them to a variable whose datatype is “List<GameItem>”. Because Weapon is a sub-class of GameItem, it is both a Weapon object and a GameItem object.

We can add any object to _standardGameItems, as long as its datatype is GameItem, or it inherits from GameItem.


To instantiate a game item object, we will create the function “CreateGameItem”, which accepts an ID as its parameter. It will look through the _standardGameItems list, to find the item with the same ID. This uses LINQ, to query the list variable. If it finds a matching object, it will create a new instance of that object – using its name, price, etc. If there is not an item with a matching ID, the function will return “null” – nothing.

This will let us have unique items in the game – with the ability to modify each item individually. This will allow for enchanting an item, or having some items wear out with use, and require repair.




Step 4: Modify GameItem.cs and Weapon.cs.

In order to get a new instance of the game objects, we need to have a way for them to create copies of themselves. This is commonly called “cloning”. You create a new object, but it has the same property values as another object – in this case, the “standard” version of the object.

We will do the cloning by adding a new Clone function to the GameItem and Weapon classes.






Step 5: Finish editing ItemFactory.cs

Now, we can go back to itemFactory, and finish the CreateGameItem function.

Inside the “if” statement that checks if an item was found in _standardGameItems, add a line to return a clone of the found game item object.

After the “if” statement, add the line to return null, for when no object was found.

This lets the CreateGameItem function create new instances of game items.




Return to main page

12 thoughts on “Lesson 05.1: Creating the Game Item Factory

  1. Hi Scott,

    I’ve recently learned about magic numbers and how to avoid straight int ID values with enums. This looks like a good place to implement that strategy – what are your thoughts?
    Also, does this strategy have a design pattern name?

    I played around with refactoring the item IDs to enums for Weapons and GameItems and it does seem to remove a lot of potential for error, especially with intellisense being able to directly give you all the available enums and reading the real object represented rather than an int ID value.

    I went ahead and tried that strategy out on the Quest and Monster IDs as well – do you think this is a good improvement, or not worth the effort? I had to change more than I thought, but the real-time errors and warnings, and the compile errors led me right to all the spots, using the techniques you showed in the first SuperAdventure.

    1. Hi Mike,

      That’s a great question. “Magic numbers” (hard-coded values, like the IDs we have for the items, monsters, etc.) are bad to use. I’m using them here because we are going to modify all the factory classes to pull data from external files, or a database. We will build a separate UI project to manage that data. In that UI project, all the IDs will be hidden from the user, and only used in the data files.

      If we weren’t going to do that, enums would be a great solution. However, since we are going to make this data-driven, I wouldn’t switch the code to use the enums for now.

    2. I am new to programming, and you make it very easy for me to follow along. Now that the project has come further along, I have difficulty remembering what some of the variables and properties are doing, and which classes are pulling information from others. Hopefully with more practice this will become easier to keep track.

      1. That’s an important part of programming – giving things (classes, functions, variables, etc.) good names and being able remember all the parts of the program. Some of the solutions I work with have over 100 projects and thousands of classes. It is extremely difficult to find anything in those programs. But, after some time, you start to remember where everything is and what everything does.

  2. Scott,

    This series is awesome. Thank you for taking the time to do this. I only have one question at this point. Wouldn’t it be less memory intensive to build the game items on the fly, instead of instantiating all objects at once and placing them in a collection? Is that what you were eluding to when you mentioned using a database in a future iteration of the game? I was also thinking along the lines of maybe using something like an array to store the parameter values needed to create an item as it’s needed, or do you think that would be more trouble than it’s worth? Thanks for your time.


    1. Hi Scott,

      You’re welcome. You’re correct that creating the objects on-demand would use less memory. However, the objects in the game are probably only using around 50 bytes each. So, thet’s a big concern for this program. If you were creating large objects (for example, images) that might be something we need to consider. When we do start populating the game objects from a file or database, we will want to follow this pattern of initializing all the objects up-front because reading from disk is generally much slower. So, we’d want to do that once, and never need to read from the disk again.

  3. Hi Scott,

    Thank you for this excellent series. I am getting a lot out of it.

    On this lesson, one thing I noticed is that it seems like the CreateGameItem() method will never call the Weapon’s Clone() method since Weapon’s Clone() method hides GameItem’s Clone() method, and CreateGameItem() calls the Clone() method off of the base class handle. I think we should have declared GameItem’s Clone() method as virtual and used the “override” keyword (instead of “new”) on Weapon’s Clone() method.

    Is that correct?

    1. Hi Adam,

      Thanks. Yes, in one of the future lessons (I think), we solve that problem by checking if the item is a Weapon. If it is, we cast it as a Weapon object to call the correct Clone function. But, in an even later lesson, we completely eliminate the need for that by using “composition over inheritance” to remove the Weapon sub-class – all Weapon objects just become GameItem objects with attacking behavior.

  4. I am enjoying working through your tutorial! I just wanted to know if itemfactory and the use of clone functions by the gameitem classes is what is called a Prototype design pattern? thanks. I hope your consultant business is going well.

  5. Can’t we simplify the CreateGameItem() function return statement by using a null conditional operator?

    return standardItem?.Clone(); should execute Clone() if standardItem is not null and return its value. If standardItem is null, Clone() isn’t executed and null is returned, if I understand how this operator works.

Leave a Reply

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