Map generation in Create event - versus draw event - question

Discussion in 'Programming' started by Carcophan, Oct 10, 2019.

  1. Carcophan

    Carcophan Member

    Joined:
    Aug 4, 2019
    Posts:
    53
    Hello everyone.

    I am using a script to generate a random map/maze, which uses the code below in the create event of the Level object, to fill in the grid with flooring sprites.
    Code:
    for ( global.i = 0; global.i < mazeW ; global.i++){
        for ( global.j = 0; global.j < mazeH ; global.j++){
        global.cellFill = ds_grid_get(global.flooring, global.i, global.j);
            if(global.cellFill = 1) {  draw_sprite(sCells, 1, global.i*global.tileSize, global.j*global.tileSize); }
            if(global.cellFill = 0) {  draw_sprite(sCells, 0, global.i*global.tileSize, global.j*global.tileSize); }    
        }
    }
    I have seen a lot of posts, which follow this logic:
    but until now, everything has worked as expected. When I put this in the draw event, the game lags down and goes insanely slow. So I kept it in Create event.

    Problem is, I need to change individual sprites, from 1's, to 0's, or visa versa, and draw_sprite command isn't working when I use this code from the player/mouse step event:
    Code:
    var tileCheck = ds_grid_get(global.grid1, mouse_x div global.tileSize, mouse_y div global.tileSize);
        if(tileCheck = 1){ 
        global.grid1[# mouse_x div global.tileSize, mouse_y div global.tileSize]    = 0;
        draw_sprite(sCells, 3, mouse_x div global.tileSize, mouse_x div global.tileSize);
    }//however, this does not change the image from the 1/0 to the '3' image.  

    I can't just move the create event code to the draw event, ( i dont think so, can I??)

    How should I manage this with an eye towards performance management in the future?


    Edit: Adding - This is the contents of the draw event in the level object:
    Code:
    if not surface_exists(surf){   
        surf = surface_create(room_width, room_height);
        surface_set_target(surf); // set the surface target
    }
    draw_surface(surf, 0, 0);
     
  2. Simon Gust

    Simon Gust Member

    Joined:
    Nov 15, 2016
    Posts:
    3,185
    What you want to do is having a surface with everything drawn on it once. As long as the surface is intact and you aren't changing anything on the map, you'll only have to draw the surface and no cells.
    You said your game lags when you continously draw, this leads me to believe that your map is very large and drawing everything on the surface once can cause lag for one frame.

    There are some things you can do to improve drawing time by optimizing.
    CREATE EVENT
    Code:
    // shortcut global variables
    var grid = global.flooring;
    var size = global.tileSize;
    
    // create surface
    global.surface = surface_create(mazeW * size, mazeH * size);
    
    // set surface drawing
    surface_set_target(global.surface);
    draw_clear_alpha(0, 0);
    
    // double for-loop
    for (var i = 0; i < mazeW; i++) 
    {
        var xx = i * size;
        for (var j = 0; j < mazeH; j++) 
        {
            var yy = j * size;
           
            // get cell at i, j
            var cell = ds_grid_get(grid, i, j);
           
            // draw to surface
            draw_sprite(sCells, cell, xx, yy);
        }
    }
    
    // reset surface drawing
    surface_reset_target();
    
    Here I've made sure that variables get calculated as soon into the loop as possible, that way less calculations have to be done.
    Second thing is the use of local variables, they are faster to read and write as global variables.

    DRAW EVENT
    Code:
    draw_surface(global.surface, 0, 0);
    
    If this isn't enough for it to not lag you will have to look into other methods to draw.

    paint over method
    You keep everything on the surface and when you change something you just draw over the old drawings.
    This works easily as long as your cells aren't neighbour-dependent (like autotiling)
    Example
    Code:
    // on mouseclick
    if (mouse_check_button_pressed(mb_left)) 
    {
        // get coordinates
        var i = mouse_x div global.tileSize;
        var j = mouse_y div global.tileSize;
       
        // set surface drawing
        surface_set_target(global.surface);
       
        // draw over cell
        var tileCheck = ds_grid_get(global.grid1, i, j);
        if (tileCheck == 1) 
        { 
            // change data
            ds_grid_set[global.grid1, i, j, 0);
            var xx = i * global.tileSize;
            var yy = j * global.tileSize;
           
            // clear cell by erasing
            gpu_set_blendmode(bm_subtract);
            draw_sprite(sWhiteCell, 0, xx, yy); // preferably just a normal sprite that is just a white rectangle
           
            // draw new cell
            gpu_set_blendmode(bm_normal);
            draw_sprite(sCells, 3, xx, yy);
        }
       
        // reset surface drawing
        surface_reset_target();
    }
    
    chunk method
    It's best to watch these videos, they are a great example.
     
  3. Yal

    Yal GMC Memer GMC Elder

    Joined:
    Jun 20, 2016
    Posts:
    3,742
    The draw event is run at least 30 times per second (if you use the default room speed), the create event is run once in an object's lifetime. If the map is always the same, it makes sense to only generate it once, not 30 times per second.
     
    ParodyKnaveBob likes this.
  4. Carcophan

    Carcophan Member

    Joined:
    Aug 4, 2019
    Posts:
    53
    Awesome post Simon, thank you so much. That is a great video too.

    I 'restarted' the file and am rewriting it, as a clean blank slate, implementing your and the pieces of my code together, but am still not able to get the draw_sprite to update the drawn map when I click. I still have to debug, so I may figure it out soon, but the player/enemy are also not loading on the map anymore, so I have to work that out. I will keep plugging away. :)

    I would say the lag is secondary to the sprite updating, in overall importance. But addressing one may address the other, I think.
     
  5. Carcophan

    Carcophan Member

    Joined:
    Aug 4, 2019
    Posts:
    53
    So it looks like I am having success now, with changing sprites/tiles on the map. I was able to implement your code suggestions and learned during that process that the only "real" differences from my original code is the additions of the (very important) GPU_SET_BLENDMODE which I was not aware of until you posted your suggestion. Aside from being cleaner and faster :)


    This was a big step forward, thank you so much again for your help.

    Once I get the enemy/player spawning on the map, and AI and some menu stuff settled, I look forward to posting an early alpha type release to get some very early feedback!!
     
    Last edited: Oct 14, 2019

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