So im making an RPG. For collision detection, I thought I would do it like this:

  1. Read text file containing collision data.
  2. Iterate through the list using nested for loops.
  3. When a value of 1 occurs (denoting an inpassable tile) add a rectangle to list 'badTiles', where the x and y pos of the rectangle is the x and y value from the nested for loop times the tile width and height.
  4. Now that all bad tiles are stored in a list of rectangles, we can check for collision.
  5. In player class, perform a foreach loop, checking all rectangles in badTiles list.
  6. If players rectangle intersects any member of the badTiles list, a collision has occured and perform an action (not the problem)

My problem is, collision detection is only working on the last 'badTile' in the list. I have added code so that when the badTiles are added to the list, and when the player collides with the badTiles, text on the console will appear, this all works fine and dandy. However, when it actually comes to preventing my player from walking through the tile, it only is prevented on the last badTile in the list..... huh?!

I have a hunch the probem lies with the actual reading of the file data. This is because I wanted to count how many rectangles were being added to the badTiles list (so I cross check with the data file and make sure the correct amount are being added in). I did this by creating a local int c = 1, and everytime the file parses a 1, c += 1. However the output in my console window only displays 1. The variable isnt incrementing?!

Here is the code for the loading of the data file:

// Reads collision map file. 
public void LoadCollisionMap(string name)
{
    string path = "C:/Users/Chris/Desktop/Documents/C# Projects/RPGEngine/Maps/" + name + ".txt";

    // Width and height of our tile array
    int width = 0;
    int height = File.ReadLines(path).Count();

    StreamReader sReader = new StreamReader(path);
    string line = sReader.ReadLine();
    string[] tileNo = line.Split(',');

    width = tileNo.Count();

    sReader.Close();

    // Re-initialising sReader
    sReader = new StreamReader(path);

    for (int y = 0; y < height; y++)
    {
        line = sReader.ReadLine();
        tileNo = line.Split(',');

        for (int x = 0; x < width; x++)
        {
            if ((Convert.ToInt32(tileNo[x])) == 1)
            {
                int c = 1;
                badTiles.Add(new Rectangle((x * Core.TILE_WIDTH), (y * Core.TILE_HEIGHT), 32, 32));
                Console.WriteLine("New rectangle added, number: " + c + "."); // Adds some info to the console for easy viewing.
                c++;
            }
        }
    }
    sReader.Close();
}

Any and all help will be appreciated!

for (int x = 0; x < width; x++) this line loops x amount of times inside you perform a check if ((Convert.ToInt32(tileNo[x])) == 1) so if it passes this check then it declares c and assigns the value 1. So every time the check is passed it assigns 1. You need to only increment the variable in this check and declare it outside the for loop.

Yeah I know that now, silly me. I have narrrowed down the problem to lie within the player class, i'll post the code of the method...

private void TestCollResolve(Player player, Core core, Camera camera, Direction dir)
{    
    foreach (Rectangle badTile in core.badTiles)
    {
        if (futurePos.Intersects(badTile))
        {
            Console.WriteLine("Collision with bad tile: " + badTile.ToString());

            // Players future position will intersect a bad tile, dont change players position vector.
            if (dir == dirUp)
            {
                player.playerVel.Z = 0; // Change velocity vector of player and camera to 0.
                camera.CameraVel.Z = 0;
            }
            else if (dir == dirDown)
            {
                player.playerVel.W = 0; // Change velocity vector of player and camera to 0.
                camera.CameraVel.W = 0;
            }
            else if (dir == dirLeft)
            {
                player.playerVel.X = 0; // Change velocity vector of player and camera to 0.
                camera.CameraVel.X = 0;
            }
            else if (dir == dirRight)
            {
                player.playerVel.Y = 0; // Change velocity vector of player and camera to 0.
                camera.CameraVel.Y = 0;
            }
        }
        else if (!futurePos.Intersects(badTile))
        {
            // Players future position will not intersect a bad tile, chenge players position vector.
            if (dir == dirUp || dir == dirDown)
            {
                // Change players yVector to tmp yVector.
                player.playerBounds.Y = futurePos.Y;

                // Restore players velocity components to origional values.
                player.playerVel.Z = 2;
                player.playerVel.W = 2;

                // Restore cameras velocity components to origional values.
                camera.CameraVel.Z = 2;
                camera.CameraVel.W = 2;
            }

            else if (dir == dirLeft || dir == dirRight)
            {
                // Change players xVector to tmp xVector.
                player.playerBounds.X = futurePos.X;

                // Restore players velocity components to origional values.
                player.playerVel.X = 2;
                player.playerVel.Y = 2;

                // Restore cameras velocity components to origional values.
                camera.CameraVel.X = 2;
                camera.CameraVel.Y = 2;
            }
        }
    }
}

So using the Console.WriteLine(); I can see that when the player collides with every bad tile, a message appears in the console. Its only when the player collides with the last bad tile in the rectangle list that you are prevented from walking through it?!

I would suggest you insert breakpoints in foreach (Rectangle badTile in core.badTiles) When you reach the last bad tile ensure that it is contained in core.badTiles by right clicking and adding a watch and inspecting the items. If it indeed does step the code and determine why it's passing the checks.

Regards

Okay so ive added in a break point at the start of the foreach loop. I can confirm that all of the bad tiles in the file are indeed contained within the badTiles List. Why is it only th last tile which will invoke the if statements below it?

if (dir == dirUp) also add checks on each of these if statements. and make sure the values are updating. best way of checking why the velocity isn't being set to zero is to actually step the code and see why the checks are failing and only succeeding on the last bad tile.

Okay so again, I added break points at each if(dir == direction) and they are all returning that the arrow keys are being pressed? This is confussing the nuts off of me!

Are they going inside the statements? Is the velocity and camera being set to 0? and if not then why is if (dir == dirUp) failing if it's suppose to succeed. What do you expect dir and dirup to be in this instance and what are the actual values when stepping the code? and when you step the code and press F5 until you reach the last iteration implying that you are on the "Last bad tile" what are the values then? and why is it succeeding

Hmmm... So I cant send the project over this, can you PM me your email address and I'll do it over that.

Here is the zip incase you didnt get the email:

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.