1
\$\begingroup\$

This might be really simple but it is giving me a lot grief and I wondered if you guys would be able to shed some light on it. Basically I have a tile map which draws tiles at 64 * 64 and that works very well and they are drawn in a 2D array like this in the game1 class.

TileMap tileMap = new TileMap(new int[,]
    {
        { 2,2,2,2,2,2,2,2,2,2 },
        { 2,2,2,2,2,2,2,2,2,2 },
        { 0,0,0,0,0,0,4,4,4,4 },
        { 0,0,0,0,0,0,1,1,4,4 },
        { 1,1,1,1,1,1,1,1,1,1,},
        { 1,1,1,1,1,1,1,1,1,1,}
    });

Now comes the problem. Basically I want to determine which side the player has hit the tile from. However, with the algorithm below the collision only works correctly for the bottom and left side. if the player hits the tile from the top it will state it was hit from the bottom. if the player hits from the right it will specify the left side was hit. if the player hits from the left or bottom it will show that collision has happened but state it happened on the right or top of it. it will output that the top of the has been hit but only when the player is completely in the tile like this

.

Pretty much the same thing happens when it displays the right side is hit (player moves more to the left)

enter image description here

TileMap

int left = (int)Math.Floor((float)player.playerBounds.Left / TILE_WIDTH);
        int top = (int)Math.Floor((float)player.playerBounds.Top / TILE_HEIGHT);
        int right = (int)Math.Ceiling((float)player.playerBounds.Right / TILE_WIDTH) - 1;
        int bottom = (int)Math.Ceiling((float)player.playerBounds.Bottom / TILE_HEIGHT) - 1;

        Rectangle tileBounds = new Rectangle((int)tilePosX, (int)tilePosY, TILE_WIDTH, TILE_HEIGHT);
        Rectangle playerBounds = player.playerBounds;

        float WidthOfRects = 0.5f * playerBounds.Width + tileBounds.Width;
        float heightOfRects = 0.5f * playerBounds.Height + tileBounds.Height;

        int centerX = (playerBounds.Left + playerBounds.Width / 2) - (tileBounds.Left + tileBounds.Width / 2);
        int centerY = (playerBounds.Top + playerBounds.Height / 2) - (tileBounds.Top + tileBounds.Height / 2);

        for (int y = top; y <= bottom; ++y)
        {
            for (int x = left; x <= right; ++x)
            {

                if (mapCell[y, x].TileID == 1)
                {
                    //minkowski sum
                    if (Math.Abs(centerX) <= WidthOfRects && Math.Abs(centerY) <= heightOfRects)
                    {
                        double wy = WidthOfRects * centerY;
                        double hx = heightOfRects * centerX;
                        if (wy > hx)
                        {
                            if (wy > -hx)
                            {
                                Console.WriteLine("bottom");
                                //newPos.Y = tileCollision.Bottom;
                            }
                            else
                            {
                                Console.WriteLine("right");
                                //newPos.X = tileCollision.Right;

                            }
                        }
                        if (wy > -hx)
                        {
                            Console.WriteLine("left ");
                            //newPos.X = tileCollision.Left - playerBounds.Width;
                        }
                        else
                        {
                            Console.WriteLine("top");
                            //newPos.Y = tileCollision.Top - playerBounds.Height;
                        }
                    }
                    // player.Position = newPos;
                }
            }
        }

Map Cell

public class MapCell
{

    public int TileID { get; set; }

    public MapCell(int tileID) 
    {
        TileID = tileID;
    }

Any help would be greatly appreciated.

Thank you.

\$\endgroup\$
1
\$\begingroup\$

Solution #1: Try to check for collisions before they happen:
if player's position + his horizontal velocity collides with the tile
and
the velocity is negative (i.e he's moving up),
then the collision will happen from above.

The same logic can be applied to the other sides.

Solution #2: You can create additional collision boxes on every side of the "main" box,
so-called 'sensors', and check for collisions with them:sensors example

The red box is the main one and the yellow boxes are those additional sensors. My drawing is far from ideal, but hopefully you got the idea.

\$\endgroup\$
-1
\$\begingroup\$

Check out my answer: Platformer collision problems (C++)

Maybe it doesn't seem so simple to implement with your codes but that collision system would be the best choice for you (I think).

\$\endgroup\$
  • \$\begingroup\$ This answer doesn't stand on its own very well at present. It doesn't describe what key points you're recommending from the linked answer, nor why it would be "the best choice" for this situation. \$\endgroup\$ – DMGregory Jan 26 '18 at 17:56
-3
\$\begingroup\$

Get this:

float WidthOfRects = 0.5f * (playerBounds.Width + tileBounds.Width);
float heightOfRects = 0.5f * (playerBounds.Height + tileBounds.Height);
\$\endgroup\$
  • \$\begingroup\$ Hey, thanks for the reply. I've just changed what you said but it hasn't made any difference unfortunately. \$\endgroup\$ – Anonymous5642 Dec 25 '16 at 3:50
  • 4
    \$\begingroup\$ Answers should stand on their own as much as possible. Rather than sharing just a couple of lines of code, try to include a description of what you think the problem is, and why your proposed change would help fix it. \$\endgroup\$ – DMGregory Dec 25 '16 at 4:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.