1
\$\begingroup\$

I am new to game programming and to these sites for help. I am making a 2D game but I can't seem to get the collision between my character and certain tiles. I have a map filled with grass tiles and water tiles and I want to keep my character from walking on the water tiles. I have a Tiles class that I use so that the tiles are objects and also has the collision method in it, a TileEngine class used create the map and it also holds a list of Tiles, and the class James which is for my character. I also have a Camera class that centers the camera on my character if that has anything to do with the problem. The character's movement is intended to be restricted to 4 directions(up, down, left, right). As an extra note, the bottom right water tile does have collision, but the collision does not occur for any of the other water tiles.

Here is my TileEngine class

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Test2DGame2
{
 class TileEngine : Microsoft.Xna.Framework.Game
 {
    //makes a list of Tiles objects
    public List<Tiles> tilesList = new List<Tiles>();

    public TileEngine()
    {}

    public static int tileWidth = 64;
    public static int tileHeight = 64;

    public int[,] map = {
          {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
          {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
          {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
          {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
                 };

    public void drawMap(SpriteBatch spriteBatch)
    {
        for (int y = 0; y < map.GetLength(0); y++)
        {
            for (int x = 0; x < map.GetLength(1); x++)
            {
                //make a Rectangle
                tilesList[map[y, x]].rectangle = new Rectangle(x * tileWidth, y *        tileHeight, tileWidth, tileHeight);

                //draw the Tiles objects
                spriteBatch.Draw(tilesList[map[y, x]].texture,
                    tilesList[map[y, x]].rectangle,
                    Color.White);
            }
        }
    }
 }
}

Here is my Tiles class

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Test2DGame2
{
 class Tiles
 {
    public Texture2D texture;
    public Rectangle rectangle;

    public Tiles(Texture2D texture)
    {
        this.texture = texture;
    }

    //check to see if james collides with the tile from the right side
    public void rightCollision(James james)
    {
           if (james.GetBounds().Intersects(rectangle))
           {
               james.position.X = rectangle.Left - james.front.Width;
           }
    }        
 }
}

I have a method for rightCollision because I could only figure out how to get the collisions from specifying directions.

and here is the James class for my character

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Test2DGame2
{
 class James
 {
    public Texture2D front;
    public Texture2D back;
    public Texture2D left;
    public Texture2D right;
    public Vector2 center;
    public Vector2 position;

    public James(Texture2D front)
    {
        position = new Vector2(0, 0);
        this.front = front;
        center = new Vector2(front.Width / 2, front.Height / 2);
    }

    public James(Texture2D front, Vector2 newPosition)
    {
        this.front = front;
        position = newPosition;
        center = new Vector2(front.Width / 2, front.Height / 2);
    }


    public void move(GameTime gameTime)
    {

        KeyboardState keyboard = Keyboard.GetState();
        float SCALE = 20.0f;
        float speed = gameTime.ElapsedGameTime.Milliseconds / 100.0f;

        if (keyboard.IsKeyDown(Keys.Up))
        {
            position.Y -=speed * SCALE;
        }
        else if (keyboard.IsKeyDown(Keys.Down))
        {
            position.Y += speed * SCALE;
        }
        else if (keyboard.IsKeyDown(Keys.Left))
        {
            position.X -= speed * SCALE;
        }
        else if (keyboard.IsKeyDown(Keys.Right))
        {
            position.X += speed * SCALE;
        }
    }

    public void draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(front, position, null, Color.White, 0, center, 1.0f, SpriteEffects.None, 0.0f);
    }

    //get the boundingbox for James
    public Rectangle GetBounds()
    {
        return new Rectangle(
            (int)position.X,
            (int)position.Y,
            front.Width, front.Height);
    }
 }
}
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

For the most basic form of collision detection, you need to maintain a "bounding box" around objects that should have collision. For example, you need to maintain a rectangle around James and around each water tile. These rectangles serve as the bounding boxes used to determine if collision is occurring. On each update, you can check to see if any points of James' bounding box are contained within the bounds of the water tile bounding boxes.

It looks like you're doing that. However, you can simply store the previous position of James prior to each position update and collision detection. That way, you can move James back to whatever position he was in if his bounds intersect with the bounds of a water tile.

For example (pseudo code):

Position jamesPosition = james.Position;    

james.Move(x, y);    

Rectangle jamesBounds = james.Bounds;
Rectangle tileBounds = tile.Bounds;

if(jamesBounds.Intersects(tileBounds))
    james.Position = jamesPosition;

A better way would probably be not to move James, but to calculate the position where he would move, do the collision detection, and then move him only if there was no collision.

Check this out too: Microsoft XNA Platformer Example, is the Collsion Detection implemented accurately?

EDIT

tilesList[map[y, x]].rectangle = new Rectangle(

map[y,x] will evaluate to 0 or 1 based on the values of your matrix. So, basically, you're only accessing tilesList[0] and tilesList[1]. Rectangles are being created and drawn properly, but the values of the Tiles at index 0 and index 1 of tilesList are being overwritten on each update.

\$\endgroup\$
3
  • \$\begingroup\$ Thank you very much. This makes my collision work much better. However my problem still stands. The water tiles still have no collision except for the very last one drawn. Could it be because it is not actually placing the object in those places but just drawing the texture and moving the object until it is at it's last position? \$\endgroup\$
    – zenzero
    Jul 7, 2012 at 2:00
  • \$\begingroup\$ Sorry, I did not see the link you posted. I will try to learn from the link to see if it helps, but as of right now I am still stuck so any more suggestions from anyone will be appreciated. \$\endgroup\$
    – zenzero
    Jul 7, 2012 at 2:19
  • \$\begingroup\$ I think that you are drawing the tiles in the correct position, but you are overwriting the values of the rectangles on each update. Please see my revised answer for more information. \$\endgroup\$ Jul 7, 2012 at 2:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .