Tuesday, October 30, 2007

Silverlight: Unit Testing

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/silverlight_unit_testing.htm]

Silverlight 1.1 lets you use C# code, which is awesome. However, the next natural question for a developer is "How will I test that code?" For example, any silverlight game, like the TruckWars game that I've been blogging about, has lots of backend logic for collision detection, movement algorithms, interactions between units, checking for victory conditions, etc... Ideally, you could follow the standard pattern of having a core assembly with all the logic (a Silverlight class library), exposed with just a light GUI wrapper (a Silverlight project). Then you could add that class library to a test harness (like MSTest) and do Test-Driven-Development.

 

The problem is that Silverlight doesn't let you mix Silverlight and non-Silverlight assemblies. So, you can't add your SL class library to a test harness (like MSTest), nor can you even add an assembly to your Silverlight library (like NUnit). [If there's a way to do this, I haven't seen it yet, and I'm all ears].

 

So, there is a work-around. What you could do is create an MSTest project, and then place your Silverlight class library in a child folder of that MSTest project. Then each project has references to all the same physical files.

 

For example, have a Test solution at:

    FolderSilverlight\Tank\Tank.Test\Tank.Test.csproj

 

And then your silverlight class library, called "SilverlightUtilities", as a child:

    FolderSilverlight\Tank\Tank.Test\SilverlightUtilities\SilverlightUtilities.csproj

 

Then, say you have a silverlight file to test, like "MathHelper.cs", located in the SilverlightUtilities:

    FolderSilverlight\Tank\Tank.Test\SilverlightUtilities\MathHelper.cs

   

Both projects, "Tank.Test" and "SilverlightUtilities" can have references to the same physical file, "MathHelper.cs" (there is only one copy of this file, but it gets referenced by two projects). Essentially, this means that the Tank.Test Project includes both the source code, and the test code.

 

Note, you'll need to give the Test project references to several Silverlight prerequisites:

  • agclr - C:\Program Files\Microsoft Silverlight\agclr.dll

  • System.Core - C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll

  • System.Silverlight - C:\Program Files\Microsoft Silverlight\System.Silverlight.dll

  • System.Xml.Core - C:\Program Files\Microsoft Silverlight\System.Xml.Core.dll

This does mean that as you add each new C# file, you have to build two projects, but an automated script should make that easy.

 

Also, I still haven't found a way to test code that uses Xaml (like a Silverlight Control). I keep getting the error:

 

    Project file must include the .NET Framework assembly 'WindowsBase, PresentationCore, PresentationFramework' in the reference list.

 

I'm sure there's a way to deal with this, but I haven't found it yet.

 

I hope that because Silverlight is still a beta, that Microsoft will eventually make it easier to unit test. In the meantime, it's good to be able to continue writing tests, even on Silverlight.

 

Monday, October 29, 2007

Silverlight: Using isolated storage to save client data

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/silverlight_using_isolated_storage_to_save_client_data.htm]

Silverlight allows developers to persist data to a file on the client's machine using Isolated Storage. This is just like writing a normal file, except that it handles a bunch of extra grunt work to write that file to unique spot for the user and application. So, instead of writing a file to "C:\Temp\myStuff.txt", that all users and applications can see, it writes it to something essentially like "FolderRoot\UserName\Application\myStuff.txt" (although, the real directory structure is a little more optimized and less plain-text).

 

What's also interesting about Silverlight isolated storage is that unlike other browser client-side repositories, like a cookie, (A) it is shared across browsers, and (B) it's not cleared by deleting temp files.

 

For example, in my Silverlight arcade TruckWars game, it uses isolated storage to determine what's the highest level you've reached, effectively saving your progress. The code has a class, IsolatedStorageHelper, that provides static utility methods to SetData, GetData, and Delete a file:

 

