• Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

Discussion will gamemaker 2 support yield and wait for the new functions and possibly events?

S

Shadowblitz16

Guest
will gamemaker 2 support yield an wait keywords this year?
I think it would make a good addition to functions and might also be useful if you could use them in events as well

Code:
var x = 0
yield (x++ >= 4);
wait(4);
//Do something
this is just example code so I'm not sure if its correct but you should get the idea
basically this would be a alternative to alarms but for functions and events
 
Last edited by a moderator:

Evanski

Raccoon Lord
Forum Staff
Moderator
A wait function would be very useful seeing you cant call alarm events in scripts
 
S

Shadowblitz16

Guest
I would prefer it to be a keyword that works similar to yield but accepts time in frames
I don't think yield works outside it's scope in other languages so trying to create a wait function wouldn't work
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
There are no plans for this in the future, but that doesn't mean you can't file it with the helpdesk as a feature request. :)
 

TsukaYuriko

☄️
Forum Staff
Moderator
You can find the feature request form on the contact page - it's one of the dropdown options - so yes, same link as the bug report form.
 
S

Shadowblitz16

Guest
@TsukaYuriko thankyou so much.
EDIT: sent it :D
hopefully the yoyo games devs see it and like it.
 
Last edited by a moderator:

FrostyCat

Redemption Seeker
YoYo should not bow to suggestions that arise from ignorance of basic techniques, in this case asynchronous handling of sequential actions.

This suggestion is only ever meaningful for people who over-complicate their code by never delegating between events and components. It's an emotional outburst from novice users when they run into walls with poor code architecture, in particular the kind dictated by the cult of "everything-in-one-place". Anyone who is past that stage and does delegate can see a variety of existing alternatives in GM, some even designed explicitly for the purpose:
  • Timelines
  • Worker objects
  • Asynchronous events
  • Manual/built-in alarms
  • Scripted solutions such as TMC Script Batch
And with the upcoming introduction of chained accessors and lambdas, promise-like mechanisms such as the kind in modern Javascript will also become a viable alternative, with generality surpassing all of the above options yet also permitting the delayed actions to be specified in the same piece of code.

The suggestion also fails to think of contradictions with existing syntax and functionality. Consider the following:
Code:
///@func foo()
wait(4);
return "FOO";
Code:
///@desc Draw event
for (var i = 0; i < 10, i++) {
  draw_text(x, y, foo());
}
If it returns "FOO" right away, then the wait didn't happen, thus violating the suggestion's premise. If the wait does happen, a run of the Draw event code will be delayed past schedule, likely to a point where it becomes inconsistent with the engine's internal state. There's no way for conflicts like this to be resolved in a way that is consistent with clear-cut, reliable execution.

Compared to learning how to do asynchronous sequential actions properly with existing and well-defined techniques, introducing loosey-goosey, self-contradictory syntax to GM is a far worse alternative.
 

Hyomoto

Member
I can't say anything Frosty Cat hasn't already said better, but I support his conclusion. However, it's already possible to do this. The wait as described is nothing more a program execution pause, a purposeful code hang. You essentially "lag" execution. If you wanted to wait in this way, you could write a function that is nothing more than a loop that continues until some time passes.
Code:
@func wait( time );
var _wait = delta_time + argument0;
while ( delta_time < _wait ) { continue }
We simply get our current time, add the amount we want to wait to it, and then freeze execution with a while loop until that time passes. At that point the loop ends, and the program execution continues. The reason I assume GML doesn't include this as a built-in function, as opposed to trigonometry for is example, is because hanging program execution is not a good habit to get into.
 
Last edited:

Tthecreator

