Thursday, November 1, 2007

Comparing XNA and Silverlight for 2D game development

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

Most developers are interested in writing games, if even just as hobbyists. That's why there's all this buzz around about two (relatively) new technologies - XNA and Silverlight. I wrote a simple real-time strategy on each platform, and I found the differences very educational. There's a lot of overlap. For example, the powerful Farseer Physics Engine is being marketed to both groups. The best blog I've seen so far on this has been MVP Bill Reiss's stuff - he's written good tutorials for game development on both platforms.

 

 XNASilverlight 1.1
SummaryA platform designed explicitly for gamer development. XNA is obviously more powerful, as it's a client download, requires DirectX, and is optimized specifically for games and high-speed (including 3D) rendering.A new plug-in that hosts xaml, letting you write thick-client applications in the browser. Silverlight lets you write many things, of which games are just one.
Why care?Solves rendering and gameLooping such that anyone can now make a simple game.Allows you to write simple games over the web, so you can share with anyone.
Age of technology?Came out about a year agoStill in alpha
RenderingThe Game class has a built-in gameLoop, which fires both an Update and Draw. The Update method updates your models, positions, and logic, whole the Draw method then uses those models to draw images to the screen via the SpriteBatch. If you want to add a new object, simply display its sprite. If you want to remove that object, stop rendering its sprite.

For 2D games, XNA just displays sprites - it's not vector based (as far as I could tell).

You add objects using Xaml, and then the objects stay rendered until you explicitly remove them from the root canvas.

Xaml is vector based, so you can draw shapes as well as sprites.

 

AnimationDeveloper manually handles by updating the position and what images to show in the code.You can use Xaml storyboards for simple animation sequences. You can also set the position, rotate, and clip of a sprite.

SEE: how to make an animating sprite

Transparent ImagesHandled by setting all pixels to magentaHandled by making a transparent png image.
Killer Features
  • Awesome performance
  • 3D games
  • Deploys over the web, on all major browsers, using just FTP (you don't even need ASP.Net on the server)
  • Integrates with Html and Ajax, so you can also use web controls (for example, TruckWars uses an html dropdown to let you select levels, and an html button to both reset levels, and provide a confirm box)
Big Problem

 

Slow performance compared to XNA, but good enough for classic 2D games.
Benefit to learningGood way for a hobbyist to get started.I personally think that the skills needed to make Silverlight games are much more marketable because they can also be applied to enterprise and business development. For example, if you can make Pacman in Silverlight, you can make graphs and input controls that the business world cares about. While XNA can make graphs too, there's a much bigger market for web development than on the XNA platform.
TutorialBill Reiss on XNABill Reiss on Silverlight
TruckWars sampleTruckWars in XNA (you need to download a bunch of stuff)TruckWars in Silverlight (runs right in the browser)

 

Silverlight and XNA are both easy to get started, especially with the active communities evolving around each of them. Even if you're a full-time .Net developer, it's still fun to toy around with these technologies on the side.

 

Personally, I started with XNA, but quickly moved to Silverlight. For me, the deciding factor is that (1) The Silverlight skill set is more applicable to my job (enterprise development), (2) Silverlight is so much easier to deploy, so I can share the results with others.

 

Wednesday, October 31, 2007

Why try if you can't be the best?

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

In a competitive world of information overload, with millions of other developers, there will always be someone better than you. Even if you pick a niche, chances are there will still be someone even more talented than you in that niche. "There's always a bigger fish in the sea". Furthermore, learning any new field always requires hard work and making mistakes. So, a common question is "Why should I try if I can't be the best?" For example, why learn how to build web applications, or computer games, or any programming, when there will always be someone so much better?

 

It's a good question, one that unfortunately intimidates a lot of people from trying in the first place. There are several reasons:

  • You don't need to be the best. You can still get a job, contribute to the field, and have fun.

  • You can learn something just for the enjoyment of learning it. For example, you may enjoy making a Silverlight or XNA game just to have fun - it doesn't have to be the next Super Mario or Age of Empires. Similarly, I go running just for my own enjoyment - even though I make a turtle look fast.

  • The act of trying will improve your character, and still teach you other skills.

  • Often the "best" isn't available (they're already locked up in another job or project), so one's moderate skills are still needed.

  • You can still add value, even if you're not the best. Often star developers want to coordinate other people to help build a project bigger than what any one person can create by themselves.

  • Even if you're not the best, you can still probably help other people more junior than yourself. I.e., you're probably still an expert to someone - even if it's just a young student, intern, or someone changing careers.

  • Everyone has to start someplace. You may even become that super-expert someday.

Someone who constantly passes up the opportunity to learn something new, simply because they can't be the expert at it, is selling themselves short. As a father pointed out in the movie Facing the Giants, in a scene about a soccer kid hesitant to try out for the football team because he may not make the cuts, "You aren't on the team right now. You can't be any less on the team than you are right now." Likewise in development, if you don't know a technology and you're hesitant to learn because you're not an expert, you can't be any less of an expert than you are right now. You might as well take a stab at something you enjoy, have fun along the way, and become good enough to do what you want to do. I'll never be Michael Jordan, but it's still fun to shoot a few hoops.

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.