Silverlight and Windows Phone 7 Game

With the release of Silverlight 4 RC the Windows Phone 7 developer tools I wanted to take a stab at building a Silverlight application for both the web and phone to see what kind of differences there are between the two. Except for the inability to use the ChildWindow I was able to build out controls and share them between the two applications. The main differences were in the MainPage.xaml that is created, along with the default styles, when you create a new Silverlight application for the web and Windows Phone 7. Of course,

I decided to create a game (called ShapeAttack) to see how it would perform on the phone emulator. Sad to say the performance on the emulator is very poor but I would imagine that it would be better on the physical device but as I do not own a Windows Phone 7 yet the emulator has to do for now. For that reason I would recommend doing this parallel type of development so you can actually test your application.

What I did was create all of the game code in UserControls, including the main game surface, then I linked the files from the standard Silverlight project into the phone project.

The game is very simple and kind of cheesy :D, just click on the shapes to destroy them. And of course you can download the source code for ShapeAttack(2.8MB) or play ShapeAttack online.



Performance Tips for Silverlight on Windows Phone 7

Andy Beaulieu has some helpful performance tips for Windows Phone 7 and Silverlight primarily focused on games of course.


Silverlight Community

Jeff Weber, the guy behind the Farseer Physics Engine, has posted an An Open Letter To Microsoft Regarding The Silverlight Game Development Community. I fully agree and want to add my voice in the request for an XNA-like community site!

From Jeff’s post:

“I hereby request, on behalf of all the future and present Silverlight game developers,  an awesome Silverlight game development portal along the lines of what exists for the XNA Creators Club Online community.”


Pirates Video

Here is a video of the Pirates game:



General Purpose Sprite Class

On the heels of some great posts by Bill Reiss on Sprites Part 1 and Sprites Part 2 in Silverlight I wanted to post some general base sprite classes that I use. The classes are intended to be used with the SilverSprite framework.

These classes all exist in an assembly I lovingly call the “Shady Engine” (to explain the namespaces)

The base class I used is ingeniously called Sprite. It implements an interface called ISprite. I added the interface in order to create an interface called IPlayer that the main Game class uses.


using System.Windows;using Microsoft.Xna.Framework;namespace Shady.Sprites{    public interface ISprite    {        ISprite Owner { get; set; }        Vector2 Position { get; set; }        double Rotation { get; set; }        System.Windows.Point Scale { get; set; }        double Width { get; set; }        double Height { get; set; }        Rect Bounds { get; }        bool IsActive { get; set; }    }}
.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{ background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }

And here is the Sprite.cs file:

using System;using System.Windows;using System.Windows.Controls;using System.Windows.Markup;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Shapes;using Microsoft.Xna.Framework;namespace Shady.Sprites{    [TemplatePart(Name = PART_RootElement, Type = typeof(Canvas))]    [TemplatePart(Name = PART_ContentElement, Type = typeof(ContentControl))]    [TemplatePart(Name = PART_DebugCenter, Type = typeof(Ellipse))]    [ContentProperty("Content")]    public class Sprite : Control, ISprite    {        public const string PART_RootElement = "PART_RootElement";        public const string PART_ContentElement = "PART_ContentElement";        public const string PART_DebugCenter = "PART_DebugCenter";        protected Canvas RootElement { get; set; }        protected ContentControl ContentElement { get; set; }        protected Ellipse DebugCenterElement { get; set; }        protected TranslateTransform TranslateTransform { get; set; }        protected RotateTransform RotateTransform { get; set; }        protected ScaleTransform ScaleTransform { get; set; }        protected double HalfWidth = 0;        protected double HalfHeight = 0;        public ISprite Owner { get; set; }        public object Content        {            get { return (object)GetValue(ContentProperty); }            set { SetValue(ContentProperty, value); }        }        public static readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(object), typeof(Sprite), new PropertyMetadata(null));        public bool Debug        {            get { return (bool)GetValue(DebugProperty); }            set { SetValue(DebugProperty, value); }        }        public static readonly DependencyProperty DebugProperty = DependencyProperty.Register("Debug", typeof(bool), typeof(Sprite), new PropertyMetadata(false, new PropertyChangedCallback(Sprite.OnDebugPropertyChanged)));        private static void OnDebugPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)        {            var sprite = obj as Sprite;            if (sprite == null)                return;            if (sprite.DebugCenterElement != null)                sprite.DebugCenterElement.Visibility = (bool)e.NewValue ? Visibility.Visible : Visibility.Collapsed;        }        public Vector2 Position        {            get            {                var x = (double)GetValue(Canvas.LeftProperty);                var y = (double)GetValue(Canvas.TopProperty);                return new Vector2((float)x, (float)y);            }            set            {                SetValue(Canvas.LeftProperty, (double)value.X);                SetValue(Canvas.TopProperty, (double)value.Y);            }        }        public virtual double Rotation        {            get { return this.RotateTransform.Angle; }            set { this.RotateTransform.Angle = value; }        }        public System.Windows.Point Scale        {            get { return new System.Windows.Point(this.ScaleTransform.ScaleX, this.ScaleTransform.ScaleY); }            set            {                this.ScaleTransform.ScaleX = value.X;                this.ScaleTransform.ScaleY = value.Y;            }        }        public new double Width        {            get { return base.Width; }            set            {                base.Width = value;                HalfWidth = Width * 0.5;                TranslateTransform.X = -HalfWidth;                if (this.DebugCenterElement != null)                    Canvas.SetLeft(this.DebugCenterElement, HalfWidth);            }        }        public new double Height        {            get { return base.Height; }            set            {                base.Height = value;                HalfHeight = Height * 0.5;                TranslateTransform.Y = -HalfHeight;                if (this.DebugCenterElement != null)                    Canvas.SetTop(this.DebugCenterElement, HalfHeight);            }        }        public Rect Bounds        {            get            {                Vector2 position = this.Position;                return new Rect(position.X - HalfWidth, position.Y - HalfHeight, this.Width, this.Height);            }        }        private WriteableBitmap _bitmap;        protected internal virtual WriteableBitmap Bitmap        {            get            {                if (_bitmap == null && this.ContentElement != null)                {                    var content = this.ContentElement.Content;                    if (content != null && content is Image)                    {                        _bitmap = new WriteableBitmap((int)this.Width, (int)this.Height);                        _bitmap.Render((content as Image), new TranslateTransform());                        _bitmap.Invalidate();                    }                }                return _bitmap;            }        }        private bool _isActive = true;        public bool IsActive        {            get { return _isActive; }            set            {                _isActive = value;                this.Visibility = _isActive ? Visibility.Visible : Visibility.Collapsed;            }        }        public Sprite()        {            this.DefaultStyleKey = typeof(Sprite);            this.TranslateTransform = new TranslateTransform();            this.RotateTransform = new RotateTransform();            this.ScaleTransform = new ScaleTransform();        }        public override void OnApplyTemplate()        {            base.OnApplyTemplate();            this.RootElement = GetTemplateChild(PART_RootElement) as Canvas;            this.ContentElement = GetTemplateChild(PART_ContentElement) as ContentControl;            this.DebugCenterElement = GetTemplateChild(PART_DebugCenter) as Ellipse;            if (DebugCenterElement != null && !Double.IsNaN(this.Width) && !Double.IsNaN(this.Height))            {                Canvas.SetLeft(DebugCenterElement, HalfWidth - 1.5);                Canvas.SetTop(DebugCenterElement, HalfHeight - 1.5);            }            if (this.RootElement != null)            {                var group = new TransformGroup();                group.Children.Add(TranslateTransform);                group.Children.Add(RotateTransform);                group.Children.Add(ScaleTransform);                this.RootElement.RenderTransform = group;                this.RootElement.RenderTransformOrigin = new System.Windows.Point(0, 0); // At 0,0 because the translate transform positions the sprite.            }            this.Initialize();        }        public virtual void Initialize()        {        }        public virtual void Update(GameTime gameTime)        {        }        public virtual void Draw(GameTime gameTime)        {        }        /// <summary>        /// Re-initializes the sprite.        /// </summary>        public virtual void Reset()        {            this.IsActive = true;            this.Owner = null;        }        protected static void OnDependencyPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)        {            var sprite = obj as Sprite;            if (sprite == null) return;            sprite.Initialize();        }    }}
.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{ background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }

Because Sprite is a templated control there is also some XAML to go along with it (You will need to place this in a themes/generic.xaml file):

<Style TargetType="sprites:Sprite">        <Setter Property="Background" Value="{x:Null}"></Setter>        <Setter Property="Foreground" Value="{x:Null}"></Setter>        <Setter Property="Template">            <Setter.Value>                <ControlTemplate TargetType="sprites:Sprite">                    <Canvas x:Name="PART_RootElement" Background="{TemplateBinding Background}">                        <ContentControl x:Name="PART_ContentElement"/>                        <Ellipse x:Name="PART_DebugCenter" Width="3" Height="3" Fill="Red" Visibility="Collapsed"/>                    </Canvas>                </ControlTemplate>            </Setter.Value>        </Setter>    </Style>
.csharpcode, .csharpcode pre{ font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt{ background-color: #f4f4f4; width: 100%; margin: 0em;}.csharpcode .lnum { color: #606060; }

That is my basic Sprite class, I will post my animated sprite class next.


Yar, I do be re-visiting Pirates!

One of the first games I started building in Silverlight I called Pirates! Since working on Perenthia and various other tasks I have not re-visited the game for a long time. I really would like to get this game finished so I have to decided to spend some time working on it. I hope to include some videos soon that show the game in varied stages of development. The first screen shot displays what currently exists after implementing some path finding and the SilverSprite library:

Here is the post from the game blog: Pirates Game in Silverlight


XNA and Silverlight Development

Mad Laumann has a new post up about the development progress of his game Little Longhorn, a tower defense game written for XNA and Silverlight using the SilverSprite framework. I have been following his progress with the game and have been able to play the early versions of it (both XNA and Silverlight) and have found it quite fun and challenging. The game has grown quite a bit over the last few months with game play and graphics improving all the time. Needless to say Mads is becoming an authority on XNA/Silverlight combination platform development so be sure to check out his blog A Silverlight Playground.


SilverMap – A Silverlight Game Tile Map and Editor

I am happy to announce that I have uploaded a new project called SilverMap to CodePlex. SilverMap is a tile map control for Silverlight games that uses layered maps where the higher layers are drawn over the lower ones. In addition, individual tiles have a z-index position and can be drawn over one another. You can also place the tiles anywhere on the map, instead of in a tight grid, which is both beneficial and kind of a pain. :)

SilverMap makes use of the WriteableBitmapEx library. I also used Danc's Miraculously Flexible Game Prototyping Tiles while testing and included them as a zip with the project.

The maps that are created can be saved as XML and the layering information is stored with them. You can set the opacity of a tile and in the near future will be able to scale and rotate them. Aside from the editor the SilverMap.UIMap control can be included in your game project and has the ability to load maps from a file stream (useful for maps that download on the fly).

The code is freely available under the Microsoft Public License so feel free to use it your games, whether they are free games or not.

SilverMap Editor


A Silverlight Games Star Field

Here is a really nice large star field in Silverlight if you are creating a space based game, or even if you are not it is still pretty cool. :)


Silverlight and Multi-Player Games

I have been working on a multi-player library for Silverlight games over the past few months, well, off and on working on it while continuing Perenthia development.

I hope to be able to get the code on CodePlex before too much longer along with a tutorial on how to use it and a demo game.

The library will start with Duplex services but I do have plans to implement sockets in the future. Silverlight’s duplex and socket support is sufficient for RPGs and RTS or really any kind of turn based game but until Silverlight can support UDP sockets it is probably not suited to real time action games.

The goal is that the library can be used with any game engine such as SilverSprite or PlayBits and that it will provide easy to setup and use networking capabilities for your game.

The library is coming along well and I am building a demo game to help with implementation and testing that I hope to have finished in the next week or so.


Game Objects - My Design

I thought I would share one of the core concepts I implemented in Perenthia that has been working quite well. Early on in development I decided to create templates and instances in regards to game objects. A template would define common, unchangable properties of an object whereas an instance would be the opposite. An example would be a Sword; there is a template for a Sword that defines its damage value, price, required skill level, etc. 

I have one table that stores all the objects for the game. Since objects being actively used are loaded into memory and the table is indexed for those queries it runs pretty fast. Since I store all of the objects into one table I make heavy use of the XML data type in SQL 2005 to provide a bunch of XML Serialized Key/Value pairs that define the properties of an object. On the code side of things a dictionary provides the underlying data store for properties of the object. For instance, the Sword example above has a Power property that is used in combination with the wielder's skill in swords to determine damage. The Power property just fetches the Power value from the properties dictionary using the property name. This works a lot like the dependency properties, just my collection serializes to XML for database storage. When an object is loaded from the database the xml from the template is retrieved and added to the object, then the object instance xml is dropped into the object, overriding any template properties of the same name.

This property dictionary also allows me to store whether or not the property belongs to a template or instance. If the property belongs to a template then when the instance is serialized and saved to the database those template properties are excluded. Likewise saving a template does not serialize and save the instance properties. This structure allows for a lot of flexibility with my objects and has been working out quite well. I probably would not have used serialization and xml the way I am if I was doing a typical call to the database qith each request as the extra overhead would not have been worth the effort. However, since my objects are loaded into memory and my saves are background threaded I experience a lot of benefit of an easy to use object.

I shuld note that players character data is stored in a separate table from the core objects table. It follows the same design buy allows me to migrate and change data in the objects table without overwriting player data, since players are essentially the same as mobiles. 


Perenthia World Builder in Silverlight

I have been working to modify the tool I wrote for building the Perenthia world. The tool started life as a WinForms application, migrated to a WPF application but is now a part of the Silverlight Client UI. Since all of the actions are role based and controlled with permission on the server having it in the main client UI allows me to make use of all of the framework already in place for Perenthia.

The world builder UI connects to the server via WCF services tailored for world building. What this will also give me is the ability to open up the world builder to allow users to create custom dungeons, towns, etc.

Some features of the world builder are a background map of the world so I know where to place rooms, zoom capabilities that scale the map, draggable map and the ability to drag items, creatures, NPCs, etc. onto rooms on the map and configure the properties of each.


Silverlight Window Control

Here is a draggable Window control I wrote in Silverlight for Perenthia. A screen shot of the Window being used can be seen at

Here is the XAML from my generics.xaml file:


<!-- Default style for Lionsguard.Window -->
	<Style TargetType="lg:Window">
		<Setter Property="Background" Value="#99000000" />
		<Setter Property="Foreground" Value="#FFFFFFFF" />
		<Setter Property="BorderBrush" Value="#FFC38312" />
		<Setter Property="Template">
				<ControlTemplate TargetType="lg:Window">
					<Grid x:Name="RootElement">
						<Border HorizontalAlignment="Stretch" Margin="0,24,0,0" Padding="4,4,4,4" VerticalAlignment="Stretch" BorderThickness="2,2,2,2" CornerRadius="0,0,4,4">
							<ContentControl x:Name="ContentElement" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"/>
						<Border Height="24" HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Top" CornerRadius="4,4,0,0" BorderThickness="2,2,2,0" x:Name="TitleBarElement" />
						<Button Height="20" HorizontalAlignment="Right" Margin="0,3,3,0" VerticalAlignment="Top" Width="20" Content="X" FontWeight="Bold" FontFamily="Trebuchet MS" FontSize="14" x:Name="CloseButtonElement"/>
						<TextBlock Height="20" Margin="8,3,27,0" VerticalAlignment="Top" Text="Title" TextWrapping="Wrap" x:Name="TitleLabelElement" FontFamily="Georgia" FontSize="16" FontWeight="Bold" HorizontalAlignment="Left"/>


And here is the code for the class:


using System;
using System.Collections.Generic;
using System.Net;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Lionsguard
	[TemplatePart(Name = "RootElement", Type = typeof(FrameworkElement))]
	[TemplatePart(Name = "ContentElement", Type = typeof(ContentControl))]
	[TemplatePart(Name = "TitleBarElement", Type = typeof(Border))]
	[TemplatePart(Name = "CloseButtonElement", Type = typeof(Button))]
	[TemplatePart(Name = "TitleLabelElement", Type = typeof(TextBlock))]
	public class Window : Control
		public FrameworkElement RootElement { get; set; }
		private ContentControl ContentElement { get; set; }
		private Border TitleBarElement { get; set; }
		private Button CloseButtonElement { get; set; }
		private TextBlock TitleLabelElement { get; set; }

		private Point MousePosition { get; set; }

		/// <summary>
		/// Gets or sets the Content of the Window.
		/// </summary>
		public UIElement Content
			get { return (UIElement)GetValue(ContentProperty); }
			set { SetValue(ContentProperty, value); }
		public static readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(UIElement), typeof(Window), new PropertyMetadata(null, new PropertyChangedCallback(Window.OnContentPropertyChanged)));
		private static void OnContentPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
			(obj as Window).SetControlValues();

		/// <summary>
		/// Gets or sets the Title displayed in the title bar of the window.
		/// </summary>
		public string Title
			get { return (string)GetValue(TitleProperty); }
			set { SetValue(TitleProperty, value); }
		public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(Window), new PropertyMetadata("Title", new PropertyChangedCallback(Window.OnTitlePropertyChanged)));
		private static void OnTitlePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
			(obj as Window).SetControlValues();

		/// <summary>
		/// Gets or sets a value indicating whether or not the close button of the title bar should be displayed.
		/// </summary>
		public bool ShowCloseButton
			get { return (bool)GetValue(ShowCloseButtonProperty); }
			set { SetValue(ShowCloseButtonProperty, value); }	
		public static readonly DependencyProperty ShowCloseButtonProperty = DependencyProperty.Register("ShowCloseButton", typeof(bool), typeof(Window), new PropertyMetadata(true, new PropertyChangedCallback(Window.OnShowCloseButtonPropertyChanged)));
		private static void OnShowCloseButtonPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
			(obj as Window).SetControlValues();

		/// <summary>
		/// Gets a value indicating whether or not the window is currently open and visible.
		/// </summary>
		public bool IsOpen
			get { return this.Visibility == Visibility.Visible; }

		/// <summary>
		/// An event that is raised when the window is closed.
		/// </summary>
		public event EventHandler Closed = delegate { };

		/// <summary>
		/// Initializes a new instance of the Lionsguard.Window class.
		/// </summary>
		public Window()
			this.DefaultStyleKey = typeof(Window);

		public override void OnApplyTemplate()

			this.RootElement = base.GetTemplateChild("RootElement") as FrameworkElement;
			this.ContentElement = base.GetTemplateChild("ContentElement") as ContentControl;
			this.TitleBarElement = base.GetTemplateChild("TitleBarElement") as Border;
			this.CloseButtonElement = base.GetTemplateChild("CloseButtonElement") as Button;
			this.TitleLabelElement = base.GetTemplateChild("TitleLabelElement") as TextBlock;
			if (this.RootElement != null)
				this.RootElement.MouseLeftButtonDown += new MouseButtonEventHandler(OnRootElementMouseLeftButtonDown);

				this.TitleBarElement.MouseLeftButtonDown += new MouseButtonEventHandler(OnTitleBarMouseLeftButtonDown);
				this.TitleBarElement.MouseEnter += new MouseEventHandler(OnTitleBarMouseEnter);
				this.TitleBarElement.MouseLeave += new MouseEventHandler(OnTitleBarMouseLeave);

				this.TitleLabelElement.MouseLeftButtonDown += new MouseButtonEventHandler(OnTitleBarMouseLeftButtonDown);
				this.TitleLabelElement.MouseEnter += new MouseEventHandler(OnTitleBarMouseEnter);
				this.TitleLabelElement.MouseLeave += new MouseEventHandler(OnTitleBarMouseLeave);

				this.CloseButtonElement.Click += new RoutedEventHandler(OnCloseButtonClick);


		private void SetControlValues()
			if (this.ContentElement != null && this.Content != null)
				this.ContentElement.Content = this.Content;
			if (this.TitleLabelElement != null)
				this.TitleLabelElement.Text = this.Title;
				ToolTipService.SetToolTip(this.TitleLabelElement, this.Title);
			if (this.CloseButtonElement != null)
				if (this.ShowCloseButton) this.CloseButtonElement.Visibility = Visibility.Visible;
				else this.CloseButtonElement.Visibility = Visibility.Collapsed;

		private void OnRootElementMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
			// Set the Z-Index of the window to the top most position.

		private void OnCloseButtonClick(object sender, RoutedEventArgs e)

		private void OnTitleBarMouseLeave(object sender, MouseEventArgs e)
			this.Cursor = Cursors.Arrow;

		private void OnTitleBarMouseEnter(object sender, MouseEventArgs e)
			this.Cursor = Cursors.Hand;

		private void OnTitleBarMouseMove(object sender, MouseEventArgs e)
			Point position = e.GetPosition(null);

			// Prevent the mouse from moving outside the bounds of the parent canvas.
			if (position.X <= 30) position.X = 30;
			if (position.Y <= 30) position.Y = 30;

			Canvas parent = this.Parent as Canvas;
			if (parent != null)
				if (position.X >= (parent.Width - 30)) position.X = parent.Width - 30;
				if (position.Y >= (parent.Height - 30)) position.Y = parent.Height - 30;

			System.Diagnostics.Debug.WriteLine("position = {0}", position);

			double deltaX = position.X - this.MousePosition.X;
			double deltaY = position.Y - this.MousePosition.Y;
			Point newPosition = new Point(
				((double)this.GetValue(Canvas.LeftProperty)) + deltaX,
				((double)this.GetValue(Canvas.TopProperty)) + deltaY);

			this.SetValue(Canvas.LeftProperty, newPosition.X);
			this.SetValue(Canvas.TopProperty, newPosition.Y);

			this.MousePosition = position;

		private void OnTitleBarMouseLeftButtonUp(object sender, MouseButtonEventArgs e)

			this.Cursor = Cursors.Arrow;

			this.TitleBarElement.MouseLeftButtonUp -= new MouseButtonEventHandler(OnTitleBarMouseLeftButtonUp);
			this.TitleBarElement.MouseMove -= new MouseEventHandler(OnTitleBarMouseMove);
			this.TitleLabelElement.MouseLeftButtonUp -= new MouseButtonEventHandler(OnTitleBarMouseLeftButtonUp);
			this.TitleLabelElement.MouseMove -= new MouseEventHandler(OnTitleBarMouseMove);

		private void OnTitleBarMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
			this.MousePosition = e.GetPosition(null);
			this.Cursor = Cursors.Hand;


			this.TitleBarElement.MouseLeftButtonUp += new MouseButtonEventHandler(OnTitleBarMouseLeftButtonUp);
			this.TitleBarElement.MouseMove += new MouseEventHandler(OnTitleBarMouseMove);
			this.TitleLabelElement.MouseLeftButtonUp += new MouseButtonEventHandler(OnTitleBarMouseLeftButtonUp);
			this.TitleLabelElement.MouseMove += new MouseEventHandler(OnTitleBarMouseMove);

		/// <summary>
		/// Causes the current window to be re-z-indexed to the top most window.
		/// </summary>
		protected void BringToFront()
			// Search the top most "Window" and swap z-indexes.
			Panel parent = this.Parent as Panel; // Panel is the base for Canvas, Grid and StackPanel.
			if (parent != null)
				int currentZIndex = (int)this.GetValue(Canvas.ZIndexProperty);
				var child = (from c in parent.Children where c is Window select c as Window).OrderByDescending(c => (int)c.GetValue(Canvas.ZIndexProperty)).FirstOrDefault();
				if (child != null)
					int topZIndex = (int)child.GetValue(Canvas.ZIndexProperty);
					if (topZIndex == 0) topZIndex = 1; // If the value has not been set then just default it to 1.
					if (topZIndex > currentZIndex)
						this.SetValue(Canvas.ZIndexProperty, topZIndex);
						child.SetValue(Canvas.ZIndexProperty, currentZIndex);

		public void Show()
			this.Visibility = Visibility.Visible;
			// If content is present show that as well.
			if (this.Content != null) this.Content.Visibility = Visibility.Visible;

		public void Close()
			this.Visibility = Visibility.Collapsed;
			// If content is present hide that as well.
			if (this.Content != null) this.Content.Visibility = Visibility.Collapsed;
			this.Closed(this, EventArgs.Empty);

		public void ToggleWindow()
			if (this.Visibility == Visibility.Visible)


This is how I am using it within the Pernethia UI (The content of window is actually the Character Sheet as displayed in the screenshot from above):

Namespace: xmlns:Lionsguard="clr-namespace:Lionsguard;assembly=Lionsguard.Silverlight"


<Lionsguard:Window Height="375" x:Name="diagCharacterSheet" Visibility="Collapsed" Width="634" Canvas.Left="8" Canvas.Top="19" Title="Character Sheet" Style="{StaticResource WindowStyle}" d:IsLocked="True">
    		<Perenthia_Dialogs:CharacterSheetDialog x:Name="diagCharacterSheetContent" SkillChanged="diagCharacterSheetContent_SkillChanged"/>





Silverlight Drag and Drop Manager

I wrote some classes for handling drag and drop operations in Silverlight that I use within Perenthia. I thought I would go ahead and share them since I found them to be very useful in getting drag and drag working quickly in new projects.

The Drag and Drag classes consist of two interfaces (IDroppable, IDropContainer) and a manager class (DragDropManager). The interfaces are defined as such:

namespace Lionsguard
    /// <summary>
    /// Defines an object that can be dragged and dropped via the DragDropManager.
    /// </summary>
	public interface IDroppable
		/// <summary>
		/// An event that is raised when the IDroppable item begins the drag operation.
		/// </summary>
		event BeginDragEventHandler BeginDrag;

		/// <summary>
		/// Gets the UIElement that will server as the cursor replacement when dragging the current object.
		/// </summary>
		/// <returns></returns>
		UIElement GetDragCursor();

    /// <summary>
    /// Defines an object that accept IDroppable items as part of a drop operation.
    /// </summary>
	public interface IDropContainer
		/// <summary>
		/// Handles the drop of the specified IDroppable item onto the container.
		/// </summary>
		/// <param name="item"></param>
		void Drop(IDroppable item);

The DragDropManager (and and associated delegate and event args class) are defined as such:

namespace Lionsguard
    /// <summary>
    /// Represents a class used to manage drag and drop items.
    /// </summary>
	public class DragDropManager
		private Panel Host { get; set; }
		private Point MousePosition { get; set; }
		private UIElement DragCursor { get; set; }	
		private bool HasProcessedEndDrag { get; set; }
		private IDroppable Item { get; set; }	

        /// <summary>
        /// Initializes a new instance of the DragDropManager class.
        /// </summary>
        /// <param name="host">The hosting panel where the drag cursor instance will be added.</param>
		public DragDropManager(Panel host)
			this.Host = host;
			this.Host.LostFocus += new RoutedEventHandler(OnHostLostFocus);

		private void OnHostLostFocus(object sender, RoutedEventArgs e)

		private void OnDragCursorLostMouseCapture(object sender, MouseEventArgs e)

		private void OnDragCursorLostFocus(object sender, RoutedEventArgs e)

		private void OnDragCursorMouseLeftButtonUp(object sender, MouseButtonEventArgs e)

			this.MousePosition = e.GetPosition(null);


		private void OnDragCursorMouseMove(object sender, MouseEventArgs e)
			Point position = e.GetPosition(null);

			double deltaX = position.X - this.MousePosition.X;
			double deltaY = position.Y - this.MousePosition.Y;

			Point newPosition = new Point(
				((double)this.DragCursor.GetValue(Canvas.LeftProperty)) + deltaX,
				((double)this.DragCursor.GetValue(Canvas.TopProperty)) + deltaY);

			this.DragCursor.SetValue(Canvas.LeftProperty, newPosition.X);
			this.DragCursor.SetValue(Canvas.TopProperty, newPosition.Y);

			this.MousePosition = position;

        /// <summary>
        /// Begins a drag operation for the specified IDroppable instance starting at the specified mousePosition.
        /// </summary>
        /// <param name="droppable">The IDroppable instance to being dragging.</param>
        /// <param name="mousePosition">The Point at which the drag operation will begin.</param>
		public void BeginDrag(IDroppable droppable, Point mousePosition)
			if (droppable != null && this.Host != null)
				System.Diagnostics.Debug.WriteLine("Begin Drag...");
				this.Item = droppable;

				this.DragCursor = droppable.GetDragCursor();
				this.DragCursor.LostFocus += new RoutedEventHandler(OnDragCursorLostFocus);
				this.DragCursor.LostMouseCapture += new MouseEventHandler(OnDragCursorLostMouseCapture);

				// Add the drag cursor to the host control and set the z-index very high.
				this.DragCursor.SetValue(Canvas.ZIndexProperty, 5000);
				this.Host.Cursor = Cursors.Hand;

				this.MousePosition = mousePosition;
				this.DragCursor.SetValue(Canvas.LeftProperty, this.MousePosition.X);
				this.DragCursor.SetValue(Canvas.TopProperty, this.MousePosition.Y);
				this.DragCursor.Visibility = Visibility.Visible;

				this.HasProcessedEndDrag = false;


				this.DragCursor.MouseLeftButtonUp += new MouseButtonEventHandler(OnDragCursorMouseLeftButtonUp);
				this.DragCursor.MouseMove += new MouseEventHandler(OnDragCursorMouseMove);

		private void EndDrag(bool processDrop)
			// This prevents the mouse up event or the end drag event firing more than once from causing the
			// events to bubble up and the drop be handled more than once.
			System.Diagnostics.Debug.WriteLine("End Drag...");
			if (this.HasProcessedEndDrag) return;
			this.HasProcessedEndDrag = true;

			// Reshow the cursor and hide the source image.
			this.Host.Cursor = Cursors.Arrow;

			// Hide the drag cursor.
			if (this.DragCursor != null)
				this.DragCursor.Visibility = Visibility.Collapsed;

                this.DragCursor.LostFocus -= new RoutedEventHandler(OnDragCursorLostFocus);
                this.DragCursor.LostMouseCapture -= new MouseEventHandler(OnDragCursorLostMouseCapture);
				this.DragCursor.MouseLeftButtonUp -= new MouseButtonEventHandler(OnDragCursorMouseLeftButtonUp);
				this.DragCursor.MouseMove -= new MouseEventHandler(OnDragCursorMouseMove);

			if (processDrop)
				System.Diagnostics.Debug.WriteLine("Process Drop...");
				// Search within host for an IDropContainer instance within the area of the current mouse position.
				var container = (from v in VisualTreeHelper.FindElementsInHostCoordinates(this.MousePosition, this.Host)
								where (v as IDropContainer) != null
								select v as IDropContainer).FirstOrDefault();
				if (container != null)

    /// <summary>
    /// Provides a delegate for handling IDroppable.BeginDrag events.
    /// </summary>
    /// <param name="sender">The IDroppable initiating the drag operation.</param>
    /// <param name="e">Event data for the operation.</param>
	public delegate void BeginDragEventHandler(object sender, BeginDragEventArgs e);

    /// <summary>
    /// Represents event data for a BeginDrag event.
    /// </summary>
	public class BeginDragEventArgs : EventArgs
        /// <summary>
        /// Gets or sets the IDroppable initiating the event.
        /// </summary>
		public IDroppable Droppable { get; set; }

        /// <summary>
        /// Gets or sets the Point at which the drag operation should begin.
        /// </summary>
		public Point MousePosition { get; set; }	
To use the manager is your project have the controls wyou wish to drag and drop implement the IDroppable interface and the destinations for the drop operation should implement the IDropContainer. One control could implement both if you have operations where items can be dragged into other items of the same type.
Here is an example of the IDroppable and IDropContainer implementation (Both of which are in the same user control).
The GetDragCursor method creates the item so it looks like you are dragging it across the screen, you can have any kind of cursor replacement UIElement you want with this.

namespace Perenthia.Controls
public partial class AvatarListItem : UserControl, IDroppable, IDropContainer

#region IDroppable Members

public event BeginDragEventHandler BeginDrag = delegate { };

public UIElement GetDragCursor()
Image img = new Image();
img.Source = this.GetImageSource();
img.Width = 16;
img.Height = 16;
Border border = new Border();
border.Background = Brushes.DialogFillBrush;
border.BorderBrush = Brushes.BorderBrush;
border.Padding = new Thickness(2);
border.Width = 18;
border.Height = 18;
border.Child = img;
return border;


private void NameLabel_MouseLeave(object sender, MouseEventArgs e)
if (_details != null)

#region IDropContainer Members

public void Drop(IDroppable item)
// Do stuff when the object is dropped...


And here is an example of the usage of the drag and drop manager (Contained within a silverlight Page class):

I declare an instance of the DragDropManager when my control is loaded (I use a Canvas for LayoutRoot as I find the drag operation to be smoother with a Canvas).
private void AdminScreen_Loaded(object sender, RoutedEventArgs e)
_dragDropManager = new DragDropManager(LayoutRoot);

When my IDroppable control instance is created I register a listener to the BeginDrag event:
avatarItem.BeginDrag += new BeginDragEventHandler(OnDroppableBeginDrag);

When the IDroppable raises the BeginDrag event, on a left mouse button click, this method is called which causes the DragDropManager to being the drag operation for the current IDroppable.

private void OnDroppableBeginDrag(object sender, BeginDragEventArgs e)
			if (_dragDropManager != null)
				_dragDropManager.BeginDrag(e.Droppable, e.MousePosition);

When an IDroppable is dropped onto the very same control this method is executed:

#region IDropContainer Members
		public void Drop(IDroppable item)
                    // Do stuff when the object is dropped...

This is pretty much all there is to it.



Working on a Silverlight Multi-Player Library

I have been porting out the multi-player aspects of Perenthia into a separate library I hope to get up on CodePlex before too long. What the library will provide is some interfaces and classes related to handling multi-player environments. A central static class will manage connected clients and three protocol classes for HTTP, Polling Duplex and Sockets will use the static class to retrieve connected clients and push information down to them. A simple set of "tags" are used to send information back and forth and some providers allow for defining your own implementation of handling commands and encrypting data.

The library will be focused on providing an easy way to get setup and implement a multi-player structure. You will still need our own game engine and associated components.

As soon as I get it cleaned up a little and tested out I will put it up on CodePlex and provide a tutorial and sample application showing how to implement and use the component.


Perenthia Fan Site

Perenthia has a fan site, it is called Beyond Angarath, Angarath being a primary city in within the game world. This is exciting for me and extremely cool! It is very rewarding to see people enjoying your creation enough to put work into a fan site for that creation. The forums have been getting more active lately with folks trying out the Alpha and giving lots of feedback and suggestions. I hope stay close with the community in building this game; I have a vision for it but ultimately I want people to play it and enjoy playing it.


Silverlight for Multi-Player Games

I am hoping to start writing some articles about building multi-player games in Silverlight. I am planning on charting my development progress and ideas in my design and development of Perenthia.

Silverlight is a great platform for .NET developers to be able to write multi-player browser based games. You get a great tool for building a UI, animations, sounds, etc. and can program everything in your .NET language of choice. Silverlight 3 is supposed to support 3D so that will open it up even more for some great games.

Over the next few months, in between working on Perenthia, I am going to work on the first of a series of articles outlining how I built Perenthia. I will start with the Server component, outlining the core communication architecture and design decisions.

Keep checking back for more information.


Perenthia Armorial Version 1.0

I uploaded the Perenthia Armorial Version 1.0 to the Perenthia Alpha site tonight. The Perenthia Armorial is a way to provide external access to Perenthia information. The first version includes the Player Bar feature, where you pass a player name to the service and renders back HTML with player details.

The call to renders the following:


Perenthia Alpha Testing

I did a Character Creation, Movement and Chat test last night with the Perenthia Alpha players. The tests went well, I chatted with a few players, found some bugs and was very encouraged by the whole thing. The next test should start next weekend and will include some combat/spell tests. After that we will do some questing tests, travel tests (boats and stuff) and then I will open up more of the world for the alpha players to help resolve other issues not covered by the main feature tests.

I am enjoying Silverlight as the client UI, it provides a Windows like interface with ability to be run in a browser.


Client/Server Communication Data Formats

While developing Perenthia I tried several different communication formats from sending JSON serialized objects back and forth to sending byte arrays containing mostly integers indicating what should be loaded and displayed, what commands to execute etc. What I eventually settled on was a bit of a hybrid. I've created a simple set of "tags" that can be sent to and from the server. The tags are nothing more than pipe delimited strings contained within curly braces and there are a limited number of tags that provide simplicity yet flexibility with the data that is transmitted. The tags are represented in C# by tag objects allow me to create them, query them, etc.

A simple command tag for the SAY command might look like this: {CMD|SAY|"Hello World!"}

I wrote a custom tag writer class that parses the tag objects into strings to be sent to the client and likewise a tag reader that reads the strings sent from the client and parses them into tag objects.

The client can only send commands to the server but the server sends commands, messages and objects to the client. The commands are all the same, the CMD text then the one word name of the command and then a list of arguments, messages are system, chat and tell messages but objects have a bit more information. For instance, an object tag encompasses several different types starting with a base ACTOR, a PLACE, a PLAYER and a PROP or property. The ACTOR, PLACE and PLAYER tags all define the ID, Name and Descriptions of the objects, with some additional data per type but the PROP tag defines the object id of its owner and a name/value pair. An example of a PLAYER tag with properties for x, y and z coordinates might be:

{OBJ|PLAYER|3756|"Aldarian"|"My character description..."}




The client can find and parse the player tag and then find the properties associated with that player instance. The way the server works now it will send the full player tag once logged in and a character is selected and then from then on out it just sends property updates.

Using this type of tag structure allows quite a bit of flexibility for the client. I could choose to write a very simple client that only displays MSG tags, much like a MUD, I could write a simple 2D interface client and display and move sprites about the map using the properties from the server, etc. Once Perenthia is up and running I will probably post some information on the tags and how to talk with the server should someone feel the need to write their own client. :)


Almost Alpha Time!

For those waiting, Perenthia is almost ready for alpha. I have a few more things to complete and then the first phase of the Alpha will be ready. Hopefully you have had time to look over the various races, attributes and skills on the Perenthia web site and will be ready to create a character and begin your journey.

Here is a list of the remaining tasks I need to complete before Alpha, this does not include testing and fixing bugs with these features, just implementing them:

  • Spellcasting (Basic framework is in place, just need to define some spells and test them out)
  • Monster drops, including currency, gold, silver, etc. (They don't drop anything right now, stingy)
  • Help (Just need the framework in place as the help will get compiled during the alpha)
  • Quests (May not finish these for the first phase of alpha, want to try and keep it simple to start)
  • Some UI cleanup (got some windows not responding to updates from the server)
  • Content (Need to finish adding monsters to the dungeon, just the one dungeon for alpha)

I thought I would include a couple of screen shots along with this update. The first is a shot of the map window of the world builder tool I wrote for managing the places and things within the Perenthia world. This is the shot of the Alpha testing area, a small village called "Delcor". This view is actually a windows forms application with a WPF (ElementHost) control for rendering the map. The little red dots are NPCs that I can actually drag around into other rooms on the map after I create them, makes for moving the monsters in the dungeon a lot easier. :)

This second shot is the game user interface showing the same map that I was working on in the screen shot above.


Evolution of a Game UI

As I have been working on the Silverlight UI for Perenthia I find myself constantly adding little things here there to provide more information or easier click-to-action type of functionality. The UI has evolved, for the better I hope, over the past few months from my original design as I have discovered something else that needed to be displayed while hooking it into the server. This seems to be the natural progression of things, at least with the way I work. :)

Here is the latest UI screen shot, this one shows my character viewing the items a merchant has for sale, with my inventory items on the left and the ones the merchant offers on the right. I will do a development update again soon, had to backtrack a bit with the UI.


Silverlight Game Controls

While building the Silverlight UI for Perenthia I have been building some re-usable game controls that I plan on posting before too long. One of the controls I created is a Window control that is just a control that provides a title bar with a close button and provides a Content section to add custom controls. I needed it to provide menu windows or panels but it could be used outside of games for just about anything. The control is draggable, as long as the parent control is a Canvas and will position itself as the top window when clicked, provided other windows exist in the same parent.

The Window control is featured in the screen shot below, the "Spellbook", "Character Sheet" and "Adenturer's"** are the windows. They contain custom controls that determine the content of the windows. The small icons at the very bottom of the screen shot are Slot controls that allow for a background image, primary image and object Item to be set on them. They also respond to clicks so click events can be handled on them. The ChatPanel under the windows is also a re-usable control and allows for adding any type of UIElement as content for the main chat area, not just text.

I hope to get these controls commented and the source up soon.

** The "Adventurer's" window is actually "Adventurer's Backpack", have a font sizing issue :)


Silverlight 2 Release

Silverlight 2 has officially been released. I've upgraded both Joust and Cameron's Dungeon as well as the Perenthia client. Work on Perenthia continues, albeit a little slow but it does continue. :)


