Building a pseudo-3d game using SilverTile

27. juli 2010

I needed a break from my Zelda remake and decided to try something completely different. Being a fan of the Dungeon Master and Eye of the Beholder games I decided to build a 3d-engine for that kind of game.

 

A scene from Dungeon Master - tasty monsters!

The principle is simple - you only allow the player to turn 90 degrees and the entire world is built up of square blocks. When the player moves he always moves one square at a time. This means that we don't need 3d models of everything, 2d sprites are enough. All we need is to draw everything from all four sides and we are done! We get the 3d effect by drawing the objects furthest away before those that are closer.

Creating the effect in SilverTile

Doing this in SilverTile turned out to be quite easy. SilverTile already supports layering of sprites, it supports sprites of any size at any location and it supports transparent pixels. The major job was to decide where to place each sprite. We have three images for walls on each z-level supported by the game - front facing, left and right.

 

Wall tiles: Left, front facing, right

The screenshot below shows a screenshot from the game engine. The wall on the left is made up by three images stiched together, the floor and roof are static pictures.

A screenshot from the game engine running in Silverlight

The figure below shows and overhead view of the rendered scene. The red squares are walls and the green are floor.

The wall layout rendered in the screen shot

I have built a prototype game that runs in both Silverlight and on Windows Phone 7. The game lets you explare a randomly generated maze and is controlled by using the arrow keys on Silverlight and touch gestures on WP7.

The game runs on Windows Phone 7 as well as on Silverlight

You can try the Silverlight verison here. Contact me if you are interested in the source code. The game uses an unreleased version of Silvertile and the source code is quite messy (a real prototype!), so I won't post it here. :-)

 

Update (27. september 2010):

I decided to use my code and build a simple dungeon exploration game and submit it to the Norwegian Windows Phone 7 developer contest. I got a designer buddy (@hiemil) to make a pretty user interface, and I borrowed Ralf Hinrichsens custom DMJava graphics to draw the dungeon and the monsters. The end result was a much prettier game than what you can see on the screens here. Watch a short gameplay video here:

 

 

.NET, Silverlight, WP7 , , ,

Using the XKCD color survey for something useful

4. mai 2010

Update:

I just installed Moonlight Preview 7 in Ubuntu and the color picker almost works. :-) You can browse the colors and select some, but searching doesn't work properly.

 

XKCD just published the results of a survey where people would try to name a bunch of colors. The result, published here, is fun to read and for me it was really inspiring.

One of the data sets that were published was a list of popular color names along with their equivalent HTML color values. Since playing with colors is fun, I decided to take this list and turn it into .Net color constants. In .Net you have lots of defined color constants like Color.Blue and Color.Cornsilk, but even the creative ones are not as interesting as the colors Vomit (brown/green), Dark Periwinkle (a bluish color), Battleship Grey (grey like a battleship) or BabyShitBrown (don't ask). 

Interesting colors

The result is the XKCDColors class. I made two versions, one that returns System.Drawing.Color values and one that returns System.Windows.Media.Color values. The first is used with the System.Drawing namespace and WinForms applications, while the second is used for WPF and Silverlight applications.

To visualize the colors I created a tiny Silverlight 4 application that lists them all. Open it here.

And if you want to download the color files you can find them here:

XKCDColors.zip (20.47 kb)

 

Update:

After a suggestion from Randall Munroe himself I added a search box to the application. Now you can enter the hex notation for a color and get out the closest named color.

kick it on DotNetKicks.com

.NET, Silverlight, WPF , ,

New version of the sample application is ready.

8. april 2010

Edit:

I found a few nasty bugs in this version, so I uploaded a new one. This version also has even more monsters to hunt, so have fun!

 

Try it here!

The game is only available in Silverlight 4 at the moment.

 

New monsters!

Any comments?

Bugs?

.NET, Silverlight , ,

SilverTile needs your help!

9. mars 2010

A few days ago I discovered a very interesting project. Ryan Corradini has a project named Canvassa that is a HTML5/Canvas based Zelda clone. He does more or less the same thing I do with SilverTile but his approach is quite different. His blog is quite interesting and especially the posts about reverse engineering the game map based on a huge picture was very interesting.

Canvassa

 

Inspired by Ryans posts I wrote a simple C# program that would parse the entire map for The Legend of Zelda (I found the map here) and spit out tile images and Xaml code that SilverTile could utilize. (More on this in a later post - it was quite fun actually!)

The entire game world - click the image for the full 4096 pixel wide version

 

With this in place I think SilverTile is ready to be tested by a broader audience than me and a couple of friends. So that is where you dear reader come in.

I need you to test out two versions of SilverTile, one running under Silverlight 4 beta and one running under Silverlight 3. If you only have Silverlight 3 installed then just run that one. :-) What I am after is feedback on wheter I need to optimize the game engine or not. In its current state the engine is full of naive implementations that could probably be easily optimized, but I don't want to spend unnecessary time on it. I am also interested in getting feedback on the game engine itself. Does it work? Is it playable? What should I change?

