tiling an image between sets of coordinates

Discussion in 'Tutorials' started by Didjargo, Jan 12, 2017.

  1. Didjargo

    Didjargo Member

    Joined:
    Jun 21, 2016
    Posts:
    46
    GM Version: GMS2 v2.0.3.56
    Target Platform: ALL
    Download: N/A
    Links: N/A

    Summary:
    GML has a function to draw a sprite and tile it, but that is designed to fill the whole room with the tiled image. I have come up with a script which allows you to draw a sprite at one set of coordinates and tile it until it reaches a second set of coordinates. This can be useful for creating in-game menu windows with a tiled image in it.

    Tutorial:
    - import an image you wish to tile. It does not have to be a perfect square. I created this one for you to test out and called it "window_bg_spr"
    https://s28.postimg.org/jimhi4ei5/window_bg_spr.png
    -create a new script and call it "tile_image_scr" or whatever you like.
    - for the "tile_image_scr" script, write this code.
    Code:
    //argument0 = x1, argument1 = y1, argument2 = x2, argument3 = y2, arguemnt4 = alpha argument5 = image
    
    bg_width = sprite_get_width(argument5); //obtain the width of the tiled image
    bg_height = sprite_get_height(argument5); //obtain the height of the tiled image
    
    x_tile = (argument2-argument0)/bg_width;  //the number of horizontal tiles
    y_tile = (argument3-argument1)/bg_height;  //the number of vertical tiles
    
    x_tile_place = argument0  +  (floor(x_tile)*bg_width);  //the x coordinate of the last tile
    y_tile_place = argument1  +  (floor(y_tile)*bg_height);  //the y coordinate of the last tile
    
    //count the number of tiles that should be there (x_tile and y_tile) and place a tile at each point
    //until it reaches the needed count.
    x_show_tile = floor(x_tile)+1;
    y_show_tile = floor(y_tile)+1;
    
    //check to see if the difference between the sets of coordinates requires image tiling
    if (x_show_tile * y_show_tile) > 0
    {
        x_row = 0;
        y_row = 0;
        count = 0;
        row_count = 0;
       
        draw_set_alpha(argument4);
       
        //this do statment will draw the tiles to fill in between the coordinates
        do
        {
        if (argument0+(x_row*bg_width))+ bg_width <= argument2
        x_scale = bg_width
        else
        x_scale= (x_tile-floor(x_tile)) * bg_width
       
        if (argument1+(y_row*bg_height))+ bg_height <= argument3
        y_scale = bg_height
        else
        y_scale= (y_tile-floor(y_tile)) * bg_height
       
        //if the whole image fits within the coordinates, draw it whole. Otherwise, draw part of it
        if (x_scale = bg_width) and (y_scale = bg_height)
        draw_sprite(argument5,0,argument0+(x_row*bg_width),argument1+(y_row*bg_height))
        else
        draw_sprite_part(argument5,0,0,0,  x_scale, y_scale ,argument0+(x_row*bg_width),argument1+(y_row*bg_height))
        x_row += 1;
        row_count += 1;
        if row_count = x_show_tile
            {
            y_row += 1;
            x_row = 0;
            row_count = 0;
            }
       
        count += 1;
        }
        until (count = x_show_tile * y_show_tile)
    }
    
    You should call upon the script in the "draw" or "draw GUI" events of an object. the variables for the script are
    tiled_image_obj(x1,y1,x2,y2,alpha, sprite)
    so for example:
    tiled_image_obj(x,y,mouse_x,mouse_y,0.8,window_bg_spr)
     
    NeZvers and sludgecoyote like this.
  2. chance

    chance predictably random Forum Staff Moderator

    Joined:
    Apr 22, 2016
    Posts:
    785
    I haven't tried this, so we'll leave it for readers to test.

    But please add some brackets to the two if / else segments in the middle of the main loop to make it clear what statements are included inside the conditional. The way it's written makes it difficult to read -- and potentially ambiguous.
     
  3. Poddington

    Poddington Member

    Joined:
    Jul 15, 2016
    Posts:
    13
    Whilst it does work it's very limited. Keeping the script as originally written it only work on a positive x,y from the starting point. So where either the starting x and y is it will only draw tiles correctly to the right and/or down. This will also show tiles to the edge, even if the regions right and bottom aren't the full tiles size. I'm sure it has a use, but I often find when making an auto tiler that you'd only want to show full tiles. A simple for loop within a for loop drawing tiles from the region start to the region end with increments of the tile size will have the same effect if in the draw event. I could be missing it's purpose and maybe it didn't work properly for me. Here is code I used recently that did the same thing I saw when using the script above.

    Code:
    if(object_current_x > object_start_x and object_current__y > object_start_y) //if the current x and y is greater than the x and y when the mouse button was pressed then...
            {
            for (i = object_start_x; i < object_current_x; i += 32)
                {
                for (j = object_start_y; j < object_current__y; j += 32)
                    {
                     draw_sprite(spr_draw_tile,0,i,j);
                     draw_select_x = i;  //the x position after the loops useful to capture the last tiles x and y to use afterwards. This was used to select the region in a DS grid when I wrote this.
                     draw_select_y = j; //the y position after the loops useful to capture the last tiles x and y to use afterwards. This was used to select the region in a DS grid when I wrote this.
                    }
                }
            }
     
    NeZvers likes this.
  4. sludgecoyote

    sludgecoyote Member

    Joined:
    Apr 7, 2019
    Posts:
    9
    This works great but had to add a line in there to reset the alpha back to default.
     

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