6 ms·
This teaches a bad practice: frame-rate-dependent movement speed. Perhaps it runs fine on your 3GHz 16-thread i7 Chromebook Pixel with a single tab open that ac
by TazeTSchnitzel 10y ago
This teaches a bad practice: frame-rate-dependent movement speed. Perhaps it runs fine on your 3GHz 16-thread i7 Chromebook Pixel with a single tab open that achieves a consistent 60fps, but it makes the game unplayable on machines achieving slower or less consistent framerates (like mine, which has a somewhat overburdened Firefox process on a mere 4-thread mobile i5).
If you're writing a game which, like this one, does not run at a fixed guaranteed framerate, you should vary movement speed based on the time delta between frames, i.e. instead of `x += 2.5` on every frame, do `x += (2.5 * 60) * seconds_since_last_frame`.
- CJefferson 10y agoNo, that's also a terrible idea. It makes problems like jumps that are easier, or harder (maybe impossible) to achieve based on frame rate. Games used to do this, now noone does as it leads to impossible to fix bugs and weird physics problems. The best idea (but i don't know how to do this in is) is to run your engine at 60fps (say), then skip drawing if you are behind (but then always draw at least every third frame, if someone's computer isn't good enough to even run the engine). If you want to go above 60fps, then extrapolate between two states. EDIT: If you want to see an example of this, see for example https://www.quake3world.com/forum/viewtopic.php?f=13&t=2170 https://www.quake3world.com/forum/viewtopic.php?f=13&t=2170 , which is a big investigation into the "best frame rate" to play Quake 3 at, to run fastest / jump highest.
- wareya 10y agoFirst, even at a constant framerate, different players will have different experiences with the game due to different amounts of latency in their peripherals, weird CPU bugs, very very minor floating point behavior deviations, etc. The important part of making something framerate independent is to make the effects of framerate independence /smaller enough/ than other factors that make player experiences. It's entirely possible to not have gameplay change at different tickrates. There are three usual types of problem that cause gameplay to change at different tickrates: 1) Events that happen at specific times If events can only happen "in sync" with ticks, then running at different framerates will make them happen at different times. Say you have a machine gun that fires once every 1/10th of a second. If you're running at 24fps, then not only do you need to make sure that you correctly output a bullet every two-or-three frames, you also have to make it so that they /act like/ they came out at a time between frames, presumably by simulating them a little extra bit or a little less depending on what's necessary to make each bullet a fixed distance apart (for example). You could also use a continuous interaction system here but that's really hardcore and doesn't matter in 99.9%+ of cases. 2) Treating curved motions as linear motions This isn't a problem in 99% of cases, but it ~can~ be a problem. If you can't represent your physics curves in closed form, it's effectively impossible to trace them in a framerate-independent way. The only thing you can do for these things is to "fix your timestep", but "fix your timestep" should be used with extreme caution and not be applied to action games because it adds input latency and hides frame-specific-timing information from players. Recommendation: use simpler game physics. Constant acceleration everywhere you can, special-purpose closed form functions with the right curves where you can't, and avoid tight curves. This makes it less of an issue. You might also want a collision system that allows curved paths, but if you have enough control over your game's environments, and you don't expect people to run at SUPER low framerates, this isn't an issue. 3) Running different "integral" parts of the simulation out of sync with eachother. This isn't literally about code order execution, it's about the behavior of different pieces of code that "add up" "over time" (if you're into calculus, think antiderivatives) If you add n to your position every frame, that's all fine and good, as long as it always starts at exactly the right time. If you add "five pixels per second" to your position, then you need to make sure that always causes the same amount of distance travelled. Quake 3 handles this by giving subframe timings to things like pressing and releasing movement keys. Another example is gravity. Normally, game code adds a specific amount of gravity every frame, possibly adjusted for time, either before or after motion. This isn't good enough, because if you add gravity after moving, very low framerates will have a higher initial frame of gravitational movement; essentially, low framerates will skip "outside" the ideal jump arc rather than tracing it. If you add gravity before moving, the opposite happens, low framerates trace "inside" the ideal jump arc. The correct thing to do is to calculate motion with around half the added velocity from all accelerations for that frame, which basically means the average of accelerating before or after. You can also trace a hermite spline, which is more flexible (you will have perfect framerate independence for any acceleration values that only change along line segments, i.e. "constant jerk", as long as you handle start/stop conditions for changes in acceleration with a correct continuous interaction simulation), but harder to implement. The above is only 100% ideally possible for things you can represent closed form, and in practice, people will only implement something correctly if it's not just closed form but /simple/. Many games stop short of correct jump arcs, but it's entirely possible. Gang Garrison 2 was just changed to have a correct framerate-independent jump arc.
- CJefferson 10y agoI don't know what kind of CPU bugs or float point behaviour deviations you think modern cpus have that will effect a game.. such things would cause most online games to immediately go out-of-sync, and in practice they don't, and while latency might effect player's enjoyment, it won't effect how fast they run / how high they jump. The hardest part is the curved motions -- and also collision detection. Without ticks it's extremely hard to make collision detection repeatable. I'm unaware of any recent notable multi-player game which don't run on a tick-based physics engine (I'd be interested if you could point me to some) -- that suggests to me that tick-based is necessary. Sure, you can get things "closer" in tickless physics, but I've never seen anything non-trivial which can produce exactly the same results, for reasons of floating point: when (A+B)+C isn't the same as A+(B+C), it's very hard to make your game produce exactly the same results. As you say, with a lot of work, you can get a 95% repeatable result with a tickless engine, but you can easily get 100% repeatable with a fixed time-step engine, and in practice it seems to make things work well enough, and is VASTLY easier.
- wareya 10y agoOnline games avoid that problem by having an authoritative networking architecture, not by avoiding minor deviations in CPU behavior between players. Games that use synchronized lockstep that use floating point math always desync, because floating point math differs slightly between different processors. Curved motions are easy as long as you have simple polygons and only one of them is accelerating and is accelerating in a simple way. You remove the acceleration by skewing the polygon you're going to collide with and then you have a linear path of motion again. (if the acceleration is not constant for the duration of that frame, then skewing doesn't give the right result; as long as you have a closed form representation, though, it's entirely possible to get it right) "Don't run on a tick-based physics engine" is a misconception. Interactions are the borders between ticks. It's just dynamic. As long as your tick doesn't contain interaction changes inside it, you can simulate that tick with 100% tickrate independence with 100% certainty. Floating point differences between cpus are Much Larger, especially if your code uses hardware-accelerated trig at all. Games networking is authoritative for this reason. You can get a 100% repeatable result with a tickless engine. Fixed timestep doesn't solve the problem. If the user can't run the simulation at 60 ticks per second, they're still going to slow down, period. All you're doing is separating simulation from rendering, which basically every modern FPS under the sun already tries to do in a different way than fixed timestep does. If you run the simulation slow enough that nobody will have performance problems with it, you just added tons of input latency. Thanks a lot, sincerely, someone with dysgraphia.
- golergka 10y agoNo, the usual way of achieving this is to decouple your movement (as in, physics) from rendering. Instead of having an "update" loop, have "renderUpdate" and "physicsUpdate" as separate loops, one tied to FPS, other constant.
- p0nce 10y agoFully agreed. You can certainly deal with some aspects of variable framerate integration. But it's by far a better solution, more future proof even, to just have a fixed number of iterations by second and don't account for time deltas in integration. My physics-based game is using the method argued against. Never again, integrating every behaviour over time got sometimes surprisingly hard. It also costs a lot of exp() and log() calls. https://auburnsounds.itch.io/vibrant https://auburnsounds.itch.io/vibrant (of course multiplayer is impossible now) Some of the AI is still framerate-dependent, because: // fixed framerate if (randomFloat0To1() < 0.1f) doThis(); becomes a Poisson distribution sampling.
- strainer 10y agoWe do also loose much accuracy/stability of physics info when varying timesteps, without adjusting velocities to the new half timestep (eg. verlet type refinement) which is a bit demanding to do most accurately.
- Mithaldu 10y agoOn the other hand, beyond a certain level framerate-dependent movement speed can be enabling to the player. If there are parts in the game where the performance breaks down on certain machines, then it can be preferable to have the game go slower, i.e. still controllable, than a slide show that leaves the player no time to react. There is no one-size-fits-all when it comes to game loops. There's various ways to approach them and which one fits your game best is determined by its gameplay.
- TazeTSchnitzel 10y ago> If there are parts in the game where the performance breaks down on certain machines, then it can be preferable to have the game go slower, i.e. still controllable, than a slide show that leaves the player no time to react. Indeed, it's somewhat delicate.
- Jare 10y agoI haven't looked in detail for this example, but IIRC Phaser always supported multiple updates per tick by default, see https://github.com/photonstorm/phaser/blob/9579263333d799bf730f31ac889d187f5e9d65fb/v3/src/boot/MainLoop.js#L196 https://github.com/photonstorm/phaser/blob/9579263333d799bf7... edit: guess I spoke too quickly, that was v3. In v2 the game loop in Phaser is more aggressive detecting "spiral of death" scenarios. Still, the idea is that if your CPU just can't deal with the given number of updates per second even when skipping renders and other "optional" stuff, then there is just no way to avoid a bad experience, either very low framerate or slow motion. Variable framerate simulations can be quite dangerous and unstable, and the example doesn't even try.
- edem 10y agoTry this out: http://gameprogrammingpatterns.com/game-loop.html http://gameprogrammingpatterns.com/game-loop.html The book itself is very good as well.
- awqrre 10y agoNot saying that you are wrong about the game design but there might be some issues with your i5... perhaps a cleanup or fresh install would help.
- TazeTSchnitzel 10y ago…huh? The hardware on this MacBook Air is perfectly fine. I just have TweetDeck open in another tab, and e10s isn't enabled, so Firefox suffers.
- awqrre 10y agoI was talking about the software installed on your hardware...
- TazeTSchnitzel 10y agoOkay, what about it? The web is not a particularly fast platform. That it doesn't always achieve 60fps in practice is not surprising.
- mfichman 10y agoUsing the delta between frames directly isn't quite right either, but it's better than writing framerate-dependent code. I think an even better way is to use an accumulator with a fixed time step, as described here: http://gafferongames.com/game-physics/fix-your-timestep/ http://gafferongames.com/game-physics/fix-your-timestep/
- 0xdada 10y agoExactly what I was going to link. It's a very useful article that I've had bookmarked for a while now.
- koonsolo 10y agoYes, that article is 100% correct. Shameless plug here: A long time ago I wrote an article on how to implement a proper game loop, http://www.koonsolo.com/news/dewitters-gameloop/ http://www.koonsolo.com/news/dewitters-gameloop/
- fenomas 10y agoVariable timesteps have their own host of problems. Considering the target and scope of TFA I think best practices are beside the point, but your suggested replacement is bad practice as well. The "right thing to do" in most games is to integrate at fixed timesteps that are decoupled from rendering. But this can be tricky to get right, and would require another article to explain [0]. Considering all that, the article's implementation is fine! [0] Except that the definitive article has already been written, that is: http://gafferongames.com/game-physics/fix-your-timestep/ http://gafferongames.com/game-physics/fix-your-timestep/