Jump to content


Photo

Enabling Sequential Programming


  • This topic is locked This topic is locked
24 replies to this topic

#1 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Member
  • 15878 posts
  • Version:GM:Studio

Posted 23 February 2008 - 05:06 AM

OK guys, this is truly an expert topic…

Remember the old days of sequential programming when you would wait for something like user input or wait ‘till a task was done before progressing further in the code execution?

Well, for a while, I’ve been thinking of a way to be able to make gm objects work like that. Such as when you ask for text using get_string(), I wanted to be able to make my own GM objects act like a message box.

Or pop up a menu system that uses all of GM’s features, using objects and event to draw the menu, react to mouse click, alarms and so forth… But wait until the menu is done before continuing.

Well, here it is…

Posted Image
[Updated Feb 25 2008 12:43 PM]

I wrote a GMGameLoop that emulates a GM game frame with most events being triggered manually, to the best of my knowledge and skills.

What it allows to do (eventually) is to create an interface that works/acts as though it’s being run normally, but really, it’s executing within a loop.

Goodbye screen capture, instance_deactivate, clunkyness…

instance_create(x,y,MenuObj)
GameLoopObjectTillGone(MenuObj)
show_message(“Ah, you are done making your choice!? Good. Let’s get back to the game”);

So, would you kindly take a gander at the code and tell me what you think… If I missed anything or programmed something wrong…

Also, if you could try it out in one of your games? I need to know if I thought of everything and if everything is working as it would normally... There are simply too many variations to verify all by myself.


Also, check out the main function and see if anything could be made to work more efficiently.

Thanks, have fun. You’ll love this, I promise.


[Update Feb 23 2008]
Changed while for repeat in NSteps
Added Optional keyboard key in NSteps
moved var s to top of script
Added more accurate timer in GameFrame Tested with 240 room_speed (Yay) (Thank Yourself and myself)
fixed-xprevious,yprevious ommision

[Update Feb 25 2008 12:43 PM]
Moved the Script in the demo object to an alarm (hoping this fixes GM6 hang problem)
Added recommended check if the event is currently executed so not to stack fault.
Fixed a code mistake for the _wasin local var... was using global_get (thank sinaz)
12:43
Potential fix for CPU hogging (thank xot)

[KNOWN ISUES]
-dumbfounded >>mouse down triggers mouse pressed<<
-solid object collision cannot be emulated (properly) unless I find a way to see if the colliding objects have a collision event. As the demo shows...
-demo ran in GM6 hangs (hopefully fixed Feb 25 2008)
-takes a lot of processor... (so!?? It's dedicated to the game :D Perhaps I can wip up a little DLL to handle this but I would prefer to keep this pure GML) (FEB 25 12:43 fixes it I hope)
>>issues with >>these<< means HELP ME!<<

Edited by icuurd12b42, 25 February 2008 - 05:48 PM.

  • 0

#2 Sinaz

Sinaz

    MCP Killer

  • GMC Member
  • 2751 posts
  • Version:GM8

Posted 23 February 2008 - 04:30 PM

This is a really interesting concept and example. I'd like to put it through some paces with Yourself's high-resolution timer.

In the mean time, looking through the code, I noticed a few minor optimizations that could be made.

The first is in the GameLoopForNSteps() script. Why not use repeat() instead of while() since the iteration count seems to be fixed. This will eliminate one variable assignment and one comparison per iteration.

The other is that you do not need to use the time functions to wait for a room tick. Instead, remove the ct variable, and add the screen_wait_vsync() just before the draw event execution, and the system will stop ALL execution while it waits for the next v scan.

I think that would be an ideal solution, since your code is essentially trying to time it for the v-sync anyway. This will overcome the inaccuracy of GM's time functions.

speed -= friction;

^^ this is a bit precarious. I don't like the way you set it and cap it... try this:

speed = max(0, speed - friction);

one less comparison to make, and you are only making one assignment to the speed variable.

I also wonder if you've fully tested the collision portion to see if it behaves appropriately for solid vs. non-solids. The execution is detailed in the GM Helpfile.

Kudos, as well to the keyboard event design.

PS: One last thing... with any of these loops, you need to have a global LoopTillKeyPress feature working somewhere because you cannot exit the program while the loop is running. It could be a toggle just like GM's global settings, mapped to Escape by default.
  • 0

#3 xot

xot

    GMC Dismember

  • GMC Member
  • 4772 posts
  • Version:GM:Studio

Posted 23 February 2008 - 05:06 PM

speed = max(0, speed - friction);

That's a little precarious, too. What if speed needs to be negative?

Of the top of my head:
speed = sign(speed) * max(0, abs(speed) - friction);

Maybe there is a better solution.
  • 0

#4 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Member
  • 15878 posts
  • Version:GM:Studio

Posted 23 February 2008 - 07:14 PM

This is a really interesting concept and example.  I'd like to put it through some paces with Yourself's high-resolution timer.

In the mean time, looking through the code, I noticed a few minor optimizations that could be made.

The first is in the GameLoopForNSteps() script.  Why not use repeat() instead of while() since the iteration count seems to be fixed.  This will eliminate one variable assignment and one comparison per iteration.

Yes, though the function does call another that waits for the next frame. I'll add it in for good measure.

The other is that you do not need to use the time functions to wait for a room tick.  Instead, remove the ct variable, and add the screen_wait_vsync() just before the draw event execution, and the system will stop ALL execution while it waits for the next v scan.

I though of that but, no, I’m tied to the room_speed, not the vsync

I think that would be an ideal solution, since your code is essentially trying to time it for the v-sync anyway.  This will overcome the inaccuracy of GM's time functions.

Actually, the resolution of the current time is 1 ms (GetTickCount()). Even if there is a potential for error, 1000/60 = 16 millisecs to play with… So I only foresee a problem if you set the room_speed to a ludicrous value.

[edit]It was a problem. using better technique now[/edit]

+ I get the time at the top of the loop, so if the time to execute the code is longer than a frame, the code will exit right away. If I had missed a vsynch while in the code, I would wait an extra vsynch at the bottom. Loosing 1 frame...



speed -= friction;

^^ this is a bit precarious.  I don't like the way you set it and cap it... try this:

speed = max(0, speed - friction);

one less comparison to make, and you are only making one assignment to the speed variable.

Like xot says, what it the friction is negative

I also wonder if you've fully tested the collision portion to see if it behaves appropriately for solid vs. non-solids.  The execution is detailed in the GM Helpfile.

In theory, it should but it’s pretty darn slow… [edit] Solid handling (GM placing the instances back to x/yprevious on collision) is not emulatable but the collision is still triggered which can be a problem (eg move_contact_solid)[/edit]

I need a method to eliminate some of the with() calls automatically… Like if there are no objects with this type of event hooked in, skip it…

But, being a set of script, you have the ability to remove some of the calles to make it faster for your setup. Like if your menu has no collision event, you can duplicate the script with that useless code stripped out.

Kudos, as well to the keyboard event design.

PS: One last thing... with any of these loops, you need to have a global LoopTillKeyPress feature working somewhere because you cannot exit the program while the loop is running.  It could be a toggle just like GM's global settings, mapped to Escape by default.

<{POST_SNAPBACK}>

Really? I thought the mouse emulation was much more freakish myself.

You actually are in charge of passing on the keycode to the functions (optional). Using vk_escape if you want to make it behave like GM. I forgot to set it up in GameLoopForNSteps… But the others do use it. The reason is that not all games respond to escape to quit, so I left it to the user to pass the vk_escape keycode to the script… But, if there was a way to actually get the global game settings in GML, I would add it in. Same for the vsynch setting.

speed = max(0, speed - friction);

That's a little precarious, too. What if speed needs to be negative?

Of the top of my head:
speed = sign(speed) * max(0, abs(speed) - friction);

Maybe there is a better solution.

<{POST_SNAPBACK}>


I’ll benchmark this…
Group Name,Test Name,Num Executions,Total Time (ms)
friction,Test1,5000000,40638 <xot>
friction,test2,5000000,39796 <current>

Same speed, current is tiny bit faster.

I did remove the var s; and the extra sign I had forgotten in the if

But really, much more time is wasted elsewhere in the loops. I need a way to optimise the usage of event_perform

Edited by icuurd12b42, 24 February 2008 - 05:31 PM.

  • 0

#5 Yourself

Yourself

    The Ultimate Pronoun

  • GMC Member
  • 7352 posts
  • Version:Unknown

Posted 23 February 2008 - 08:35 PM

So I only foresee a problem if you set the room_speed to a ludicrous value.


Like anything over 60?

Actually, the resolution of the current time is 1 ms (GetTickCount()).


Yes, that's its resolution, but it only updates 60 times/second, regardless of what your room_speed is set to, so you have an effect resolution of 16 ms. Which is, needless to say, terrible. Imagine if room_speed is set to 50. That means the minimum time spent in a frame should be 1000/50 = 20 ms. However, if current_time only counts in increments of 16 (or 15), you will almost always end up with frames that take a minimum of 30-32 ms to complete, which puts you squarely at 30 FPS, even if you have nothing else going on.

You essentially get locked in to these FPS values:

60, 30, 20, 15, 12, 10, ~8.6, 7.5, ~6.67, 6, ...

So you no longer have a continuum of room_speed values, they're actually discrete.
  • 0

#6 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Member
  • 15878 posts
  • Version:GM:Studio

Posted 23 February 2008 - 09:21 PM

Yes, that's its resolution, but it only updates 60 times/second, regardless of what your room_speed is set to, so you have an effect resolution of 16 ms. 

Finally, the explanation... Darn. It explains why the code was acting weird when I set the room speed higher than 30 just a few moments ago...

[snip]

You essentially get locked in to these FPS values:

60, 30, 20, 15, 12, 10, ~8.6, 7.5, ~6.67, 6, ...

So you no longer have a continuum of room_speed values, they're actually discrete.

<{POST_SNAPBACK}>


I understand. It's a shame we dont have access to GetTickCount()... Or is it GetTickCount that updates 60 times a second... You're the timer expert.

I just dont want to have to include a dll with this

...


Ah ha, I remembered a technique I used a year ago for an analoge clock. Well hidden withing the date_current_time function is a precision system accurate enough to use for this setup...

//var twelvehours, onehour, oneminute, onesecond, onethow;

//twelvehours = 1/2;

//onehour = twelvehours/12;

//oneminute = onehour/60;

//onesecond = oneminute/60;

//onethow = onesecond/1000;

//This performs a GM game frame on the object index or id passed as argument0
//It waits to match the game's room_speed
var ct;

ct= date_current_time() + .0000115740/ room_speed

//ct= date_current_time() + onesecond / room_speed

//ct = current_time+(1000 /(room_speed));

GameStepObject(argument0);

//draw_text(10,10,string(current_time-ct));
//screen_refresh();

//wait 'till it's time for the next frame
//while(current_time<ct) ct=ct;
while(date_current_time()<ct) ct=ct;

//screen_wait_vsync();


I tested it up to 240 room_speed

[I merged and edited your two posts together from the queue -Sinaz]

Edited by icuurd12b42, 24 February 2008 - 04:34 PM.

  • 0

#7 xot

xot

    GMC Dismember

  • GMC Member
  • 4772 posts
  • Version:GM:Studio

Posted 24 February 2008 - 11:30 AM

I’ll benchmark this…
Group Name,Test Name,Num Executions,Total Time (ms)
friction,Test1,5000000,40638 <xot>
friction,test2,5000000,39796 <current>

Same speed, current is tiny bit faster.


That makes sense. I remember testing min/max against if/else constructs and an optimal if/else chain is faster than a two or three argument min/max function call.

http://gmc.yoyogames...dpost&p=1923231
  • 0

#8 KC LC

KC LC

    Ex-Administrator

  • GMC Member
  • 5309 posts

Posted 25 February 2008 - 11:31 AM

You actually are in charge of passing on the keycode to the functions (optional). Using vk_escape if you want to make it behave like GM. I forgot to set it up in GameLoopForNSteps… But the others do use it. The reason is that not all games respond to escape to quit, so I left it to the user to pass the vk_escape keycode to the script…

I think this issue ^^ needs more attention.

Also, some GM built-in features may seem "clunky", but I think throwing the game into a loop like this can be dangerous. On older machines, this might cause problems.

For example, on my old ME machine (running GM6) it consistently causes the game to hang and it never displays the game window. I have to use the "three finger salute" to get out. But it was a WinME machine, so this might be expected.

However, even on my newer XP machine, it causes unpredictable behavior if I run it within GM6. Sometimes it runs --but other times it won't load the game window and only displays the menu box. It ONLY behaves consistently if I run it from within GM7.

So despite the clever programming, this may not be a practical alternative to GM's built-in features.
  • 0

#9 Smarty

Smarty

    GMC Member

  • GMC Member
  • 7465 posts
  • Version:GM:Studio

Posted 25 February 2008 - 01:56 PM

What KC describes is better illustrated when you bring up, under Windows NT systems (2000 / XP / 2003 / Vista), the Windows task manager during a run of this source. Go to the processes list and reverse-sort the list on CPU performance, so that the most active processes are on the top of the list.

For any of the sequential emulations, GM's CPU claim on my Windows XP professional is up to 99%. Where GM's native engine runs, this drops to 25-35% (note that if Game Maker shows any of its dialogue boxes, the performance of the game drops to 0 because the engine is paused).

This suggests that GM has an idle time (no doubt related to the room speed) in which other applications get their share of the time in a kind of cooperative threading model. The most logical place to idle would be when the engine has just completely finished handling a step. The most inappropriate place to do this is in the middle of instance (event) handling, script execution or drawing - at those points Game Maker is still busy with a pressing assignment, which is finishing the frame in time.

The reason other applications get any time at all to do task is because the Windows' pre-emptive multitasking model kicks into action (the OS allotting processing time between tasks). The effectiveness of this may depend on the operating system, but NT-based systems (Windows 2000 / XP / 2003 / Vista) are significantly better at this than non-NT systems (Windows 98 / ME). For me, under XP Pro other tasks are not greatly hampered, and I assume this is because (as opposed to e.g. XP Home) it needs to be capable of handling multitasking not only between tasks but also between the users logged on to a single machine. GM is allotted as much time as is available at any moment (hence the 99%) and it dynamically adjusts that share depending on the amount of threads running.

How exactly GM handles time sharing is unknown to me. To my knowledge, there is no way to tell GM to "sit and be idle for a specific amount of time" apart from letting it handle the current step. The forced wait loop in the step handler script is no proper replacement for this, and might hinder execution not only of other tasks but also separate threads within the game itself (such as those initiated by DLLs).
  • 0

#10 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Member
  • 15878 posts
  • Version:GM:Studio

Posted 25 February 2008 - 03:56 PM

For example, on my old ME machine (running GM6) it consistently causes the game to hang and it never displays the game window.  I have to use the "three finger salute" to get out.  But it was a WinME machine, so this might be expected.


I think GM6 handles things a little differently... Try to move the code to an event other than the game_start event.
Perhaps in an alarm you set to 1 when the game starts... But do use the reccomended code change below

[edit] I updated the link so you can try again in ME and gm6


What KC describes is better illustrated when you bring up, under Windows NT systems (2000 / XP / 2003 / Vista), the Windows task manager during a run of this source. Go to the processes list and reverse-sort the list on CPU performance, so that the most active processes are on the top of the list.

For any of the sequential emulations, GM's CPU claim on my Windows XP professional is up to 99%. Where GM's native engine runs, this drops to 25-35% (note that if Game Maker shows any of its dialogue boxes, the performance of the game drops to 0 because the engine is paused).

This suggests that GM has an idle time (no doubt related to the room speed) in which other applications get their share of the time in a kind of cooperative threading model. The most logical place to idle would be when the engine has just completely finished handling a step. The most inappropriate place to do this is in the middle of instance (event) handling, script execution or drawing - at those points Game Maker is still busy with a pressing assignment, which is finishing the frame in time.

The reason other applications get any time at all to do task is because the Windows' pre-emptive multitasking model kicks into action (the OS allotting processing time between tasks). The effectiveness of this may depend on the operating system, but NT-based systems (Windows 2000 / XP / 2003 / Vista) are significantly better at this than non-NT systems (Windows 98 / ME). For me, under XP Pro other tasks are not greatly hampered, and I assume this is because (as opposed to e.g. XP Home) it needs to be capable of handling multitasking not only between tasks but also between the users logged on to a single machine. GM is allotted as much time as is available at any moment (hence the 99%) and it dynamically adjusts that share depending on the amount of threads running.

How exactly GM handles time sharing is unknown to me. To my knowledge, there is no way to tell GM to "sit and be idle for a specific amount of time" apart from letting it handle the current step. The forced wait loop in the step handler script is no proper replacement for this, and might hinder execution not only of other tasks but also separate threads within the game itself (such as those initiated by DLLs).

<{POST_SNAPBACK}>


If you show a message in GM, it's a modal dialog box with it's own message pump... GM (Mark) did not have to do anything special here.

Yes, in the old days of '98-, to do this you would have to make a loop just like that in WinMain or you would freese all the applications. I assume that is what io_handle() does (sans the time loop)
//Iddle without hanging does what sleep() (Win32) does but without the window hanging
while(current_time<end_it_time)
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
//Some snooping was required to find the WM_QUIT and repost it if memory serves
if(WM_QUIT was found)
Repost WM_QUIT MEssage

Also, PeekMessage is used instead of GetMessage if I remember right... I wrote this sleep iddle loop like 5 times in 15 years...

Perhaps if we put a io_handle in the wait for next frame loop, the system will be more responsive.



If you guys find an issue, please see if you can fool arround with a few things. I only have Vista so I can't debug this for everyone. I'm counting on you.


Also, be careful where you move the code or you may cause a stack fault.

If you place this in the step event
on step
GameLoopTillGone(all);

Well it will hang because the emulator will trigger the step event, making another GameLoop, recursion to oblivion.

Same for keyboard handling.

on keypress enter
GameLoopTillGone(all);

If the user pressed enter in the gameloop... BOOM.


Recommended code
if(variable_global_get("DoingIt")) exit;
global.DoingIt =true;
GameLoopTillGone(all);
global.DoingIt =false;



It will not happen if you GameLoop for a specific object type that is not in the parent hierarchy of the instance making the call.

Edited by icuurd12b42, 25 February 2008 - 06:02 PM.

  • 0

#11 xot

xot

    GMC Dismember

  • GMC Member
  • 4772 posts
  • Version:GM:Studio

Posted 25 February 2008 - 05:02 PM

How exactly GM handles time sharing is unknown to me. To my knowledge, there is no way to tell GM to "sit and be idle for a specific amount of time" apart from letting it handle the current step.


This seems to be a lot friendlier to the CPU:
sleep((ct-date_current_time())*1000*60*60*24);
... than the sit-and-spin while statement:
while(date_current_time()<ct) ct=ct;
It seems to emulate GM better on my machine, too ... although it is not as smooth which I'm willing to believe is a precision issue.
  • 0

#12 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Member
  • 15878 posts
  • Version:GM:Studio

Posted 25 February 2008 - 05:33 PM

How exactly GM handles time sharing is unknown to me. To my knowledge, there is no way to tell GM to "sit and be idle for a specific amount of time" apart from letting it handle the current step.


This seems to be a lot friendlier to the CPU:
sleep((ct-date_current_time())*1000*60*60*24);
... than the sit-and-spin while statement:
while(date_current_time()<ct) ct=ct;
It seems to emulate GM better on my machine, too ... although it is not as smooth which I'm willing to believe is a precision issue.

<{POST_SNAPBACK}>


Actually, over here it's pretty smooth (GM7 being better with the tiny number)... AND if you reset the room speed to a reasonable setting of 30-60, as opposed to 240 (as it is now) the CPU is the exact same. Woohooo!

I have no way to debug a problem I cannot see in GM7...

Perhaps you can try

while(date_current_time()<ct) sleep(min(????,(ct-date_current_time())*1000*60*60*24));


[edit] I posted the code with a "always calculated" 1/2/12/60/60. Perhaps it will fix the smoothness

Edited by icuurd12b42, 25 February 2008 - 05:50 PM.

  • 0

#13 xot

xot

    GMC Dismember

  • GMC Member
  • 4772 posts
  • Version:GM:Studio

Posted 25 February 2008 - 06:21 PM

It performs the same in GM6 and GM7 for me. It's a really tiny detail, it looks like the effect of waiting for an extra VSync, a slight one-frame delay happening a half-dozen times during the right-traveling block's move.

I set the room speed to 170 (twice my 85Hz refresh rate) to see if that made an difference. It didn't.

I decided to run the demo using FRAPS and the fps it reports varied during the first four tests between about 162-178 fps. On the fifth test, it was a rock-solid 170 fps. At room speed 85, I got 83-84 fps for the first two tests, 79-83 fps for the third test, 80-81 fps for the fourth, and a rock-solid 85 fps for the fifth. At room speed 30, the tests were more even, in the 30-31 fps range. Again, the fifth test was a rock-solid 30 fps.
  • 0

#14 Smarty

Smarty

    GMC Member

  • GMC Member
  • 7465 posts
  • Version:GM:Studio

Posted 03 March 2008 - 05:16 PM

Ugh. I forgot all about sleep(). Thanks xot. Yes icuurd12b42, I know Windows takes care of tasking while message dialogs are displayed.

Back on topic.

In practical terms I am a bit sceptical about the efficiency of a routine that mimics the Game Maker engine, as well as the feasibility of, at least in functionality, a 100% emulation.

I'll start off with the relatively easy-to-solve issues that I have found so far:
  • The sprite's image is not animated in the GameStepObject script.(sprite_index+=image_speed at the movement block should solve this).
  • Moving the 8 backgrounds of the room (background_x[n]+=background_hspeed[n]; background_y[n]+=background_vspeed[n];)
  • Views are not updated to follow any instance they may have in focus.
  • In the GM engine a collision event is executed for the instance, but at that point, not for the instance it collides with. Your code does both. Not only is this order of events incorrect, if none of the instances are killed, the event is executed twice for each instance involved.
More challenging are the following issues:
  • Particle systems are not updated in this emulated loop. There is a command to tell Game Maker to do only manual updates, but it works per particle system, which means you have to keep track of all particle systems in a room somehow. A disadvantage of this approach is that particle (system) creation and destruction is subject to a number of rules.
  • The keyboard events do not take into account simultaneously pressed keys - only one key is registered per step. This will of course not do for many games. You're facing a challenge here. The route to go would be building a routine that builds a data structure containing the required key press, hold and release information but such a routine would be demanding. The easiest way to retrieve the keys pressed during the last cycle is the keyboard_string variable, but it does not include virtual keys - these require a loop of their own.
I'm also a little in doubt about the order in which this routine handles instances. The order in which GM does it is not as transparent as one would think (it's not 'just' the instance order), and on top of that the with statement makes selections of it. I'd like to reference a particular topic in which this was previously discussed and will do so as soon as I find it back. :D
  • 0

#15 icuurd12b42

icuurd12b42

    Self Formed Sentient

  • GMC Member
  • 15878 posts
  • Version:GM:Studio

Posted 03 March 2008 - 11:49 PM

Ugh. I forgot all about sleep(). Thanks xot. Yes icuurd12b42, I know Windows takes care of tasking while message dialogs are displayed.

Back on topic.

In practical terms I am a bit sceptical about the efficiency of a routine that mimics the Game Maker engine, as well as the feasibility of, at least in functionality, a 100% emulation.


I am not… I doubt menus using this will have more than 15-30 objects

I'll start off with the relatively easy-to-solve issues that I have found so far:

  • The sprite's image is not animated in the GameStepObject script.(sprite_index+=image_speed at the movement block should solve this).
  • Moving the 8 backgrounds of the room (background_x[n]+=background_hspeed[n]; background_y[n]+=background_vspeed[n];)
  • Views are not updated to follow any instance they may have in focus.

Cool. I'll update it... Though I am not concerned about moving background...

Remember, the loop is to allow programmers to make a menu using GM's object and event system and run it in a loop for sequential access. Not to emulate every aspect or a game... Run the actual game in a loop. Though possible to some extent…

  • In the GM engine a collision event is executed for the instance, but at that point, not for the instance it collides with. Your code does both. Not only is this order of events incorrect, if none of the instances are killed, the event is executed twice for each instance involved.

  • What? You lost me... Sounds like you are saying only one of the instances gets a collision message. The one that is colliding?? I doubt that. Just put a message in the collision event of 2 objects… In fact I posted a GM bug about GM triggering the event twice for both object in some instances… Same Collides with Same. So I guess I’m not that far from the actual GM loop LOL.

    http://gmc.yoyogames...opic=347063&hl=

    I see a point about collision triggered twice though... All for all instead of all for all after...

    I guess I can use
    instancefind(from first to last)
    {
    instancefind (from current to last)
    }

    More challenging are the following issues:

    • Particle systems are not updated in this emulated loop. There is a command to tell Game Maker to do only manual updates, but it works per particle system, which means you have to keep track of all particle systems in a room somehow. A disadvantage of this approach is that particle (system) creation and destruction is subject to a number of rules.
    • The keyboard events do not take into account simultaneously pressed keys - only one key is registered per step. This will of course not do for many games. You're facing a challenge here. The route to go would be building a routine that builds a data structure containing the required key press, hold and release information but such a routine would be demanding. The easiest way to retrieve the keys pressed during the last cycle is the keyboard_string variable, but it does not include virtual keys - these require a loop of their own.
    I'm also a little in doubt about the order in which this routine handles instances. The order in which GM does it is not as transparent as one would think (it's not 'just' the instance order), and on top of that the with statement makes selections of it. I'd like to reference a particular topic in which this was previously discussed and will do so as soon as I find it back. :D

    <{POST_SNAPBACK}>


    Does the particle effect get nuked when you screen_redraw?

    And, I posted in that "still trying to find it too" topic BTW... When you had to store the ID and sort them by depth...

    All good points though. Some solvable, some not. I guess when you make your menu system using objects, you have to be aware of the limitations of the emulation loop and not use things that are not supported...

    But, being able to support everything possible would be a great benefit too, so I am not dismissing anything you said...
    • 0

    #16 Smarty

    Smarty

      GMC Member

    • GMC Member
    • 7465 posts
    • Version:GM:Studio

    Posted 04 March 2008 - 11:43 AM

    I am not… I doubt menus using this will have more than 15-30 objects

    Let's be specific - I take it you mean instances? Given that menus typically consists of components made up of objects, the number of instances heavily depends on the complexity of the dialog box. Not only that, but the menus I've seen in games tend to be fairly sluggish, not in the least because they need to mimic a familiar, Windows behaviour (hilighting, selecting, responding to input, drawing content). Speed is important.

    Remember, the loop is to allow programmers to make a menu using GM's object and event system and run it in a loop for sequential access. Not to emulate every aspect or a game... Run the actual game in a loop. Though possible to some extent…

    I thought the goal was to find a way to run the entire game from a single GML thread, not focusing on menus alone. If all you want is an efficient method to display dialog boxes and freeze the rest of the game, then there is an alternative method that does not require a scripted thread:
    • Define a single parent (game parent) for all objects that do not belong to the menu dialogs.
    • Capture a screenshot from the game
    • Deactivate the game parent (game halts)
    • Display the captured image
    • Create your dialog box and let it handle it's input
    • When it's done, destroy the dialog box and all its components
    • Remove and delete the captured image
    • Activate the game parent (game resumes)
    This generally gives you the freedom to decide what objects, if any, are allowed to continue their processes while the dialog box is showing. If the entire game can stop, you don't even need the parent.

    What? You lost me... Sounds like you are saying only one of the instances gets a collision message. The one that is colliding?? I doubt that. Just put a message in the collision event of 2 objects… In fact I posted a GM bug about GM triggering the event twice for both object in some instances… Same Collides with Same. So I guess I’m not that far from the actual GM loop LOL.

    http://gmc.yoyogames...opic=347063&hl=

    Wow, I was not aware of that. I wonder if it was intended that both events are called for each collision. Perhaps it was. :lol: You hardly ever notice, because you normally do not define two collision events where one should suffice, and because often the collision kills either or both of the instances. It didn't seem logical to me, my fault for not checking this thoroughly.

    Does the particle effect get nuked when you screen_redraw?

    I triggered creating a built-in particle effect on a key press. The effect did not show through the emulated steps. Repeated key presses finally made the effect visible: the first frame of the effect was repeatedly painted over itself as I created many more. So it is stuck in it's first frame, the screen_redraw() routine does not handle the particle systems.
    • 0

    #17 FredFredrickson

    FredFredrickson

      Artist

    • Global Moderators
    • 9210 posts
    • Version:GM:Studio

    Posted 04 March 2008 - 06:08 PM

    Does the particle effect get nuked when you screen_redraw?

    I triggered creating a built-in particle effect on a key press. The effect did not show through the emulated steps. Repeated key presses finally made the effect visible: the first frame of the effect was repeatedly painted over itself as I created many more. So it is stuck in it's first frame, the screen_redraw() routine does not handle the particle systems.

    <{POST_SNAPBACK}>

    Not sure if you remembered Smarty, but you can set up the built-in particle system to not draw automatically, and then update and draw it when you need to (part_system_automatic_draw(), part_system_update(), part_system_drawit()).

    You might need to disable the automatic drawing and push the particles forward every step with the update function if you do everything in a single loop.

    Edited by FredFredrickson, 04 March 2008 - 06:09 PM.

    • 0

    #18 Smarty

    Smarty

      GMC Member

    • GMC Member
    • 7465 posts
    • Version:GM:Studio

    Posted 04 March 2008 - 07:36 PM

    Not sure if you remembered Smarty, but you can set up the built-in particle system to not draw automatically, and then update and draw it when you need to (part_system_automatic_draw(), part_system_update(), part_system_drawit()).

    You might need to disable the automatic drawing and push the particles forward every step with the update function if you do everything in a single loop.

    <{POST_SNAPBACK}>


    *Hits a fellow staff member with a large hammer for not reading the topic thoroughly*

    Particle systems are not updated in this emulated loop. There is a command to tell Game Maker to do only manual updates, but it works per particle system, which means you have to keep track of all particle systems in a room somehow. A disadvantage of this approach is that particle (system) creation and destruction is subject to a number of rules.


    • 0

    #19 icuurd12b42

    icuurd12b42

      Self Formed Sentient

    • GMC Member
    • 15878 posts
    • Version:GM:Studio

    Posted 04 March 2008 - 08:57 PM

    I am not… I doubt menus using this will have more than 15-30 objects

    Let's be specific - I take it you mean instances?

    Yes, sorry. Multiple object types instantiated multiple times, like menus and sub menu responding to events for moving, clicking and keyboard... Though I guess you could also disable the entire game but the player and a salesman too.

    Given that menus typically consists of components made up of objects, the number of instances heavily depends on the complexity of the dialog box. Not only that, but the menus I've seen in games tend to be fairly sluggish, not in the least because they need to mimic a familiar, Windows behaviour (hilighting, selecting, responding to input, drawing content). Speed is important.

    I agree whole heartedly... Doing tests, the system became sluggish around 100 instances (In my City Walking AIs, adding people). So I am within the limits (I hope) At least on my machine. But an old clunker may do badly… However, you can tailor to loop to only trigger the events you need for your menu.

    Remember, the loop is to allow programmers to make a menu using GM's object and event system and run it in a loop for sequential access. Not to emulate every aspect or a game... Run the actual game in a loop. Though possible to some extent…


    I thought the goal was to find a way to run the entire game from a single GML thread, not focusing on menus alone. If all you want is an efficient method to display dialog boxes and freeze the rest of the game, then there is an alternative method that does not require a scripted thread:
    • Define a single parent (game parent) for all objects that do not belong to the menu dialogs.

    • Capture a screenshot from the game

    • Deactivate the game parent (game halts)

    • Display the captured image

    • Create your dialog box and let it handle it's input

    • When it's done, destroy the dialog box and all its components

    • Remove and delete the captured image

    • Activate the game parent (game resumes)
    This generally gives you the freedom to decide what objects, if any, are allowed to continue their processes while the dialog box is showing. If the entire game can stop, you don't even need the parent.

    I am quite familiar with the concept... I use it in the tank game and posted this solution many times...

    The problem, the annoyance really is to control those object to re-enable the game (by reactivating the disabled instances)

    I often found myself trying to figure out why stuff would act funny in my game after I showed such menu... Usually it's because of an omitted reactivate, or a reactivate that activated instance in the game that should have been kept inactive (deactivated by some other control mechanism such as an (a boss) area on the map that activates only when you are done with a part of a mission.

    In any case, you can use the method with this one.

    MyLoopWhilePurchseIsDone
    screen capture
    deactivate
    instance_create(x,y,BuyMenuObj);
    loop while instance exists BuyMenuObj
    draw screen capture
    gm event handling
    end loop
    free capture
    reactivate

    So in the game you can use the sequential feature.

    On KeyPress B <-Buy
    MyLoopWhilePurchseIsDone(BuyMenu);
    //game resumes


    If I have time, I'll try to make a real menu (more complex than that clickable square LOL)...

    What? You lost me... Sounds like you are saying only one of the instances gets a collision message. The one that is colliding?? I doubt that. Just put a message in the collision event of 2 objects… In fact I posted a GM bug about GM triggering the event twice for both object in some instances… Same Collides with Same. So I guess I’m not that far from the actual GM loop LOL.

    http://gmc.yoyogames...opic=347063&hl=

    Wow, I was not aware of that. I wonder if it was intended that both events are called for each collision. Perhaps it was. :lol: You hardly ever notice, because you normally do not define two collision events where one should suffice, and because often the collision kills either or both of the instances. It didn't seem logical to me, my fault for not checking this thoroughly.


    Well, yes, it makes sense to trigger the collision for the 2 objects involved as they both can have their own code to perform... But not twice for each instance...

    Yes, I found that (double event trigger bug) out in my pool tutorial. Where the energy absorption calculation would be twice too much and my ds_list holding the colliding balls would have the same entries twice...

    In the tank game, I was wondering why the bullets would get killed too fast... By a anti bullet bullet (same parentbullet type)
    m_Health-=other.m_Dammage

    Does the particle effect get nuked when you screen_redraw?

    I triggered creating a built-in particle effect on a key press. The effect did not show through the emulated steps. Repeated key presses finally made the effect visible: the first frame of the effect was repeatedly painted over itself as I created many more. So it is stuck in it's first frame, the screen_redraw() routine does not handle the particle systems.

    <{POST_SNAPBACK}>



    I should have been more specific... If your particle system has drawn a few frame, and your puff of smoke is now a cloud. Then you freeze the game (show a menu)... Does screen_redraw display the cloud or does it disappear?

    Your menu system can't use particle effects though... That is bad...


    Anyway, the concept is still pretty out there as far as we all know but worth exploring some more…




    Off topic... BTW, it looks like you guys do have an unfair advantage by having first dibs on replies LOL.
    • 0

    #20 Smarty

    Smarty

      GMC Member

    • GMC Member
    • 7465 posts
    • Version:GM:Studio

    Posted 24 April 2008 - 08:45 PM

    I should have been more specific... If your particle system has drawn a few frame, and your puff of smoke is now a cloud. Then you freeze the game (show a menu)... Does screen_redraw display the cloud or does it disappear?

    Yes, screen_redraw() draws the particle systems, but without processing them.

    Off topic... BTW, it looks like you guys do have an unfair advantage by having first dibs on replies LOL.

    <{POST_SNAPBACK}>

    I planned the Expert forum's moderators to even approve replies made by other staff members. Trouble is that moderators should be able to bypass previews in their own forums, but the bypass applies to all forums - I can't switch that off for one forum. So the rest of us will just have to reply and see our post deleted if we said something stupid. :skull:


    Picture this... you guys are in Y-Wing bombers running the trench of the first Deathstar. TIE Fighters are closing in all around you. There's too many of them.

    Suddenly, Gold-5's voice cackles over your radio...

    "Stay on topic... STAY ON TOPIC!"


    -Sinaz :)

    • 0

    #21 xDanielx

    xDanielx

      GMC Member

    • GMC Member
    • 1002 posts
    • Version:Unknown

    Posted 27 April 2008 - 09:46 PM

    Personally, I find it easiest to just quasi-disable the step events of some objects.

    if ( obj_global.paused ) exit;

    Besides simplicity, one prominent advantage is that you can easily implement exceptions instead of freezing everything. For instance, several of my games involve custom (as in, not API-driven) window systems. I might want the player to be able to move around and interact with these windows, and various embedded controls, while the game is frozen. I also may want some color-shifting GUI effects to continue. All this would be difficult to implement if pausing the game involved interrupting the step cycle -- I would need to reprogram the system to run in two very different states, one driven by the standard step cycle and one driven by some non-standard quasi-step cycle.

    Admittedly this does interfere with some of GM's per-step features, e.g.
    • updating speed and direction based on gravity and friction
    • updating of an instance's coordinates based on its speed and direction (or alternatively, hspeed and vspeed)
    • updating image_single (or whatever it's now called) based on image_speed
    • updating the position of the view based on the position of the instance in focus
    • possibly particle systems, depending on how you want them handled

    I tend to handle these processes manually anyway, so I haven't found these issues problematic at all. (Not that I find them particularly limiting, I just find easier to do some extra framework-level programming than to try to keep track of e.g. the order of various event procedures.)
    • 0

    #22 ce gamer

    ce gamer

      GMC Member

    • New Member
    • 134 posts

    Posted 16 February 2009 - 10:06 AM

    Also, if you could try it out in one of your games? I need to know if I thought of everything and if everything is working as it would normally... There are simply too many variations to verify all by myself.

    I've used your technique in my game, to create an own message system. I haven't had much problems integrating it and it seems to work fine. You can check it out here: yoyogames. If other people that play my game get problems I'll report those problems here.
    • 0

    #23 icuurd12b42

    icuurd12b42

      Self Formed Sentient

    • GMC Member
    • 15878 posts
    • Version:GM:Studio

    Posted 17 February 2009 - 05:35 AM

    Also, if you could try it out in one of your games? I need to know if I thought of everything and if everything is working as it would normally... There are simply too many variations to verify all by myself.

    I've used your technique in my game, to create an own message system. I haven't had much problems integrating it and it seems to work fine. You can check it out here: yoyogames. If other people that play my game get problems I'll report those problems here.



    Nice. Glad someone found a use for it. that was the point of the loop. Eseally give control to only a few objects disabling the rest without major headache
    • 0

    #24 Ultimate Omicron

    Ultimate Omicron

      GMC Member

    • GMC Member
    • 451 posts
    • Version:GM:Studio

    Posted 28 July 2009 - 08:39 PM

    If all you want is an efficient method to display dialog boxes and freeze the rest of the game, then there is an alternative method that does not require a scripted thread:

    • Define a single parent (game parent) for all objects that do not belong to the menu dialogs.
    • Capture a screenshot from the game
    • Deactivate the game parent (game halts)
    • Display the captured image
    • Create your dialog box and let it handle it's input
    • When it's done, destroy the dialog box and all its components
    • Remove and delete the captured image
    • Activate the game parent (game resumes)
    This generally gives you the freedom to decide what objects, if any, are allowed to continue their processes while the dialog box is showing. If the entire game can stop, you don't even need the parent.


    I use this for pausing a 3D game, without using the parent system, just freezing everything.
    Also, the CPU usage is very low, about 15%, the equivalent of an empty game running only that in a regular cycle, and since it refreshes regularly, the window responds to cursor movement and does not stop responding.
    It does this:

    ---Runs script---
    1-Sets some global draw flags, so that only what matters is drawn, and global sound volume to 0
    2-Sets a reduced projection (half the size)
    3-Redraws the screen, sets ortho projection and draws some stuff to decorate the screen
    4-creates a background from the screen
    5-enters loop at point 6

    {
    6-Checks for key input and window input, using an array to store pressed keys
    7-procceses input and takes according actions (menu item selection, room_restarts, game_ends and even screenshots are proccessed inside the loop)
    8-refreshes the screen using the stored background and the menu draw code
    9-sleeps 5000/room_speed (one fifth the game speed)
    10-if it needs to resume, go to point 11 else go back to point 6
    }

    11-destroys the background
    12-if it needs to restart the room or end the game, do that here and exit the script
    13-sets the global draw flag back and global sound volume to 1
    14-redraws the room and clears IO.
    ---Script ends---

    Since nothing outside of the loop is changed except for the draw flag, it can access variables and even run code in other instances. It uses a text-based menu list by now, but the interface and functionality can be infinitely expanded.
    I don't remember, but i certainly based my system in something i read here.

    And I also use this system to configure joystick buttons in the main menu without complicated menu locking mechanisms (and it does not even require the screen capture for that).
    • 0

    #25 1dinglenuts1

    1dinglenuts1

      GMC Member

    • New Member
    • 99 posts

    Posted 06 November 2009 - 12:53 AM

    takes a lot of proccessing aye?
    try swapping the 98 for something a bit more modern xD ][_,([])][_,.
    did you try the basic GM stuff by plaing with the process prioritys? it may be primitive but it may help keep things running at a smooth speed
    • 0




    0 user(s) are reading this topic

    0 members, 0 guests, 0 anonymous users