• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Legacy GM Help with picking random objects

G

GMNoob

Guest
hi i need help with something.

in each of my rooms, i want to have 4 obj_bonus_spawn_point at random locations in the room, but they must only spawn at certain desired locations i have chosen beforehand.

for instance, in my first room i have created 10 obj_bonus_spawn_point at my desired locations.
now what i want to do is have the game randomly pick 4 of these obj_bonus_spawn_point, while destroying the other 6.

is there a smart way i can code this, and also so that in future rooms it will also pick 4, regardless of the number of spawn points i chose to set?
 

jo-thijs

Member
Have some controller object execute this code in its room start event:
Code:
var o = obj_bonus_spawn_point;
var n = instance_number(o);
var r1 = irandom(n - 1);
var r2 = irandom(n - 2);
var r3 = irandom(n - 3);
var r4 = irandom(n - 4);
if r2 >= r1
    r2++;
if r3 >= r1
    r3++;
if r3 >= r2
    r3++;
if r4 >= r1
    r4++;
if r4 >= r2
    r4++;
if r4 >= r3
    r4++;
var i1 = instance_find(o, r1);
var i2 = instance_find(o, r2);
var i3 = instance_find(o, r3);
var i4 = instance_find(o, r4);
with o
    if id != i1 && id != i2 && id != i3 && id != i4
        instance_destroy();
And use randomize() once in your game.

Alternatively, you could put the id of every instance of type obj_bonus_spawn_point in a ds_list
and then shuffle the list, start from index 4 and destroy every instance in the list starting from that index.
 
G

GMNoob

Guest
thank you for your fast response. i added the code in my controller object and it almost works, but there is one flaw which is that sometimes it will only spawn 3 obj_bonus_spawn_point (i restarted the room several times to test this). do you know how i can solve this?
 

jo-thijs

Member
My bad, I was in a rush and couldn't double check and my code is indeed not always correct.
It should have been:
Code:
var o = obj_bonus_spawn_point;
var n = instance_number(o);
var r1 = irandom(n - 1);
var r2 = irandom(n - 2);
var r3 = irandom(n - 3);
var r4 = irandom(n - 4);
if r4 >= r3
    r4++;
if r4 >= r2
    r4++;
if r3 >= r2
    r3++;
if r4 >= r1
    r4++;
if r3 >= r1
    r3++;
if r2 >= r1
    r2++;
var i1 = instance_find(o, r1);
var i2 = instance_find(o, r2);
var i3 = instance_find(o, r3);
var i4 = instance_find(o, r4);
with o
    if id != i1 && id != i2 && id != i3 && id != i4
        instance_destroy();
 

TheouAegis

Member
Code:
var i = 0, n = choose(irandom_range(1,16), irandom_range(18, 32) & ~1, (irandom_range(36,48) & ~3) - irandom(1), 52+irandom(4)*4) * 15;
while i < 10
{
    if !(n & 1)
        instance_deactivate_object(instance_find(obj_bonus_spawn_point,i));
    i++;
    n = n >> 1;
}

This SHOULD work - all the numbers match up for me from what I can tell - but it's not working on my PC right now. Maybe it will work in a clean project. Give it a whirl for giggles.
 
G

GMNoob

Guest
hey again mate. i tested the new code you gave me and it works perfectly, so thank you a lot, really appreciate the help :) i will admit though that by studying your first post i actually found a way to do it myself in the meantime, which i would like to share with you, since this is perhaps a simpler way.

in the room start event for my controller object:
Code:
//Checks if it should choose random spawns
if instance_number(obj_bonus_spawn_point) > 4
{
script_execute(script_spawn)
}
and my script:
Code:
while instance_number(obj_bonus_spawn_point) > 4
{
n=random(ceil(instance_number(obj_bonus_spawn_point)))
d=instance_find(obj_bonus_spawn_point,n)
with (d) {instance_destroy()}
}
i didn't know about the instance_find function before i looked it up after seeing your post (im new to GML, been playing with it for about a month now) so its cool to learn really useful stuff like this :) again, thanks a lot!
 
G

GMNoob

Guest
thank you too for your reply
TheouAegis. i would love to try, but its not necessary anymore because i got it fixed :D
 

jo-thijs

Member
Code:
var i = 0, n = choose(irandom_range(1,16), irandom_range(18, 32) & ~1, (irandom_range(36,48) & ~3) - irandom(1), 52+irandom(4)*4) * 15;
while i < 10
{
if !(n & 1)
instance_deactivate_object(instance_find(obj_bonus_spawn_point,i));
i++;
n = n >> 1;
}
This SHOULD work - all the numbers match up for me from what I can tell - but it's not working on my PC right now. Maybe it will work in a clean project. Give it a whirl for giggles.
The giggles were had.
Rewrote your code to:
Code:
var n = choose(irandom_range(1, 16), irandom_range(9, 16) * 2, irandom_range(9, 12) * 4 - irandom(1), irandom_range(13, 17) * 4) * 15;
for(var i = 0; i < 10; i++) {
    if n & 1 == 0
        instance_deactivate_object(instance_find(obj_bonus_spawn_point, i));
    n = n >> 1;
}
I mean, it's so obvious now it works!
How can you not tell only 4 bonus spawn points will remain?
Oh wait, only at most 10 spawn points will get deactivated, so if there are at least 15 spawn points, this code can't work...
Where did the logic go wrong?!? :confused:

hey again mate. i tested the new code you gave me and it works perfectly, so thank you a lot, really appreciate the help :) i will admit though that by studying your first post i actually found a way to do it myself in the meantime, which i would like to share with you, since this is perhaps a simpler way.

