Mario-Style Asymmetric Jump in Godot 4
I wanted the character in my platform game to feel better when jumping: a bit floaty on the way up, but quick and responsive on the way down.
The problem
A single gravity value gives you one of two bad options:
- High gravity → snappy landing, but the jump feels stiff (no hang time at the apex).
- Low gravity → nice floaty peak, but the descent is sluggish and the landing feels like moonwalking.
Mario, Celeste, and most good platformers solve this with asymmetric gravity: gentle pull while rising, stronger pull while falling.
The idea
Instead of exposing raw gravity numbers (hard to reason about), expose three intuitive targets:
| Parameter | What it means |
|---|---|
jump_height | How high the jump peaks (metres) |
jump_rise_time | Seconds to reach the apex (up phase) |
jump_fall_time | Seconds to fall back down (down phase) |
Then derive gravity and launch speed from kinematics:
| |
Since jump_fall_time < jump_rise_time, the fall gravity is automatically stronger.
Setup
- Create a Resource script for tuning values.
- Use it in your
CharacterBody3Dplayer script.
The tuning resource
| |
Create a .tres file: right-click in the FileSystem -> New Resource -> PlayerTuning, then set:
jump_height= 2.6jump_rise_time= 0.34jump_fall_time= 0.26
These values give a jump that peaks around 2.6m with a noticeable hang at the top and a quick drop back down.
The player script
| |
That’s the whole technique: 6 lines of physics.
How it works
| |
When _vy > 0 (rising), we use jump_rise_time to compute gravity:
| |
When _vy <= 0 (falling), we use jump_fall_time:
| |
The fall gravity is about 1.7x stronger, so the descent is noticeably quicker than the ascent. The apex feels floaty because the upward gravity is gentle: the player lingers near the peak before dropping.
Tuning tips
| Want… | Change |
|---|---|
| Higher jump | Increase jump_height (keeps timing the same) |
| More hang time at apex | Increase jump_rise_time |
| Snappier landing | Decrease jump_fall_time |
| Moon jump | jump_height = 5.0, jump_rise_time = 0.6 |
| Tight, responsive hop | jump_height = 1.5, jump_rise_time = 0.2, jump_fall_time = 0.18 |