Progress during a while.

  • So, using the trick from a for loop, I'd put a wait 0.1 in my while statement in order to update a progress bar. However, if you put a wait inside a while, the net results seems to be it locks up the entire app, which ends in an 'oh-snap' in the preview AND the editor.

    Now surely, there must be some way of updating a progress in the midst of a while without locking everything up? From what I'm seeing, if you execute a while, everything freezes till it's done.

  • the wait doesn't slow down the execution of the eventsheet - it only defers the actions after the wait until the desired time. So, the while statement is still running 60 times a second...

    instead of a while, I would probably use a global variable as a countdown - and every tick subtract dt from it, and update the progress as that goes down.

  • You need "Wait loopindex*0.016" if you want the loop to iterate 1 tick at a time. But this won't work with While loop, you should use Repeat or For:

    Repeat 100 times
    	Wait loopindex*0.016
    	ProgressText append text "."
    	// do some cpu-intensive stuff here, 1/100 portion of it.
    	// For example, if you need to fill a million array records, fill 10000 here
    
  • Well if you're not worried about interrupting a loop with the 0.1, then you might as well just use ticks.

  • God, it's taken me 2 days to get this while to work. The thought of rewriting yet again it makes me ill. Plus, I'm going to have another much larger while loop that would be a bigger nightmare to convert into something else. Instead of completely rewriting this code into a different type of loop, is there no way to update a progress? It just seems bizarre to me that a while loop should completely freeze the app till it's done with no way to update a text or a progress bar.

  • Like AlanR explained, loops in Construct are actually performed in one tick. If there is a Wait inside the loop, it doesn't pause loop execution, it creates a delayed thread. So a loop like this becomes infinite and will freeze the browser:

    While
    stop=0
    	Wait 0
    	Set stop=1
    
  • For long loops with progress indication, I use nested for loop with a progress/iteration counter.

    Every tick if 0<"progress"<=100, add 1 to progress

    > For "loop" from totaloperations/100*(progress-1) to totaloperations/100*progress

    This will start running by setting progress to 1. 100 is an arbitrary number for how many steps/ticks you want to divide your operation for. My main application of this is for parsing, where totaloperations is the tokencount of what I want to parse.

  • Ahh, you can also do that with the method I mentioned above.

    Split the loop into byte size chunks that runs every tick.

  • Like AlanR explained, loops in Construct are actually performed in one tick. If there is a Wait inside the loop, it doesn't pause loop execution, it creates a delayed thread. So a loop like this becomes infinite and will freeze the browser:

    > While
    stop=0
    	Wait 0
    	Set stop=1
    

    And that's pretty much what I was doing. So the whole point of me doing it this way was the result of another thread I started:

    construct.net/en/forum/construct-3/how-do-i-8/god-need-repeat-until-146195/page-2

    In Delphi, there's a repeat:until loop which is a lot like a while. It keeps doing something until a condition is met. And, as in my case, if you're doing lengthy loops, there's an application.update you can plug in anywhere and the interface gets updated. This while, it's going to take some effort to convert.

    I appreciate you guys giving me ideas and suggestions and it's apparent that I'm going to have to figure another way to do all of this without the while. All of the languages I've learned before Construct (except maybe Basic) have been function or procedure based and as little as possible goes on the main thread. And since I had this inside a function, running the timer or dt isn't going to be an easy fix.

    Here's what I'm doing:

    * On function 'CheckFresh'
     | Local number T‎ = 0
     | Local number B‎ = 0
     | Local number R‎ = 0
     | Local number L‎ = 0
     | Local number dir‎ = 0
    ----+ System: 0 is Number
    -----> System: Set T to ArrayOffset-1
    -----> System: Set B to ArrayHeight-ArrayOffset
    -----> System: Set L to ArrayOffset-1
    -----> System: Set R to ArrayWidth-ArrayOffset
    -----> System: Set dir to 0
    -----> Functions: Set return value 0
    
    ----+ System: While
    --------+ System: T ≤ B
    --------+ System: L ≤ R
    ------------+ System: dir = 3
    ----------------+ System: For "I" from B to T
    --------------------+ TerrainArray: Value at (LoopIndex("I"), L, 0) = WaterTileFresh
    ------------------------+ System: Functions.CheckAllWater2(LoopIndex("I"),L,0) = 1
    -------------------------> Functions: Set return value 1
    -------------------------> System: Set FreshWaterX to LoopIndex("I")
    -------------------------> System: Set FreshWaterY to L
    
    ----------------+ System: L is Number
    -----------------> System: Add 1 to L
    -----------------> System: Set dir to 0
    
    ------------+ System: Else
    -------------> (no actions)
    
    ------------+ System: dir = 2
    ----------------+ System: For "I" from R to L
    --------------------+ TerrainArray: Value at (B, LoopIndex("I"), 0) = WaterTileFresh
    ------------------------+ System: Functions.CheckAllWater2(B,LoopIndex("I"),0) = 1
    -------------------------> Functions: Set return value 1
    -------------------------> System: Set FreshWaterX to B
    -------------------------> System: Set FreshWaterY to LoopIndex("I")
    
    ----------------+ System: B is Number
    -----------------> System: Subtract 1 from B
    -----------------> System: Set dir to 3
    
    ------------+ System: Else
    -------------> (no actions)
    
    ------------+ System: dir = 1
    ----------------+ System: For "I" from T to B
    --------------------+ TerrainArray: Value at (LoopIndex("I"), R, 0) = WaterTileFresh
    ------------------------+ System: Functions.CheckAllWater2(LoopIndex("I"),R,0) = 1
    -------------------------> Functions: Set return value 1
    -------------------------> System: Set FreshWaterX to LoopIndex("I")
    -------------------------> System: Set FreshWaterY to R
    
    ----------------+ System: R is Number
    -----------------> System: Subtract 1 from R
    -----------------> System: Set dir to 2
    
    ------------+ System: Else
    -------------> (no actions)
    
    ------------+ System: dir = 0
    ----------------+ System: For "I" from L to R
    --------------------+ TerrainArray: Value at (T, LoopIndex("I"), 0) = WaterTileFresh
    ------------------------+ System: Functions.CheckAllWater2(T,LoopIndex("I"),0) = 1
    -------------------------> Functions: Set return value 1
    -------------------------> System: Set FreshWaterX to T
    -------------------------> System: Set FreshWaterY to LoopIndex("I")
    
    ----------------+ System: T is Number
    -----------------> System: Add 1 to T
    -----------------> System: Set dir to 1
    
    --------+ System: Else
    ---------> System: Stop loop
    

    This is still with my current procedural terrain kick.

    Basically, this loop starts at the top left corner of the array. It then reads across, down, left and up in a spiral fashion until it reaches the center of the array. It's purpose is to find a specific a number in the array (representing fresh water) then check all 8 surrounding elements to make sure they're the same. By spiraling inward, the last positive check it does will be the closest fresh water to the center. If it fails completely in finding any, it re initializes the array, and starts all over with a different one.

  • This could possibly be an interesting feature suggestion.

    A stop loop action except that instead of terminating the loop, it will complete anything that remains in the following tick.

    Edit: Also gives me an idea for a different approach.

    Progress=/=TotalIterations

    For "loop" from Progress to TotalIterations

    -> Do x

    -> Set Progress to loopindex.

    -> Stop loop based on desired trigger

    The following tick the loop will run again, starting at wherever you left off when you stopped the loop

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • This could possibly be an interesting feature suggestion.

    A stop loop action except that instead of terminating the loop, it will complete anything that remains in the following tick.

    In Delphi there's a while and a repeat (and of course for loops) The difference between those is, in a while loop, if the condition is met anywhere in the middle, the loop breaks. In the repeat loop, it only checks at the end of the loop to see if the condition is met and then breaks.

    But, that's just me being wishful. Considering the headache I've been through with that one above, it's obvious I still haven't figured out the logic of C3 loops.

  • Progress=/=TotalIterations

    For "loop" from Progress to TotalIterations

    -> Do x

    -> Set Progress to loopindex.

    -> Stop loop based on desired trigger

    The following tick the loop will run again, starting at wherever you left off when you stopped the loop

    And yea, I know that there should be exactly 200x200 iterations in the loops above and I could rewrite it with that in mind. The question I have is, should I really have to restructure the way that perfectly sound logic works and should I have to avoid using the while condition in the future because it freezes the app till it's done?

  • You can still use while (stop loop still will work the same way), but you'll need to track your progress manually rather than using loopindex is all.

  • You can still use while (stop loop still will work the same way), but you'll need to track your progress manually rather than using loopindex is all.

    Of course. The problem is, while the loops is running there doesn't appear to be any way to update a progress bar, a text or anything else. One of my while loops could likely take up to 5 seconds, during which time, the game is completely frozen. Since this will be during startup, those kinds of delays are considered acceptable. Not updating a text or a progress to prove the game hasn't crashed for 5 seconds? The vast collection of impatient gamers on this planet will have a collective embolism.

    I exaggerate but you get the point.

  • What I would do in your situation (i.e. not having to change a lot, and fix the problem):

    1. Instead of calling a function that starts the while loop, keep that loop in a separate Group (default: inactive). So, instead of calling the function, just make the Group active.
    2. Instead of using While loop, use simple conditions (if conditions). That way you can have your 0.1 wait and update progress timely as everything else progresses in the game. Won't get stuck. No while loops.
    3. Make the group Inactive at the end of that loop, or when progress bar has reached end.
Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)