GameMaker How to make a group of the same object appear randomly?

A

Artwark

Guest
obj_controller

randomize();
if !instance_exists(obj_coin)
{
coins = 1;

instance_create_layer(random(room_width),random(room_height),"layer_coin",obj_coin);
instance_create_layer(random(room_width),random(room_height),"layer_coin",obj_coin);
instance_create_layer(random(room_width),random(room_height),"layer_coin",obj_coin);
instance_create_layer(random(room_width),random(room_height),"layer_coin",obj_coin);
/*instance_create_layer(grow1,grow1,"layer_coin",obj_coin);
instance_create_layer(grow2,grow2,"layer_coin",obj_coin);
instance_create_layer(grow3,grow3,"layer_coin",obj_coin);
instance_create_layer(grow4,grow4,"layer_coin",obj_coin);
instance_create_layer(grow5,grow5,"layer_coin",obj_coin);*/
}
else
coin =0;

The problem with this code is that the coins appear but they don't appear within the game and they collide with the other objects meaning that you can't get the coins. How do I fix this?
 

samspade

Member
While you'd have to modify it to fit exactly what you want, generally you would do something like this:

Code:
if (you want to create something) {
    pick a random xx and yy
    while (there is a collision with xx and yy) {
        pick new position
    }
    create object
}
also, using a repeat would be better than copying the line several times, and for this type of collision checking unless you should probably add a counter to your while loop so that it can't get stuck in an infinite loop trying to spawn an object.
 
A

Artwark

Guest
While you'd have to modify it to fit exactly what you want, generally you would do something like this:

Code:
if (you want to create something) {
    pick a random xx and yy
    while (there is a collision with xx and yy) {
        pick new position
    }
    create object
}
also, using a repeat would be better than copying the line several times, and for this type of collision checking unless you should probably add a counter to your while loop so that it can't get stuck in an infinite loop trying to spawn an object.
Ok so I did it like this and still nothing happens....

Code:
randomize();
if !instance_exists(obj_coin)
{
xx = random(room_width);
yy = random(room_height);

while place_meeting(x,y,obj_wall)
{
xx = random(room_width+100);
yy = random(room_height+100);
}
coin = 1;
repeat(5)
instance_create_layer(random(room_width),random(room_height),"layer_coin",obj_coin);
}
else
{
coin = 0;
}
They still don't appear in groups and when I collect all the objects, they now won't respawn...
 

samspade

Member
Ok so I did it like this and still nothing happens....

Code:
randomize();
if !instance_exists(obj_coin)
{
xx = random(room_width);
yy = random(room_height);

while place_meeting(x,y,obj_wall)
{
xx = random(room_width+100);
yy = random(room_height+100);
}
coin = 1;
repeat(5)
instance_create_layer(random(room_width),random(room_height),"layer_coin",obj_coin);
}
else
{
coin = 0;
}
They still don't appear in groups and when I collect all the objects, they now won't respawn...
There are a lot of problems with how you've done it this time. I would try it the way I suggested instead.
 
W

warbo

Guest
I still don't understand the code that you suggested....
You need to read what he has put, it's not code but pseudo. Samspade has basically walked you through his method and what you need to call for each part so if you read it slowly line by line you will understand what is happening.

Doing this is better for yourself as you will learn more than if he just gave you the code for it.
 

samspade

Member
I still don't understand the code that you suggested....
It would be more helpful to work through the code I posted, but here are some pointers:
  • Not indenting your code is bad form. It makes it harder to read.
  • Randomize isn't in my code. While it's not really important one way or the other, you generally should only call it once at the start of your game, putting it here doesn't make much sense.
  • The first thing you did is what I suggested - picked a condition for spawning
  • The second portion is also what I suggested - picked an xx and yy
  • Your collision checking directly contradicts what I suggested and I'm little surprised your game doesn't freeze. You're not using xx yy for collision checking, and you're using the wrong collision checking function.
  • I'm not sure what this coin 1, coin 0 is doing, but it'll only be true for one frame. Next frame, after the coins exist, it will be false.
  • Your repeat doesn't have brackets - while not a problem code wise, combined with the fact that you don't indent, this is really bad form.
  • More importantly the two biggest issues are here. First, you don't actually use your xx yy here. You just pick a new location so your xx yy is pointless. Second, you shouldn't repeat just the instance create line as that will create everything in the same place, you should be repeating the whole process.
 
A

Artwark

Guest
Ok...so I tried this

randomize();
if !instance_exists(obj_coin)
{
xx = random(x);
yy = random(y);

while place_meeting(xx,yy,obj_wall)
{
xx = move_towards_point(x,y,1);
yy = move_towards_point(x,y,1);
}
coin = 1;
repeat(5)
instance_create_layer(random(room_width),random(room_height),"layer_coin",obj_coin);
}
else
{
coin = 0;
}

Still no sign of it working.
 

samspade

Member
It makes sense that your code didn't work because there are a lot of problems with it. I would use the code and ideas I suggested. Additionally,
  • Your randomly chosen xx, yy doesn't make a lot of sense.
  • You're still using the wrong collision check, now I'm very surprised your game doesn't crash
  • why are you changing your method of choosing xx, yy in your while loop? it should be the same
  • you didn't move the repeat
  • you didn't use xx or yy in your instance create
 
A

Artwark

Guest
Ok so now I tired this one... and now the game doesn't work.

Code:
if coins == 1
{
    xx = 100;
    yy = 100;
    
while position_meeting(xx,yy,obj_wall)
{
xx = 100;
yy = 100;
}
//coin = 1;
repeat[5]
instance_create_layer(xx,yy,"layer_coin",obj_coin);
}
else
{
coins = 0;
}
 

samspade

Member
Ok so now I tired this one... and now the game doesn't work.

Code:
if coins == 1
{
    xx = 100;
    yy = 100;
 
while position_meeting(xx,yy,obj_wall)
{
xx = 100;
yy = 100;
}
//coin = 1;
repeat[5]
instance_create_layer(xx,yy,"layer_coin",obj_coin);
}
else
{
coins = 0;
}
Makes sense as you're basically telling it to crash. But that aside, you have fixed a number of the other problems.

Good changes:
  • Your using the correct collision checker
  • Your using xx and yy to spawn
Bad changes:
  • You've stopped picking new xx yy in the while loop. So if your first position is bad and in collision you never change, and you've created an endless loop. This is the code I would use in the while loop:
Code:
xx = random(room_width);
yy = random(room_height);

while (position_meeting(xx, yy, obj_wall)) {
    xx = random(room_width);
    yy = random(room_height);
}
  • You still haven't moved the repeat after being told three times that you should, additionally repeat doesn't use brackets
  • Your new check coin position is going to cause you trouble not only is it unclear when coins will equal 1, it's unclear how they will ever be 0.
  • You also still haven't indented things correctly
As a side note, you should probably use an exit statement with you're while loop so you don't get stuck in an infinite loop, but I'd get the basics working before you worry about that.
 

TheouAegis

Member
Personally I would just spawn the coins in and move them out of collisions. That way you will be using the coin's mask. And use irandom(), not (random), when working with coordinates. You also shouldn't spawn them too close to each other.

if coins == 1
{
repeat # of coins
{
with instance_create_layer(irandom(room_width), irandom(room_height), "layer_coin", obj_coin);

while place_meeting(x,y,all)
and distance_to_object(obj_coin) < minimum distance
{
x = irandom(room_width)
y = irandom(room_height)​
}​
}
coins = 0​
}


This method is still potentially very slow too. It can be improved by snapping everything to a grid. If you use tiles, the grid is the size of your tiles. You'd first define the size of the room grid:

var w = room_width div tile width,
h = room_height div tile height;

Then in the method i i post above, replace irandoms with

irandom(w) * tile width
irandom(h) * tile height
 
A

Artwark

Guest
Ok..so I did this and it somewhat works...

Code:
if !instance_exists(obj_coin)
{
    xx = random(room_width);
    yy = random(room_height);

while position_meeting(xx,yy,obj_wall)
{
xx = random(room_width);
yy = random(room_height);
}
//coin = 1;
repeat(5)
{
instance_create_layer(xx,yy,"layer_coin",obj_coin);
}
}
The only problem here is that all the five coins are joined together in the same position like as if its just one coin. Should I use the choose function to fix this or the random_range instead?
 

FrostyCat