using System.IO.IsolatedStorage; using System.IO;  namespace SilverlightUtilities {   public class IsolatedStorageHelper   {     ///      /// Writes the given data to the given fileName in isolated storage.     /// If the file already exists, it is overridden.     /// If the file does not exist, it is created.     ///      ///      ///      ///      public static void SetData(string strData, string strFileName)     {       using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())       {         using (IsolatedStorageFileStream isoStream = new IsolatedStorageFileStream(strFileName, FileMode.Create, isoStore))         {           using (StreamWriter writer = new StreamWriter(isoStream))           {             writer.Write(strData);           }         }       }     }      ///      /// Gets the data from the fiven file.     /// Returns null if the file does not exist.     ///      ///      ///      public static string GetData(string strFileName)     {       using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())       {         if (isoStore.CurrentSize == 0)           return null;          using (IsolatedStorageFileStream isoStream = new IsolatedStorageFileStream(strFileName, FileMode.Open, isoStore))         {           using (StreamReader reader = new StreamReader(isoStream))           {             // Read the first line from the file.             string s = reader.ReadLine();             return s;           }         }       }     }      public static void DeleteFile(string strFileName)     {       using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())       {         if (isoStore.CurrentSize == 0)           return;          isoStore.DeleteFile(strFileName);       }     }   } }

Sunday, October 28, 2007

Releases Silverlight TruckWars v1.1

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/releases_silverlight_truckwars_v11.htm]

Silverlight TruckWars is a real-time strategy game built entirely in Silverlight. I recently releases version 1.1, which as some new features:

  • More creatures:

    • Ambulance that heals

    • Growing forests

    • Moving bricks

    • SignPost to display helpful messages

  • New levels, including tutorials and new graphics

  • Better game management - saves your progress, and an HTML toolbar that lets you jump to previously solved levels, restart the game

  • A help page

These really help round out the game.

You canplay the game online here. Being Silverlight, it essentially runs within a blog post, so feel free to leave comments on that (or any) post.

 

I'll blog more about these in the future. Definitely there are more enhancements I'd like to make. I'd group these into improving the engine, and adding new creatures to better demonstrate that engine. In particular, new features I'd like:

  • Incorporate Farseer Physics Engine for better collision detection

  • Add a game-difficult setting

  • Improve movement algorithms - i.e. a unit should be smart enough to move around a concave polygon.

  • Add a "building" type object that can create new units.

  • Something with railroad tracks - for my son :)
     



Monday, October 22, 2007

Paylocity is hiring for a .Net/C# Programmer (in Chicago)

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/paylocity_is_hiring_for_a_netc_programmer_in_chicago.htm]

Paylocity, a Chicago-based payroll company, is hiring for a .Net / C# Programmer. We have a good team culture, a growing company, and are consistently voted one of the best places to work for. The position is in Internal Development, and takes a hybrid of business and technology skills. This would be an excellent opportunity for a junior or mid-career programmer, as it provides tons of learning potential.

While it isn't my direct department (I'm in software engineering), I constantly hear good things about them.

 

If you're interested, feel free to either apply online, or contact me directly (just include your contact info if you do so that I can reply).

Sunday, October 21, 2007

Silverlight: Read xml file in FireFox (solve "Data at the root level is invalid")

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/silverlight_read_xml_file_in_firefox_solve_data_at_the_ro.htm]

Any app eventually needs to read data; and it's very likely that for Silverlight, that data will be XML files on your web server. For example, in the real-time strategy TruckWars game, each level is stored as an XML file (named 1.xml, 2.xml, etc...). The Silverlightquickstart tutorials describe how to load an Xml file into an XmlReader (there is no XmLDocument for silverlight yet). While this works great in IE, it actually has a problem in FireFox. FF tries to read the xml file, but it starts with three extra bits used for reading the encoding type. These three extra bits screw up the XmlReader, and you get the error:

 

"Data at the root level is invalid. Line 1, position 1."

 

This has something to do with theunicode.GetPreamble().

 

Practically, there's probably some way to overload the reader class, or set something on the Xml file. But I couldn't figure that out. I tried several things:

  1. Use reader.ReadToFollowing("myNode"); But those first few bytes prevent me from reading anything.

  2. I tried removing , but no luck

  3. Based on anMSDN forum, I tried removing this first line:

  4. In the StreamReader class, I set the detectEncodingFromByteOrderMarks constructor property (trying both true and false), but no luck.

  5. I tried modifying the Xml Reader to directly get from URI. However, I got the error: "Support for http:// URIs is not yet implemented."

  6. I tried overloading the XmlReader with XmlReaderSettings (and setting IgnoreProcessingInstructions )

  7. I tried reading the first three bytes of stream to "skim off" the problem characters, but it still had the same problem

So, none of those attempts worked. Eventually, I got a work-around. I would read the entire xml file into a string, and then skip the first problem characters until I go to the "

    public static XmlReader CreateXmlReader(string strRelativePath)    {      HttpWebResponse response = null;      StreamReader sr = null;      try      {        //first create standard stream:        Uri u = new Uri(strRelativePath, UriKind.Relative);        HttpWebRequest request = new BrowserHttpWebRequest(u);        response = request.GetResponse();        Stream content = response.GetResponseStream();        sr = new StreamReader(content);        string s2 = sr.ReadToEnd();        //Skim off unicode.GetPreamble()        //In firefox, this would be first three bytes for UTF8        int intIndex = s2.IndexOf(");        s2 = s2.Substring(intIndex);        StringReader sr2 = new StringReader(s2);        return XmlReader.Create(sr2);      }      catch (Exception ex)      {        throw;  //Wrap in try catch for now. Will add better error-handling later.      }    }

This solved my problem, worked in both FireFox and IE, an performed well enough for my needs.

Wednesday, October 17, 2007

Silverlight - Truck Wars Strategy Game v2.0

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/silverlight__truck_wars_strategy_game.htm]

Release 2.0 - Migrated to SL2

Microsoft has officially released Silverlight 2.0, and there are more breaking changes. I haven't updated TruckWars yet (it's gone through Alpha 1.1, Beta 1, Beta 2... running out of gas). Here's a screen shot of what it looked like. I hope to migrate sometime in the future, perhaps even adding dynamic scripting for the objects.

 

truckwars_screenshot_1_2.jpeg


Release 2.0 - Migrated to SL2 Beta 2

I started working on TruckWars as a way to learn Silverlight back in the Alpha last year. There have since been two more betas (with plenty ofbreaking changes), but I've finally migrated it.

 

Things of note - Beta 1 started supporting buttons, which obviously simplified things. For example, it helped me remove keyboard input. It also had some subtle changes that affected the gameplay. Also, there still is no dropdown. Before I was using an HTML dropdown to select the levels. Rather than jump through hoops, I just ceded the dropdown part until the next release.

 

Because the code has been migrated from an alpha, to a beta, to another beta, it's becoming pretty screwy. Not the best, most agile code out there, but good for a demo of what cool stuff Silverlight can do.


NOTE: You need to view this page in a browser in order to see the game; it doesn't show up in most RSS feeders.

 

Release 1.3: Now Open-Sourced

TruckWars is a simple SilverLight real-time-strategy game. You control the green units. You select a unit by left-clicking it. You move a unit by drag and drop. You attack an enemy unit by moving your unit into the enemy unit's space. The goal is to push all the green buttons down.TruckWars is now open-sourced at CodePlex. It's also on the Silverlight Gallery.

Release 1.1

This is a simple SilverLight real-time-strategy game. You control the green units. You select a unit by left-clicking it. You move a unit by drag and drop. You attack an enemy unit by moving your unit into the enemy unit's space. The goal is to push the numbered crates onto the pink "Victory" tiles, and then hit the green semi-circle button. You can see more info on the release notes.

Release 1.0

I converted the XNA game to Silverlight. This is a simple SilverLight real-time-strategy game. You control the green units. You select a unit by left-clicking it. You move a unit by drag and drop. You attack an enemy unit by moving your unit into the enemy unit's space. (SilverLight only allows a left click). Currently only the tanks can attack. The ambulance and pickup truck don't do anything yet. The goal is to push the numbered crates onto the pink "Victory" tiles, and then hit the green semi-circle button. Select the game (to activate it), and then click "spacebar" to start. Obviously this is just a simple test of SilverLight, and I'm open to suggestions. I'm going to explain the code in the next several posts. I was inspired by my son's love of trucks to use the truck theme. I was definitely helped by Bill Reiss's good Silverlight Tutorials.

Tuesday, October 16, 2007

XNA Real-Time-Strategy Game (with source code)

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/xna_realtimestrategy_game_with_source_code.htm]

I mentioned in my last post about XNA that I've created a sample game, complete with full source code.

 

 

You control the green tank by using the mouse. Left moves, right fires. The goal is to push the numbered crates onto the pink "Victory" tiles, and then hit the green semi-circle button. This demonstrates several things:

  • Collisions - this uses a simply polygon collision detection. It also handles heights - a fireball hovers, so it can pass over the water, but the tanks cannot.

  • User input - collecting mouse input (position, left, right buttons)

  • Animation - the water animates

  • Multiple creatures of different sizes. The green bushes (the square things) increase in size as your tank gets closer.

  • Interacting objects - you can push crates, fire at other units, hit the push button, and collect a powerup to increase your firing rate.

  • Messages

  • Opacity

  • A dashboard section on the button for user information

  • The ability to pause the game - which freezes everything (including the game clock).

Note that all the graphics were made with MSPaint.

 

The code is pretty sloppy, as it was just a toy project and my main point was to explore XNA. There's a ton that could be improved about it.

 

Obviously it's just a cute sample. Especially as XNA can handle scrolling, 3D games, and a lot more, this only skims the surface.

 

One point of note is unit-testing. There is a lot of complex code (movement algorithms, models, collisions, interactions, etc...) that should ideally be tested. However Visual C# express doesn't support unit-testing. So, I made the core DLL be referenced in another solution, which can then test it.

 

Next up: re-writing this in Silverlight. I'll go into more of the details there.