This project has moved. For the latest updates, please go here.

Improvement 1: The SnakeArena control

Now we have created a fully working Silverlight port of the Windows Forms Nibbles.NET game, we can start working on making a few enhancements to allow us to make use of some of the more cool technology that Silverlight has to offer. The first improvement was to add another custom Silverlight control called SnakeArena. This would host the game playing area, but not include the labels used to display current score and high score. This gives the advantage that the SnakeArena can be more easily repositioned within the overall Silverlight control. The original QBASIC Nibbles game used a grid size of 50 rows by 80 columns, but the top two rows were not used. The SnakeArena control has a grid of 48 rows by 80 columns to avoid the unwanted two blank rows being rendered.

Positioning isn't the only benefit of moving the snake arena to its own control. Silverlight's powerful rendering capabilities mean that now we could easily do any of the following:
  • Resize the snake arena to any scale using a simple transform
  • Fade the snake arena in or out
  • We could even rotate the arena to make the gameplay more challenging!

All of these would be extremely awkward to add on to the Windows Forms version, but are trivial in Silverlight (or WPF).

Improvement 2: Collapsing background

One of the weaknesses of this application is the use of an array of rectangles to present the majority of the graphics. As well as creating a huge number (almost 4000) of rectangles, this also limits the possibilities for nice graphical touches. The first step is to simply make background cells visibility to Collapsed, rather than painting each cell with a solid background colour. While this is not a radical change, it opens the door for more visual enhancements:
  • The background can now be a gradient instead of a solid colour
  • We could be even more adventurous and use pictures, video footage, or animations to form the background of each level with minimal code required.

Improvement 3: Snake Polyline

Now we come to terms with the fact that the snake itself does not look very impressive. Each snake simply has a Queue of points which represents the cells it occupies. Each timer tick, another point is added to the front of the queue, and one is taken off the end as well unless the snake is currently "growing" because it has just eaten a number.

Rather than colouring a rectangle for each point occupied by the snake, we will now allow the Snake class itself to render itself. We will do this by using a Polyline:

polyline = new Polyline();
polyline.Stroke = new SolidColorBrush(color);
polyline.StrokeThickness = 0.8;
polyline.StrokeLineJoin = PenLineJoin.Round;
polyline.StrokeEndLineCap = PenLineCap.Round;
polyline.StrokeStartLineCap = PenLineCap.Round;


We have given the polyline rounded ends and corners, which will make the snake look a bit nicer. We have also made the StrokeThickness 0.8 which will mean that the snake will be slightly thinner, again improving the visual appearance as you can now see where it has been more clearly.

For some reason, the Points property of a Polyline is a fixed size array of Point structures, which means that whenever we add or remove a point, we will need to completely replace the Points property with a new array. This is despite the Silverlight 1.1 alpha documentation claiming that the Points property is a PointCollection object.

When we add a new point to the snake, we translate its position by 0.5 so that it will be drawn in the centre of the grid square it operates on.

        public void Enqueue(Position position)
        {
            body.Enqueue(new Point(position.X + 0.5, position.Y + 0.5));
            polyline.Points = body.ToArray();
        }


The Snake can now give its own graphics object to the SnakeArena, meaning that the SnakeArena no longer has to render the snake itself - it simply adds the Snake's Graphics element to its Canvas.

public FrameworkElement Graphics
{
   get { return polyline; }
}


You may have noticed that the Polyline will draw the line connecting up points in a 48 x 80 area, even though the SnakeArena itself draws blocks 8 pixels by 8 pixels wide. The RenderTransform property of the Polyline makes it simple to expand the snake to be the right size for the snake arena.

ScaleTransform transform = new ScaleTransform();
transform.ScaleX = 8;
transform.ScaleY = 8;
polyline.RenderTransform = transform;


So now the snake can draw itself, and looks much better for it. The SnakeArena creates a new Canvas with a transparent background for the Snake to draw itself onto. This is simply to allow the PauseControl to remain the topmost control, even though we are adding and removing Snake Polylines every time a new game is started.

