Archive for the 'WSUXNA' Category

WSUXNA Engine Code

Saturday, June 9th, 2007

It’s about time I release the engine I created last fall in XNA. This engine is purely academic, and should be treated as such (i.e. don’t go trying to make your own games with it unless you want to retouch most of the engine). However, it’s fully commented, and I believe the code is both an excellent example of something I’ve done in the past, and of how to tackle a ton of different common game programming tasks.

This engine accomplishes many things - input management, 3D-rendering of 2D sprites, animation, text rendering (it was made before the refresh release), Quadtree, Separating Axis Theorem (oh boy!), and of course, object management. It’s not perfect, since I had to code it in a couple weeks so my team could actually do their assignments (see the WSUXNA page for more). However, with as many problems as it tackles, I think the code could be useful to look through for an aspiring game programmer.

Along with the engine code I’ve provided the engine test project I used while developing as a small example of how the engine is used. It’s a bunch of different shapes bouncing around in a box. Each shape also has debug outlines showing the underlying polygon used for collision detection (separating axis theorem allows for any convex polygon to be used!). The bouncing is just based on object centers and current velocities - so it’ll look a little odd. You can switch between objects with up/down (on dpad or keyboard) and rotate them with left/right (dpad or keyboard, again).

Get the code

Or just the engine demo

Enjoy!

QuadTree (Source Included)

Sunday, May 6th, 2007

Enjoy this tutorial on Quadtrees, explaining how they work and why they’re useful for collision detection. Includes pictures and source code. Comments are highly appreciated.

A Quadtree’s Purpouse

Your collision detection solution should operate at successively more accurate levels to be effective. Since each successive level is more accurate, deeper levels require more processing time. Therefore, the rule at each level is to perform as few collision detections as possible. We do this by eliminating unnecessary checks at higher levels. Let me explain with an example.

Imagine a game like Pong, except with a rotating triangular ball. This ball needs to have perfect collision detection with the paddles, which means if any part of the triangle intersects with the paddle, there is a collision. You can’t just do simple radial collision detection, nor can you do rectangle collision detection, because the triangle might not actually be colliding for some collisions detected in those cases. However, performing the triangle-to-paddle collision detection can be expensive to do every frame (I know, not that expensive – but imagine 200 balls with 30 players around a big field with balls also colliding with each other, or something like that). So what are you to do?

The solution is to do several levels of collision detection. First, you’re going to check if the ball is even on the paddle’s side of the line. If it’s not, then obviously it doesn’t need to be checked for a collision. Then, if it is on the paddle’s side, you’ll check if the ball is in the same vertical half of the screen as the paddle. Again, if it’s not, you’re done. You might do this a couple more times, and if you could still be colliding, that’s when you actually perform the expensive detection. With just the two checks, you’ve just reduced 75% of the expensive collision detections to a simple positional check (e.g. Position.X < ScreenMiddle.X).

How a Quadtree Divides Space

The Quadtree is your first line of defense in the two-dimensional collision detection battle. It lets you know with pretty decent accuracy which objects could be colliding. It does this with rectangular bounds checks, which are simple to perform. Once you’ve found out which objects could be colliding, you can then pass those on to a more complex algorithm, like the Separating Axis Theorem, or a pixel-based collision detection algorithm.

A Quadtree works by dividing space into rectangles as objects enter that space. It does this by following a simple rule, which is:

For any node in the Quadtree, the node will be divided further if more than n objects are contained within the node at any time.

With n being a pretty low number, like 1 or 2. When a node divides, it divides into four different rectangles by splitting the node in half horizontally and vertically. Any objects that can fit entirely within one of these new nodes are pushed down (with objects that are on node edges remaining in the higher-level node). These pictures should explain the process.

Object at level 2 of the tree.

One object in a Quadtree. The object is at level 2 of the tree (with level 1 being the entire box).

Note: Duncan points out in the comments that this image couldn’t exist unless there had previously been two objects in the Quadtree (since the level 1 box would never have been partitioned). The image is like this to demonstrate an object moving across nodes - which you’ll see in the next image. Look in the comments for further discussion.

Object at level 1 of the tree.

Now the object is at level 1, because it can’t fit entirely within a lower-level node.

Two objects in a Quadtree.

