Yet Another Guardian Progress Video

July 19, 2009 by Dave · Leave a Comment
Filed under: Game Programming, XNA 

Things are coming along nicely with Guardian. The Dream Build Play entry deadline is fast approaching, but I think I’m in pretty good shape to get my entry completed. The video shows most of the functionality. Pretty much all that’s left now is fleshing out some of the graphics, and adding a few more weapons. Then I can start getting some sleep.

XNA Game Project

June 24, 2009 by Dave · Leave a Comment
Filed under: Game Programming, XNA 

Here’s a video of the XNA game I’ve been working on. It’s a port of the iPhone version with some additional functionality planned.

Simplified XNA Message Boxes

June 11, 2009 by Dave · Leave a Comment
Filed under: C#, Game Programming, XNA 

Shawn Hargreaves brings up the subject of how annoying async coding can be.  Calling a “begin” method, dealing with the completion callback function, handling the results – it’s all very ugly to keep track of, and often leads to very ugly code.

He wants to be able to write code like this (and so do I)…

 

 int? button = Guide.ShowMessageBox("Save Game",
                                       "Do you want to save your progress?",
                                       new string[] { "OK", "Cancel" },
                                       0, MessageBoxIcon.None);

    if (button == 0)
    {
        StorageDevice storageDevice = Guide.ShowStorageDeviceSelector();

        if (storageDevice != null)
        {
            using (StorageContainer storageContainer = storageDevice.OpenContainer("foo"))
            {
                ...
            }
        }
    }

 

 

It turns out that making async code work almost like this isn’t too bad to do. It basically involves creating a static class to encapsulate all of the various things you need to keep track of. Here is the fairly well commented code for the static class.