Joust : A Silverlight 2 Game - Source Code

I didn't get a chance to work on Joust any more before the contest deadline and won't have enough time in the next hour and half. Anyway, as promised here is the source code:

Joust Source Code


Joust : A Silverlight 2 Game

I was working on a simple sports game for the Team Zone Sports Silverlight 2 Game Contest. The rules specified a sports theme but did not specify a century or the type of sports so I created a jousting game. I haven't completely finished the game, it doesn't have everything I wanted it to have and the horse kind of drives like a car :) The dust trail behind the horse actually adds to the car effect!

The game is Silverlight 2, C# and makes use of the Farseer Physics engine.

Anyway, I am hoping to get it cleaned up a little more before the contest submission deadline but not sure that is going to happen given my current workload.

I will post the source once the submission deadline is over, I want to try and get it completely finished by then but if not I will post the source anyway.

Play Joust


Scripting for Games

Scripting in games is not a new concept, most games do this on some level. Scripting allows game objects to execute code that is not compiled as part of the object. In the realm of roe playing games scripting gives objects the ability to react to the world around them. For instance, an object could execute script whenever a player gets near it, allowing a vender to hawk their wares, creatures to attack, etc. There are a variety of scripting languages currently being implement in games such as Lua and Python. Recently I have been researching these two for possible addition to Perenthia to provide me the ability to add custom behavior to objects and NPCs.

Edit: Thanks to some helpful insight and information from Michael Foord I was able to get an IronPython sample working. The sample adds scripting support to an object; the code is very basic but accomplishes the task. Thanks Michael!

Here is a snippet of a console app using the latest IronPython Beta4:

using System;using System.Collections;using System.Collections.Generic;using System.IO;using System.Reflection;using System.Scripting;using IronPython;using IronPython.Hosting;using IronPython.Runtime;using IronPython.Runtime.Exceptions;using Microsoft.Scripting;using Microsoft.Scripting.Hosting;namespace IronPythonGameScripting{    class Program    {        static void Main(string[] args)        {            try            {                Actor player = new Actor("Cam");                Actor mob = new Actor("Mob");                mob.Script = @"class Mob:    def onEncounter(self, *value):        value[0].Name = ""Mr Groovy""";                Console.WriteLine("Player name was '{0}'", player.Name);                mob.Execute(Actor.EVENT_ON_ENCOUNTER, player);                Console.WriteLine("Player name is now '{0}'", player.Name);                mob.Execute("Test", player);            }            catch (Exception ex)            {                Console.WriteLine(ex.ToString());            }            finally            {                Console.WriteLine("Press any key to exit...");                Console.ReadKey();            }        }    }    public static class Engine    {        private static ScriptEngine _engine;        private static ScriptScope _scope;        static Engine()        {            _engine = PythonEngine.CurrentEngine;            _scope = _engine.CreateScope();        }        public static void Initialize()        {        }        public static void Execute(string script)        {            ScriptSource source = _engine.CreateScriptSourceFromString(script, SourceCodeKind.Statements);            source.Execute(_scope);        }        public static void Execute(string script, string className, string methodName, params object[] args)        {            ObjectOperations ops = _engine.Operations;            ScriptSource source = _engine.CreateScriptSourceFromString(script, SourceCodeKind.Statements);            source.Execute(_scope);            if (_scope.ContainsVariable(className))            {                object @class = _scope.GetVariable(className);                object instance = ops.Call(@class);                if (instance != null)                {                    if (ops.ContainsMember(instance, methodName))                    {                        object method = ops.GetMember(instance, methodName);                        ops.Call(method, args);                    }                }            }        }    }    public class Actor    {        public const string EVENT_ON_ENCOUNTER = "onEncounter";        public string Name { get; set; }        public string Script { get; set; }        public Actor(string name)        {            this.Name = name;        }        public void Execute(string methodName, params object[] args)        {            Engine.Execute(this.Script, "Mob", methodName, args);        }    }}


As it turns out I was attempting to use the IronPython libraries compiled against the Silverlight framework rather than the libraries compiled against the normal .NET framework. I was also using an older beta 1 version of the IronPython library which may have attributed to the exceptions I was seeing. Got to make sure you reference the correct assemblies when working in both .NET and Silverlight. Surprised this is the first time I've done this...

I reviewed IronPython because it has Silverlight support with the DLR but it is really designed to be used instead of C# not as a scripting language executed from within C#. With Lua though I may be able to get it working although it still seems like everything was designed to simply execute the game in lua scripts using C# as the core instead of augmenting C# classes.

I really want to just be able to raise events on the mobile objects and have instances handle those events in a custom way. I certainly don't want to compile C# on the fly either as that has its own set of issues. Compiling C# on the fly is like running an exe for each script that is executed and would be way too costly in both execution time to compile and memory consumption.

Also, since both the client and server will need to execute scripts the scripting language needs to work in both Silverlight and ASP.NET.

Perenthia currently handles commands using a Dictionary<int, Command> where the int is command value, from a list of constants, and the Command is a method pointer (delegate). When the game loads up the first time the list of commands is constructed and the methods pointers are set to methods that related to the command. An example would be a chat command. When the command comes in and is validated the method pointer is found using this dictionary and then executed in the context of the connected player. I was thinking of doing the same thing with mobiles and the actions they can take and respond to based on the world around them. It is a bit more complex with mobiles than commands since commands do a specific thing whereas every mobile could execute a different block of code for a given event. I still have some work to do on it but this will probably be what I use in place of scripting. I loose the flexibility of writing quick scripts, changing them on the fly, etc. but gain the ability to have it work within my code framework, rely on only .NET and work in both Silverlight and ASP.NET.


Silverlight Game Contest

I thought I would take a little break from working on Perenthia and take part in a Silverlight Game Contest for a sports theme game. This will push out the alpha release date a little but I need a little change of pace.

I am a little late in deciding to do this but figured I would give it a try and see if I can come up with something fun by September 8th. I have an idea for a simple game, hopefully I can make it fun to play because I know it will be fun to build.

Once the game is finished I will also post the source code.


Silverlight 2 Farseer Physics Geom Visual Helper Method

I ported some code from the Farseer Physics Engine XNA demos that displayed  a debug view of the geom vertices used with the Physics Simulator. This is useful if you want to see where your geoms are being rendered to the screen to make sure you have everything in the right place. I know I need this a lot, helps me to understand where I am placing body geoms.

Anyway, here is the method, the _debug variable is just a Canvas I added at the top of the UI. Keep in mind that this method will slow your game WAY down so be sure and use it to test where geoms are positioned and if everything is moving properly. I use a static variable for the PhysicsSimulator, hence the cleverly named Physics.Simulator.

        private void DrawVertices()        {            _debug.Children.Clear();            int verticeCount = 0;            for (int i = 0; i < Physics.Simulator.GeomList.Count; i++)            {                verticeCount = Physics.Simulator.GeomList[i].LocalVertices.Count;                for (int j = 0; j < verticeCount; j++)                {                    Line line = new Line();                    line.Fill = new SolidColorBrush(Colors.Transparent);                    line.Stroke = new SolidColorBrush(Colors.Magenta);                    line.StrokeThickness = 1;                    if (j < verticeCount - 1)                    {                        line.X1 = Physics.Simulator.GeomList[i].WorldVertices[j].X;                        line.Y1 = Physics.Simulator.GeomList[i].WorldVertices[j].Y;                        line.X2 = Physics.Simulator.GeomList[i].WorldVertices[j + 1].X;                        line.Y2 = Physics.Simulator.GeomList[i].WorldVertices[j + 1].Y;                    }                    else                    {                        line.X1 = Physics.Simulator.GeomList[i].WorldVertices[j].X;                        line.Y1 = Physics.Simulator.GeomList[i].WorldVertices[j].Y;                        line.X2 = Physics.Simulator.GeomList[i].WorldVertices[0].X;                        line.Y2 = Physics.Simulator.GeomList[i].WorldVertices[0].Y;                    }                    _debug.Children.Add(line);                }            }        }


More Perenthia Screen Shots

Here are a few more screen shots of the Perenthia UI. The three screen shots are dialog windows that popup as a result of clicking on icons or buttons in UI. They are use a reusable control I created that has the title bar and X button and then just has a ContentControl for the guts of the dialog. The dialog window is draggable and does the hide and show thing. I need to do some cleanup on it and then I will post the source. I will also post the source for the stat bars shown on the skills dialog screen shot.

Also, I am hoping to have some time to blog about some of what I am doing with the overall game engine. I wanted to provide a development update but haven't moved the development along all that much due to working out some networking issues and trying to clean up some of the code.

The goal for Alpha is to get a working zone complete with quests, monsters, npcs, etc. However, I may do some smaller tests with the alpha registrants before all of this is complete. I was thinking of setting up a tiny zone just for testing where players could login, create a Character and accept a quest, which would be to enter a room where enemies spawn randomly and in various numbers. This would allow me to test a lot of things in one place; Character Creation, Quests, Spawning, Combat and NPC interaction.

Anyway, here are the screen shots; this first one is the Character Sheet that will display your character stats, equipped items and skills. The empty box will show the skills once I bind them to it. :)

This next screen is the actual skills screen where you can see you skill rank and all available skills. If you have Skill Points you can increase or learn new skills from this window.

This last image is just the backpack dialog, all I have is a starting candle right now. :)


Perenthia UI Screen Shot

As promised here is a screen shot of the main game UI, click on the image for a full size version. The top left is the current player's avatar and details. The map in the top right corner shows you the current zone, in relation to your z-index. The icons scattered around open other windows that allow you to view your character sheet, skills, spells, backpack, etc. The interface is built in Silverlight 2 Beta 2.

Perenthia UI



For those unfamiliar with the fantasy role playing genre; quests are simple to complex tasks that players complete in order to advance, get sweet gear, etc. They usually involved raiding a dungeon, slaying some terrible beast and wondering about the countryside trying to find the entrance to the hidden caverns.

What I hope to accomplish with quests is to provide a goal beyond just slaying monsters. Quests will actually move your Character through the game, while training and advancing them along the way.

