1. Hey! Guest! The 35th GMC Jam will take place between November 28th, 12:00 UTC - December 2nd, 12:00 UTC. Why not join in! Click here to find out more!
    Dismiss Notice

GM:S 1.4 AT-47 (Auto-tiling with 47 images)

Discussion in 'Tutorials' started by Simon Gust, Jan 28, 2017.

  1. Simon Gust

    Simon Gust Member

    Joined:
    Nov 15, 2016
    Posts:
    3,198
    GM Version: GM:S
    Target Platform: All
    Download: N/A
    Links: N/A

    Summary:
    I made a script that allows you to auto-tile with 47 images but it only works with "tiles" or more precisely a grid system using an array.

    Tutorial:
    The algorithm is use in this script is similar to the bitwise tiling system except it doesn't count or anything.
    around and noticed that say 8 calculations (1 for every direction) takes longer than, on average, 6 if-statements.
    so let's begin:

    first we must understand how the bitwise calcs work:
    upload_2017-1-28_22-9-2.png
    the brown colour represents dirt and the green colour grass.
    when we check our tile or in this image "0". we can have 8 other tiles surrounding it.
    If there is a tile below, add 1 to the total count etc.

    at the end our sum can go from 0 to 255, which is more than 46 (47 but indexes start at 0).
    In the bitwise autotiler, the numbers that are faulty are just changed manually.
    Here though we don't have to do that.
    Code:

    Code:
    ///scr_get_index(array, tile, x, y)
    var array = argument0; // the array to check on
    var tile = argument1; // The tile type to check for
    var xx = argument2; // x of the tile
    var yy = argument3; // y of the tile
    
    // directional shortcuts
    var lft = xx - 1;
    var top = yy - 1;
    var rgt = xx + 1;
    var bot = yy + 1;
    
    //1+
    if (array[@ xx, bot] != tile)
    {
        //1-2+
        if (array[@ rgt, yy] != tile)
        {
            //1-2-4+
            if (array[@ xx, top] != tile)
            {
                //1-2-4-8
                if (array[@ lft, yy] != tile)
                {
                    return (15);
                }
                else return (7);
            }
            else
            {
                //1-2-8
                if (array[@ lft, yy] != tile)
                {
                    return (11);
                }
                else
                {
                    //1-2-64
                    if (array[@ lft, top] != tile)
                    {
                        return (27);
                    }
                    else  return (3);
                }
            }
        }
        else
        {
            //1-4+
            if (array[@ xx, top] != tile)
            {
                //1-4-8
                if (array[@ lft, yy] != tile)
                {
                    return (13);
                }
                else return (5);
            }
            else
            {
                //1-8+
                if (array[@ lft, yy] != tile)
                {
                    //1-8-32
                    if (array[@ rgt, top] != tile)
                    {
                        return (23);
                    }
                    else return (9);
                }
                else
                {
                    //1-32
                    if (array[@ rgt, top] != tile)
                    {
                        //1-32-64
                        if (array[@ lft, top] != tile)
                        {
                            return (43);
                        }   
                        else return (21);
                    }
                    else
                    {
                        //1-64
                        if (array[@ lft, top] != tile)
                        {
                            return (25);
                        }
                        else return (1);
                    }
                } 
            }
        }
    }
    else
    {
        //2+
        if (array[@ rgt, yy] != tile)
        {
            //2-4
            if (array[@ xx, top] != tile)
            {
                //2-4-8
                if (array[@ lft, yy] != tile)
                {
                    return (14);
                }
                else
                {
                    //2-4-128
                    if (array[@ lft, bot] != tile)
                    {
                        return (31);
                    }
                    else return (6);
                }
            }
            else
            {
                //2-8
                if (array[@ lft, yy] != tile)
                {
                    return (10);
                }
                else
                {
                    //2-64
                    if (array[@ lft, top] != tile)
                    {
                        //2-64-128
                        if (array[@ lft, bot] != tile)
                        {
                            return (44);
                        }
                        else return (26);
                    }
                    else
                    {
                        //2-128
                        if (array[@ lft, bot] != tile)
                        {
                            return (29);
                        }
                        else return (2);
                    }
                }
            }
        }
        else
        {
            //4+
            if (array[@ xx, top] != tile)
            {
                //4-8
                if (array[@ lft, yy] != tile)
                {
                    //4-8-16
                    if (array[@ rgt, bot] != tile)
                    {
                        return (18);
                    }
                    else return (12);
                }
                else
                {
                    //4-16
                    if (array[@ rgt, bot] != tile)
                    {
                        //4-16-128
                        if (array[@ lft, bot] != tile)
                        {
                            return (37);
                        }
                        else return (17);
                    }
                    else
                    {
                        //4-128
                        if (array[@ lft, bot] != tile)
                        {
                            return (30);
                        }
                        else return (4);
                    }
                }
            }
            else
            {
                //8+
                if (array[@ lft, yy] != tile)
                {
                    //8-16
                    if (array[@ rgt, bot] != tile)
                    {
                        //8-16-32
                        if (array[@ rgt, top] != tile)
                        {
                            return (33);
                        }
                        else return (19);
                    }
                    else
                    {
                        //8-32)
                        if (array[@ rgt, top] != tile)
                        {
                            return (22);
                        }
                        else return (8);
                    }
                }
                //ONLY CORNERS
                else
                {
                    //16+
                    if (array[@ rgt, bot] != tile)
                    {
                        //16-32
                        if (array[@ rgt, top] != tile)
                        {
                            //16-32-64
                            if (array[@ lft, top] != tile)
                            {
                                //16-32-64-128
                                if (array[@ lft, bot] != tile)
                                {
                                    return (39);
                                }
                                else return (35);
                            }
                            else
                            {
                                //16-32-128
                                if (array[@ lft, bot] != tile)
                                {
                                    return (42);
                                }
                                else return (32);
                            }
                        }
                        else
                        {
                            //16-64
                            if (array[@ lft, top] != tile)
                            {                         
                                //16-64-128
                                if (array[@ lft, bot] != tile)
                                {
                                    return (41);
                                }
                                else return (34);                         
                            }
                            else
                            {
                                //16-128
                                if (array[@ lft, bot] != tile)
                                {
                                    return (36);
                                }
                                else return (16);
                            }                                   
                        }
                    }
                    else
                    {
                        //32+
                        if (array[@ rgt, top] != tile)
                        {
                            //32-64
                            if (array[@ lft, top] != tile)
                            {
                                //32-64-128
                                if (array[@ lft, bot] != tile)
                                {
                                    return (40);
                                }
                                else return (46);
                            }
                            else
                            {
                                //32-128
                                if (array[@ lft, bot] != tile)
                                {
                                    return (38);
                                }
                                else return (20);
                            }
                        }
                        else
                        {
                            //64+
                            if (array[@ lft, top] != tile)
                            {
                                //64-128
                                if (array[@ lft, bot] != tile)
                                {
                                    return (45);
                                }
                                else return (24);
                            }
                            else
                            {
                                //128+
                                if (array[@ lft, bot] != tile)
                                {
                                    return (28);
                                }
                                else return (0);
                            }
                        }
                    }
                }
            }
        }
    }
    
    what we do is checking if the tile on whatever direction is NOT our own.
    Using != instead of == is faster in this situation.

    How it works:
    first it checks below, if that tile is not one of ours then go ahead, next tile
    right? not our tile, go on
    above? yes this a tile we possess, let's else this up.
    now we are at 1-2-8
    we can see that 16 and 32 are no options anymore which saves time on average.

    and so on...

    Other stuff:
    global.tiles represents my array which is filled with all tiles and potential collision.

    On the side where we call this script from is just an iteration of our array with double for loops:
    Code:
    //FUNCTIONS START
    var array = global.tiles;
    for (var i = 1; i < width-1; ++i)
    {
        for (var j = 1; j < height-1; ++j)
        {
            var tile = array[@ i, j];
            var index = scr_get_index(array, tile,i,j);
      
            //DRAW THE TILE
      
        }
    }
    And here just the tileset for this to work properly:
    upload_2017-1-28_22-26-15.png

    !You may use it as reference!

    If you have optimizations, complaints or questions post them here =]

    Edit: Did some tests with comparing windows to yyc and this algorythm against the bitwise one
    //>
    x47 win (my) 1370ms 1380ms 1387ms
    x47 win (bit) 2125ms 2136ms 2121ms

    x47 yyc (my) 502ms 494ms 485ms
    x47 yyc (bit) 657ms 676ms 686ms
    //>

    //>
    x16 win (my) 1220ms 1216ms 1222ms
    x16 win (bit) 1473ms 1462ms 1464ms

    x16 yyc (my) 423ms 426ms 425ms
    x16 yyc (bit) 439ms 430ms 442ms
    //>
     
    Last edited: Apr 7, 2018
    Sam Verburg and slojanko like this.
  2. Simon Gust

    Simon Gust Member

    Joined:
    Nov 15, 2016
    Posts:
    3,198
    No replies must mean that noone has issues I guess. good :>
     
  3. mazimadu

    mazimadu Member

    Joined:
    Jun 21, 2016
    Posts:
    127
    Sorry mate, but GMS2 has this built in.
     
  4. Simon Gust

    Simon Gust Member

    Joined:
    Nov 15, 2016
    Posts:
    3,198
    jokes on you, not everyone uses GMS 2. which only works for tiles. This is for advanced purposes, sorry.
     
  5. mazimadu

    mazimadu Member

    Joined:
    Jun 21, 2016
    Posts:
    127
    ok
    EDIT:
    How is that a joke? It is not even funny.
     
    Last edited: Apr 22, 2017
    RujiK likes this.
  6. Deadlyapples

    Deadlyapples Guest

    GMS 2 has an auto tile feature but it only works while you create the level not in level generation that is procedural or randomly generated or generated at run time. This method could be used when ever. I imagine you can use it even when you are making a mining game that upon removing a block or changing the ds_grid, re runs the above script and rebuilds the tiles to look correct. :D
     
    Simon Gust likes this.
  7. Simon Gust

    Simon Gust Member

    Joined:
    Nov 15, 2016
    Posts:
    3,198
    The joke is that you didn't actually read what is written in the tutorial nor the title.
    It's not for GMS2 nor has it anything to do with the built in tiles, read the thing!
     
  8. mazimadu

    mazimadu Member

    Joined:
    Jun 21, 2016
    Posts:
    127
  9. Simon Gust

    Simon Gust Member

    Joined:
    Nov 15, 2016
    Posts:
    3,198
    Then why are you even here?
     
  10. mazimadu

    mazimadu Member

    Joined:
    Jun 21, 2016
    Posts:
    127
    I was forced to by GMS 2 after yoyo pulled it from the store. Sorry, but your thing would have been useful if I could just download 1.4:(
     
  11. Simon Gust

    Simon Gust Member

    Joined:
    Nov 15, 2016
    Posts:
    3,198
  12. Kenny

    Kenny Guest

     
  13. Simon Gust

    Simon Gust Member

    Joined:
    Nov 15, 2016
    Posts:
    3,198
    This isn't for objects at all. This is for entries in a 2D array.
    Though it can be translated with not too much difficulties to objects.
    As a refrence I used the image in this tutorial.
    upload_2017-6-12_18-4-28.png

    You have to arrange your tileset like this. Also note that it is a sprite, not a background / tileset actually.
    You get 47 sub-images with this one.
     
  14. Kenny

    Kenny Guest

    Man, as soon as I think I start to get it, I stop getting it...
    I get that I need a background image, set up to be a 16x16 tile set (in the same order as yours) (awesome art skills BTW).

    I think I get now that the main script is cycling through a 2D array, to identify the values at [@ x, y].

    I don't quite understand how the 2d array is being created. Did you have to manually key in all the values (e.g. global.tiles[0,0] = 0) based on a manual calculation of the bitwise "calculator" or did you use a for-loop? I thought I saw a patter, then my brain broke...

    I am a little confused on what to put under "//Draw the tile". I was thinking tile_add(bg_name, etc.), but I don't see enough data to fill in all the arguments.

    I checked out a couple other sites to get more information, but I feel like I'm not getting everything (here was a good site: https://gamedevelopment.tutsplus.co...ng-to-auto-tile-your-level-layouts--cms-25673) Also, everyone uses bitwise calculations in a different order.

    If you happen to make a Youtube video on this, you will get a like/subscribe right away, lol!
     
  15. Kenny

    Kenny Guest

    OK, I'm a spaz. I get it now that you have a sprite, with 47 images. I am still not getting what data is in the array though. So much to learn, so much time to learn it in, so little brain power to process it all!
     
  16. Simon Gust

    Simon Gust Member

    Joined:
    Nov 15, 2016
    Posts:
    3,198
    Yeah you're almost got it. The array is basically a bunch of terrain info.
    The basics is:
    0 = nothing,
    1 = dirt
    2 = stone
    3 = grass
    for example.
    I have some kind of generator that fills the information in some algorythm.

    Though I have to say, this autotiler is old and I don't use it anymore, I've switched to shaders in the meantime, but it's still fast.
     
  17. Simon Gust

    Simon Gust Member

    Joined:
    Nov 15, 2016
    Posts:
    3,198

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