class SimpleMessageBox
  {
    private static int? dialogResult = null;
    public static bool Showing { get; set; }

    public static int? ShowMessageBox(string title, string text, IEnumerable  buttons, int focusButton, MessageBoxIcon icon)
    {
      // don't do anything if the guide is visible - one issue this handles is showing dialogs in quick
      // succession, we have to wait for the guide to go away before the next dialog can display
      if (Guide.IsVisible) return null;

      // if we have a result then we're all done and we want to return it
      if (dialogResult != null)
      {
        // preserve the result
        int? saveResult = dialogResult;

        // reset everything for the next message box
        dialogResult = null;
        Showing = false;

        // return the result
        return saveResult;
      }

      // return nothing if the message box is still being displayed
      if (Showing) return null;

      // otherwise show it
      Showing = true;
      Guide.BeginShowMessageBox(title, text, buttons, focusButton, icon, MessageBoxEnd, null);
      return null;
    }

    private static void MessageBoxEnd(IAsyncResult result)
    {
      dialogResult = Guide.EndShowMessageBox(result);

      // if no button was pressed then we want the result to be -1
      if (dialogResult == null)
        dialogResult = -1;
    }

 

Using the class involves calling SimpleMessageBox.ShowMessage(…) in your Update() method. You continue to call it each frame until it returns a result. This does require some game state information (i.e. your game state is SaveGameState or something similar) so it takes a little extra work, but you have to keep track of those sorts of states anyway.

Here’s a sample of the usage:

protected override void Update(GameTime gameTime)
    {
      base.Update(gameTime);

      if (saveGame)
      {
        // show the message box - we end up calling this each frame as long as we're in the saveGame state - it will
        // return null until the user presses a button or closes the guide - it returns -1 if the guide
        // is closed, otherwise it returns the button number
        int? button = SimpleMessageBox.ShowMessageBox("Save Game", "Do you want to save your progress?",
                                                      new string[] { "OK", "Cancel", "Repeat" }, 0, MessageBoxIcon.None);

        switch (button)
        {
          case -1:
            message = "No Button";
            saveGame = false;
            break;

          case 0:
            message = "Saved";
            saveGame = false;
            break;

          case 1:
            message = "Cancelled";
            saveGame = false;
            break;

          case 2:
            message = "Repeat";
            break;
        }
      }
    }

 

I haven’t use this code in a real project yet (just the sample), but it seems like it would work in quite a few situations. It’s a bit different than doing a message box in Windows since you have to realize you’re calling the ShowMessageBox method each frame. That aside, you can almost imagine that you’re using a blocking message box function.

Download Sample Project

Lens Flare Occlusion Using Texture Masking and XNA

May 30, 2009 by Dave · Leave a Comment
Filed under: C#, Game Programming, XNA 

I have an article posted on Ziggyware that discusses an alternate method to hardware occlusion queries for checking sun visibility to control lens flare intensity.  The article is part of a contest so I can’t post it here until the contest has been over for awhile.  I can link to it however.

Lens Flare Occlusion Using Texture Masking and XNA

Hope everyone enjoys it.

Sprite Splitting with SpriteBatch

May 5, 2009 by Dave · 3 Comments
Filed under: C#, Game Programming, XNA 

Someone over in the XNA forums asked a question about how to make sprite explosions like those in the old Defender arcade game, where the sprite is broken into pieces and exploded everywhere.

This effect can be done using nothing more than the XNA SpriteBatch class. One of the overloaded Draw() methods allows you to pass a source rectangle. When drawing a sprite you can use the source rectangle to grab just a part of it. So it’s a simple matter to use multiple draw calls on a single sprite to draw little pieces of it, like so:

// draw parts of the sprite
int xInc = 8;
int yInc = 8;
float spacing = 1.5f;

// draw parts of the sprite
for (int x = 0; x < face.Width; x += xInc)
  for (int y = 0; y < face.Height; y += yInc)
  {
    Vector2 position = new Vector2(100 + x * spacing, 150 + y * spacing);
    Rectangle source = new Rectangle(x, y, xInc, yInc);
    spriteBatch.Draw(face, position, source, Color.White);
  }

“Multiple draw calls” sounds bad, but SpriteBatch is able to batch up the draw calls so you shouldn’t notice any real effect on performance.

You can download a sample XNA project to see this in action. The project also includes a SpriteExploder class that will automatically explode your sprite into multiple pieces and throw them about the screen.

screenshot

Download Sample Project

Horizon Culling 3 – Finale

April 2, 2009 by Dave · 1 Comment
Filed under: C#, Game Programming, XNA 

So we finally come to the last post in the horizon culling series.  Previously we’ve discussed what horizon culling is and some reasons for using it.  Then we went through the math involved in determining the angle between a line from the camera to the planet center  and a line from the center to the point on the horizon.

To help me visualize everything up to this point I created a standalone Windows application.  Please feel free to download the app which includes a binary and full C# source code.   You can change the height of the camera to see how the horizon distance and angle change.  

The calculations we discussed in the last post are handled in the Recalculate method.  This method is called everytime the slider is moved.  All of the drawing is performed in the Paintbox_Paint method.  The drawing code is very ugly, but since this was just intended as a simple, one time method of visualizing the math, I didn’t bother spending much time making it pretty.  

So, now that we have this angle, how do we use it?  The basic idea is that as we draw each portion of the planet we calculate the angle between the camera to planet center line and the portion of the planet we’re drawing.  If that angle is larger than the horizon angle then what we’re drawing isn’t visible to the camera so we don’t need to draw it.

In reality it isn’t quite as simple as this because the part of the planet we’re drawing may have mountain where the base is beyond the horizon, but the top would still be visible since it extends above the horizon.  There are multiple ways to handle this.  For my purposes, at least for now, I chose the lazy man’s way and just increase the horizon angle a bit so I draw things beyond the horizon.

I don’t want to go into a lot of detail here, but I need to describe in broad terms how I go about drawing a planet.  Basically, the planet is divided into patches.  When you’re far away from the planet the patches represent a very large part of the surface, and as you move closer the patches closest to you are split into more detailed patches.  So as I draw the planet, patches that are far away have much less detail in them than patches that are close by.  These patches are the lowest granularity for drawing the planet surface.  In other words I can’t draw part of a patch – either the entire patch is drawn, or none of it is. 

So that means the patches are what we’ll be culling against the horizon, and  to do that we have to use the patch position to find out what angle the patch is relative to the camera.  The image below should help clarify what I’m talking about.

horizon_culling_61

The thick green line represents a patch that is visible to the camera.  The thick red line is a patch that is beyond the horizon so it isn’t visible.  When horizon culling these patches we need to determine the angle between the camera (C) and the point on the patch that is nearest the camera (P1 and P2).   When determining P1 and P2 I actually only check the 4 corner points on the patch.

So how do we determine the angle?  The dot product of two unit length vectors gives us the cosine of the angle between them.  We can use this property to easily find the angle between the camera position and the patch position.  For our purposes a point and a vector are in effect the same thing.

First we have to translate each point into planet space.  I’m defining planet space as a coordinate system where the center of the planet is at the coordinate 0, 0, 0.  For the camera it’s camera_position – planet_position.  For P1 you may have to do something different depending how your data is organized.  For mine, the patch itself has a position that’s already in planet space, and each point in the patch is in patch space.  So to get the closest point into planet space it’s the patch_position + closest_point_position.  Again, your mileage may vary, but the ultimate goal is that both points have to be in planet space.

Now, the other thing that’s required for the dot product to work is that each vector has to be unit length – i.e. it must have a length of one.  To do that we have to normalize the vector, which simply involves calculating the length of the vector, then dividing each component (x, y, z) by the length. We’ll be using the built in XNA functionality for normalizing a vector.

Once we have the two vectors in the same space and unit length we can do the dot product operation to give us the cosine of the angle.  To get the angle we use the arccos function as we have before.

So, here are the steps using C#, and the XNA vector class.

      // get camera position and patch position in planet space
      Vector3 C = CameraPosition - PlanetPosition;
      Vector3 P1 = PathPosition + ClosestPatchPoint;

      // normalize each vector
      C.Normalize();
      P1.Normalize();

      // calculate the angle between the two vectors
      double Angle = MathHelper.ToDegrees((float)Math.Acos(Vector3.Dot(C, P1)));

Again, we get both points into planet space, normalize each, then calculate using the arccos of the dot product.  And since my brain still works in degrees, we use an XNA helper function to convert the angle.

Now that we have that angle, we can compare it to the horizon angle.  If this angle is greater than the horizon angle then we can skip drawing the patch. I mentioned earlier that you need to tweak the horizon angle a bit to account for mountains.  I just add 5 degrees  to the calculated angle.  When very far away from the planet (over 1000 miles) I also add another 25 degrees to account for the very very large patch sizes.  I arrived at these values through observation of an Earth-sized planet and they would likely need to be tweaked for different sized planets.  At some point I would want to come up with an algorithm to deal with these things automatically, but they work fine now for my current needs.

There are probably more formal and accurate ways of doing horizon culling to more properly deal with mountains and such, but in practice this way requires very little extra processing and the few extra (but unnecessary) patches we draw from time to time have a fairly negligible impact on performance.

So, I think that does it for this series.  Hopefully I’ve provided a clear enough explanation of this technique that you can use it in your own projects.  If not that, then the math techniques have many applications as well.

Download Sample Project

« Previous PageNext Page »