One of my primary goals with Perenthia is to provide a different game play experience as players mature within the game. The first phases of the game will include some of the normal grind, killing monsters to get better gear, to level up, to kill monsters, etc. This gives the players immediate satisfaction while getting them used to moving around, using commands, spells, equipping items, buying and selling and everything else that goes along with eradication of the demon beasts of the underworld. The second phase of the game will follow a bit of a storyline, requiring players to venture into dungeons and caverns to retrieve special items they will need in order to move into the next phase of the game. While this involves a lot of the same type of situation, you have a reason to go into the dungeon and complete it, rather than just killing 10 rats because some dude is freaking out. The third phase will require the player to use the items created from the previous phase to solve puzzles, riddles and the like, which will take them into the next phase. The fourth phase will require the player to purchase some form of transportation in order to visit very far off places and located individuals who can further their progress with quests of their own. This will continue in this manner for the remainder of the game. I currently have 4 phases planned and ideas for 3 more that I hope to get written down and planned out before too long, although I will probably wait until after the alpha an beta test phases.

I want to try and provide a fun game and I feel that doing this phased game progress could provide an enjoyable gaming experience. I know when playing other games of the genre I usually burn out in the high levels because I worked so hard to get there and it is just more of the same. I would also like the world to progress forward around the players so that new challenges are introduced to both high and low level characters that are in keeping with the overall storyline. I want players to have as much fun playing the game as I am having making it. :)

I hope to provide a robust questing system that can handle these phases and still maintain a clean and easy way for players to know what to do next. For the alpha I have planned out some quests that take you around the alpha starting area and should advance the alpha players enough so that the next area will introduce another phase in the game experience.

I will do another development update after this weekend.


Perenthia World Builder Screen Shots

I am not quite ready to post the screen shots of the actual game UI, still need to do some cleanup. So, since I promised I would post some screen shots here are a few of my world builder tool. This is a windows application that just reads and writes to the database.

This first screen is the map builder and as you can see I can draw the actual places/rooms in which players will adventure. The map that is displayed will be the Alpha starting map, it consists of a small town, a forest and a small sewer system. The sewer nodes are not displayed because they are one level down.

This is the creature manager window that allows me to create creature "templates", from which actual creature instances can be created and placed onto the map from above. (Using the Add Mobile button).

This is just a shot of the item manager window, displaying some of the items I've added so far, got a long way to go on these. The items also follow the same "template" pattern that the creatures do. I still need to add in support for placing the drop items on Mobiles.

I hope to have the game UI screen shots ready soon.


Perenthia - Pre-Alpha Details

I have made so many changes to Perenthia since the alpha/beta release I did last year that I am actually going to take the game back to Alpha and go through the whole process again. Most of the data elements remain the same, the story is the same, the goals, etc. but the server and client pieces have been modified so much its not really the same code base.

Anyway, I am hoping to get a pre-alpha signup form on the site this weekend and get the closed Alpha live by the end of summer.


Just an Update

I am still plugging along on my games, working mostly on Perenthia and checking out the new stuff in Silverlight 2 beta 2. I want to try and get the Perenthia beta 2 up and running by the middle or end of the summer, free time permitting.

 I haven't blogged much lately but I have been working on a lot of stuff. I will try and get some posts together to outline some of the stuff I have taken advantage of in developing Perenthia such as adding files as links in Visual Studio and then using partial classes to separate server and client logic and multi-threading in Silverlight and how to avoid cross thread access, which you will get exceptions on now in SL 2 beta 2. I will also try and get some screen shots of Perenthia, quite a bit has changed since the last screen shot I posted and I would like to get some of the new ones up.


Pirates! Progress

Rebuilding Pirates! in Silverlight 2 is coming along well. I got it running on my Silverlight game engine I was writing for use with Perenthia, which changed some of the way it worked initially. Anyway, I plan on doing a release once I get a few levels complete. In the mean time here is a screen shot of me testing sailing around.

Since I started over in Silverlight 2 and decided to use my game engine I am having to re-write a good portion of the functionality. I had to re-do movement since some of the structure of events has changed so this screen shot is the ship sailing around.


Perenthia Map

I thought I would post an image of the map I have been working on for Perenthia. I made this in Photoshop using a variety of brushes and layers. I still have some more that I want to do with it but I am pretty happy with it so far.


Perenthia Screen Shot

OK, I decided to post a screen shot of the Perenthia interface so far. Keep in mind this is still under development. The main sprite is not the final, just a ripped image from a Flash game called Exile and the background is just a sample I created so I could tell if the camera was following my player.



Perenthia and Pirates

After surviving the flu I am back to working on Perenthia. I did some work on Pirates but I am still having some positioning issues that I can't seem to get worked out and may have to rebuild a good portion of the game.

I should have a screen shot or two of the progress on Perenthia in another few days, I will see how it goes.

I have a good portion or rather the majority of the Perenthia Server finished and have been working on the Silverlight front end. I am still not sure whether or not I will be using sockets for communication or a custom IHttpHandler implementation.


Multi-threading in Silverlight

I've been working with Sockets in Silverlight over the past couple of days, in between getting the Pirates game to a workable Silverlight 2 state. One thing I came across today which sent me round and round was BeginInvoke. Anyone who has programmed multi-threaded applications in Windows has used this, mostly to execute code on the UI thread from events.

Anyway, controls in Silverlight 2 do not have the Invoke or BeginInvoke methods but controls do have a Dispatcher reference which lives in System.Windows.Threading. WPF programmers are probably already used to this but it was new for me. The Dispatcher allows you to check to see if you can access the current object on the current thread.

One thing to note about the Dispatcher is that it has a method called CheckAccess() that returns true if you can access the control on the current thread of false if you are not on the control's thread. The CheckAccess() method is decorated with a EditorBrowsableAttribute and has it's value set to Never. This prevents us from being able to see the method via intellisense in Visual Studio but does not prevent the method from being used. Not sure why the folks at MS wanted to hide this method and the documentation does not provide an explanation. The DependancyObject class also provides a CheckAccess method that is also hidden from the editor and just calls the Dispatcher method of the current object. Maybe it's not documented because it might be removed in the future, it is in beta after all.

