Small corrections (I learn some things from you as well, how nice, haha): - Using Time.deltaTime in Fixed Update is actually fine in Unity cause it automatically returns Time.fixedDeltaTime depending on where it is called from. - Using Delta Time in fixed update still makes sense for various reasons (it keeps speed to units/second and helps when inaccuracies in the fixed update intervals occur) That means 10 free points to you if your read this, haha. Will keep updating this in case I got anything else wrong. :P
dont these 2 corrections contradict eachother? or am I being dumb xD If deltaTime returns fixedDeltaTime while in the Fixed Update, then how can it keep speed to units/second and help inaccuracies?
@@blockify no because fixedDeltatime takes the inaccuraties and inconsistencies in fixedupdate into account, and deltaTime gives rhat fixedDeltatime. Point is in fixedUpdate fixedDeltatime==DeltaTime. There is no difference using one or another. Still, using either one can be helpful to get around inaccuraties(which can happen in fixedupdate if u use neither)
@@blockifyif it helps, you can think of multiplying by deltaTime or fixedDeltaTime as a sort of "per frame -> per second" conversion in unity! (You can also convert the other way by dividing by deltaTime, e.g. if you want to get the amount an object has moved in a single frame, you'd divide its velocity by deltaTime since in Unity velocities are usually per second)
It doesn't return fixedDelta time. If we go back to what I said in another comment, the correct answer is not A in fact non of the truly was the right answer. delta time is the time it took to process the last frame, the documentation backs this up. So when you run that in FixedUpdate, that means the normal delta and the fixed delta will be the same value, but one does not simply return the other. Physics is a fixed step, therefore both are going to equal the same value!
6:50 I would say that it's not pointless to multiply by fixedDeltaTime; Makes it easier to code consistent units (say if you're trying to follow SI units strictly, or if you have calculations in both Update and FixedUpdate that should follow the same unit). Also, if you ever end up changing the frame rate of the FixedUpdate, you'll have to change every single calculation.
The physics will actually break if you change Time.timeScale and don't multiply by fixedDeltaTime, because fixedDeltaTime will change with the timeScale. Meaning it's actually not always the same value, if you have any kind of speedup or slowdown with timeScale in your game.
Just want to add that the code example did not need to be changed at all to be called for FixedUpdate. And that is because Time.deltaTime actually returns Time.fixedDeltaTime when called from within FixedUpdate.
@@zelos666it actually is the other way. The fixed delta time stays the same, but anything running in fixed time will become more granular in real time because fewer fixed steps will occur between frames. This is why you might need to reduce your fixed time step for slow motion. If you are modifying your fixed delta time for this purpose then you definitely need multiply by it in fixed update.
If you're not using fixed updates, you might end up clipping through walls from lag spikes, unless you're using rays to assert if the player has moved through a wall between the previous frame and the current.
correct me if im wrong but, this will only happen if you use a rigid body controller, not for example the player controller asset, also you dont need to code a ray check as you can just set the rigid body to 'continuous' or 'continuous dynamic'
im literally so new at game dev, im just pretty much using everything in fixedupdate, and what needs to execute fast for example key pressed in update, idk if its fine but it works fine, example in my game this: void Update() { if (Input.GetMouseButtonDown(0)) { isShooting = true; CalculateShootDirection(); } else if (Input.GetMouseButtonUp(0)) { isShooting = false; } if (isShooting) { CalculateShootDirection(); } } void FixedUpdate() { if (isShooting) { shootTimer += Time.fixedDeltaTime; if (shootTimer >= shootingDelay) { Vector3 bulletVelocity = bulletSpeed * shootDirection; GameObject bullet1 = Instantiate(bulletPrefab, bulletSpawnPoint1.position, Quaternion.identity); bullet1.GetComponent().velocity = bulletVelocity; GameObject bullet2 = Instantiate(bulletPrefab, bulletSpawnPoint2.position, Quaternion.identity); bullet2.GetComponent().velocity = bulletVelocity; float rotationAngle = Mathf.Atan2(shootDirection.y, shootDirection.x) * Mathf.Rad2Deg; bullet1.transform.rotation = Quaternion.Euler(0f, 0f, rotationAngle); bullet1.transform.Rotate(Vector3.forward, 90f); bullet2.transform.rotation = Quaternion.Euler(0f, 0f, rotationAngle); bullet2.transform.Rotate(Vector3.forward, 90f); shootTimer = 0f; } } } private void CalculateShootDirection() { // Calculate the shoot direction based on the player's transform shootDirection = bulletSpawnMainPoint.up; // Assuming the player's forward direction is along the X-axis shootDirection.Normalize(); }
21:50 From your testing scheme, it's actually possible to get everything wrong and also the -10 points, leaving you with a grading that is undefined according to your evaluation :P (if I didn't miss anything)
Actually things get 100x more complicated if you have non-constant forces, you need to lookup numerical integration (initial value problem). Your recommended way is called Leapfrog integration. It can work really far from accurate if you have spring forces (with springs you need tiny timestep or other more sophisticated methods which usually are not suitable for real-time).
@@drstrangecoin6050 It depends. For springs or gravity (N-body sim) to get stable results Taylor series won't be enough. You would need implicit methods for accurate and stable results (too slow for real-time). But for games springs could be done without forces in more stable way (e.g XPBD). Stability of gravity forces usually not an issue unless you're doing Solar system simulations or the like (in which case parametrized elliptical orbits may be better option for game). For a game maybe first check implicit Euler and then XPBD if it fails, otherwise start faking it.
Implicit is used all the time in games. In fact they showed a common example in the video … velocity = velocity + acceleration * deltaTime position = position + velocity * deltaTime 2nd order Taylor series is fine for most use-cases. If you have to support some wildly stiff springs or need a high degree of accuracy then you could try rk4. p0=initialPos r=restingPos v0=initialVelocity k=springStiffness dt=deltaTime m=mass f1=k*(r-p0) // force v1=dt*f1/m+v0 p1=0.5*dt*v1+p0 f2=k*(r-p1) v2=0.5*dt*f2/m+v0 p2=0.5*dt*v2+p0 f3=k*(r-p2) v3=0.5*dt*f3/m+v0 p3=dt*v3+p0 f4=k*(r-p3) v4=dt*f4/m+v0 v_final=v0+(f1+2*f2+2*f3+f4)*(dt/m)/6 p_final=p0+(v1+2*v2+2*v3+v4)*dt/6
Performance cost is relative as well. It’s all about scale of use. If you wanted a 3rd person spring arm camera and it needed to be super stiff/snappy one use of rk4 would be fine. However if you are setting up a dense foliage section where foliage physically interacts with the player then you’d probably just use a simple implicit approach with v_final=v0+dt*k*(r-p)/m p_final=v_final*dt+p0
I think that in the latest unity versions using deltaTime in fixedUpdate will automatically use the fixedDeltaTime internally so you do not need to change this. Unity implicitly understand which one to use by the context it is used in.
Wow that's kind of terrible API design. Would be a lot better if using deltaTime in fixedUpdate were an error. Implicit/hidden behavior is an evil that you might expect to see in the realm of web dev frontend nonsense, but not in applications programming.
Unity's API design choices are notoriously bad. Thankfully once you learn all the shitty things and minefields it's full of, you can safely ignore it and build up your own software more robustly. But be warned, Unity is a hell to learn.
When people misuse lerp you can really feel it in the gameplay. I did a little different than you though. I recorded the start position and start time, then I use the elapsed time to calculate the lerp factor in each frame. I also like using cosine instead of sqrt, because it gives a more natural feel. The formula is (1 - cos(x * PI)) / 2, where x is the elapsed time.
Are you saying you did position = lerp(startingPosition, endingPosition, 1-cos(x*pi)/2)? Because that would cause it to go back and forth between the start and end, not approach but never reach the end.
@@bastian_5975 It should probably be cos(1/(x+2)*PI), which is really just a differently smoothed version of 1 - (1/(x+1)), where x is elapsed time in both scenarios. (There's an absolute ton of "sigmoid" functions you can use to infinitely approach a number.) The delta-time lerp works though, just it makes a little less sense logically because instead of lerping between two fixed points, you end up lerping between the destination and the previous location.
@@gajbooks at first I thought you meant cos(1/(pi*(x+2))), but cos(pi/(x+2)) looks so much better that I think you mean that. And are you saying that the function you defined was a sigmoid function or that sigmoid functions are a class of functions that also achieve that effect?
I recall when I got into Math 251 Differential Calculus, I thought it was going to be some pretty insane shit, but it turns out we use it all the time without even realizing it. It's just so much more powerful if you know the fancy tricks. I cannot recommend enough that those who don't know at least differential calculus to learn it. You will not regret it.
I love the presentation of this video, with an actual test. The whole "YOU WILL BE GRADED JOKE" actually motivated me to do well on this test that no one will see. I've seen many youtubers educate with information, by just telling us the right answer, showing it in examples, with great animations to help visualize. That process works, but I think many content creators forgot how effective it is to challenge our knowledge. At 3:41, despite me using deltaTime in many places, I realize that... I'm not EXACTLY sure which of these four are true. Thank you for challenging my knowledge, and because of that, you've stuck out as a memorable youtube educator. I've subscribed and I look forward to learning more from you.
Now THIS is the kind of tutorial i need, ive had enough of people just telling me what to put in to get my desired output, and i need that perfect level between talked to like a baby, and expecting im Einstein. You hit that nail right on the head.
Very impressed, you've covered many of the pitfalls. Just two remark: Fixed Update is useful to avoid costly exponent which are very common in Physics calculation because if you have a constant delta time then the linear approximation is good enough (so the "bad" lerp in a FixedUpdate would work just fine). The big drawback with FixedUpdate is that you'll usually notice "jerking" as one frame you'll update 3 times, but then the next frame only 1, then the next 2. Usually to fix this you need to extrapolate the difference between the current frame's deltatime and the FixedDeltaTime.
Or avoid FixedUpdate() altogether and call Physics.Simulate() by yourself in Update() after disabling automatic PhysX Update. Actually the only method I know to avoid Unity's microstuttering.
I don't code, but I am a physics nerd and saw delta time and it peaked my interest. Was not disappointed to see the explanations of calculating changes in distance as a function of time when not accelerating, when accelerating, and with a changing acceleration value. With the questions that were math based and not definition based other then syntax i am happy to say I got the idea right lol.
For those confused about the lerp section, I have a really easy way to think about it intuitively: If your "lerpSpeed" is 1, then the base of the exponent (the number on the bottom) is the portion of the distance you want to cover in one second. So in the video this number is 0.5 which means the character covers 1/2 the distance to the goal every second. The reason this works is because when you do this multiple times in a row, the distance decreases exponentially. So, if you imagine your frame rate is 4 frames per second, then in the first frame the character covers 0.5 ^ 0.25 of the distance (because deltaTime is 0.25), and the next frame the distance will be less but they will still cover another 0.5 ^ 0.25 of _that_ distance. So the total distance covered will be (0.5 ^ 0.25)(0.5 ^ 0.25), which if you remember your exponent rules is equal to 0.5 ^ 0.5. In other words when you exponentiate like this, the deltaTime in the exponent adds linearly every time you lerp. In this example, if you lerp every frame for one second (that is 4 frames) then the exponent adds up to 0.5 ^ 1. In other words, you cover half the distance in one second, regardless of your deltaTime, as I stated in the beginning. EDIT: as explained in the replies, the base of the exponent actually represents the portion _remaining_ after 1 second, not the portion covered after 1 second, because you start at t = 0 which would give a blend value of 1, so we use 1 - 0.5^t instead (or Jonas puts the current position in the second parameter of lerp, which is equivalent)
Just want to point something out here, cause this kinda bothered me. You are correct in that the reason for the deltaTime being in the exponent is so that they add to 1, but the total distance covered is NOT just the product of the blends. You can easily see this if you use a base other than 0.5. Assuming you have the function laid out like Jonas did, where the target position occurs when the blend is 0, then the position of the snail after n frames is going to be (target_position)(1 - (product of all the blends)). You can deduce this through induction with the lerp function. Lets say that our blend is 0.1 ^ 0.25, where the 0.25 is our deltaTime, just like in your example. Initially, the snail's position is 0. After 4 frames, or 1 second, the snail's position will be (target_position)(1 - (0.1 ^ 0.25) ^ 4) = (target_position)(1 - 0.1) = 0.9(target_position). After 4 frames, the snail moves 90% of the distance, not 10% as you implied. Fundamentally, what you're saying is helpful, but I saw the comment and got caught up on that snag for a while, and it kept me from truly understanding what was going on. Also, I agree with @NXTangl, using the built in exponential function is nice because then you don't have that arbitrary base and the speed is more directly controlled by lerpSpeed.
> So in the video this number (lerpspeed) is 0.5 which means the character covers 1/2 the distance to the goal every second No, in the video you cover 0.3 of the distance every second because of that number (lerpspeed) being 0.5.
@@feha92 No, "this number" refers to the base of the exponent, which is 0.5 in the video. I also say that I'm setting lerpSpeed to 1 for simplicity. lerpSpeed is also 1 in the video IIRC, so I'm not sure how you mixed that up. Edit: actually, lerpSpeed is 0.5 in the video, so it makes sense you got mixed up. But I still said "if lerpSpeed is 1".
@@pixelz3040 You're right, the base of the exponent is the portion _remaining_ after one second, not the portion covered. Those two numbers just happen to be the same when the base is 0.5, my bad. I personally still like to use the arbitrary base because the meaning of the base is clear when the exponent is 1, and I don't want to think about a base of 1 / 2.718. lerpSpeed controls the speed the same way in either case.
I'm going to contest question 2 based on the wording. The presentation of a frame can be conceptualized as happening at specific instant of time, but the game logic of a frame takes meaningful time to happen. If I just see phrases like "the current frame" and "the last frame" in reference to timing and without further indication, I will interpret that as referring to those spans of time. In the context of timing, frames have a start and an end, and that end is before the frame's presentation. Since each operation can be conceptualized as contributing to a specific frame, the end of a frame is the same as the start of the next. You don't know when the current frame will finish or when it will present, but you do know when it started. A game engine is going to use the most recent frame-time estimate it can, and that would be the time between the start of the current frame and the start of the previous frame. This is more consistent with the wording of option B than the wording of option A, and it is consistent with the wording in the Unity script reference for Time.deltaTime: "The interval in seconds from the last frame to the current one"
Way back before I even knew about delta time I used to have my games code run at 120fps and didn't noticed any weird behaviour, but as soon as other players with 60hz displays played the game everything was in slow motion running at half the speed, they often commented the game feels slow and me and my friend playing at 120 allways wondered what do they mean until I realised this issue.
For anyone interested in learning more about numerical integration, there's a whole range of other schemes you can apply which have different stability properties based on the deltaTime and the equations of motion of the players. Here at 8:22, if I can recall properly, he first uses Euler Forward then Euler Backward and after that, Crank-Nicolson. If you had a more complicated movement, you could as well switch to a spicier scheme (like Runge-Kutta) but it's propably over-engineering the task you're trying to achieve.
True, although this makes the difference between explicit (forward Euler) and implicit methods (backward E, C-N) appear very similar, since there is only a time dependence here. Normally you will need to solve a system of equations, which makes the thing inherently stable. A good example is the exponential speed case, where an explicit method can easily overshoot.
3:48 This could actually be A or B depending on your definitions. I picked B, because it's the time between when the current frame started being processed and when the previous frame started being processed. If your definition for the time of a frame is when it is done processing, then A is the correct answer. I view the start of the frame as the true time, since that is also when inputs are registered, so the actual frame that is being displayed is slightly behind, not the other way around.
Just to add on to your comment, the video is wrong here as per reasonable definitions. The term 'current frame' always refers to the one you're currently processing. 'deltaTime' is calculated at the start of the processing of the current frame by comparing the time to the time the previous frame began processing. deltaTime is essentially how long the last frame took to process from start to end (where 'end' is the start of the current frame). "Time elapsed between the last frame and the one preceeding it" is a not a good definition of deltaTime because the frame before the last one has no relevance. The current frame's deltaTime value is calculated in the current frame and not at the end of the previous one. As per Unity's own documentation for Time.deltaTime it says it's "The interval in seconds from the last frame to the current one". I believe the error is largely due to representing frames as a point in a timeline when something is rendered on the screen. At some time, typically very shortly after that rendered frame point on the timeline, the deltaTime value will be calculated. The only relevant frames in the calculation is the previous frame and the current frame. Carrying on from this the video then describes deltaTime having a "1 frame delay" which is also stated and described confusingly. Obviously deltaTime is not going to be related to how slow the current frame is because it can't predict the future. So the best value it actually could be: the previous frame's calculation time, is essentially what it actually is. Describing that as a "1 frame delay" doesn't really make sense. Obviously here the video is referring to deltaTime in relation to something moving on screen and pointing to how the object moves only a little bit on screen on the frame that took a long time and then has the larger jump on the next frame. Saying that "deltaTime always has a 1 frame delay" because of this particular example is not reasonable. deltaTime is not delayed, it is the correct value for when it was calculated. Nothing prevents a programmer from calculating their own deltaTime equivalent value and moving objects with that right before rendering. Time.deltaTime is not delayed, you have just chosen to use it in a way that gives a result that you refer to as having a delay. If anyone was confused by the 1 frame delay part of the video and curious, the way the deltaTime value would work after a slow frame is is: If a game was running at 60FPS on Frame A, Frame B's deltaTime would be ~0.0166s. That's how long it was from the start of Frame A to the start of Frame B. If Frame B was then slow and took 0.1s (10FPS) to complete, Frame C's deltaTime value would be 0.1s Basically the frame after the slow frame would see the larger deltaTime value. Not a bad video otherwise, but that section in particular I think would be very confusing to programmers trying to learn about deltaTime. I believe conceptually it's essentially correct, but by representing frames in relation to deltaTime in that way and slightly misrepresenting when deltaTime is calculated it makes something fairly simple much more confusing.
And I just want to say that I don't like leaving some big comment like that, I just needed to write that much to explain everything. Obviously Jonas seems to be great at what he does and has made an excellent video. I know I'd hate making videos like this because it'd be very had to not make errors or poorly represent some things even if you know them well yourself in reality. I'd not want to have to see comments like mine above, but know that it's only left in the interest of helping clarify those elements from the video for anyone confused or off-put by them. I'm sure you (Jonas) understand what I've explained yourself and just (in my opinion) didn't express them adequately in that small part of the video.
@@mcarr87 Your comment is far more confusing than the video is. There are a few reasons for this. Firstly, there are two entirely contradictory definitions of a "current frame" at play here, which you don't seem to realise. On their own, both definitions are valid, but the one you present here has some issues in its broader context. You seem to define a "frame" as the routine that runs to produce it. In that sense, the current frame is indeed the one you're processing. But then a frame is a process and not a point in time. This contradicts with the definition of deltaTime in the Unity documentation you quoted, "The interval in seconds from the last frame to the current one". That one notably _does_ define a "frame" as being a point in time, as evidenced by it not saying "from the _start_ of the last frame". One important problem with your definition is that updating the game state is not linked to visuals whatsoever. A game could poll for inputs twice as often as it renders a new frame. These are still two game updates, but there is only one frame rendered. If you define a frame as a process, you'd have to exclude the time spent updating the game state, and only include the rendering time. But that's demonstrably not the value that deltaTime contains. The other definition of a frame is "the image being shown on the screen". This is a far more intuitive definition, and how most people understand such terms as "fps". There are 60 images being shown to me per second. And whatever is being shown to me at any given time, is the "current" frame. This frame is shown to me all at once and does not change afterwards until the next frame arrives. Thus, the moment it appears on my screen is a single point in time and not a process. Reading the definition of deltaTime again, this makes a lot more sense. Because the "current frame" is what you just finished. And deltaTime is indeed the space between those points in time by all definitions. You say that the way this definition is worded in the video is inaccurate, but that is simply not true. "Time elapsed between the last frame and the one preceding it" is a perfectly valid way of describing it, so long as you take "last" to mean "most recent" over "previous". The current frame is the most recent frame, and therefore the current frame can also be described as the last frame. This is not a strange way to use English, and should not be confusing for someone who speaks the language well enough to watch English videos on UA-cam and writes English comments. Additionally, I strongly disagree with that a "1 frame delay" is a bad way to describe what happens. Of course, the variable itself isn't delayed. Because it's defined with that delay already built-in. If I told you what I ate yesterday, my statement isn't delayed by one day. But that doesn't mean that your knowledge of what I ate isn't! The latter is the "delay" the video refers to. The example is clear about this as well: the frame shown after the lagspike does not take the lagspike into account exactly because that frame is being calculated as if it will render in the same amount of time that the last frame did. Regardless of what you're actually building, it is theoretically impossible to react within 1 frame to the time it takes to render just by reading the deltaTime variable. In short, it takes exactly one frame before you can react to how long a frame takes to render. I'd like to ask what you would describe this effect as, if not a "1 frame delay." This description has nothing to do with motion; it's a factual description of what you observe when you look at the game frame by frame. It takes one frame to adjust to a frame taking longer to render. You cannot adjust immediately. This is the definition of a delay. Don't get me wrong, I agree that there are ways in which the video could have been clearer. I just don't think that the things you take issue with are the problem, and that the alternatives you provide make things less clear rather than more clear. What the video really needed is not a change in definitions, but a more precise and consistent use of language. "Last" and "current" typically have the same meaning, but it'd be clearer if you stuck to one. It'd also be helpful to distinguish a "frame" as what's being shown, from an "update" as being the process to create it. And possibly a few other similar things. The content and presentation itself is fine and doesn't need to be changed, the script for the video really just needed one more editing pass.
@@Gamesaucer I appreciate your arguments and while I don't disagree that much of this depends on your particular definition, I don't agree that in this context of programming the definition of 'current frame' would only refer to the frame most recently output to the GPU. While not used too commonly as a direct term in the Unity docs and variables, you'll only find "current frame" referring to the one currently being processed that would next render (e.g. OnDemandRendering.willCurrentFrameRender) unless referencing something selected in a timeline like in the Profiler. Also I was directly referring to where the video's uses the phrase "the frame currently being processed". I 100% agree that a frame can and often does refer simply to the image presented to the screen, and the duration of that image on the screen in a standard, single buffered game would be determined by how long the following frame takes to update and render. That's not in question. But you bring up a great point that I didn't bother with because I'd already written too much before, and that is how a game could have multiple Updates without rendering a frame if it wanted. Alternatively you could have things like double or triple buffering that could delay the rendering of a frame until after other queued frames had rendered. To me, both of these are great arguments for my point. First, going off your concept, lets say you're in Unity with a disabled Camera object and you manually called Render() every 3rd frame. Here you have 3 Updates over 3 frames (as per Unity's definition of a frame. See e.g.: "Update[()] is called every frame") where only 1 of them is something drawn to the screen. You also have 3 different deltaTime values across those frames, 2 of which can't be said to have any relevance to what was drawn on screen last. You could also run your game's multiplayer server without rendering anything ever and it still has deltaTime and what most refer to as a frame rate (including Profilers, etc). You could argue that without rendering anything there is no 'frame rate' if you wanted, but that only diminishes your arguments because deltaTime still exists and is still calculated in the way I said it was without any relevance to what was drawn or if anything was drawn at all. The same type of example can be given for multiple buffering of frames where the deltaTime does not relate to what was last drawn on screen. I don't think in the context of programming your point "the moment it appears on my screen is a single point in time and not a process" has much validity. For one, saying a frame is a point in time doesn't really relate to the concept being discussed which is to do with the duration of a frame. Secondly even if you were to try to talk about it as a singular moment in time, what moment is that? When the LCD monitor draws the first line or the CRT's electron gun starts emitting or when the end of the image is finally displayed? What if the frame rate is faster than the monitor and it never finishes? I know that's overly pedantic, but it's just to illustrate that that is not a consistent or really even well definable thing and doesn't actually relate to actual programming and deltaTime. I don't really want to continue, but I'll quickly address your points on "1 frame delay" which I also find a bit odd. Saying what you ate yesterday is completely different from deltaTime. When deltaTime is calculated by Unity when a new frame begins processing, that is not a value telling you about something from the past. That is an immediate, current time difference between right now and back then. If it's referred to on the next line it's extremely current and relevant. You could say it's less 'current' later in the frame processing, but that depends entirely on how it's used. This is why I mentioned how you could use your own delta time calculation for rendering if you really wanted something more current for the frame you're processing than deltaTime. To say it has a delay is to proscribe a very weird definition to it. It is what it says it is and it does not give a delayed value at any point after its value is set. It's always 100% accurate as per what it is defined as being the value of. You know immediately at the start of processing a frame what the time the last frame took, there's no delay. That's the point of the value. To say it has a delay would be to give it the definition of "this is how long this frame will take, but you won't know until next frame because it has a 1 frame delay". I feel like this sort of discussion comes across as antagonistic and I apologise if it comes across that way. I also expect this could be one of those things where it's an ongoing back and forth, but I don't want to do that. I will freely admit that there's validity to the video's way of putting it and taken with certain definitions it's not wrong. This is what I said in my original post. I just don't believe in the context of programming, which this is, it was stated in the most valid and coherent way.
Thanks for the Lerp fix! This is something I pretty much gave up on after I realized the solution would be a easy to mess up, and almost completely just changed to using spring-damp systems, though partially because they're also often just better. Though I'd say that the "simple" solution to calculating per-frame movement deltas is not ok 9/10 time but probably closer to 99/99.9% of the time. I've never actually brushed against it but have had a lot of pain due to different update rates simply ending up with different results, and inconsistent amounts of FixedUpdates causing frame pacing issues. For the Xbox One port of Thief of Thief for example, I ended up doing a hack that connects Update and FixedUpdate rates as long as they don't want to be too far from each other and managed to remove almost all frame pacing issues (which were bad otherwise) from the game. I've had to do this only once, but I had a sprint-joint system smoothly controlling the camera in Among The Trolls. If the framerate got REALLY bad, the system went completely out of whack. So for that I implemented custom sub-stepping where the calculation was always calculated with an almost non-changing deltatime but just repeated enough times during a frame if the framerate was bad. This is how FixedUpdate also works in essence, but with FixedUpdate this can cause those cursed problems where the frames get longer because FixedUpdate is called more, if FixedUpdate gets even slightly expensive. Closest solution I have to syncing 2 clients with different frame times (in absolute time) was a server-time synchronized RPC where, I decided to trigger the event on the slower-updating client even if the trigger time wasn't yet reached as long as if the estimated time of the next frame would be even more off. Of course this also used the last frame's frametime though but made some events seem almost magically in-sync as long as I could schedule the event far enough in the past (like 300ms).
You actually do want to multiply by fixedDeltaTime in FixedUpdate a lot of the time, to ensure that your speeds are in units per second and the numbers in the inspector actually have meaning. It's also needed for more advanced custom physics, used in the integrations.
2:20 Well, arguably, Betty has the advantage here, because as she and Jerry go really far distances, Jerry is changing his x position by a very small number, which gets essentially zeroed out as he loses precision, meanwhile, Betty can keep going for a bit longer, since she is adding a bigger number to her x position, thus precision takes longer to catch up with her.
It is called FixedUpdate, but that doesn't mean it is actually 100% fixed. It tries to run in fixed intervals. However this will never be exactly right, either because of cpu cycles or if a fixed update exceeds its time budget. This will most likely be insignificant in most cases, but there is still a reason to use fixedDeltaTime for this. For example if you run physics in this fixed update and it always takes just a tiny bit longer than expected, the error can add up over time and without fixedDeltaTime it might explode your physics.
I'm glad you pointed out the issues with update and fixed update, The thing is, some things need to be calculated before you should continue, in which case, fixed update is the answer, however those need to be lightweight because you need them for function quickly, in some games the physics may not need high accuracy, in which case, it's fine for them to happen whenever. However games that are heavily reliant on the physics (like an FPS) you really need those collisions calculated before continuing.
The reason why fixedDeltaTime exists, is that you'll be able to change the rate of fixed updates per second. By default unity uses 50hz, but you might wanna increase or decrease this value depending on your project. If you don't multiply your values by the delta, changing the rate in [Edit > Settings > Time > Fixed Timestep] will result in the physics running faster or slower than intended.
yep absolutely, once was having issues with the precision of physics collisions in a project I was working on so I had to bump up the fixed update rate to help solve it. I use fixedDeltaTime in my workflow for exactly cases like that, I might have had to rewrite weeks of code otherwise
Using deltaTime in FixedUpdates still makes a lot of sense, since you often want to keep your velocity as meters/second rather than meters/(fixed update interval)
I think this is a great subject and something that many lack a good understanding of, but in my opinion this video too shows a lack of understanding of deltaTime. My biggest problem with this video's explanation of deltaTime arises in the explanation of why alternative b) is wrong in the first question (around 4:18). This video seems to present the idea that a frame should represent what the state of the program is when the frame is presented, while in reality, a frame represents what the state of the program was when the frame's update function began (when deltaTime was measured, to be precise). This means we're not using "the last frame's deltaTime as an approximation for the current one's," we are instead rightfully using deltaTime as the time between the last update call and the current one, because that gives us the state of the program at the time of updating. This also means that deltaTime does not "always have a 1 frame delay" (5:34) as an explanation for why lag spikes are 1 frame off. Instead, the state of the program that a frame is presenting is always at a 1 frame delay from the current state of the program. There is no special feature of deltaTime making it 1 frame behind. Furthermore, in any well-designed double-buffer renderer, the previous frame should be drawn on the gpu while the current frame is updating on the cpu. Once updating has completed, the previous frame is presented as the current frame, making the presented frame TWO frames behind the current state of the program. (+1 for every additional frame buffer) Other than that, I think this video explains things well and was fun to watch. A quick point to make is that for the explanation of the last question, the idea is presented that an exponential function is essential to achieve the desired result, while any function beginning at 0 and approaching 1 would work, such as 1 - 1/(1 + deltaTime * lerpSpeed), removing the need of Math.Pow. I guess I'll come across as another know-it-all, but I just wanted to share my understanding of the topic and I'll be happy to discuss it further!
@@magnusm4 multiplayer you can't just use deltatime for each pc because everything needs to be synced. So you need a main computer (which could be a player too) that does the calculations, and the players' pcs need to display that information. But frames can't be involved in the calculations of the variables, otherwise things would move really weirdly. You need the numbers sent to the pcs, and the pcs to render that information using deltatime, because you need to get the correct number for that point of time based on when the individual player's frame renders. And the rendering calculations are gonna need to be precise otherwise objects are going to appear in the wrong spot because if the calculation is off the number on the server is still correct, but it's displayed incorrectly on the player pc.
A. I mean, it's pretty simple. The first thing you learn about deltaTime is what it is (but I know that lots of people just rush things up to make games quicker). The rest of the reasoning flows from that
As a Godot user, I love that this just explains the concepts. Doesn't matter what the engine is! I felt I kinda knew all this, but it's presented so well I feel I learned something anyway.
Yeah, thankfully stuff like this is pretty engine agnostic. Once you know how one engine works, a lot of it is easy to carry over to others, at least from a technical perspective.
19:50 I generally find it better to just use deltaTime alone as the exponent rather than multiplying by a lerp speed. This way you can adjust the 0.5 to whatever ratio you want the lerp to reach each second.
i dont think this has to do anything with coding. more like high school physics and how delta time on game engines work with a very very simple explanation.
@@Fix-- Why did you get scared away? If you didn't understand anything, I want to say that it's completely normal for a newbie to not understand like 70% of the video. To be able to take something from this video, you need to have basic knowledge of C# (at least be able to write a quadratic equation solver), basic knowledge of Unity (at least what GameObject is, what MonoBehaviour class and its methods are and a rough idea of how physics work in Unity), a good school level math and some calculus knowledge. Besides, you have to have tried to make a character move to encounter the problems Jonas is talking about.
My go-to example of why you might need integrals to handle varying delta intervals is: - Imagine you have a simple homing missile/enemy tracking the player. - It travels at a constant speed but can adjust its heading by up to 180 degrees per second. - At a stable 60fps, that means 3 degrees per engine tick; at 30fps, 6 degrees per tick. - What if there's a sudden lag spike and the next tick has a delta of, say, just 3fps? If you updated its movement simply as (adjust heading) then (increment position) this lag spike enables the projectile to change its heading by _60 degrees in a single tick_ which (under certain edge cases) can allow it to successfully target the player in a position that would (under normal conditions) be slightly outside its defined turning rate.
Wow, I'm honestly quite impressed by the quality of this video. It's very entertaining and informative at the same time, I hope you do more videos like this ;)
Interesting. My biggest takeaways were • The 1 frame delay • Splitting up speed calculation on two steps (before and after applying movement) for better accuracy • Exponential formula in lerp (I'm actually still confused why it can reach the destination with that method - and my way would be to add some IF-statement when close and snap it into final position) Edit: interesting use of lerp too as stands for linear interpolation, but because he changes the "start position" each frame it does not become linear anymore. I guess it's still legit!
I have been developing games since the 1980s and have built several game engines from scratch. So I didn't really learn anything today, but I think that Jonas did an excellent job of explaining the concept. Keep up the good work!
My solution to deltatime inconsistencies was always "just make sure the game runs at full framerate even on potato computers lmao" but even so, looks like I still have a lot of things to check for and improve in my code when one of the games I'm making is about all about speed and precision with the physics engine. I know someone will try to run the game on a computer that's probably weaker than my already 10 year old test machine, and they'll be counting on it.
Jokes on *you*! You multiplied your grade by a number almost certainly less than one! Your grade was lowered to a fraction of what it would've been! Unless you run with less than 1 FPS in which case the joke would again be on Jonas...
Awesome videos Jonas! Keep up the great work. Nice to see other people loving Unity. It seems you got something slightly wrong (semantics-wise). You see according to the Unity docs (and tests I did) Time.deltaTime is "The interval in seconds from the last frame to the CURRENT one" and you also agree to this schematically on the 4:16 point where the black dot shows our point and 0.14s frame is indeed the last. To make a long story short, the correct answer is the time it took from the last frame start, to this frame's start which I think is stated in a cleaner way.
You think I'm using delta time incorrectly? Well jokes on you, I'm not using it at all. If the game lags, everything goes in slow motion and a pop up appears to insult the player's setup
6:05 Objection! The developer may want to change the physics framerate in the future. If you do not account for dt, you'll have a lot of fires to put out every time you change the physics timestep (which some assets actually require). Time.deltaTime will automatically return Time.fixedDeltaTime in FixedUpdate.
when your use the lerp function your supposed to have a "linear" speed without acceleration because it's a Linear intERPolation, if it looks exponential it's because you change each frame the beginning position (parameter a) so : pos = lerp(pos_begin, pos_end, t) Great video though !!
So, is the reason the lerp was looking exponential causes by the fact he use transform.Position, which got the current position, instead of the start position which never changes, so it should be a constant, somewhere outside the update function?
These visuals were insanely good. I didn't expect the answer for the linear acceleration, splitting it up like that. But it makes sense with the graphs!
There is actually another layer of complexity here, which even experienced games developers often miss: regardless of how much time has passed between your consecutive update calls, the monitor typically can only present images spaced at a fixed interval from each other - the refresh rate of the monitor. The only exception here would be if you are using a variable-refresh monitor with a GSync or FreeSync technology. If you are updating your game with variable deltaTimes, but presenting those frames on the screen at a fixed rate, you will create what we call "microstuttering". The animation will overall keep correct pace with the wall clock, but it will appear jerky, unsmooth. Unless you are using GSync, you should only ever update your game in increments that are a multiple of the monitor refresh rate and then tell the rendering system to present these frames at the correct time in the future - if you are updating the game for X milliseconds, then the frame you've generated should be presented exactly X milliseconds from when the previous frame was presented. This technique is callled "frame pacing" and fixes microstuttering. Note that modern game-engines like Unity and Unreal might automate frame-pacing for you behind the scenes, by feeding you deltaTimes and presenting the frames as appropriate (support might also depend on the platform you are shipping the game on).
If your engine is developed properly, DeltaTime should be tied directly to the update of a frame. Most modern engines (Unreal Engine, Unity, and most AAA Engines) tie DeltaTime directly to the update of every frame. This by definition means that each tick is tied to the update of a frame. In the scenario you presented this is not what happens. If your actual frame update is not in sync with your refresh rate on your monitor, you'll typically see frame tearing (since almost all engines will queue at least a frame in advance in the back buffer and update the screen on each refresh). Screen tearing happens since the new frame that was in the process of rendering in the back buffer is being pushed to the screen in an incomplete state. Microstuttering really happens when you're close to the target refresh rate. Since there's some variability in each frames workload (both on the CPU and GPU), frame completion may not fall exactly on the expected interval to update (ie 1 frame may have taken 17ms rather than 16.5ms to complete rendering). In order to avoid this, a lot of devs will try to exceed performance from the target enough to minimize Microstuttering. It has nothing to do with updating your game with variable DeltaTimes. It has more to do with frame consistency.
If I'm understanding this properly, you're talking about the need for vertical synchronization or VSync, right? I'm pretty sure you can actually toggle it on or off in the project settings in Unity, and I assume the frame pacing will be taken into account when calculating deltaTime. I do believe it should be the engine's job to get that working properly, you shouldn't carry that burden during the game programming phase.
When I first started physics programming about 15 years ago I found fixed step with accumulation and display interpolation is the way to go. It always surprises me that variable step is still a thing, but I guess it's just faster if accuracy isn't needed.
Agreed. As far as I can understand, it's stems from wanting to ship a game to a multitude of pcs with vastly different specs, and then wanting the game speed to be equal on those machines in wall time. If you look at nintendo games tho, they use fixed step, and if the game lags, the game simply runs slower, no sudden movement jumps to try to stick to wall time. I like keeping the simulation time and wall time as different.
I highly appreciate the math explanations. Calculus is an important topic that can be learned as early as high school, maybe earlier if you have the perfect teacher, and solutions to game development like this are why learning advanced math is important.
The sad thing is that teachers make a terrible case for learning calculus, algebra, and geometry, usually throwing only rocket science as an example. I went through the classes just fine but never understood why I should learn the material and could never discover a legit use case for it. That is until dealing with graphics and games, at which point I heavily regretted forgetting most of what I had learned.
I'm with you, but schools don't seem to have an interest in teaching "real" math. It's all just about calculating numbers, like robots. Studying physics was an absolute eye opener for me. There I got taught math on a more fundamental level, which really made it click. I'm still wondering why they don't teach axiomatic systems, logic and set theory in schools and let the students be creative for once. The basics actually aren't that hard. After having achieved some knowledge of those topics, calculating stuff, even derivatives and integrals, which are the highest level topics in schools, becomes piss easy.
This video was recommended to me at 1AM in bed, stayed glued to my phone screen all of the time and still understood everything. World-class explanation. Subscribed
During the part on acceleration, you can use the equations of motion to get: transfrom.position += Vector.right*speed*dt+Vector.right*acceleration*dt*dt/2; speed += acceleration*dt; You should get the same result but in a "physically correct" manner. In the end it reduces to the same result, but it could still be useful.
Correct me if I'm wrong, but the first method (which is the same as you provide) is called the forward Euler method, which tends to artificially adds energy to the system the further it goes. Updating speed before position (the sympletic/semi-implicit Euler method) or adding half before and after (the midpoint method, which equates to 0.5 because he is using a linear function) tends to be more stable (the error is bounded)
To be clear: It's not just the same result but it's also the same mathematical formula, except not applied with intermediate state (only modify speed once). It's easier to see if you simplify the formula to: transform.position += Vector.right * dt * (speed + acceleration * dt/2); speed += acceleration * dt; And then pulling out the acceleration term to apply to speed makes looks like Jonas' code: var boost = acceleration * dt/2; speed += boost; transform.position += Vector.right * dt * speed; speed += boost;
@@mrnowhere-sc3mvFor anyone who wants to go deeper on this math, "Math for Game Programmers: Building a Better Jump" goes into Euler integration, Velocity Verlet, and concludes simplified Verlet (the same result we have here) is a good compromise: ua-cam.com/video/hG9SzQxaCm8/v-deo.html
19:27 I had as a solution: float elapsedTime; void Update() { elapsedTime += Time.deltaTime * someMul; transform.position = Mathf.Lerp(startPos, target, 1 - 1 / elapsedTime); } I was hela confused when you presented your solution, but then saw you used transform.position instead of startPos. It would work if the startPos is set, but your solution doesn't need that and is therefore still better Edit: Looking back I see the issue that you should probably split the Time.deltaTime-adding in 2 halfs
Very good!!! I'm glad it's getting easier and easier to teach people about the acceleration gotcha. I'm always sad when I play a precision platformer and some of the jumps are impossible unless I limit the game to 60fps. I got 160 points!
Hey you seem to understand this. can you explain why he used .5f as if it means half? isn't that hexadecimal for 95? isn't he trying to get half the acceleration for the first part of the frame and half the acceleration for the second half of the frame? if that's the case why didn't he actually just use .5? And if he wasn't trying to get half, doesn't that mean the snails would've accelerated quicker than they were when it was just one line? was the point not to get them to move the same speed but split the acceleration addition up so that it would get an average of the frame start and the frame end acceleration? to be clear, i need no explanation of delta, i understand how it works. I just don't get this bit. about splitting the acceleration into two. i get why he does it, cuz i understand why you wouldn't want the acceleration from before nor the after, but rather the midpoint of the two, i just don't understand how multiplying by .5f gets that, unless .5f is in fact just .5, but it seems like it's hexadecimal for 95 edit: oh my god, i was right the whole time it is just 1/2. 0.5f is unity notation for floats. that was so confusing as someone who uses godot. correct me if i'm wrong
I've only used DeltaTime in some bad game tutorials but still got one question half right and the rest all right, but I learnd much watching this video. So thank you!
Great to know that I have using Time.deltaTime correctly all along, except for my lerps... That explains why my character sometimes teleports around. Good video, now I got to dig through my code and fix my mistakes.
Great video! However, wouldn't 19:49 still be wrong though since you are just using the deltatime for each frame and not a sum of all previous deltatimes?
0:30 Ok, Ok, I got the pan and the notepad++, I'll pass ur test. 1. float NumberOfTicksPassed = DeltaTime / GameTickTime; position.x += SpeedPerTick * NumberOfTicksPassed; Gonna be same speed no matter the rendering frames per second or game tick update rate(Hz). 2. B).
Loved this, a lot to chew on even for more experienced game devs! Just one extra thing, in 15:35 isn't there also a potential error where the jump input is checked after running movement code, introducing an extra frame of delay when a user wishes to jump?
Funnily enough the case where you do a half step before and after is a better approximation in any case, as that corresponds to the midpoint RK2 method. What also works for that case, and is also a valid RK2 method, is computing the average of both the speed at the start of the step and at the end of the step. And of course there's even fancier methods like RK4: (I will refer to the speed at the start as v0 for clarity) Make one step with 1/2*deltaTime, store the speed resulting from that step in v1 Make one step from the starting position with v1, also 1/2*deltaTime, store the speed after that step as v2. Then do one step, again from the start, this time with full deltaTime, using v2 and store the speed after that step as v3. Now take a weighted average of 1/6 * v0 + 1/3 * v1 + 1/3 * v2 + 1/6* v3, lets call this result v, and then using this final v do the last step, yes, again from the start, with deltaTime. The resulting position will be your now even better approximation! Is this horribly overkill for most games? Of course! But I'd be remiss not to mention it. :P
I dont think your right with the assumption that deltaTime lags behind 1 frame. Unity docs also state, that it's "The interval in seconds from the last frame to the current one". So it's basically the time since last frame to the start of calculation of the current frame. I briefly tested by logging Time.deltaTime ,Time.time and Time.frameCount. If you press Play in "Paused" mode you can see for the first frame the deltaTime is 0 but for the second frame you will get the correct deltaTime. If the deltaTime would be delayed by 1 frame you should see 0 for the first two frames. As there is nothing to compare against. Interestingly Unity seems to be buggy in regards to the deltaTime. If you don't start with Pause enabled, you somehow get a deltaTime > 0 in the first frame. Also if you do start in Paused Mode but disable it after stepping a few frames. You will somehow get a deltaTime of 0 at the frame you disabled paused mode ¯\_(ツ)_/¯
I think this is an ambiguity with the phrase "current frame". In the video, he means the frame that hasn't been displayed yet, and the "start" of that frame is when it is displayed. But most game developers think about the "start" of the "current frame" as when the previous frame ended and the frame is displayed at the "end" of the frame rather than the "start".
This is just what I needed. Yesterday I realized that the most watched unity recoil tutorial had major mathematical errors and this perfectly summarizes how to avoid them. Thank you
This was truly such a treat to watch! As an experienced game developer myself, I am definitely sharing this with aspiring and junior devs around me as this is such an informative and fun way to understand the use of deltaTime. Big ups and don't mind making more of these videos! 😉
Using the mid point to calculate the average on an exponential function should be sufficiently accurate unless your frame time is extremely large. I do it for IRL ballistics calculations with an assumed time interval
Awesome video! Some time ago I made myself a helper function for the framerate-independent lerping function: public static float SmoothLerpFactor(float smoothing, float deltaTime, bool fractional = false, float minFractionPerSecond = 0, float maxFractionPerSecond = float.PositiveInfinity) { float smoothingClamped = Mathf.Clamp01(smoothing); //Mapping a [0, 1] range smoothing rate into a (0, infinity) exponential decay rate, //so that 0 becomes infinity and 1 becomes 0. float decayRate = smoothingClamped == 0 ? float.PositiveInfinity : (fractional ? Mathf.Log(1 / smoothingClamped) : 1 / smoothingClamped - 1); float lerpFactor = 1 - Mathf.Exp(-decayRate * deltaTime); if (deltaTime != 0) { //We ignore min and max speed if game is paused (in which case deltaTime = 0) lerpFactor = Mathf.Clamp(lerpFactor, minFractionPerSecond * deltaTime, maxFractionPerSecond * deltaTime); } return lerpFactor; } It is used for example like this: //Framerate-independent smoothdamping, this object's rotation follows another object's rotation smoothly: transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, SmoothLerpFactor(smoothing, Time.deltaTime)); The benefit to me is that the "smoothing" argument is between 0 and 1, and its intuition is that 0 = no smoothing, reach target instantly, and 1 = infinite smoothing, AKA never moving. If you put the "fractional" argument to true, then "smoothing" will literally mean that (one minus) the fraction you want the object to reach after one second. So for example with "fractional" true, putting 0.5 to "smoothing" means that you want the object to move half of the remaining distance per second. Otherwise, the smoothing used is based on the exponential function with base e. The benefit of "fractional" = false is that if you use a slider for "smoothing" parameter in the inspector betwen 0 and 1, the values you're working with are more human. With "fractional" = false, setting "smoothing" to 0.01 can be the same as setting "smoothing" to 10e-12 with "fractional" as true, which is a hard value to work with in the inspector slider, and is more prone to floating-point approximation errors.
Thank you ! currently developing my first game now, and want speedrunning as a focus. So I'm always scared of having inconsistent results. I mostly do FixedUpdate stuff tho. Rb char controller. But anyone know any other areas I should look out for or ways to test this easy ? the lag spike was a neat trick. Edit: oh no, im actually doing all the speed calculation in Update, time to refactor some stuff... haha
Stumbled onto this video. The information is clear, the illustrations are all over, it's funny and witty, and has thought me something while maintaining my attention. I've been a dev for sometime but this video has by far explained this topic better than any other. You have gained a sub from me! Can't wait to check out your other content!
I disagree with your description of deltaTime, it's not the time between the last frame and the frame before that. It is the time elapsed between the START of the current frame and the START of the last frame. In most cases these mean the same thing, but it's usually implemented as I describe.
@@JonasTyroller Yeah you just worded it unintuitively. B could be interpreted as correct because you always set the current time at the start of a frame i.e. the frame that is being processed and the last time at the end (which becomes the start of the previous frame when the next frame starts).
I was just watching this video, thinking I knew most of this stuff (and I did, perks of my CS/Math degree) but still learned a lot nonetheless. I'm not surprised to learn that deltaTime is from the last frames, but never really thought about that much. Then at the end I noticed you're the developer of Thronefall and I got a bit envious I won't lie 😂 Oh and great video, I always love learning new things and cementing prior knowledge!
Coming from only knowing the maths and modelling side (basically just the engineering modelling stuff) and next to nothing about the game development side this is super useful - especially the intricacies of how an uneven interval can introduce issues and so on
Subscribed, i really like your fun way of explaining things Most people try this and imo wind up compromising the quality of the video/explanation/etc but not here, this was great!
I always liked the fixed update per second model more. It is actually deterministic and it is a lot simpler to write and less bug prone. Yes it will make the game run in slow motion if you are unable to achieve the TPS but also if you can not run quickly enough with delta time, you will get large deltas and possibly break the game in a bad way such as phasing trough walls, consuming more resources than exist and such so so much more.
Very cool video I def learned something new!! BUT, in the lerp example I will suggest instead of using Time.deltaTime only use Time.time and compare your current time to a starting time that you set when you want the animation to start. This will completely avoid all the problems that you listed without having to figure anything out (like average speed change and what not).
Tell me about it. Stop locking game logic to framerate. Most game engines have built in delta time functions to do all the work for you. It's really frustrating to play a cool game and have to lock my monitor's refresh rate manually.
The main point in the video is that it doesn't just magically do all the work for you, you can't just multiply everything by deltaTime and call it good in every situation. Some of this stuff uses kinds of math I hadn't even heard of before (integrals), and stuff I mostly get when seeing it but wouldn't come up with myself (the math.pow exponential bit). That being said, I test things and even wrote a separate thing to shoddily graph things out to test that it lines up, to make sure, but I found just using Time.deltaTime did not make what I was doing consistent across framerates, only close to it. It was years ago so I don't remember what it was, but I gave up and accepted the approximation because I had been at it for days, getting nothing done.
@@Aeroxima Yeah I actually made that comment before watching the video haha, just based on the title. It's way harder than I thought, so I get why some Devs don't use it. It's not rocket science as Jonas says, but it isn't particularly simple either. Really makes me respect and appreciate that much more the people that put in the work to get right.
Thank you so much! I rewatched this because I was having an issue with a game I was trying to make and figured it was a deltaTime issue, haha. Doing the half-and-half solution fixed it immediately!
it really isnt all that trash pixel art and ""psx"" garbage isnt even hard to do actual pretty games like ori are very very rare look at pizza tower and cruelty squad those games are hideous and still popular@@blacktiger974
The scalable trick is to have separate threads for input, physics and rendering which get called at regular time intervals and sleep until next call once it is finished. This way the motion is independent of the GPU power of the machine.
Educational and informative as always, but this is also funny as heck. At 10:34 I legit laughed so hard for like 2 minutes straight just at your delivery, that was so frickin funny, I was not prepared for that. 😂😂
On the first question, it really depends on what you mean by “current frame” - if the engine is measuring time at the end of the last frame, then that is also the time of the beginning of the current frame - which frame owns it is a matter of semantics. Of course I don’t know when in the frame Unity records the current time, but in most game engines it is sandwiched between frames, if not using a fancy GPU readback scheme for “true” elapsed time. So assuming Unity is like other engines, B would also be correct.
On the second question, I would deduct points for not including fixedDeltaTime (or equivalently and more portably, deltaTime) because including it makes your game logic independent from your choice of fixed time step - e.g. going from 60 to 30 Hz or vice-versa. You don’t want to have to change every single number in code or editor if you need to change the time step, that’d be a nightmare. And perhaps most importantly, including the time step allows you to base velocities and such on real physical units, which gives you a frame of reference for understanding your hand-tuned variables, especially if comparing with values from other games. Finally, it makes your code more readable imo, since it highlights that it is time-dependent simulation code, not an instantaneous change or something.
Third question, the first two integration techniques are explicit Euler (position before velocity update) and semi-implicit Euler (position after velocity update). The improved version rearranges to Verlet integration, if I’m not mistaken. Verlet is often used in particle and fluid simulations, but is often considered overkill for physics sim. It’s close to zero added expense for something like a character controller however. And as you noted, Verlet will still have error if velocity changes at a non-linear rate. Discontinuities may also present error as well. But this is exactly why you perform this simulation in fixed update - there should never be that much error if the time step is fixed and never huge.
Final question - I’m impressed, almost nobody knows this! I use the “1 -“ version because I find the lerp more legible this way. Your parameterization is essentially a “half life”, which in chemistry would be the time until half the initial quantity is reached, given an exponential decay. I actually parameterize as follows: “1 - Math.pow(v, Time.deltaTime * 60)”, where v is “change per 60th second,” a good frame of reference for game developers, that tends to retain accuracy for most values. (You’ll notice that Pow reduces to a no-op for 60 Hz refresh rate.) If you find yourself needing values close to the extremes of 0 and 1 however, you can change the 60 in order to retain accuracy. I’m actually really curious how your version would perform given extreme values, I imagine much better! The way I derived this for myself was noticing that integration of addition becomes multiplication, thus integration of multiplication becomes exponentiation. This technique can be applied to any time-dependent update, and is invaluable for designing your own character controllers. Great video! I hope a lot of Unity devs start standardizing this stuff in discussion, would help out sooooo many newbie devs! I recommend everyone check out “Gaffer on Games” for some fantastic, approachable articles on all this stuff.
One more thing: it’s really important to understand that FixedUpdate doesn’t correspond 1-to-1 with real time. It actually plays “catchup” depending on how much varied time elapsed, executing a number of times (or none at all) until the most recent fixed update is AFTER the next regular update. Why? So that Update can interpolate between the previous and future FixedUpdate based on its relative time, i.e. “p = lerp(p0, p1, w); w = (time - fixedTime0) / (fixedTime1 - fixedTime0)”. Strangely, Unity doesn’t seem to compute this weight for you anywhere, so you have to compute and maintain it yourself, but it’s extremely useful if you need to render something from FixedUpdate without using the built-in “transform,” or let FixedUpdate and Update talk to each other in a meaningful and accurate way. If you’ve ever found yourself struggling to port code between Update and FixedUpdate, this may be the reason why.
16:17 I hate this I hate this I hate this I hate this PUT BRACKETS DOWN I'M GOING TO PALPITATE 16:29 Ah, so when simulating gravity such as in Brackey's FPS tutorial, I should not square time ( multiply by another Time.deltaTime ). Got it.
Crazy how I watched this around the time it came out and had no clue what was happening. Roughly a year later, I come back and find I'm actually getting most of it. Still have no clue what I'm doing, but hey, that's progress!
Super interesting to see integrals come into play here. I'm assming if you'd be exponentially increasing the speed then integrals would be the only solution.
This video is very entertaining and engaging!! I usually fall asleep to these technical type if videos. This video kept me totally into it with your delivery and graphics!
Small corrections (I learn some things from you as well, how nice, haha):
- Using Time.deltaTime in Fixed Update is actually fine in Unity cause it automatically returns Time.fixedDeltaTime depending on where it is called from.
- Using Delta Time in fixed update still makes sense for various reasons (it keeps speed to units/second and helps when inaccuracies in the fixed update intervals occur)
That means 10 free points to you if your read this, haha. Will keep updating this in case I got anything else wrong. :P
Can you do more of these please?, Maybe an episode on debugging or finding code related problems that don't seem to have an answer
dont these 2 corrections contradict eachother? or am I being dumb xD If deltaTime returns fixedDeltaTime while in the Fixed Update, then how can it keep speed to units/second and help inaccuracies?
@@blockify no because fixedDeltatime takes the inaccuraties and inconsistencies in fixedupdate into account, and deltaTime gives rhat fixedDeltatime.
Point is in fixedUpdate
fixedDeltatime==DeltaTime. There is no difference using one or another.
Still, using either one can be helpful to get around inaccuraties(which can happen in fixedupdate if u use neither)
@@blockifyif it helps, you can think of multiplying by deltaTime or fixedDeltaTime as a sort of "per frame -> per second" conversion in unity! (You can also convert the other way by dividing by deltaTime, e.g. if you want to get the amount an object has moved in a single frame, you'd divide its velocity by deltaTime since in Unity velocities are usually per second)
It doesn't return fixedDelta time. If we go back to what I said in another comment, the correct answer is not A in fact non of the truly was the right answer. delta time is the time it took to process the last frame, the documentation backs this up. So when you run that in FixedUpdate, that means the normal delta and the fixed delta will be the same value, but one does not simply return the other. Physics is a fixed step, therefore both are going to equal the same value!
I just love how He's one of the only devs that instead of showing "what to do" shows "why does it do" which is something so important.
6:50 I would say that it's not pointless to multiply by fixedDeltaTime; Makes it easier to code consistent units (say if you're trying to follow SI units strictly, or if you have calculations in both Update and FixedUpdate that should follow the same unit). Also, if you ever end up changing the frame rate of the FixedUpdate, you'll have to change every single calculation.
Fair! :)
The physics will actually break if you change Time.timeScale and don't multiply by fixedDeltaTime, because fixedDeltaTime will change with the timeScale. Meaning it's actually not always the same value, if you have any kind of speedup or slowdown with timeScale in your game.
Just want to add that the code example did not need to be changed at all to be called for FixedUpdate. And that is because Time.deltaTime actually returns Time.fixedDeltaTime when called from within FixedUpdate.
@@ThePhoenix107 Cool to know, but I'll still stick with fixedDeltaTime for consistency and clarity.
@@zelos666it actually is the other way. The fixed delta time stays the same, but anything running in fixed time will become more granular in real time because fewer fixed steps will occur between frames. This is why you might need to reduce your fixed time step for slow motion.
If you are modifying your fixed delta time for this purpose then you definitely need multiply by it in fixed update.
If you're not using fixed updates, you might end up clipping through walls from lag spikes, unless you're using rays to assert if the player has moved through a wall between the previous frame and the current.
correct me if im wrong but, this will only happen if you use a rigid body controller, not for example the player controller asset, also you dont need to code a ray check as you can just set the rigid body to 'continuous' or 'continuous dynamic'
im literally so new at game dev, im just pretty much using everything in fixedupdate, and what needs to execute fast for example key pressed in update, idk if its fine but it works fine, example in my game this:
void Update()
{
if (Input.GetMouseButtonDown(0))
{
isShooting = true;
CalculateShootDirection();
}
else if (Input.GetMouseButtonUp(0))
{
isShooting = false;
}
if (isShooting)
{
CalculateShootDirection();
}
}
void FixedUpdate()
{
if (isShooting)
{
shootTimer += Time.fixedDeltaTime;
if (shootTimer >= shootingDelay)
{
Vector3 bulletVelocity = bulletSpeed * shootDirection;
GameObject bullet1 = Instantiate(bulletPrefab, bulletSpawnPoint1.position, Quaternion.identity);
bullet1.GetComponent().velocity = bulletVelocity;
GameObject bullet2 = Instantiate(bulletPrefab, bulletSpawnPoint2.position, Quaternion.identity);
bullet2.GetComponent().velocity = bulletVelocity;
float rotationAngle = Mathf.Atan2(shootDirection.y, shootDirection.x) * Mathf.Rad2Deg;
bullet1.transform.rotation = Quaternion.Euler(0f, 0f, rotationAngle);
bullet1.transform.Rotate(Vector3.forward, 90f);
bullet2.transform.rotation = Quaternion.Euler(0f, 0f, rotationAngle);
bullet2.transform.Rotate(Vector3.forward, 90f);
shootTimer = 0f;
}
}
}
private void CalculateShootDirection()
{
// Calculate the shoot direction based on the player's transform
shootDirection = bulletSpawnMainPoint.up; // Assuming the player's forward direction is along the X-axis
shootDirection.Normalize();
}
Orange grenade lifestyle
Neutral Milk Hotel
so that’s how i fix that.. too bad i’m already making a new player controller
21:50 From your testing scheme, it's actually possible to get everything wrong and also the -10 points, leaving you with a grading that is undefined according to your evaluation :P (if I didn't miss anything)
Negative F!
being undefined, there's every chance we hit a negative integer overflow and land on a grade no less than 150
In this case I think you can just give yourself 4294967285 points
Spoken like a true game tester!
@@madmax404 the only winning move is not to play
Actually things get 100x more complicated if you have non-constant forces, you need to lookup numerical integration (initial value problem). Your recommended way is called Leapfrog integration. It can work really far from accurate if you have spring forces (with springs you need tiny timestep or other more sophisticated methods which usually are not suitable for real-time).
I feel like springs are better expressed with approximations in games.
Is a second order taylor series the wrong thing to do here?
@@drstrangecoin6050 It depends. For springs or gravity (N-body sim) to get stable results Taylor series won't be enough. You would need implicit methods for accurate and stable results (too slow for real-time). But for games springs could be done without forces in more stable way (e.g XPBD). Stability of gravity forces usually not an issue unless you're doing Solar system simulations or the like (in which case parametrized elliptical orbits may be better option for game). For a game maybe first check implicit Euler and then XPBD if it fails, otherwise start faking it.
Implicit is used all the time in games.
In fact they showed a common example in the video …
velocity = velocity + acceleration * deltaTime
position = position + velocity * deltaTime
2nd order Taylor series is fine for most use-cases.
If you have to support some wildly stiff springs or need a high degree of accuracy then you could try rk4.
p0=initialPos
r=restingPos
v0=initialVelocity
k=springStiffness
dt=deltaTime
m=mass
f1=k*(r-p0) // force
v1=dt*f1/m+v0
p1=0.5*dt*v1+p0
f2=k*(r-p1)
v2=0.5*dt*f2/m+v0
p2=0.5*dt*v2+p0
f3=k*(r-p2)
v3=0.5*dt*f3/m+v0
p3=dt*v3+p0
f4=k*(r-p3)
v4=dt*f4/m+v0
v_final=v0+(f1+2*f2+2*f3+f4)*(dt/m)/6
p_final=p0+(v1+2*v2+2*v3+v4)*dt/6
Performance cost is relative as well. It’s all about scale of use. If you wanted a 3rd person spring arm camera and it needed to be super stiff/snappy one use of rk4 would be fine. However if you are setting up a dense foliage section where foliage physically interacts with the player then you’d probably just use a simple implicit approach with
v_final=v0+dt*k*(r-p)/m
p_final=v_final*dt+p0
I think that in the latest unity versions using deltaTime in fixedUpdate will automatically use the fixedDeltaTime internally so you do not need to change this. Unity implicitly understand which one to use by the context it is used in.
it won't auto use the fixed delta time, the timing will just be identical.
It's not only in the latest Unity version. I recall hearing about this behavior at least several years ago.
Wow that's kind of terrible API design.
Would be a lot better if using deltaTime in fixedUpdate were an error.
Implicit/hidden behavior is an evil that you might expect to see in the realm of web dev frontend nonsense, but not in applications programming.
In my opinion, the best API design would be to have the delta time as argument to the update functions, that way it's impossible to mess it up.
Unity's API design choices are notoriously bad. Thankfully once you learn all the shitty things and minefields it's full of, you can safely ignore it and build up your own software more robustly. But be warned, Unity is a hell to learn.
When people misuse lerp you can really feel it in the gameplay. I did a little different than you though. I recorded the start position and start time, then I use the elapsed time to calculate the lerp factor in each frame.
I also like using cosine instead of sqrt, because it gives a more natural feel. The formula is (1 - cos(x * PI)) / 2, where x is the elapsed time.
Are you saying you did position = lerp(startingPosition, endingPosition, 1-cos(x*pi)/2)? Because that would cause it to go back and forth between the start and end, not approach but never reach the end.
@@bastian_5975 It should probably be cos(1/(x+2)*PI), which is really just a differently smoothed version of 1 - (1/(x+1)), where x is elapsed time in both scenarios. (There's an absolute ton of "sigmoid" functions you can use to infinitely approach a number.) The delta-time lerp works though, just it makes a little less sense logically because instead of lerping between two fixed points, you end up lerping between the destination and the previous location.
@@gajbooks at first I thought you meant cos(1/(pi*(x+2))), but cos(pi/(x+2)) looks so much better that I think you mean that.
And are you saying that the function you defined was a sigmoid function or that sigmoid functions are a class of functions that also achieve that effect?
As someone who litteraly had a math test earlier today on the subject of integrals, this was a great ego boost
I recall when I got into Math 251 Differential Calculus, I thought it was going to be some pretty insane shit, but it turns out we use it all the time without even realizing it. It's just so much more powerful if you know the fancy tricks. I cannot recommend enough that those who don't know at least differential calculus to learn it. You will not regret it.
@@nobody.of.importance*sigh* FINE. I'll go learn differental calculus this month.
@@gogauze im learning it in the fall
@@gogauze Knowledge is power! Good luck! Same for you Nidhsa c:
this is not only integrals, this is discrete integrals!
I love the presentation of this video, with an actual test. The whole "YOU WILL BE GRADED JOKE" actually motivated me to do well on this test that no one will see. I've seen many youtubers educate with information, by just telling us the right answer, showing it in examples, with great animations to help visualize. That process works, but I think many content creators forgot how effective it is to challenge our knowledge. At 3:41, despite me using deltaTime in many places, I realize that... I'm not EXACTLY sure which of these four are true.
Thank you for challenging my knowledge, and because of that, you've stuck out as a memorable youtube educator. I've subscribed and I look forward to learning more from you.
I didn't know i always wanted a video from Jonas directly to the developers. Gotta love these videos!
Now THIS is the kind of tutorial i need, ive had enough of people just telling me what to put in to get my desired output, and i need that perfect level between talked to like a baby, and expecting im Einstein. You hit that nail right on the head.
please we need more of thisss this is the exact technical info no one talks about and it even has a visualisation very good video 10/10
Someone needs to send this to Gearbox given the new Risk of Rain 2 update apparently commits several of these crimes.
Very impressed, you've covered many of the pitfalls. Just two remark: Fixed Update is useful to avoid costly exponent which are very common in Physics calculation because if you have a constant delta time then the linear approximation is good enough (so the "bad" lerp in a FixedUpdate would work just fine). The big drawback with FixedUpdate is that you'll usually notice "jerking" as one frame you'll update 3 times, but then the next frame only 1, then the next 2. Usually to fix this you need to extrapolate the difference between the current frame's deltatime and the FixedDeltaTime.
Or avoid FixedUpdate() altogether and call Physics.Simulate() by yourself in Update() after disabling automatic PhysX Update. Actually the only method I know to avoid Unity's microstuttering.
I don't code, but I am a physics nerd and saw delta time and it peaked my interest. Was not disappointed to see the explanations of calculating changes in distance as a function of time when not accelerating, when accelerating, and with a changing acceleration value. With the questions that were math based and not definition based other then syntax i am happy to say I got the idea right lol.
For future reference: It *piqued* your interest.
@@superscatboy Maybe his interest curve reached a local maximum, so it really did peak his interest.
@@oisyn- Or maybe that's just a load of old bollocks 🤷♂️
@@superscatboy
Well, my interest definitely *peaked* when seeing the title of this video
@@baitposter So your interest decreased when actually watching the video?
For those confused about the lerp section, I have a really easy way to think about it intuitively:
If your "lerpSpeed" is 1, then the base of the exponent (the number on the bottom) is the portion of the distance you want to cover in one second. So in the video this number is 0.5 which means the character covers 1/2 the distance to the goal every second. The reason this works is because when you do this multiple times in a row, the distance decreases exponentially. So, if you imagine your frame rate is 4 frames per second, then in the first frame the character covers 0.5 ^ 0.25 of the distance (because deltaTime is 0.25), and the next frame the distance will be less but they will still cover another 0.5 ^ 0.25 of _that_ distance. So the total distance covered will be (0.5 ^ 0.25)(0.5 ^ 0.25), which if you remember your exponent rules is equal to 0.5 ^ 0.5. In other words when you exponentiate like this, the deltaTime in the exponent adds linearly every time you lerp. In this example, if you lerp every frame for one second (that is 4 frames) then the exponent adds up to 0.5 ^ 1. In other words, you cover half the distance in one second, regardless of your deltaTime, as I stated in the beginning.
EDIT: as explained in the replies, the base of the exponent actually represents the portion _remaining_ after 1 second, not the portion covered after 1 second, because you start at t = 0 which would give a blend value of 1, so we use 1 - 0.5^t instead (or Jonas puts the current position in the second parameter of lerp, which is equivalent)
For this reason, I would use Math.Exp(-lerpSpeed * deltaTime).
Just want to point something out here, cause this kinda bothered me. You are correct in that the reason for the deltaTime being in the exponent is so that they add to 1, but the total distance covered is NOT just the product of the blends. You can easily see this if you use a base other than 0.5.
Assuming you have the function laid out like Jonas did, where the target position occurs when the blend is 0, then the position of the snail after n frames is going to be (target_position)(1 - (product of all the blends)). You can deduce this through induction with the lerp function. Lets say that our blend is 0.1 ^ 0.25, where the 0.25 is our deltaTime, just like in your example. Initially, the snail's position is 0. After 4 frames, or 1 second, the snail's position will be (target_position)(1 - (0.1 ^ 0.25) ^ 4) = (target_position)(1 - 0.1) = 0.9(target_position). After 4 frames, the snail moves 90% of the distance, not 10% as you implied.
Fundamentally, what you're saying is helpful, but I saw the comment and got caught up on that snag for a while, and it kept me from truly understanding what was going on. Also, I agree with @NXTangl, using the built in exponential function is nice because then you don't have that arbitrary base and the speed is more directly controlled by lerpSpeed.
> So in the video this number (lerpspeed) is 0.5 which means the character covers 1/2 the distance to the goal every second
No, in the video you cover 0.3 of the distance every second because of that number (lerpspeed) being 0.5.
@@feha92
No, "this number" refers to the base of the exponent, which is 0.5 in the video. I also say that I'm setting lerpSpeed to 1 for simplicity. lerpSpeed is also 1 in the video IIRC, so I'm not sure how you mixed that up.
Edit: actually, lerpSpeed is 0.5 in the video, so it makes sense you got mixed up. But I still said "if lerpSpeed is 1".
@@pixelz3040
You're right, the base of the exponent is the portion _remaining_ after one second, not the portion covered. Those two numbers just happen to be the same when the base is 0.5, my bad.
I personally still like to use the arbitrary base because the meaning of the base is clear when the exponent is 1, and I don't want to think about a base of 1 / 2.718. lerpSpeed controls the speed the same way in either case.
I'm going to contest question 2 based on the wording.
The presentation of a frame can be conceptualized as happening at specific instant of time, but the game logic of a frame takes meaningful time to happen. If I just see phrases like "the current frame" and "the last frame" in reference to timing and without further indication, I will interpret that as referring to those spans of time. In the context of timing, frames have a start and an end, and that end is before the frame's presentation. Since each operation can be conceptualized as contributing to a specific frame, the end of a frame is the same as the start of the next.
You don't know when the current frame will finish or when it will present, but you do know when it started. A game engine is going to use the most recent frame-time estimate it can, and that would be the time between the start of the current frame and the start of the previous frame. This is more consistent with the wording of option B than the wording of option A, and it is consistent with the wording in the Unity script reference for Time.deltaTime: "The interval in seconds from the last frame to the current one"
Thank you.
wtf this is exactly what I just wrote lol. With a lot more fancy words sprinkled in though
I agree, and was thinking along a similar line. The wording of those questions were just bad
Way back before I even knew about delta time I used to have my games code run at 120fps and didn't noticed any weird behaviour, but as soon as other players with 60hz displays played the game everything was in slow motion running at half the speed, they often commented the game feels slow and me and my friend playing at 120 allways wondered what do they mean until I realised this issue.
Lol
Haha. Oh, no. :D
haha i too didn't realise for ages because since I never did anything big scale the fps stayed relatively consistent
same with us lol tested it out by racing each other in different refresh rates haha
For anyone interested in learning more about numerical integration, there's a whole range of other schemes you can apply which have different stability properties based on the deltaTime and the equations of motion of the players. Here at 8:22, if I can recall properly, he first uses Euler Forward then Euler Backward and after that, Crank-Nicolson. If you had a more complicated movement, you could as well switch to a spicier scheme (like Runge-Kutta) but it's propably over-engineering the task you're trying to achieve.
True, although this makes the difference between explicit (forward Euler) and implicit methods (backward E, C-N) appear very similar, since there is only a time dependence here. Normally you will need to solve a system of equations, which makes the thing inherently stable. A good example is the exponential speed case, where an explicit method can easily overshoot.
3:48 This could actually be A or B depending on your definitions. I picked B, because it's the time between when the current frame started being processed and when the previous frame started being processed. If your definition for the time of a frame is when it is done processing, then A is the correct answer. I view the start of the frame as the true time, since that is also when inputs are registered, so the actual frame that is being displayed is slightly behind, not the other way around.
Just to add on to your comment, the video is wrong here as per reasonable definitions. The term 'current frame' always refers to the one you're currently processing. 'deltaTime' is calculated at the start of the processing of the current frame by comparing the time to the time the previous frame began processing. deltaTime is essentially how long the last frame took to process from start to end (where 'end' is the start of the current frame).
"Time elapsed between the last frame and the one preceeding it" is a not a good definition of deltaTime because the frame before the last one has no relevance. The current frame's deltaTime value is calculated in the current frame and not at the end of the previous one. As per Unity's own documentation for Time.deltaTime it says it's "The interval in seconds from the last frame to the current one".
I believe the error is largely due to representing frames as a point in a timeline when something is rendered on the screen. At some time, typically very shortly after that rendered frame point on the timeline, the deltaTime value will be calculated. The only relevant frames in the calculation is the previous frame and the current frame.
Carrying on from this the video then describes deltaTime having a "1 frame delay" which is also stated and described confusingly. Obviously deltaTime is not going to be related to how slow the current frame is because it can't predict the future. So the best value it actually could be: the previous frame's calculation time, is essentially what it actually is. Describing that as a "1 frame delay" doesn't really make sense.
Obviously here the video is referring to deltaTime in relation to something moving on screen and pointing to how the object moves only a little bit on screen on the frame that took a long time and then has the larger jump on the next frame. Saying that "deltaTime always has a 1 frame delay" because of this particular example is not reasonable. deltaTime is not delayed, it is the correct value for when it was calculated. Nothing prevents a programmer from calculating their own deltaTime equivalent value and moving objects with that right before rendering. Time.deltaTime is not delayed, you have just chosen to use it in a way that gives a result that you refer to as having a delay.
If anyone was confused by the 1 frame delay part of the video and curious, the way the deltaTime value would work after a slow frame is is:
If a game was running at 60FPS on Frame A, Frame B's deltaTime would be ~0.0166s. That's how long it was from the start of Frame A to the start of Frame B.
If Frame B was then slow and took 0.1s (10FPS) to complete, Frame C's deltaTime value would be 0.1s
Basically the frame after the slow frame would see the larger deltaTime value.
Not a bad video otherwise, but that section in particular I think would be very confusing to programmers trying to learn about deltaTime. I believe conceptually it's essentially correct, but by representing frames in relation to deltaTime in that way and slightly misrepresenting when deltaTime is calculated it makes something fairly simple much more confusing.
I understood it that way too, thanks for confirming! +10 points to me!
And I just want to say that I don't like leaving some big comment like that, I just needed to write that much to explain everything.
Obviously Jonas seems to be great at what he does and has made an excellent video. I know I'd hate making videos like this because it'd be very had to not make errors or poorly represent some things even if you know them well yourself in reality. I'd not want to have to see comments like mine above, but know that it's only left in the interest of helping clarify those elements from the video for anyone confused or off-put by them.
I'm sure you (Jonas) understand what I've explained yourself and just (in my opinion) didn't express them adequately in that small part of the video.
@@mcarr87 Your comment is far more confusing than the video is. There are a few reasons for this.
Firstly, there are two entirely contradictory definitions of a "current frame" at play here, which you don't seem to realise. On their own, both definitions are valid, but the one you present here has some issues in its broader context.
You seem to define a "frame" as the routine that runs to produce it. In that sense, the current frame is indeed the one you're processing. But then a frame is a process and not a point in time. This contradicts with the definition of deltaTime in the Unity documentation you quoted, "The interval in seconds from the last frame to the current one". That one notably _does_ define a "frame" as being a point in time, as evidenced by it not saying "from the _start_ of the last frame".
One important problem with your definition is that updating the game state is not linked to visuals whatsoever. A game could poll for inputs twice as often as it renders a new frame. These are still two game updates, but there is only one frame rendered. If you define a frame as a process, you'd have to exclude the time spent updating the game state, and only include the rendering time. But that's demonstrably not the value that deltaTime contains.
The other definition of a frame is "the image being shown on the screen". This is a far more intuitive definition, and how most people understand such terms as "fps". There are 60 images being shown to me per second. And whatever is being shown to me at any given time, is the "current" frame. This frame is shown to me all at once and does not change afterwards until the next frame arrives. Thus, the moment it appears on my screen is a single point in time and not a process.
Reading the definition of deltaTime again, this makes a lot more sense. Because the "current frame" is what you just finished. And deltaTime is indeed the space between those points in time by all definitions.
You say that the way this definition is worded in the video is inaccurate, but that is simply not true. "Time elapsed between the last frame and the one preceding it" is a perfectly valid way of describing it, so long as you take "last" to mean "most recent" over "previous". The current frame is the most recent frame, and therefore the current frame can also be described as the last frame. This is not a strange way to use English, and should not be confusing for someone who speaks the language well enough to watch English videos on UA-cam and writes English comments.
Additionally, I strongly disagree with that a "1 frame delay" is a bad way to describe what happens. Of course, the variable itself isn't delayed. Because it's defined with that delay already built-in. If I told you what I ate yesterday, my statement isn't delayed by one day. But that doesn't mean that your knowledge of what I ate isn't!
The latter is the "delay" the video refers to. The example is clear about this as well: the frame shown after the lagspike does not take the lagspike into account exactly because that frame is being calculated as if it will render in the same amount of time that the last frame did. Regardless of what you're actually building, it is theoretically impossible to react within 1 frame to the time it takes to render just by reading the deltaTime variable.
In short, it takes exactly one frame before you can react to how long a frame takes to render. I'd like to ask what you would describe this effect as, if not a "1 frame delay." This description has nothing to do with motion; it's a factual description of what you observe when you look at the game frame by frame. It takes one frame to adjust to a frame taking longer to render. You cannot adjust immediately. This is the definition of a delay.
Don't get me wrong, I agree that there are ways in which the video could have been clearer. I just don't think that the things you take issue with are the problem, and that the alternatives you provide make things less clear rather than more clear.
What the video really needed is not a change in definitions, but a more precise and consistent use of language. "Last" and "current" typically have the same meaning, but it'd be clearer if you stuck to one. It'd also be helpful to distinguish a "frame" as what's being shown, from an "update" as being the process to create it. And possibly a few other similar things. The content and presentation itself is fine and doesn't need to be changed, the script for the video really just needed one more editing pass.
@@Gamesaucer I appreciate your arguments and while I don't disagree that much of this depends on your particular definition, I don't agree that in this context of programming the definition of 'current frame' would only refer to the frame most recently output to the GPU. While not used too commonly as a direct term in the Unity docs and variables, you'll only find "current frame" referring to the one currently being processed that would next render (e.g. OnDemandRendering.willCurrentFrameRender) unless referencing something selected in a timeline like in the Profiler. Also I was directly referring to where the video's uses the phrase "the frame currently being processed".
I 100% agree that a frame can and often does refer simply to the image presented to the screen, and the duration of that image on the screen in a standard, single buffered game would be determined by how long the following frame takes to update and render. That's not in question.
But you bring up a great point that I didn't bother with because I'd already written too much before, and that is how a game could have multiple Updates without rendering a frame if it wanted. Alternatively you could have things like double or triple buffering that could delay the rendering of a frame until after other queued frames had rendered. To me, both of these are great arguments for my point.
First, going off your concept, lets say you're in Unity with a disabled Camera object and you manually called Render() every 3rd frame. Here you have 3 Updates over 3 frames (as per Unity's definition of a frame. See e.g.: "Update[()] is called every frame") where only 1 of them is something drawn to the screen. You also have 3 different deltaTime values across those frames, 2 of which can't be said to have any relevance to what was drawn on screen last.
You could also run your game's multiplayer server without rendering anything ever and it still has deltaTime and what most refer to as a frame rate (including Profilers, etc). You could argue that without rendering anything there is no 'frame rate' if you wanted, but that only diminishes your arguments because deltaTime still exists and is still calculated in the way I said it was without any relevance to what was drawn or if anything was drawn at all.
The same type of example can be given for multiple buffering of frames where the deltaTime does not relate to what was last drawn on screen.
I don't think in the context of programming your point "the moment it appears on my screen is a single point in time and not a process" has much validity. For one, saying a frame is a point in time doesn't really relate to the concept being discussed which is to do with the duration of a frame. Secondly even if you were to try to talk about it as a singular moment in time, what moment is that? When the LCD monitor draws the first line or the CRT's electron gun starts emitting or when the end of the image is finally displayed? What if the frame rate is faster than the monitor and it never finishes?
I know that's overly pedantic, but it's just to illustrate that that is not a consistent or really even well definable thing and doesn't actually relate to actual programming and deltaTime.
I don't really want to continue, but I'll quickly address your points on "1 frame delay" which I also find a bit odd.
Saying what you ate yesterday is completely different from deltaTime. When deltaTime is calculated by Unity when a new frame begins processing, that is not a value telling you about something from the past. That is an immediate, current time difference between right now and back then. If it's referred to on the next line it's extremely current and relevant. You could say it's less 'current' later in the frame processing, but that depends entirely on how it's used. This is why I mentioned how you could use your own delta time calculation for rendering if you really wanted something more current for the frame you're processing than deltaTime.
To say it has a delay is to proscribe a very weird definition to it. It is what it says it is and it does not give a delayed value at any point after its value is set. It's always 100% accurate as per what it is defined as being the value of. You know immediately at the start of processing a frame what the time the last frame took, there's no delay. That's the point of the value. To say it has a delay would be to give it the definition of "this is how long this frame will take, but you won't know until next frame because it has a 1 frame delay".
I feel like this sort of discussion comes across as antagonistic and I apologise if it comes across that way. I also expect this could be one of those things where it's an ongoing back and forth, but I don't want to do that. I will freely admit that there's validity to the video's way of putting it and taken with certain definitions it's not wrong. This is what I said in my original post. I just don't believe in the context of programming, which this is, it was stated in the most valid and coherent way.
Thanks for the Lerp fix! This is something I pretty much gave up on after I realized the solution would be a easy to mess up, and almost completely just changed to using spring-damp systems, though partially because they're also often just better.
Though I'd say that the "simple" solution to calculating per-frame movement deltas is not ok 9/10 time but probably closer to 99/99.9% of the time.
I've never actually brushed against it but have had a lot of pain due to different update rates simply ending up with different results, and inconsistent amounts of FixedUpdates causing frame pacing issues. For the Xbox One port of Thief of Thief for example, I ended up doing a hack that connects Update and FixedUpdate rates as long as they don't want to be too far from each other and managed to remove almost all frame pacing issues (which were bad otherwise) from the game.
I've had to do this only once, but I had a sprint-joint system smoothly controlling the camera in Among The Trolls. If the framerate got REALLY bad, the system went completely out of whack. So for that I implemented custom sub-stepping where the calculation was always calculated with an almost non-changing deltatime but just repeated enough times during a frame if the framerate was bad. This is how FixedUpdate also works in essence, but with FixedUpdate this can cause those cursed problems where the frames get longer because FixedUpdate is called more, if FixedUpdate gets even slightly expensive.
Closest solution I have to syncing 2 clients with different frame times (in absolute time) was a server-time synchronized RPC where, I decided to trigger the event on the slower-updating client even if the trigger time wasn't yet reached as long as if the estimated time of the next frame would be even more off. Of course this also used the last frame's frametime though but made some events seem almost magically in-sync as long as I could schedule the event far enough in the past (like 300ms).
I am one of those. I know everything. No need for pen and paper. I already know. Even what I don't know I know... And then some..
it feels like you're a creator of a game called A difficult game about climbing
@@_sIashI kinda feel like he's the creator of a game called punch a bunch
You actually do want to multiply by fixedDeltaTime in FixedUpdate a lot of the time, to ensure that your speeds are in units per second and the numbers in the inspector actually have meaning. It's also needed for more advanced custom physics, used in the integrations.
Which grade did you get? :D
Please when is thronefall dropping on PS4
I got grade c! (Being a beginner programmer that can't even make a simple player movement script lol)
F, because I didn't write down my points. I did okay but it counts for nothing :P
F i got 10 in the second question and ten in another and then lost ten
Grades are of no importance
2:20 Well, arguably, Betty has the advantage here, because as she and Jerry go really far distances, Jerry is changing his x position by a very small number, which gets essentially zeroed out as he loses precision, meanwhile, Betty can keep going for a bit longer, since she is adding a bigger number to her x position, thus precision takes longer to catch up with her.
It is called FixedUpdate, but that doesn't mean it is actually 100% fixed. It tries to run in fixed intervals. However this will never be exactly right, either because of cpu cycles or if a fixed update exceeds its time budget. This will most likely be insignificant in most cases, but there is still a reason to use fixedDeltaTime for this.
For example if you run physics in this fixed update and it always takes just a tiny bit longer than expected, the error can add up over time and without fixedDeltaTime it might explode your physics.
That's a useful addition. Good to know.
@@JonasTyrollerthis comment should be pinned tbh
I'm glad you pointed out the issues with update and fixed update, The thing is, some things need to be calculated before you should continue, in which case, fixed update is the answer, however those need to be lightweight because you need them for function quickly, in some games the physics may not need high accuracy, in which case, it's fine for them to happen whenever. However games that are heavily reliant on the physics (like an FPS) you really need those collisions calculated before continuing.
The reason why fixedDeltaTime exists, is that you'll be able to change the rate of fixed updates per second. By default unity uses 50hz, but you might wanna increase or decrease this value depending on your project. If you don't multiply your values by the delta, changing the rate in [Edit > Settings > Time > Fixed Timestep] will result in the physics running faster or slower than intended.
yep absolutely, once was having issues with the precision of physics collisions in a project I was working on so I had to bump up the fixed update rate to help solve it. I use fixedDeltaTime in my workflow for exactly cases like that, I might have had to rewrite weeks of code otherwise
You can even modify fixedDeltaTime at runtime.
Someone please show this video to risk of rain's game devs
Using deltaTime in FixedUpdates still makes a lot of sense, since you often want to keep your velocity as meters/second rather than meters/(fixed update interval)
Agreed. Only if you use fixedDeltaTime, though, otherwise the game dev gods are gonna cry.
@@JonasTyroller Although when Time.deltaTime is called from inside FixedUpdate, it returns Time.fixedDeltaTime anyways (at least in Unity).
isn't it the same if you multiply velocity increases by fixed update interval since a game at 30fps/s at 15m/s is 15/30 = 0.5 meters/frame
@@lhilbert_ Oh, does it? Shame on me for not knowing that. That makes sense I guess. Oops-dee-doops. :D
@@JonasTyroller -10p!
I think this is a great subject and something that many lack a good understanding of, but in my opinion this video too shows a lack of understanding of deltaTime.
My biggest problem with this video's explanation of deltaTime arises in the explanation of why alternative b) is wrong in the first question (around 4:18). This video seems to present the idea that a frame should represent what the state of the program is when the frame is presented, while in reality, a frame represents what the state of the program was when the frame's update function began (when deltaTime was measured, to be precise). This means we're not using "the last frame's deltaTime as an approximation for the current one's," we are instead rightfully using deltaTime as the time between the last update call and the current one, because that gives us the state of the program at the time of updating.
This also means that deltaTime does not "always have a 1 frame delay" (5:34) as an explanation for why lag spikes are 1 frame off. Instead, the state of the program that a frame is presenting is always at a 1 frame delay from the current state of the program. There is no special feature of deltaTime making it 1 frame behind.
Furthermore, in any well-designed double-buffer renderer, the previous frame should be drawn on the gpu while the current frame is updating on the cpu. Once updating has completed, the previous frame is presented as the current frame, making the presented frame TWO frames behind the current state of the program. (+1 for every additional frame buffer)
Other than that, I think this video explains things well and was fun to watch. A quick point to make is that for the explanation of the last question, the idea is presented that an exponential function is essential to achieve the desired result, while any function beginning at 0 and approaching 1 would work, such as 1 - 1/(1 + deltaTime * lerpSpeed), removing the need of Math.Pow.
I guess I'll come across as another know-it-all, but I just wanted to share my understanding of the topic and I'll be happy to discuss it further!
*screams in multiplayer*
Love this video, Jonas. Beautifully explained. Would love to see more like it!
Please elaborate. I've wanted to implement multiplayer in the future so any hiccups or things to consider is really useful.
.
@@magnusm4 multiplayer you can't just use deltatime for each pc because everything needs to be synced. So you need a main computer (which could be a player too) that does the calculations, and the players' pcs need to display that information. But frames can't be involved in the calculations of the variables, otherwise things would move really weirdly. You need the numbers sent to the pcs, and the pcs to render that information using deltatime, because you need to get the correct number for that point of time based on when the individual player's frame renders. And the rendering calculations are gonna need to be precise otherwise objects are going to appear in the wrong spot because if the calculation is off the number on the server is still correct, but it's displayed incorrectly on the player pc.
@@IONProdAnd this is the reason why so many beautiful indy games lack multiplayer support. It's really hard to do properly.
A. I mean, it's pretty simple. The first thing you learn about deltaTime is what it is (but I know that lots of people just rush things up to make games quicker). The rest of the reasoning flows from that
As a Godot user, I love that this just explains the concepts. Doesn't matter what the engine is! I felt I kinda knew all this, but it's presented so well I feel I learned something anyway.
yeah, btw for those that don't know, the equivalent of FixedUpdate() in Godot is _physics_process().
@@lukkkasz323isnt it _physics_process(Delta)
Yeah, thankfully stuff like this is pretty engine agnostic. Once you know how one engine works, a lot of it is easy to carry over to others, at least from a technical perspective.
I'm also a Godot user, and I know that Update() is "_process(delta)", and FixedUpdate() is "_physics_process(delta)"
ive also never seen someone mult everything by delta time in a godot tutorial
19:50 I generally find it better to just use deltaTime alone as the exponent rather than multiplying by a lerp speed. This way you can adjust the 0.5 to whatever ratio you want the lerp to reach each second.
Thank you for your service professor Jonas😎
Always.
Thank you for this cursed knowledge Jonas
We thought you perished!
This needs to be turned into a series to help new people to understand more on coding.
i dont think this has to do anything with coding. more like high school physics and how delta time on game engines work with a very very simple explanation.
@@Fix-- Why did you get scared away? If you didn't understand anything, I want to say that it's completely normal for a newbie to not understand like 70% of the video. To be able to take something from this video, you need to have basic knowledge of C# (at least be able to write a quadratic equation solver), basic knowledge of Unity (at least what GameObject is, what MonoBehaviour class and its methods are and a rough idea of how physics work in Unity), a good school level math and some calculus knowledge. Besides, you have to have tried to make a character move to encounter the problems Jonas is talking about.
My go-to example of why you might need integrals to handle varying delta intervals is:
- Imagine you have a simple homing missile/enemy tracking the player.
- It travels at a constant speed but can adjust its heading by up to 180 degrees per second.
- At a stable 60fps, that means 3 degrees per engine tick; at 30fps, 6 degrees per tick.
- What if there's a sudden lag spike and the next tick has a delta of, say, just 3fps? If you updated its movement simply as (adjust heading) then (increment position) this lag spike enables the projectile to change its heading by _60 degrees in a single tick_ which (under certain edge cases) can allow it to successfully target the player in a position that would (under normal conditions) be slightly outside its defined turning rate.
Wow, I'm honestly quite impressed by the quality of this video. It's very entertaining and informative at the same time, I hope you do more videos like this ;)
Creating and using test functions to visualize your code is so much more satisfying than most people realize.
UA-cam game dev eduction needs more videos just like this! Really great format.
Interesting. My biggest takeaways were
• The 1 frame delay
• Splitting up speed calculation on two steps (before and after applying movement) for better accuracy
• Exponential formula in lerp (I'm actually still confused why it can reach the destination with that method - and my way would be to add some IF-statement when close and snap it into final position)
Edit: interesting use of lerp too as stands for linear interpolation, but because he changes the "start position" each frame it does not become linear anymore. I guess it's still legit!
I have been developing games since the 1980s and have built several game engines from scratch. So I didn't really learn anything today, but I think that Jonas did an excellent job of explaining the concept. Keep up the good work!
My solution to deltatime inconsistencies was always "just make sure the game runs at full framerate even on potato computers lmao" but even so, looks like I still have a lot of things to check for and improve in my code when one of the games I'm making is about all about speed and precision with the physics engine.
I know someone will try to run the game on a computer that's probably weaker than my already 10 year old test machine, and they'll be counting on it.
Jokes on you, I multiplied my grade by delta time and now I'm above the maximum!
Jokes on *you*! You multiplied your grade by a number almost certainly less than one! Your grade was lowered to a fraction of what it would've been!
Unless you run with less than 1 FPS in which case the joke would again be on Jonas...
@@lFunGuyl I'll take the risk for a shot at glory!
Awesome videos Jonas! Keep up the great work. Nice to see other people loving Unity. It seems you got something slightly wrong (semantics-wise). You see according to the Unity docs (and tests I did) Time.deltaTime is "The interval in seconds from the last frame to the CURRENT one" and you also agree to this schematically on the 4:16 point where the black dot shows our point and 0.14s frame is indeed the last. To make a long story short, the correct answer is the time it took from the last frame start, to this frame's start which I think is stated in a cleaner way.
You think I'm using delta time incorrectly?
Well jokes on you, I'm not using it at all.
If the game lags, everything goes in slow motion and a pop up appears to insult the player's setup
lol
Genius solution. We should all start doing it like that!
@@JonasTyroller just finished the video, it was greatly informative and entertaining, thanks Jonas! Sorry about the meme comment hahahaha
6:05 Objection! The developer may want to change the physics framerate in the future. If you do not account for dt, you'll have a lot of fires to put out every time you change the physics timestep (which some assets actually require). Time.deltaTime will automatically return Time.fixedDeltaTime in FixedUpdate.
when your use the lerp function your supposed to have a "linear" speed without acceleration because it's a Linear intERPolation, if it looks exponential it's because you change each frame the beginning position (parameter a)
so :
pos = lerp(pos_begin, pos_end, t)
Great video though !!
So, is the reason the lerp was looking exponential causes by the fact he use transform.Position, which got the current position, instead of the start position which never changes, so it should be a constant, somewhere outside the update function?
@@pepperdayjackpac4521
Yes it wouldn't be exponential if he sets the initial position.
You can test yourself to see.
I have a degree in electrical engineering and I changed my career into programming and finally the math I learned became useful! I loved your video !
The amount of work put into this video is insane! I am not even interested in deltaTime, but I am still watching
These visuals were insanely good. I didn't expect the answer for the linear acceleration, splitting it up like that. But it makes sense with the graphs!
There is actually another layer of complexity here, which even experienced games developers often miss: regardless of how much time has passed between your consecutive update calls, the monitor typically can only present images spaced at a fixed interval from each other - the refresh rate of the monitor. The only exception here would be if you are using a variable-refresh monitor with a GSync or FreeSync technology. If you are updating your game with variable deltaTimes, but presenting those frames on the screen at a fixed rate, you will create what we call "microstuttering". The animation will overall keep correct pace with the wall clock, but it will appear jerky, unsmooth. Unless you are using GSync, you should only ever update your game in increments that are a multiple of the monitor refresh rate and then tell the rendering system to present these frames at the correct time in the future - if you are updating the game for X milliseconds, then the frame you've generated should be presented exactly X milliseconds from when the previous frame was presented. This technique is callled "frame pacing" and fixes microstuttering. Note that modern game-engines like Unity and Unreal might automate frame-pacing for you behind the scenes, by feeding you deltaTimes and presenting the frames as appropriate (support might also depend on the platform you are shipping the game on).
If your engine is developed properly, DeltaTime should be tied directly to the update of a frame. Most modern engines (Unreal Engine, Unity, and most AAA Engines) tie DeltaTime directly to the update of every frame. This by definition means that each tick is tied to the update of a frame.
In the scenario you presented this is not what happens. If your actual frame update is not in sync with your refresh rate on your monitor, you'll typically see frame tearing (since almost all engines will queue at least a frame in advance in the back buffer and update the screen on each refresh). Screen tearing happens since the new frame that was in the process of rendering in the back buffer is being pushed to the screen in an incomplete state.
Microstuttering really happens when you're close to the target refresh rate. Since there's some variability in each frames workload (both on the CPU and GPU), frame completion may not fall exactly on the expected interval to update (ie 1 frame may have taken 17ms rather than 16.5ms to complete rendering). In order to avoid this, a lot of devs will try to exceed performance from the target enough to minimize Microstuttering. It has nothing to do with updating your game with variable DeltaTimes. It has more to do with frame consistency.
screen tearing is what I call it
If I'm understanding this properly, you're talking about the need for vertical synchronization or VSync, right? I'm pretty sure you can actually toggle it on or off in the project settings in Unity, and I assume the frame pacing will be taken into account when calculating deltaTime. I do believe it should be the engine's job to get that working properly, you shouldn't carry that burden during the game programming phase.
When I first started physics programming about 15 years ago I found fixed step with accumulation and display interpolation is the way to go. It always surprises me that variable step is still a thing, but I guess it's just faster if accuracy isn't needed.
Agreed. As far as I can understand, it's stems from wanting to ship a game to a multitude of pcs with vastly different specs, and then wanting the game speed to be equal on those machines in wall time. If you look at nintendo games tho, they use fixed step, and if the game lags, the game simply runs slower, no sudden movement jumps to try to stick to wall time. I like keeping the simulation time and wall time as different.
I highly appreciate the math explanations. Calculus is an important topic that can be learned as early as high school, maybe earlier if you have the perfect teacher, and solutions to game development like this are why learning advanced math is important.
The sad thing is that teachers make a terrible case for learning calculus, algebra, and geometry, usually throwing only rocket science as an example. I went through the classes just fine but never understood why I should learn the material and could never discover a legit use case for it. That is until dealing with graphics and games, at which point I heavily regretted forgetting most of what I had learned.
I'm with you, but schools don't seem to have an interest in teaching "real" math. It's all just about calculating numbers, like robots.
Studying physics was an absolute eye opener for me. There I got taught math on a more fundamental level, which really made it click. I'm still wondering why they don't teach axiomatic systems, logic and set theory in schools and let the students be creative for once. The basics actually aren't that hard.
After having achieved some knowledge of those topics, calculating stuff, even derivatives and integrals, which are the highest level topics in schools, becomes piss easy.
This video was recommended to me at 1AM in bed, stayed glued to my phone screen all of the time and still understood everything. World-class explanation.
Subscribed
During the part on acceleration, you can use the equations of motion to get:
transfrom.position += Vector.right*speed*dt+Vector.right*acceleration*dt*dt/2;
speed += acceleration*dt;
You should get the same result but in a "physically correct" manner. In the end it reduces to the same result, but it could still be useful.
use * 0.5f
Correct me if I'm wrong, but the first method (which is the same as you provide) is called the forward Euler method, which tends to artificially adds energy to the system the further it goes. Updating speed before position (the sympletic/semi-implicit Euler method) or adding half before and after (the midpoint method, which equates to 0.5 because he is using a linear function) tends to be more stable (the error is bounded)
To be clear: It's not just the same result but it's also the same mathematical formula, except not applied with intermediate state (only modify speed once).
It's easier to see if you simplify the formula to:
transform.position += Vector.right * dt * (speed + acceleration * dt/2);
speed += acceleration * dt;
And then pulling out the acceleration term to apply to speed makes looks like Jonas' code:
var boost = acceleration * dt/2;
speed += boost;
transform.position += Vector.right * dt * speed;
speed += boost;
@@mrnowhere-sc3mvFor anyone who wants to go deeper on this math, "Math for Game Programmers: Building a Better Jump" goes into Euler integration, Velocity Verlet, and concludes simplified Verlet (the same result we have here) is a good compromise: ua-cam.com/video/hG9SzQxaCm8/v-deo.html
19:27 I had as a solution:
float elapsedTime;
void Update() {
elapsedTime += Time.deltaTime * someMul;
transform.position = Mathf.Lerp(startPos, target, 1 - 1 / elapsedTime);
}
I was hela confused when you presented your solution, but then saw you used transform.position instead of startPos. It would work if the startPos is set, but your solution doesn't need that and is therefore still better
Edit: Looking back I see the issue that you should probably split the Time.deltaTime-adding in 2 halfs
Same thing, was hella confused when he didn't put in a time counter until I've noticed that the start position is not a constant one
Mans violated my last braincell after clapping for nobody at 12:50
BRO I HAD NO IDEA ABOUT ANY OF THE FIRST PART AND THEN I GOT THE 50 POINTS 😭
Very good!!! I'm glad it's getting easier and easier to teach people about the acceleration gotcha. I'm always sad when I play a precision platformer and some of the jumps are impossible unless I limit the game to 60fps.
I got 160 points!
Hey you seem to understand this. can you explain why he used .5f as if it means half? isn't that hexadecimal for 95? isn't he trying to get half the acceleration for the first part of the frame and half the acceleration for the second half of the frame? if that's the case why didn't he actually just use .5?
And if he wasn't trying to get half, doesn't that mean the snails would've accelerated quicker than they were when it was just one line? was the point not to get them to move the same speed but split the acceleration addition up so that it would get an average of the frame start and the frame end acceleration?
to be clear, i need no explanation of delta, i understand how it works. I just don't get this bit. about splitting the acceleration into two. i get why he does it, cuz i understand why you wouldn't want the acceleration from before nor the after, but rather the midpoint of the two, i just don't understand how multiplying by .5f gets that, unless .5f is in fact just .5, but it seems like it's hexadecimal for 95
edit: oh my god, i was right the whole time it is just 1/2. 0.5f is unity notation for floats. that was so confusing as someone who uses godot. correct me if i'm wrong
@@dexlovesgames_dlg yeah, f is the suffix for "this is a single-precision float, not a double-precision one"
I've only used DeltaTime in some bad game tutorials but still got one question half right and the rest all right, but I learnd much watching this video. So thank you!
New Jonas Video Lets gooooo!
Great to know that I have using Time.deltaTime correctly all along, except for my lerps... That explains why my character sometimes teleports around. Good video, now I got to dig through my code and fix my mistakes.
Great video! However, wouldn't 19:49 still be wrong though since you are just using the deltatime for each frame and not a sum of all previous deltatimes?
The lerp is from the current position, not the starting position.
0:30 Ok, Ok, I got the pan and the notepad++, I'll pass ur test.
1.
float NumberOfTicksPassed = DeltaTime / GameTickTime;
position.x += SpeedPerTick * NumberOfTicksPassed;
Gonna be same speed no matter the rendering frames per second or game tick update rate(Hz).
2. B).
Loved this, a lot to chew on even for more experienced game devs! Just one extra thing, in 15:35 isn't there also a potential error where the jump input is checked after running movement code, introducing an extra frame of delay when a user wishes to jump?
Good catch :)
Funnily enough the case where you do a half step before and after is a better approximation in any case, as that corresponds to the midpoint RK2 method.
What also works for that case, and is also a valid RK2 method, is computing the average of both the speed at the start of the step and at the end of the step.
And of course there's even fancier methods like RK4:
(I will refer to the speed at the start as v0 for clarity)
Make one step with 1/2*deltaTime, store the speed resulting from that step in v1
Make one step from the starting position with v1, also 1/2*deltaTime, store the speed after that step as v2.
Then do one step, again from the start, this time with full deltaTime, using v2 and store the speed after that step as v3.
Now take a weighted average of 1/6 * v0 + 1/3 * v1 + 1/3 * v2 + 1/6* v3, lets call this result v, and then using this final v do the last step, yes, again from the start, with deltaTime. The resulting position will be your now even better approximation!
Is this horribly overkill for most games? Of course! But I'd be remiss not to mention it. :P
I dont think your right with the assumption that deltaTime lags behind 1 frame. Unity docs also state, that it's "The interval in seconds from the last frame to the current one".
So it's basically the time since last frame to the start of calculation of the current frame.
I briefly tested by logging Time.deltaTime ,Time.time and Time.frameCount. If you press Play in "Paused" mode you can see for the first frame the deltaTime is 0 but for the second frame you will get the correct deltaTime. If the deltaTime would be delayed by 1 frame you should see 0 for the first two frames. As there is nothing to compare against.
Interestingly Unity seems to be buggy in regards to the deltaTime. If you don't start with Pause enabled, you somehow get a deltaTime > 0 in the first frame. Also if you do start in Paused Mode but disable it after stepping a few frames. You will somehow get a deltaTime of 0 at the frame you disabled paused mode ¯\_(ツ)_/¯
I think this is an ambiguity with the phrase "current frame". In the video, he means the frame that hasn't been displayed yet, and the "start" of that frame is when it is displayed. But most game developers think about the "start" of the "current frame" as when the previous frame ended and the frame is displayed at the "end" of the frame rather than the "start".
This is just what I needed. Yesterday I realized that the most watched unity recoil tutorial had major mathematical errors and this perfectly summarizes how to avoid them. Thank you
GEARBOOOOOOOOX
Risk of rain 2 moment
This was truly such a treat to watch! As an experienced game developer myself, I am definitely sharing this with aspiring and junior devs around me as this is such an informative and fun way to understand the use of deltaTime. Big ups and don't mind making more of these videos! 😉
just when you think it starts to make sense
Using the mid point to calculate the average on an exponential function should be sufficiently accurate unless your frame time is extremely large. I do it for IRL ballistics calculations with an assumed time interval
Please more of this format!! It was helpful and entertaining at the same time!
Awesome video! Some time ago I made myself a helper function for the framerate-independent lerping function:
public static float SmoothLerpFactor(float smoothing, float deltaTime, bool fractional = false, float minFractionPerSecond = 0, float maxFractionPerSecond = float.PositiveInfinity)
{
float smoothingClamped = Mathf.Clamp01(smoothing);
//Mapping a [0, 1] range smoothing rate into a (0, infinity) exponential decay rate,
//so that 0 becomes infinity and 1 becomes 0.
float decayRate = smoothingClamped == 0 ? float.PositiveInfinity : (fractional ? Mathf.Log(1 / smoothingClamped) : 1 / smoothingClamped - 1);
float lerpFactor = 1 - Mathf.Exp(-decayRate * deltaTime);
if (deltaTime != 0)
{
//We ignore min and max speed if game is paused (in which case deltaTime = 0)
lerpFactor = Mathf.Clamp(lerpFactor, minFractionPerSecond * deltaTime, maxFractionPerSecond * deltaTime);
}
return lerpFactor;
}
It is used for example like this:
//Framerate-independent smoothdamping, this object's rotation follows another object's rotation smoothly:
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, SmoothLerpFactor(smoothing, Time.deltaTime));
The benefit to me is that the "smoothing" argument is between 0 and 1, and its intuition is that 0 = no smoothing, reach target instantly, and 1 = infinite smoothing, AKA never moving.
If you put the "fractional" argument to true, then "smoothing" will literally mean that (one minus) the fraction you want the object to reach after one second. So for example with "fractional" true, putting 0.5 to "smoothing" means that you want the object to move half of the remaining distance per second. Otherwise, the smoothing used is based on the exponential function with base e. The benefit of "fractional" = false is that if you use a slider for "smoothing" parameter in the inspector betwen 0 and 1, the values you're working with are more human. With "fractional" = false, setting "smoothing" to 0.01 can be the same as setting "smoothing" to 10e-12 with "fractional" as true, which is a hard value to work with in the inspector slider, and is more prone to floating-point approximation errors.
Thank you ! currently developing my first game now, and want speedrunning as a focus. So I'm always scared of having inconsistent results. I mostly do FixedUpdate stuff tho. Rb char controller. But anyone know any other areas I should look out for or ways to test this easy ? the lag spike was a neat trick. Edit: oh no, im actually doing all the speed calculation in Update, time to refactor some stuff... haha
Stumbled onto this video. The information is clear, the illustrations are all over, it's funny and witty, and has thought me something while maintaining my attention. I've been a dev for sometime but this video has by far explained this topic better than any other. You have gained a sub from me! Can't wait to check out your other content!
I disagree with your description of deltaTime, it's not the time between the last frame and the frame before that. It is the time elapsed between the START of the current frame and the START of the last frame. In most cases these mean the same thing, but it's usually implemented as I describe.
Ah, I see. Thanks for specifying that further. Should still work as described in the video then, right?
way easier to wrap your head around too, thanks
@@JonasTyroller Yes, the description of how it works is correct.
@@JonasTyroller Yeah you just worded it unintuitively. B could be interpreted as correct because you always set the current time at the start of a frame i.e. the frame that is being processed and the last time at the end (which becomes the start of the previous frame when the next frame starts).
I was just watching this video, thinking I knew most of this stuff (and I did, perks of my CS/Math degree) but still learned a lot nonetheless. I'm not surprised to learn that deltaTime is from the last frames, but never really thought about that much. Then at the end I noticed you're the developer of Thronefall and I got a bit envious I won't lie 😂
Oh and great video, I always love learning new things and cementing prior knowledge!
A little technical precision in times of "with AI everyone can make games without learning or hard work". Wonderful.
Coming from only knowing the maths and modelling side (basically just the engineering modelling stuff) and next to nothing about the game development side this is super useful - especially the intricacies of how an uneven interval can introduce issues and so on
It says 0-10 for an F, what happens if I got a -10?
give up
(just kidding, keep on learning)
Subscribed, i really like your fun way of explaining things
Most people try this and imo wind up compromising the quality of the video/explanation/etc but not here, this was great!
I always liked the fixed update per second model more. It is actually deterministic and it is a lot simpler to write and less bug prone.
Yes it will make the game run in slow motion if you are unable to achieve the TPS but also if you can not run quickly enough with delta time, you will get large deltas and possibly break the game in a bad way such as phasing trough walls, consuming more resources than exist and such so so much more.
Very cool video I def learned something new!! BUT, in the lerp example I will suggest instead of using Time.deltaTime only use Time.time and compare your current time to a starting time that you set when you want the animation to start. This will completely avoid all the problems that you listed without having to figure anything out (like average speed change and what not).
Tell me about it. Stop locking game logic to framerate. Most game engines have built in delta time functions to do all the work for you. It's really frustrating to play a cool game and have to lock my monitor's refresh rate manually.
The main point in the video is that it doesn't just magically do all the work for you, you can't just multiply everything by deltaTime and call it good in every situation. Some of this stuff uses kinds of math I hadn't even heard of before (integrals), and stuff I mostly get when seeing it but wouldn't come up with myself (the math.pow exponential bit). That being said, I test things and even wrote a separate thing to shoddily graph things out to test that it lines up, to make sure, but I found just using Time.deltaTime did not make what I was doing consistent across framerates, only close to it. It was years ago so I don't remember what it was, but I gave up and accepted the approximation because I had been at it for days, getting nothing done.
@@Aeroxima Yeah I actually made that comment before watching the video haha, just based on the title. It's way harder than I thought, so I get why some Devs don't use it. It's not rocket science as Jonas says, but it isn't particularly simple either. Really makes me respect and appreciate that much more the people that put in the work to get right.
Thank you so much! I rewatched this because I was having an issue with a game I was trying to make and figured it was a deltaTime issue, haha. Doing the half-and-half solution fixed it immediately!
Who cares if it works
Undertale is a barely working mass of steel wool and its one of the best selling indie games of all time
being a decent artist is infinitely better than being a superb dev when it comes to indie gamedev
it really isnt
all that trash pixel art and ""psx"" garbage isnt even hard to do
actual pretty games like ori are very very rare
look at pizza tower and cruelty squad those games are hideous and still popular@@blacktiger974
The scalable trick is to have separate threads for input, physics and rendering which get called at regular time intervals and sleep until next call once it is finished.
This way the motion is independent of the GPU power of the machine.
What grade do I get for a total of -10 points?
Negative F...
Educational and informative as always, but this is also funny as heck. At 10:34 I legit laughed so hard for like 2 minutes straight just at your delivery, that was so frickin funny, I was not prepared for that. 😂😂
On the first question, it really depends on what you mean by “current frame” - if the engine is measuring time at the end of the last frame, then that is also the time of the beginning of the current frame - which frame owns it is a matter of semantics.
Of course I don’t know when in the frame Unity records the current time, but in most game engines it is sandwiched between frames, if not using a fancy GPU readback scheme for “true” elapsed time.
So assuming Unity is like other engines, B would also be correct.
On the second question, I would deduct points for not including fixedDeltaTime (or equivalently and more portably, deltaTime) because including it makes your game logic independent from your choice of fixed time step - e.g. going from 60 to 30 Hz or vice-versa. You don’t want to have to change every single number in code or editor if you need to change the time step, that’d be a nightmare.
And perhaps most importantly, including the time step allows you to base velocities and such on real physical units, which gives you a frame of reference for understanding your hand-tuned variables, especially if comparing with values from other games.
Finally, it makes your code more readable imo, since it highlights that it is time-dependent simulation code, not an instantaneous change or something.
Third question, the first two integration techniques are explicit Euler (position before velocity update) and semi-implicit Euler (position after velocity update). The improved version rearranges to Verlet integration, if I’m not mistaken.
Verlet is often used in particle and fluid simulations, but is often considered overkill for physics sim. It’s close to zero added expense for something like a character controller however.
And as you noted, Verlet will still have error if velocity changes at a non-linear rate. Discontinuities may also present error as well.
But this is exactly why you perform this simulation in fixed update - there should never be that much error if the time step is fixed and never huge.
Final question - I’m impressed, almost nobody knows this! I use the “1 -“ version because I find the lerp more legible this way.
Your parameterization is essentially a “half life”, which in chemistry would be the time until half the initial quantity is reached, given an exponential decay. I actually parameterize as follows: “1 - Math.pow(v, Time.deltaTime * 60)”, where v is “change per 60th second,” a good frame of reference for game developers, that tends to retain accuracy for most values. (You’ll notice that Pow reduces to a no-op for 60 Hz refresh rate.) If you find yourself needing values close to the extremes of 0 and 1 however, you can change the 60 in order to retain accuracy. I’m actually really curious how your version would perform given extreme values, I imagine much better!
The way I derived this for myself was noticing that integration of addition becomes multiplication, thus integration of multiplication becomes exponentiation. This technique can be applied to any time-dependent update, and is invaluable for designing your own character controllers.
Great video! I hope a lot of Unity devs start standardizing this stuff in discussion, would help out sooooo many newbie devs!
I recommend everyone check out “Gaffer on Games” for some fantastic, approachable articles on all this stuff.
One more thing: it’s really important to understand that FixedUpdate doesn’t correspond 1-to-1 with real time. It actually plays “catchup” depending on how much varied time elapsed, executing a number of times (or none at all) until the most recent fixed update is AFTER the next regular update.
Why? So that Update can interpolate between the previous and future FixedUpdate based on its relative time, i.e. “p = lerp(p0, p1, w); w = (time - fixedTime0) / (fixedTime1 - fixedTime0)”. Strangely, Unity doesn’t seem to compute this weight for you anywhere, so you have to compute and maintain it yourself, but it’s extremely useful if you need to render something from FixedUpdate without using the built-in “transform,” or let FixedUpdate and Update talk to each other in a meaningful and accurate way.
If you’ve ever found yourself struggling to port code between Update and FixedUpdate, this may be the reason why.
16:17 I hate this I hate this I hate this I hate this PUT BRACKETS DOWN I'M GOING TO PALPITATE
16:29 Ah, so when simulating gravity such as in Brackey's FPS tutorial, I should not square time ( multiply by another Time.deltaTime ). Got it.
Crazy how I watched this around the time it came out and had no clue what was happening.
Roughly a year later, I come back and find I'm actually getting most of it.
Still have no clue what I'm doing, but hey, that's progress!
Super interesting to see integrals come into play here. I'm assming if you'd be exponentially increasing the speed then integrals would be the only solution.
Laughed from beginning to end of the video, you owed the follow. Thanks for the content!
This video is very entertaining and engaging!! I usually fall asleep to these technical type if videos. This video kept me totally into it with your delivery and graphics!