Why does my dungeon generator sometimes generate rooms that aren't connected?
Asked Answered
D

2

0

Hello. I'm new to Godot, and I've created a simple dungeon generator. It generally works well, as it avoids repeating rooms; however, I've encountered issues where rooms aren't always connected or are placed diagonally. I've been trying to fix these problems for a while, but I can't figure out what is wrong. Can anyone point me in the right direction? Thank you in advance.

Example:

My code:

using Godot;
using System.Collections.Generic;
public partial class Rooms : Node2D
{
    [Export] private const int numRooms = 10;

    private PackedScene[] SPAWN_ROOMS;

    private PackedScene[] INTERMEDIATE_ROOMS;

    private PackedScene[] END_ROOMS;

    private const int TILE_SIZE = 16;

    private List<Vector2> rooms;

    private Node2D room;

    private TileMap roomTilemap;

    public override void _Ready()
    {
        SPAWN_ROOMS = new PackedScene[] { GD.Load<PackedScene>("res://Rooms/SpawnRoom0.tscn")};
        INTERMEDIATE_ROOMS = new PackedScene[] { GD.Load<PackedScene>("res://Rooms/Room0.tscn")};
        END_ROOMS = new PackedScene[] { GD.Load<PackedScene>("res://Rooms/EndRoom0.tscn") };
        Generate(numRooms);
    }

    private void AddRoom(Node2D room)
    {
        while (rooms.Contains(room.Position))
        {
            Vector2 dir = new Vector2[] { new (-1, 0), new (1, 0), new (0, -1), new (0, 1) }[GD.Randi() % 4];
			roomTilemap = room.GetNode<TileMap>("TileMap");
            room.Position += dir * roomTilemap.GetUsedRect().Size.Y * TILE_SIZE;
        }

        rooms.Add(room.Position);
        AddChild(room);
    }

    private void Generate(int count)
    {
        rooms = new List<Vector2> { new(0, 0) };
        Vector2 from = rooms[rooms.Count - 1];

        for (int i = 0; i < count; i++)
        {
            Vector2 dir = new Vector2[] { new (-1, 0), new (1, 0), new (0, -1), new (0, 1) }[GD.Randi() % 4];

            if (i == 0)
            {
                room = SPAWN_ROOMS[GD.Randi() % SPAWN_ROOMS.Length].Instantiate() as Node2D;
                roomTilemap = room.GetNode<TileMap>("TileMap");
                room.Position = from + dir * roomTilemap.GetUsedRect().Size.Y * TILE_SIZE;
                AddRoom(room);
                from = room.Position;
            }
            else
            {
                if (i == count - 1)
                {
                    room = END_ROOMS[GD.Randi() % END_ROOMS.Length].Instantiate() as Node2D;
                    roomTilemap = room.GetNode<TileMap>("TileMap");
                    room.Position = from + dir * roomTilemap.GetUsedRect().Size.Y * TILE_SIZE;
                    room.Modulate = Color.Color8(255, 50, 255);
                    AddRoom(room);
                	from = room.Position;
                }
                else
                {
                    room = INTERMEDIATE_ROOMS[GD.Randi() % INTERMEDIATE_ROOMS.Length].Instantiate() as Node2D;
                    roomTilemap = room.GetNode<TileMap>("TileMap");
                    room.Position = from + dir * roomTilemap.GetUsedRect().Size.Y * TILE_SIZE;
                    AddRoom(room);
                	from = room.Position;
                }
            }
        }
    }
}
Divinadivination answered 6/12, 2023 at 21:24 Comment(0)
T
1

I'm not quite sure I can spot your issue, but there are a couple of things that seem weird to me:

  1. while (rooms.Contains(room.Position)) This is unreliable as it's directly comparing Vector2s using floating point. It actually doesn't make sense to use floats when you're filling a grid. It would be much less error-prone to use Vector2i and directly increment/decrement it by 1, tracking that. You could have AddRoom return Vector2i to make it work.

  2. Why are you using roomTilemap.GetUsedRect().Size.Y? Shouldn't all of your cells be the same size?

Truman answered 7/12, 2023 at 2:0 Comment(0)
D
0

Truman Thank you very much for your input. You are right i change Vector2 to Vector2i and it does work better now, also before rooms where rectangular not square that's why i was using Size.Y but now there is no need for that and Size works perfectly fine.After a good night of sleep i managed to find what was cousing the issue that room were sometimes placed in the wrong spot

Before:
	while (rooms.Contains(room.Position))
	{
	Vector2 dir = new Vector2[] { new (-1,0), new (1,0), new (0,-1), new (0,1) }[GD.Randi() % 4];
	roomTilemap = room.GetNode<TileMap>("TileMap");
	room.Position += dir * roomTilemap.GetUsedRect().Size.Y * TILE_SIZE;
	}

	rooms.Add(room.Position);
	AddChild(room);

After:

    roomTilemap = room.GetNode<TileMap>("TileMap");
    int maxAttempts = 10;
    int attempts = 0;

    while (rooms.Contains((Vector2I)room.Position) && attempts < maxAttempts)
    {
        dir = new Vector2I[] { new(-1, 0), new(1, 0), new(0, -1), new(0, 1) }[GD.Randi() % 4];
        room.Position = rooms[rooms.Count - 1] + dir * roomTilemap.GetUsedRect().Size * TILE_SIZE;
        attempts++;
    }

    rooms.Add((Vector2I)room.Position);
    AddChild(room);

Before i was adding a wrong position in room.Position now after specifying a previous room it works perfectly fine and it doesn't crush randomly.

Divinadivination answered 7/12, 2023 at 13:24 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.