So, to sum up, if you need to be able to invoke methods on a control's thread from a background thread you can do the following: (snippet from socket testing)

        private delegate void AppendTextDelegate(string text);        public void AppendText(string text)        {            if (txtChat.CheckAccess())            {                // Append the message to the chat buffer.                _content.Append(text).Append(Environment.NewLine);                // Re-post the contents of the chat buffer to the chat text and scroll to                // the bottom.                txtChat.Content = _content.ToString();                txtChat.ScrollToVerticalOffset(txtChat.ScrollableHeight);            }            else            {                txtChat.Dispatcher.BeginInvoke(new AppendTextDelegate(this.AppendText), text);            }        }

The _content control is just a StringBuilder that actually holds the content from the chat control.

Again, Silverlight 2 is in beta 1 so maybe this will change in the future.


Silverlight 2 Sockets

I started working with Sockets in Silverlight 2 tonight and got my Silverlight application connected to the server and sending and receiving commands. I am going to write some code to testing sending commands from the server at the same time commands are coming from the client to see how the app and my code will handle it.

I will post some code as I get further along. Also, I made more progress on getting the Pirates game upgraded to Silverlight 2.


HttpWebRequest Helper for Silverlight 2

I wrote this helper class to assist with processing an Http Request via Silverlight 2. Since we can't provide a custom class by deriving from BrowserHttpWebRequest because it is internal I wrote this helper that will create and send the request and raise an event when the request completes. I am using it in my current game to send commands to the server and process the responses.

Edit: I revised the class slightly based on finding from Mike Briseno:

Edit: Some folks have experienced issues with this class after installing Silverlight 2 Beta 2. Be sure to check your domain access policy xml file for the new changes in beta 2 but if you experience issues feel free to contact me and we can try and figure them out.

Edit: Added HttpUtility.UrlEncode to the post values before writing them to the stream. Thanks for the suggestion Stefan!

using System;using System.Collections.Generic;using System.IO;using System.Windows;using System.Windows.Browser;using System.Windows.Controls;using System.Windows.Documents;using System.Windows.Ink;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Animation;using System.Windows.Shapes;using System.Net;namespace Lionsguard{    public class HttpHelper    {        private HttpWebRequest Request { get; set; }        public Dictionary<string, string> PostValues { get; private set; }        public event HttpResponseCompleteEventHandler ResponseComplete;        private void OnResponseComplete(HttpResponseCompleteEventArgs e)        {            if (this.ResponseComplete != null)            {                this.ResponseComplete(e);            }        }        public HttpHelper(Uri requestUri, string method, params KeyValuePair<string, string>[] postValues)        {            this.Request = (HttpWebRequest)WebRequest.Create(requestUri);            this.Request.ContentType = "application/x-www-form-urlencoded";            this.Request.Method = method;            this.PostValues = new Dictionary<string, string>();            if (postValues != null && postValues.Length > 0)            {                foreach (var item in postValues)                {                    this.PostValues.Add(item.Key, item.Value);                }            }        }        public void Execute()        {            this.Request.BeginGetRequestStream(new AsyncCallback(HttpHelper.BeginRequest), this);        }        private static void BeginRequest(IAsyncResult ar)        {            HttpHelper helper = ar.AsyncState as HttpHelper;            if (helper != null)            {                if (helper.PostValues.Count > 0)                {                    using (StreamWriter writer = new StreamWriter(helper.Request.EndGetRequestStream(ar)))                    {                        foreach (var item in helper.PostValues)                        {                            writer.Write("{0}={1}&", item.Key, HttpUtility.UrlEncode(item.Value));                        }                    }                }                helper.Request.BeginGetResponse(new AsyncCallback(HttpHelper.BeginResponse), helper);            }        }        private static void BeginResponse(IAsyncResult ar)        {            HttpHelper helper = ar.AsyncState as HttpHelper;            if (helper != null)            {                HttpWebResponse response = (HttpWebResponse)helper.Request.EndGetResponse(ar);                if (response != null)                {                    Stream stream = response.GetResponseStream();                    if (stream != null)                    {                        using (StreamReader reader = new StreamReader(stream))                        {                            helper.OnResponseComplete(new HttpResponseCompleteEventArgs(reader.ReadToEnd()));                        }                    }                }            }        }    }    public delegate void HttpResponseCompleteEventHandler(HttpResponseCompleteEventArgs e);    public class HttpResponseCompleteEventArgs : EventArgs    {        public string Response { get; set; }        public HttpResponseCompleteEventArgs(string response)        {            this.Response = response;        }    }}

And this is how I am using it in my app:

        private void ProcessCommand(short cmd, string msg)        {            App app = App.Current as App;            HttpHelper helper = new HttpHelper(app.ServerUri, "POST",                new KeyValuePair<string, string>("authKey", app.AuthKey),                new KeyValuePair<string, string>("cmd", cmd.ToString()),                new KeyValuePair<string, string>("msg", msg));            helper.ResponseComplete += new HttpResponseCompleteEventHandler(this.CommandComplete);            helper.Execute();        }        private void CommandComplete(HttpResponseCompleteEventArgs e)        {            txtAlert.Text = e.Response;        }

For the VB Developers out there David Thiessen has converted my code to VB:

' Usage....'Private Sub ProcessCommand(ByVal cmd As Short, ByVal msg As String)'    Dim app As App = TryCast(App.Current, App)'    Dim helper As New HttpHelper(app.ServerUri, "POST", New KeyValuePair(Of String, String)("authKey", app.AuthKey), New KeyValuePair(Of String, String)("cmd", cmd.ToString()), New KeyValuePair(Of String, String)("msg", msg))'    AddHandler helper.ResponseComplete, AddressOf CommandComplete'    helper.Execute()'End Sub'Private Sub CommandComplete(ByVal e As HttpResponseCompleteEventArgs)'    txtAlert.Text = e.Response'End Sub''' <summary>''' Converted C# code from''' </summary>''' <remarks></remarks>Public Class HttpHelper    Private Property Request() As HttpWebRequest        Get            Return _Request        End Get        Set(ByVal value As HttpWebRequest)            _Request = value        End Set    End Property    Private _Request As HttpWebRequest    Public Property PostValues() As Dictionary(Of String, String)        Get            Return _PostValues        End Get        Private Set(ByVal value As Dictionary(Of String, String))            _PostValues = value        End Set    End Property    Private _PostValues As Dictionary(Of String, String)    Public Event ResponseComplete As HttpResponseCompleteEventHandler    Private Sub OnResponseComplete(ByVal e As HttpResponseCompleteEventArgs)        RaiseEvent ResponseComplete(e)    End Sub    Public Sub New(ByVal requestUri As Uri, ByVal method As String, ByVal ParamArray postValues As KeyValuePair(Of String, String)())        Me.Request = DirectCast(WebRequest.Create(requestUri), HttpWebRequest)        Me.Request.ContentType = "application/x-www-form-urlencoded"        Me.Request.Method = method        Me.PostValues = New Dictionary(Of String, String)()        For Each item In postValues            Me.PostValues.Add(item.Key, item.Value)        Next    End Sub    Public Sub Execute()        Me.Request.BeginGetRequestStream(New AsyncCallback(AddressOf HttpHelper.BeginRequest), Me)    End Sub    Private Shared Sub BeginRequest(ByVal ar As IAsyncResult)        Dim helper As HttpHelper = TryCast(ar.AsyncState, HttpHelper)        If helper IsNot Nothing Then            Using writer As New StreamWriter(helper.Request.EndGetRequestStream(ar))                For Each item In helper.PostValues                    writer.Write("{0}={1}&", item.Key, HttpUtility.UrlEncode(item.Value))                Next            End Using            helper.Request.BeginGetResponse(New AsyncCallback(AddressOf HttpHelper.BeginResponse), helper)        End If    End Sub    Private Shared Sub BeginResponse(ByVal ar As IAsyncResult)        Dim helper As HttpHelper = TryCast(ar.AsyncState, HttpHelper)        If helper IsNot Nothing Then            Dim response As HttpWebResponse = DirectCast(helper.Request.EndGetResponse(ar), HttpWebResponse)            If response IsNot Nothing Then                Dim stream As Stream = response.GetResponseStream()                If stream IsNot Nothing Then                    Using reader As New StreamReader(stream)                        helper.OnResponseComplete(New HttpResponseCompleteEventArgs(reader.ReadToEnd()))                    End Using                End If            End If        End If    End SubEnd ClassPublic Delegate Sub HttpResponseCompleteEventHandler(ByVal e As HttpResponseCompleteEventArgs)Public Class HttpResponseCompleteEventArgs    Inherits EventArgs    Public Property Response() As String        Get            Return _Response        End Get        Set(ByVal value As String)            _Response = value        End Set    End Property    Private _Response As String    Public Sub New(ByVal response As String)        Me.Response = response    End SubEnd Class



Silverlight 2.0 and My Game Engine

I got the chat portion of the game engine working with Silverlight 2.0 tonight. I am just using web services to send the commands back and forth for now. Once I complete incorporating the other portions of the engine into Silverlight I will start playing around with sockets. 


Data Format for Socket Server Packets

For my PBBG Engine I started off programming it all for the web and AJAX. Recently I added support for sockets by porting over my socket server code I wrote for a Flash server and incorporating the code into the PBBG Engine. In a previous post about my PBBG Engine Architecture I outlined my plans for how the socket and web pieces would work together. I spent some time today refining my command pipeline and server protocol for the socket side of the engine and will probably utilize that on the web side as well.

I decided on the following format for the data packets that will go to and from the server and client. Since it is just bytes going back and forth and I wanted to keep the data streams as small as possible I decided to abandon the string based command protocol and use this instead:

The first 2 bytes of the packet will be used to store an Int16 (short) value that indicates the command to execute. I have an event being raised from the game engine that allows the implementing libraries to set the game commands. This was a Dictionary<string, ICommand> but I am going to change it to a Dictionary<short, ICommand>. That will save me some bytes back and forth without passing the command names. I can have the clientsend the proper short value for the command typed into the console or just have the links and events in the client supply the proper short value.

The next 4 bytes will be the integer length value of the message. This will allow me to know when this message ends and the next one begins.

All the bytes following up to the length value will be the actual message sent to the client or sent to the server.

The server is already validating commands, I will just need to modify to validate these bytes and watch for buffer over runs. I still need to work out validating that a logged in user is sending the information but I will work out something, maybe have the client send the encrypted authentication key to the server after a connection is opened but before commands can be processed. 



PBBG Engine Architecture

Thought I would go ahead and post a little about the architecture I have set up for my PBBG engine so far. Basically, the engine is a library that other projects can reference to make building PBBGs a little easier. All of the logic for handling incoming requests and parsing commands is contained within the engine. My PBBG engine is kind of like a MUD driver, it requires a MUDLib to define objects, persist data, etc. Some interfaces are defined within the engine library to make it extensible while it also contains base class implementations of those interfaces to make building on top of working logic possible. When the engine starts up it raises a set of events and when it processes commands it also raises events to allow the implementing application to control loading of commands, determining the server implementation and creating command instances.


Not the best diagram in the world but kind of gives you the idea of how it works. The column down the middle are the interfaces defined by then engine, which also define base classes, except for the CommandManager which is just a static class for processing commands.

In addition to the classes here are the Verb abstract class, the ICommand interface and the Command<Verb> instance for creating commands from Verbs. The CommandManager raises an event when it finds the command text that allows an external library to set the ICommand instance that will execute the current command. When the engine starts up though it raises an event that will allow the implementation library to set all the commands into memory rather than creating a new instance with each command.

The IServer interface defines an IConnectionManager property where connections into the server are managed, either socket or http.

On the WEB side, which is actually a namespace ".Web"; the "Server" instance writes out a JavaScript reference to an embedded js file containing the script required to submit commands to the engine using AJAX. A separate RequestHandler class actually parses the input from the AJAX call and then attempts to locate or create an IConnection instance on the Server's IConnectionManager instance. The Server in this namespace actually sends the command to the CommandManager.

On the NET side, which is actually a namespace ".Net"; the "Server" instance actually contains the socket used to listen for incoming connections on a port specified during startup. From there the individual IConnection instances contained in the IConnectionManager instance handle processing the input and formatting it into a command. The IConnection instance contains the connected socket and will send the command to the CommandManager.

Both IConnection instances in both namespaces allow messages to be sent to the client along with custom data such as stats, gold, map data, etc. The difference between the two is that the WEB instance sends all of this back as JSON in the HTTP response and the NET instance sends the messages down the socket as they are added to the IConnection instance and then sends the additional data once the command completes execution.

That is all I have completed at this point on the engine side, it processes commands from the web and the implementation library sitting on top of it handles the commands and persists the data. There is plenty of work on the implementation library side still yet to be completed.


Perenthia Update

I haven't decided yet but am considering using Silverlight 2.0 with the next release of Perenthia. I've completed a good portion of my PBBG engine that will drive Perenthia but want to be able to take advantage of some the features of Silverlight 2.0 to provide better user experience. One of the features that really interests me is the socket support for 2.0. Once I get the 2.0 beta 1 bits I am going to start playing around with running my PBBG engine on a socket server application I wrote for Flash. If all goes well I should be able to provide some better multiplayer features in Perenthia such as real time chat and possibly player vs player combat.

Perenthia will still primarily be a text-based game but Silverlight could allow me to bridge the gap between web and client software. 


Advanced Physics with Farseer

Andy Beaulieu has posted another great article about Advanced Physics with Silverlight and Farseer. His demo allows you to draw objects that are then associated with a Farseer Physics Body. Andy mentions me in his post and references the code I created to render a Path based on Vertices. Andy's first tutorial "Getting Started with Farseer Physics and Silverlight" was key in helping me understand how to get Farseer working with Silverlight.


Thanks Andy! 


Silverlight Pirates! Prototype

The Silverlight Pirates! prototype is online!

Keep in mind that this is a very early prototype and about the only thing you can do is destroy that other ship that is sitting there. I didn't get the enemy AI quite where I wanted it but it will fire on you if you get close. You can sail around and dock at ports, although you can't buy anything yet. Once your ammo runs out you will have to refresh the page to reload the game. You will also have to refresh if the enemy ship kills you.

On my TODO list are:

  • boundaries to keep you from sailing on forever
  • merchant ships to attack
  • better enemy AI so the merchants will run and man-o-war will chase
  • sea monsters
  • whirlpools
  • storms, which should be a big challenge
  • menu for when you are at port to buy ammo or repair your ship
  • gold and/or ammo drops from enemy ships

If you find any funky bugs please let me know and of course, you will need Silverlight 1.1 in order to run the prototype.

Silverlight Pirates! Prototype 


Silverlight Pirates!

I'm going to put up the Silverlight Pirates prototype in another day or so. The prototype will only include one enemy ship. I was going to get the port menus completed so you could buy ammo and repair your ship but I think I am going to wait until the Silverlight 2.0 beta is released. 

I'm not competely happy with the enemy ship AI but I have time to work it out. Once I finish the prototype I am going to wait for Silverlight 2.0 to finish out the game.


Some Additional Silverlight Pirates! Screenshots

The first screenshot is just sailing around. I was working on positioning the cannons and making sure the mini map was working as planned.


 Silverlight Pirates!


The second screenshot is me docked at the port of this island. Ports will be places to repair your ship, buy cannons, cannon balls and rum.


Silverlight Pirates!



Silverlight Pirates! Arr!

Thought I would post a screenshot of the game so far. I still have a lot to do but it is coming along pretty well I think. I am hoping to get a playable prototype in the next few days, just depends on how development goes.



Silverlight Pirate Game and Farseer Physics Engine

I have recently been working on a Pirate Game in Silverlight 1.1 Alpha and decided to use the Farseer Physics Engine to handle collisions, etc. I used Andy Beaulieu's Getting Started with Farseer Physics and Silverlight to create my SpriteBase class. I originally used the Silverlight Games 101 tutorials to get started and got turned on to Farseer from that site.

Since this is a Pirate game you will be sailing around in a ship encountering other ships and various islands. One of the big challenges I ran into right from the start was getting the Vertices setup for collision with an island. I am unable to visualize more than a view Vertex points at a time so I was having trouble getting the island border setup correctly. For those unaware, Farseer provides a Body class which just represents a body in space. You can assign the Body a Geometry object that actually defines its physical structure within your world. The GeomFactory class provides methods for creating circle, rectangle and polygon geometries.Since I have a island I was in need of a ploygon geometry which is created using a collection of Vector2 instances within a Vertices instance.

Geom g = GeomFactory.Instance.CreatePolygonGeom(this.PhysicsSimulator, this.Body, vertices, 1);

When creating the Vector2 instances to add to the Vertices collection you have to specify the X and Y values in relation to the center of the geometry. In other words, if I have a geometry that will be 64 X 64 and want to set a Vertex at the top, left of the square the Vector2 instance would be new Vector2(-32, -32). For an island that is 512 X 512 that is a lot of going back and forth with the calculator.

Anyway, not matter what I did I still couldn't get the vertices correct. I eventually created a helper method in a Utils class that will accept the Vertices collection, a width and height and create a Path instance that I can add to my Canvas in order to see the Vertices. This greatly helped me to understand where I was placing my points. Here is the CreatePathFromVertices method I created:

public static Path CreatePathFromVertices(Vertices vertices, double width, double height)
            Path path = new Path();
            path.Stroke = new SolidColorBrush(Colors.Magenta);
            path.StrokeThickness = 1;
            path.Fill = new SolidColorBrush(Colors.Transparent);
            PathGeometry pathGeom = new PathGeometry();
            PathFigureCollection figures = new PathFigureCollection();
            pathGeom.Figures = figures;
            PathFigure figure = new PathFigure();
            figure.StartPoint = new Point((double)vertices[0].X, (double)vertices[0].Y);
            figure.Segments = new PathSegmentCollection();

            foreach (var vector in vertices)
                LineSegment line = new LineSegment() { Point = new Point((double)vector.X, (double)vector.Y) };

            TranslateTransform trans = new TranslateTransform();
            trans.X = width / 2;
            trans.Y = height / 2;
            path.RenderTransform = trans;

            path.Data = pathGeom;
            return path;

To use it all I do is call it after creating my Vertices collection and add the returned Path to my UserControl Canvas:

this.Root.Children.Add(Utils.CreatePathFromVertices(vertices, this.Root.Width, this.Root.Height));

This was working better but I wanted to be able to create the Vertices collection a little faster. I had originally created my island image in Photoshop and so I opened up the PSD and added a new transparent layer called Vertices. In the Vertices layer I proceeded to draw points around the island using a 1px Pencil of Magenta color. After I created a point based structure around the image I saved just the Vertices layer as a PNG. I then wrote a C# WinForms application to load up the PNG and parse it pixel by pixel, creating a Vertex for each of the Magenta points located within the image. The WinForms application then writes out the Vertices code required by the Farseer engine based on these Vertex instances.

Doing this gave me the Vertices I needed but not in the order I needed. The CreatePloygonGeom method requires the vertices to be in a clockwise or counter clockwise order. Parsing each pixel of an image only gives you the pixels in order from each x to y or y to x. I ended having to add the Image x and y location of each pixel as a comment to the end of the Vertices.Add line of code being generated by my WinForms application. From there I was able to use Photoshop to re-order the Vertices so that they rendered correctly.

vertices.Add(new Vector2(-208f, -173f)); // 48, 83
vertices.Add(new Vector2(-126f, -240f)); // 130, 16
vertices.Add(new Vector2(-61f, -200f)); // 195, 56

Using my CreatePathFromVertices method I was able to see the outline of the shape I created as the collision geometry for my island. One this I did notice was that I needed the very first line of the Vertices code to be repeated at the very end in order to join the geometry shape.

vertices.Add(new Vector2(-208f, -173f)); // 48, 83
vertices.Add(new Vector2(-126f, -240f)); // 130, 16
vertices.Add(new Vector2(-61f, -200f)); // 195, 56
vertices.Add(new Vector2(-208f, -173f)); // 48, 83

Here is a screenshot of the game with the Path around the island displayed. Granted the path is not perfect but sufficient for the game I think. I can always alter it but the more Vertices you add the longer it takes to load.

Here is the full code from the Constructor of my island class:

public SpringIsland(PhysicsSimulator physicsSimulator)
            : base (physicsSimulator)
            System.IO.Stream s = this.GetType().Assembly.GetManifestResourceStream("Pirates.SpringIsland.xaml");
            this.Initialize(new System.IO.StreamReader(s).ReadToEnd());

            this.Body = BodyFactory.Instance.CreateRectangleBody(this.PhysicsSimulator, (float)this.Root.Width, (float)this.Root.Height, 1000);
            this.Body.IsStatic = true;

            #region Vertices
            Vertices vertices = new Vertices();
            vertices.Add(new Vector2(-208f, -173f)); // 48, 83
            vertices.Add(new Vector2(-126f, -240f)); // 130, 16
            vertices.Add(new Vector2(-61f, -200f)); // 195, 56
            vertices.Add(new Vector2(9f, -201f)); // 265, 55
            vertices.Add(new Vector2(43f, -241f)); // 299, 15
            vertices.Add(new Vector2(152f, -256f)); // 408, 0
            vertices.Add(new Vector2(235f, -209f)); // 491, 47
            vertices.Add(new Vector2(218f, -155f)); // 474, 101
            vertices.Add(new Vector2(118f, -145f)); // 374, 111
            vertices.Add(new Vector2(23f, -50f)); // 279, 206
            vertices.Add(new Vector2(114f, 55f)); // 370, 311
            vertices.Add(new Vector2(90f, 92f)); // 346, 348  
            vertices.Add(new Vector2(152f, 97f)); // 408, 353
            vertices.Add(new Vector2(235f, 148f)); // 491, 404
            vertices.Add(new Vector2(216f, 219f)); // 472, 475
            vertices.Add(new Vector2(147f, 252f)); // 403, 508
            vertices.Add(new Vector2(26f, 241f)); // 282, 497   
            vertices.Add(new Vector2(-62f, 234f)); // 194, 490
            vertices.Add(new Vector2(-118f, 203f)); // 138, 459
            vertices.Add(new Vector2(-126f, 167f)); // 130, 423
            vertices.Add(new Vector2(-156f, 143f)); // 100, 399
            vertices.Add(new Vector2(-218f, 129f)); // 38, 385
            vertices.Add(new Vector2(-233f, 103f)); // 23, 359
            vertices.Add(new Vector2(-232f, 35f)); // 24, 291
            vertices.Add(new Vector2(-200f, 16f)); // 56, 272
            vertices.Add(new Vector2(-195f, -32f)); // 61, 224
            vertices.Add(new Vector2(-230f, -95f)); // 26, 161
            vertices.Add(new Vector2(-199f, -141f)); // 57, 115
            vertices.Add(new Vector2(-208f, -173f)); // 48, 83

            this.Root.Children.Add(Utils.CreatePathFromVertices(vertices, this.Root.Width, this.Root.Height));

            Geom g = GeomFactory.Instance.CreatePolygonGeom(this.PhysicsSimulator, this.Body, vertices, 1);
            g.CollisionHandler += new FarseerGames.FarseerPhysics.Collisions.Geom.CollisionHandlerDelegate(this.HandleCollision);

The code in the "Vertices" region was generated by the C# WinForms application and I re-ordered manually. I will release the source to the Pirate game once it is complete, if you want the prototype code just contact me. I will probably post the prototype online once I get the Ship AI and cannons working so at least there would be more to do that just sail around the island. :)

Here is the code for the C# WinForms app that will read the image pixel data and create the Vertices code segment:


A Silverlight Pirate Game

I've decided to take a little break from working on Perenthia and focus some time on building some smaller, shorter life span games. I have two reasons for doing this; the first being that by building some smaller games I can get the games completed faster which is very encouraging and allows me to have new projects to work on. Perenthia is very time consuming because I keep making it complex, I feel it needs this complexity though to be a fun and engaging game. The second reason is that I want to get my feet wet in Silverlight and building some smaller games would give me just that. I will continue working on Perenthia but want to get a few more of my ideas built and playable before finishing it out.

That being said the first Silverlight game I will be creating will be a Pirate game where you sail around, avoiding the navy, attacking ships and finding buried treasure. Doing something like this will enable me to get core mechanics worked out in Silverlight along with animation, collision detection, etc.

As it stands right now I have the basic player movement and ship movement down. The graphics are pretty bad as it was just something for prototyping. The game will be a top down view and hopefully provide some fun gameplay in short intervals. I want to be able to persist the player information so you can pick back up where you left off and ultimately complete the game.

The goal of the game will be to attain the buried fortune of a long dead pirate named Rough Hand James. He created a map to his treasure and scattered the pieces all across the globe. It will be your adventure to find those map pieces and locate the treasure. You will start out on your ship with the first clue to the treasure and along the way you may encounter the Royal Navy, sea monsters and other pirates. You will engage in sea and land battles, loot merchant vessels and follow clues through towns, uncharted waters and wilderness all to find the greatest fortune every massed by one pirate.

I am going to work a little on the graphics and get some animations working and then I will post either a screenshot or working prototype of the game in the next few days.