Legacy GM [SOLVED] Object Spawner (spawn in walls)

Gamerev147

Member
So basically I coded a super simple spawner for medkits in my game. I would like to keep it simple.
However my problem is that when they spawn, some spawn in open areas (they should do this) and some spawn in the walls and other solid static objects (should NOT do this).

My code is below, just tell me how to fix this with a short explanation. Thanks!

obj_Medkit_Spawner :
Create Event:
Code:
randomize();
alarm[0] = 60;
Alarm 0 Event:
Code:
///Spawn Medkit
if (!place_meeting(x, y, obj_Parent)) { //i have all solid walls attached to a parent so i can call them all once, it works

    instance_create(random(room_width), random(room_height), obj_Medkit);
    
}

alarm[0] = 60;
But the medkits spawn in the walls. I've also tried the place_free function but to no avail.
 

obscene

Member
When you check place meeting at x,y , you are using the coordinates of the spawner object not the random place you refer to in the next line.

So first, set two variables like xx,yy , randomize them, check a collision at that point and then spawn the instance there.
 
D

DarthTenebris

Guest
I think this will work.
Code:
with(instance_create(x,y,obj_medikit)) {
     do {
          randomize();
          x = irandom(0, room_width);
          y = irandom(0, room_height);
     } until {
          place_free(x, y);
     }
}
Hope I helped :)
 

Perseus

Not Medusa
Forum Staff
Moderator
The problem with finding random coordinates prior to actually creating an instance is that you get only a single pixel to check for collisions at. It is possible that a position exactly one pixel (or a few pixels, for that matter) to the left of a solid instance is found. Although that position is free of collisions, but when you create an instance, it would overlap with the solid one. Methods exist to use the mask instead but they are unnecessarily complicated. So I'd suggest creating an instance first, then finding a free position for it.

The solution that @Fat_Man3468800 offered is viable, but it has some problems and typos which I'd like to point out. First, randomize should be called only once at game start, not every time you need to use a random function. In your (OP's) case, it is being called in the Create event. I'd suggest moving it to a Game Start event to avoid weird flaws in future. Second, irandom takes a single argument, unlike irandom_range. Third, consider making the until statement an actual statement, not a block.

Code:
with (instance_create(x, y, obj_medikit)) {
    do {
        x = irandom(room_width);
        y = irandom(room_height);
     }
    until (place_free(x, y));
}
 

Gamerev147

Member
The problem with finding random coordinates prior to actually creating an instance is that you get only a single pixel to check for collisions at. It is possible that a position exactly one pixel (or a few pixels, for that matter) to the left of a solid instance is found. Although that position is free of collisions, but when you create an instance, it would overlap with the solid one. Methods exist to use the mask instead but they are unnecessarily complicated. So I'd suggest creating an instance first, then finding a free position for it.

The solution that @Fat_Man3468800 offered is viable, but it has some problems and typos which I'd like to point out. First, randomize should be called only once at game start, not every time you need to use a random function. In your (OP's) case, it is being called in the Create event. I'd suggest moving it to a Game Start event to avoid weird flaws in future. Second, irandom takes a single argument, unlike irandom_range. Third, consider making the until statement an actual statement, not a block.

Code:
with (instance_create(x, y, obj_medikit)) {
    do {
        x = irandom(room_width);
        y = irandom(room_height);
     }
    until (place_free(x, y));
}
Awesome! Thank you for the explanation and a solution. I will give it a try right now and get back to you.
Thanks! :)
 

Gamerev147

Member
The problem with finding random coordinates prior to actually creating an instance is that you get only a single pixel to check for collisions at. It is possible that a position exactly one pixel (or a few pixels, for that matter) to the left of a solid instance is found. Although that position is free of collisions, but when you create an instance, it would overlap with the solid one. Methods exist to use the mask instead but they are unnecessarily complicated. So I'd suggest creating an instance first, then finding a free position for it.

The solution that @Fat_Man3468800 offered is viable, but it has some problems and typos which I'd like to point out. First, randomize should be called only once at game start, not every time you need to use a random function. In your (OP's) case, it is being called in the Create event. I'd suggest moving it to a Game Start event to avoid weird flaws in future. Second, irandom takes a single argument, unlike irandom_range. Third, consider making the until statement an actual statement, not a block.

Code:
with (instance_create(x, y, obj_medikit)) {
    do {
        x = irandom(room_width);
        y = irandom(room_height);
     }
    until (place_free(x, y));
}
So when I launched the game I noticed something weird happening with the medkits. I have a light attached to the medkit, so I can see where they spawn in walls (if it happens).
I've been getting a TON of medkits spawning in the same area (inside a wall). I can see this because the light is super dense (should not be; many instances on top of eachother).

Another issue is medkits spawning together in bunched groups (they spawn really close to eachother). Is there any way to solve these issues?
I've included a screenshot below to help with understanding my mess above.

Thanks!
 
D

DarthTenebris

Guest
The problem with finding random coordinates prior to actually creating an instance is that you get only a single pixel to check for collisions at. It is possible that a position exactly one pixel (or a few pixels, for that matter) to the left of a solid instance is found. Although that position is free of collisions, but when you create an instance, it would overlap with the solid one. Methods exist to use the mask instead but they are unnecessarily complicated. So I'd suggest creating an instance first, then finding a free position for it.

The solution that @Fat_Man3468800 offered is viable, but it has some problems and typos which I'd like to point out. First, randomize should be called only once at game start, not every time you need to use a random function. In your (OP's) case, it is being called in the Create event. I'd suggest moving it to a Game Start event to avoid weird flaws in future. Second, irandom takes a single argument, unlike irandom_range. Third, consider making the until statement an actual statement, not a block.

Code:
with (instance_create(x, y, obj_medikit)) {
    do {
        x = irandom(room_width);
        y = irandom(room_height);
     }
    until (place_free(x, y));
}
Thank you for correcting me :) Nobody is perfect, we're all still learning. :)

@Gamerev147 To solve that, simply add a proximity check to the loop. If it is too close, randomize again, else keep the coordinates.
Code:
...
until ((place_free(x, y)) && (distance_to_object(obj_medikit) > minimum_separation_distance));
Apologies if the code doesn't work as expected, but at least you get the logic.
 
Top