Codetopia

A place to talk about things related to XNA, .NET, and enterprise application development.
Welcome to Codetopia Sign in | Join | Help
Home My Book Blogs Forums Photos Files Roller

CH28 - Pixel-Perfect 2D Collisions

File Details
Downloads: 498 File Size: 24.7kB
Posted By: groundh0g Views: 640
Date Added: Fri, Jan 18 2008

This ZIP archive contains source code from the book, XNA Game Studio Express: Developing Games for Windows and the Xbox 360, by Joseph Hall. The following paragraphs describe the changes that have been made to the code since it was first released with the book.

Housekeeping

To make the structure of this chapter's source code more consistent with the other examples, I split the logic into a game (EXE) which references a reusable library (DLL). This change required several minor tweaks to the source code. Those changes are detailed in the following paragraphs.

The Game1.Texture member variable (a reference to the one and only texture for the game) was declared as static and instances of the GameSprite class redirected queries for its texture to Game1.Texture. Since the GameSprite class is no longer in the same assembly (or the same namespace) as the game, I replaced the static reference to Game1.Texture with a per-instance reference and updated the Game1.ResetSprites logic to assign the texture reference to every instance of GameSprite.

In the original version, we didn't need to worry about texture reloads (for example, when the game is dragged from one monitor to another) since all game objects were refering to the same, static texture reference (Game1.Texture). Now that the texture reference is shared among many instances, we need to make sure that each instance is notified whenever the texture reference changes. That logic is contained within the Game1.ResetSprites method.

Another issue that I noticed while converting this code is that the Game1.ResetSprites method was replacing the existing GameSprite instances with new instances on every call. This example is simple enough that the added overhead isn't that great, but it does create extra work for the garbage collector and I think it's bad to have such wasteful logic in an example that's supposed to teach people how to write games. The converted version only creates new GameSprite instances when the existing references are null. Those instances are null when the game starts up, and the Game1.LoadContent sets the instances to null whenever the game's texture is reloaded, triggering an update to the GameSprite.Texture reference.

The call to PixelPerfectHelper.GetOpaqueData really only needs to be called when the game first starts up (assuming that the texture XNB file doesn't change while the game is running), but I didn't want to make the logic any more complicated than necessary. The new Game1.LoadContent and Game1.ResetSprites logic follows.

    // (re)load game content
    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which
        // can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);

        // (re)load game texture
        m_texture = Content
            .Load<Texture2D>(@"media\game");

        // reset game sprites so that they know
        // to grab the updated texture
        Array.Clear(
            m_sprites, 0, m_sprites.Length - 1);
        m_playerSprite = null;

        // reset our obstacle course
        ResetSprites();
    }

    // reset our obstacle course
    protected void ResetSprites()
    {
        Random rand = new Random();
        for (int i = 0; i < NUM_OBSTACLES; i++)
        {
            if (m_sprites[ i ] == null)
            {
                m_sprites[ i ] = new GameSprite();
                m_sprites[ i ].TextureData =
                    this.Texture;
                m_sprites[ i ].OpaqueData =
                    PixelPerfectHelper
                    .GetOpaqueData(m_sprites[ i ], 128);
            }
            m_sprites[ i ].Location = new Vector2(
                rand.Next(SCREEN_WIDTH),
                rand.Next(SCREEN_HEIGHT));
            m_sprites[ i ].Location = new Vector2(
                rand.Next(SCREEN_WIDTH),
                rand.Next(SCREEN_HEIGHT));
        }

        if (m_playerSprite == null)
        {
            m_playerSprite = new GameSprite();
            m_playerSprite.TextureData = this.Texture;
            m_playerSprite.OpaqueData =
                PixelPerfectHelper
                .GetOpaqueData(m_playerSprite, 128);
        }
        m_playerSprite.Location = Vector2.One * 100.0f;
    }
 
New Game1 Member Variables

The Microsoft.Xna.Framework.Game class now has a SpriteBatch member variable, named "spriteBatch". We don't need to add one, so you can replace any reference in the text to "m_batch" with the provided member variable, "spriteBatch". Of course, this means that you'll want to remove this auto-generated SpriteBatch logic for game projects in which you won't be using any sprites (which is the case with the example 3D code in Chapter 06).

The Game class now provides a member variable (called "Content") which exposes the ContentManager class. We don't need to manage our own reference to the content manager now, so you can replace any reference in the text to "content" with the provided member variable, "Content" (notice the change in capitalization).

The Game class also provides a member variable (called "GraphicsDevice") which exposes the GraphicsDevice object which represents the active graphics device. You can replace any reference in the text to "graphics.GraphicsDevice" with the provided member variable, "GraphicsDevice". You'll see this change in the auto-generated Game1 class when you create a new XNA 2.0 game. The spriteBatch member variable is initialized using "new SpriteBatch(GraphicsDevice);" rather than the previous "new SpriteBatch(graphics.GraphicsDevice);".

LoadContent vs. LoadGraphicsContent

The LoadGraphicsContent and UnloadGraphicsContent methods of the Microsoft.Xna.Framework.Game class (technically, they're members of the DrawableGameComponent class, from which Game is derived) have been replaced with the LoadContent and UnloadContent methods. The old content management methods still work, but the compiler will generate deprecation warnings for them, and there's a good chance that the old methods will be removed from future releases of the XNA Framework.

Content Folder

All content is now stored under the Content folder of your project. Prefix any content subdirectory names in the code with "Content\". For example, most of the book's examples store game media in the "media" subdirectory, which is located just off the root directory of the project. An image named "myImage.png" within that subdirectory would have been refered to as "media\myImage" in XNA 1.0 and XNA 1.0 Refresh. In XNA 2.0, that same resource would be refered to as "Content\media\myImage".

The Content folder actually represents a subproject called "Content" which manages the building, converting, and importing of media for your game. Any media that is accessed via the ContentManager class should live here. This includes items such as textures, models, and XACT projects. Any game-specific content data that you manage manually, such as level data and persisted game data, is not housed within the Content directory.

Intuitive File Names

I used longer, more descriptive filenames for the solution files, project files, and directory names. The new names make it much easier to locate the source code for a specific chapter. This may cause issues if you do your development in a deeply-nested subdirectory, like the default Visual Studio project folder of "C:\Documents and Settings\{username}\My Documents\Visual Studio 2005\Projects\".

I suggest creating a folder off the root of the drive from which you wish to develop your XNA games. I use "C:\projects\" on my laptop, and "E:\projects\" on my desktop.

ZIP Anatomy

All of the ZIP files which host the book's source code use a parallel directory structure. I expect the user to download the ZIP files into a common directory, then extract the files from each ZIP directly into that directory, preserving the ZIP file's internal directory structure. For example, if you download PT1_CH04.zip, PT1_CH07.zip, and PT2_18.zip into the "C:\projects\" directory on your local PC, and then extract the files to that same folder, you should have the following directory structure on your local drive.

   C:\projects\Part 1 - Introduction\CH04 - Graphics 2D\
   C:\projects\Part 1 - Introduction\CH07 - Input GamePad\
   C:\projects\Part 2 - Genre Studies\CH18 - Board Games\

Comments
No comments exist for this file.

Add Comment

Add
Name
Web Site
Comment
Powered by Community Server, by Telligent Systems