Wednesday, June 17, 2009

Markov Name Generator C# Class

A Markov Chain is a way of generating a result based on the statistical probabilities in a set of sample data. The MarkovNameGenerator class can generate random words (names) based on a set of sample words that it takes as input.

It works by building "chains" that count the number of occurrences of each letter in the alphabet after each group of "N" letters in the sample name. "N" is called the "Order" of the Markov Chain.

The class generates a new name by first selecting a random group of "N" letters to begin the name. It then goes forward letter by letter, examining the Chains and picking a new letter from the pool of letters that followed the previous "N" letter groups in the sample data.

For example, the words "Sally Sells Seashells" breaks down into the following 2-Order Chains:

SA-(L)
AL-(L)
LL-(Y)
LY-(End)
SE-(L,A)
EL-(L,L)
LL-(S,S)
LS-(End,End)
EA-(S)
AS-(H)
SH-(E)
HE-(L)

Note the Chains in yellow. These represent 2 letter pairs that occurred more than once in the sample words. The Chain contains all of the letters that follow the single pair of letters.

Now, when the generator makes a new random name it follows this sequence:

1 - Pick a starting pair of letters randomly:

AS

2 - Pick a random letter in the Chain following AS. In our example the only one is H.

AS->H

3 - Continue picking random letters in the chain until we get an end.

A(SH)->E
AS(HE)->L
ASH(EL)->L
ASHE(LL)->S

Result = Ashells

In this sample, we never encountered the SE pair, but if we had, we would have appended one of the two candidate letters in the chain randomly.

The fun comes when you feed the name generator with a large number of sample names. The generator, particularly when set to an Order of 3, can produce new names that bear a remarkable similarity in style to the sample names, while still being original.

Using the Class

The MarkovNameGenerator class constructor takes 3 arguments:

public MarkovNameGenerator(IEnumerable sampleNames, int order, int minLength)

The first parameter is the collection of sample names. This can be an array or list of strings. Each string can contain one sample name, or a number of samples separated by commas.

The second parameter determines the Order of the Markov Chains, and the last parameter specifies the minimum length of a generated name.

Accessing the NextName property returns a new random name based on the sample data. The class ensures that the same random name is not returned twice.

Call the Reset method to clear out the internal list of previously generated names.

Download

Click here to download the MarkovNameGenerator.cs C# file.

Silverlight Sample App

http://www.siliconcommandergames.com/markov/TestPage.html

Monday, June 15, 2009

Vector or Image?

I'm learning that to take best advantage of the graphical model in WPF/Silverlight I need to shift much of the design work from bitmap based images to vector based graphics. This is especially true in Silverlight which has a much more limitted .NET class library, and no direct support for colorizing images.

In Solar Vengeance, I have a set of grayscale images that represent each StarShip type. When a game begins, SV dynamically generates colorized versions of the images for display. This was easy to do in WinForms and System.Drawing. I haven't found a reasonable solution to this in Silverlight. The WriteableBitmap class that's coming in Silverlight 3 might be a solution, but along the way I have found a better way.

The StarShip graphics for SV are very simple representations, and lend themselves well to vector based graphics. I can create custom classes in Silverlight that render the images using a combination of the simple graphics primitives that Silverlight offers, like Rectangle and Ellipse.

By creating a common StarShip visual base class, I can provide a single "Color" property that gets inherited to the customized rendering classes.

In the latest update of my demo app I render some StarShip types in a list box with a vector based version next to the image based. My work in progress is here ...

http://www.siliconcommandergames.com/SVSilverlight/TestPage.html

Sunday, June 14, 2009

Foray into Silverlight

I finally installed the Visual Studio 2008 Service Pack 1 and the Silverlight 2 development tools. I created my very first Silverlight test project today! Along the way I found something rather alarming. Visual editing of the design surface is not possible for Silverlight apps in Visual Studio 2008! You cannot drag and drop controls on the Window, nor can you edit the properties of controls using the Property Window in VS2008. My XAML chops are getting better every day, but this will really force me to exercise them. I understand the VS2010 might include design time support for Silverlight, which would be most welcome. On the other hand, this might finally push me to get off my behind and get Expression Blend.

