GameMaker Help with randomize() [SOLVED]

N

nlolotte

Guest
Hello,

I am working on an enemy object spawner.

I have an object called obj_spawn region which can spawn enemies anywhere between the object x and y.

Code:
var view_x = camera_get_view_x(view_camera[0]);
var view_y = camera_get_view_y(view_camera[0]);
var view_w = camera_get_view_width(view_camera[0]);
var view_h = camera_get_view_height(view_camera[0]);

if spawn_count < max_spawn_count
{
    if (point_in_rectangle(x, y, view_x, view_y, view_x + view_w, view_y + view_h))
    {
        scr_spawn_enemy(id);
        spawn_count +=1
        show_debug_message("spawned")
    }
}
I pass the object id into a script, scr_spawn_enemy
Code:
xmin = argument0.x;
xmax = xmin + argument0.sprite_width;
instance_create_layer(irandom_range(argument0.xmin,argument0.xmax),y,"Enemies",obj_enemy_respawn_spawner)
The trouble I am getting is that the enemy spawns at the same place every time it respawns. This does change each time I restart the game. I have debugged using random_get_seed and can see a new seed generates upon restart. My question is how can I make the enemy object spawn in a different location every new spawn?

Thanks in advance.
 
D

Drago the Shinigami

Guest
Did you try the function randomize() ? I don't see it in your code.
 
D

Drago the Shinigami

Guest
Perhaps you shouldn't have it in the create event; it only works once per call. Perhaps the step events might work.
 
T

ThePropagation

Guest
I see a few problems with your code. First, your xmax is only adding the sprite_width to the xmin. So there's not a lot if difference in that. Second in the random range you don't need to say "argument0.xmin" and "argument0.xmax" just say xmin and xmax, and you will get a random in between those values. but that goes back to the first problem, you're not creating a wide range for yourself to randomize.

"
 
Last edited by a moderator:

JasonTomLee

Member
Hello,

I am working on an enemy object spawner.

I have an object called obj_spawn region which can spawn enemies anywhere between the object x and y.

Code:
var view_x = camera_get_view_x(view_camera[0]);
var view_y = camera_get_view_y(view_camera[0]);
var view_w = camera_get_view_width(view_camera[0]);
var view_h = camera_get_view_height(view_camera[0]);

if spawn_count < max_spawn_count
{
    if (point_in_rectangle(x, y, view_x, view_y, view_x + view_w, view_y + view_h))
    {
        scr_spawn_enemy(id);
        spawn_count +=1
        show_debug_message("spawned")
    }
}
I pass the object id into a script, scr_spawn_enemy
Code:
xmin = argument0.x;
xmax = xmin + argument0.sprite_width;
instance_create_layer(irandom_range(argument0.xmin,argument0.xmax),y,"Enemies",obj_enemy_respawn_spawner)
The trouble I am getting is that the enemy spawns at the same place every time it respawns. This does change each time I restart the game. I have debugged using random_get_seed and can see a new seed generates upon restart. My question is how can I make the enemy object spawn in a different location every new spawn?

Thanks in advance.

I dont know why " argument0.xmin " is necessary. I think GMS reads both the variables as argument0 because the xmin & xmax variables aren't a part of argument0. So instead try changing it to:
Code:
instance_create_layer(irandom_range( xmin, xmax ),y,"Enemies",obj_enemy_respawn_spawner)
A small heads up, your Y position is the same so don't expect it to be randomized. Hope it helps!
 
N

nlolotte

Guest
Thanks for the help people,

I see a few problems with your code. First, your xmax is only adding the sprite_width to the xmin. So there's not a lot if difference in that. Second in the random range you don't need to say "argument0.xmin" and "argument0.xmax" just say xmin and xmax, and you will get a random in between those values. but that goes back to the first problem, you're not creating a wide range for yourself to randomize.

"
This is an oversight by me. Looking at it now I could just write xmin and xmax.
try putting randomize() in the room creation event
I will try this but I’m sure the room creation happens after the object create event?

I dont know why " argument0.xmin " is necessary. I think GMS reads both the variables as argument0 because the xmin & xmax variables aren't a part of argument0. So instead try changing it to:
Code:
instance_create_layer(irandom_range( xmin, xmax ),y,"Enemies",obj_enemy_respawn_spawner)
A small heads up, your Y position is the same so don't expect it to be randomized. Hope it helps!
Looking at my code I realised I only need to write xmin and xmax because the argument is already declared. The y position is static to prevent enemies spawning in the floor.
 

