• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GameMaker "While" function not working in scripts

M

MaestroMetty

Guest
Hi I need to create a timer in my script so i can show a text for 3 seconds, i tried using this code but it's showing, i think, multiple copies of the same texts for less than a second and then not changing the state, remaining in the same state forever. This is the code:

Code:
var _tick = 0;
while(_tick < 3*room_speed)
{
    _tick++;
    draw_text(20,60,"Password salvata");
}

if(_tick > 3*room_speed) systemStates = systemStates.FirstCommand;
Anyone can help? Thanks.
 

NightFrost

Member
While is working as it should. Beginning coders many times make the assumption that loops somehow spread across multiple steps. They do not, but instead always run into completion in a single step (or in case of loops that never satisfy their exit clause, loop infinitely and lock the program). In this specific case, the while-loop will keep running until _tick has increased to room_speed*3, and then code execution resumes on the line following the loop. To make it work properly, you gave to:
Code:
// CREATE EVENT
_tick = 0;

// STEP EVENT
if(_tick < 3 * room_speed){
    _tick++
} else {
    systemStates = systemStates.FirstCommand;
}

// DRAW EVENT
if(_tick < 3 * room_speed){
    draw_text(20, 60, "Password salvata");
}
Alternatively, you could use an alarm. This would be a good case to study how they work if you're not familiar with them yet.
 
M

MaestroMetty

Guest
Is there any way to create a working timer with every information and variables needed inside of one or multiple scripts?
 

curato

Member
yes, alarm is definitely the way
Code:
// create
draw_it = true;
alarm[0] = 3 * room_speed;

// draw event
// draw_self();// if needed
if (draw_it) then
{
     draw_text(20, 60, "Password salvata");
}

//alarm[0]
draw_it = false;
 
M

MaestroMetty

Guest
yes, alarm is definitely the way
Code:
// create
draw_it = true;
alarm[0] = 3 * room_speed;

// draw event
// draw_self();// if needed
if (draw_it) then
{
     draw_text(20, 60, "Password salvata");
}

//alarm[0]
draw_it = false;
I knew i could use alarms, but it seems to me a "rusty" way, I was looking for a way to put all i need inside a script because in the future i will need lots of timers. Thanks for the reply anyway.
 

NightFrost

Member
Is there any way to create a working timer with every information and variables needed inside of one or multiple scripts?
Well you could wrap the code of all three events into scripts and call when you need to. However, the counter variable (_tick) needs to persists across multiple steps so you can't declare it in var scope. So it makes no difference calling it in create or through a script in create, the variable is a permanent part of the instance thereafter. The text needs to be done in draw because it is a draw. You could combine the step code into it, but YYG does not recommend running non-draw code in draw events for performance reasons. Though that's just a small code fragment.
 

FrostyCat

Redemption Seeker
You need to learn to delegate to workers. "Helicopter programming" is fundamentally incompatible with doing things over time in GML.

Create a new worker object called obj_popup_text and set up its events like this:

Create:
Code:
text = "";
alarm[0] = 1;
owner = noone;
callback = undefined;
callback_argument = undefined;
Alarm 0:
Code:
instance_destroy();
Destroy:
Code:
if (instance_exists(owner)) {
  with (owner) {
    script_execute(other.callback, other.callback_argument);
  }
}
Draw:
Code:
/* Remember to set your font and drawing colour here */
draw_text(x, y, text);
Now add a script called create_popup that wraps the creation of obj_popup_text:
Code:
///@desc create_popup(x, y, message, <duration>, <callback>, <callback_args>)
var inst = instance_create_layer(argument[0], argument[1], layer, obj_popup_text);
with (inst) {
  owner = other.id;
  text = argument[2];
  if (argument_count >= 4) alarm[0] = argument[3];
  if (argument_count >= 5) callback = argument[4];
  if (argument_count >= 6) callback_argument = argument[5];
}
return inst;
And add another script called setvar that wraps variable_instance_set():
Code:
///@desc setvar([varname; varval])
variable_instance_set(id, argument0[0], argument0[1]);
Then what you want can be safely wrapped in a single call:
Code:
create_popup(20, 60, "Password salvata", 3*room_speed, setvar, ["systemStates", systemStates.FirstCommand]);
 
Top