This change again opens up the door for future graphical enhancements:
  • The snake could have a gradient brush, or even an animated gradient to create a slithering appearance
  • The snake could animate its end-point to slide smoothly rather than jump one block at a time.
  • The snake could change from being a Polyline to a complicated Canvas made up of all kinds of visual elements, and no change would be needed to the SnakeArena control.

Improvement 4: Level drawing

The final improvement is for each level to draw itself onto a Canvas, constructing Rectangles as needed, rather than simply reporting the coordinates of each square to be drawn. This means we can finally get rid of the array of 4000 Rectangles, and also that the obstacles in each level can have rounded edges, along with any other graphical niceties we can think of. This was implemented by creating a new XAML control called LevelControl.

Improvement 5: Making it Scriptable

What if we want to have some buttons on our web page that start a new game, or checkboxes that turn various gameplay options on. This requires us to make our Page class scriptable. We will make the NewGame function accessible to JavaScript.

First we must mark both the Page class and the NewGame function with the Scriptable attribute, found in the System.Windows.Browser namespace.

using System.Windows.Browser;
...
namespace SilverNibbles
{
    [Scriptable]
    public partial class Page : Canvas
    {
        ...
        [Scriptable]
        public void NewGame(int players)
        {
           ...


The next step is to register a variable that JavaScript can use to access the instance of the Page class. We do this in the Page's Loaded event handler. We have chosen to call our instance, "SilverNibbles".

public void Page_Loaded(object o, EventArgs e)
{
    ...
    WebApplication.Current.RegisterScriptableObject("SilverNibbles", this);


Now we will create some buttons in our main HTML page that will start a new game, along with some JavaScript that handles them. Notice I have set the focus to the Silverlight control which will ensure we have keyboard focus for the new game. Also notice that our registered scriptable object is referenced as a member of the Content property of the Silverlight control.

<head>
    <title>SilverNibbles</title>
    <script type="text/javascript" src="Silverlight.js"></script>
    <script type="text/javascript" src="SilverNibbles.html.js"></script>    
    <script type="text/javascript">
    function onNewGameClick(players) {
       var silverlight = document.getElementById('SilverlightControl');
       silverlight.focus();
       silverlight.Content.SilverNibbles.NewGame(players);
    }
    </script>    
</head>
<body>
   ...
   <p>New game: 
      <input type="button" onclick="onNewGameClick(1)" value="One Player" />
      <input type="button" onclick="onNewGameClick(2)" value="Two Players" />
   </p>
</body>

Animation

Coming soon...

Future Possibilities

So we have finally ended up with not just a Silverlight port of a Windows Forms application, but one that begins to explore the new possibilites that the Silverlight rendering engine offers us. As well as the graphical enhancements described earlier, there are a couple more Silverlight technologies we could utilise to enhance this application further.

The first is to integrate more fully with the host web page.
  • A new game button could be added, which could set the focus to the control and launch a new game, possibly avoiding the user wondering why the keys are unresponsive
  • Text boxes and check boxes could allow the user to customise the gameplay, setting colours or enabling various ways of enhancing the gameplay:
    • Snakes that get faster
    • Snakes that only grow, requiring you to take care not to box yourself into a corner
    • Snakes and walls that go invisible, requiring you to remember what you were doing
    • Psychedelic background colours and rotating display
    • Walls that can move

Another avenue for improvement would be to make use of Siverlight's audio playback to create background music and sound-effects for various events.

Conclusion

Silverlight offers a number of great benefits over Windows Forms for creating casual games
  • You can host the game on your website, without the need for any server side hosting, or the need for the user to install your app on their PC (they will of course need Silverlight)
  • The power of the Silverlight Rendering engine puts advanced graphical techniques within the reach of developers without the need to learn any complicated GDI+ APIs.
  • The XAML based nature of Silverlight means that you could collaborate with a graphic designer and incorporate their work very easily into your code.

Last edited May 31, 2007 at 9:46 PM by markheath, version 1

Comments

No comments yet.