简体   繁体   中英

Tile Engine Collision Optimization

Alright, so today I decided to try to further optimize my collision detection code for my tile engine.

This is what I did:

Circle class checks if there are points within range. If there are, then check for collision between player and tile.

Code:

        int tileWidth = 128;
        int tileHeight = 128;

        int[,] Layer3 = { 1, 1, 1, etc... };

        int tileMapWidth = Layer3.GetLength(1);
        int tileMapHeight = Layer3.GetLength(0);

        Rectangle tile, tile2;

        for (int x = 0; x < tileMapWidth; x++)
        {
            for (int y = 0; y < tileMapHeight; y++)
            {
                int wallIndex = Layer3[y, x];

                if (wallIndex == 1) //Full-sized Tile Collision (128 x 128)
                {
                    if (collisionCircle.Contains(new Vector2(x * tileWidth + (tileWidth / 2) + (int)Player.camera.Position.X,
                                                             y * tileHeight + (tileHeight / 2) + (int)Player.camera.Position.Y))) //+ tile / 2 is for centering the point
                    {
                        tile = new Rectangle(x * tileWidth + (int)Player.camera.Position.X, y * tileHeight + (int)Player.camera.Position.Y, tileWidth, tileHeight);
                        Collide(tile);
                    }
                }
            }
        }

This would check throughout layer3 if there is a "1". If there is, assign rectangle and check for collision if point is inside collision radius.

Also, I checked this code(with a draw method), and I know it's working properly, at least the behavior.

I added in about 120,000(32 x 3888) tiles to try to make it lag, and before the code, it lagged a little bit. But after I added in the code, it lagged even more so.

I thought that since it would only check for collision between tiles(points) that are within the radius it wouldn't even remotely lag, but that's not the case...

Any help/ideas on how to optimize this would be great.

Thanks a lot, Shyy

EDIT:

Cirlce.Contains() code:

    public bool Contains(Vector2 Point)
    {
        return ((Point - position).Length() <= radius);
    }

I used a circle because I've heard it's faster than using a rectangle.

Another possible optimization is instead of return ((Point - position).Length() <= radius); use return ((Point - position).LengthSquared() <= radius * radius);

This is faster because Vector2.Length() has to perform a costly square root operation. Vector2.LengthSquared() does not have to perform that slow operation. The radius has to be multiplied by itself to account for the length from the vector being squared.

It sounds like you're trying to determine what tiles you don't need to use for collision with the player. Another optimization you could do is that if a tile at (X=5,Y=5) is above and to the left of the player, then you don't need to check a tile at (X=4,Y=4). Similarly if (X=5,Y=5) is below and to the right, (X=6,Y=6) is guaranteed to be too far as well. Try to determine when you've passed the player and no longer need to check collisions.

I suggest to loop only over visible tiles in screen to check collision using movement offset. i will try something from my head..

for x as integer = 0 + offSetX to tilesInWidth + offSetX
   for y as integer = 0 + offSetY to tilesInHeight + offSetY
      if player.insideCircle(player.position, radius) '
         object = layer(y,x);
         if player.collideWith(object) then Collide()
      end if
   next
next

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM