ThisThing
Member
Mar 24, 2024
- #1
I am using this loop:
GML:
var _val = 80;for (var i = 0; i < 30; i++) { var _xx = irandom_range(-_val, _val); var _yy = irandom_range(-_val, _val); dest_x = x + _xx; dest_y = y + _yy; // loop if target location is inside solid object while collision_circle(dest_x, dest_y, 32, o_solid, 1, 0) { _xx = irandom_range(-_val, _val); _yy = irandom_range(-_val, _val); dest_x = x + _xx; dest_y = y + _yy; }}
Desc: It is pretty much taken straight from the manual. What I am doing, or trying to do properly, is to get a y / x location that is not inside a solid object (dest_x and dest_y). I then have an 'entity' object move to that location.
Question: What would be a better approach than using the 'i < 30' that I am using? I mean, what if a location outside a solid has not been found within 30 steps? I could just increase the number of steps to check, but are there not a better way?
Any help is much appreciated.
Yal
🐧 *penguin noises*
GMC Elder
Mar 24, 2024
- #2
The right answer here depends a bit on how the rest of your game works, for instance you could store a list of all valid positions and then pick one of those randomly, but it becomes impractical if things spawn/move a lot (and invalidates those positions each time).
Also since you only check at a range of up to 80 pixels away, if enough of these things spawn at roughly the same area there might be literally no valid positions left after a while. One idea to fix this would be to increase "val" by 10% each time you fail, eventually it'll grow big enough that your random position is free even if it means this object needs to spawn outside the room.
Another idea is to spawn the things at x, y and not check for collisions at all, but the objects has a collision event that moves them out of solid objects by XYZ distance each step (you could even give them a little bouncy animation or something to make it look like they bounce off the obstacles). Finding the direction to move is gonna be tricky if you don't wanna do collision checks everywhere, but a safe assumption if these objects are items you want to pick up would be something like, "pick the direction towards the player, add a random value between -25 and 25 degrees" - if they're stuck on spawn, they move in this direction until they're not.
RefresherTowel
Member
Mar 24, 2024
- #3
GML:
var _dest_x, _dest_y, _max_loops = 1000, _val = 80;do { _dest_x = x + irandom_range(-_val, _val); _dest_y = y + irandom_range(-_val, _val); _max_loops--;}until (!collision_circle(_dest_x, _dest_y, 32, o_solid, 1, 0) || _max_loops <= 0);
That'll run either 1000 loops or until collision circle is free. You can tell which happened by checking the value of _max_loops
. If it's 0 or less, it didn't find a place, otherwise _dest_x
and _dest_y
are free.
ThisThing
Member
Mar 24, 2024
- #4
RefresherTowel said:
GML:
var _dest_x, _dest_y, _max_loops = 1000, _val = 80;do { _dest_x = x + irandom_range(-_val, _val); _dest_y = y + irandom_range(-_val, _val); _max_loops--;}until (!collision_circle(_dest_x, _dest_y, 32, o_solid, 1, 0) || _max_loops <= 0);
That'll run either 1000 loops or until collision circle is free. You can tell which happened by checking the value of
_max_loops
. If it's 0 or less, it didn't find a place, otherwise_dest_x
and_dest_y
are free.
Okay, I'll try this right away. What will happen, however, if a free space is not found after 1000 loops? Just in theory?
ThisThing
Member
Mar 24, 2024
- #5
Yal said:
The right answer here depends a bit on how the rest of your game works, for instance you could store a list of all valid positions and then pick one of those randomly, but it becomes impractical if things spawn/move a lot (and invalidates those positions each time).
Also since you only check at a range of up to 80 pixels away, if enough of these things spawn at roughly the same area there might be literally no valid positions left after a while. One idea to fix this would be to increase "val" by 10% each time you fail, eventually it'll grow big enough that your random position is free even if it means this object needs to spawn outside the room.
Another idea is to spawn the things at x, y and not check for collisions at all, but the objects has a collision event that moves them out of solid objects by XYZ distance each step (you could even give them a little bouncy animation or something to make it look like they bounce off the obstacles). Finding the direction to move is gonna be tricky if you don't wanna do collision checks everywhere, but a safe assumption if these objects are items you want to pick up would be something like, "pick the direction towards the player, add a random value between -25 and 25 degrees" - if they're stuck on spawn, they move in this direction until they're not.
Okay, I will explain further:
It is a top-down (like GTA2) and this code is for the enemy. When the enemy reaches dest_x / dest_y it count down to when to change location. Then I run this code to find an area around the enemy itself to go to. I use mp_potential so I want to avoid any dest_x/dest_y inside a solid object.
Solid object will not be able to spawn during gameplay (and are not planned to do so). This code is more to find a free destination, and not so much spawning things.
However, I am interested in the way you increase the radius by 10% each fail. That is a cool little trick.
RefresherTowel
Member
Mar 24, 2024
- #6
ThisThing said:
Okay, I'll try this right away. What will happen, however, if a free space is not found after 1000 loops? Just in theory?
Using that immediate code, nothing will happen beyond the loop ending. However, if you are going to then go on and try to create an instance using _dest_x
and _dest_y
as that instances starting position, then the instance will be created on top of some obstacle somewhere (because there was no valid free space found). You would use the value of _max_loops
to determine if you can create an instance or not. If _max_loops
is less than or equal to 0 then you did not find a valid space, and therefore you should not try to create the instance (or, at least, you should be aware that if you do create an instance it will be colliding with something). However, if _max_loops
is any positive number, then you know the loop ended because there was a free space found, instead of _max_loops
hitting 0, which means that _dest_x
and _dest_y
are holding a valid position that doesn't have a collision registering and you can create an instance there knowing it won't be colliding with any o_solid
instances.
That's all assuming the point is to create an instance in a free spot. But no matter the actual end goal, you know what your two potential outcomes are. _max_loops
> 0, no collisions were found, else if _max_loops
<= 0 no valid space could be found within the number of loops it tried.
ThisThing
Member
Mar 25, 2024
- #7
RefresherTowel said:
Using that immediate code, nothing will happen beyond the loop ending. However, if you are going to then go on and try to create an instance using
_dest_x
and_dest_y
as that instances starting position, then the instance will be created on top of some obstacle somewhere (because there was no valid free space found). You would use the value of_max_loops
to determine if you can create an instance or not. If_max_loops
is less than or equal to 0 then you did not find a valid space, and therefore you should not try to create the instance (or, at least, you should be aware that if you do create an instance it will be colliding with something). However, if_max_loops
is any positive number, then you know the loop ended because there was a free space found, instead of_max_loops
hitting 0, which means that_dest_x
and_dest_y
are holding a valid position that doesn't have a collision registering and you can create an instance there knowing it won't be colliding with anyo_solid
instances.That's all assuming the point is to create an instance in a free spot. But no matter the actual end goal, you know what your two potential outcomes are.
_max_loops
> 0, no collisions were found, else if_max_loops
<= 0 no valid space could be found within the number of loops it tried.
Ah, that makes total sense! What a good idea.
I am just finding a free spot to move to here, but the idea to use _max_loops that way is so simple yet smart.
Thanks a lot.
You must log in or register to reply here.