Monday, June 29, 2009
ChatNDraw was created using my PrismServer component suite that I just converted to WPF/Silverlight from WinForms (.NET 2.0). I plan to release the source for PrismServer as soon as I can complete the documentation.
Friday, June 26, 2009
Note - if you create an account here, it will become the eventual account you'll use for all SCG Silverlight games.
I wanted to get this news out to allow for some early testing. I do plan on creating a post describing the new PrismServer in more detail, and possibly a revised CodeProject article. For now, my fingers are falling off of my hands so I need a break from coding ;)
Tuesday, June 23, 2009
Earlier I began porting my object-oriented TurboSprite framework to WPF. This was relatively easy because WPF had the OnRender event and the DrawingContext that corresponds to WinForms Paint/Graphics combo.
When I decided to target Silverlight as the next platform for Silicon Commander Games development, one of the first hurdles was the fact that it did not expose the OnRender/DrawingContext feature of WPF. This forced me to use the animation system(s) built into Silverlight/WPF and abandon further development of TurboSprite.
One of the benefits of encapsulating animation in TurboSprite was its clean, object-oriented design. I could create animatable sprite classes that were self-contained and re-usable.
In Silverlight I am following the same philosphy of design, but using the animation model(s) provided by the framework. Note the plural!
Model 1 - Property Based Animation
This model works by creating Storyboard objects, and then adding animations (like DoubleAnimation, ColorAnimation, etc.) to its Children. You call Begin() to start animating, and can handle the Complete event when the animation is finished. You provide a Duration that controls how long the animation lasts. The Storyboard can have multiple animations in its Children collection. Each animation targets a specific property of a specific object.
I use this method when I need to move an object from one cell to another on the game grid. To simplify the model, I created a base class called SquareGridGameBoard that derives from UserControl. SquareGridGameBoard allows you to set the number of cells that compose the game board, as well as the width and height of each cell. It also provides a visual cell cursor, and a selection band that facilitates selecting a range of cells. SquareGridGameBoard also contains helper methods that make it easy to position, and move, an element on the game board.
The MoveElement helper method encapsulates the plumbing of creating a Storyboard, the animations, and handling the completed event. Here's the code:
//Move an element to another cell
public void MoveElement(UIElement element, int newX, int newY, Duration duration)
//Create Storyboard, and remember the element it references
Storyboard sb = new Storyboard();
sb.Completed += MoveCompleted;
_storyboardTargets[sb] = element;
//Animate X coordinate
DoubleAnimation animX = new DoubleAnimation();
animX.To = newX * CellWidth + _cellWidthHalf;
animX.Duration = duration;
Storyboard.SetTargetProperty(animX, new PropertyPath("(Canvas.Left)"));
//Animate Y coordinate
DoubleAnimation animY = new DoubleAnimation();
animY.To = newY * CellHeight + _cellHeightHalf;
animY.Duration = duration;
Storyboard.SetTargetProperty(animY, new PropertyPath("(Canvas.Top)"));
private void MoveCompleted(object sender, EventArgs e)
//what element was being moved?
Storyboard sb = sender as Storyboard;
UIElement element = _storyboardTargets[sb];
//push values into properties after animation changes them
double x = Canvas.GetLeft(element);
double y = Canvas.GetTop(element);
You can see this in action in the current demo as of Build 7. When you click on a cell of the game map, it creates a random StarShip, but also moves a StarSystem to that location, using the MoveElement method described above.
Model 2 - Frame-Based Animation
Another animation option that Silverlight provides is enabled by creating an event handler for the static CompositionTarget.Rendering event. When you do this, Silverlight calls your handler on each frame of animation. The default frame rate is 60 FPS, but this is adjustable by adding the "maxFramerate" parameter in your HTML.
I use this method to cycle the colors of an array of 10 SolidColorBrushes that draw the Shields around StarSystems. The Ellipse elements that compose the Shields have their Stroke properties set to one of the brushes in this static array. When the color of one of the brushes changes, it impacts all of the Shield Ellipses that used that brush in their Strokes.
You can see the Shield color cycling in action in Build 7 of the demo.
Sometimes it makes sense to use property-based animations, but sometimes frame-rate animations are a more logical choice. There's no need to sacrifice, use both models, and select the one that makes the most sense for each particular animation task in your Silverlight app!
Monday, June 22, 2009
- I call the BuildScenario method of a Scenario-derived class (in this case Classic).
- Classic creates some random Nebula in the SVGame object.
- I create a PngGenerator of 100x100 pixels in size, representing the full number of cells in the map grid.
- For each cell that contains a Nebula, I set the pixel to a bluish color, otherwise set it to black.
- I make the image the source for an Image object and add this to the Canvas of the game board, sizing it to the full dimensions of the board (3,500 x 3,500) and setting its Stretch property to Stretch.
I was expecting to see sharp edges in the blown up image, but was surprised and happy to see the blended edges that Silverlight produced. Another hurlde overcome (this time thanks to Ian) in my quest to port Solar Vengeance to Silverlight.
See the latest demo build here:
Wednesday, June 17, 2009
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:
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:
2 - Pick a random letter in the Chain following AS. In our example the only one is H.
3 - Continue picking random letters in the chain until we get an end.
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:
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.
Click here to download the MarkovNameGenerator.cs C# file.
Silverlight Sample App
Monday, June 15, 2009
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 ...
Sunday, June 14, 2009
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 ...