Press "Enter" to skip to content

Lesson 16.1 – Writing the function to move the player

Lesson Objectives

At the end of this lesson, you will know…

  • How to plan a function
  • How to write the code/logic for a function
  • Some of the most common C# commands

 

Ok, we’ve spent all this time building up the pieces we need for our game. Now it’s time to actually get the game to do something. The first thing we’re going to add the code to handle when the player moves to a new location.

By the way, this is a long lesson, and covers a lot of new things. So make sure you have some time to complete it.

 

Outline of the function

The first thing we need to do is figure out what’s going to happen during a move.

When I write a function that needs to do a lot of things, like this one, I like to do some planning first – so I don’t miss anything.

When the player moves to a new location, we’ll completely heal them, we’ll check to see if the location has any quests (and if the player can complete them), and if there are any monsters to fight there.

Here is an outline of the logic for a player move function. Something like this is often called “pseudo-code”. It isn’t C# code, but it represents what the code will do.

Each indentation level is where we handle a different condition – for example, the steps to follow if the location has a monster, and the steps to follow if the location doesn’t have a monster.

  • If the location has an item required to enter it
    • If the player does not have the item
      • Display message
      • Don’t let the player move here (stop processing the move)
  • Update the player’s current location
    • Display location name and description
    • Show/hide the available movement buttons
  • Completely heal the player (we assume they rested/healed while moving)
    • Update hit points display in UI
  • Does the location have a quest?
    • If so, does the player already have the quest?
      • If so, is the quest already completed?
        • If not, does the player have the items to complete the quest?
          • If so, complete the quest
            • Display messages
            • Remove quest completion items from inventory
            • Give quest rewards
            • Mark player’s quest as completed
      • If not, give the player the quest
        • Display message
        • Add quest to player quest list
  • Is there a monster at the location?
    • If so,
      • Display message
      • Spawn new monster to fight
      • Display combat comboboxes and buttons
        • Repopulate comboboxes, in case inventory changed
    • If not
      • Hide combat comboboxes and buttons
  • Refresh the player’s inventory in the UI – in case it changed
  • Refresh the player’s quest list in the UI – in case it changed
  • Refresh the cboWeapons ComboBox in the UI
  • Refresh the cboPotions ComboBox in the UI

 

Creating a shared function

We have four different functions for movement, one for each direction. And we need to do the steps shown above for moving in each direction.

We could do that by writing the same code in each function. But then, if we ever want to change that logic, we’d need to make the change in four places – and that often leads to mistakes.

So, we’re going to create a new shared “MoveTo” function to handle movement to any location. Each of the four movement functions will call that one new function.

 

Storing the player’s location

We also need a place to save the player’s current location. Since this value will change, we need to store it in either a variable or a property.

In this case, we’ll make a property in the Player class. It makes sense to do this because a player’s location is a “property” (in the general sense) of the player.

 

Storing the current monster

We also need a place to store the current monster that the player is fighting, in case they move to a location that has a monster there.

In the World class, we have a list of all the monsters in the game. However, we can’t use the monsters from there to fight against. We only have one “instance” of each monster. So, if we fought against the rat in the World.Monsters list, and killed it, the next time we fight against it, it would already be dead.

When we move to a new location, if it has a monster there, we’ll create a new instance of that type of monster and save it to a variable. Then, the player will fight against that instance of the monster.

 

Now that we know what we want to accomplish, we’re ready to add the code.

 

Creating the functions to move the player

Step 1: Start Visual Studio and open the solution.

 

Step 2: First, let’s create the new property to store the player’s current location.

Double-click on the Player class, in the Engine project. Add a new property named CurrentLocation, with a datatype of Location.

public Location CurrentLocation { get; set; }

Note: You don’t have to put the properties in any specific order. I just like to like to keep my List properties at the end of the properties. I find it a little easier to read when they’re grouped in the same place in every class.

 

Step 3: Right-click on the SuperAdventure.cs form, in the SuperAdventure project, then select “View Code”.

 

