Danger Zone
Danger Zone

Reputation: 159

Unable to detect if two rectangles are colliding C#

I am working on a procedural room generator in c#, I would like the rooms not to overlap and I am having a hard time getting that to work. After @Idle_Mind's comments, I have a new problem. The Image produced by the program has many overlapping rooms. Bellow is the class that should handle the intersection checking and the placement of the rooms onto the tilemap

        public int XSize, YSize;
        private Cell[ , ] cells;
        private List<Room> rooms;

        public Tilemap(int xSize, int ySize)
        {
            XSize = xSize;
            YSize = ySize;
            rooms = new List<Room>();
            cells = new Cell[XSize, YSize];

            for (int y = 0; y < YSize; y++)
            {
                for (int x = 0; x < XSize; x++)
                {
                    cells[x, y].type = CellType.Empty;
                }
            }

            for (int i = 0; i < 10; i++)
            {
                GenerateRandomRoomSafe(10);
            }
        }

        private Room GetRoomBounds()
        {

            Utils.Int2 min = new Utils.Int2(0, 0);
            Utils.Int2 max = new Utils.Int2(XSize,YSize);
            Utils.Int2 q1 = Utils.GetRandomCoords(min, max);

            max.X = XSize - 1 - q1.X;
            max.Y = YSize - 1 - q1.Y;

            Utils.Int2 siz = Utils.GetRandomCoords(min, max);
            Room check = new Room(q1.X, q1.Y, siz.X, siz.Y);


            return check;
        }

        public void GenerateRandomRoomSafe(int maxTries)
        {
            Room check = new Room(0, 0, 0, 0);
            bool isValid = false;
            int tries = 0;

            if (rooms.Count == 0)
            {
                isValid = true;
                check = GetRoomBounds();
                tries = 1;
            }
            else
            {
                while (!isValid && tries < maxTries)
                {
                    check = GetRoomBounds();
                    for (int i = 0; i < rooms.Count; i++)
                    {
                        if (!rooms[i].Walls.IntersectsWith(check.Walls))
                        {
                            isValid = true;
                            break;
                        }
                    }
                    tries++;
                }
            }

            if (isValid)
            {
                Console.WriteLine(check + " was placed after " + tries + " tries");
                PlaceRoomUnsafe(check);
            }
        }

        public void PlaceRoomUnsafe(Room r)
        {
            for (int y = r.Walls.Y; y <= r.Walls.Y + r.Walls.Height; y++)
            {
                cells[r.Walls.X, y].type = CellType.Wall;
            }
            for (int y = r.Walls.Y; y <= r.Walls.Y + r.Walls.Height; y++)
            {
                cells[r.Walls.X + r.Walls.Width, y].type = CellType.Wall;
            }
            for (int x = r.Walls.X; x <= r.Walls.X + r.Walls.Width; x++)
            {
                cells[x, r.Walls.Y].type = CellType.Wall;
            }
            for (int x = r.Walls.X; x <= r.Walls.X + r.Walls.Width; x++)
            {
                cells[x, r.Walls.Y + r.Walls.Height].type = CellType.Wall;
            }

            for (int y = r.Floor.Y; y < r.Floor.Y + r.Floor.Height; y++)
            {
                for (int x = r.Floor.X; x < r.Floor.X + r.Floor.Width; x++)
                {
                    cells[x, y].type = CellType.Floor;
                }
            }
            rooms.Add(r);
        }

        public void GenerateRandomRoomUnsafe()
        {
            Room r = GetRoomBounds();
            PlaceRoomUnsafe(r);
        }


        public int GetCellPixel(int x, int y)
        {
            return (int) cells[x, y].type;
        }


        public class Room
        {
            public Rectangle Walls;
            public Rectangle Floor;

            public Room(int q1X, int q1Y, int xSize, int ySize)
            {
                Walls.X = q1X;
                Walls.Y = q1Y;
                Walls.Width = xSize;
                Walls.Height = ySize;
                Floor.X = q1X + 1;
                Floor.Y = q1Y + 1;
                Floor.Width = xSize - 1;
                Floor.Height = ySize - 1;
            }

            public override string ToString()
            {
                return "[Walls: " + Walls + "\n Floor: " + Floor + "]";
            }
        }
    }

Image below for referenceImage

Upvotes: 0

Views: 134

Answers (1)

Idle_Mind
Idle_Mind

Reputation: 39122

Your logic in GenerateRandomRoomSafe() is backwards.

In this code block:

while (!isValid && tries < maxTries)
{
    check = GetRoomBounds();
    for (int i = 0; i < rooms.Count; i++)
    {
        if (!rooms[i].Walls.IntersectsWith(check.Walls))
        {
            isValid = true;
            break;
        }
    }
    tries++;
}

What you're saying is, "If it doesn't intersect with at least one room, then it must be valid".

Just because it doesn't intersect with the current room, doesn't mean it won't intersect with a different one!

It should look more like: (note the comments)

while (!isValid && tries < maxTries)
{
    isValid = true; // assume it's good until proven otherwise
    check = GetRoomBounds();
    for (int i = 0; i < rooms.Count; i++)
    {
        if (rooms[i].Walls.IntersectsWith(check.Walls)) // if it DOES intersect...
        {
            isValid = false; // .. then set valid to false.
            break;
        }
    }
    tries++;
}

So we start by assuming it is valid, then when we encounter a room that DOES intersect, we set valid to false and stop the for loop so another random room can be tried (assuming we haven't exceeded the number of tries).

Some of the maps it produced:

enter image description here

Upvotes: 1

Related Questions