Solved - Drawing Rectangle over time in GUI

Iskardes

Member
Hi,

I have some semi-working code in my project that runs a script when the player clicks on certain tiles in-game. I'm struggling with slowing things down to get a smooth look!

What I want to happen is:
  • The player clicks the tile.
  • A small blue bar appears in the tile below and fills from left to right.
  • Once the bar has filled, the bar disappears and the selected tile gets added to the players inventory.
This does all happen, however it happens in less than a second. What I want to do is to slow down the rate at which the bar fills, so it takes roughly 2 seconds for the bar to fill and then the player gets the tile.
Here is the code relevant to the bar being triggered:
GML:
if (mouse_check_button_pressed(mb_left) && (_dataWater!= 0))
                {
                //Charge effect - draw blue bar underneath tile

                for (var i = 0; i < obj_player.element_pickup_charge; i++)
                {
                    var _percent = i / obj_player.element_pickup_charge;
                    
                    draw_set_alpha(0.3);
                    draw_rectangle_color((mx div _cs) * TILE_SIZE, ((my div _cs) * TILE_SIZE) + TILE_SIZE + 5,
                    (_gx * TILE_SIZE) + (_percent * TILE_SIZE), (_gy * TILE_SIZE) + TILE_SIZE +  7, c_blue, c_blue, c_blue, c_blue, false );
                    draw_set_alpha(1);
                    
                    
                
                }
                
                ElementListAdd(EL_TYPE.WATER);
                }
This is how it looks in runtime:
(I've set the value for obj_player.element_pickup_charge to be really high thinking the amount of loop iterations would take longer, am I wrong for thinking so??)

TilePickup.png

I've tried altering the integers used in my for loop code, but nothing seems to slow the process down! I've also looked in the manual and there aren't any YouTube videos I could find that match my problem / search. Any advice or pointers would be helpful and much appreciated.
Thanks in advance!
 

Nidoking

Member
(I've set the value for obj_player.element_pickup_charge to be really high thinking the amount of loop iterations would take longer, am I wrong for thinking so??)
Yes. No graphics processing of any kind happens during a loop. You need to handle the iterations of drawing different sized rectangles in separate steps to see what you want.
 

Iskardes

Member
Yes. No graphics processing of any kind happens during a loop. You need to handle the iterations of drawing different sized rectangles in separate steps to see what you want.
Thanks for getting back to me, I didn’t realise that! What’s misleading me is that the full blue bar appears for a millisecond, do you know why that would be? Like you say no processing seems to be happening, but for some reason the full bar flashes up. 🤦🏼‍♂️

9B8A428F-954D-45CA-8F04-841F3A60FDB7.jpeg
 

Nidoking

Member
In short, the Draw events tell the graphics card what to draw on the screen where, but the actual drawing doesn't happen until after all of the events are complete. So the way you'd written it, the sequence was:
Loop through placing blue rectangles of increasing size in the graphics buffer.
The loop ends.
The event ends.
Draw the contents of the graphics buffer, which is now just the largest rectangle.
Next step:
The mouse button has not been pressed since the last step, so do not draw the rectangles.
Draw the contents of the graphics buffer, with no rectangles.
etc.
 

gkri

Member
I am not sure I understood what you are trying to do, but if you want to change a value over time you can use this script (create a new script, name it approach.gml and copy paste the following code):

GML:
/// @func approach(target, endpoint, amount);
/// @description move target to endpoint by given amount
/// @arg target
/// @arg endpoint
/// @arg amount

if(argument0 < argument1) return min(argument0 + argument2, argument1);
    else return max(argument0 - argument2, argument1);
A small example of how you could use it :

GML:
//create event
fill_bar = false;
percent = 0;

//step event
if mouse_check_button_pressed(mb_left) and _dataWater!= 0 then fill_bar = true;

//draw event or step event depending what you want to do               
if fill_bar
{
    percent = approach(percent, 100, 1); //will add 1 to percent every step
    // your code here what you want to do when the percent is raising   

    if percent == 100
    {
       //reset the values
        fill_bar = false;
        percent = 0;
        // rest of code what to do after percent reach 100
    }
}
 

Yal

🐧 *penguin noises*
GMC Elder
GM doesn't have parallel processing, so your loop will pause the rest of the game until it's done, and then resume. So depending on how good your CPU is, your old approach will either have no discernible effect, or cause a lagspike.
 

Iskardes

Member
It's probably showing for 1 frame, the frame that you click the mouse on. That's totally expected with the way you are trying to do it. The number one rule is you do not use loops for things you want to happen "gradually", whether that be a quarter of a second or an hour. Have a read over this page: https://forum.yoyogames.com/index.p...p-structures-vs-step-checks-and-alarms.39941/
Thanks for replying with this, I’m still new to GMS2 and it really helped me understand what’s happening in the background! This fixed my problem, I made a new object with an animated sprite, then used a step check / alarm and everything flows nicely now 😂
 
Top