Another position was that my fledgling port of the Solar Vengeance logical engine class library ported to Silverlight without any errors or changes needed.

When I develop a game, I always strive to cleanly separate the logical data model from the user interface. I create a .NET Class Library project that contains the logical model of the game, and a separate project for the user interface.

By maintaining this strict seperation it is now much easier for me to port SV to another platform such as WPF and/or Silverlight. I'm also probably going to change how the multiplayer communication works. A beefed up custom PrismServer will use the same SV logical engine to create an instance of the game and serve as the "host" of the game. It will receive the orders from players, process the turn, and send the results back to each client on each Impluse.

I have some challenges ahead if I want to create an SV front end in Silverlight. In particular, Silverlight does not support the DrawingContext and OnRender method which is the basis of my TurboSprite animation system. If I want a Silverlight SV, I will have to leverage its animation model, perhaps building my lightweight framework around Composition.Rendering which lets you get at the animation loop in a WPF/Silverlight app.

For now, here's my first "Hello, World" Silverlight page ...

http://www.siliconcommandergames.com/SVSilverlight/TestPage.html

Saturday, May 30, 2009

WPF Black Holes


My journey into WPF is still in its infancy, but I want to document some of the ups and downs I've discovered working with the framework, ending in a big UP!

I've been googling like mad and absorbing knowledge as I ramp up the WPF learning curve. Some of my early research left me feeling pessimistic about the prospects of writing a game using WPF. First, there was the message group post (I cannot locate the link anymore, but I promise this was for real) where the poor programmer was experiencing poor render performance drawing lines in WPF (more on that later!) The suggestion he finally adopted was to run a WinForms Picture control hosted in his WPF application! Astonishingly, the GDI+ based WinForms outperformed WPF in the line drawing heavy application!

Second was the promosing blog entitled "WPF for Games". The author was literally gushing about WPF in his early blog entries. By the end of the blog, this grim topic appeared - "Throwing in the Towel", where the author is fed up fighting against the WPF framework and decides to write his game in XNA.

I love a good challenge, and this just makes me want to try harder to get a decent game out of WPF ;)

My first concrete project in WPF is a port of my TurboSprite sprite engine. I have debated internally about whether to port TurboSprite to WPF, or to try and use WPF's framework as the basis for my sprite animation. I concluded that porting TurboSprite would save me alot of headaches in the long run. My feeling is that my lightweight sprite engine will allow me to realize the graphics performance I want without pushing this burden onto the WPF framework. My sprites descend from Object - and there's nothing more lightweight than that! I will use the WPF framework to try and make a cool user interface surrounding the main SpriteSurface that contains the game's action.

But how to translate TurboSprite to WPF? The main component of TurboSprite is the SpriteSurface, and for this I derive from FrameworkElement, and drawing in an overridden OnRender method, using the supplied DrawingContext. In my next blog post I plan to go into some of the early technical details of my implementation, but for now I can describe some of the early results.

I've found that rendering images in the DrawingContext using DrawImage is blazingly fast, and perforing rotations using Transforms seems to not impact rendering performance. I was able to create many very large ImageSprites and add them to the SpriteSurface without and degredation in FPS. This is good news for Scenarios that like to use many large background graphics!

Next I tried to tackle porting beat2k's SpiralSprite, which is the basis for black holes in the SV graphics. The code ported easily enough, but when I created a SpiralSprite in my new WPF TurboSprite, the animation rate went down the toilet! Adding 2 or 3 SpiralSprites caused a complete bottleneck and the FPS was down in the single digit range.

But I was determined to find a better solution than hosting a WinForms control for my SpriteSurface!

After some research I discovered that creating a Geometry was the way to go. Apparently, the Geometry can be rendered with graphics acceleration all in one shot, while rendering the individual lines was very time consuming. The problem with this approach is that it sacrificed the ability to color each segment of the spiral, an effect that beat2k implemented in his code. I solved the problem by rendering the SpiralSprite using a RadialGradientBrush, with the end color set to Transparent.

The end result is a new SpiralSprite class that still has the customizability, the rotation (now leveraging the existing Sprite Spin and SpinSpeed properties), and that can be rendered extremely quickly on the SpriteSurface.

