GMS 2 [SOLVED] Collision with tiles

Discussion in 'Programming' started by Zyr0, Dec 3, 2018.

  1. Zyr0

    Zyr0 Member

    Joined:
    Dec 3, 2018
    Posts:
    8
    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.
     
  2. Baldi

    Baldi Member

    Joined:
    Feb 17, 2017
    Posts:
    40
    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.
     
  3. immortalx

    immortalx Member

    Joined:
    Sep 6, 2018
    Posts:
    69
    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
    }
    
     
  4. Zyr0

    Zyr0 Member

    Joined:
    Dec 3, 2018
    Posts:
    8
    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.
     
  5. Zyr0

    Zyr0 Member

    Joined:
    Dec 3, 2018
    Posts:
    8
    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.
     
  6. Zyr0

    Zyr0 Member

    Joined:
    Dec 3, 2018
    Posts:
    8
    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: Dec 4, 2018
  7. immortalx

    immortalx Member

    Joined:
    Sep 6, 2018
    Posts:
    69
    Have you put the layer name inside quotes?
     
  8. Zyr0

    Zyr0 Member

    Joined:
    Dec 3, 2018
    Posts:
    8
    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: Dec 4, 2018
  9. Zyr0

    Zyr0 Member

    Joined:
    Dec 3, 2018
    Posts:
    8
    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.
     
  10. immortalx

    immortalx Member

    Joined:
    Sep 6, 2018
    Posts:
    69
    It would help if you could post at least the relevant parts of your code
     
  11. Zyr0

    Zyr0 Member

    Joined:
    Dec 3, 2018
    Posts:
    8
    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();
    
     
  12. immortalx

    immortalx Member

    Joined:
    Sep 6, 2018
    Posts:
    69
    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
     
  13. Zyr0

    Zyr0 Member

    Joined:
    Dec 3, 2018
    Posts:
    8
    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.
     
    immortalx likes this.
  14. immortalx

    immortalx Member

    Joined:
    Sep 6, 2018
    Posts:
    69
    Glad I could help!
     
  15. RefresherTowel

    RefresherTowel Member

    Joined:
    Jul 13, 2016
    Posts:
    667
    You should be using div instead of / when converting pixel positions to grid positions.
     

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice