Parallel Processing Update Frequency?

Status
Not open for further replies.

Gorou Fujita

Villager
Member
Joined
Jun 23, 2013
Messages
13
Reaction score
0
First Language
English
Primarily Uses
I'm currently taking a break from my "proper" RPG to make some games in an unusual way, and I seem to have run into a problem. I've already gone through the help file as well as searching the forums, and it seems like events should run once per frame, but that's not what's happening for me.

One of the games that I'm making is a side-scrolling shooter. I'm only using pictures, determining their location using variables and drawing them with show/move picture events, such as the player's plane that you move by pressing the directional buttons(thanks to the conditional branch button press event). When a directional button is being pressed, I add a fixed value to a variable. If I'm pressing up or down, I subtract or add 2 to my "PlayerY" variable(RPGMaker seems to use an inverted Y axis which drives me crazy!), and if I'm pressing right or left, I add or subtract 2 to my "PlayerX" variable. All of this works perfectly, including things like shooting bullets/missiles when pressing the correct button(again with the conditional branch event) and even the "collision" of hitting the one enemy plane I've put in the game so far. All of the math seems to work just fine.

The problem I'm having is that there is a huge discrepancy between a parralel processing event adding to a variable and waiting for it to reach a value(in this case, adding 10 and waiting for it be 300), and using a wait 30 parallel processing event. After a lot of testing, it became obvious that it was taking about twice as long for the expected result using the variable method.

I also noticed that my "screen scrolling" parallel processing event, which subtracts 1 from a variable corresponding to the x value of a 2000 pixel wide image(with a move picture event after it) took a little less than 50 seconds to move it -1455 pixels. A little less than 50 seconds would be a little less than 3000 frames(50x60), and if the events are really only updating every 2 frames, then 1455x2 would be a little over 2900 frames. No matter how many times I test, it takes the same amount of time to scroll the screen.

I made a simple game to confirm this. It sets the game time to a variable in a parallel processing event and adds 1 to a different variable in that same parallel processing event. Then I have another parallel processing event that is nothing more than a "wait 300" event and a message box that spits out the values of the variables(\V[1] and \V[2]), and I made it so that the message box does not wait for player input to close(\^). The value of the variable seems to climb by about 150 everytime the message box pops up, and the game time confirms that right around 5 seconds passes between each message box, meaning that the event is only updating once every 2 frames. If the game time was wrong, or my own subjective timing my scrolling event was wrong, I could assume that the "wait" event is actually at fault, but all signs point to events updating once every 2 frames.

tl;dr

My parallel processing events only seem to run every 2 frames. Is this normal?

Edit - I made sure that the game was running at full speed by checking the FPS in the window(one of the F keys does this).
 
Last edited by a moderator:

Andar

Veteran
Veteran
Joined
Mar 5, 2013
Messages
31,359
Reaction score
7,672
First Language
German
Primarily Uses
RMMV
normally there should be 60 frames per second - but lag is a problem in the game, especially if you have a lot of parallel processes.

And lag that reduces from 60 to 30 frames per second is usually not detectable when playing in a normal way.

So that could be a reason for this to happen,,,
 

Gorou Fujita

Villager
Member
Joined
Jun 23, 2013
Messages
13
Reaction score
0
First Language
English
Primarily Uses
Sorry, I should have mentioned that I pressed that F key that shows the FPS in the window and it was always 60.

I would also hope that if the game slows down, the events don't asplode. lol
 

Mithran

Global Moderators
Global Mod
Joined
Mar 2, 2012
Messages
404
Reaction score
217
First Language
English
Primarily Uses
The actual problem is that when an event has run its course, the Fiber controlling it still exists until the next frame, then is resumed only to be nullified and finally ended. It is not until the frame after that that the event gets set up again, in the case of a parallel process.


A simple fix would be to simply wrap your entire event contents in a loop, which will not allow it to reach the point where there would be a frame delay. If nothing in the loop explicitly returns processing to the main thread (from what you have stated, nothing you have added for this event would), you will need to add a wait(1) at the end of loop or it will hang.
 

Gorou Fujita

Villager
Member
Joined
Jun 23, 2013
Messages
13
Reaction score
0
First Language
English
Primarily Uses
The actual problem is that when an event has run its course, the Fiber controlling it still exists until the next frame, then is resumed only to be nullified and finally ended. It is not until the frame after that that the event gets set up again, in the case of a parallel process.

A simple fix would be to simply wrap your entire event contents in a loop, which will not allow it to reach the point where there would be a frame delay. If nothing in the loop explicitly returns processing to the main thread (from what you have stated, nothing you have added for this event would), you will need to add a wait(1) at the end of loop or it will hang.
Wow, how did you even know something like that? LOL

If I would have known that was the problem, I never would have expected an answer. Also, I've never been able to get loops to work before because they always caused a hang, but you just answered that too, so thank you for throwing that bonus in your response.

I just put the loop into my quick test game, and it worked "properly." But I remember reading about this loop thing to fix parallel processes so that they keep running while a message box is up, and that indeed threw the numbers off. It would increase about 320 each time, probably to compensate for the time the game takes to set up the message box and automatically close it(because I used \^). I don't know how I'll compensate for that if I have text in the middle of a mission, but I'm sure I can do something with a conditional branch when the time comes.

I also just put it into my side-scrolling game, and it works, but apparently I need to redo all parallel process variable values since the game was essentially running at half speed. ;_;

I have a few more questions that are now unfortunately relevant. If I have a common event with a parallel process trigger switch that gets turned off from within the parallel process itself, will this loop cause it stay in the common event anyway, or will the common event be killed the frame(or two?) after the switch is turned off? I currently use labels and jump to labels to make sure that only one condition gets fulfilled in certain events when it's possible that the one condition will modify a variable such that the next condition could activate before it reaches the end of the event(I keep them in one event for organization purposes and the labels haven't failed me yet). If the loop causes me to get stuck in an event, could I put a conditional branch somewhere in there to check if the event did what it was supposed to, and then a jump to label event to somewhere outside of the loop? I'm just scared of loops since I could never get them to work before. :p
 

Shaz

Veteran
Veteran
Joined
Mar 2, 2012
Messages
40,098
Reaction score
13,704
First Language
English
Primarily Uses
RMMV
A common event with a parallel process trigger switch will still run all the way to the end, even if the first command is to turn off that switch. If you want to interrupt/cancel it half way through, you'd need to use an Exit Event Processing command, or a Jump to Label command, with the corresponding label at the end of the event.


In a loop, you could use a Jump to Label, or you could just use a Break Loop command. I normally use Break Loops.
 

Gorou Fujita

Villager
Member
Joined
Jun 23, 2013
Messages
13
Reaction score
0
First Language
English
Primarily Uses
A common event with a parallel process trigger switch will still run all the way to the end, even if the first command is to turn off that switch.
What if the entire common event, including the switch off command, is inside a loop and I never use a jump to label outside of the loop or a break loop event? Will it repeat indefinitely even though the switch was turned off? Since technically it never reaches the end of the event. Basically, is one enough, or do I need to both turn off the switch and jump/break out of the loop?

Also, I don't know if I just messed something up, but I had a common event that didn't behave like what you described. I'll refer to them as CE A and CE B. Both are parallel processes with different switches.

1) CE A had a conditional branch that turned on a switch that activated CE B and then went about its business.

2) When CE B activated, it drew one picture, erased another one(meaning a different picture number 1-100), had a large wait command(60), and then erased the first picture.

3) There was another conditional branch in CE A that turned off the switch that actived CE B as well as the switch that activated itself. When this conditional branch was used before CE B finished(because of that wait command), it would never erase the first picture. If I either removed the wait command in CE B or I didn't turn off the switch in CE A, then CE B finished normally.

Was that a bug, or does turning off a switch from a different event instantly kill the common event that had it as its trigger?
 
Last edited by a moderator:

Shaz

Veteran
Veteran
Joined
Mar 2, 2012
Messages
40,098
Reaction score
13,704
First Language
English
Primarily Uses
RMMV
Hmm ... it seems you're right. I keep forgetting that common events and map events don't have the same structure or behaviour.


I'll look into this a little when I have more time, as I don't understand why you can change switches on regular map events and the current list of event commands will continue to play out, but that's not the case for common events - they LOOK like they do similar checks and updates and restarts of the command list.


To work around your issue, if you actually WANT the second common event to complete, you can turn on a switch from CE1 - not the one that controls CE2, but a new one, let's call it 'stop pending'. Then at the end of CE2, check this new 'stop pending' switch. If it's on, turn off the switch that controls CE2 as well as the 'stop pending' switch. That means from CE1 you're saying "I want CE2 to stop running after its current iteration" rather than "stop running right now".
 
Last edited by a moderator:

Another Fen

Veteran
Veteran
Joined
Jan 23, 2013
Messages
564
Reaction score
275
First Language
German
Primarily Uses
As far as I know, the following steps are processed every frame:

- If a switch or variable was recently written all events are checked for consistency. Events triggered by "Parallel Process" get canceled if their event page was changed or their triggering switch was disabled (even within a loop). The main event process (which runs any event not triggered by parallel process) however will remain unaffected until the event runs out.

- Now, every active event will be updated. Within a single update an interpreter executes as many commands until one of them causes the interpreter to wait (such as the Message Commands, "wait", any command with "Wait for XY to finish" enabled or when you use "Fiber.yield" within a script command) or the event gets finished.

This is also the reason why the game crashes when you use an empty loop within your event: the interpreter will never finish updating this process for one frame.

On the other hand, for example, a variable of yours temporarely falling below a certain value due to a step of calculation won't cause an event page to break instantly.

(Hope that is somehow helpful; need to write english texts more often, Sorry)
 
Last edited by a moderator:

Mithran

Global Moderators
Global Mod
Joined
Mar 2, 2012
Messages
404
Reaction score
217
First Language
English
Primarily Uses
What Another Fen stated above explains it pretty well. Parallels are designed to be killed when their conditions are no longer met. However, these conditions are only checked when the game detects a change in one of the conditions, and only ever once per frame, right before the event starts processing for that frame. So anything done within the same frame before "Fiber.yield" is reached within its execution path is still executed. When it does yield back to the main thread, the condition check is performed before the next frame can be executed and it is killed there. Anything with "wait for finish", any messages or choices, explicit waits, fadein/out, and scene changes will all yield processing back to the main thread. Variable/switch operations or move routes, picture changes, screen tinting, even "erase event" or other things which have the option to wait but do not have wait for finish checked, do not return processing to the main thread and the event will move to the next line until it does.


Autoruns and other event triggers work differently in that they are run through the map interpreter (the main interpreter), which runs the event list until completion or until explicitly told otherwise (exit event processing). Common events that are autorun or parallel behave like map events that are autorun or parallel. If explicitly called, common event processing is entirely dependent on the parent that called it. If called without a source event or trigger (eg., the common event field for items/skills, which simply 'reserves' one to be run when next possible), it is run through the main interpreter, like an autorun.


To answer other questions, a parallel common event stops processing the frame after its condition switch is turned off, with the last command being processed being anything that will yield back to the main thread. If you turn off the switch and explicitly kill it in a 'exit event processing' through a conditional branch, it will stop processing there and officially end the next frame (still before anything else is processed). The reason why it needs two frames if allowed to reach the end and restart is that the last operation an event runs is to resurrect the dead Fiber only to discard it. I actually am not really sure why it does this exactly, and I have never tested it, but it could be needed for Autoruns to process properly, it could be for performance reasons (30 times per second parallel restarts instead of 60) or it could just be a mistake.


Loops in event processing or not 'real' loops, per se. They are functionally the same as the goto label command, in that they just move the pointer controlling which line that should be processed next to a specific point. If you are more comfortable with that, you don't need to use loop at all. You can freely jump in and out of loops using conditional branches, just like the space between goto commands. I simply used loop because it is cleaner conceptually in my mind but it really makes more difference in this case. The important thing is that if you do not want the 'frame delay' when restarting a parallel process, you need to prevent it from reaching the last line.
 

Gorou Fujita

Villager
Member
Joined
Jun 23, 2013
Messages
13
Reaction score
0
First Language
English
Primarily Uses
I tried to put everything together, and I somehow got everything to work how it is explained in this thread.

Parallel Paradox Solved.PNG

If you look in that picture, going left to right, the first picture is what was supposed to be there, minus the message box. I put that in there to test if the event went all the way to the end if I didn't put a jump to label after I turned off the switch. The message box did display, which was not good, so I left the jump to labels in all of my events right after I turn the switches off. Fortunately, like Another Fen confirmed, the event did still stop after that frame even if I didn't jump out of it or break the loop(not shown in the picture). And I also experimented with break loops, and they didn't bite me, so I may start using them. :p

The second picture stopped after showing "hit2." Now that I understand this whole frame updating nightmare, it seems to me that using waits in parallel processes can be very dangerous if you either have more than one event dependent on a switch or control a switch from more than one place. I know I have 5000 of them, but I was still trying to group things together wherever possible to save them. If that's just going to cause even more problems, I'll be liberal with my use of variables and switches from now on.

The third picture is like what I was explaining to Shaz in post 7, except in this case, CE B prevented CE A from finishing. And just for reference, I picked wait(6) to match where picture 1/2 would normally wait, and sure enough, it stopped after showing "hit2." Also, I recreated my problem CE A and CE B from memory and tried the solution that Shaz mentioned, and both events worked normally, so it seems like all of this is simply "do not cross the streams."

Even though Mithran confirmed this, I replicated all of these results by moving the common events into parallel process map events that had the same triggers. But that brought up a new question.

I know that within a map event, all conditions being equal, the higher event page will be chosen. But what order do parallel process map events and also parallel process common events get called in? Is it something like Map001->Map999 and then CE001->CE999? Or Map999->Map001 and then CE999->CE001? Or do common events go before map events?

The dilemma I have in my head is if I accidentally arrange all of my events so projectiles' locations are updated before planes/other targets' locations are updated, then for example, a plane that should have been hit and destroyed(plane moves->projectile moves and hits) would be able to move on top of a projectile and maybe get another shot off in that one frame. Without knowing what order events are processed in, I would have to double all of my conditional branches to check not only if a bullet is within a plane's hit box, but also if a plane is within a bullet's hit box, and then I'd need to make sure I don't duplicate the actual damage(variable) effect... I sure hope the answer to this question is simpler than the others. lol

Edit - I'm sorry that picture is so tiny even when you click on it. I've never embedded a picture here before, but I guess I need to upload to an external host from now on.
 
Last edited by a moderator:

Mithran

Global Moderators
Global Mod
Joined
Mar 2, 2012
Messages
404
Reaction score
217
First Language
English
Primarily Uses
Order of event execution is Main interpreter (if running, or if there is an event that needs to be setup to run), then all map events, then all common events.  Within the specific groups, it should enumerate 1 through 999, since that is the order they would be added to the hash and Ruby 1.92 onwards would preserve this order, but there is an outside possibility the map may save the events in order of creation rather than ID, in which case that is the order that would be used.  I'd lean toward it being structured to being saved by ID, but I can't do any tests right now.
 

Another Fen

Veteran
Veteran
Joined
Jan 23, 2013
Messages
564
Reaction score
275
First Language
German
Primarily Uses
First of all:
I don't know the details about your project, but since a frame is just a 60th of a second you will most probably hardly see a difference between

Plane moves -> fires
Projectile moves -> hits
Screen (frame) update


and

Plane moves -> fires

Screen (frame) update
Projectile moves -> hits


Apart from that it's just as Mithran mentioned. Map events seem to update in the order they were created in the editor (regardless of their actual IDs) while common events update in ascending order of their IDs. Updating a map event means to advance its movement first and then processing its "Parallel Process" page (if it has an active one).
 
Last edited by a moderator:

Gorou Fujita

Villager
Member
Joined
Jun 23, 2013
Messages
13
Reaction score
0
First Language
English
Primarily Uses
I actually figured out a good way to merge all player/enemy movement and all player/enemy attacks into huge yet order independent common events, so I'm covered even if I accidentally update movement before projectiles or vice versa in any events I create later on. The issue was never the visual aspect, it's just that I would be angry if a plane that was supposed to die at the start of a frame ended up shooting a missile at me or something right at the last second and killed me at the end of a stage. lol

Unfortunately, the map event order sounds like a scary situation that I want no part of. Whenever I start messing around on a map, I sometimes make a complicated event, then move it into a common event when everything works like it should, and finally delete the event on the map. This is regardless of it being a parallel process event, or a simple action button event. On the only map I'm using right now, in addition to the parallel process common events, I have a few parallel process map events of varying IDs and with gaps in the IDs so I can't even tell what order I made them in.  >.>

I'll just have to stick all parallel process events in common events, and use a simple single parallel process event on each map to set up things like player starting position, and other static objects like the background. But that's my problem to deal with. :p

And with that, I have run out of questions. \o/

I was kind of worried that I wouldn't get any help since I'm using RPGMaker in an unorthodox way, but thankfully there are some really knowledgeable people here. Seeing as how this was all a lot more complicated than I could have imagined, it's a miracle that it all worked out in just one day. Thank you to everyone that explained how the engine handles events, as well as that extremely useful tip to finally get loops to work.
 

Shaz

Veteran
Veteran
Joined
Mar 2, 2012
Messages
40,098
Reaction score
13,704
First Language
English
Primarily Uses
RMMV
I think it helped that you provided so much information on how you were testing and the results you were getting, and that your question was very specific. We really didn't even need to focus on the type of game you're attempting to make :)


This thread is being closed, due to being solved. If for some reason you would like this thread re-opened, please report this post and leave a message why. Thank you.
 
Status
Not open for further replies.

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

Couple hours of work. Might use in my game as a secret find or something. Not sure. Fancy though no? :D
Holy stink, where have I been? Well, I started my temporary job this week. So less time to spend on game design... :(
Cartoonier cloud cover that better fits the art style, as well as (slightly) improved blending/fading... fading clouds when there are larger patterns is still somewhat abrupt for some reason.
Do you Find Tilesetting or Looking for Tilesets/Plugins more fun? Personally I like making my tileset for my Game (Cretaceous Park TM) xD
How many parameters is 'too many'??

Forum statistics

Threads
105,857
Messages
1,017,019
Members
137,564
Latest member
McFinnaPants
Top