I want to check if a Rectangle(A Player) , intersects with one of the rectangles in a list (List).

I am currently using a for loop , which makes it slow , and poor performance.

for (int i = 0; i < gameObjects.objectList.Count; i++)
{
   if (gameObjects.objectList[i].IntersectsWith(gameObjects.player))
   {
        gameObjects.objectList.RemoveAt(i); // if the player collided with an object, remove that object
    }
}

How can I make it more efficient / is there another way to do it faster?

3 Answers

0
Mark Shevchenko On Best Solutions

You can try organize your rectangles in a structure called k-d-tree.

It gives you up to O(log N) complexity in a large rectangle array (> 100).

F.e. make binary tree with fixed length, say, 2. Divide your space into left and right halves, then each half divide into top and bottom quarters (and so on).

Inside leaf node create a list on rectangles. If a rectangles falls into left half and top quarter, locate it in the list of this quarter.

A rectangle may be locates in a few list at the same time (f.e. in case if it falls in left and right halves).

To check intersection you should test rectangle in responding halves and quarters.

Or, you removes too many rectangles, it's faster to copy remaining rectangles into the new list in your own code.

Small example.

public enum CheckBy
{
    Horizontal,

    Vertical
}

public class Node
{
    public Node First { get; set; }

    public Node Second { get; set; }

    public int Coordinate { get; set; }

    public CheckBy CheckBy { get; set; }

    public List<Rectangle> Rectangles { get; set; }
}

public bool IsRectangleInFist(Node node, Rectangle rectangle)
{
    if (node.CheckBy == CheckBy.Horizontal)
        return rectangle.Left <= node.Coordinate;

    return rectangle.Top <= node.Coordinate;
}

public bool IsRectangelInSecond(Node node, Rectangle rectangle)
{
    if (node.CheckBy == CheckBy.Horizontal)
        return rectangle.Right >= node.Coordinate;

    return rectangle.Bottom >= node.Coordinate;
}

public void AddRectangleInSuitableNode(Node node, Rectangle rectangle)
{
    if (InRectangleInFirst(node, rectangle))
        AddRectangleInSuitableNode(node.First, rectangle);

    if (InRectangleInSecond(node, rectangle))
        AddRectangleInSuitableNode(node.Second, rectangle);
}

public void SearchIntersectedRectangles(Node node, Rectangle rectangle, List<Rectangles> result)
{
    // If not-leaf node
    if (node.Rectangles == null && node.First != null && node.Second != null)
    {
        if (IsRectangleInFirst(node, rectangle))
            SearchIntersecatedRectangles(node.First, rectangle, result);

        if (IsRectangleInSecond(node, rectangle))
            SearchIntersecatedRectangles(node.Second, rectangle, result);

        return;
    }

    result.AddRangle(Rectangles.Where(r => r.IsIntersect(rectangle)));
}

These all lines makes simple 2D-tree. First, make the tree:

// Say, all rectangles would be inside this "space"
const int leftest = -1000;
const int rightest = 1000;
const int bottomest = -1000;
const int toppest = 1000;

// Tree with depth == 2
var tree = new Node
{
    CheckBy = CheckBy.Hozirontal,
    Coordinate = (leftest + rightest)/2,
    First = new Node
    {
        CheckBy = CheckBy.Vertical,
        Coordintate = (toppest + bottomest)/2,
        Rectangles = new List<Rectangle>(),
    },
    Second = new Node
    {
        CheckBy = CheckBy.Vertical,
        Coordintate = (toppest + bottomest)/2,
        Rectangles = new List<Rectangle>(),
    },
}

Then, sort all rectangles in this tree:

foreach (var rectangle in rectangles)
    AddRectangleInSuitableNode(tree, rectangle);

Now you can fast get intersecting rectangles:

var intersecting = new List<Rectangles>();
SearchIntersecatedRectangles(tree, targetRectangle, intersecting);
// Here you can remove intersecting rectangles...
0
Nox Noctis On

Basically, you need to stop checking all of the rectangles every time. You need to somehow figure out which rectangles are located in the vicinity of the player.

You could use some kind of spatial grid to store your rectangles so you could quickly find adjacent rectangles to be checked for collision. See this tutorial for example: N Tutorial B - Broad-Phase Collision.

0
TheLethalCoder On

I doubt it will be faster but you can always do it with Ling in a one liner:

gameObjects.objectList = gameObjects.objectList
                         .Select(go => go)
                         .Where(go => !go.IntersectsWith(gameObjects.player))
                         .ToList();

This essentially sets the list to one where any gameObject that collides with player is removed.

Also note that it is usually faster to process a sorted list first, so doing this:

gameObjects.objectList = gameObjects.objectList
                         .OrderBy(go => go.X)
                         .ThenBy(go => go.Y)
                         .ToList();

may help speed things up a bit. Doing this ordering every frame will be slow though so it will be worth ordering the objects as they are added to the list.