Progress during a while.

  • > 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.

    Yes. The point is if you stop a loop, the current tick will complete, you can update progress text, and continue looping the next tick if you kept track of how far along the loop you were. You can control how many breaks there are depending on how long you expect the loop to take. In my first example I made 100 breaks, to give a percentage progress indicator, thus if my loop took 300 seconds to run in whole, progress would be seen every 3 seconds. Or if it took 5 seconds in total, it would update every .05s.

  • 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.

    This technique makes the most sense, thanks. But I'd still have to shoehorn the while into it. As I mentioned before, I'm reading an array in a spiral. In the code above t=top b=bottom l=left & r=right and represents which row or column it's looking at. As each loop finishes it either adds one to top or left or it subtracts one from from bottom or right. The reason I use a while is so that it keep running until top <= bottom and left <= right.

    I could do recursion but I spent so much time rearranging this so that c3 likes it that I'm loathe to dive into that pit again. I may just leave it without a progress update. This one only takes 1-3 seconds which isn't bad. The next one takes longer but it's much more susceptible to being broken up into chunks.

    Here, let me show you guys what I'm doing and maybe your brains will come up with a better solution than I have.

    I'm creating procedural maps. The light blue represents fresh water, dark blue salt water. I want the character to start as close to the center of the map as possible and have fresh water nearby. The while loop starts at the top left of the array that makes this map and spirals inward. The last x,y coordinates it finds with viable fresh water is saved so that from there, I can do another search for a spot for the character to start.

    I could have spiraled outward from the center and found the fresh water sooner but the logic of figuring that out hurt my head. Either way, I was looking at using a while.

    You can barely see it, but there's a green dot on the fresh water real close to the center of the map. That's the x,y coordinates the loop finds.

  • Um, you're not using javascript?

  • I played around with a few ideas I had...

    I made a tilemap that is 200 x 200 and put 5 random water tiles on it.

    the search starts in the middle and spirals outward, stopping as soon as it finds water.

    I wasn't sure what you were looking for in CheckAllWater2, so my function just assumes it passes the test and that we found water if it is a WaterTileFresh tile.

    as the search progresses, the searched tiles are turned yellow so you can see what is going on. when it finds water, it turns that tile pink.

    it finds water almost instantly on my computer. on my iPad it takes about 20 seconds just to load the project in preview mode from C2, but once it actually starts it takes less than a second to initialize the array, tilemap and then find water. I tried a variety of ways to test why it was so slow on my iPad. Eventually I loaded the capx into C3, exported, and loaded it from the web - then it only took 4 or 5 seconds to load, then found water in the typical half second...

    https://www.rieperts.com/games/forum/FindWater.capx

  • I played around with a few ideas I had...

    This looks like what I had planned to do. I'm going to have to study this but it looks a good bit more efficient than what I'm doing.

    The CheckAllWater2 simply looks at the 8 surrounding tiles to make sure they're all fresh water as well. In a later smoothing process a lot of tiles get changed but as long as there's a 3x3 grid it should pass that process. The way I have it set now, if it doesn't find any 3x3 fresh water grid 1/3 of the distance from the center, it recreates the entire map and tries again. Since the smoothing takes a while, I'm doing this check early.

    That GameState var. Clever. I would have never thought you could call a function like that.

    Thanks.

  • Um, you're not using javascript?

    That's why I pay for Construct. So that I can avoid it like the plague.

  • Because you can expect up to a 30% increase of speed in cpu intensive tasks.

    But hey they make Php to Js converters don't they?

  • You need to use the "main" loop, to execute a set amount of "units of work" per tick. Otherwise, the whole thing is gonna hang while the logic is running.

    Check out this file : github.com/Magistross/Magistross.github.io/raw/master/files/progress.c3p

    10 millions of "units of work" (that does nothing) are ran per tick, after each time the progress is updated and the screen is refreshed. You can tweak the amount of "units of work" you want done in a tick, higher numbers will make your FPS drop to a crawl, but less time is loss updating the screen/progress.

    You will however need to change how you implemented things so you can exit the local loop mid-task without crashing everything :P.

  • I just updated my sample, made it check if fresh water is around the tile found, and aborts if it gets more than 1/3 out from middle...

    (I purposely have some water too small)

    https://www.rieperts.com/games/forum/FindWater.capx

  • Just to clear a few things up...

    Construct runs each tick like this:

    1. Run the events to completion
    2. Run any waits that have expired
    3. Draw the screen

    This means if you have a long-running loop in your events that takes 5 seconds, it gets stuck on step 1. Since the engine is tied up in an event loop it never gets as far as checking if any waits have expired, nor does it get to draw the screen - so you can't show any progress during a loop.

    This is exactly how many other programming languages work, including JavaScript - for example if you add a "click" handler on a button for a web page, and in that handler run a loop that takes 5 seconds, the browser never gets as far as redrawing the screen (or running any timers), and so the web page will appear to hang for the user. It's a common architecture since everything has to be done in a series of steps, each step is not interruptable (otherwise you get bugs involving half-baked states), and it's largely done on the same thread (since multithreading large and complex programs is extremely complicated and highly error prone). So the way Construct does this isn't at all unusual.

    The ideal solution is to actually run the work on another thread, but Construct doesn't support that yet, given the extreme complexity of the feature and questionable feasibility - see this blog I wrote a few years ago on Why do events only run on one core? Therefore the next-best solution is just to run the work in chunks, so the engine has the chance to periodically continue to the other steps needed to run a tick, including drawing the screen.

    An obvious way to do this is to run a fixed number of iterations, like 100000 per tick. However this isn't ideal since on very fast systems it will complete the work early, and sit idle while it waits for the next tick, meaning it doesn't complete as fast as it could; and on slow systems that amount of work could still be enough to make it noticably slow.

    So really the best approach is to do work for an amount of time. So you'd break up work in to chunks of 15ms, for example. This means fast computers get more work done per tick, and slow computers just take longer, while also allowing the possibility to reach 60 FPS if everything else is fast. But! 'Wait' events don't run during loops, so you have to use a timer value that can update during a loop... and in Construct, that's the wallclocktime expression. So you should save that time at the start of the loop, and then repeat until wallclocktime is greater than startTime + 15ms.

    Also...

    In Delphi, there's a repeat:until loop which is a lot like a while.

    As I pointed out in the thread you linked to, this is supported in Construct. A 'While' followed by another condition is equivalent to 'Repeat until condition false'.

    The difference between those is, in a while loop, if the condition is met anywhere in the middle, the loop breaks.

    Almost every programming language I've ever heard of only checks loop conditions upon repeating the loop - so this would be an unusual design if it is the case. The reason most languages only check conditions upon the repeat is that if they can break *anywhere* inside the loop, it makes it extremely slow, since it has to keep doing "is condition false" checks after every single statement, which can be a lot of extra work. So that design would basically make it impossible to write efficient loops.

    Also newt or anyone else who says "just use JavaScript" - that is not really helpful in this forum. There is a separate scripting forum for people who want to use JavaScript. In any posts outside of that forum the assumption should be they are working only with events and only want help with events.

  • I'm not a programmer. That's what brought me here to Construct. I do think people should be encouraged to try scripting for cpu intensive tasks like this.

    If we can get an event solution for it, that would be great.

    Edit:

    Also I've been doing stuff like this with Construct for years, so I know frustrating it is when events take longer than pure code.

  • Try Construct 3

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

    Try Now Construct 3 users don't see these ads
  • I do think people should be encouraged to try scripting for cpu intensive tasks like this.

    Just be mindful that many people choose Construct specifically not to code, so won't be interested - as Fengist already stated.

    When we added the JavaScript coding feature several people also raised the concern that they'd no longer get useful help on the forums since people would tell them "just use code". That's something I'm keen to avoid, hence the separation of the forums.

  • I'm not a programmer. That's what brought me here to Construct. I do think people should be encouraged to try scripting for cpu intensive tasks like this.

    If we can get an event solution for it, that would be great.

    Yea, I'd love to see an event solution but that's apparently going to take threading which I'm learning JS apparently doesn't do all that well. That's a shame. I've played with threading in other languages and the things that can be done (scraping 50 web pages simultaneously vs 1) are pretty astounding.

    Writing code isn't that difficult for me. I know 4 or 5 languages, html and css. The problem with learning JS is that it instead of interfacing with a computer & it's hardware, it interfaces with the browser. That means it has a plethora of functions to learn that simply don't apply to other languages. The logic remains the same and the syntax isn't too difficult. It's all those blasted unique functions that cause me to spend hours digging to figure out how they work. So, learning all that gobbldey-gook JS introduces is not something I've needed nor wanted to learn. I pay Ashely and the crew to do that for me.

    It's nice know that I can write JS if it comes down to it. And I have written some functions to handle HTML changes. It wasn't because I wanted to, it's because it was the only solution.

    If I can solve things with events and not have to facedesk my way through JS, I'm happy.

  • I expanded my example to switch over to the wallclock check explained by Ashley.

    github.com/Magistross/Magistross.github.io/raw/master/files/progressWallclock.c3p

    There's still plenty of room for improvement, but the basic idea is there.

    20 millions iterations, done while trying to keep FPS at 60.

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)