0 votes

I'm currently trying my hand at procedural generation, which is something I've never really attempted before. I have a basic scene with a Node as root and a script attached to it. In the script, there is a Room class that (at the present time) is little more than a glorified Rect2. I intend to add more as time goes on, but right now I'm in a bit of a pickle.

I start in the _ready function of my Node script by calling my Room class and generating ten random rooms. I tested this before adding anything else and, indeed, all the rooms appeared in random sizes and at random positions. Once I had this working, I added some code to delete any overlapping rooms. This all goes according to plan, but when I run the game I now see nothing. No rooms. Just a gray background.

I added a dummy function where I call the _draw function on each of my Room objects, which I already know is unnecessary. I did this just so I could do some debugging. When this function is called, it throws an error because it says it's trying to call previously removed instance:

Attempt to call function '_draw' in base 'previously freed instance'
on a null instance.

Setting up a breakpoint at the end of the _ready function shows the *rooms* array with all the instances intact. Their Instance IDs are present and clicking on each one shows me information about them.

Setting up a separate breakpoint at the start of the _process function, however, reveals the root of the problem: the array still has ten rooms, but they all have a value of NULL. Somewhere between _ready and _process, all the instances are being removed. I even made sure to add each instance as a child of the root node to see if that would help, but it did not. Here's my script for reference:

extends Node
export var minimumSize := Vector2(0,0);
export var maximumSize := Vector2(0,0);
export var minimumPosition := Vector2(0,0);
export var maximumPosition := Vector2(0,0);
var rooms = [];

func _ready():
    var instance_count = 0;
    while instance_count < 10:
        var r : Room = Room.new();
        randomize();
        var x = floor(rand_range(minimumPosition.x,maximumPosition.x));
        var y = floor(rand_range(minimumPosition.y,maximumPosition.y));
        var sx = floor(rand_range(minimumSize.x, maximumSize.x));
        var sy = floor(rand_range(minimumSize.y, maximumSize.y));
        r.pos = Vector2(x,y);
        r.size = Vector2(sx,sy);
        r.setRect();
        if rooms.size() == 0:
            rooms.append(r);
            instance_count += 1;
        for room in rooms:
            if not room.checkIntersect(r.rect):
                rooms.append(r);
                add_child(r); #add to root node in attempt to preserve
                instance_count += 1;
            else:
                r.queue_free();
    pass; #added for the purposes of setting up a breakpoint here

func _process(delta):
    for room in rooms: #second breakpoint is here
        room._draw();

class Room:
    extends Node2D

    var rect : Rect2;
    var pos := Vector2(0,0);
    var size := Vector2(0,0);
    func generateRoom():
        pass;

    func setRect():
        rect = Rect2(pos, size);

    func checkIntersect(var r: Rect2) -> bool:
        if rect.intersects(r):
            return true;
        return false;

    func _draw():
        draw_rect(rect, Color.white);

Why are all of my instances being deleted? I don't want them to be deleted! I never ask the engine to delete them. I do, in fact, store them in an array for the sole purpose of preserving them. What am I doing wrong here? Can someone out there lend a helping hand? Please?

asked Mar 8 in Engine by SawmillTurtle (42 points)
edited Mar 8 by SawmillTurtle

I don't know how you managed to hit those breakpoints as i'm getting into an infinite loop. That's because you're appending to an array while iterating over it.

for room in rooms:

                rooms.append(r);

That's a bad practice in programming.

You're right about that. I hadn't noticed that I'd done that. I'll change it, but I'm not hitting an infinite loop. Not sure why. Best to fix it, though. Thanks.

1 Answer

0 votes
Best answer
func _ready():
    var instance_count = 0;
    while instance_count < 10:
        # 1. Make Room "r"
        var r : Room = Room.new();
        .......
        # 2. rooms.size() == 0 so append "r" to rooms
        if rooms.size() == 0:
            rooms.append(r);
        # 3. now rooms has ["r"]
        for room in rooms:
            # 4. "room" and "r" points same instance. so it intersects.
            if not room.checkIntersect(r.rect):
                rooms.append(r);
                add_child(r); #add to root node in attempt to preserve
            else:
                # 5. finally you freed "r" in rooms, but rooms has "r" reference
                r.queue_free();
answered Mar 8 by volzhs (9,452 points)
selected Mar 9 by SawmillTurtle
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.