Monsters! This is what awaits you if you move left from the start area

 

Once the game is running you can control your character using the arrow keys. Move to the open edges on the screen to visit other areas of the game world. If you move to the left you will face hordes of enemies and if you move up you will face a few enemies. All other areas are empty, and you cannot fight the monsters at the moment. If you die just reload the page to start again.

What I want you to do is the following:

  • First move around the screen and see if you can control the player sprite properly.
  • Then move up to the next area and see if the monsters run around more or less randomly. If you run into a monster your life (the hearts) should decrease.
  • Then move back down and to the left. Here you will meet a huge number of monsters. Watch the monster counter and let me know how many monsters there are when the game starts to feel sluggish. Aslo watch the frame rate counter in the bottom of your browser window. It should be around 38-40. How long can you survive before the monsters eat you?
  • Finally explore the map a little and see how this works. Does the game engine crash or behave strangely?

 

When you are done testing I want you to leave a comment to let me know what kind of computer you are running and what your results were. I am particularily interested in hearing how many monsters the game engine could handle and if you experience anything strange. Which operating system and browser you are using is also interesting.

Click here for the Silverlight 4 version and here for the Silerlight 3 version.

Thanks in advance for helping!

kick it on DotNetKicks.com

.NET, Silverlight , ,

SilverTile: Working on the game

22. februar 2010

It's time for another project update.

I just uploaded a new version of the SilverTile sample application. The new version has four areas that you can move between freely and lots of monsters you can hunt. The monsters have different AI, the blue ones will try to hunt you while the red ones will move randomly.

Lots of dangerous monsters!

Since my last update I have added some features to the game engine:

  • A simple keyboard input handler
  • Improved area transitions
  • Improved collision detection
  • Layering of sprites (z-index)
  • Improvements to the monster spawning process

All the changes I have done are based on the needs of my sample game. A more structured keyboard input was needed as the complexity of the game grew.

Area transitions needed to be directional so that you can transition into a tile with an area transition back without being stuck in an endless loop.

I found some bugs in the collision detection algorithm that I fixed (Yay for TDD!), but my implementation is really naive. I would be grateful if anyone could help with a better algorithm. :-)

Layering of sprites was something I really wanted the engine to have, but I didn't need it until I was to render the players sword. The sword is drawn underneath the player sprite when the attack animation starts, and I needed to make sure the sword wasn't draw on top of the player.

The monster spawning process was modified so that monsters can be spawned immediately when a level is loaded. The classic The Legend of Zelda spawns enemies this way, so I need to support it.

All game levels were drawn using the editor application I wrote. The application is really simple, but it allows me to draw the game levels and export them as Xaml easily, so I am happy with it.

Whats next

With a more complete game engine I think it is time to build a better user interface for the game. I have added hit points to the player, but I need to display them as hearts as in the classic Zelda.

I also need to build more game levels and start adding items to the game. Monsters should drop coins that you can use to buy stuff.

And then I need to add text rendering and an intro screen and a game over screen!

... So there is still lots of work to do.

kick it on DotNetKicks.com

.NET, Silverlight , ,

Update: The DataTable meets dynamic - improved!

12. februar 2010

A few days ago I blogged about a tiny fun project of mine, where I added dynamic type support to the DataTable and DataRow classes.

This was fun, and the code works as intended, but it has a two shortcomings: There was a bug preventing you from setting values of regular properties on the DynamicDataRow type, and you couldn't add new columns using dynamic properties.

Naturally, I had to fix this, so here it is: The DynamicDataTable v2!

What is new?

Most of the code is the same as last time, but this time the useage is even simpler. You just create a new DynamicDataTable object, add a new row using the NewRow method and assign values to the properties you need. Look at this:

// Create a DataTable
var tb = new DynamicDataTable();

// Row using dynamic syntax
dynamic row = tb.NewRow();
row.aa = "Dynamic here!";
row.bb = 44;
row.cc = DateTime.Now; 
tb.Rows.Add(row);

// Access column values using property accessors instead of using the indexer
Console.WriteLine("AA: " + row.aa);
Console.WriteLine("BB: " + row.bb);
Console.WriteLine("CC: " + row.cc);

If you compare this with the previous version you see that I have removed the column definitions. Now when the DynamicDataRow intercepts a call to a property set for a property that doesn't exist it will check its DataTable to see if there is a column with that name. If it can't find a column with that name it will add a new column and set its datatype to the type of the assigned value. In the above example our table ends up with three columns: "aa" of type String, "bb" of type Int32 and "cc" of type DateTime. Later you can access the DataTable as a regular table if you want.

The updated source code

I have uploaded an updated version of the source code if you are interested: DynamicDataTable.zip (4.57 kb)

kick it on DotNetKicks.com

.NET

Creating a monster: The DataTable meets dynamic

9. februar 2010

This is just for fun, so don't use this at work! :-)

Some day ago we had a discussion on Twitter about using the DataTable and DataSet types in .Net. We talked about the differences between typed and untyped DataSets and the merits of both. 

Personally I don't like typed DataSets, not only do I see them as unnecessary, but the DataSet Designer in Visual Studio is terribly buggy and unstable. The one place where typed DataSets have an advantage is in code readability - using property names is easier to read than accessing the DataRow using the indexer property.

Having just read about the dynamic type support in C#4 I got the idea that we could use it to get the pretty syntax of the typed DataSets without all their extra annoyances. Not that it would be very useful, but it would be a good chance to get to know dynamic typing better while writing some fun code. After all, this combines the "old" techonology of the DataTables with the new fancy technology of dynamic types. What could be better?

What I would like to do

Since this is just for fun, I don't care about writing a very robust implementation. What I want is a way to do the following:

// Create a DataTable object
var tb = new DynamicDataTable();

// Add some columns using old-style syntax
tb.Columns.Add("aa", typeof(string));
tb.Columns.Add("bb", typeof(Int32));

// Add a row using dynamic syntax
dynamic row = tb.NewRow();
row.aa = "Dynamic here!";
row.bb = 42;
tb.Rows.Add(row)

// Access column values using property accessors instead of using the indexer
Console.WriteLine("AA: " + row.aa);
Console.WriteLine("BB: " + row.bb);

Note that this syntax is somewhere between the regular DataTable syntax and the syntax for typed DataTables.

Implementing it

I implemented the DynamicDataTable using three classes: The DynamicDataTable itself, a new DynamicRowsCollection that replaces the DataRowCollection of regular DataTables and the DynamicDataRow that extends the DataRow type with dynamic capabilities.