Your Creator!
I can't say anything Frosty Cat hasn't already said better, but I support his conclusion. However, it's already possible to do this. The wait as described is nothing more a program execution pause, a purposeful code hang. You essentially "lag" execution. If you wanted to wait in this way, you could write a function that is nothing more than a loop that continues until some time passes.
Code:
@func wait( time );
var _wait = delta_time + argument0;
while ( delta_time < _wait ) { continue }
We simply get our current time, add the amount we want to wait to it, and then freeze execution with a while loop until that time passes. At that point the loop ends, and the program execution continues. The reason I assume GML doesn't include this as a built-in function, as opposed to trigonometry for is example, is because hanging program execution is not a good habit to get into.
Just as a clarification, this is like a proof of concept function. Please don't actually use this. A decent sleep function tells the OS not to execute the program's/thread's instructions for X amount of time. This one just lags the CPU sucking up resources.

If you need a timeout in your code, it's probably not very good code. (Except perhaps if it is something async)
 
S

Sam (Deleted User)

Guest
Just as a clarification, this is like a proof of concept function. Please don't actually use this. A decent sleep function tells the OS not to execute the program's/thread's instructions for X amount of time. This one just lags the CPU sucking up resources.

If you need a timeout in your code, it's probably not very good code. (Except perhaps if it is something async)
Well, a similar thing is done as a common practice in VBScript, so it can't be all bad. Sometimes, like when using Microsoft Script Control, or the IActiveScript Interface, you don't have access to the normal WScript.Sleep method, so you have no choice but to use a delta time while loop. Have you actually tested this and verified it eats up resources? Or did you just read that somewhere?
 

chamaeleon

Member
I'm anxiously awaiting a good example of a use case for a wait/pause function that halts the execution of everything, every step, every draw event, until the required time has elapsed. Right now that would be equivalent to having disabled every object except a controller object that only checks for elapsed time in a step event or until an alarm goes off, at which point all objects are enabled again. What is the use case for this? Given no other side functionality.
 

Tthecreator

Your Creator!
@Samuel Venable I know from C/C++/C# experience.
If I run the following C program on my computer:
Code:
int main(int argc, char** args){
[INDENT] while(true){
[INDENT]//do nothing[/INDENT]
}[/INDENT]
}
I can see that the program uses about 4,0% CPU. If I look at per core utilization I can see one of my cores being 100%.
upload_2019-7-8_23-27-46.png(I couldn't get a better screenshot since the program keeps jumping from core to core)
It actually kind of differs per programming language. Lower level languages have more problems with this than higher end ones. This is why I can't say for certain how GameMaker will deal with this. I'd have to test that. I'll do that in a moment.


EDIT:
Jup, a while(true){} loop in gm does indeed result into high resource usage
upload_2019-7-8_23-41-26.png
 
Last edited:
S

Sam (Deleted User)

Guest
@Samuel Venable I know from C/C++/C# experience.
If I run the following C program on my computer:
Code:
int main(int argc, char** args){
[INDENT] while(true){
[INDENT]//do nothing[/INDENT]
}[/INDENT]
}
I can see that the program uses about 4,0% CPU. If I look at per core utilization I can see one of my cores being 100%.
View attachment 25651(I couldn't get a better screenshot since the program keeps jumping from core to core)
It actually kind of differs per programming language. Lower level languages have more problems with this than higher end ones. This is why I can't say for certain how GameMaker will deal with this. I'd have to test that. I'll do that in a moment.
Yeah, VBScript is scripting language as the name suggests, therefore it's not exactly the same category of thing as raw C++, and that's why I was curious how GM would react to it, in which direction would it lean to...

However, I've seen while (true) used many times in software, most notably game engines. That's what a main game loop is. It executes every step without fail, at least until it either crashes or a break is called, like in most cases it would on the close button and/or escape key for the latter.
 

GMWolf

aka fel666
YoYo should not bow to suggestions that arise from ignorance of basic techniques, in this case asynchronous handling of sequential actions.

This suggestion is only ever meaningful for people who over-complicate their code by never delegating between events and components. It's an emotional outburst from novice users when they run into walls with poor code architecture, in particular the kind dictated by the cult of "everything-in-one-place". Anyone who is past that stage and does delegate can see a variety of existing alternatives in GM, some even designed explicitly for the purpose:
  • Timelines
  • Worker objects
  • Asynchronous events
  • Manual/built-in alarms
  • Scripted solutions such as TMC Script Batch
And with the upcoming introduction of chained accessors and lambdas, promise-like mechanisms such as the kind in modern Javascript will also become a viable alternative, with generality surpassing all of the above options yet also permitting the delayed actions to be specified in the same piece of code.

The suggestion also fails to think of contradictions with existing syntax and functionality. Consider the following:
Code:
///@func foo()
wait(4);
return "FOO";
Code:
///@desc Draw event
for (var i = 0; i < 10, i++) {
  draw_text(x, y, foo());
}
If it returns "FOO" right away, then the wait didn't happen, thus violating the suggestion's premise. If the wait does happen, a run of the Draw event code will be delayed past schedule, likely to a point where it becomes inconsistent with the engine's internal state. There's no way for conflicts like this to be resolved in a way that is consistent with clear-cut, reliable execution.

Compared to learning how to do asynchronous sequential actions properly with existing and well-defined techniques, introducing loosey-goosey, self-contradictory syntax to GM is a far worse alternative.
And anyone who has written a script (not like a GML a script, but like, a script script, where you have instructions, timings, and under interactions, like in a dialogue system for example) knows the value of coroutines!
They are invaluable.
Sure you can have an array of instructions etc, but even that is limiting.
Coroutines allow you to describe these scripts very naturally, and with a lot less fuss and boilerplate.

I would love to see coroutines.
It's one of the things scripting languages are great for. And would greatly help in tasks such as cutscenes, dialog systems etc.

They would help people polish their games without needing to develop more complex systems just for ,say, a cutscene system.

And more than just the scripty things!
Man, writing a log in system with proper handshakes require managing a lot of different states!
Or you can use a couple coroutines and describe the sequence of state really naturally, writing the logic as if you didn't have to wait for server responses and all!

They are a tremendously useful tool!
 
Last edited:
S

Shadowblitz16

Guest
I don't see why everytime a suggestion for gml is posted most people shun it.
coroutines are a easy way to delay code execution and it doesn't take much power to use them.
lua and java script have coroutines and gml is a lot like javascript.

I think implementing coroutines right into functions and events would probably be a easier for non programmers that use gml.
simple yield a value and optionally pass a condition or amount of frames you want the yield to happen for..
Code:
function animate(index, speed)
{
    yield(index, speed); //return index for 4 frames.
    index=index+1;
    return index
}
image_index = animate()
this is probably better then using keywords since you can pass optional values like a condition or frames to wait.
 
S

Shadowblitz16

Guest
a better example of this would be a sword swing for example...
(NOTE I SWITCH THE RETURN AND WAIT TIME AROUND SINCE THE RETURN CAN BE OPTIONAL)
Code:
function swing(speed, angle)
{
    sword = new sword(x,y)
    sword.angle = angle;
    sword.angle = angle+90;
    yield(speed/5);
    sword.angle = angle+45;
    yield(speed/5);
    sword.angle = angle+00;
    yield(speed/5);
    sword.angle = angle-45;
    yield(speed/5);
    sword.angle = angle-90;
    yield(speed/5);
}

swing(0.5, image_angle
or if you wanted to check against if it was done then you could do..
Code:
function swing(speed, angle)
{
    sword = new sword(x,y)
    sword.angle = angle;
    sword.angle = angle+90;
    yield(speed/5, false);
    sword.angle = angle+45;
    yield(speed/5, false);
    sword.angle = angle+00;
    yield(speed/5, false);
    sword.angle = angle-45;
    yield(speed/5, false);
    sword.angle = angle-90;
    yield(speed/5, false);
    return true;
}

while(swing(0.5, image_angle))
{
    //sword is swinging
    yield();
}
//sword is done swinging
 

Hyomoto

Member
Well, probably for focusing on wait. Yield has visible benefits and can make sense, I can see them being helpful. I have not seen any evidence that suggests wait is equally helpful. So perhaps it's worthwhile to break them apart, and rather than treating them as equally meritorious discuss their merits separately.
 

FrostyCat

Redemption Seeker
Anyone seeking to make this syntax a reality must answer for the contradiction I raised in post #12.
The suggestion also fails to think of contradictions with existing syntax and functionality. Consider the following:
Code:
///@func foo()
wait(4);
return "FOO";
Code:
///@desc Draw event
for (var i = 0; i < 10, i++) {
draw_text(x, y, foo());
}
If it returns "FOO" right away, then the wait didn't happen, thus violating the suggestion's premise. If the wait does happen, a run of the Draw event code will be delayed past schedule, likely to a point where it becomes inconsistent with the engine's internal state. There's no way for conflicts like this to be resolved in a way that is consistent with clear-cut, reliable execution.
Other languages supporting co-routines don't require specific synchronization with a fixed event cycle. This is not the case with GML, and needs special handling.

One potential resolution would be to mark coroutines with a distinct keyword, such that it cannot be used anywhere instantaneous returns are expected. Then execution instances tied to a specific event are spawned using blocks in which both coroutines and regular functions can be used:
Code:
coroutine animate(sprite, from, to) {
  sprite_index = sprite;
  image_index = from;
  repeat (abs(to-from)) {
    sleep(1);
    image_index += sign(to-from);
  }
}
Code:
/// Step event
if (hp < 0 && !dying) {
  dying = true;
  corun (ev_step) {
    animate(spr_dying, 0, 16);
    animate(spr_disappear, 0, 16);
  }
}
In any case, any attempt at coroutines in GML must keep a clear line between regular execution and coroutine execution, and coroutines must have well-defined relationships to the step cycle. Otherwise it runs the risk of becoming internally inconsistent. And I'd rather take a language that's marginally less friendly than a language that contradicts itself.
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
GMEdit has a coroutine compiler. If at least 3 people confirm that they are willing to give me $5, I can look into making a version that does not require GMEdit to function (taking a script and generating code into another script).

Since coroutines add a degree of complexity to multiple features, I somewhat doubt that we'll be seeing an official implementation of this within the next year.
 

GMWolf

aka fel666
Anyone seeking to make this syntax a reality must answer for the contradiction I raised in post #12.

Other languages supporting co-routines don't require specific synchronization with a fixed event cycle. This is not the case with GML, and needs special handling.

One potential resolution would be to mark coroutines with a distinct keyword, such that it cannot be used anywhere instantaneous returns are expected. Then execution instances tied to a specific event are spawned using blocks in which both coroutines and regular functions can be used:
Code:
coroutine animate(sprite, from, to) {
  sprite_index = sprite;
  image_index = from;
  repeat (abs(to-from)) {
    sleep(1);
    image_index += sign(to-from);
  }
}
Code:
/// Step event
if (hp < 0 && !dying) {
  dying = true;
  corun (ev_step) {
    animate(spr_dying, 0, 16);
    animate(spr_disappear, 0, 16);
  }
}
In any case, any attempt at coroutines in GML must keep a clear line between regular execution and coroutine execution, and coroutines must have well-defined relationships to the step cycle. Otherwise it runs the risk of becoming internally inconsistent. And I'd rather take a language that's marginally less friendly than a language that contradicts itself.
This wait function isn't really necessary for coroutines.
All you need is yield and resume. Lua style.
Then you have no issues.
You could write these scripts as follows:
Code:
///Coroutine
yield [ "", 5]; //no text, sleep 5 seconds
yield[ "FOO", 0]; //some text, no sleep
Code:
//Create event
timer =0;
text = "";
routine = coroutine ();
//Step event
if (timer <= 0)
{
   if (!co_alive(routine)) instance_destroy();
   var ret = co_resume(routine);
   text = ret[0];
   timer = ret[1];
   //Draw text here
}
timer -= dt;
This structure allows you to write these sorts of sequence of events quite naturally, but with a generic, and safe coroutine system.

The best thing is this just needs generators!
When calling your coroutine, you return an object that stores the stack state of the function. You split the coroutine function into an array of functions between yields.
Then the co_resume is quite simple, increment your script index and execute it, with the object as the variable store.
 
Last edited:

Hyomoto

Member
I would argue for people who want that complexity, they should be using GMedit. I'm not one to sell products, but for people who wish GML had feature X, GMedit probably does.

I'm not one of this community's prolific members, so I often feel like I'm shouting at the feet of giants, but I have been with GM long enough to know that everyone has a version of the language they think it should be. The feature GML is always missing just so happens to be, "that feature from another language I like." I've never seen someone argue GML should adopt features they hate because it would be good. In this case, coroutines. Do they add something to GML? Are you just frustrated not having it? GML isn't pure and chaste, I'm glad for any improvements. The question still becomes is this a feature that makes GML better, or is it one that makes it better for you? It's okay for GML to evolve, but it has conventions. Maybe it's like JavaScript, but it also isn't JavaScript. If the goal is simply to make another language, it might as well be another language. So how do they fit in the conventions of GML? Take @GMWolf 's example.
Code:
switch ( argument0 ) {
  case 0 : return [ "", 5 ];
  case 1 : return[ "FOO", 0 ];
}
return undefined
Code:
// create
timer = 0;
segment = 0;
text = "";
routine = my_routine;
// step
if ( timer <= 0 ) {
  var _ret = script_execute( my_routine, segment++ );
  if ( is_undefined( my_routine ) { instance_destroy(); }
  timer = ret[ 0 ];
  text = ret[ 1 ];
}
timer -= dt;
It's a simple source example but the only thing being transposed to the coroutine is state. We've gotten rid of the switch block and segment variable but it's because we've passed those off into the GML aether. It's why I agree with Frosty's original post. Much of what's being made of this seems to rely on wanting a specific implementation, rather than that GML lacks alternatives (some which may be equally useful). As for @Shadowblitz16 's example, what happens if this coroutine is interrupted because the player is struck, or falls off a cliff or a timer ends? Now you have some vague state floating around that you end up having to handle just because you were hoping to pass state handling off to the coroutine. Your example is precisely why you shouldn't use a coroutine there. That rabbit hole is going to lead to a lot of "I have no idea what state my character is in" situations. My point here isn't that current methods are superior, but coroutines are being advocated for in a way here that suggests their worst case uses, not their best. They seem most useful during complex logic chains where a lot of waits happen because it's impossible to know the rate or reliability of data processing. For example, a network login or an IAP. But as a function of basic game state? Not only can you do it other ways, you probably should.
 

GMWolf

aka fel666
Take @GMWolf 's example.
Code:
switch ( argument0 ) {
case 0 : return [ "", 5 ];
case 1 : return[ "FOO", 0 ];
}
return undefined
Code:
// create
timer = 0;
segment = 0;
text = "";
routine = my_routine;
// step
if ( timer <= 0 ) {
var _ret = script_execute( my_routine, segment++ );
if ( is_undefined( my_routine ) { instance_destroy(); }
timer = ret[ 0 ];
text = ret[ 1 ];
}
timer -= dt;
It's a simple source example but the only thing being transposed to the coroutine is state.
Yeah sure but once you have variables, conditions etc having generators does help.

Take this for example:
Code:
yield "hi";
yield "how are you?";
var flag = some function();

yield "foobar";
var aaaa = 89;
if (flag)
{
  yield "text text text";
  aaaa = 67;
   yield "more text";
}
else
{
   yield "thing";
   yield "I like cake!"
}

aaaa *= 6;
 
yield "the number was: " + string(aaaa);
Very natural way to define a script.
Much harder without coroutines.

Don't get me wrong I'm not saying GML should get this, just pointing out how coroutines could work in GML.
 
Top