aylictal Posted April 9, 2018 Share Posted April 9, 2018 Hello- This might seem basic, but when I look at boilerplate phaser projects i typically see 3 functions (either standalone, or a part of the newer es6 classes): preload(){ } create(){ } update(){ } Most game logic I've worked with does not tie in it's rendering calls with its physics calls such as player positional data, etc. Is there a good standard for seperating these two concerns with phaser? Thanks. Link to comment Share on other sites More sharing options...
samme Posted April 9, 2018 Share Posted April 9, 2018 If you need to do your own rendering, it can be done in a render method. But usually you'll just using update, as Phaser renders things automatically. Link to comment Share on other sites More sharing options...
aylictal Posted April 9, 2018 Author Share Posted April 9, 2018 The reason for this post is because (as of my understanding) update triggers request animationframe under the hood which is both good and bad. RAF will render stuff as fast as the machine can possibly render it. The issue is if you tie physics in with that update (such as positioning, or player speed, stuff like this) then it will update much faster on faster machines than on slower machines, which is why you don't really want to tie these two things together (otherwise known as framelocking). This is so that while the renderer can be rendering many many many times, the updates to physics can be on a separate loop altogether. Link to comment Share on other sites More sharing options...
aylictal Posted April 9, 2018 Author Share Posted April 9, 2018 Is there any good examples of phaser 3 projects with this in mind anywhere to what is being discussed above? How to seperate game physics updates from game render updates? Link to comment Share on other sites More sharing options...
digitsensitive Posted April 9, 2018 Share Posted April 9, 2018 I think there is no way to separate game physics from game render updates, because they are bound together ... or what do the others think? Quote The issue is if you tie physics in with that update (such as positioning, or player speed, stuff like this) then it will update much faster on faster machines than on slower machines, which is why you don't really want to tie these two things together (otherwise known as framelocking). Is that true for Phaser 3? Link to comment Share on other sites More sharing options...
snowbillr Posted April 9, 2018 Share Posted April 9, 2018 I _think_ that you can do this with the latest version of Phaser (3.4.0) - https://github.com/photonstorm/phaser/blob/master/CHANGELOG.md#new-features The changelog talks about customizing how MatterJS physics updates. That might be what you are looking for. Link to comment Share on other sites More sharing options...
samme Posted April 9, 2018 Share Posted April 9, 2018 RAF doesn't run as fast as possible, it runs at a stable rate (usually 60Hz) when the thread is free or less when it's busy. Physics systems receive the time delta from the update loop, so they won't necessarily run any faster or slower. Link to comment Share on other sites More sharing options...
aylictal Posted April 9, 2018 Author Share Posted April 9, 2018 58 minutes ago, samme said: RAF doesn't run as fast as possible, it runs at a stable rate (usually 60Hz) when the thread is free or less when it's busy. It runs on several factors, but monitor refresh rate is one of them, so if a player is using a 144hz monitor, it is going to try to match that, which is drastically different than 60hz. However, your answer about physics systems receiving time delta from the update loop is very helpful. Is there a way to set up a rudimentary physics system in it's own method ie preload(){ } create(){ } update(){ } physics(){ //?? } Link to comment Share on other sites More sharing options...
Antriel Posted April 9, 2018 Share Posted April 9, 2018 1 hour ago, samme said: RAF doesn't run as fast as possible, it runs at a stable rate (usually 60Hz) when the thread is free or less when it's busy. RAF will fire as fast as it can, synced to display refresh rate. So on 60 Hz display, you get 60 Hz or less. On 144 Hz display it will run 144 Hz or less. On g-sync/freesync/hdmi 2.1 vrr, it can be anything. What needs to be understood here is that phaser doesn't provide you with proper game update loop. It gives you RAF loop (or fallbacks). It's on your to handle whatever you need, e.g. fixed timestep physics with interpolation. V3 had recently added automatic fixed timestep and manual update options to matter.js physics. I'm not sure if the automatic fixed timestep is still running off RAF (which makes the option kinda pointless), but you can use the manual option in any case. In my case, if the game is mostly async tween actions (think match 3 sliding stuff), I just use tweens and don't care about deltatime. As soon as I have any kind of physics or time based logic (even simple speed += acceleration), I switch to fixed timestep with interpolation. I did describe my approach in at least one topic here webdva, aylictal and theNeedle 3 Link to comment Share on other sites More sharing options...
aylictal Posted April 9, 2018 Author Share Posted April 9, 2018 Will take a look at any examples you provide, and may possibily stalk your posts @Antriel If you have a specific, please link it here in the thread though as it is much appreciated and answers my topic. Cheers Link to comment Share on other sites More sharing options...
aylictal Posted April 9, 2018 Author Share Posted April 9, 2018 But yes, the problem is that player locations are going to be stored on a server, which is async by default, and the client then needs to get updated from messages sent, thus relying upon update() to interpret those will fail Link to comment Share on other sites More sharing options...
Antriel Posted April 9, 2018 Share Posted April 9, 2018 When it comes to syncing with server, it gets much more complicated. Depending on the approach you take, from simple interpolation from past data with a buffer through basic prediction and correction to converging prediction. All these, even though work similarly to rendering interpolation with fixed timestep physics, are there to solve different kind of problem though. I wrote an article about Entity Interpolation for multiplayer games, but it's not really aimed at total beginners. That said I do link to other articles that describe the basics, so all this should get your started. Link to comment Share on other sites More sharing options...
samme Posted April 9, 2018 Share Posted April 9, 2018 Maybe we just have different ideas of "as fast as possible" here. I mean RAF doesn't run continuously. It's synchronized, and it's stable as long the thread isn't busy. I said usually 60Hz because that's the most common refresh rate. If it's not 60 it will be come other stable rate. More importantly, you can use the time delta in update: http://labs.phaser.io/edit.html?src=src\timestep\variable smooth step.js Link to comment Share on other sites More sharing options...
Antriel Posted April 10, 2018 Share Posted April 10, 2018 Yes, alright. Except that it might not be stable on gpu-synced displays. Using provided delta time is of course the way to do anything, but you can't always apply it raw like that. Thus the need for fixed timestep for physics and basically any kind of numerical integration. As I mentioned before, even simple `speed += acceleration * dt` will behave differently at different dt. Link to comment Share on other sites More sharing options...
Trance Posted April 10, 2018 Share Posted April 10, 2018 10 hours ago, Antriel said: Using provided delta time is of course the way to do anything, but you can't always apply it raw like that. Thus the need for fixed timestep for physics and basically any kind of numerical integration. As I mentioned before, even simple `speed += acceleration * dt` will behave differently at different dt. I don't understand what you mean by "behave differently" in this context. Isn't the whole point of that formula that the physics will behave the same at different dt? If dt is 20, the object will move twice as far as if dt was 10, because it's been twice as long since the last update - hence making the physics behave correctly regardless of how often Update() is called. Link to comment Share on other sites More sharing options...
Antriel Posted April 10, 2018 Share Posted April 10, 2018 I'm not very versed in terms as far as math and physics goes, but basically physics engines use only approximations to calculate what happens. There's a few approaches and each have their pros and cons. If you take basic Euler: position += velocity * dt; velocity += acceleration * dt; You will find out that different `dt` will give you different result within the same time. Semi-implicit Euler (just swap those 2 lines) is lot better, but still wrong. You can read pretty good article about it here. So basically, to have predictable and stable physics, you want to run your `physics.update(dt)` with fixed `dt`. That means it's the same every time. But that also means you can't just call it once every frame, because time between frames won't be exactly `dt` every time. So you do something like: var accumulator = 0; var physicsTimestep = 1/60; function renderUpdate(timeSinceLastFrame) { accumulator += timeSinceLastFrame; while(accumulator >= physicsTimestep) { accumulator -= physicsTimestep; physics.update(physicsTimestep); } render(timeSinceLastFrame); } Link to comment Share on other sites More sharing options...
aylictal Posted April 10, 2018 Author Share Posted April 10, 2018 (edited) Yes I have figured out how to cater the native update loop to accomodate this, but also had to write my own render method: This is what I'm working with to customize for this behavior. I could probably use a code review to make sure my ducks are in line (it seems to work for me, but this heavy math involved). class scene1 extends Phaser.Scene { constructor(){ super({key: "scene1"}); this.lag = 0; this.fps = 60; //physics checks 60 times/s this.frameduration = 1000/ this.fps; } phys(delta) { //phys checks and server IO events update state of entities here } render(delta){ //rendering stuff here } update(timestamp, elapsed){ if (elapsed > 1000) elapsed = this.frameduration; this.lag += elapsed; while(this.lag >= this.frameduration){ this.phys(elapsed); this.lag -= this.frameduration; } this.render(this.lag/this.frameduration); } } Edited April 10, 2018 by aylictal code comments to explain this madness Link to comment Share on other sites More sharing options...
Antriel Posted April 11, 2018 Share Posted April 11, 2018 Few notes: Phaser 3 smooths out deltaTime so I can't see it ever being over 1000. That check isn't really needed. You pass the raw elapsed time to `phys()`. That's not fixed timestep, you should pass `frameduration` (which is really bad name imo, it's not duration of the frame, it's your physics timestep). What you pass into render isn't `delta`, it's progress towards next update that is to be used as interpolation value. I usually call it `alpha`, and although the name doesn't matter, I would avoid calling it `delta` as that's not what it is. aylictal 1 Link to comment Share on other sites More sharing options...
aylictal Posted April 12, 2018 Author Share Posted April 12, 2018 Is interpolation/alpha really needed for the renderer? Can't that be conducted in phys() checks where phys is updating the state based upon io sent from server, or evaluating state of current objects of the game (ie client side physics updates)? Based upon your suggestions, review the following please if this makes the most sense: class scene1 extends Phaser.Scene { constructor(){ super({key: "scene1"}); this.lag = 0; this.fps = 60; //physics checks 60 times/frame this.frameduration = 1000/ this.fps; } phys(currentframe) { //phys checks and server IO events update state of entities here } render(){ //rendering stuff here } update(timestamp, elapsed){ this.lag += elapsed; while(this.lag >= this.frameduration){ this.phys(this.frameduration); this.lag -= this.frameduration; } this.render(); } } Link to comment Share on other sites More sharing options...
Antriel Posted April 13, 2018 Share Posted April 13, 2018 Looking good now 7 hours ago, aylictal said: Is interpolation/alpha really needed for the renderer? Technically not. It's there to improve the smoothness and avoid frame skips. Even if the display has the same refresh rate as physics, it will eventually go out of sync (frame skips, etc.). What happens then is that you could possibly be juuuust not enough to update physics, so you render the same frame again. That will cause visible stuttering. Alternatively, if your user has higher refresh rate display (120/144, even more Hz displays are pretty common now), you essentially limit them to whatever your physics update is. By providing alpha or however you call it. That is, a relative value of how close we are to next update, and then use that for interpolation, you essentially remove the stutter and enable smoother movement than your physics update rate is. The interpolation itself looks like this: `obj.pos = (obj.next_pos - obj.old_pos) * alpha + obj.old_pos;` Where `obj` is whatever you update in physics and `pos` is whatever property that is (x, y, rotation usually). The `old_pos` and `next_pos` are previous and current values respectively. So in your physics update, first thing you do (before running physics) is `obj.old_pos = obj.next_pos` for all objects. And then instead of updating `pos` directly in your physics update, you update `next_pos`. At a cost of at most one physics step additional input latency (which is really negligible in the whole picture), you get smooth movement at any display refresh rate (if it's high enough for smoothness that is :D). Alternatively, you could run your physics using this approach at much much higher rate, say 200 Hz. And then interpolation stops being that useful. This is usually done if you need very stable physics and can afford the computational time (as you would be running multiple physics update per frame). Link to comment Share on other sites More sharing options...
Recommended Posts