locked
XNA Collision RRS feed

  • Question

  • Hello, I'm having a bit of a problem getting Collision to work.

    I have an Array Map:

            int[,] Map1 = new int[MapHeight, MapWidth]
            {
                {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                {1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1},
                {1,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1},
                {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
            };

    I set GameMap[0] as the floor and GameMap[1] as the wall graphic.

    I have my Ball drawn at 180, 180 on this 200, 200 screen/map.

    Each Tile and the Ball are 10x10 Pixels.

    I have been spending hours and hours plus last night to figure out Collision and how to make my Ball that use a Point for x, y, position to not go through the walls.  I keep getting stuck and I'm unable to do this at all.  I have never been good with Collision in General and have no idea how to set GameMap[1] as non-passable.

    I have my full source code below, however I really would like some help to understand Collisions, I'm not looking for Pixel Perfect or 3D related since this is 100% 2D.

    I'm not looking for a 100% hand out for the answer but help so I can get collision working, I have spent over 15 hours trying to figure this out, I searched the web and found nothing related to what I'm trying to do.

    Thanks to anyone who has any time to help me understand Collisions.


    ============
    Game1.cs
    ============

    #region Using Statements
    using System;
    using System.Collections.Generic;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.Content;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Storage;
    #endregion

    namespace WindowsGame1
    {
        /// <summary>
        /// This is the main type for your game
        /// </summary>
        public class Game1 : Microsoft.Xna.Framework.Game
        {
            GraphicsDeviceManager graphics;
            ContentManager content;

            Texture2D sBall;
            SpriteBatch spriteBatch;

            Ball cball;

            Texture2D[] GameMap = new Texture2D[2];

            const int MapHeight = 20;
            const int MapWidth = 20;

            // Draw Map
            int[,] Map1 = new int[MapHeight, MapWidth]
            {
                {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                {1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,1},
                {1,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,1},
                {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1},
                {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
                {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
            };

            int Map1X = 0;
            int Map1Y = 0;

            int MapOffsetX = 0;
            int MapOffsetY = 0;

            int MapTileDisplayWidth = 20;
            int MapTileDisplayHeight = 20;

            int MapTilesWidth = 10;
            int MapTilesHeight = 10;


            public Game1()
            {
                graphics = new GraphicsDeviceManager(this);
                content = new ContentManager(Services);

                graphics.PreferredBackBufferHeight = 200;
                graphics.PreferredBackBufferWidth = 200;

                cball = new Ball(180, 180);
            }

            public void InputUpdate()
            {
                // Up
                if (Keyboard.GetState().IsKeyDown(Keys.Up))
                {
                    cball.position.Y--;
                }

                // Down
                if (Keyboard.GetState().IsKeyDown(Keys.Down))
                {
                    cball.position.Y++;
                }

                // Right
                if (Keyboard.GetState().IsKeyDown(Keys.Right))
                {
                    cball.position.X++;
                }

                // Left
                if (Keyboard.GetState().IsKeyDown(Keys.Left))
                {
                    cball.position.X--;
                }

                // Check Movement
            }

            /// <summary>
            /// Allows the game to perform any initialization it needs to before starting to run.
            /// This is where it can query for any required services and load any non-graphic
            /// related content.  Calling base.Initialize will enumerate through any components
            /// and initialize them as well.
            /// </summary>
            protected override void Initialize()
            {
                // TODO: Add your initialization logic here

                base.Initialize();
            }


            /// <summary>
            /// Load your graphics content.  If loadAllContent is true, you should
            /// load content from both ResourceManagementMode pools.  Otherwise, just
            /// load ResourceManagementMode.Manual content.
            /// </summary>
            /// <param name="loadAllContent">Which type of content to load.</param>
            protected override void LoadGraphicsContent(bool loadAllContent)
            {
                if (loadAllContent)
                {
                    // TODO: Load any ResourceManagementMode.Automatic content
                    GameMap[0] = content.Load<Texture2D>("Floor");
                    GameMap[1] = content.Load<Texture2D>("Wall");
                    sBall = content.Load<Texture2D>("Ball");
                    spriteBatch = new SpriteBatch(graphics.GraphicsDevice);
                }

                // TODO: Load any ResourceManagementMode.Manual content
            }


            /// <summary>
            /// Unload your graphics content.  If unloadAllContent is true, you should
            /// unload content from both ResourceManagementMode pools.  Otherwise, just
            /// unload ResourceManagementMode.Manual content.  Manual content will get
            /// Disposed by the GraphicsDevice during a Reset.
            /// </summary>
            /// <param name="unloadAllContent">Which type of content to unload.</param>
            protected override void UnloadGraphicsContent(bool unloadAllContent)
            {
                if (unloadAllContent == true)
                {
                    content.Unload();
                }
            }


            /// <summary>
            /// Allows the game to run logic such as updating the world,
            /// checking for collisions, gathering input and playing audio.
            /// </summary>
            /// <param name="gameTime">Provides a snapshot of timing values.</param>
            protected override void Update(GameTime gameTime)
            {
                // Allows the default game to exit on Xbox 360 and Windows
                if (Keyboard.GetState().IsKeyDown(Keys.Escape))
                    this.Exit();

                // TODO: Add your update logic here
                InputUpdate();
                CollisionCheck();

                base.Update(gameTime);
            }


            /// <summary>
            /// This is called when the game should draw itself.
            /// </summary>
            /// <param name="gameTime">Provides a snapshot of timing values.</param>
            protected override void Draw(GameTime gameTime)
            {
                graphics.GraphicsDevice.Clear(Color.CornflowerBlue);

                // TODO: Add your drawing code here
                spriteBatch.Begin(SpriteBlendMode.AlphaBlend);

                // Draw the map
                for (int y = 0; y < MapTileDisplayHeight; y++)
                {
                    for (int x = 0; x < MapTileDisplayWidth; x++)
                    {
                        spriteBatch.Draw(GameMap[Map1[y + Map1Y, x + Map1X]], new Rectangle((x * MapTilesWidth) + MapOffsetX, y * MapTilesHeight + MapOffsetY, MapTilesWidth, MapTilesHeight), Color.White);
                    }
                }

                // Draw the ball
                spriteBatch.Draw(sBall, new Rectangle(cball.position.X, cball.position.Y, sBall.Height, sBall.Width), Color.White);
               
                spriteBatch.End();

                base.Draw(gameTime);
            }       

            public void CollisionCheck()
            {
                // Collision Code
            }
        }
    }

    ==========
    Ball.cs
    ==========

    using Microsoft.Xna.Framework;

    namespace WindowsGame1
    {
        class Ball
        {
            public Point position;

            public Ball(int x, int y)
            {
                position = new Point(x, y);
            }
        }
    }
    Wednesday, November 29, 2006 9:58 PM

Answers

  • The easiest way that I can think to help is to use the bounding objects found within XNA. If you build your floor map as a series of boundingboxes( with a z component of 0 in both minimum and maximum, then you essentially get a bounding square). So instead of you having a floor map like:
    1,1,1,1,1,
    0,0,0,0,1,
    1,1,1,0,1,
    0,0,0,0,1,
    1,1,1,1,1,

    you'd have something more like this:
    BoundingBox[] floor = new BoundingBox[4];

    floor[0] = new BoundingBox(new Vector3(0,0,0),new Vector3(4,0,0));

    floor[1]= new BoundingBox(new Vector3(0,2,0),new Vector3(2,2,0));

    floor[2]= new BoundingBox(new Vector3(0,4,0),new Vector3(4,4,0));

    floor[3] = new BoundingBox(new Vector3(4,0,0),new Vector3(4,4,0));

    And remember to define the ball also: BoundingBox Ball = new BoundingBox(new Vector3(Vector2 Pos,0),new Vector3(Vector2 Pos,0)); // Pos is the location of the ball. The difference between the two Vector3's should be the size of the ball.

    So now the collision detection algorithm would go something like:
    bool colliding = false;
    foreach(BoundingBox BB in floor)
        if(BB.Intersects(Ball))
            colliding=true;

    Now, simply check colliding to see if the ball intersected one of the walls.

    Thursday, November 30, 2006 5:23 PM