Part of the Perenthia re-birth is to get the game running in the cloud on Windows Azure. I started an Azure 1.2 web role project to handle the game. I got some of the basic stuff working like authentication and character creation. With the release of Azure 1.3 SDK I had to install IIS 7.5 components. Since I did not install it previously I had to run “aspnet_regiis –iru” to setup the IIS mappings for .NET 4 and I had to install the “HTTP Redirection” component for IIS 7. After getting all that setup I am up and running with Azure 1.3.
Because I am scaling the game down a bit and restructuring it to run with basic html and a variety of devices I am essentially re-building the game. I have a lot of code to work from and the concepts are already defined but I do have to do some new things. With running in the cloud some of the previous in-memory stuff I was doing has to be setup to store that in-memory data either in the database or in Azure Storage. For instance, when you connect to the game you get a token or session that identifies you. That token contains a reference to an in-memory object that stores the user id and currently selected character of the player. While I could setup and use .NET Sessions with some providers to store the data in Azure Storage I am going to continue to use the existing system I had in place and store in the in-memory data in Azure Table Storage.
I have some additional in-memory data that will either scale back to database driven queries or work the same way as tokens/sessions with table storage.
12/1/2010
After many months of not working on Perenthia I find myself once again desiring to see it complete. The last revision I did on Perenthia was some time ago and involved a Silverlight UI with a C#/SQL 2008 backend.
During the course of development on Perenthia I discovered some of the pitfalls of attempting to develop a role playing game by one self. Mainly, the inability to handle content creation on a large enough scale as to appeal to players and have enough interactivity to make the game fun. I have been thinking lately of ways to reduce that load and still keep the game fun. I have some new ideas I want to put into place and re-release Perenthia with these concepts.
Among the changes I plan to implement will be scaling the game down to function solely in an HTML environment. This will enable me to provide a mobile version that works on all phones with a browser and keep the feature set the same for both phone and web.
I have begun to refactor pieces of the code and am making heavy use of jquery for the character creation screen.
11/30/2010
5/31/2010
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.
3/27/2010
Andy Beaulieu has some helpful performance tips for Windows Phone 7 and Silverlight primarily focused on games of course.
3/25/2010
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.”
3/24/2010
Laurent Bugnion has discovered a bug in the Windows Phone 7 emulator when multi-threading and has posted a workaround:
3/20/2010
Frank LaVigne has posted a very useful tool to download all of the MIX 10 session content.
3/17/2010
Here is a video of the Pirates game:
[youtube http://www.youtube.com/watch?v=b9LHFS1dKWg&hl=en_US&fs=1&color1=0x2b405b&color2=0x6b8ab6]3/11/2010
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.
ISprite.cs
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.
3/10/2010
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
3/10/2010
If you plan on pre-ordering Silverlight 4 Business Application Development – Beginner's Guideuse the following codes to save some money!
MsSilver15 – Save 15% off hard copy of the book
MsSilver30 – Save 30% off the eBook
If you are looking to get into Silverlight this is a great intro book. Frank Lavigne starts the book out by getting you involved in the code right away and we try and keep the working code methodology through out. If you learn by doing then you will benefit from the book!
2/2/2010
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.
2/1/2010
I thought I would some extension methods I have been using for a little while now for Linq to Xml. When loading and retrieving the attribute values from XML nodes via Linq there is a bit of code to write to make sure the attribute exists and that the value is a valid data type. Rather than having a bunch of code to do this I simply wrote some extensions that operate on an XElement and are targeted at returning the value of an XAttribute.
Usage:
var element = XElement.Parse("<value x="50.5"/>");var value = element.GetDoubleValue("x");.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; }.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; }
Anyway, here is the class for the extensions:
1: using System;
2: using System.Xml.Linq;
3:
4: namespace System.Xml.Linq
5: {
6: public static class XLinqEx
7: {
8: /// <summary>
9: /// Gets a short value for the specified attribute.
10: /// </summary>
11: /// <param name="element">The element to parse.</param>
12: /// <param name="attributeName">The XName of the attribute to parse.</param>
13: /// <returns>A short value representation of the attribute value.</returns>
14: public static short GetInt16Value(this XElement element, XName attributeName)
15: {
16: var attribute = element.Attribute(attributeName);
17: if (attribute == null)
18: return 0;
19:
20: short result = 0;
21: Int16.TryParse(attribute.Value, out result);
22: return result;
23: }
24:
25: /// <summary>
26: /// Gets an int value for the specified attribute.
27: /// </summary>
28: /// <param name="element">The element to parse.</param>
29: /// <param name="attributeName">The XName of the attribute to parse.</param>
30: /// <returns>An int value representation of the attribute value.</returns>
31: public static int GetInt32Value(this XElement element, XName attributeName)
32: {
33: var attribute = element.Attribute(attributeName);
34: if (attribute == null)
35: return 0;
36:
37: int result = 0;
38: Int32.TryParse(attribute.Value, out result);
39: return result;
40: }
41:
42: /// <summary>
43: /// Gets a long value for the specified attribute.
44: /// </summary>
45: /// <param name="element">The element to parse.</param>
46: /// <param name="attributeName">The XName of the attribute to parse.</param>
47: /// <returns>A long value representation of the attribute value.</returns>
48: public static long GetInt64Value(this XElement element, XName attributeName)
49: {
50: var attribute = element.Attribute(attributeName);
51: if (attribute == null)
52: return 0;
53:
54: long result = 0;
55: Int64.TryParse(attribute.Value, out result);
56: return result;
57: }
58:
59: /// <summary>
60: /// Gets a double value for the specified attribute.
61: /// </summary>
62: /// <param name="element">The element to parse.</param>
63: /// <param name="attributeName">The XName of the attribute to parse.</param>
64: /// <returns>A double value representation of the attribute value.</returns>
65: public static double GetDoubleValue(this XElement element, XName attributeName)
66: {
67: var attribute = element.Attribute(attributeName);
68: if (attribute == null)
69: return 0;
70:
71: double result = 0;
72: Double.TryParse(attribute.Value, out result);
73: return result;
74: }
75:
76: /// <summary>
77: /// Gets a bool value for the specified attribute.
78: /// </summary>
79: /// <param name="element">The element to parse.</param>
80: /// <param name="attributeName">The XName of the attribute to parse.</param>
81: /// <returns>A bool value representation of the attribute value.</returns>
82: public static bool GetBooleanValue(this XElement element, XName attributeName)
83: {
84: var attribute = element.Attribute(attributeName);
85: if (attribute == null)
86: return false;
87:
88: bool result = false;
89: Boolean.TryParse(attribute.Value, out result);
90: return result;
91: }
92:
93: /// <summary>
94: /// Gets a string value for the specified attribute.
95: /// </summary>
96: /// <param name="element">The element to parse.</param>
97: /// <param name="attributeName">The XName of the attribute to parse.</param>
98: /// <returns>A string value representation of the attribute value.</returns>
99: public static string GetStringValue(this XElement element, XName attributeName)
100: {
101: var attribute = element.Attribute(attributeName);
102: if (attribute == null)
103: return String.Empty;
104:
105: return attribute.Value;
106: }
107:
108: /// <summary>
109: /// Gets a byte array from the base 64 encoded value of the current element.
110: /// </summary>
111: /// <param name="element">The element to parse.</param>
112: /// <returns>A byte array of the base 64 encoded element value.</returns>
113: public static byte[] GetByteArray(this XElement element)
114: {
115: var value = element.Value;
116: if (!String.IsNullOrEmpty(value))
117: {
118: return Convert.FromBase64String(value);
119: }
120: return null;
121: }
122: }
123: }
1/19/2010
For those of you out there wanting to get into Silverlight development but just do not know where to start, Frank LaVigne and I have just about completed our book titled Microsoft Silverlight 4 Business Application Development – Beginner’s Guide(link to pre-order). This book will be ideal for current Windows or ASP.NET developers who want to learn Silverlight and because the book is centered on Business Application Development we will empower you with knowledge so you can recommend Silverlight for the next business project at your company.
Gaining the basics required to develop in Silverlight, make use of data binding, WCF and RIA Services you will be prepared to lead the Silverlight charge at your company. Be warned, once you start developing in Silverlight you will have a hard time going back to normal ASP.NET development.
1/18/2010