Building a Solar System in XNA (Part 2)

by Chris at 10:42 am

As promised, here’s the second part in my effort to make a solar system in XNA. It’s not really as good as I’d have liked it, but it’s functionable, and it has some nifty things going on. As usual, I’ve provided a copy of the Code, and Binaries so that you can play with things yourself.

The first thing that I worked on was making a scene graph. This is a nifty class / algorithm that allows you to specify a hierarchical relationship between the objects within your scene. You can build the scene from diffent scene nodes, and depending on the order they appear in the scene graph, objects can be shown, or moved around.

In this example, I’ve written several different node types (some of which can be reused in other projects).

  • SceneGraphBase - This is the base node that all the other scene nodes implement. The class implements a list of SceneGraphBase nodes, so it basically becomes a big tree (similar to the image to the left). It contains code in it’s Update() and Draw() routines that all of it’s child node’s Update & Draw routines.
  • TransformNode - Multiplies it’s own Transform matrix against the world matrix prior to calling any child methods. This allows you to perform a Translation or Rotation (or pretty much any other matrix operation you can think of) to all subsequent nodes.
  • Camera - A flexible camera class that can walk, strafe, fly, pitch, yaw, and roll.. and (importantly) can be used to generate a View Matrix at the current camera location. This is one of my old pieces of code from another project, that’s been adapted many times. It would probably be better to implement the movement functions within the TransformNode if you were starting from scratch.
  • ModelNode - Draws a model at the current world location
  • PlanetNode - Draws a planet at the current world location. Note this could easily be replaced by a prettier ModelNode, but I wanted to write a routine that could generate a sphere.
  • Starfield - You may recognise the starfield from the origonal code, I modified it so that it implemented the SceneGraphBase class, and thus could be included as a scene node.

Building the HUD

So, once I got the scene graph working, I realised that the distances between the planets was HUGE. I could pretty much only find the Sun (which I put in as a planet, but should have some extra cool glowing effects), anc could only find that because I was parked right next to it, and it was so large. So the next thing that I worked on was heads up display (HUD) that could show me 1) how fast I was going, and 2) how to get to each of the planets.

After a bit of searching around for how to write text onto the screen, I found out about the SpriteFont content item. You can add a SpriteFont into your content folder by right clicking on the content folder, then choosing “Add -> New Item”, and selecting the SpriteFont item from the list. Once you have done this, it will add an XML file with the extension “.spritefont” to your content folder. Fill out this file with the font details, and the font will be imported into the project for use later on. You can then load the font during your LoadContent() routine (or whenever you like) by using the single line of code below.

   m_Font = m_Game.Content.Load<SpriteFont>(”SpriteFont”);

Then when you want to use the font to draw a string, you can use this line of code

   SpriteBatch.DrawString(m_Font, “Look at me, I’m a string”, new Vector2(0.0f, 0.0f), Color.Gold);

It’s probably worth mentioning that you probably still shouldn’t use the standard Microsoft fonts in a distributed game, as this would breach copyrights. Many fonts are not free to use, including those provided with Windows. Fortunately, most windows installations do come with a little known font editor. You can get to it in C:\Windows\System32\EUCEDIT.EXE. I’ve not tried to import fonts that have been written using this, but I would imagine that it’s possible.

Reaching the other planets became a huge problem, but fortunately, due to playing games like EVE I knew that building a snazzy HUD tracking system would do the trick. So, I just went ahead and whacked one in there (heh.. yeah right, it was that easy :D). After A L O T of trial and error (about 20-30 hours worth), I managed to re-invent the wheel, and come up with a genuine, planet tracking, boot-skootin HUD. Strangely (as all good solutions are), it was much simpler to do than I thought it would be, so naturally, I tried all the harder things first.

After about 20 hours worth of trial and error of more and more complicated techniques, I was amost completely exhausted and thought about throwing in the towel and cancelling the blog entry :).

Finally, I was ready to use my brain.. after a nice coffee, and some tv, and some sleep.. I got back to it and started by thinking “I wonder if there is any maths that will give me the screen relative position of an object”.. followed quickly by a forehead-slap moment (I have a lot of them). The VIEW and PROJECTION matrices do exactly that for all of the damed triangles that you look at in a 3d scene.

I simply took vector to the object (planet, or whatever), and transformed it with the view, then projection matrices. Suddenly my little tracking circles were working like they knew where things were. One last thing that I did with them, was to Normalize the object’s vector, prior to passing it through the matrices. After doing this, I was able to figure out where the object was using a 180? field of view, and hide everything that was behind the ship.

Finaly some minor tinkering

After spending all my time (and then some) on the HUD, I went to find the furthest reaches of our solar system. I noticed that after a while, the ship started breaking apart. It looked as though the triangles started to get distorted, and that things started shaking. So, naturally, I went into discovery mode to try and figure out what was happening.. It turns out that positioning system I was using was having a bit of Goldilocks syndrome. Floats are just too small to accuately handle points at 4,553,759,184 km (30.44 AU), and similarly, small objects in a ragnge of 0 AU to 30 AU were too small to be handled correctly. So, I translated everything to light-seconds… and they were just right… 1 light second ~ 299,792.458 km ~ 1/499 AU

Leaving the cleaning up for later

Being a lazy, lazy person, I like to leave the cleaning up for later.. or in other words.. never. There are a couple of fun bugs that you will no-doubt find with my code, and a few things that really should (but wont) be cleaned up before any real people look at it..

A couple of hilites you might want to see are:

  • Flying into the sun or a planet always produces hilarious exploding results… I just let you fly strait on in and have a look around under the planet’s skin.
  • It would appear that you can fit a whole planet between the ship and the camera (perspective ftw).
  • The space ship you are flying in is a stolen vehcle.
  • Planets look like ugly green blobs