5 ms·
Any idea what a game loop would look like for an ECS engine that only renders a new frame when some animation is running or when the user is manipulating the ca
by korijn 4y ago
Any idea what a game loop would look like for an ECS engine that only renders a new frame when some animation is running or when the user is manipulating the camera, but not otherwise?
Let's not argue "why". Most obvious would be saving battery.
- ajmmertens 4y agoDefinitely possible. I know of a project that used an event-based architecture to decide when to run ECS systems.
- jiggawatts 4y agoI wrote a game engine that did that, because it was for a very simple, largely static scene. You would implement it almost the same as a standard Windows GUI -- using an event handler loop that marks the screen as "dirty" and needing a refresh if it has changed. Where it would immediately break down is ongoing animations. If you stopped moving your mouse, then animations would stop. Of course, you can set up the event loop to continue triggering if there are animations going on, but then you basically have a standard game engine loop running most of the time. Personally, I'd be happy if games simply paused rendering when minimised. Some games do this, some don't.
- exDM69 4y ago> I'd be happy if games simply paused rendering when minimised. Some games do this, some don't. Yes, please. It drives me nuts to have GPU fans spinning when game is minimized, paused, in the loading screen, turn based and no inputs, etc.
- korijn 4y agoWell, if those animations are things such as camera smoothing, it won't have such an impact. But I see your point. Thanks for entertaining the idea!
- cnity 4y agoYou just have to include all the parameters of the animation as part of your "dirtiness" calculation. I reckon in practice this means centralising pretty much _all game state_ in some way that you force the dirtiness state to be set correctly.
- Cthulhu_ 4y agoSome games (I'm thinking FFXIV) will run on a lower framerate (15fps) while minimized or, in that game's case, if the player is idle for an X amount of time, that's a pretty decent compromise. But yeah, games don't need to render any frames while minimized. I do feel like this should be the operating system's responsibility as well, but then, a lot of games still have the graphics rendering and other parts of the game linked tightly together.
- crabmusket 4y agoI've implemented exactly this at $WORK. We literally just set a global variable, "should render next frame", from input handlers and other important events. It's not pretty but it gets the job done. There are occasional bugs where someone forgets to set the render flag after some significant event. But the bug goes away as soon as the mouse is moved, so it's usually not a big deal. If we wanted we could also schedule a "render once per second" to bound the amount of time that visual issues would persist for. I'm not sure how this translates to ECS architecture - probably depends on your library, but if you're in charge of the main loop it shouldn't be a problem.
- nyanpasu64 4y agoOne trick I found is to gate mutable access to state behind a "transaction object" which sets a flag for each object mutated, then once the transaction object's destructor is called, recomputes all derived state based on which flags were set. Using a destructor might not be the best idea since I ended up not marking it noexcept, it may be better to add an explicit "recompute" function called at the end, but this breaks the convenience of `state().cursor_mut() = new_cursor;` automatically recomputing derived state once the state() object is destroyed.
- pavlov 4y ago> “the bug goes away as soon as the mouse is moved, so it's usually not a big deal” This reminds me of: https://thedailywtf.com/articles/Hidden-Tax-Moves https://thedailywtf.com/articles/Hidden-Tax-Moves "Wait, let me try," Bruce said, grabbing the mouse. "Whoa, what just happened?" a teammate exclaimed. "What did you do? A ton of traffic just came through!"
- crabmusket 4y agoIncredible. It's like the opposite of JS logic, where you are encouraged to do as little as possible in event handlers.
- fileeditview 4y ago> After several meetings, it was decided that it wasn't the best idea to put critical code in an app's MouseMove event. Prove that the story is real ;)
- tbillington 4y agoThe bevy engine (ECS based) has an `UpdateMode` that specifies "Continuous" vs "Reactive" https://docs.rs/bevy/0.10.1/bevy/winit/enum.UpdateMode.html https://docs.rs/bevy/0.10.1/bevy/winit/enum.UpdateMode.html. Here's an example using it, it's well suited for "desktop applications", the shorthand to use it is `desktop_app()` https://github.com/bevyengine/bevy/blob/1c5c94715cb17cda5ae209eef12a938501de90b5/examples/window/low_power.rs#L18 https://github.com/bevyengine/bevy/blob/1c5c94715cb17cda5ae2.... https://github.com/bevyengine/bevy/ https://github.com/bevyengine/bevy/
- charcircuit 4y agoHow often your app takes in events != How often your app outputs frames The OP only mentioned that he wanted to stop outputting frames. Animations, physics, input, etc should still happen normally.
- pengaru 4y agoECS isn't really relevant to the question game loops usually call into simulate() and render() entrypoints. There's state potentially mutated by simulate().. render() looks at that state and potentially produces a new output to present on-screen. Typically the render() entrypoint returns a status indicating whether a new output was produced or not to put on-screen. If no output was produced you don't flip pages. So in a quiescent situation with nothing changing, render() returns "don't flip" and you just leave the existing page displayed til the next iteration. How you track the internal game state / dirty vs. clean state is implementation detail behind those simulate() and render() entrypoints and depends greatly on the type of game.
- Cthulhu_ 4y agoI'd say this is something that can be done on a driver / GPU level; if the inputs to render the next frame are the same, it can just reuse the previous one. That's probably oversimplifying it, I don't know anything about graphics programming.
- cnity 4y agoThis doesn't really work. By the time the driver or GPU could "know" that the frame is the same, it's already done a lot of the heavy lifting. As in, it has basically still rendered the next frame by this point. Actually writing the result to the framebuffer is not expensive. fwiw: The downvotes are not from me.
- ww520 4y agoFor energy efficient game loop, it still runs in a fixed frequency, e.g. in 60fps or 30fps. For each frame, the time is spent on event processing, state update, rendering, and sleep. Some of the steps can be skipped. The goal is to lower the times spent in the non-sleeping steps, and sleeps more for each frame. Event queues are used to track things in long duration across multiple frames, like user input, animation sequences, sound sequences, pending state update, pending physics update, pending AI update, etc. In each frame, check the event queues. If they are empty, sleep. Otherwise, process the events in the queues. For user input, do the state update corresponding to the input, like updating the camera position. For ongoing animations, advance the steps in the sequences (the drawing is done in the rendering step). When an animation sequence completes, remove it from the queue. Same for sound. For pending state update, run the update. E.g. the ship is moving, do the state update on its velocity and position. For ECS, you might end up calling or not calling the systems for the item type for batch update. E.g. when the bullet queue is not empty, you might just run the bullet related systems over all bullets for simplicity. When all the bullets end and the queue is empty, the bullet related systems can be skipped. The physics queue has the items being simulated. Run those. Physics could run at a slower rate like 5fps, so the queued items would be skipped most of the times. Same with the AI items in the AI queue. Whenever there's a state update, mark the screen as outdated. At the rendering step, run rendering if the screen is outdated. It's simpler to just run the whole rendering for any change. Ideally, when there's no event in the queues or the state updates are not triggered, there's no need for rendering. This applies to using ECS or not. ECS is for tracking states of entities and do batch update with systems.