The code for the modified SpiralSprite


//SpiralSprite class by Jason Milliser

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;

namespace SCG.TurboSprite
{
public class SpiralSprite : Sprite
{
//constructor
public SpiralSprite(int arms, float radiusmin, int radiusmax, int armslope, int slopelength, bool isSpinningClockwise, Color CenterColor)
{
//arm slope is the number of lines drawn to the center of the spiral. Also controls the tightness of teh spiral.
//slopelength is the length of each line segment of each spiral. longer lines can tighten spiral, but quality will go down.
slength = slopelength;
_centerColor = CenterColor;
_direction = isSpinningClockwise;
_radiusMax = radiusmax;
_radiusMin = radiusmin;
_armSlope = armslope;
_arms = arms;
Shape = new Rect(0-_radiusMax, 0-_radiusMax, _radiusMax * 2, _radiusMax * 2);
}

//calculate points of spiral
protected internal override void Process()
{
//we now need to create points only once, rotation performed by transformed
if (_points != null)
return;

int theta = 0;
float sinvalue = 0;
float cosvalue = 0;
double altitude = 0;
float faltitude = 0;
double radiusscale = 0;
double dradiusmin = 0;
int rdegrees = 0;

//preliminary math calculations
theta = 360 / _arms;

if (_points == null)
_points = new Point[_arms * _armSlope + 1];

for (int arm = 0; arm < _arms; arm++)
{
for (int seg = 0; seg < _armSlope; seg++)
{
if (_direction == true)
rdegrees = (seg * slength) + (arm * theta);
else
rdegrees = -(seg * slength) - (arm * theta);
while (rdegrees < 0) rdegrees = rdegrees + 360;
while (rdegrees >= 360) rdegrees = rdegrees - 360;

radiusscale = _radiusMax - _radiusMin;
dradiusmin = _armSlope;
altitude = (seg + 1) / dradiusmin;
altitude = radiusscale * altitude;
dradiusmin = _radiusMin;
altitude = dradiusmin + altitude;
faltitude = Convert.ToSingle(altitude);

sinvalue = LookupTables.Sin(rdegrees) * faltitude;
cosvalue = LookupTables.Cos(rdegrees) * faltitude;

_points[(arm * _armSlope) + seg].X = sinvalue;
_points[(arm * _armSlope) + seg].Y = cosvalue;
}
}
}

//Render the sprite
protected internal override void Render(DrawingContext dc)
{
if (_points != null)
{
//Create the Geometry if it doesn't yet exist
//this needs to be done on the same thread, so it's done here and not in Process
if (_geom == null)
{
_geom = new StreamGeometry();
StreamGeometryContext sgc = _geom.Open();
sgc.BeginFigure(_points[0], false, false);
List points = new List();
for (int i = 1; i < _points.Length; i++)
points.Add(_points[i]);
sgc.PolyLineTo(points, true, true);
sgc.Close();
}

//Transform the location to match the sprite's position
Transform t = new TranslateTransform(X - Surface.OffsetX, Y - Surface.OffsetY);
dc.PushTransform(t);

//Rotate sprite
Transform rotate = new RotateTransform(FacingAngle);
dc.PushTransform(rotate);

//Create gradient brush so spiral fades out
RadialGradientBrush rgb = new RadialGradientBrush(_centerColor, Colors.Transparent);

//Draw the spiral geometry
dc.DrawGeometry(null, new Pen(rgb, 2), _geom);

//Draw the central back hole
dc.DrawEllipse(Brushes.Black, null, new Point(0, 0), 7, 7);
dc.Pop();
dc.Pop();
}
}

//private members
private Point[] _points;
private int _arms;
private float _radiusMax;
private float _radiusMin;
private int _armSlope;
private Color _centerColor;
private bool _direction;
private int slength;
private StreamGeometry _geom = null;
private Pen _pen = new Pen(Brushes.Yellow, 1);
}
}

Friday, May 29, 2009

Better Days ahead for WPF

