Lesson 04.3: Moving in the game world

In this lesson, we will add buttons to let the player move to different locations in the game world.




Step 1: Remove the old test button.

Open MainWindow.xaml. Find, and delete, this line:


Open MainWindow.xaml.cs. Delete the function that was called for the button Click event.


Step 2: Add the buttons to MainWindow.xaml

Find the label for the Combat/Movement controls, and delete it.


In its place, add this grid (with an inner grid) and the movement button controls.


To make the movement button look the same, set the Height, Width, and Margin attributes for each of them:


Step 3: Now we need to make the movement buttons work.

For each movement button, add the Click attribute, at set their value to the name of functions we will create, which will be run when the player clicks the button.


Next, we need to create the functions that the button Click event will call. These will be in MainWindow.xaml.cs.

They can be “private”, because they will only be called by the buttons in MainWindow.xaml. The returning datatype for these functions is “void”, because the functions will not return any values.

The Click event sends two parameters to its function, so we need to accept them. For Click events, the two parameters are the sender and the event arguments. The “sender” is the object that “sends” the event (in this case, the button in MainWindow.xaml). The event arguments are any additional information that the sending object includes. The Click event sends event arguments whose datatype is “RoutedEventArgs”.

We are not going to do anything with these event arguments, in these functions (we will with other events, in the future). So, I won’t go into detail about them now. However, we do need to include the parameters with the function, because the Click event will send them. So, the function needs to have a place to accept them.


If we wanted to, we could change the player’s location inside these functions. But, these functions are in the View. It’s better to put the game logic inside the ViewModel, or a Model (this makes it easier to test, or connect the game to different UIs in the future).

So, we will create new functions inside the GameSession class, which will be called by the event-handling functions we just created.


Now we can go back to MainWindow.xaml.cs, and make the Click event functions call the functions in GameSession.cs


Next, we’ll add the code to move the player, inside the new functions in GameSession.cs.

Each of these functions will use the CurrentLocation’s X and Y coordinates, add (or subtract) 1 to the appropriate coordinate for the movement, and get the location at the new coordinates – using the LocationAt function of CurrentWorld.


If we run the game now, the player’s location does not change on the screen. That’s because the UI did not receive a notification that the CurrentLocation property has changed. We need to make the GameSession class implement INotifyPropertyChanged, and raise a PropertyChanged notification when the CurrentLocation changes.

To do this, we’ll do the same thing we did for the Player class.

First, at the top of the class, add “: INotifyPropertyChanged”, to declare that this class will implement the INotifyPropertyChanged interface – which lets the WPF UI know it needs to watch for PropertyChanged events from this object.

Next, we need to add the PropertyChanged event, and the OnPropertyChanged function, to implement the interface. We can copy those from the Player class.

Finally, we need to change the CurrentLocation property to use a backing variable, and call the PropertyChanged function when it gets a new value – just like we did with the properties in the Player class.



Step 4: Now that we can move, we need a way to prevent the player from moving in a direction where there is no valid location. The way we’ll do that (for now) will be to hide the movement buttons when the player cannot move in a direction.

To do this, we’ll use the “Visibility” attribute on the buttons. This attribute can be set to “Collapsed”, “Hidden”, or “Visible”. “Collapsed” means the control should not be displayed, and it should not take up any space in the screen. “Hidden” means the control should not be displayed, but it will still use the same amount of space as it would if it was visible – although the space will be blank. And, we can “Visible” when we want the control displayed.

As the player moves to different locations, the hidden and visible buttons will change – depending on which directions have valid locations, from the CurrentLocation. So, we will add four new properties on the GameSession class. These will be “Boolean” properties (which hold true/false values), and will see if the World contains a location in each direction from the CurrentLocation.

If there is a location in the direction, the property for that direction will be “true”/ If there isn’t, that property will be “false”.

For these properties, we’re going to only use the “get” – no “set”. And, we will calculate the value to return for the “get”.

The calculation will look in the CurrentWorld, and use the LocationAt function to get the location in the property’s direction. If there is a Location in that direction, LocationAt will return the Location. If there is not a Location in that direction, LocationAt will return “null” (nothing).

So, we want the “HasLocation” properties to return “true”, when LocationAt returns an object (is not null). It will return “false”, when LocationAt returns “null – because there isn’t a Location in that direction. The “get” values for these properties will change as the CurrentLocation changes.