Two objects in a QuadTree. Note that they are in different nodes, so the space doesn’t need to be divided further.

Three objects in a Quadtree.

Now three objects are in the QuadTree. Two objects were in the level 2 node at the top-left, so the node had to be split (since this is a tree with a maximum of one object per node). The objects fit entirely within the new level 3 nodes now.

Nodes created by an object moving in a Quadtree.

This image shows the nodes created by an object moving across the space. Notice that as the object passes through the first level 3 node, it divides the space again. Then, as it passes through a level 2 node, it has to divide it twice to be able to satisfy the “only one object per node” rule. Also notice that the object actually passes through every level of Quadtree node in this image – try to figure out how.

So How Does This Help Me?

Well, when it comes time to figure out if some object is colliding with anything else, you’ll want to check the Quadtree to see what items it might be colliding with, so you can then perform a more complicated collision detection check later. You do this by querying the Quadtree with a query box. The Quadtree will then figure out which nodes contain any part of the box, and return a collection of all items within those nodes. So for a query box like this:

A query rectangle.

The following would happen:

The steps in querying a Quadtree with a query rectangle.

  1. The box collides with the level 1 node – but there are no objects in level 1.
  2. The box collides with two level 2 nodes – but there are no objects in them either. However, their child nodes need to be checked now.
  3. The box collides with four level 3 nodes, and there is one object in them, which is added to the return list. Note that there are no level 3 nodes in the top-right level 2 node, so it is not queried any further.
  4. Finally, the box is colliding with six level 4 nodes, one of which contains another object. Note that the object we just returned was on an edge, so it was contained within the level 3 node instead of a level 4 node.

So, for this query, two objects would be returned. In this example, all of the returned objects are colliding with the box. However, if there was an object on the middle line on the left (at level 1), it would also be returned, though it clearly does not collide. However, in a world with hundreds of objects, this would be acceptable (as long as everything wasn’t on the line).

The Moral

If you query the tree with all n objects in the tree, with each query returning log n results, you have reduced the number of expensive collision detections from n-squared (checking every object against every other object) to n log n (the average number of objects returned from this sort of tree query). Sound like big-O notation?

Some Code?! Oh boy!

I updated the QuadTree used in my WSUXNA engine to work with the newest version of XNA, to be generic, and to be a little more efficient than its previous incarnation. It comes in two files – one containing the QuadTree and all related classes, and one containing a floating-point rectangle class, which I needed for this implementation. I’ve tried to comment it as fully as possible, so hopefully you shouldn’t have any problems reading through it - if you do, please, ask questions!

In my Quadtree, I’ve made the query methods take a List by reference, to cut down on the garbage generated by throwing new Lists around every frame. I also perform a simple box collision detection method on every object that might be returned, to reduce the edge-crossing objects problem.

There are three classes in the QuadTree file, two of which you will use. I’ll explain the useful ones:

  • QuadTree – The Quadtree. Create a Quadtree with the generic type being the type of object you want to place in the Quadtree. You’ll need to specify your initial world size, which can be at whatever scale you’d like.
  • QuadTreePositionItem – A long name for a position class. You’ll need to instantiate and store these in your objects and then add then to the QuadTree by using the QuadTree.Insert method. You can also just store the position item returned by the QuadTree.Insert overload method. To move an object in the QuadTree, just update the Position property in the position item class. The position item also contains a link to its Parent, which is the object that it’s being used by (yah yah, I can see you OO people cringing…but it’s easy to use and understand this way, and isn’t really that horrid). Finally, remember to Delete() the position item when you’re done with it and set your references to it to null – that’ll remove it from the Quadtree and make sure it gets picked up by the garbage collector.

Now, if you need to get a list of items that might be colliding with some item, just query the QuadTree class by using its GetItem methods.

Enjoy!

Get the source code!

Note: I may update this code later…I’ve tested it a bit, but I haven’t subjected it to really rigorous testing since I removed it from the engine, so it might have a couple bugs. There’s also a few things I’d like to do, like make the node class internal, and possibly extend the QuadTree to return a list of parents when you query it. Go ahead and explore that yourself though ;) Also, comments are highly appreciated, as I’d like this article to be as helpful as possible to everyone who runs across it.

