Databinding the videogame, part 2: mapping terrain types to GUI

When I started trying to write a databound video game, my first thought was to use databinding for movement and scrolling. Which is all well and good, and I’ll cover them later. But I quickly hit on a more interesting problem (and solution).

My game needed to know which areas the hero could move through. This is a simple tile-based game, so each 40×40 map square is either passable or not. So my back-end logic needed a Map object to hold that “passability” data. It could be something as simple as a two-dimensional array of Booleans. Except that in my game, there are varying degrees of passability — for example, some terrains are passable, you just have to be moving at terminal velocity before you can crash through them. So it’s not just a Boolean; more like an enum, or, better yet, a Terrain object. So far so good.

And whenever the hero enters a new randomly-generated part of the map, I need to do two things: I need to add some new objects to this Terrain array, and I also need to add the corresponding GUI tiles on the screen.

“Aha!” thinks I. “Why should I waste ten minutes writing a simple method that adds something to two different data stores, when I could instead spend all weekend figuring out how to use an immensely complicated, nigh-impossible-to-troubleshoot databinding system that can automatically do that boring work for me?”

And so I databound the map to the GUI. And it worked. Eventually.

(If you’ve done much with WPF, this may not seem very interesting. You might even know better ways of doing it — and if so, please feel free to let me know in the comments. But I’m still learning this stuff, so I thought it was pretty cool.)

Starting small: mapping a class to a control

I won’t databind the whole map today; I’ll start with a small part — displaying one terrain square.

I’m being a good boy and writing my code in layers. The lower layer has the data model, which (for now) is just POCOs. The upper layer has the GUI. The data objects know nothing about anything GUI. So far so good — textbook stuff.

In the data model, I have classes to represent different terrains. At the moment there are only two — Dirt and SteelPlate. At the moment, they know nothing. Here are their declarations:

public class Dirt
{
}
public class SteelPlate
{
}

Not a typo. They’re both empty classes. Hey, come on, it’s only part 2 of the series.

The cool thing is, if I create an instance of this empty Dirt class, and try to show that object instance in the GUI, I don’t get a compile error, or an exception, or an empty screen, or the text “Game.Core.TerrainDataModels.Dirt”. I get a pretty picture of a square piece of dirt. (Or as close as my limited artistic ability will allow.) If I push a SteelPlate instance into the GUI, I get a pretty picture of a steel plate, with rivets in the corners and everything.

Okay, WPF doesn’t come with built-in knowledge of know to map a class called Dirt to a picture of dirt. How did I set up the mappings from those empty objects to GUI representations? Well, let’s start with this: it’s not in code. I’ll show you the only two lines of actual code I wrote in this test app (in the handlers for the “Dirt” and “Steel Plate” buttons, respectively):

mapView.Content = new Dirt();
// ...
mapView.Content = new SteelPlate();

The magic is in the way WPF can render any arbitrary object to the screen. There are a bunch of ways to tell it how to turn that POCO into a GUI control, but in this case, DataTemplate seems like the best fit. I just give it one DataTemplate that’s keyed to the Dirt class, that says “when you want to display the Dirt class on the screen, do it by creating and displaying a DirtView control”, and another one for SteelPlate that says “create and display a SteelPlateView control”. I defined a UserControl named MapView, which has the magic XAML to set up these mappings:

<UserControl x:Class="Game.Core.GameViews.MapView" ...boring XML stuff...>
    <UserControl.Resources>
        <DataTemplate DataType="{x:Type TerrainDataModels:Dirt}">
            <TerrainViews:DirtView/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type TerrainDataModels:SteelPlate}">
            <TerrainViews:SteelPlateView/>
        </DataTemplate>
    </UserControl.Resources>
</UserControl>

Then all the code has to do is add a Dirt or a SteelPlate somewhere inside a MapView, and the appropriate DirtView or SteelPlateView is created and displayed automatically.

You can see the full MapView code in MapView.xaml, but the interesting part is above — the rest of the file is XML namespace definitions, the control’s size, and its background color.

Interesting note: when I was thinking about what I wanted my classes to look like, I debated whether I should use a different class for each different type of terrain, or just have one Terrain class with an enum property. WPF decided that one for me, at least for now. It’s much easier to select a DataTemplate based on class. It’s possible to select a DataTemplate based on the value of a property, but it’s nowhere near as simple. So I’m keeping it simple.

Databinding the Videogame part 2: Sample project

Today’s test project

For today’s post, I wrote a test project with two buttons: Dirt and Steel Plate. Each button has one line of code (excerpted above) that creates a POCO and pushes it into the GUI, there to be displayed as a pretty picture. Nice and simple so far.

You can browse today’s code online, or check it out from my Subversion repository:

svn co http://svn.excastle.com/databinding_the_videogame/tags/part2

What’s next?

So far, I can show a single terrain square at a time. I’m thinking the next thing is to bind to a whole collection of them, and actually show a whole map (or a subset of it) on the screen. Stay tuned.

Leave a Reply

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