Redemption Seeker
If you don't want them all spawning at the same place, simply offset the coordinates. That should have been obvious if you gave it any thought.
Code:
instance_create_layer(xx, yy, "layer_coin", obj_coin);
instance_create_layer(xx+32, yy, "layer_coin", obj_coin);
instance_create_layer(xx-32, yy, "layer_coin", obj_coin);
instance_create_layer(xx, yy+32, "layer_coin", obj_coin);
instance_create_layer(xx, yy-32, "layer_coin", obj_coin);
If you do intend to spawn over an area instead of a single point, make sure you also replace position_meeting() with something like collision_rectangle() that covers the area.
 

samspade

Member
Ok..so I did this and it somewhat works...

Code:
if !instance_exists(obj_coin)
{
    xx = random(room_width);
    yy = random(room_height);

while position_meeting(xx,yy,obj_wall)
{
xx = random(room_width);
yy = random(room_height);
}
//coin = 1;
repeat(5)
{
instance_create_layer(xx,yy,"layer_coin",obj_coin);
}
}
The only problem here is that all the five coins are joined together in the same position like as if its just one coin. Should I use the choose function to fix this or the random_range instead?
Neither. You should move the repeat function as instructed many times and as demonstrated by TheouAegis. Frostycat's suggestion is also good with a slightly different effect.
 

TheouAegis

Member
Go back up and look at my post. You aren't even do anything samspade has been telling you to do, you just keep posting the same code over and over and over. Look at how my code is structured and where the repeat is relative to the restof the code.

And as I said in my post, the difference between my code and what Sam was trying to get you to eventually figure out is your code is going to quite possibly not check for collisions properly because the collision check is within the object that is spawning the coins, not from the coins themselves. My code uses the coins themselves to check for collisions.

There is always a possibility thatthe while loop will freeze if it can't find a valid place to spawn the coins, but you only have five coins, so that shouldn't be an issue.
 
A

Artwark

Guest
Personally I would just spawn the coins in and move them out of collisions. That way you will be using the coin's mask. And use irandom(), not (random), when working with coordinates. You also shouldn't spawn them too close to each other.

if coins == 1
{
repeat # of coins
{
with instance_create_layer(irandom(room_width), irandom(room_height), "layer_coin", obj_coin);

while place_meeting(x,y,all)
and distance_to_object(obj_coin) < minimum distance
{
x = irandom(room_width)
y = irandom(room_height)​
}​
}
coins = 0​
}


This method is still potentially very slow too. It can be improved by snapping everything to a grid. If you use tiles, the grid is the size of your tiles. You'd first define the size of the room grid:

var w = room_width div tile width,
h = room_height div tile height;

Then in the method i i post above, replace irandoms with

irandom(w) * tile width
irandom(h) * tile height
Ok so I did this...

Code:
if coins == 1
{
    repeat(5)
    {
        instance_create_layer(irandom(room_width),irandom(room_height),"layer_coin",obj_coin);

while place_meeting(x,y,all) and distance_to_object(obj_coin) < 100
{
    x = irandom(room_width);
    y = irandom(room_height);
}
}
coins = 0;
}
I'm still facing the problem that the coins do not appear in groups as they appear in random positions. I want it so that if one spawns in one place, the others will spawn next to it.

Also, I got a doube regarding tiles. Are you suggesting that the objects have to be tiles for this to work better(i.e the coins?)

And I want to apologise for not following correctly as you and samspade have said so many times. I'll try to understand better in future. Thank you for your understanding.
 

FrostyCat

Redemption Seeker
The coins appeared in random positions because YOU TOLD THEM to appear in random positions. This is the part where you did that:
Code:
repeat(5)
   {
       instance_create_layer(irandom(room_width),irandom(room_height),"layer_coin",obj_coin);
I've made my point clear as to how to make them appear as a group, and anyone who reads instructions properly could have easily come up with someothing like this:
Code:
var xx, yy;
do {
  xx = irandom(room_width-96);
  yy = irandom(room_height-96);
} until (collision_rectangle(xx, yy, xx+96, yy+96, obj_wall, false, false) == noone)
instance_create_layer(xx+32, yy+32, "layer_coin", obj_coin);
instance_create_layer(xx+64, yy+32, "layer_coin", obj_coin);
instance_create_layer(xx, yy+32, "layer_coin", obj_coin);
instance_create_layer(xx+32, yy+64, "layer_coin", obj_coin);
instance_create_layer(xx+32, yy, "layer_coin", obj_coin);
Until you start critically proofreading your own code and stop taking blind shots, all you're doing is trolling us on purpose and wasting our time. If you want GMC members to continue helping you and not get into a bad mood in the process, STOP trolling us on purpose and wasting our time.
 
A

Artwark

Guest
The coins appeared in random positions because YOU TOLD THEM to appear in random positions. This is the part where you did that:
Code:
repeat(5)
   {
       instance_create_layer(irandom(room_width),irandom(room_height),"layer_coin",obj_coin);
I've made my point clear as to how to make them appear as a group, and anyone who reads instructions properly could have easily come up with someothing like this:
Code:
var xx, yy;
do {
  xx = irandom(room_width-96);
  yy = irandom(room_height-96);
} until (collision_rectangle(xx, yy, xx+96, yy+96, obj_wall, false, false) == noone)
instance_create_layer(xx+32, yy+32, "layer_coin", obj_coin);
instance_create_layer(xx+64, yy+32, "layer_coin", obj_coin);
instance_create_layer(xx, yy+32, "layer_coin", obj_coin);
instance_create_layer(xx+32, yy+64, "layer_coin", obj_coin);
instance_create_layer(xx+32, yy, "layer_coin", obj_coin);
Until you start critically proofreading your own code and stop taking blind shots, all you're doing is trolling us on purpose and wasting our time. If you want GMC members to continue helping you and not get into a bad mood in the process, STOP trolling us on purpose and wasting our time.
Ok first off, I did your code and it just ended up crashing for no reason. Secondly, I said I'm sorry and yeah I get that I did bad here.

I should have worded what I wanted right instead of saying random. What I really wanted is that I want objects to appear in groups randomly. So if one coin spawns in one position, then I would like other coins appear next to it. The problem is that there are coins that still collide with one another.

Ultimately this is what I have done...

Code:
xx = random(room_width);
    yy = random(room_height);
if!instance_exists(obj_coin)
{
instance_create_layer(xx, yy, "layer_coin", obj_coin);
instance_create_layer(xx+32, yy, "layer_coin", obj_coin);
instance_create_layer(xx-32, yy, "layer_coin", obj_coin);
instance_create_layer(xx, yy+32, "layer_coin", obj_coin);
instance_create_layer(xx, yy-32, "layer_coin", obj_coin);

while position_meeting(xx,yy,obj_wall)
{
xx = random(room_width);
yy = random(room_height);
}
}
I also tried the collision_rectangle as well but that also had problems as well.
 

samspade

Member
Ok first off, I did your code and it just ended up crashing for no reason. Secondly, I said I'm sorry and yeah I get that I did bad here.

I should have worded what I wanted right instead of saying random. What I really wanted is that I want objects to appear in groups randomly. So if one coin spawns in one position, then I would like other coins appear next to it. The problem is that there are coins that still collide with one another.

Ultimately this is what I have done...

Code:
xx = random(room_width);
    yy = random(room_height);
if!instance_exists(obj_coin)
{
instance_create_layer(xx, yy, "layer_coin", obj_coin);
instance_create_layer(xx+32, yy, "layer_coin", obj_coin);
instance_create_layer(xx-32, yy, "layer_coin", obj_coin);
instance_create_layer(xx, yy+32, "layer_coin", obj_coin);
instance_create_layer(xx, yy-32, "layer_coin", obj_coin);

while position_meeting(xx,yy,obj_wall)
{
xx = random(room_width);
yy = random(room_height);
}
}
I also tried the collision_rectangle as well but that also had problems as well.
I'm enjoying this thread. At this point, I have to believe you are doing this intentionally. Assuming that, I'll also assume you really could solve this problem by now if you really wanted. If I'm wrong, and you're not doing this on purpose here are some things you should consider:
  • You never actually follow or listen to the advice given. For example, you had to be told many times how to do the while loop and to move the repeat, and you're still not indenting your code to make it easier for us to read.
  • You don't appear to think through any element of the advice given or your own code. Every post is filled with numerous errors which should be obvious even to a novice coder if for no other reason than they would prevent your game from compiling e.g. saying repeat[5] or immediately crash it (as with one of the earlier versions of your while loop)
  • You make random changes to your code for no reason each time you post code. For example, in this last one, why would you move the while loop to the end? That has never been suggested in any code example or reply and is completely useless.
So assuming you're actually struggling here, you should start back at the top of this post and re-work through the answers as you have been given three different and workable methods to solve the issue including one which you nearly got to work before randomly changing it into an unworkable mess. Listen to and follow the advice and think through your own code.
 

Bentley

Member
Ok first off, I did your code and it just ended up crashing for no reason. Secondly, I said I'm sorry and yeah I get that I did bad here.

I should have worded what I wanted right instead of saying random. What I really wanted is that I want objects to appear in groups randomly. So if one coin spawns in one position, then I would like other coins appear next to it. The problem is that there are coins that still collide with one another.

Ultimately this is what I have done...

Code:
xx = random(room_width);
    yy = random(room_height);
if!instance_exists(obj_coin)
{
instance_create_layer(xx, yy, "layer_coin", obj_coin);
instance_create_layer(xx+32, yy, "layer_coin", obj_coin);
instance_create_layer(xx-32, yy, "layer_coin", obj_coin);
instance_create_layer(xx, yy+32, "layer_coin", obj_coin);
instance_create_layer(xx, yy-32, "layer_coin", obj_coin);

while position_meeting(xx,yy,obj_wall)
{
xx = random(room_width);
yy = random(room_height);
}
}
I also tried the collision_rectangle as well but that also had problems as well.
I would take it one piece at a time. For example:
1. How do I randomly place an instance
2. How do I also keep it in the room
3. How do I also make sure there is room for the surrounding instances

Here's an example:
Code:
var xx, yy, x1, y1, x2, y2;

x1 = sprite_get_width(spr_ball) + sprite_get_xoffset(spr_ball);
y1 = sprite_get_height(spr_ball) + sprite_get_yoffset(spr_ball);
x2 = room_width - x1;
y2 = room_height - y1;
do
{
    xx = irandom_range(x1, x2);
    yy = irandom_range(y1, y2);
}
until (!place_meeting(xx, yy, all)); // Put the object index of the object you want to avoid instead of all

with (instance_create_layer(xx, yy, layer, obj_ball))
{
    instance_create_layer(xx + sprite_width, yy, layer, obj_ball);
    instance_create_layer(xx - sprite_width, yy, layer, obj_ball);
    instance_create_layer(xx, yy + sprite_height, layer, obj_ball);
    instance_create_layer(xx, yy - sprite_height, layer, obj_ball);
}
If you plan to create new groups, the code needs to be changed a bit.
until (!place_meeting becomes until (!collision_rectangle(

I'd be happy to explain any of the code if you want my help.
 
Last edited:
A

Artwark

Guest
I would take it one piece at a time. For example:
1. How do I randomly place an instance
2. How do I also keep it in the room
3. How do I also make sure there is room for the surrounding instances

Here's an example:
Code:
var xx, yy, x1, y1, x2, y2;

x1 = sprite_get_width(spr_ball) + sprite_get_xoffset(spr_ball);
y1 = sprite_get_height(spr_ball) + sprite_get_yoffset(spr_ball);
x2 = room_width - x1;
y2 = room_height - y1;
do
{
    xx = irandom_range(x1, x2);
    yy = irandom_range(y1, y2);
}
until (!place_meeting(xx, yy, all)); // Put the object index of the object you want to avoid instead of all

with (instance_create_layer(xx, yy, layer, obj_ball))
{
    instance_create_layer(xx + sprite_width, yy, layer, obj_ball);
    instance_create_layer(xx - sprite_width, yy, layer, obj_ball);
    instance_create_layer(xx, yy + sprite_height, layer, obj_ball);
    instance_create_layer(xx, yy - sprite_height, layer, obj_ball);
}
If you plan to create new groups, the code needs to be changed a bit.
until (!place_meeting becomes until (!collision_rectangle(

I'd be happy to explain any of the code if you want my help.
I tried your code and there is just one problem that I faced....

The one that I faced is that the coins only spawned at the left side and didn't spawn anywhere else besides there...I'm guessing its either how the tiles are mapped or that its probably due to the limited random range. I would like a fix for this if possible.

in the end I managed to do it like this...

Code:
var xx,yy,x1,y1,x2,y2;
x1 = sprite_get_width(spr_coin) + sprite_get_xoffset(spr_coin);
y1 = sprite_get_height(spr_coin) + sprite_get_yoffset(spr_coin);
x2 = room_width - x1;
y2 = room_height - y1;

if coins == 1
{
    time++;
do
{
    xx = irandom_range(x1,y1);
    yy = irandom_range(y1,y2);
}
until (!place_meeting(xx,yy,obj_coin))

with(instance_create_layer(xx, yy, "layer_coin", obj_coin))
{
instance_create_layer(xx + sprite_width, yy, "layer_coin", obj_coin);

instance_create_layer(xx-sprite_width, yy, "layer_coin", obj_coin);

instance_create_layer(xx, yy+sprite_height, "layer_coin", obj_coin);

instance_create_layer(xx, yy-sprite_height, "layer_coin", obj_coin);

}
if time>5//this is to make a limit of how many coins have to appear for a few seconds
{
    coins = 0;
}
if !instance_exists(obj_coin)
{
    time = 0;//this is to reset the time for spawning coins
}
}
But I have a couple of questions regarding the code...

The first one is how are you able to use an instance_create_layer on a with function? And how are you able to use that to use instance_create_layer for spawning objects? Normally I use with function to change action for a different object instead of using it for the current one.

The other one I have a doubt with is I created those variables in the create event and then did the do function on the step event. When I ran it, it showed an error and the only way I could fix it was to paste those created variables to the step event. Why is that?
 

Bentley

Member
The one that I faced is that the coins only spawned at the left side
The other one I have a doubt with is I created those variables in the create event and then did the do function on the step event
They are likely spawning in the same place because you are setting xx and yy in the create event. You should set xx and yy to a new random position every time you want to create a group of objects.
The first one is how are you able to use an instance_create_layer on a with
instance_create_layer(…
returns the ID of the instance you are creating.
Ex: var ball = instance_create_layer(x, y, layer, obj_ball);
"ball" now holds the ID of the ball you just created.
you can then change the ball this way

ball.x = 100;
ball.speed = 8;
etc.

or this way

with (ball)
{
x = 100;
speed = 8
}

So what I am doing is saying, "with (the ball I just created)" do some stuff. I now have access to the ball's variables, which makes it easy to create the other balls the correct distance away, as I can use the balls sprite_width, sprite_xoffset, etc. You don't have to do it that way. You would just have to get the ball's sprite dimensions from the calling instance via: instance_create_layer(xx + sprite_get_width(obj_ball) etc.

I would look into the difference between local variables (declared with "var") and instance variables. Just look them up in the manual.

Also, I can't emphasize enough how important it is to understand the code. This is just my opinion, but I would say if you don't understand something, don't put it in your code. It's worth taking the time. Like I was saying in the above post, try to first place an instance at a random position. Then try to place it within the room, etc.
 
Last edited:
A

Artwark

Guest
I'm still facing problems....

The first is that after collecting the objects, they stop spawning for some reason. I even tried the collision_rectangle issue and even that doesn't work.

Code:
var xx,yy,x1,y1,x2,y2;
x1 = sprite_get_width(spr_coin) + sprite_get_xoffset(spr_coin);
y1 = sprite_get_height(spr_coin) + sprite_get_yoffset(spr_coin);
x2 = room_width - x1;
y2 = room_height - y1;

time++;

if time = 5
{
do
{
    xx = irandom_range(x1,x2);
    yy = irandom_range(y1,y2);
}
//until (!place_meeting(xx,yy,obj_coin))
until (!collision_rectangle(x1,y1,x2,y2,obj_coin,true,true))
with(instance_create_layer(xx, yy, "layer_coin", obj_coin))
{
instance_create_layer(xx + sprite_width, yy, "layer_coin", obj_coin);
instance_create_layer(xx-sprite_width, yy, "layer_coin", obj_coin);
instance_create_layer(xx, yy+sprite_height, "layer_coin", obj_coin);
instance_create_layer(xx, yy-sprite_height, "layer_coin", obj_coin);
}
}
if time>=5 && !instance_exists(obj_coin)
{
    time = 0;
}
The other problem is that they still don't appear as groups. One coin collides with the other still and the other doesn't come close to some other groups....
 
Top