Read the followup article

WSUXNA Part 1 - A Common Design

Monday, April 23rd, 2007

Last Fall I took a game design class at my University. Far from design, the class mainly consisted of game programming, with some lectures on design. As part of the class, we were required to program several games, the last game being a large group project. The professor supplied us with two separate engines to use for our games - one using C++ and the other Java. We decided to roll our own.

Thus began work on the WSUXNA engine - a simple 2D game engine built using Microsoft’s XNA Game Studio Express Beta 1 (which was released in the middle of our first project) - and later XNA Beta 2. I did most of the engine coding for the Beta 1 engine (a three-day effort), and recoded the whole thing for Beta 2. It was a huge amount of code (thousands of lines), and by the end of Beta 2, a fully-commented and working engine.

Building on Common Ground

The Subject-Observer design pattern.

You may recognize this pattern, though not in this format. This is the subject-observer design pattern from the Gang of Four. It’s also pretty much a simplified version of the Event model in the .NET framework. This is one of the basic components of the WSUXNA engine - it allows the engine to maintain a hierarchical architecture (nothing can directly touch anything above it in the architecture).

The purpose of this design pattern is to let components that are lower in the hierarchy notify components above themselves about some event, such as the death of a component (so it can be removed from a collection), or perhaps that a component has moved by the movement manager (and its visual position should be updated as well). When a component is created by a manager (more on those later), the component inherits the Subject class and the Manager implements the IObserver interface. You can see what these contain above.

When a subject is created, the manager will register events with the component through the AttachNotifier method. This will register a delegate (pointing to the manager’s implementation of the Notify method) with the subject, to be called when an event (e.g. “die”) is raised. The subject places this delegate in a dictionary that contains a list of delegates to call whenever a certain event is raised (e.g. “die”, again). Later, the manager can detach the notifier if it wishes by using the DetachNotifier method of the subject.

So, for example, the entity manager might be called upon to create a brick in a Breakout game. The entity manager will need to know when the brick has been destroyed, so it can be removed from the entity manager’s list of items needing updating. The game manager will also need to know when the brick has been destroyed so it can add points to the game state. Both will register a “die” notifier with the brick so that when it is destroyed (i.e. when it “die”s), it will notify them both before removing itself.

Like I said, this is basically a simple implementation of the Event handling capabilities of the .NET framework. If you chose to use something like this in your own designs, I’d suggest exploring the Event handling already present in C#. At the time, I overlooked Events - but by doing so I gained better understanding of them and was able to have more control over how my engine worked.

Next: The rest of the basics - Managers and Components.

Note: Do you like the class diagram above? It was created by importing my code into Visual Studio 2005 Professional and creating a class diagram from the code. They’re a really awesome way to design code, and I’d like to see them included in XNA Game Studio Express. Shall we campaign for them?

Almost at 0.2!

Friday, November 3rd, 2006

It’s been a while since my last post - October was ridiculously full of midterms, assignments, etc. I haven’t just been sitting around though, I’ve pretty much made it to version 0.2 of the engine! Here’s what I’ve done:

The entire input namespace has been updated to version 0.2 (minus a mouse component), and I’ve almost finished removing the 0.1 artifacts. The new input manager supports WasPressed along with IsPressed, and brings the ability to set up named key mappings. For example, you can now just check if IsPressed(”Attack”), without having to worry about what button attack is mapped to.

I’ve also been working on cleaning up some of our vector problems. Namely, when changing the velocity of a movement component, you couldn’t just say Movement.Velocity.X = 5; - that would produce a compile error, since you are using the get accessor for the Velocity vector instead of accessing it directly. I solved this by creating a Vector2 handle which allows you to access and change X and Y as if it were a variable. Unfortunately, since C# doesn’t have operator=, you can’t directly set the handle equal to a vector. Oh well…

I’ve also added text! We a text component in version 0.1, but the engine didn’t really have the kind of support we needed for text at that time, so it was very slow at changing text. Now the engine is very capable of displaying text. It loads a font from an xml file creating using BMFontGen.  Then, changing the Text string on the component will update the shape coordinates list in a visual component, mapping letters to shape coordinates.  These can be manipulated in exactly the same way as other visual components, allowing scaling, rotation, etc.