The DynamicDataTable simply wraps a DataTable and overrides or overwrites a few methods. By overriding the NewRowFromBuilder, GetRowType methods and then overwriting the NewRow method I can force the DynamicDataTable to return my DynamicDataRow objects. In addition I overwrite the Rows collection with my own DynamicRowsCollection type to ensure that we only store DynamicDataRow objects.

public class DynamicDataTable : DataTable
{

  private DynamicRowsCollection _rows;

  protected override DataRow NewRowFromBuilder(DataRowBuilder builder)
  {
    return new DynamicDataRow(builder);
  }

  protected override Type GetRowType()
  {
    return typeof(DynamicDataRow);
  }

  public new DynamicRowsCollection Rows
  { 
    get
    {
      if (_rows == null)
      {
        _rows = new DynamicRowsCollection(base.Rows);
      }
      return _rows;
    }
  }

  public new DynamicDataRow NewRow()
  {
    return (DynamicDataRow)base.NewRow();
  }

}

I then wrote a DynamicRowsCollection type as a replacement for the old RowCollection. It implements the IList<DynamicDataRow> interface but all it does is to reroute all method calls to the contained RowCollection:

public class DynamicRowsCollection : IList<DynamicDataRow>
{

  private DataRowCollection _rows;

  public DynamicRowsCollection(DataRowCollection rows
  {
    _rows = rows;
  }

  #region IList implementation

  // Snipped lots of dumb code...

Finally I implemented the DynamicDataRow. This is my specialized DataRow that reroutes all attemps at getting or setting properties to access the indexer instead. I hit upon a challenge here where I first rerouted all property calls, also those that were to existing properties. This meant that trying to access the DataRow.Table property ended up in an attemt to access a column named Table. To fix this I added a check of whether there already exists a property with the given name. I should also add the same check when setting property values, but I haven't done so yet.

public class DynamicDataRow : System.Data.DataRow, IDynamicMetaObjectProvider
{

  public DynamicDataRow(DataRowBuilder builder) : base(builder)
  { }

  public DynamicMetaObject GetMetaObject(Linq.Expressions.Expression parameter)
  {
    return new DataRowDynamicMetaObject(parameter, this);
  }

  private class DataRowDynamicMetaObject : DynamicMetaObject
  {

    private DataRow _row;

    private DataTable _table;

    public DataRowDynamicMetaObject(Expression parameter, DataRow row)
      : base(parameter, BindingRestrictions.Empty, row)
    {
      _row = row;
      _table = row.Table;
    }

    public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
    {

      // Look for an existing property with this name
      var existingProperty = typeof(DataRow).GetProperty(binder.Name);

      if (existingProperty != null)
      {
        // Call the property directly
        var callProperty = Expression.Property(Expression.Constant(_row),  existingProperty);
        var callPropertyConverted = Expression.Convert(callProperty, binder.ReturnType);
        return new DynamicMetaObject(callPropertyConverted, BindingRestrictions.GetInstanceRestriction(Expression, _row), _row);
      }
      else
      {
        // Try to find a column with the name of the property
        var indexer = typeof(DataRow).GetProperty("Item", new Type[] { typeof(string) });
        var getRow = Expression.Constant(_row);
        var colName = Expression.Constant(binder.Name);
        var getIndexerValue = Expression.Property(getRow, indexer, colName);
        return new DynamicMetaObject(getIndexerValue, BindingRestrictions.GetInstanceRestriction(Expression, _row), _row);
      }

      public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
      {

        var indexer = typeof(DataRow).GetProperty("Item", new Type[] { typeof(string) });
        var getRow = Expression.Constant(_row);
        var colName = Expression.Constant(binder.Name);
        var setIndexerValue = Expression.Property(getRow, indexer, colName);
        var newValue = Expression.Constant(value.Value, typeof(object));
        var assignColValue = Expression.Assign(setIndexerValue, newValue);
        return new DynamicMetaObject(assignColValue, BindingRestrictions.GetInstanceRestriction(Expression, _row), _row);
      }
    }
  }

The first thing to note here is that the DynamicDataRow itself is really simple. All it does is to inherit from the DataRow and add an implementation of the IDynamicMetaObjectProvider interface. This interface has only one method named GetMetaObject. My implementation of GetMetaObject is also simple - all it does is to return an instance of a DataRowDynamicMetaObject.

The DataRowDynamicMetaObject is more complex. It implements the BindGetMember and BindSetMember methods that handles all property calls for the dynamic object.

The implementation of BindGetMember will first check if there exists a property with the requested name. This is done by checking the return value of the Type.GetProperty method. If a property exists we just call itand return the value. If the property doesn't exist, we first get a reference to the indexer property of the DataRow. We then call the indexer passing it the name of the property/column we ask for and return the value.

The implementation of BindSetMember is somewhat easier since we don't care about existing properties here. The code is similar to that for BindGetMember but we end up with an Assign expression where we assign the new value to the column.

Possible improvements

My code is not at all meant to be used in a real-life scenario, so I haven't cared about performance of error checking at all. The most obvious improvement would be to cache the generated DynamicMetaObject objects for each property. This could be done using a simple Dictionary shared between all instances of the DataRowDynamicMetaObject type. In addition we should fix the BindSetMember method to check if the property exists on the DataRow type. On top of that we should add some error checking code to make sure the types we assign to the columns are compatible with the columns data type.

Another nice improvement would be to add new columns to the DataTable the first time we assigned a value to a property. This would save us the calls to DataTable.Columns.Add that defines the table.

Conclusion

The dynamic type support in .Net 4 is really nice and opens up some really nice possibilities. It also enables some terrible hacks like the DynamicDataTable.

Feel free to download the source code if you want: DynamicDataTable.zip (4.46 kb)

 

kick it on DotNetKicks.com

.NET

Pixel perfect positioning of list elements in WPF

21. januar 2010

This is something I had to look up several times myself, so I thought I should write it down for later reference.

I was building a simple level editor for SilverTile (more about that in another post later) and wanted to place the map tiles in a grid-like fashion. This could be done using my dynamic Grid control, but I wanted pixel perfect control of where the tiles were placed on screen. Note the gaps between the grid rows in the following screen shot.

Fail!

Fail! Note the gaps between the tiles!

To do this I would need to use a Canvas control and place each tile using the Canvas.Left and Canvas.Top properties to set the position.

Win! This is what we want. Pixel perfect placement of our images!

The challenge is that the Canvas control doesn’t support list binding directly, so you must use some other control to accomplish this. Luckily there is a solution available by using the ItemsControl class. The ItemsControl is a list control that lets you specify which control should be the root element. In our case we will use a Canvas control as the root and then use data binding to specify the values for the Canvas.Left and Canvas.Top properties.

Using the ItemsControl

To exemplify the usage of the ItemsControl I first created a simple view model for the application. This was simply a list of TileData objects where each describes one tile. Each TileData object has an image source and Left and Top properties. The Left and Top properties tell where the tile should be placed on screen. In a real application your view model would probably be more complex and possibly calculate the positions based on some other data.

// The TileData class describes a tile
public class TileData
{
    public Uri Image { get; set; }
    public double Left { get; set; }
    public double Top { get; set; }
}

Now, with the view model in place we can setup our application.

<Grid Name="Root" Loaded="Root_Loaded">
    <Grid.Resources>
        <Style x:Key="ContainerStyle">
            <Setter Property="Canvas.Left" Value="{Binding Left}" />
            <Setter Property="Canvas.Top" Value="{Binding Top}" />
        </Style>
    </Grid.Resources>
    <ItemsControl Name="map" ItemsSource="{Binding}" ItemContainerStyle="{StaticResource ContainerStyle}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas Width="{Binding Path=Root.ActualWidth}" Height="{Binding Path=Root.ActualHeight}" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Image Source="{Binding Image}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

Here we have a Grid as the root element of the application. I’ve used a grid since it will be sized dynamically when the window is resized, something the Canvas control doesn’t. We then have the ItemsControl that has its ItemsSource bound to our data context. The ItemsSource is the list of TileData objects that is used to describe the map.

And now we get to the interesting part: The ItemsControl.ItemsPanel property. This property defines which control should be the container into which all our list items are placed. By setting this to a Canvas control we end up with a layout where you can set your child controls position as you want.

Further we have the ItemsControl.ItemsTemplate that tells how you want each object in your ItemsSource to be rendered. In our case we render it as an Image control with its source bound to the Image property of your TileData object.

The final missing part is how we place our controls. The obvious way to do this would be to set the Canvas.Left and Canvas.Top properties of our Image control by binding them to the Left and Top properties of our TileData object. One would expect this to work but if you try it you will see that all our controls are placed at the top left corner of the canvas, with Canvas.Left = 0 and Canvas.Top = 0. The solution is to create a style that sets the Canvas.Left and Canvas.Top properties and to assign that to the ItemContainerStyle property of the ItemsContainer. By doing this you will see that our Image controls are placed correctly where we want them.

Using Snoop to find out what really happened here

To understand what really happened here we need to examine the control hierarchy our Xaml code generates. A good tool to do this is Snoop. It lets you attach to a running Wpf application to examine all properties of all generated controls.

Using Snoop to look at our applications control hierarchy

Look at the above screen shot. Here you can see the control hierarchy of the GridWin application. If you look down the tree you will find an ItemsControl control with a child Border control. The Border contains an ItemsPresenter Control that contains a Canvas. This Canvas control is the one we assigned to our ItemsControl.ItemsPanel property.

The Canvas contains a bunch of ContentPresenter controls that each contains one Image control. And this is the reason why we cannot set the Canvas.Left and Canvas.Top properties of our Image controls directly. Since the images are contained in the ContentPresenter controls we need to set the properties here instead. And this is what we do when we set the ItemContainerStyle property. The style is applied to the ContentPresenter which is placed at the correct position.

Using the code

I am using this approach in a level editor application for SilverTile that I will be writing about soon. The application stores the map as a list of Tile objects where each Tile knows which row and column they should be placed in. The Canvas.Left and Top properties are then bound to the X and Y properties that are caluclated by multiplying the row or column number with the tiles width or height in pixels. The tile list is used as the ItemsSource for an ItemsControl that renders the tiles at the wanted position.

The ItemsControl is available in Silverlight as well as in WPF, so this approach works just as well there. The only challenge is that the binding of the Canvas' size to the size of the Root grid cannot be done in Silverlight 3 since it doesn't support element to element binding. This is fixed in Silverlight 4 though, so there you should be able to use the exact same approach.

kick it on DotNetKicks.com

.NET, Silverlight, WPF , ,

SilverTile: Another progress report

17. desember 2009

It's time I posted another progress report.

Since my last progress report I have implemented most of the features from my feature list. I'm not entirely happy about the Xaml support for level design, and I am still missing the support for per-pixel collision detection, but the game engine works well enough that I have implemented a VERY simple game using it. 

The game, available here, lets you control your character on a field throwing swords at some monsters. You get points for how many monsters you kill and if you are touched by a monster you die. 

Hunting monsters

Hunting monsters

As simple as it is the game demonstrates the features needed for a proper game:

  • We have collision detection - both between moving sprites (character, monster, sword) and between sprites and background (you cannot walk across mountains). 
  • We have animation support and an animated sprite can have many animations that we can choose.
  • The game area and all game assets are defined in Xaml. 
  • Graphics are reused between sprites. This means that two identical monsters share the same bitmaps in memory.

The engine is still missing some features. The most obvious one is the pixel perfect collision detection. This is a simple feature to add, but I fear that it will be a real performance killer so I postpone it until I really need it. Apart from that I feel that the framework surrounding game setup needs some work.

The current implementation lets you define one or many GameAreaGrid objects. The GameAreaGrid lets you place one rectangular sprite in each cell. You then tell the Viewport to load the grid and it will be setup as the background area of your game. To change maps you tell the viewport to load another GameAreaGrid object.

While this works well enough I would like it to be even simpler to use.

The idea is to add support for area transitions to cells in the GameAreaGrid so that when the player enters one of these we automatically loads the new grid and places the player at the new location. This should allow us to setup an entire game world using only Xaml. I'm not entirely sure what would be the best way to define an area transition but I think it would be nice to add an AreaTransitions collection property to the GameAreaGrid where each object in the collection described a transition that would be performed when the player enters a given cell. A transition would be from a cell (grid row and column) to a new cell in another GameAreaGrid. The reference to the GameAreaGrid would be a regular object reference that could be modeled as a binding to a StaticResource in Xaml. This still gives us the option of designing the GameAreaGrid in Xaml or in code if we prefer. 

I would also like to allow random placement of enemies in a GameAreaGrid. Either completely random or by identifying cells where mosnters can spawn. The types of monsters, the number of monsters and how often they spawn would also have to be specified.

So that will be my plan for the week until christmas. Implementing more support for game mechanics, paving the way for a complete game engine :-)

kick it on DotNetKicks.com

.NET, Silverlight , ,

SilverTile: Old-school gaming on a modern platform - progress report

8. desember 2009

It's time for a progress report.

The last week I have been adding basic features to SilverTile. The first feature was to add basic rendering support. My first attempt used Array-copy functions to copy pixel data from the sprite to the viewport. This worked well, but it did not support alpha blending (transparency) of pixel data. To improve this I added some code from the Silverlight Games 101 blog that allowed rendering of bitmap data from one WriteableBitmap to another. I modified the code somewhat to support rendering of data from any IRenderable and then I had the rendering support I needed.

The intial architecture of SilverTile defined each sprite object as having its own pixel data. This is fine as long as you have only a few sprites or if each sprite have an unique appearance, but in most cases you will have many sprites using the same image. One example is the walls of a game area. I model each wall segment as an unique sprite, but each is built up of the same image. So instead of having each sprite have its own pixel data I refactored out the pixel data into a Frame object that could be reused between sprites. This also lay the ground for animation support later.

Zelda walking

Link walking!

To set up a game area I want to support two modes. One mode should be building game areas in code by using the AddBackgroundSprite() method of the Viewport class. This lets you add one sprite at a time at the desired location. While building the game area in code works well, I wanted to support using Xaml to describe the game area and the graphical resources used by a game. Since Silverlight only allows classes that inherit from UIElement to be named (given the x:Name and x:key attributes) in Xaml I had a choice of either letting the Sprite classes derive from UIElement or using a separate set of classes to describe the game area. I cholse the latter option and built a set of classes that can be instansiated in Xaml and that describes a game area, a game tile and a frame. I then added a SetGameArea helper method to the viewport that reads the GameArea data and performs the setup.

Finally I added support for animated sprites. An animation is a list of IFrame objects in combination with a frame rate. Each time the Update method of the animated sprite is called, we check if the elapsed time is greater than the time a frame should last and if it is we switch frames to the next frame. When we reach the last frame in the animation we go back to the first frame again. Although I will need for sprites to support multiple animations (like walk left and walk right), this is a good starting point.

On top of all this I have written tests for everything. This really helped me when refactoring the code to use IFrame and the bitmap blitting.

If you have the Silverlight 4 beta installed you can watch a live demo here: http://rag.no/st/silvertile.html. (Try clicking on the game area!) Or you can download the source code here: http://silvertile.codeplex.com/

 

kick it on DotNetKicks.com

.NET, Silverlight , ,