Step 4: Because we have a lot of code to write, and it’s easy to mistype something, copy the new code for the SuperAdventure form from here (https://gist.github.com/ScottLilly/208630cfcdded1cbfdc0) and overwrite all the existing code in SuperAdventure.cs with it.

 

What’s in the code you just added?

On line 18, we added a new variable to hold the monster that the player is fighting at the current location.

In the form’s constructor, we do a couple things to start the game.

On line 25, we “move” the player to their home. Since the MoveTo function expects a location as the parameter, we need to use the World.GetLocationByID() function to get the correct location. This is where we use the constant World.LOCATION_ID_HOME, instead of using the value 1. It’s much easier to look at the code with the constant and know what it’s supposed to be doing when we use this clearly-named constant.

On line 26, we add an item to the player’s inventory – a rusty sword. They’ll need something to fight with when they encounter their first monster.

We added the new MoveTo function to handle all player movement.

We’ve also gone into each of the four functions that handle moving in a different direction and had them call the MoveTo function.

The MoveTo function

The first thing you may notice in this function are the lines that have a “//” in them. These are comments. Comments are ignored by the computer. They only exist for programmers to read, to know what the program is supposed to be doing. Everything after the double-slashes, until the end of the line, is ignored by the computer.

I used a lot more comments in this function than I normally would. That’s to make it easier for you to follow along with what is happening, and see how the code ties back to the pseudo-code we have above.

The second thing you may have noticed is that this function is long – over 300 lines long.

That’s really too long for a function.

When a function is that long, it’s difficult to keep track of what exactly it’s supposed to be doing. But we’re going to clean this up in the next lesson. Personally, I like to keep my functions around 10 to 40 lines long.

We’ll break this function into smaller functions in the next lesson.

 

What’s happening in the MoveTo() function?

On line 57, we have our first “if” statement.

In this case, we check if the new location has any items required to enter it.

The “!=” is how C# says “not equal to”. The exclamation point, when doing any sort of comparison in C#, means “not”. And “null” means nothing/empty.

So, if the ItemRequiredToEnter property of the location is not empty, we need to check if the player has the required item in their inventory. If it is empty, we don’t need to do anything – there is no required item, so the player can always move to the new location.

On line 72 we see if we found the required item in the player’s inventory. If we didn’t find an item with a matching ID, the “playerHasRequiredItem” variable will still be “false”.

Notice the exclamation point in front of playerHasRequiredItem.

Let’s assume the player does not have the required item in their inventory. The “playerHasRequiredItem” variable will have a value of “false”. Doing a “not” on a Boolean variable, reverses its value: “!true” equals “false”, and “!false” equals “true”.

Thinking “if not false” is not as clear as thinking “if true”. But they both mean the same thing.

On line 75, we display the message that the player is missing the item required to enter this location. This line has a new “+=” symbol.

“+=” means, take the value from the variable/property on the left, add the value on the right to it, and assign the results back into the variable/property on the left.

When you use “+=” with a string, it means, “add the string value on the right to the end of the existing string”. When you use it with a number, it means, “add the value on the right to the value on the left”.

Here, we take the text in the rtbMessages RichTextBox, and add our new message to the end of it. That way, the player can still see the old messages. If we used the “=” sign instead, it would replace the existing “Text” value with our new message.

We also have “Environment.NewLine”. This adds an “Enter” to the text, so the next thing we add to it will be displayed on the next line, instead of the end of the current line.

Line 76 has “return”. This means “exit out of this function”.

Since this function is a “void” function (see line 54), it doesn’t return a value. We can “return” here and not do the rest of the function. We want to do that in this case, because the player does not have the item required to enter the location. So, we don’t want to do the rest of the function, which would actually move them to the location.

On lines 84 through 87, we make the movement buttons visible, or not, based on whether or not the new location has a place to move to in each direction. We do this by checking if the property for the location is empty or not.

The “Visible” property of the buttons expects a Boolean value: true or false.

So, on line 84, if the LocationToNorth property is not empty, the value to the right of the equal sign will evaluate to “true”, and the button will be visible. If the LocationToNorth property is empty, this will evaluate to “false”, and the button will not be visible.

On line 100, we check if there is a quest at this location. If so, we need to do some more work.

Lines 106 through 117 are where we look through the player’s quest list, to see if they already have the quest at this location and if they already completed it.

Lines 128 through 163 looks at each item required to complete the quest, then checks each item in the player’s inventory, to see if they have it, and have enough of it, to complete the quest.

There are some “break” statements in this “foreach”. Those are used to stop looping through the items and exit the “foreach” loop. If we discover that the player doesn’t have one item, or enough of it, to complete the quest, we can stop checking for any other items.

Line 180 has a “-=”. The “+=” means, “add the value on the right to the variable/property on the left”. So, a “-=” means, “subtract the value on the right from the variable/property on the left”. You can only use this with numbers, and not strings, unlike the “+=”.

In this case, we are using it to remove items from the player’s inventory that they turn in to complete the quest.

On line 204, there is a “++”. When you have this after a variable or property, it means “add 1 to this variable or property”. There is also a “–“, for when you want to subtract 1 from a variable or property.

At lines 264 through 273, we create the new monster to fight, by making a new monster object, using the values from the standard monster in our World class.

 

Updating the DataGridViews in the UI

From lines 290 through 321 we update the DataGridView controls in the UI.

The player’s inventory will have changed if they completed a quest. The items needed to turn in were removed from their inventory. The reward item was added to their inventory. So, we need to update the UI with their current inventory.

Also, if they received a new quest, or completed an existing one, their quest list would change.

 

Updating the ComboBoxes in the UI

For the ComboBoxes in the UI, we create new lists to hold the specific datatype of items we want to show in the list (lines 324 and 353). Next, we go through all the items in the player’s inventory and add them to these lists, if they are the correct datatype (lines 326-335 and 355-364).

On lines 328 and 357, there is a new comparison: “is”. This is used to see if an object is a specific datatype.

Remember how we created the Weapon and HealingPotion sub-classes of the Item class? When you create a Weapon object, its datatype is both Weapon and Item. When you create a HealingPotion object, its datatype is both HealingPotion and Item.

If the lists are empty (weapons.Count or healingPotions.Count are equal to 0), we hide the ComboBox and “use” buttons, since there is no weapon or potion for the player to use.

If the lists have items in them, we “bind” the list to the comboboxes (lines 345-349 and 374-378). The “DisplayMember” determines what property will be displayed in the comboboxes. In this case, we want to display the value of the Name property. The “ValueMember” is the behind-the-scenes value we’ll use a little later, to know which item was selected.

NOTE: There are better ways to connect your list properties to DataGridViews and ComboBoxes. But we’re just concentrating on the basics in these tutorials.

NOTE: Hopefully you noticed something about the variable names. They are generally long and descriptive. That makes it easy to understand what values they are supposed to hold. By making your variable names descriptive, it will be easier to work with your program – especially when fixing bugs or making changes in the future.

There are a couple cases in the “foreach”s where I use short variables like “qci” and “ii”.

Since the foreach loop is only a few lines long, I sometimes use a shorter variable name. The variable has a very short life – it only exists within those few lines of the loop. You can display the whole loop on your screen, without scrolling. So, it’s easy to keep track of where the variable is populated and where it is used. If the loop was longer, I’d use a longer, more descriptive name.

 

Summary

Now you’ve seen how to plan out your logic in pseudo-code, and then create a function in the program to perform that logic.

You’ve seen how “if”s, “else”s, and “foreach”s are used in a function.

You’ve also seen what a huge function looks like, and you probably have an idea how difficult it would be to work with it. The next lesson will cover how to clean up that function and make it easier to understand.

We covered a lot in this lesson. If there was anything that wasn’t clear, please leave a comment below and I can update this lesson with some more details.

 

Source code for this lesson

Source code on GitHub

Source code on Dropbox

 

Next lesson: Lesson 16.2 – Refactoring the player movement function

Previous lesson: Lesson 15.1 – Getting random numbers for the game

All lessons: Learn C# by Building a Simple RPG Index

220 Comments

  1. Robert
    Robert November 26, 2016

    Hello Scott,

    I first want to say that I’ve really loved this whole tutorial. I’ve made a couple variations since going through with SuperAdventure the first time. I think I’ve hit a snag on movement, though. I wanted to post my question here because I feel as though I’m missing something fundamental either within or associated with the MoveTo function.

    I am currently assuming that my modified MoveTo function “works,” in a broad sense, because it successfully “places” the player in the starting location when the game is loaded. It also correctly displays buttons based on where locations are relative to the starting location. So when I use MoveTo with one of the location IDs using the LocationByID function, it’s fine.

    For some reason, though, I cannot move out of the starting location using the buttons. When I click on one, nothing happens at all. I don’t even get an error. The location name and description do not update, and there is no change in which buttons are visible or hidden even though the next location should be different in that respect.

    So, in short, it looks like MoveTo can be used, but either it or something connected to it is not updating the player’s location when the button is pressed. I thought I’d try cutting down to the most basic elements for movement — nothing with quests or item requirements — in hopes of isolating the problem, but I think I need help. Assuming movement was the only aim, should the following work, or is something missing from here?

    For each button, I have this: MoveTo(player.CurrentLocation.LocationTo<Direction>);

    This was my attempt at a “cut down to basics” MoveTo function:

    private void MoveTo(Location newLocation)
    {
    // Update the player’s current location
    _player.CurrentLocation = newLocation;

    // Show/hide available movement buttons
    btnNorthwest.Visible = (newLocation.LocationToNorthwest != null);
    btnNorth.Visible = (newLocation.LocationToNorth != null);
    btnNortheast.Visible = (newLocation.LocationToNortheast != null);
    btnWest.Visible = (newLocation.LocationToWest != null);
    btnEast.Visible = (newLocation.LocationToEast != null);
    btnSouthwest.Visible = (newLocation.LocationToSouthwest != null);
    btnSouth.Visible = (newLocation.LocationToSouth != null);
    btnSoutheast.Visible = (newLocation.LocationToSoutheast != null);

    // Display current location name and description
    rtbLocation.Text = newLocation.Name;
    rtbDescriptions.Text = newLocation.Description;
    }

    • Robert
      Robert November 26, 2016

      Correction for the buttons: MoveTo(_player.CurrentLocation.LocationTo);

      That’s what I get for trying to retype it instead just copy and paste.

    • Scott Lilly
      Scott Lilly November 26, 2016

      Ho Robert,

      If you want to try tracking down the problem on your own, I suggest starting with using the debugger to see if the movement button click handlers are being called. You could set a breakpoint on them, and also on the MoveTo function, to verify if they are called, and what values they have in their parameters. That might give you a clue to the source of the problem.

      If you aren’t familiar with the debugger, you can see how to use it here: https://www.scottlilly.com/how-to-use-the-visual-studio-2013-debugger/

      If the button click handler functions are never called, that probably means the handlers are not configured in the SuperAdventure.Designer.cs file. If they are called, we would need to look into the functions.

      If you try that, and don’t find the source of the problem, can you upload your solution (and all the files in its sub-directories) to GitHub, or Dropbox, so I can investigate?

      • Asparuh
        Asparuh July 16, 2017

        Hello Scott,
        At line 25, (World.LocationByID(World.LOCATION_ID_HOME), the World is not recognized! Can you tell me why? It says the name World does not exist in the current context.
        At line 190, RewardItem.Name is underlined and everywhere where is written RewardItem, it says to create in Quest.cs public string RewardItem { get; set; } that, is it correct for this problem?

        • Asparuh
          Asparuh July 16, 2017

          And also btnUseWeapon – button does not exist in the current context, and I cannot run the project because of these errors

          • Scott Lilly
            Scott Lilly July 16, 2017

            Open SuperAdventure.cs, in Design mode. Right-click on the “Use” button for the weapon, and select “Properties” from the menu. On the right side of Visual Studio, you should see the properties for the button. Look in the “Design” section, for the “(Name)” property, and make sure it has “btnUseWeapon”. It should look like this:

            btnUseWeapon button name

            Please tell me if that does not fix the error.

        • Scott Lilly
          Scott Lilly July 16, 2017

          Check The World class, and make sure it starts with this:

          public static class WorldIn the Quest class, check the datatype on the RewardItem property. It should be “Item, like this:

          public Item RewardItem { get; set; }

          Please tell me if that does not fix the errors.

          • Asparuh
            Asparuh July 16, 2017

            Is that correct? I wrote as you said.
            public static class World {get; set;}
            public Item RewardItem { get; set; }

            public Quest(int id, string name, string description, int rewardExperiencePoints, int rewardGold, Item rewardItem)
            {
            ID = id;
            Name = name;
            Description = description;
            RewardExperiencePoints = rewardExperiencePoints;
            RewardGold = rewardGold;
            RewardItem = rewardItem;
            QuestCompletionItems = new List();
            }

          • Scott Lilly
            Scott Lilly July 16, 2017

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

          • Scott Lilly
            Scott Lilly July 17, 2017

            Hi. I saw a few problems in the project. I will work on them, and try to get you a version with all the fixes in the next few days. Unfortunately, I am having internet problems, and can only use my phone right now.

          • Asparuh
            Asparuh July 21, 2017

            Hi Scot,
            Is it possible to tell me when you will be able to check my code because I am checking a couple of times per day and this makes me nervous 😀 it if is possible of course 😀

          • Scott Lilly
            Scott Lilly July 21, 2017

            I fixed your program last night. My internet is supposed to be fixed on Saturday afternoon. If it is, I can upload the corrected version of your program. it does not get fixed then, I will find a place with WiFi, so I can upload it.

          • Scott Lilly
            Scott Lilly July 22, 2017

            I uploaded a zip file with a corrected version of your solution at https://www.dropbox.com/s/5vf3q54ecggsnk1/CSharp-Game-master.zip?dl=0.

            The two big problems were that the solution did not have the World.cs class, and the button to use a weapon was named “btnUserWeapon” (while the code expects it to be named “btnUseWeapon”).

            Please tell me if you have any problems downloading, or running, this version.

          • Asparuh
            Asparuh July 23, 2017

            Hi Scott,

            Thank you a lot! It is fine I can run it without any problems! If you have any other tutorial that would be great. Your tutorial is just amazing.

  2. Robert
    Robert November 27, 2016

    Hello Scott,

    Thank you for the debugger info. I am glad to know more about that feature. I’m not sure if I’m using it correctly for this problem, though. I could not find anything to suggest why I did not at least see the location info update.

    Here is a link to the project in question: LINK REMOVED FOR PRIVACY

    Thank you very much for your time and assistance!

    • Scott Lilly
      Scott Lilly November 27, 2016

      Hi Robert,

      The problem is that the buttons do not have eventhandlers – which connect the button “click” to the function to run in RandomGame.cs. There are two ways to fix this.

      You can open RandomGame.cs, in Design mode. Click once, on a movement button. If you accidentally double-click, Visual Studio will create a new function to handle the button’s “Click” event. After you click on the movement button, look at the buttons properties, in the lower-right corner of the screen. Click on the lightning bolt icon (for events), and look for the “Click” row. The cell to its right should be blank. Click on the down arrow, and select the function you want to run when the button is clicked. You’ll need to do that for each movement button. The screen should look like this:

      The other way to fix this would be to add the eventhandler in the RandomGame.Designer.cs file. You can see an example of how to do that in Lesson 21.3

      Please tell me if that does not fix the problem.

  3. Robert
    Robert November 27, 2016

    Thank you, Scott! That was indeed the problem. Interestingly, a couple buttons had that, but the rest were all blank as you indicated. I’m not sure what I did differently when creating them, but I’ll look out for that in the future. Thank you again.

    • Scott Lilly
      Scott Lilly November 27, 2016

      You’re welcome! There are a few ways that might have happened. But now, you know how to fix it, if the problem ever happens again.

  4. DaveG
    DaveG December 3, 2016

    Hi Scott,

    I’m a little confused by these lines:

    // Make a new monster, using the values from the standard monster in the World.Monster list
    Monster standardMonster = World.MonsterByID(newLocation.MonsterLivingHere.ID);

    Since the type of monster is already defined in World.cs, why do we need to use the MonsterByID function again here?
    …we already know what type of monster it is.

    i.e. why can’t we just say:
    // First get the World.Monster properties and store as a standard monster
    Monster standardMonster = newLocation.MonsterLivingHere;

    // Create a new instance of the monster
    _currentMonster = new Monster(
    standardMonster.ID,
    standardMonster.Name,
    standardMonster.MaximumDamage,
    standardMonster.RewardExperiencePoints,
    standardMonster.RewardGold,
    standardMonster.CurrentHitPoints,
    standardMonster.MaximumHitPoints);

    …or even do it directly without declaring a new variable:
    // Create a new instance of the monster
    _currentMonster = new Monster(
    newLocation.MonsterLivingHere.ID,
    newLocation.MonsterLivingHere.Name,
    newLocation.MonsterLivingHere.MaximumDamage,
    newLocation.MonsterLivingHere.RewardExperiencePoints,
    newLocation.MonsterLivingHere.RewardGold,
    newLocation.MonsterLivingHere.CurrentHitPoints,
    newLocation.MonsterLivingHere.MaximumHitPoints);

    Thanks,
    Dave

    …and I’m really loving these tutorials and your quick feedback to my previous questions – thanks so much 🙂

    • Scott Lilly
      Scott Lilly December 3, 2016

      Hi Dave,

      We could use any of those techniques. It’s been a while since I wrote that code, but I might have added that extra standardMonster variable as a place to expand in the future.

      If you continue on with the lessons, especially the recent lesson 25.1 (where we add the ability to have different possible monsters) you’ll see that the code is refactored, and the extra variable has been removed.

  5. DaveG
    DaveG December 3, 2016

    Hi Scott,

    After going through your code, I have been trying to re-write it myself using only your pseudo code as a guide, which I have found to be a good test of my understanding!
    …and where I end up doing things a little differently it throws up various questions like my previous one!

    So a few more questions…
    Q1.
    In your pseudo code, you say:
    Is there a monster at the location?
    If so,
    Display message
    Spawn new monster to fight
    Display combat comboboxes and buttons
    Repopulate comboboxes, in case inventory changed
    If not
    Hide combat comboboxes and buttons

    However the “Repopulate comboboxes, in case inventory changed” part does not have any corresponding code.
    I guess this is covered by the last lines of your pseudo code:
    Refresh the cboWeapons ComboBox in the UI
    Refresh the cboPotions ComboBox in the UI

    Q2.
    Where you have the code:
    else
    {
    _currentMonster = null;

    cboWeapons.Visible = false;
    cboPotions.Visible = false;
    btnUseWeapon.Visible = false;
    btnUsePotion.Visible = false;
    }

    …when I was re-writing it myself, I forgot the “_currentMonster = null;”

    Wouldn’t that be the case by default anyway?
    What would be the implications of missing this line?

    …and if it is essential to do this, why not do it when we declare the variable (so we don’t forget),
    i.e.
    private Monster _currentMonster = null;

    Thanks again,
    Dave

    • Scott Lilly
      Scott Lilly December 3, 2016

      For the first question, pseudo-code doesn’t always match up with the final source code. You write the pseudo-code as your rough plan – and to help confirm all possible scenarios covered. As you write the code, you might find that some tasks are already covered, or can be handled differently. In this case, since the final two lines (“refresh cboWeapons” and “refresh cboPotions”) handle the “Repopulate comboboxes” line, we don’t need to have any specific code for “Refresh comboboxes”.

      For the second question, we do need the “_currentMonster = null” line, when moving to a new location that does not have a monster. If the previous location had a monster, that would have populated the _currentMonster variable. When the player moves to the new location, if we do not set _currentMonster to null, it will look like the new location has the same monster as the last location.

      Because the _currentMonster variable is a class-level variable, and we are always in the one instance of the SuperAdventure class (we never instantiate a new SuperAdventure object, after the game automatically creates one at the startup), _currentMonster will be null at the very start of the program. When we set the value of _currentMonster, that will remain its value for the rest of the game – unless we set its value again. So, when we move to a new location, we either need to set _currentMonster value to the location’s monster (if the location has one), or set it to null (if the location does not have a monster).

      Let me know if that was clear, or if you still have questions.

      • DaveG
        DaveG December 4, 2016

        Ah, now I see why 🙂
        Many thanks.

  6. Josh
    Josh December 15, 2016

    Just fyi, it looks like the source code from Github uses “dvgInventory” rather than “dgvInventory”. I’m assuming it should be the latter, since it is supposed to represent a DataGridView. Kinda messed me up because I had it the other way in my original code, and I overwrote everything in this lesson with the recommended code, and it didn’t match the UI project.

    • Scott Lilly
      Scott Lilly December 15, 2016

      What line are you seeing with the “dvgInventory”? When I looked at the Lesson 16.1 Gist page, I didn’t see it. But I could be missing something.

  7. Lukasz
    Lukasz January 1, 2017

    Hi Scott,

    Happy 2017!

    I’m getting the ‘System.NullReferenceException’ with reference to this part:

    foreach(QuestCompletionItem qci in newLocation.QuestAvailableHere.QuestCompletionItems)
    {
    if(qci.Quantity == 1)
    {
    rtbMessages.Text += qci.Quantity.ToString() + ” ” + qci.Details.Name + Environment.NewLine;
    }
    else
    {
    rtbMessages.Text += qci.Quantity.ToString() + ” ” + qci.Details.NamePl + Environment.NewLine;
    }
    }

    Could help me out?

    Best

    L

    • Scott Lilly
      Scott Lilly January 1, 2017

      Hello Lukasz,

      Happy New Year to you, too!

      Can you use the debugger (article on how to use it here: https://www.scottlilly.com/how-to-use-the-visual-studio-2013-debugger/) and set a breakpoint on the line with the error? When you run the program, hover the cursor over each of the variables in that line, to discover the one that is null. That will help us find the property that is missing.

      • Lukasz
        Lukasz January 1, 2017

        Awesome, that helped, thank you!

        NamePl was missing, because it was referring to a loot item I added later on to the loot table, but not to the Items list.

        NamePl is initiated only while adding an item to the list and hence the exception.

        • Scott Lilly
          Scott Lilly January 2, 2017

          You’re welcome! Knowing how to use the debugger is a good skill to have.

  8. Rickardo
    Rickardo January 8, 2017

    Hi Scott

     

    I have no error but when I run the game this pop up

    NullReferenceException was unhandled

    An unhandled exception of type ‘System.NullReferenceException’ occurred in Rpg.exe

    What is the problem and how do I handle it

    • Rickardo
      Rickardo January 8, 2017

      in btnNorth.Visible = (newLocation.LocationToNorth != null);

    • Scott Lilly
      Scott Lilly January 9, 2017

      There are a few things that might cause that error. Can you upload your solution (all the files in it, and in the folders under it) to GitHub, or Dropbox, so I can look at it?

      • Rickardo
        Rickardo January 10, 2017

        LINK REMOVED FOR PRIVACY

        thx a bunch

        • Scott Lilly
          Scott Lilly January 10, 2017

          You need to add this line as the first line in the Rpg.cs constructor:

          InitializeComponent();

          This calls the InitializeComponent function in the Rpg.Designer.cs file, which instantiates the buttons (and other controls on the form). This must be done before the line “MoveTo(World.LocationByID(World.LOCATION_ID_HOME));”, because the MoveTo function tries to set the visibility on the buttons. So, the buttons must be instantiated first.

          Let me know if that does not fix it, or if you have any other questions.

  9. Kevin
    Kevin January 30, 2017

    Thanks for this tutorial. I’ve enjoyed going through it.

    When I paste the SuperAdventure.cs code from gist into my project I’m getting a failure in the designer for this.Load += new System.EventHandler(this.SuperAdventure_Load); under SuperAdventure_Load specifically.

    The error is ‘SuperAdventure’ does not contain a definition for ‘SuperAdventure_Load’ and no extension method ‘SuperAdventure_Load’ accepting a first argument of type ‘SuperAdventure’ could be found (are you missing a using directive or an assembly reference?)

    Repo with the latest and previous commit where this begins to happen:
    https://github.com/kevinbushman/SuperAdventure

    • Scott Lilly
      Scott Lilly January 30, 2017

      You’re welcome!

      It sounds like you might have double-clicked on the form, while in the UI design mode. Visual Studio would have created an “eventhandler” for the “Load” event.

      To fix it, you can edit SuperAdventure.Designer.cs, and remove (or comment out) the line where the SuperAdventure_Load eventhandler is being connected. You can learn more about how the eventhandler, and Designer pages, work by looking ahead at Lesson 21.3.

      Please tell me if that does not fix the problem.

      • Kevin
        Kevin January 31, 2017

        That did the trick! I appreciate the further context on how I got this issue.

        • Scott Lilly
          Scott Lilly January 31, 2017

          Great! I’m glad it helped. If you start learning WPF, you’ll discover that the eventhandling is a little simpler.

  10. Jackman10k
    Jackman10k February 12, 2017

    Hello, Mr. Lilly,

    Allow me to first say that I’ve learned quite a bit about both C# and Visual Studio by working on this tutorial you’ve created. I had an idea of how to approach some of these concepts of game design, but I had no idea how complex some of these things can be even for something as simple as a text-based RPG.

    So the problem I’m having right now is that the game, up to this lesson, doesn’t work. It compiles and runs just fine, and the initial screen is accurate, but when I try to move north away from the starting area, nothing happens. That leads me to believe that the issue is in the MoveTo function, but I can’t find anything wrong. I’ve even gone as far as to copy-paste your tutorial code exactly into my solution, but the same results occur. I’d really like to understand what’s happening and finish this properly, so any way you can help me with this would be greatly appreciated.

    I thank you for these wonderful lessons, and I thank you in advance for your time.

    Regards

    • Scott Lilly
      Scott Lilly February 12, 2017

      Hello!

      I’m glad to hear you’ve learned some things from the lessons.

      Can you upload your solution (and all the files in the folders under the solution) to GitHub, or Dropbox? Then I can look at it and see if I can find the source of the problem.

      • Jackman10k
        Jackman10k February 14, 2017

        Of course! Thank you. I apologize for the late reply. I was expecting an email to be sent after my comment was approved or something like that.

        Here’s the link to my project on Dropbox: LINK REMOVED FOR PRIVACY

        I thank you again, Mr. Lilly. If you need anything else, please do let me know.

        • Scott Lilly
          Scott Lilly February 14, 2017

          The site is supposed to send out an email. I’ll see if I can find out why that didn’t work.

          I checked the source code. The problem is that the movement (and “Use”) buttons are not connected to the functions in SuperAdventure.cs. There are two ways to fix this.

          First, you can open SuperAdventure.cs in Design mode, single-click on the button (make sure to not accidentally double-click, because Visual Studio would try to make the eventhandlers for you). Then, look in the Properties section for the button. Click on the lightning bolt, find the “Click” action, and fill the box to the right with the function that should be called when the player clicks on the button.

          Or, you could manually add the eventhandler lines to SuperAdventure.Designer.cs, which would look like this:

          You can read more about connecting eventhandlers in Lesson 21.3.

          Please tell me if that does not fix the problem for you.

          • Jackman10k
            Jackman10k February 14, 2017

            That fixed it! Thank you again, Mr. Lilly. I wasn’t even aware that was something I had to do. I guess that shows just how far I have to go. With that issue resolved, I can get back to trying to fully understand what’s going on here on the logical level. This is definitely the most fun programming tutorial I’ve come across. Some of my CS classes in college could’ve benefited from being like this.

          • Scott Lilly
            Scott Lilly February 15, 2017

            Great!

            The eventhandling creation should have happened in Lesson 13.2. By double-clicking on each button, Visual Studio would have created the eventhandler line in SuperAdventure.Designer.cs – and an empty function for each of the buttons’ Click events in SuperAdventure.cs.

            So, there are actually three different ways to connect a UI control event to a function:
            1. Double-click on the control in the Design screen, which creates an event handler for the default event of the control – “Click” for buttons, “Load” for screens, etc.
            2. Add the function in the control’s “Properties” section
            3. Manually add the line to the Designer.cs file.

            It’s good to know about all these ways.

  11. Zack
    Zack March 3, 2017

    I am running into an issue. When you create a location the public constructor requires more info than you put in, such as ItemRequiredToEnter, Quest here, and monster. Do you just set these values to null?

    • Scott Lilly
      Scott Lilly March 3, 2017

      Yes. When you create a Location object, you can pass in null for the itemRequiredToEnter, questAvailableHere, and monsterLivingHere parameters – because every location won’t need values for those properties.

  12. Neeltje
    Neeltje March 7, 2017

    Ive completed the tutorial until 16.3, but i dont understand the game. I dont have a weapon in it, so there is no way to fight a rat nor a snake.
    I tried to fix this, by trying to set my inventory with a rusty axe, but couldn’t find out how.
    Am i missing something? Is there a way in the standard program to get a weapon?

    • Scott Lilly
      Scott Lilly March 7, 2017

      If you’ve made the changes for 16.3, make sure that the constructor in SuperAdventure.cs looks like this:

      public SuperAdventure()
      {
      InitializeComponent();

      _player = new Player(10, 10, 20, 0, 1);
      MoveTo(World.LocationByID(World.LOCATION_ID_HOME));
      _player.Inventory.Add(new InventoryItem(World.ItemByID(World.ITEM_ID_RUSTY_SWORD), 1));

      lblHitPoints.Text = _player.CurrentHitPoints.ToString();
      lblGold.Text = _player.Gold.ToString();
      lblExperience.Text = _player.ExperiencePoints.ToString();
      lblLevel.Text = _player.Level.ToString();
      }

      That gives the player a Rusty Sword, to start with.

  13. Neeltje
    Neeltje March 9, 2017

    Thank you very much for the great tutorial and your fast reply:).

  14. Keegan
    Keegan March 14, 2017

    Hello Scott.

    I was following the pdf version of this tutorial, and after typing all the scripts, I thought I was home free. That was until I pressed the Start button. Right after that, I received a “TypeInitializationException was unhandled” Error. I’m fairly new to Visual Studio, so I tried to seek help and searched for answers on this page. I found one person who had the same problem, but when trying to follow the same instructions to solve it, It didn’t fix anything. I was wondering if you could help me if you’re not too busy. Here’s the problem area, I think.

    _player = new Player(10, 10, 20, 0, 1);
    MoveTo(World.LocationByID(World.LOCATION_ID_HUT));
    _player.Inventory.Add(new InventoryItem(World.ItemByID(World.ITEM_ID_STICK), 1));
    lblHP.Text = _player.CurrentHP.ToString();
    lblDough.Text = _player.Dough.ToString();
    lblXP.Text = _player.XP.ToString();
    lblLevel.Text = _player.Level.ToString();

    Thanks, and enjoy your day.
    Keegan

    • Scott Lilly
      Scott Lilly March 16, 2017

      Hi Keegan,

      Can you upload a copy of your solution (including the files in the folders underneath it) to GitHub or Dropbox? Then I can track down the problem.

      • Keegan
        Keegan March 22, 2017

        Thanks Scott! Sorry it took me so long to see this.

        Here is a link to the GitHub page: LINK REMOVED FOR PRIVACY

        Hope you can help me!

        Thanks, and enjoy your day.
        Keegan

        • Scott Lilly
          Scott Lilly March 22, 2017

          Hi Keegan,

          Someone else had the same type of problem that you are seeing. Here is a video to help you figure out how to track down the error https://www.youtube.com/watch?v=Ide5v6Cfk6o.

          If that doesn’t help, my next hint is to double-check the Quest class.

          If you still need help to fix the error, please let me know.

  15. Michael
    Michael March 28, 2017

    You know, this is an even better ride going through it a second time but having to convert C# into Java simply to see how far into these tutorials I can get

    I’ve gotten this far with a few bumps and scrapes but now I’m fairly certain this test can probably be taken the rest of the way.. with hopeful assumption I can find Java equivalencies/workarounds for any of the C# windows form stuff I run into later on (and continue to break Java language conventions on the way.. I threw out the layout manager in favor of absolute positioning via code since you gave the nice numbers and all, but that’s apparently bad >-> )

    • Scott Lilly
      Scott Lilly March 29, 2017

      That’s cool! I’ve always wondered how useful the tutorial would be for learning Java – since C# and Java are very similar.

      Building a scalable UI, with relative positioning would be nice. I didn’t do it with these lessons, because I wanted to focus more on the “logic” coding. It would be nice to see how the game looks. If you want, please share a screenshot when it is completed.

  16. Alex
    Alex April 23, 2017

    Hello! I’m getting multiple errors after pasting the code into the SuperAdventure.cs

    Like this:
    Severity Code Description Project File Line Suppression State
    Error CS1061 ‘InventoryItem’ does not contain a definition for ‘Details’ and no extension method ‘Details’ accepting a first argument of type ‘InventoryItem’ could be found (are you missing a using directive or an assembly reference?) SuperAdventure C:\Users\Strygwyr\documents\visual studio 2015\Projects\SuperAdventure\SuperAdventure\SuperAdventure.cs 64 Active

    And this:
    Severity Code Description Project File Line Suppression State
    Error CS1061 ‘PlayerQuest’ does not contain a definition for ‘Details’ and no extension method ‘Details’ accepting a first argument of type ‘PlayerQuest’ could be found (are you missing a using directive or an assembly reference?) SuperAdventure C:\Users\Strygwyr\documents\visual studio 2015\Projects\SuperAdventure\SuperAdventure\SuperAdventure.cs 108 Active

    And so on. Any idea what’s going on?

    • Scott Lilly
      Scott Lilly April 23, 2017

      Make sure your classes InventoryItem, LootItem, PlayerQuest, and QuestCompetionItem match the code from Lesson 10.1 (https://gist.github.com/ScottLilly/161a5812ae4843563d6b). Especially check that everything has a “public”, if it is in the code on the Gist page.

      Please let me know if that does not help you fix the errors.

      • Alex
        Alex April 24, 2017

        Thank you, it worked!
        That’s the only one that’s left tho:

        Severity Code Description Project File Line Suppression State
        Error CS1061 ‘Monster’ does not contain a definition for ‘CurrentHitPoints’ and no extension method ‘CurrentHitPoints’ accepting a first argument of type ‘Monster’ could be found (are you missing a using directive or an assembly reference?) SuperAdventure C:\Users\Strygwyr\documents\visual studio 2015\Projects\SuperAdventure\SuperAdventure\SuperAdventure.cs 268 Active

  17. Erwin
    Erwin May 17, 2017

    Ik krijg errors hier:
    regel 308-321,

    // Refresh player’s quest list
    dgvQuests.RowHeadersVisible = false;

    dgvQuests.ColumnCount = 2;
    dgvQuests.Columns[0].Name = “Name”;
    dgvQuests.Columns[0].Width = 197;
    dgvQuests.Columns[1].Name = “Done?”;

    dgvQuests.Rows.Clear();

    foreach (PlayerQuest playerQuest in _player.Quests)
    {
    dgvQuests.Rows.Add(new[] { playerQuest.Details.Name, playerQuest.IsCompleted.ToString() });
    }

    The name ‘dgvQuests’does not exist in the current context.

    Weet iemand hoe dit komt?
    Avast bedankt

  18. Auke Keijser
    Auke Keijser June 16, 2017

    Hi Scott,

    I have plenty of these errors:
    the name ‘rtbMessages’ does not excist in the current context

    Error 18 ‘SuperAdventure.SuperAdventure’ does not contain a definition for ‘label5_Click’ and no extension method ‘label5_Click’ accepting a first argument of type ‘SuperAdventure.SuperAdventure’ could be found (are you missing a using directive or an assembly reference?

    Error 1 The name ‘lblHitPoints’ does not exist in the current context

    Could you please indicate what is the issue?

    Kind Regards,

    • Scott Lilly
      Scott Lilly June 17, 2017

      Hello Auke,

      For the first error, open SuperAdventure.cs in the Design screen. Right-click on the textbox control on the middle of the right side of the screen, and select “Properties” from the menu. Look for the “Name” property, and make sure it is “rtbMessages”.

      This might also be the way to fix the problem for the missing lblHitPoints error. While on the Design screen, you can press the “Tab” key to highlight the controls. This is probably the easiest way to select the label for the hit points, because it is very small. When the label to the right of “Hit Points:” is selected, check its Name in its properties.

      For the label5_Click, that could have happened if you accidentally double-clicked on one of the labels. If you do that, Visual Studio will create a function for you. However, if you paste in code from a lesson, it will not have that function. This error is because the program is looking for that missing function. You can fix it by modifyinh SuperAdventure.Designer.cs, and removing the line that has “label5_Click”. You can read more about what id happening in Lesson 21.3.

      If that does not fix the problems, please tell me.

  19. Truong
    Truong June 23, 2017

    Hi Scott.First thing I want to say that you make great tutorial man. Secondly I have few error when copy the new code, I hope you can show me where it gone wrong

    LINKS REMOVED FOR PRIVACY

    • Scott Lilly
      Scott Lilly June 23, 2017

      Thank you. The links went to error pages. Can you upload your solution to GitHub, or Dropbox, so I can try to find the source of the errors?

  20. Zeph
    Zeph July 19, 2017

    Dear Mr Scott. Lilly,

    I would like to ask, what is the exact purpose of binding? You applied it in your code but i cannot figure out the meaning of it. Thank you!

    • Scott Lilly
      Scott Lilly July 20, 2017

      Another way to think of “binding” is to call it “subscribing”. One thing in the program wants to know when something happens to another thing. In this situation, it is UI controls (labels, datagrids, etc.) that want to “subscribe” to properties on the player object. When the player property changes, it notifies all its “subscribers” about the change – so they can update the values they are displaying on the screen.

      Please let me know if that is clear, or if you have more questions.

Comments are closed.