Ido-f

Member
Just checked and sprite_width returns 0 when no sprite is assigned.
Does your spawner object have a sprite assigned to it?
If not, xmin and xmax would be the same number.

Btw, it seems that you're confused about how variable scope works in scripts.
You don't need to pass the id to scr_spawn_enemy when you only use it to reference id.x and id.sprite width -
scr_spawn_enemy is still being run by the same instance so you can simply use x and sprite_width.
 
Last edited:
N

nlolotte

Guest
Just checked and sprite_width returns 0 when no sprite is assigned.
Does your spawner object have a sprite assigned to it?
If not, xmin and xmax would be the same number.

Btw, it seems that you're confused about how variable scope works in scripts.
You don't need to pass the id to scr_spawn_enemy when you only use it to reference id.x and id.sprite width -
scr_spawn_enemy is still being run by the same instance so you can simply use x and sprite_width.
Yes, the spawner has a sprite. So I don’t need to pass the Id even though I have multiple instances in the same room?
 

JasonTomLee

Member
Regarding passing ids, I'd recommend saving the instance as a separate variable if you want to do anything with it!
Even the randomized x_coordinate should be set as a variable to optimize your workflow & prevent any code repetition.

Here's an example:

Code:
var x_rand = irandom_range( xmin, xmax );
//var y_rand = irandom_range( ymin, ymax );
var y_rand = y;

var OBJ = instance_create_layer( x_rand, y_rand,"Enemies",obj_enemy_respawn_spawner)

OBJ.x = //you can adjust its coords here as well
OBJ.Y = //

// or you can call them inside the object as well using the With statement

with( OBJ ){
x = //randomize coords
y = //
}
From the looks of it, it seems like you're almost done solvin this cookie :D Any other questions man?
 
