Sunday, November 18, 2007

Releases Silverlight TruckWars v1.3 - OpenSourced on CodePlex

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

Silverlight TruckWars is a real-time strategy game built entirely in Silverlight. I recently releases version 1.3. The biggest thing is that I've now open-sourced it on CodePlex.

 

Check it out:

I've also added several enhancements

  • Added hold-able objects, like a key

  • Gameplay enhancmeents.

    • The biggest one is that selecting any creature now provides help text.

    • Destroying an enemy unit now can optionally provide a "treasure", like a powerup or key.

  • Lots more powerups:

    • Bounce - projectile bounces off walls

    • Thrust - doubles your thrust

    • Clone - clones the creature that got the powerup

    • Health - plus 50 health points

  • New creatures & levels

    • LandMine

    • Giant Tank

Thursday, November 8, 2007

Don't let me hurt myself

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

In the real world - apart from computers - it was always understood that you could do dumb things to hurt yourself. Therefore a level of discipline was always required. You could hold a sharp knife wrong and cut yourself. You could say something dumb to a friend and ruin the relationship. A sufficiently out-of-luck person could basically mess up anything they came in contact with.

 

What I find ironic is that with software, there seems more and more a demand to reverse all that - to almost make it impossible for a user to hurt themselves:

  • Through intuitive UI and instant validation, software hinders you from doing something wrong. It won't let you type bad input, it prompts you with warnings if your intent is unclear ("Do you really want to delete this account?"), and it lets you undo your action ("Please restore that account I just deleted"). Unlike a knife, good software won't let you get cut, no matter how incorrectly you hold it.

  • Every other product seems to have a long list of disclaimers on how not to use that product. "Don't do X, or you could get hurt, and our company is not responsible."

  • If you send a bad communication that blows something up, good software lets you undo it, edit it, or roll it back.

  • Even when building software, because you can instantly back up all your work (with source control), any mistake can be reverted. Imagine baking a cake and accidentally putting in one too many eggs - you can't just "undo" it.

While it's great that software keeps improving, I find this un-paralleled expectation very interesting.

 

Wednesday, November 7, 2007

Releases Silverlight TruckWars v1.2 - uses Farseer Physics Engine

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

Silverlight TruckWars is a real-time strategy game built entirely in Silverlight. I recently releases version 1.2, with the big feature being that it uses the Farseer Physics engine. I also simplified the game play, and added some new creatures. I'm trying to move the game from "technical gimmick" to "fun".

 

Ultimately I'll try to open-source it so others could create their own creatures and levels.

 

Check it out:

 

About the game play - I had feedback that the previous physics engine (some scrappy code I had whipped up) just wasn't powerful enough to do what I wanted. I want the game to be about interacting systems - like trucks colliding with each other, growing objects (that change their size), pushing around crates, bouncing bricks that can crush a unit if they overlap, etc... All of this requires a powerful physics engine, which is why I took the effort to migrate to Farseer.

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);       }     }   } }