GameMaker [SOLVED] Collision with tiles

Z

Zyr0

Guest
Hello everyone ! So, I'm in trouble, and I would appreciate your help.
My issue is as follow :

What I have :

I have a simple controller that randomly generates objects in my room. (Trees, Rock etc...) It doesn't use grids, I wanted the placement of my objects to look more random.
The rest of the room is a layer of ground tiles and a layer of water tiles.

What I want to do :

I want to use a common parent for my randomly generated objects which commands them to self-destroy if they exist in water. So what I want is to make the objects KNOW which tile they are currently standing on, and if it is water, make them instance_destroy().

What I tried :

I tried about every combination of functions on the Yoyo page about tilemap :
https://docs2.yoyogames.com/source/_build/3_scripting/4_gml_reference/rooms/tilemaps/index.html

I tried a method from someone on reddit : (His script worked, but it involved re-doing my random terrain generation a way I didn't like. Simply adapting his method to mine didn't seem to work.)
https://www.reddit.com/r/gamemaker/comments/a180qf/checking_for_general_tile_collision/

And finally, I tried to follow a bunch of tutorials : (I'm giving one example here but all of these tutorials have the same problem : they check for tile collision to prevent you from clipping through the borders of the tiles, but what if you are already in ?) (PS : Same goes for the yoyo in-built demo about tile-based collision.)
https://forum.yoyogames.com/index.php?threads/gms-2-tilemap-as-collision-maps-gmwolf.13182/

If you manage to help me with this, I'll kiss you or something.
 

Baldi

Member
are the tiles of the map handplaced in the room editor or generates as well?
Im not good with tilemaps myself but if it's randomly generated anyways you could use a DS grid that has 0 for water 1 for land and then you could check the number of the cell your objects are on. I'm guessing "tilemap_get()" should be the one that does what you want but I'm assuming you already tried.
 
I

immortalx

Guest
I want to use a common parent for my randomly generated objects which commands them to self-destroy if they exist in water.
I assume you meant if they were created in water? If that's the case, then you don't have to generate them and then destroy them. Just prevent them from being created if the randomly generated x and y values are inside a water tile.
Code:
// assuming the index of water tile is 2
if (tilemap_get_at_pixel(tilemap, randx, randy) != 2) {
    // create instance
}
 
Z

Zyr0

Guest
are the tiles of the map handplaced in the room editor or generates as well?
Im not good with tilemaps myself but if it's randomly generated anyways you could use a DS grid that has 0 for water 1 for land and then you could check the number of the cell your objects are on. I'm guessing "tilemap_get()" should be the one that does what you want but I'm assuming you already tried.
To answer your question, the tiles are hand-placed, only the objects are generated.
I tried tilemap_get() yes, but your post gave me an idea, I'm gonna try that soon as I get the chance.
 
Z

Zyr0

Guest
I assume you meant if they were created in water? If that's the case, then you don't have to generate them and then destroy them. Just prevent them from being created if the randomly generated x and y values are inside a water tile.
Code:
// assuming the index of water tile is 2
if (tilemap_get_at_pixel(tilemap, randx, randy) != 2) {
    // create instance
}
I mean... yeah, but the tilemap_get_at_pixel() won't work out of the blue. Although I could optimise my code with your suggestion later on.
 
Z

Zyr0

Guest
UPDATE : I think I have something that will work thanks to you both. (Also Immortalx you were right, it's much easier to just get it not to create objects in water in the first place, I don't know what I was thinking.)

But I ran into another problem along the way, the layer_get_id() function doesn't work. I fed it the name of the layer but it returns me an error as if the layer didn't exist. I found several posts talking about a bug in 2.2.0.343 with layer functions, can you confirm ?
 
Last edited by a moderator:
Z

Zyr0

Guest
Man I'm 💩💩💩💩ing retarded. Thank you, it works. That was my problem all along. I'm gonna edit the title.

EDIT : ABORT ! ABORT ! SPOKE TOO SOON !

So, I got it to recognise what layer it was on, and I found that because of the way I placed water and land in my room, it was much easier to make the controller check if it is on land rather than if it is on water. So I made the necessary modification, but now it seems to think that the whole room is land, even water. Back to square 1.

EDIT 2 : I also tried replacing water a handy way for the code to recognise it and reverting to the water checking method, and I've still got nothing. At least I don't have any error now. I'm gonna try to revert to a previous version of GM2, see if it works.
 
Last edited by a moderator:
Z

Zyr0

Guest
Update : Tried that, didn't work. I'm starting to get desperate, I tried so many things, I did it the most secure way I know, it's so stupid that my project would be slowed down so much by such a tiny detail.
 
I

immortalx

Guest
It would help if you could post at least the relevant parts of your code
 
Z

Zyr0

Guest
Yeah, that's definitely my only solution, here we go :

That's the controller's create event :

Code:
// Controller's position

cont_pos_x = 0;
cont_pos_y = 0;

// Water tilemap

water_lay_id = layer_get_id("Tiles_water");
water_tilemap_id = layer_tilemap_get_id(water_lay_id);

// Frequency of rocks

rock_creation_factor = 400;

f_large_rock = 1;
f_medium_rock = 2;
f_small_rock = 3;

// Frequency of flora

flora_creation_factor = 400;

f_large_tree = 1;
f_small_tree = 2;
f_bush = 4;
And that's the step event :

Code:
// Sets the controller's position.

x = cont_pos_x;
y = cont_pos_y;

// Check if the controller is on water.

water = tilemap_get_at_pixel(water_tilemap_id,cont_pos_x,cont_pos_y);

// large rock creator.

cont_pos_x = 120;
repeat(room_height / 120 - 1)
{
    repeat(room_width / 120 - 1)
    {
        if(irandom(rock_creation_factor) <= f_large_rock and water != 1) // That's the part where it is supposed to prevent the instance form being created if it is on water. 
        {
            instance_create_depth(cont_pos_x,cont_pos_y,100,obj_rock_large); 
        }
        cont_pos_x += 120;
    }
    cont_pos_x = 120;
    cont_pos_y += 120;
}
cont_pos_x = 0;
cont_pos_y = 0;

// I only show the large rock part, but it's the same code for all the other objects.

// Clears the instance once it is done creating the terrain.

instance_destroy();
 
I

immortalx

Guest
If I'm not mistaken, you're continuously checking the same pixel every step (0,0).
If I'm reading this right, in every step cont_pos_x and cont_pos_y get reset to zero, you assign the result of tilemap_get_at_pixel to water, but it seems there's no water tile at 0,0 and that's why the if block fires over and over again.
You'll have to assign the water variable inside the repeat block, only after you have given new values to cont_pos_x and cont_pos_y
 
Z

Zyr0

Guest
It worked ! Oh I can't thank you enough, you unstuck me for way more stuff than this terrain generaton thing. Here is the updated code for reference :

Code:
// large rock creator.

cont_pos_x = 120;
repeat(room_height / 120 - 1)
{
    repeat(room_width / 120 - 1)
    {
        water = tilemap_get_at_pixel(water_tilemap_id,cont_pos_x,cont_pos_y); 
        if(irandom(rock_creation_factor) <= f_large_rock and water != 1)
        {
            instance_create_depth(cont_pos_x,cont_pos_y,100,obj_rock_large);   
        }
        cont_pos_x += 120;
    }
    cont_pos_x = 120;
    cont_pos_y += 120;
}
cont_pos_x = 0;
cont_pos_y = 0;
All's well that ends well, thanks to you.
 
Top