# Megarunner 5 - Jumping Math

Posted December 2, 2019

NOTE:
This tutorial is most likely not compatible with versions of SGDK above 1.70. Unfortunately, I simply do not have the capacity or ability to update them right now. Read more about it here. Sorry.

### Hold up!

If you like 90s platformers, check out my new game Kid Bubblegum!

Now that we have obstacles, we need to enable the player to jump over them. However, in order to do that we need to use math. Don’t panic, SGDK makes it quite simple. Let’s go!

## Fixed Point Math

To make the player jump we’ll have to change his vertical velocity to move him upwards, then apply gravity to pull him back down so that we get a jumping arc. We could do this using variables of type `int`, but this would lead to very hectic and jerky movement, because there’s just not much precision. So we’ll just use `floats`, right? That way we can get smoother movement.

Well…yes and no. The thing is, using variables of type `float` is very expensive on retro hardware such as the Mega Drive. This might seem weird, but if you recall that irrational numbers exist, it makes a bit more sense. So using floats is not the way to go here.

Luckily there is a way to “fake” floats, and even more luckily, SGDK can do it for us! Introducing: Fixed-point arithmetic! Don’t worry: You don’t have to work through the theory and understand how they work. Using them in SGDK is straightforward and we’ll learn as we go. So let’s finally dive in!

## Setting Up

First we’ll need to define some variables that we will use. Add the following variable near the top of `main.c` which will store the vertical velocity of the player:

``````fix16 player_vel_y = FIX16(0);
``````

And here we’re already getting to some new stuff. As you can see, the variable is of the type `fix16`, which means it’s a 16bit fixed number variable. Since the player won’t be moving vertically at the beginning, we want to assign 0 to it…but we can’t exactly do that, because `0` would be a regular `int`. In order to turn it into a `fix16` we have to use the helper function `FIX16(X)`, which will turn the value X into a `fix16`. So even if we only assign a constant (like 0, 6 or -14) we have to convert them to a `fix16` first. Keep that in mind!

And while we’re up here we’ll change the `player_y` variable as well, because otherwise we’d add a `fix16` velocity value to an `int` position value:

``````fix16 player_y = FIX16(112);
``````

And finally, we’ll add these variables that’ll help us with jumping:

``````int player_height = 16;
const int floor_height = 128;
fix16 gravity = FIX16(0.2);
bool jumping = FALSE;
``````

The variable `player_height` stores the height of the player. The constant `floor_height` will specify how high the floor is. `gravity` on the other hand needs to be a `fix16` as a gravity value of `1` would be too strong, leading to wonky jumping arcs. `jumping` will keep track of whether the player is currently in the air or not. We’ll be using all of these in a second.

## Jumping

Now to implement the jumping mechanic! First, we’ll check if the player has pressed the jump button. Add the following statement to your `myJoyHandler` callback function:

``````if (state & BUTTON_C)
{
if(jumping == FALSE){
jumping = TRUE;
player_vel_y = FIX16(-4);
SPR_setAnim(player,ANIM_JUMP);
}
}
``````

This is what we’re doing: If C is pressed while the player is on the ground (meaning “not jumping”, meaning `jumping == FALSE`), we set jumping to `TRUE`. Then we set the player’s vertical velocity to -4, which will launch him upward. Remember to use `FIX16(-4)` as `player_vel_y` is of type `fix16`! Finally we set the player’s animation to `ANIM_JUMP` which we’ve defined in the previous step of this tutorial.

Now let’s head to our main game loop and put some code inside the `if(game_on == TRUE){...}` statement. We need to actually apply the player’s velocity to its position so that the sprite will move. Add this between the scrolling code and the obstacle code:

``````//Apply velocity
``````

Here is the next new thing: If you want to add two variables of type `fix16`, you will have to use the function `fix16Add(a,b)` which will return the sum of `a` and `b`. Just doing `player_y + player_vel_y` wouldn’t cut it in this case! As you can see, working with `fix16` values isn’t exactly harder, you just have more stuff to remember.

Okay, now let’s head to the end of the game loop and tell SGDK where to put our sprite. Put the following line before (or after) `SPR_setPosition(obstacle,obstacle_x,120);`:

``````SPR_setPosition(player,player_x,fix16ToInt(player_y));
``````

We’re using yet another `fix16` helper function here: `fix16ToInt(X)`. As the name implies, this converts a `fix16` value to a regular `int`. We have to do this here, because `SPR_setPosition` expects an `int` value as the Mega Drive obviously can’t render anything smaller than 1 pixel.

But anyway, if you try the game now, the player should jump when you press C…and bing, ZOOM, will go straight to the Moon. Obviously we’ll need some gravity!

## Gravity

Let’s add some gravity after we apply the jumping velocity to the player:

``````//Apply gravity
if(jumping == TRUE) player_vel_y = fix16Add(player_vel_y, gravity);
``````

We only have to worry about gravity when the player is in the air, so we’ll only add it to the player’s vertical velocity while `jumping == TRUE`. This line will drag the player back down by a value of `gravity` per frame (which in our case is 0.2).

But of course the player will now jump majestically into the air, only to drop through the floor on his way down and fall eternally. Clearly we need some collision code to make sure the player stops when he hits the ground! So let’s add this big ol' chunk of code right after the previous lines:

``````//Check if player is on floor
if(jumping == TRUE && fix16ToInt(player_y)+player_height >= (floor_height)){
jumping = FALSE;
player_vel_y = FIX16(0);
player_y = intToFix16(floor_height-player_height);
SPR_setAnim(player,ANIM_RUN);
}
``````

Let’s break down the conditional. First we check if the player is currently jumping and thus in the air. Then we check whether the bottom edge of the player sprite (which would be the y-position + its height) is lower than the `floor_height` we defined previously. We have to use `fix16ToInt(X)` again here, because `player_height` is of type `int`, and you can’t simply add a `fix16` and an `int` without converting one of them first.

Okay, so if the player is currently in the air and has reached the floor, we:

1. Set `jumping` to `FALSE` as the player is no longer jumping
2. We set `player_vel_y` to `0` so the player stops falling
3. We position the player on top of the floor (in case the sprite slipped into it)
4. We change the animation of the player back to `ANIM_RUN`.

Phew! That was a lot of stuff, but compile the game now and we should have a working jump. If you want, try playing with the values to make the player jump higher, increase gravity, etc. to see the effects.

Oh and you might notice that the player isn’t positioned correctly at the beginning of the game…his vertical position is off. Maybe I forgot something…? hint hint

I hope this part wasn’t too complex or dry, despite all the math shenanigans. As you can see, using fixed-point math in SGDK isn’t really difficult, just a bit more cumbersome. Next time we’ll actually turn the obstacles into hazards by adding collision and a points system, so that players are rewarded for jumping over them. Thank you for reading and until next time!

If you've got problems or questions, join the official SGDK Discord! It's full of people a lot smarter and skilled than me. Of course you're also welcome to just hang out and have fun!

### Join my Discord Server!

Hang out, get news, be excellent!

### Want To Buy Me a Coffee?

Coffee rules, and it keeps me going! I'll take beer too, though.

## Check out the rest of this tutorial series!

By using the Disqus service you confirm that you have read and agreed to the privacy policy.