The engine is coming along nicely.  It’s time to update it for the XNA Framework Beta 2, along with adding sound, and then it’ll be ready for a 0.3 release.

Moving in the right direction

Friday, September 22nd, 2006

I made a ton of progress in the last week. Along with the Visual Engine mentioned in my last post, I finished the Movement Engine. Considering those were my major goals this week, along with cleaning up the last bits of the engine (which I’m doing tonight/tomorrow), I’d say I’ve made great progress.

I made a major push in the last few days and completely recoded the movement engine. I implemented (then reimplemented, then optimized) a QuadTree and implemented the Separating Axis Theorem for arbitrary convex polygons (defined by a list of vertices). It was a beast to get all of the vectors pointing in the right directions at the right times. It was even worse trying to hunt down errors. I ended up recoding a lot just to fix some problems (and made things more efficient in the process).

For example, at one point everything was bouncing as if I were using simple axis-aligned bounding boxes. I wasn’t, so it was kind of confusing. After hunting around the collision detection code for a while (tons of breakpoints >.<) I still couldn’t find it. I took a bit of a break and came back to it later, where I found out that some of the optimizations I had performed ended up biting me.

When I check for collisions, I only check objects that have moved. I take that list of objects and query the Quadtree. I’ve slightly optimized the Quadtree query so it’ll only return objects where the object’s bounding box intersects (or is contained within) the query rectangle. To make a long story short, my collision detection was always returning true, but the Quadtree query was working fine - so it looked like bounding box collisions. To make a long story short, I fixed it and it works great! Off to entity management!

Moving to 3D rendering

Friday, September 15th, 2006

I’m part of a University team working with XNA and building a 2D engine around it to support projects in a course. It’s been a lot of work, but it’s also been pretty interesting. XNA is pretty much Managed DirectX redesigned for C#. This includes garbage collection, automatic references and all of the rest of the features of C#. Along with the language move, XNA removes a ton of the annoyances of working with Manged DirectX. Having worked a little bit with MDX in the last couple of years, I definitely am liking XNA.

Over the last week I’ve been considering moving to 3D-based rendering (along with many other engine cleanup tasks). The easy method of 2D rendering in XNA is to use a SpriteBatch. Once you’ve loaded your texture (which is a single line of code), the code to render it looks like this:

spriteBatch.Begin(SpriteBlendMode.AlphaBlend);
spriteBatch.Draw(myTexture, new Rectangle(spriteX, spriteY, 50, 50), Color.White);
spriteBatch.End();

You basically tell it what texture to render and where (even specifying tint), and it draws it. This is great, and you could probably make tons of 2D games using it. However, having dipped my feet in the world of 3D a couple semesters ago (CptS 442), I’ve seen the power of transformations, and wished to harness it for my engine. As it turns out, linear algebra was actually one of the most useful math courses here. It took a lot of work, but I’m now convinced that moving to 3D was a great idea.

Behind the interface of a visual component (how our visual information is stored) is a set of vertices with corresponding texture coordinates, a scale transformation and a translation. When the visual manager goes to draw everything for the frame, it sorts visual components by texture, then loads the first texture into memory. It places each object by multiplying the matrices together:

DrawTransformation = Scale * Translation * View * Projection;

Best of all, since every visual component using the same texture is drawn in a batch, there are only as many draw calls to the gpu as there are textures! Depth is even handled by the depth-buffer (I’ve specified a depth value for visual components that roughly cooresponds to a Z-value).

Now, if I want to add a rotation to an object, or perhaps even add a world translation (similar to camera position - useful for side-scrollers), all I have to do is add another tranformation matrix to the positioning call. Sure, I could have just used the SpriteBatch and done most of this that way, but using 3D allows me to use lighting and other 3D-effects if I want to in the future.

Finally, the way I’ve set up my View and Project matrices, world coordinates translate almost directly to screen coordinates (i.e. pixels). By default, placing an object at (20,20) will place it 20 pixels from the left and top of the drawing window. This makes it extremely easy when programming a game to make sure things are placed correctly.

I’m not sure if the other engines do this or allow it, but I think it’s much better than just blitting to the screen, and you should at least consider looking into transformations on your points if you plan to make anything other than a static-screen game.