The Right Thing To Do is to run logic and rendering at separate cadences, with rendering driven exclusively by requestAnimationFrame. Then when the browser is minimized, RAF stops firing and rendering is skipped entirely (on top of the other benefits of decoupling logic and rendering).
The "background mode" mentioned in the article is about the Steam version, which runs in Electron and I have to set `backgroundThrottle: false` flag. In this case, Electron will not throttle timers and I can safely disable rendering while leave the logic running.
[1] https://www.reddit.com/r/incremental_games/comments/seid8w/c...
I think idle games are a special case here, in that variable timesteps aren't necessarily a liability for them. In an ideal world, one would like all the systems in an idle game to be able to quickly simulate arbitrary amounts of time (for offline progression etc), and if the whole game is made that way then in principle one is immune to throttling. But I think games actually built that way are pretty few and far between.
If so, how do you ensure that when the rendering loop reads the shared state, it sees something consistent (i.e. something that hasn't been updated by the logic loop in between the time when the rendering loop started accessing it, and the time when the rendering loop finished accessing it)?
Rendering can be but isn't always the most expensive portion of a game's execution, but if you have a lot feeding into that in terms of object updates and game logic you can find yourself chewing a surprising amount of CPU time, and therefore power, which isn't great if the host device is running on batteries.
One of the most frustrating things about using a web stack is issues like this where you've got an embarrassingly parallel problem and you can't use threads easily.
Even in Unity non ECS, which is fairly constrained, high performance dot processing would be fairly straight forward.
I'm working on an idle web game using ClojureScript, and it's very much the other end of the spectrum. The game design is event driven and state small out of necessity.
Although I'll of course agree a better computer helps the iterative dev cycle.
You forget what “real people” experiences are like when you’re on your $2000 beefy rig.
Everyone on the internet is an expert (/s), so here is my intuition: If a mine produces $stuff at a rate of x $stuff/s, the factory it is sending to will have a supply of x $stuff/s coming from that mine; the factory's total supply will be the sum of all these x from the various mines that are sending to that factory. So what I would do is a setTimeout("increase supply of stuff for target factory by x every 2.5s", 2.5) to link a mine to a factory (and "decrease..." for unlink). This simulates that the first resources take some time to arrive.
Are the deliveries continuous and not bursty? Then the cheap way is then to increase the resources every second (or whatever your ticklength is) for the appropriate fraction by iterating over the factories - which are probably much fewer than the resources in flight. Players might notice this.
Are the deliveries bursty? Keep an array of pairs (burst_amount, burst_time, burst_stride) and when iterating over the factories to add resources, add those for which "burst_time modulo tick_time == burst_stride". This requires some discretisation, but would the players even notice...? Just make sure that if you draw resources on the screen that they arrive roughly in sync with the actual resource update in the factory.
Bonus: This could go in a thread of it's own that only takes care of these updates. But I am not sure if that can be done in your language like I would do it in C++.
Curious why you've chosen to use massive amounts of timeouts with the respective overhead.
They are not "bursty", but they can fluctuate. Power fluctuation, fuel shortage or upstream supply chain issue could cause a building to skip a production cycle - and impact all its downstream. In fact that is a core challenge in the game. So the core game logic has to be simulated, not calculated.
Doing multithread in JavaScript (via WebWorker) is kind of painful.
Yeah, multithreading is often a pain. OTOH the gains can be enormous.
What you have implemented here is a priority queue, with O(1) insertion and O(n) deletion. It is easy to get down priority queues to O(log n) deletion without sacrificing insertion speed noticeably much. So unless you have some good reason to iterate all resources every iteration, changing to a better priority queue implementation will most probably yield you even more of a benefit.
I don't know much about cocos2d but since the dots are purely visual, do they need to be game objects? Couldn't you keep their transform in a separate data structure which you can update independently and pass to a shader (or similar) for rendering? I'm thinking something similar to how particles in VFX are usually done.
I ended up not doing it in this iteration because:
- cocos2d's custom shader support is kind of poor, especially documentation is pretty much zero
- the dot is not "purely" visual. For example you can trace and highlight a resource's movement. This is not a blocker per se, but requires more work
hybrid canvas html game are a joy to work with, there's no reason to limit oneself to canvases as long as you can export and import events to the external world. I've built some, and having for example the ux in html sending control events to the canvas cut the development time a lot. all these 2d libs have painful ux api, with dreadful limitation, while in html you can just slap whatever stile and it'll always be crisp.
iphone's chrome entered the chat
Using Unity to compile to the browser seems to yield much better performance out of the box