Here is the code for the four new properties:


Next, we need to connect these properties to the UI. But, we need a way to convert from the Boolean property values to Hidden/Visible. XAML has a built-in converter function we can use to do this.

Open MainWindow.xaml, and add this between the opening <Window> tag, and the first <Grid> control.


That will let us use the built-in XAML converter that converts “true” to “Visible”, and “false” to “Hidden”.

Now, we’ll set the Visibility attribute on the buttons, binding the Boolean properties, and using the BooleanToVisibility converter to convert “true” to “Visible”, and “false” to “Hidden”.

We use Binding, just like we did with the Player properties, but we need to add the Converter, to get the Visibility values. So our buttons will look like this now:


Step 5: Notify the UI when the HasLocation properties change.

If we run the game right now, the buttons never disappear – even when there is no Location in their direction. That’s because we haven’t configured the GameSession class to raise a notification when the HasLocation properties’ values change.

We need to add the same type of PropertyChanged notification that we did for the CurrentLocation property. However, the HasLocation properties don’t have a “set”, which is where we raised the PropertyChanged notification for CurrentLocation.

Fortunately, the values for the HasLocation properties will change at the same time the CurrentLocation property changes. So, we can add the PropertyChanged notifications for the HasLocation properties inside the CurrentLocation property’s setter.

Change the CurrentLocation property’s code to this:


Now, when the CurrentLocation changes, the UI will receive notification that the HasLocation properties have changed, and will hide (or show) the direction buttons.


Step 6: Run the game, and try moving around in the worlld. You should see the buttons hide/appear, as you move. You should also see the Location image and description change.


Final Source Code







Return to main page