@Drago the Shinigami randomise() does not "only work once per call"...I'm not even sure what that would mean. When you boot up a GMS game, GMS automatically assigns a seed that it uses to power it's random*() functions. While you are running your game in the GMS IDE, it chooses the SAME seed each run (this is to make debugging easier, as weird behaviour could be caused by a different seed, rather than incorrect code, so it's useful to have it run with always the same seed for debugging puproses). When you call randomise() you are forcing the game to choose an ACTUAL random seed, instead of the default seed that GM chooses. This applies throughout the entire of the rest of the runtime for the game. If you are calling randomise() in any point that doesn't ONLY happen once in the entire runtime of the game (i.e. a Step Event or the Create Event of an object that is spawned multiple times) you are changing the seed multiple times in the same run, which can lead to unwanted behaviour and make debugging harder. Only call it once ever.

When you actually properly compile your game, I believe the randomise() line is not needed as the game will choose a true random seed when it's run from it's compiled version (though it's not necessary to remove the randomise() function if you are actually compiling the finished product).
 
N

nlolotte

Guest
Regarding passing ids, I'd recommend saving the instance as a separate variable if you want to do anything with it!
Even the randomized x_coordinate should be set as a variable to optimize your workflow & prevent any code repetition.

Here's an example:

Code:
var x_rand = irandom_range( xmin, xmax );
//var y_rand = irandom_range( ymin, ymax );
var y_rand = y;

var OBJ = instance_create_layer( x_rand, y_rand,"Enemies",obj_enemy_respawn_spawner)

OBJ.x = //you can adjust its coords here as well
OBJ.Y = //

// or you can call them inside the object as well using the With statement

with( OBJ ){
x = //randomize coords
y = //
}
From the looks of it, it seems like you're almost done solvin this cookie :D Any other questions man?
Thank you for your help. I have amended my code but I still get the enemies respawning in the same place until I restart the game. Here is a video, watch the enemy spawn location. They should change every time but remain the same until the game is restarted and a different seed is generated.


It seems the x is still not being randomised. Here is my new script:

Code:
xmin = x;
xmax = xmin + sprite_width;
var random_x = irandom_range(xmin,xmax)
instance_create_layer(random_x,y,"Enemies",obj_enemy_respawn_spawner)
spawn_count +=1
show_debug_message("spawned")
 

chamaeleon

Member
@nlolotte Perhaps you can create a throwaway project for the sole purpose of testing randomize, irandom, etc. Ensure that you can get different random number sequences every time you start that project. Then apply what you have to your game and do extensive logging of what calls are made and what the values are of all involved variables and what your sequence of numbers are. Don't rely on visually observing your game, output debug values.
 
N

nlolotte

Guest
I need to stop coding early in the morning. I had the enemy destroy object returning the enemy to xstart which therefore meant the randomness would only happen on the first spawn. Since I've fixed that I now need to work out a way to tell which enemy spawned from which spawner so when I deduct from spawn count upon enemy destroy event it does so from the correct spawner. Any help with this would be appreciated.
 
Last edited:
T

ThePropagation

Guest
in the enemy creation code (hopefully inside the enemy spawner object code this

Code:
with (instance_create_layer(x, y, "Layer", enemy)
{
         host = other.id
}
then in your enemy destroy code

Code:
host.spawn_count -= 1
 
N

nlolotte

Guest
in the enemy creation code (hopefully inside the enemy spawner object code this

Code:
with (instance_create_layer(x, y, "Layer", enemy)
{
         host = other.id
}
then in your enemy destroy code

Code:
host.spawn_count -= 1
I had the host = other.id part then you helped me get the rest. Thank you everyone for all your input. I really appreciate the help.
 
T

Taddio

Guest
Perhaps you shouldn't have it in the create event; it only works once per call. Perhaps the step events might work.
Don't ever do that, this is like the Guiness Recold Holder for a bad advice about randomize();
I mean, a mouse-wheel click on the function would have avoided making you look not so bright for a moment, sorry to say, bro!
 
N

nlolotte

Guest
Don't ever do that, this is like the Guiness Recold Holder for a bad advice about randomize();
I mean, a mouse-wheel click on the function would have avoided making you look not so bright for a moment, sorry to say, bro!
@Drago the Shinigami randomise() does not "only work once per call"...I'm not even sure what that would mean. When you boot up a GMS game, GMS automatically assigns a seed that it uses to power it's random*() functions. While you are running your game in the GMS IDE, it chooses the SAME seed each run (this is to make debugging easier, as weird behaviour could be caused by a different seed, rather than incorrect code, so it's useful to have it run with always the same seed for debugging puproses). When you call randomise() you are forcing the game to choose an ACTUAL random seed, instead of the default seed that GM chooses. This applies throughout the entire of the rest of the runtime for the game. If you are calling randomise() in any point that doesn't ONLY happen once in the entire runtime of the game (i.e. a Step Event or the Create Event of an object that is spawned multiple times) you are changing the seed multiple times in the same run, which can lead to unwanted behaviour and make debugging harder. Only call it once ever.

When you actually properly compile your game, I believe the randomise() line is not needed as the game will choose a true random seed when it's run from it's compiled version (though it's not necessary to remove the randomise() function if you are actually compiling the finished product).
Man, these guitar players going in haha
 
T

Taddio

Guest
Bro, try to learn to play an instrrument and have the balls to come back and tell me programming's hard after that;)
 
D

Drago the Shinigami

Guest
@Drago the Shinigami randomise() does not "only work once per call"...I'm not even sure what that would mean. When you boot up a GMS game, GMS automatically assigns a seed that it uses to power it's random*() functions. While you are running your game in the GMS IDE, it chooses the SAME seed each run (this is to make debugging easier, as weird behaviour could be caused by a different seed, rather than incorrect code, so it's useful to have it run with always the same seed for debugging puproses). When you call randomise() you are forcing the game to choose an ACTUAL random seed, instead of the default seed that GM chooses. This applies throughout the entire of the rest of the runtime for the game. If you are calling randomise() in any point that doesn't ONLY happen once in the entire runtime of the game (i.e. a Step Event or the Create Event of an object that is spawned multiple times) you are changing the seed multiple times in the same run, which can lead to unwanted behaviour and make debugging harder. Only call it once ever.

When you actually properly compile your game, I believe the randomise() line is not needed as the game will choose a true random seed when it's run from it's compiled version (though it's not necessary to remove the randomise() function if you are actually compiling the finished product).
Don't ever do that, this is like the Guiness Recold Holder for a bad advice about randomize();
I mean, a mouse-wheel click on the function would have avoided making you look not so bright for a moment, sorry to say, bro!
I apologize for my bad advice, I misunderstood the function. I am sincerely sorry for any confusion I might have caused, I am still relatively new and shouldn't have tried to answering without knowing for sure, I made some assumptions I shouldn't have made, and even though I didn't know about the mouse wheel click, I know I made a mistake. I'm sorry.
 
Top