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



14 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.

  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.


  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.

Leave a Reply

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