34 thoughts on “Lesson 04.3: Moving in the game world

  1. Moving around let me see that one of all of my images was not working. I know its set to the right size as I resized it with all the other images I used, however, it is not showing up at all. I checked the name of the addlocation text and the file name matches.

    Is there something else I need to do to make it show up?

    On a side note, How would we be able to add a button to the middle of the movement buttons for the map, so we can view it whenever we want? Would that button have to make a new window to show the map?

    1. Fixed me own image issue. I just reloaded the image and it seems to work. Probably had something to do with renaming the image so it was the same as yours for coding purposes.

    2. I saw in your other comment that you fixed the problem with the one location’s image.

      You could add another button, to show the game map. I’ll show how to do this in the lessons for the trade screen, when we add vendors (planned for lesson 8). However, if you want to try it now, you could create a new Window in the UI project – to display the map. Inside the function that handles the map button’s Click event, instantiate the new map Window object, and use its ShowDialog function, to display it.

  2. Something other students might find fun. Using your movement code and the already established HasLocationTo… booleans, I’ve configured my game to utilize the standard WASD movement keys with an OnKeyDown event and a slight modification to the Move(direction) code.

    protected override void OnKeyDown(KeyEventArgs e)

    if (e.Key is Key.W)

    public void MoveNorth()
    if (HasLocationToNorth)
    CurrentLocation = CurrentWorld.LocationAt(CurrentLocation.XCoordinate, CurrentLocation.YCoordinate + 1,
    else return;


    Just thought I’d share.

    1. Another thought on movement keys WASD and arrow keys.

        1. Thanks for the prompt reply 🙂
          Is there a difference if I add an event in the xaml file for keyboard and change the handling function to private in the xaml.cs? Seems to work the same. I added code snip below. The contents of the function is same as above.

          Just let you know I’m learning a lot from reading and watching the videos from this site.
          Thanks and may buy you a coffee.



          1. You’re welcome!

            There isn’t any real difference if you use this technique. If you notice, the “xaml” file’s Window has an attribute of x:Class+”WPFUI.Window”. And, the “xaml.cs” file has “public partial class MainWindow”. So, even though those are two separate files, they are both parts of the MainWindow class. That’s how the xaml file can use the private function in the “xaml.cs” file – they’re both get combined to make the one MainWindow class.

            So, this is one of those things in programming that comes down to personal preference.

  3. Scott,

    I’m still relatively new to all this (hence the reason im here) so I apologise if this is completely incorrect thinking but;
    Why do the Move methods not belong to player, surely it is the player who is responsible for moving themselves around the world?



    1. Hi Mark,

      Where you put this movement functions depends on how you view the program, and the objects in it. There are (at least) three ways you could see player movement.

      1. The player is the object that is moving, and that’s where you should have the movement functions.
      2. The locations care about their occupants. That might lead you to create AddOccupant() and RemoveOccupant() functions to handle “moving” (populating the location with a player).
      3. The game is managing the “state” (status) of everything that is currently happening. This is how I saw it, with the ViewModel being the class where I hold this game state (CurrentPlayer, CurrentMonster, etc.).

      If you look at the code for the original Windows Form version of this game, you’ll see the movement functions in the Player class. But, I needed to add a lot of other functions in there to handle getting quests, fighting, checking if the player is allowed to go to a location. That Player class is larger than I like, and doesn’t really follow the Single Responsibility Principle – it’s doing a lot of non-player things.

      But, there are definitely many other ways to organize every program. As you work with more programs, you’ll see different ways to do things, and start to develop your own style from the techniques that make the most sense to you.

      Let me know if that isn’t clear, or if you have more questions.

  4. Hi Scott,

    Thanks for getting back to me, I’ve so far found the hardest parts of programming are working out what classes should be doing what to ensure that my programs remain extensible in ways that don’t mean repeating tons of code and won’t breaks what’s already built, I’ve built apps that are currently used in production of the small company I work for and I fear every day that one of them will end up falling over because I didn’t design my classes well enough.

    I think it’s hard as a self learner to understand if you’re on the right track with something so I appreciate you taking time out to answer my question.


    1. You’re welcome.

      You might want to look into “code smells”, design patterns, Martin Fowler’s book “Refactoring”, and Michael Feathers’ book “Working Effectively with Legacy Code”. These will help you see the difference between code that is difficult to maintain and modify, and code that has a good structure.

      The thing to always remember is that we usually write the best program we’re capable of writing based on our current understanding of the problem, and our current skills. However, as the program is used, and as we learn new techniques, we can often make improvements to the program.

      You’ll need to decide if it’s worth the time and effort to change the program – sometimes it’s best not to touch a working program. Other times, especially if you are continually adding new features to a program, it may be worth the effort to improve the program’s structure and quality. That will help you with future changes. This is easier to do if the program has unit test, so you can confirm the changes didn’t break anything.

  5. Hey Scott,

    You should, if you’re still adding to this lesson, do a future lesson where you show us how to make each of the location nodes have connections, rather than just being able to go to any adjacent location. For example, imagine a wall being between 2 locations, you wouldn’t want to be able to travel between those locations, but instead you would have to go around that wall. I noticed that I could have just done a check for the specific coordinates in our “HasLocationTo” blocks, but I feel like instead, there should be a way to add a list of “connections” to each location, and then you would only be able to move to any of the “connections” rather than any adjacent location.


    1. Hi Matt,

      I wanted to do the same thing. In my game there is a train line separating the location directly to the North of my Home location. I created an extra property for the Location: public List Blocked { get; set; } (this represents a list of all the blocked locations). So my Home location now has “North” in the Blocked list. I had to make some changes to the WorldFactory.cs, the World.cs, the Location.cs and the GameSession.cs – it seems to all work so far.

      The cool thing about this is now I can do stuff like add keys for locked doors, or have certain locations open up when I complete a quest. If you’re interested I can paste the code here, or however Scott would like the format to be.

  6. Hi Scott,

    I know this is an old post, but I was wondering why I’m getting this exception, despite having reproduced your code exactly as I went through your video. Just to check, I also just copy-pasted the files and got the same result.

    It seems like there’s a problem with the ‘get’ of CurrentLocation? The code that follows a similar pattern in the Player class seems to be working fine.

    And here’s the exception:

  7. Hi Scott,

    I figured out what was wrong almost as soon as I saw your reply. I had a typo in my WorldFactory where there wasn’t a location at 0,0, so the LocationAt function was returning null – of course!

    I didn’t think to see if there were any errors in the files not referenced in this lesson.

    Enjoying the series a lot. Thanks for doing this and also for the quick response.

    1. sorry it removed some of my text when I posted it.

      I’m getting the null exception error Craig was dealing with, however I do have a location at (0, 0) in my World Factory Class. The link to the proj on Github is here: LINK REMOVED FOR PRIVACY

      1. Hi Chris,

        Check the GameSession class. It looks like there is a typo on line 44 (in the HasLocationToEast property). Change this part:
        CurrentLocation.XCoordinate = 1
        CurrentLocation.XCoordinate + 1

        The equal sign was changing the value of the starting location X coordinate to “1”.

        Let me know if that doesn’t fix the problem, or if you have any other questions.

  8. Hi, Scott.

    From the structure of properies’ get {}, a Binding involves a value-reading from the changed property.
    I wonder who does it.

    Do View or listeners read it and update their own properties with the read value just after they receive notification?
    Or, PropertyChangesEventArgs object at first reads the new value and carries the new value to the listener?
    Then, the listener just update their value with carried one.

    1. Hi Charles,

      I never looked at the MSIL code (the “compiled” code for the program). But, I think the View would subscribe to the PropertyChanged event of the property it is binding to – unless you set the Binding Mode to OneWayToSource (but, I never tried that).

  9. Hi! Thank you so much for your tutorials. I have a small problem which I can’t seem to fix no matter what I do. I’ve done exactly as you said up until

    GameSession : INotifyPropertyChanged

    Where even though I can move with the buttons, I cannot see the locations and the images that shows it also does not load. All it does is default me to 0, 0 or wherever I had set the location. Any way to make it so that it displays in your video correctly?

      1. Hi. I am unfamiliar with GitHub, so I apologize if this is wrong.

        The link to the sln and all the contents is in here: LINK REMOVED FOR PRIVACY

        Thank you for looking into it. (´• ω •`)

        1. I made a few fixes and it looks like it’s working now.

          1. The “cove.png” file is in the Engine\Images folder, and should be moved to the Engine\Images\Locations folder
          2. For all the location images, set their “Build Action” to “Resource”
          3. In GameSession.cs (line 25), OnPropertyChanged should be “CurrentLocation” (without a space between the words)
          4. In GameSession.cs, the property “HasLocationEast” needs to be “HasLocationToEast”
          5. In MainWindow.xaml (line 80), the TextBlock should have Grid.Row=”0″, and the Binding should be to “CurrentLocation.Name”
          6. In MainWindow.xaml (line 95), add TextWrapping=”Wrap” for CurrentLocation.Description

          It looks like you still have some steps to complete from this lesson (connecting the HasLocation… properties in MainWindows.xaml and adding the OnPropertyChanged notifications for them).

          Let me know if you try that and still have any problems or questions.

          1. Thank you very much, Scott Lily! And yes, I stopped as I couldn’t seem to get images(and Locations) to work despite the buttons being able to work as per following your videos, so I admittedly stopped halfway trying to figure what was the issue(s), but now that you’ve pointed it out I can see it, and should probably follow through before posting. Forever grateful once again!

  10. Hey Scott, what software do you use to record your screen? I tried using the default windows and it refuses to record the build. It’ll show the code, but once I run the program, the game doesn’t show up in the recording just visual studio beneath it. I wanted to send a clip of it to my little brother. Enjoying the tutorial so far, this is my first introduction to XAML, WPF, source control, AND building a project in visual studio. So I am learning a ton from your videos. My first college course introducing WPF starts next week so I didn’t want to go unprepared!

    1. Hi Cody,

      I use Camtasia to record my screen and audio. I write about how I make the videos here at: https://scottlilly.com/how-to-record-a-programming-screencast/.

      Camtasia is a commercial program that costs $249. If you’re looking for a free alternative, you might want to look at OBS Studio and maybe Audacity (for more audio editing). I haven’t used them, other than playing around with Audacity a bit, but they seem to be popular – especially in the streaming world.

  11. Hi. Why do you create a row in the movement grid, when there’s only one? Is it any different than not creating any row at all?

    1. Hi Dave,

      That is a habit from when I used to write HTML web pages. You can write HTML that is missing things, like an opening <tr> node without the closing </tr> node. The browser is usually smart enough to know to close the table’s row when it sees the next opening <td>. But, some browsers couldn’t handle that correctly.

      Now, even if I only have one Grid row or column, I still usually add it to the XAML. It might not be important now, but it might be important in the future. Plus, I think it is clearer to understand. When you look at the top of the Grid, you know exactly how many rows and columns it will have. That’s also why I add the Grid.Row and Grid.Column attributes for all the XAML controls (textboxes, comboboxes, grids, etc.) You can leave out the value if it’s zero. But, if you include the value, I think it’s faster to read. I don’t need to think about why some of the controls don’t have it.

Leave a Reply

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