in the room start event for my controller object:
Code:
//Checks if it should choose random spawns
if instance_number(obj_bonus_spawn_point) > 4
{
script_execute(script_spawn)
}
and my script:
Code:
while instance_number(obj_bonus_spawn_point) > 4
{
n=random(ceil(instance_number(obj_bonus_spawn_point)))
d=instance_find(obj_bonus_spawn_point,n)
with (d) {instance_destroy()}
}
i didn't know about the instance_find function before i looked it up after seeing your post (im new to GML, been playing with it for about a month now) so its cool to learn really useful stuff like this :) again, thanks a lot!
That's the kind of thing we like best at the GMC!
You're welcome!

EDIT: @TheouAegis, it actually just occured to me,
was that comment a hint at me that I didn't explain my code?
 
P

ParodyKnaveBob

Guest
I'm glad you're learning and applying to create your own solutions that work, GMNoob! $:^ ]

Just a heads-up, though:
Code:
n=random(ceil(instance_number(obj_bonus_spawn_point)))
d=instance_find(obj_bonus_spawn_point,n)
This accidentally works because apparently instance_find() uses the integer from n for that argument. Here's what the line above actually does:

Code:
n = random(ceil(instance_number(obj_bonus_spawn_point))); // assign to n any random floating point number that's >= 0 and < number of spawn point instances

n = // assign to n
    random( // return ANY random floating point number that's >= 0 and < the following argument...
        ceil( // return the following argument after rounding it up to nearest integer
            instance_number( // return the integer count of instances from the following argument...
                obj_bonus_spawn_point // object index for your spawn point
            )
        )
    );
You'll notice you're rounding an integer to an integer, then finding any random number, most likely with trailing decimals... What you more likely intended:

Code:
n = ceil(random(instance_number(obj_bonus_spawn_point))); // assign to n any random integer from 1 to the number of spawn point instances
...which means you'd probably want the result of floor() instead of ceil() (to get 0 to number-1 instead of 1 to number), and which also means another way to go about this is to use the irandom() function which, coming from a BASIC background from thirty years ago, I absolutely love. $E^ J

Code:
n = irandom(instance_number(obj_bonus_spawn_point) - 1); // assign to n any random integer from 0 to 1-less-than-spawn-instances-count
Little things, little things, but I hope this helps,
Bob $:^ J

P.S. Don't forget to change this topic's prefix from "GM: Studio" to "SOLVED"! $:^ b
 
Last edited by a moderator:

TheouAegis

Member
The giggles were had.
Rewrote your code to:
Code:
var n = choose(irandom_range(1, 16), irandom_range(9, 16) * 2, irandom_range(9, 12) * 4 - irandom(1), irandom_range(13, 17) * 4) * 15;
for(var i = 0; i < 10; i++) {
    if n & 1 == 0
        instance_deactivate_object(instance_find(obj_bonus_spawn_point, i));
    n = n >> 1;
}
I mean, it's so obvious now it works!
How can you not tell only 4 bonus spawn points will remain?
Oh wait, only at most 10 spawn points will get deactivated, so if there are at least 15 spawn points, this code can't work...
Where did the logic go wrong?!? :confused:



That's the kind of thing we like best at the GMC!
You're welcome!

EDIT: @TheouAegis, it actually just occured to me,
was that comment a hint at me that I didn't explain my code?

The op had 10 spawn points. 15*irandom_range(1,64) creates a 10 bit value. The various irandom choices within that range will only yield values with just 4 bits set. So while i<10 is to loop through the 10 bits. For each bit that isn't set, deactivate instance_find(object, i). At the end, there will be 6 deactivated and 4 still active.

It worked for me at first, but then stopped working for some reason. I had 10 objects in my room, ran the code, verified n was a value with exactly 4 bits set, but the wrong instances were deactivated. It was acting like 5 bits were set.
 

jo-thijs

Member
Ah, but the OP also asked:
is there a smart way i can code this, and also so that in future rooms it will also pick 4, regardless of the number of spawn points i chose to set?
Also, the multiplying a number between 1 and 16 with 15 is quite a genius trick for getting 4 bits checked (I realize it is in the same vane as the trick for checking if a number is dividable by 9, but I didn't think of it before).
I also understand why you use irandom_range(9, 16) * 2, as it allows using 1 extra bit of the 10 bits (so now 9 bits in total are used).
I don't understand the subtracting of irandom(1) though, nor the irandom_range(13, 17).
I feel like this might be part of the problem it doesn't always work.
I can also see that not every possible selection of spawn points are considered by this approach.

Another thing that makes me think this doesn't always work, is that you let i increase to 10 instead of decrease to 0.
However, I believe deactivating instances influences the function instance_find.
If i == 9 would need to be deactivated, then you would provide instance_find with an index out of bounds.

Nonetheless, the multiplying with 15 trick is a neat one I might use in the future.
 

TheouAegis

Member
Ah! instance_find was getting jacked up! That would make sense! I'll double check it again.

Update:
Another thing that makes me think this doesn't always work, is that you let i increase to 10 instead of decrease to 0.
However, I believe deactivating instances influences the function instance_find.
If i == 9 would need to be deactivated, then you would provide instance_find with an index out of bounds.
THAT WAS IT! You found my logic error!


If you have Win10, open the calculator, go to Programmer Mode, make sure you're in DEC, type 15+15=, then keep pressing = over and over, paying attention to the BIN value. After a while, the number of bits will increase for certain numbers. I tried to work out algorithmic patterns for avoiding those particular numbers.But yeah... It wasn't perfect; just something I came up with while waiting until I had to get ready for work.
 
Last edited:
Top