GameMaker [Solved]: On-collision event with a while loop inside it

C

Carcophan

Guest
Hello everyone.

I have some code that is triggered from a collision event.

When the player interacts with the 'quest item' in one location, it should spawn a 'key' in a new random-ish location (a small confined area, versus just going any where).

Problem seems to be that the key is spawning on top of existing walls and other objects sometimes, instead of in an open available space/tile. In one case the key spawned ON the chest itself and was unobtainable.

This leads me to believe that the code below just happens to work sometimes and is in fact wrong in some way.

Is it okay that the code below exists only in the 'obj_quest' on-collision event? Should it live somewhere else, or should I be attempting another route?

Code:
var ranKeyLocXX = irandom_range((global.mazeWidth div 2),global.mazeWidth - 3), ranKeyLocYY = irandom_range((global.mazeHeight div 2),global.mazeHeight - 3);
while    (    !global.grid [# ranKeyLocXX, ranKeyLocYY]                &&
                !position_meeting(ranKeyLocXX, ranKeyLocYY, obj_Chest) ) {
        ranKeyLocXX = irandom_range((global.mazeWidth div 2),global.mazeWidth - 3);
        ranKeyLocYY = irandom_range((global.mazeHeight div 2),global.mazeHeight - 3);
    }
    instance_create_depth(ranKeyLocXX * global.tileSize + (global.tileSize div 2), ranKeyLocYY * global.tileSize + (global.tileSize div 2), -10, obj_Key01);

Thanks all!
 

Rob

Member
When you're creating the instance, you're multiplying ranKeyLocXX/Y by global.tileSize, but you're not checking for that with the collisions, would be my guess - at least for the chest.

What's stored inside global.grid? I would use a show_debug_message 's to show what value is actually inside global.grid[# ranKeyLocXX, ranKeyLocYY] just after the while loop ends. That should help you find out what the problem is.

eg

Code:
var ranKeyLocXX = irandom_range((global.mazeWidth div 2),global.mazeWidth - 3), ranKeyLocYY = irandom_range((global.mazeHeight div 2),global.mazeHeight - 3);
while    (    !global.grid [# ranKeyLocXX, ranKeyLocYY]                &&
                !position_meeting(ranKeyLocXX, ranKeyLocYY, obj_Chest) ) {
        ranKeyLocXX = irandom_range((global.mazeWidth div 2),global.mazeWidth - 3);
        ranKeyLocYY = irandom_range((global.mazeHeight div 2),global.mazeHeight - 3);
    }

   show_debug_message(string(global.grid[# ranKeyLocXX , ranKeyLocXY));

    instance_create_depth(ranKeyLocXX * global.tileSize + (global.tileSize div 2), ranKeyLocYY * global.tileSize + (global.tileSize div 2), -10, obj_Key01);
 
Last edited:
C

Carcophan

Guest
Thanks for the reply.


I had the individual XX and YY in a debug, to get its actual location - but not the grid value for some reason.

The grid replies with the wall or floor values (1/0's). There are times it should be a '0' because it is on the floor (not a wall, which is a 1). And, there are times is should return a 2 or a 3 and doesn't either, so I am super confused as to my logic problem or typo.

I also changed !global.grid [# ranKeyLocXX, ranKeyLocYY] to global.grid [# ranKeyLocXX, ranKeyLocYY] != 1, with the same results (imagine that!).

I also have a debug message in the while loop, and outside.

This for example:
Code:
...show_debug_message("inner  " + string(global.grid[# ranKeyLocXX , ranKeyLocYY]) + " -- " + string(ranKeyLocXX) + " AND "  + string(ranKeyLocYY)   );
    }
    show_debug_message(string(global.grid[# ranKeyLocXX , ranKeyLocYY]));
provided me with:

inner 0 -- 22 AND 18
inner 0 -- 18 AND 21
inner 0 -- 18 AND 17
inner 0 -- 13 AND 21
inner 0 -- 14 AND 17
inner 0 -- 16 AND 16
inner 1 -- 21 AND 19
1
The Key has been spawned

Which translates to "the While loop Grid had a 0" (which, to me, is not equal to 1) and it should have put it where it had a 0. But it went through, until it got a 1.... and then broke the loop.

WHAT am I doing wrong with the while loop logic. I feel silly.
 
Last edited by a moderator:
I am unsure if you're referring to an mp grid here, as I use 1.4 and don't see the relevant code here to get whether a grid cell is flagged or not. But, assuming you are using a grid, is there a reason you can't place chests into the grid? And so remove the need for a physical collision check.

And if for some reason you can't / won't do chests other than as physical collisions - are you making sure that you have properly translated the grid position into x / y coordinates?

Checking a collision at "22" and "18" is literally an x position of 22, and a y position of 18. I don't see anywhere that you are converting this figure by the cell width / cell height, and so are only getting the cells vertical and horizontal number - not an actual position. At least, not in the way you think you are. Which is what I believe Rob tried to make you aware of.
When you're creating the instance, you're multiplying ranKeyLocXX/Y by global.tileSize, but you're not checking for that with the collisions, would be my guess - at least for the chest.
Code:
var ranKeyLocXX = irandom_range((global.mazeWidth div 2),global.mazeWidth - 3), ranKeyLocYY = irandom_range((global.mazeHeight div 2),global.mazeHeight - 3);
var is_cell_width = global.tileSize + (global.tileSize div 2); // what you're applying later, when creating the instance
var is_cell_height = global.tileSize + (global.tileSize div 2); // what you're applying later, when creating the instance
while    ( !global.grid [# ranKeyLocXX, ranKeyLocYY]  &&
!position_meeting(ranKeyLocXX * is_cell_width, ranKeyLocYY * is_cell_height , obj_Chest) ) //
{
       ranKeyLocXX = irandom_range((global.mazeWidth div 2),global.mazeWidth - 3);
       ranKeyLocYY = irandom_range((global.mazeHeight div 2),global.mazeHeight - 3);
   }

   show_debug_message(string(global.grid[# ranKeyLocXX , ranKeyLocXY));

   instance_create_depth(ranKeyLocXX * is_cell_width, ranKeyLocYY * is_cell_height, -10, obj_Key01);
EDIT: Whilst I think that would fix the problem with the coordinates, I am unsure of the logic.

For as long as the grid position is empty, and there is no collision, keep finding the random spot. So it only stops when there is a collision....??

Code:
var ranKeyLocXX = irandom_range((global.mazeWidth div 2),global.mazeWidth - 3), ranKeyLocYY = irandom_range((global.mazeHeight div 2),global.mazeHeight - 3);
var is_cell_width = global.tileSize + (global.tileSize div 2);
var is_cell_height = global.tileSize + (global.tileSize div 2);
while    (
global.grid [# ranKeyLocXX, ranKeyLocYY]  ||
position_meeting(ranKeyLocXX * is_cell_width, ranKeyLocYY * is_cell_height , obj_Chest)
)
{
       ranKeyLocXX = irandom_range((global.mazeWidth div 2),global.mazeWidth - 3);
       ranKeyLocYY = irandom_range((global.mazeHeight div 2),global.mazeHeight - 3);
   }
It's confusing me now :) but wouldn't the above change mean that the while loop only exists for as long as there is found to be an occupied cell OR the physical collision...?

Can't recall if a while loop supports an OR expression, but if not:

Code:
var ranKeyLocXX = irandom_range((global.mazeWidth div 2),global.mazeWidth - 3), ranKeyLocYY = irandom_range((global.mazeHeight div 2),global.mazeHeight - 3);
var is_cell_width = global.tileSize + (global.tileSize div 2);
var is_cell_height = global.tileSize + (global.tileSize div 2);
var check = true;
while    (check)
{
if global.grid [# ranKeyLocXX, ranKeyLocYY] == 0 &&
!position_meeting(ranKeyLocXX * is_cell_width, ranKeyLocYY * is_cell_height , obj_Chest)
{
check = false;
}
ranKeyLocXX = irandom_range((global.mazeWidth div 2),global.mazeWidth - 3);
ranKeyLocYY = irandom_range((global.mazeHeight div 2),global.mazeHeight - 3);
}
 
Last edited:

Rob

Member
WHAT am I doing wrong with the while loop logic. I feel silly.
I've been over the code a few times now and I can't see the problem from that either. If you said the grid doesn't always return the proper values that it should, it would be worth looking into that first.
I keep wondering if the key sprite origin is in the wrong place but that doesn't account for the debug messages that you've shown.
 
C

Carcophan

Guest
For as long as the grid position is empty, and there is no collision, keep finding the random spot. So it only stops when there is a collision....??
Close. if the random cell is already occupied, keep randoming until you find an unoccupied spot.

But, assuming you are using a grid, is there a reason you can't place chests into the grid?
No specific reason, no. That is a cleaver idea actually, and can directly integrate into my existing structure. Will play around with doing it this way, versus the current object / collision.

(The second example, having an OR statement there, causes an infinite loop :p )

I tried all three of your examples, but not the "grid vs object" idea yet. I'll make an update if that works, which it should, just hadn't planned it out that way.
 
C

Carcophan

Guest
I keep wondering if the key sprite origin is in the wrong place but that doesn't account for the debug messages that you've shown.
Good news / bad news....

Good news - you were right about the key origin being off. It was literally the only sprite that was unlocked and had the origin off by like 200 pix somehow.... but fixing that, sadly, and strangely, was not the solution.
Bad news - key object doesn't even spawn now for some reason, with my old code and with the_dude_abides


If you said the grid doesn't always return the proper values that it should, it would be worth looking into that first.
So the grid is returning the proper value (I think), because the map looks right. The location the key is on, the X/Y returned by the random + math, is off.

The debugging shows where the key should be there (like at grid location 16, 22... or 24, 10), regardless of what is or isn't under the key object, but since the changes, now it does not spawn.
 
Last edited by a moderator:

Rob

Member
Good news / bad news....

Good news - you were right about the key origin being off. It was literally the only sprite that was unlocked and had the origin off by like 200 pix somehow.... but fixing that, sadly, and strangely, was not the solution.
Bad news - key object doesn't even spawn now for some reason, with my old code and with the_dude_abides


So the grid is returning the proper value (I think), because the map looks right. The location the key is on, the X/Y returned by the random + math, is off.

The debugging shows where the key should be there (like at grid location 16, 22... or 24, 10), regardless of what is or isn't under the key object, but since the changes, now it does not spawn.
Have a line in the draw gui that shows "instance_number(obj_Key01)" - also is its depth still -10 and will -10 still be drawn above everything else? What does the code look like now if you changed it?
 
Last edited:
Code:
cell_width = 32;
cell_height = 32;
grid = mp_grid_create(0, 0, room_width div cell_width, room_height div cell_height, cell_width, cell_height);
Code:
check = false;
ranKeyLocXX = irandom_range(0, room_width div cell_width); // same dimensions as number of grid cells horizontally
ranKeyLocYY = irandom_range(0, room_height div cell_height);// same dimensions as number of grid cells vertically
while (!check)
{
if ((mp_grid_get_cell(grid, ranKeyLocXX, ranKeyLocYY) == 0) &&
(!position_meeting(ranKeyLocXX * cell_width, ranKeyLocYY * cell_height, object1)))
{
check = true;
}
else
{
ranKeyLocXX = irandom_range(0, room_width div cell_width);
ranKeyLocYY = irandom_range(0, room_height div cell_height);
}
}
instance_create((ranKeyLocXX * cell_width) + 16, (ranKeyLocYY * cell_height) + 16, object2) // added 16  because object 2 had a centred origin and is 32 by 32 pixels
This worked for me (ignoring where I've not set it up with the same variables / objects as you)

I ran it close to a 100 times, and never saw it fill a space that was an occupied position.
 
Last edited:
C

Carcophan

Guest
I ended up going with you latest idea, and it seems to it working I think!


I've run it about 50 times, with no issue.
 
Top