Hi, I'm Kyle Pittman. I'm a graduate of the Guildhall at SMU. I worked at Gearbox Software for 6 years and in 2013, my brother and I founded Minor Key Games and now we do indie development. Uh today I'm going to be talking about jumping in video games. The principles I'll be discussing can apply to platformers, both 2D and 3D, but it can also apply to uh first-person shooters or endless runners or really any sort of game that has a jumping mechanic. Our goal is going to be to move away from the trial and error that occurs when we start by defining physical constants up front. I've had this experience in my own development. Maybe some of y'all have had a similar experience, where you're working on a new project and you say, "All right, let's let's start by defining gravity. We'll say gravity is 9.8 m/s squared, real-world physics. That's a good place to start." And then we'll choose a jump velocity relative to that. Uh maybe we'll tweak these numbers a little bit, get something that feels sort of in the ballpark of what we expect our characters jump to look and feel like.
But then maybe we send the build to friends and get some feedback that says, "Jumping feels floaty." or "Jumping feels heavy." And you go, "Okay, how do we respond to this? How do we tune the feel of our game without potentially breaking things, you know, five levels down the road, because suddenly your character can't jump high enough to reach a platform or can't jump far enough to clear a gap?" And what we would like to do instead is start by describing a jump trajectory in terms that are familiar to us as players and as designers. I know that I need to jump this high. I know that I need to jump this far. And from that description, derive the mathematical uh Sorry, derive the mathematical uh parameters that we need to model this in code. So, we'll start with a few assumptions. We're going to be modeling our player character as a massless, frictionless particle in a vacuum, cuz game programmers love those, right? We're not going to worry about air friction or drag yet. We could bring those in later if we want to, but we're going to keep things simple for right now. Uh collision bounds don't matter whether
you're using a box or a sphere or a capsule, whatever, the math is going to be exactly the same. We're going to be representing our player character's state as a position in space, a velocity that they're currently traveling, and a constant downward acceleration due to gravity. So, let's look at gravity. Gravity is the one and only external force that's acting on our player character. It's constant over time. So, if we graph this out, it's just a flat line, and we can write this as an equation, f''(t) = g, and g is our gravitational constant. Now, from physics, we know that acceleration, velocity, and position are all related to each other in that they are derivatives and integrals of each other. So, if we know acceleration at any time, we can integrate with respect to time to find velocity. So, we'll go ahead and do that. And this gives us a function for velocity, f'(t) = gt plus we have to add an initial condition anytime we integrate, and we call this a v₀. This is our initial velocity.
When we graph this out, it's a descending line. In fact, the slope of that line is our gravitational constant g. We can integrate once more with respect to time to find a function for position, so we'll do that. And this gives us a function for position, f(t) = 1/2 gt² + v₀t + we add another initial condition when we integrate, p₀, and this is our initial position. And throughout the rest of this talk, I'll be assuming that our initial position is zero, that we're jumping from a ground height of zero, and that term just sort of goes away, but it's important to understand why that's there. And when we graph this one out, you can see it sort of has a nice smooth curve to it. It's sort of what you would expect to see if you plotted your player character's jump over time. Uh in fact, this equation is just the textbook physics 101 projectile motion formula. If you were asked to solve a physics problem about, you know, how high in the air is a baseball 5 seconds after being hit by a batter, this is probably the equation you would be using. And all that we did to get there is we started by saying gravity is the
one thing that affects us, and we integrated twice with respect to time. Now, this equation has another cool property, which is that this is a parabola. Algebraically, we can define a parabola as f of x = ax ^ 2 + bx + c. And substituting these values, you can see that our projectile motion formula does fit that description. And what that tells us is that the position and the path our player character follows as they are traveling through the air under the influence of gravity is a parabola. So, necessarily, any properties of parabolas that we can identify would also hold true for that path. So, let's look at some properties of parabolas next. Every parabola is symmetric about an axis of symmetry that intersects its vertex, what we would think of as the peak of the jump. So, what that tells us is that the duration of time from when we leave the ground to when we reach the peak of the jump is
going to be same as the time from the peak of the jump back down to the ground again. Every parabola is geometrically self-similar to every other parabola. And what that tells us sort of intuitively is that if we can find a uh sufficient set of constraints to describe a parabolic jump trajectory, for instance, a vertical axis of symmetry and desired height and distance, there's only one parabola that could pass through that set of points, that could fulfill those constraints. And finally, the uh the shape of a parabola, whether it's very wide and flat or very tall and narrow, this is entirely dependent on the quadratic coefficient a, which in our projectile motion formula is 1/2 g. And hopefully that intuitively makes sense as well that this would depend on gravity. As gravity gets stronger, we expect to see a steeper, sharper fall off on that curve. Now, for reference, the the B and C terms uh of this parabola would be the initial velocity, what we could think of as the tangent to the jump, and the initial
position, which is sort of just a translational offset on that graph. So, understanding that our player's jump trajectory is a parabola, and understanding some of these properties of parabolas, what we can do next is start designing a jump on paper. And for right now, we're going to be talking about standing in place, jumping straight up, and falling straight down. We aren't jumping sideways through space yet, but we'll get there. So, for right now, our X axis is time. So, we'll draw a graph of what we want our player's jump trajectory look like. I'll say we have some height that we want to Now, we'll call this height H. Maybe you have a platform that's 50 units off the ground, so you want your jump height to be a little bit above that. Next, we need to answer the question, how long does it take us to reach that height? And we'll call this duration T sub H. Now, because we know every parabola is symmetric, we know that the time at which we land back on the ground again will be 2 T sub H. Now, from this description, what we would like to do is calculate the
mathematical properties that we need to model this jump in code. And we need two things. We need to know gravity, and we need to know our initial jump velocity. So, we'll start by looking at velocity. We go back to our graph from earlier, and we say at time zero, we have some initial velocity V naught. We don't know what that is yet. That's one of the things we want to find. At time T sub H, our velocity is zero. This is the peak of the jump. This is when gravity has pulled down hard enough that we are momentarily weightless before we fall back to Earth. And then at time 2 T sub H, this is just as we're landing on the ground again, our velocity is equal in magnitude and opposite in direction to our initial velocity. So, this is negative V naught. So, we'll look at this point in the middle here where time is T sub H and velocity is zero and we'll substitute these values into our function for velocity and solve for V naught. And sort of skipping skipping to the end there, what this gives us is a solution for our initial
velocity V naught in terms of gravity, which we don't yet know, and the duration to the peak of the jump, which we've defined in advance. So, next we need to find a solution for gravity. So, to solve for gravity, we'll go to the graph of position that we just drew. We start at a height of zero at time zero. At time T sub H, we have some desired height H and then at time 2 T sub H, we've landed on the ground again. Our height is zero. From the previous slide, we know that we can express our initial velocity as a function of gravity and time. So, we'll substitute these values into our equation for position. And again, we'll look at this point in the middle where our height is H and our time is T sub H and we'll solve this for G. And again, sort of skipping through all the math there, what this gives us is a solution for our gravitational constant G in terms of the height and distance or in terms of the height and the duration of the jump. So, that's one of the two things we were
wanting to find. Now that we have a solution for gravity, we can go back to the previous slide where we wrote initial velocity in terms of gravity and we can substitute this in. And this gives us a solution for initial velocity also in terms of the height and the duration of the jump. So, to review, I know I'm skipping through a little bit of the math here quickly, but if you're taking notes or taking pictures on your cell phone, this would be probably one of the slides you'd want to remember. What we've done here is we've described a jump trajectory in terms of the height and in terms of the duration that it takes to get us to that height. And from that description, we can calculate the gravity and the initial velocity that we need to model this jump accurately in code. So, this is cool. This gets us some of the way to our goal. But as long as we're speaking about the height of the jump, it would also be useful to speak about the distance of the jump. And we can do that, but we need to introduce another parameter, which is how fast do we move side to
side. So, I'll be calling this lateral speed or foot speed. Uh depending on your game, depending on your application, this might not be a constant value. You might have some ramp up and ramp down time in your foot speed. You might have a different horizontal speed when you're running on the ground versus jumping through the air. But for the purposes of this talk, whatever the maximum horizontal speed that you could reach as you are moving through the air, whatever that is, that's the number we want to use. Uh it's also important to note here that you need to keep the horizontal and vertical components of your player character's velocity separate. If you're making a 2D platformer, this means keeping your X and Y values separate. If you're making a 3D platformer, whatever your up axis is, whether that's Y or Z, you need to keep that separate from movement in the horizontal plane. And when I say keep those separate, what I mean is if your player is running really fast sideways and they press the jump button, you don't want to kill that horizontal movement and jump straight up. You want to keep the horizontal movement going and just add a vertical
component to that. Uh we also have this relationship among three parameters now. Previously, we were speaking about the duration of the jump, the time to reach the peak of the jump, Tsub H. Now we're going to start talking about the horizontal distance that we cover on the way to the peak of the jump, and we're also going to be talking about our foot speed, Vsub X. You can pick two of these, but the third one necessarily has to be a function of the other two. So, for my money, I think it makes the most sense to define the horizontal distance to the peak of the jump and define the foot speed and allow the duration of the jump to be a function of those just because when we're talking about the duration of a jump, usually we're talking about fractions of a second and that's not necessarily the most intuitive thing to speak about or the most intuitive thing to design up front. So just as before, we're going to draw a graph of what we would like our jump trajectory to look like only now we're jumping through space. So our x-axis is distance rather than time.
And in fact, you could draw this graph over a representative scene from your game, especially if you're making a 2D platformer. You could say, well, I have a platform this high or I have a pit of spikes that's this long. I know that I need to jump that high or that far to cross those. So we're defining our jump now in terms of the height, but also the distance horizontally that we cover on the way to the peak of the jump and we call that x sub h and then we have our lateral foot speed and we call that v sub x. So just as before, we want to find gravity and we want to find initial velocity because those are the things we need to model this in code. And to do this, we're going to take the equations we found previously for those values and make some substitutions. So on the left here, we have a substitution for t sub h, the duration to the peak of the jump. We can rewrite this as x sub h, the horizontal distance to the peak of the jump, divided by our lateral foot speed v sub x. On the top row, we have the equations we
found previously for initial velocity and gravity and on the bottom row, we've substituted that t sub h term with the substitution from the side. So again to review, this would probably be one of the slides you'd want to get a picture of. What we've done is we've started by describing an ideal desired jump trajectory in terms of height, in terms of distance and in terms of how fast our player character moves side to side. And from that description, we can calculate gravity, and we can calculate initial velocity, and we have everything that we need to model this jump in code. So, this is pretty cool. This gets us a little bit further. But at this point, we're still talking about very perfect parabolic jumps. And while that might be true to real-world physics in the case of this massless, frictionless particle in a vacuum, it's not necessarily the most fun or interesting or good-feeling thing for a video game. So, what we'd like to do next is start looking for ways that we can break the rules a little bit while
still relying on these properties and knowing that we can design our jump and trust that we're going to reach a certain height and distance. And to do this, we're going to do start thinking about our jump trajectory not as a single parabola, but as multiple segments of partial parabolas. And to give you a a real-world example of a game that does this sort of rule-breaking, in in the original Super Mario Brothers, uh I think this was mentioned in Steve Swink's book, Game Feel. In the original Super Mario Brothers, Mario runs and jumps and flies through the air, and he reaches the peak of his jump, and suddenly gravity triples, and Mario falls like a brick. Now, there's nothing real-world physics about a sudden increase in gravity at the peak of a jump, but that treatment is part of what gives Mario his characteristic, trademark sense of weight, along with a slow ramp-up and ramp-down time on his sideways movement. It's what makes him feel different than other video game characters. And we'd
like to look for ways that we can bring those sorts of unique characteristics to our own game. So, let's look at an example. Uh we'll we'll take the same example of falling faster beyond the peak of the jump. We can start by drawing a jump trajectory exactly as we have in the past in terms of height and distance and lateral foot speed, but that's not shown here. But once we get to the peak of the jump, we'll break it there and we'll draw a different curve on the other side, a different part of a different parabola, one with the same height, but a shorter distance. Now from the materials that we've already covered, we have everything that we need to calculate an initial velocity and a gravity for each part of this trajectory. We only need the initial velocity for the first part as our character is taking off from the ground. But what we do then is we would apply gravity over time for the first half of the curve. And when we reach the peak of the jump, encode when the vertical component of our velocity goes from positive to
negative, we would switch over and start applying the heavier gravity corresponding to the second half of this trajectory. And when you play this back in real time, you would see your character follow a trajectory trajectory just like this. They would fly through the air, have sort of a nice smooth ascent, and they would reach the peak of their jump and fall much faster. We can do a similar thing for variable height jumping. Variable height jumping tends to be communicated to the player in terms of hold the button down longer to jump higher. But the way we would think about this in code is we would treat the maximum height that the player could ever reach as the default. That's where we get our initial velocity from. And if the player releases the jump button early before they've reached the peak of the jump, we switch over to a heavier gravity value to reach the peak sooner. So in this graph here, uh where the line goes from blue to red, that's the moment where the player has released the jump button.
You can see another outline of blue an outline in blue in the back, and that represents sort of that maximum jump height that they could reach if they kept the button held down. You can see another smaller outline in red, and that's a minimum jump height. If you were to just feather the button on and off again for a split second, you would still want to cover some distance. So, that's where this minimum jump height comes from. And that's that corresponds to the gravity that we used to bring the player character to the peak of their jump sooner. Now, once we reach the peak of the jump, we have a few options. In this graph, I show us reverting back to the original gravity, so we have sort of a nice smooth descent on the other side. But, you could also remain at a heavier gravity value if the player had released the button sooner. Or you could even combine this technique with the one from the previous slide and say, "Regardless of whether the player released the button early, we always switch to a different falling gravity beyond the peak of the jump." Uh if you're implementing double jumping or any number of multi-jumps, you could define each stage of the jump as a
separate parabola. Define these in terms of height and distance again, just as we have in the past, and calculate an initial velocity and a gravity for each each stage of this jump. In this case, you would need to know the initial velocity for that second part, because you would be treating that just like a jump from a standstill in that case. So, throughout this talk I've been mentioning that we need two things to model a jump in code. We need gravity and we need initial velocity. So, let's talk a little bit about how this works. With initial velocity, as soon as the player presses the jump button, we want to apply that to the player character's current state. But again, it's important to note that you want to decouple your horizontal movement from your vertical. You don't want to kill horizontal movement and just jump straight up. You want to keep horizontal movement going and apply a vertical component to that. A gravity needs to be applied over time, so for that one we need to talk about integration.
Generally speaking, integration solves the problem of we have some previous game state, and then there's been some passage of time, and we want to predict with as much accuracy as possible what the next game state is going to be. In any engine or any framework, you're going to have the same sort of uh integration with this passage of time. This might be a variable amount of time, it might be constant, it might be sort of obscured a little bit, but that's always there and your math does need to account for that. So, the easiest way to do this is with Euler integration. We increment our position by velocity multiplied by delta time. We increment velocity by acceleration multiplied by delta time. So, this is easy, right? But, it's not very stable and in the worst-case scenario, the player might perceive a difference in the way their character handles, for instance, if a lot of stuff is happening on the screen and the frame rate drops. And those are the sorts of inconsistencies that we would like to avoid. So, on the far end of the spectrum, we have the Runge-Kutta methods. And RK4 in particular.
I don't have pseudo code for this one because it tends to be very wordy, but I would point to the Gaffer On Games article Integration Basics as a really great overview of what this might look like in an actual game development scenario. However, my takeaway from that article and from some of the comments on that article is that if all we're doing is dealing with this sort of projectile motion, the Runge-Kutta methods are way more complex than what we need. We can actually find an integration method that is every bit as accurate, but much, much simpler to write. So, let's take a look at velocity Verlet next. The way velocity Verlet is written, you start off similar to Euler integration, you increment position based on velocity, but then we have this term 1/2 acceleration times the square of the delta time. Then you calculate a new acceleration value as a function of position. You increment your velocity by an interpolation halfway between the previous and new acceleration values. And then you commit the change to acceleration.
So, this is interesting. It's definitely, you know, simpler to write than Runge-Kutta methods, but it's not necessarily applicable to our situation because in our case gravity is mostly constant except for those few places where we've chosen to break the rules and increase or decrease gravity. So, maybe we can simplify this a little bit further. What's also interesting to notice here is we have this 1/2 acceleration times the square of the delta time term. And that sort of recalls our original projectile motion formula. And in fact, if we think about it in those terms, we have this projectile motion formula and that already answers the question of given any set of initial conditions, for instance, the previous game state, we know with 100% accuracy where our player is going to be at any time in the future, for instance, after this delta time. So, if we were to simplify velocity Verlet, assuming a constant acceleration, this would actually correspond directly to our projectile
projectile motion formula and we could trust that we are getting 100% accurate results. But what about those times when we do deliberately break the rules a little bit and we say, "We reach the peak of the jump, we increase gravity." How much error do we accumulate in those cases if we were to just naively integrate this way assuming a constant acceleration? Uh that error would be on the the order of the change in acceleration from the previous frame to the new one multiplied by the square of the delta time. Now, when I ran these numbers on one of my own games, this error was about half a pixel and this isn't something that would accumulate over an entire session and eventually throw things out of whack. This is a one-time offset that gets zeroed out the next time your player character lands on the ground. So, I would argue this is a perfectly acceptable amount of error and if you've been using Euler integration and if you're dealing with projectile motion, I would recommend giving this simplified
velocity Verlet integration method a try. I think you'll be really happy with the results. So, to review, our goal has been to move away from trial and error, move away from defining physical constants up front, and move in a direction where we can describe a jump trajectory in terms that are familiar to us as players and as designers. I know that I want to jump this high and this far, and then we want to lean on those abilities to craft a unique individual characteristic jump trajectory that can give our particular game its own unique feel. And we use we still can trust that it's going to feel rooted in the truth of gravity constantly pulling our player character down. So, oops. I'll plug my own game here real quick. I have a game on Steam. Uh it's called You Have to Win the Game. It's free, like actually free, not in-app purchases free. And it uses most of the principles I've talked about here today. So, if you have a chance to try that, um hopefully you'll like the way it feels and be convinced that this is a good method to
follow. Uh you can find me on Twitter as well at PirateHearts. Uh my websites are minorkeygames.com and gunmetalarkadia.com, another platformer I'm making that uses all of these same principles. But uh that's it for me. Thank you for your time. All right. Uh I guess we do have time for some questions. So, if anyone wants to uh come up to the mic there. Could you put up the slide with the game velocity simplification part? Oh, yeah, absolutely. Uh yeah, that one. Um I guess I wanted to ask you quickly. Um I know you briefly mentioned Super Mario Bros. as a way of as an example of good jumping. Are there like any other games you want to mention that have examples of good or bad jumping? Um I haven't analyzed others as specifically as that one, but I would point to Super Meat Boy as a really good example of having a unique characteristic sort of fluidity, but you know, fluidity necessarily doesn't
always feel good, but they managed to make it feel good in that way. I think it was a combination of you know, the way the character moves, but also interacts with walls and his, you know, wall jumping and all those sorts of abilities. Thank you. Yeah, thanks. Now, if anyone else has another question, I guess we have time for one more. All right, let's thank Kyle.
Auto-generated captions from YouTube — names and numbers may be misheard.
Distilling the key insights…
Game Developers Conference · 2026
Game Developers Conference · 2023
Comments