I see after reading this article that the deficiencies in the WPF development experience that I mentioned in the previous blog post are being addressed in Visual Studio 2010. For example, the Property window has an Events button that lets you see the events of a class and set event handlers. It was frustrating to see that missing in the VS 2008 WPF Designer. I know, you can get a list of events by typing a space in the XAML and using Intellisense, but this is a very poor substitute for having the events nicely laid out in the Property window. Also, there are RAD tools that help creating bindings and apply styles to controls. I also noted that VS 2010 will also include a Designer for Silverlight applications. Maybe 2010 will be the year for SV 2010 - WPF and Silverlight editions.

Wednesday, May 27, 2009

Feet wet with WPF

I usually make a major shift in programming technologies when there's a very compelling reason. I remember when I decided to switch from Visual Basic to Delphi because Delphi offered a perfect object oriented framework and component model. Years later, when Delphi began to decline, I made a shift to the .NET Framework and C#. Mainly, I follwed Anders Hejlsberg from Borland to Microsoft - he was the primary architect of Delphi until Microsoft lured him away and he became the primary driver of C#.

With .NET came a layer of abstraction away from Windows, meaning less fine-grained control and power, but a modern development environment with a clear future.

Since the release of the .NET Framework 3.0 in late 2006, the WPF (Windows Presentation Foundation) framework was the cool new API in the Windows world. Windows Forms became old fashioned and quaint.

I'm about 3 years late to the party, but I have finally begun to update myself in WPF. The compelling reason this time is fear that Windows Forms is becoming a dinosaur framework, and I need to keep current. I have mixed feelings about this move, unlike for example the shift from VB to Delphi which I felt had no negative aspects.

First of all, my feeling is that WPF is currently half baked, without a full RAD development experience in Visual Studio. The idea of using two tools (Visual Studio and Expression Blend) to work on an application is not appealing to me. The direction of promoting XAML as a form markup language that a developer needs to code in leaves a very bad taste in my mouth. In my mind, the form markup language should remain in the background without having to be seen, much less edited. Also, much of the WPF API seems to have the flavor of the old Win32 APIs, with function calls with loads of obscure parameters in favor of a cleaner and more well thought out framework.

On the positive side, preliminary conversion of TurboSprite to pure WPF is showing promising results, with an animation frame rate of 3000+ FPS in my basic testing with no sprites added yet to an animated surface. All of my research indicates that GDI+ suffered badly in terms of performance when rendering images. WPF makes better use of graphics accelerators, so in general rendering should be much faster, as my early tests support.

Hopefully this will translate to an eventual SV6 and future games where graphics updates are no longer an issue! This transition also opens the door to create a companion SV6 client in Silverlight that will run in the web browser (in Windows or Macs) and allow multiplayer play through PrismServer. You may not remember, but once upon a time there was a Java applet version of SV that ran in the browser. Having a browser based, full fledged SV client is another compelling reason in favor of shifting development to WPF.

Sunday, April 12, 2009

WinWarII 5.0 Research and Bombing


I completed two more features in WinWar II 5.0. Firstly, the Technological Research component is in place. To have your Nation conduct research, all you need to do is build Labs in one or more of your Zones. The Labs generate tech points behind the scenes, and you get periodical improvements during the game. If you place a Spy in another Nation's Zone that contains a Lab, you can also steal some of their tech points as they are generated.

There are Conventional Technology Levels for Land, Air, and Sea. When you advance a Level, the units you build for the particular Unit Class (land/air/sea) are 10% stronger in their attack and defense (and bombing if applicable) levels.

Special Technologies include:

Radar
Allows you to build Radar installations in Zones that extend visibility.

Encryption
Gives you a chance of eavesdropping on private communications between other Players.

Rockets
Lets you build Rocket Launchers that can conduct Strategic Bombing in a target Zone in their range.

Atomic
Lets you build "Atomic" units such as an Atomic Bomber. Atomic attacks will devastate a Zone, reducing its Value, and possibly destroying Bases, Factories, Labs, etc. in the Zone, in addition to taking a large chunk out of the Funds of the Nation attacked.

I also completed the Strategic Bombing concept for the game. Certain Unit Types can be given the "Bombing" attribute which gives them Strategic Bombing capability. When these units are in an enemy Zone they will automatically conduct Strategic Bombing attacks periodically. The damage done is subtracted from the Funds of the Nation being attacked. Attacking high value Zones obviously does more damage.