Gravity
A constant change to a character's vertical speed every frame, usually up to a fastest fall.
On this page
In a platformer, gravity is a constant added to the character’s downward speed on every update, usually with a cap on the fall. Super Mario Bros., Mega Man 2, Super Mario World, Sonic the Hedgehog, and Celeste all work this way. Castlevania’s jump has no gravity at all; a table moves Simon1.
- NoneCastlevania (1986). The arc is fixed, and past its end Simon drops at one steady speed.1,2Castlevania III: Dracula's Curse (1989). The arc is fixed frame by frame, and a long fall never gets faster than 6 px a frame.3
- One gravityCastlevania II: Simon's Quest (1987). One gravity on every jump, with a capped fall.4Mega Man (1987). One gravity, whatever the button does.5Mega Man 2 (1988). One gravity, whatever the button does.6,7,8Mega Man 3 (1990). The same gravity as Mega Man 2, but a slower top falling speed.9Sonic the Hedgehog 2 (1992). One pull of gravity whether the button is held or not, lighter underwater.10Sonic 3 & Knuckles (1994). The pull of the first two games, the same whether the button is held or not.11
- Switch on releaseSuper Castlevania IV (1991). Gravity waits a few frames while the button is held, then slows the rise.12
- Lighter while heldSuper Mario World (1990). A lighter gravity on any frame the button is held.13,14,15Castlevania: Symphony of the Night (1997). Hold the button and he floats at the top of the jump.16
#Across games
Moving first means each frame’s step is the speed it began with. Super Mario Bros.17, Mega Man 27, Super Mario World18, and Sonic19 all do this. Celeste adds gravity before it moves Madeline20.
| Gravity | Fastest fall | Units | |
|---|---|---|---|
| Super Mario Bros. | 0.117–0.156 px/frame² ($1E–$28)21 held, 0.375–0.5625 px/frame² ($60–$90)22 after the switch | 4 px/frame23 | 8.8 fixed point17 |
| Castlevania | none in the arc1 | 8 px/frame2, past the table | whole pixels1 |
| Mega Man 2 | 0.25 px/frame² ($40)6 | 12 px/frame8 | 8.8 fixed point7 |
| Super Mario World | 0.1875 px/frame² held, 0.375 released13 | 4.375 px/frame (4.1875 holding the button)14 | sixteenths of a pixel15 |
| Sonic the Hedgehog | 0.21875 px/frame² ($38)24 | none25 | 8.8 speed, 16.16 position19 |
| Celeste | 900 px/s²26 | 160 px/s27 | float px/s, whole-pixel positions28 |
The caps aren’t always the plain minimum. Super Mario Bros. tests the speed’s fraction before clamping, so a fall can briefly run past the cap29. Super Mario World clamps first and adds gravity after, so its fastest fall is the cap plus a frame of gravity14.
Several games tie gravity to the jump button, which is how variable jump height works in the two Mario games30,13. Celeste halves gravity near the top of a held jump31.
Banjo-Kazooie halves its gravity through a held jump and restores it for the rest of the jump once A is up on the rise32. With A held, the lighter gravity lasts past the peak, as in Super Mario World13, where Super Mario Bros. swaps on release or at the peak30. Sonic Advance 2 adds 0.1640625 px/frame²33 on each frame of a jump, held or not, except a frame where Sonic’s forward thrust or a mid-air move starts33. The gravity is three quarters of what Sonic’s ObjectFall adds24. Metroid Fusion and Metroid: Zero Mission also ignore the button, at 0.1875 px/frame²34 and 0.3125 px/frame²35 out of liquid. Like Castlevania1, Prince of Persia has no gravity in its jumps; only a fall speeds up, by 3 px/cycle per cycle, from 15 up to 3336. In a decompilation that doesn’t yet match, Super Mario Sunshine’s jump gravity is 0.8 by default (data on the disc)37, a default the game’s own data can replace37.
Mega Man 3 keeps Mega Man 2’s gravity but caps a fall at 7 px/frame, where Mega Man 2 allows 129. Sonic the Hedgehog 2 adds 0.21875 px/frame² ($38)10 on each airborne frame, and Sonic 3 & Knuckles keeps that gravity from Sonic 1 and Sonic 211.
Castlevania II: Simon’s Quest adds the gravity Castlevania lacks: 0.21875 px/frame² on every airborne frame, with a fall capped at 3 px/frame4. Castlevania III: Dracula’s Curse keeps the table for every character but Grant, and a long fall holds at 6 px/frame where Castlevania’s reaches 83. Super Castlevania IV holds the take-off speed with no gravity for up to 4 frames while the button stays down, then adds 0.375 px/frame² each frame and caps a fall at 8 px/frame12. Castlevania: Symphony of the Night adds 0.171875 px/frame² on each jumping frame, a fifth of that near the top while Cross is held, and caps a fall at 7 px/frame16.
Games
| Game | Year | How | Note |
|---|---|---|---|
| Felix the Cat | 1992 | 45/256 px a frame per frame, to 6 px a frame | |
| Metroid | 1986 | One gravity | 0.09375 px/frame² in a jump, 0.0703 with the High Jump Boots, held or not |
| Castlevania II: Simon's Quest | 1987 | One gravity | one gravity on every jump, with a capped fall |
| Contra | 1987 | One gravity | 0.137 px/frame² on every airborne frame |
| Mega Man | 1987 | One gravity | one gravity, whatever the button does |
| Mega Man 2 | 1988 | One gravity | one gravity, whatever the button does |
| Prince of Persia | 1989 | One gravity | a fall adds 3 px per cycle to the speed, up to 33, or 1 up to 4 while weightless |
| Mega Man 3 | 1990 | One gravity | the same gravity as Mega Man 2, but a slower top falling speed |
| Super C | 1990 | One gravity | Contra's 0.137 px/frame², with falls capped at 5 px/frame |
| Sonic the Hedgehog | 1991 | One gravity | one pull of gravity whether the button is held or not, and a jump's fall isn't capped |
| Sonic the Hedgehog 2 | 1992 | One gravity | one pull of gravity whether the button is held or not, lighter underwater |
| Mega Man 6 | 1993 | One gravity | the same pull on every frame, lighter in one kind of tile |
| Sonic 3 & Knuckles | 1994 | One gravity | the pull of the first two games, the same whether the button is held or not |
| Super Metroid | 1994 | One gravity | 0.109375 px/frame² in air, held or not, with lighter values in water and lava |
| Pilotwings 64 | 1996 | One gravity | the gyrocopter adds a gravity of 9.8 on the world's vertical every update, scaled by the frame time |
| Quake | 1996 | One gravity | 800 units/s² every frame out of water, 100 on E1M8 |
| Super Mario 64 | 1996 | One gravity | 4 units/frame² in most jumps and 2 in the long jump, down to −75 |
| Pokémon Pinball | 1999 | One gravity | 11/256 px per frame² on the ball, 8.8 fixed point |
| Metroid Fusion | 2002 | One gravity | 0.1875 px/frame² in air, held or not, two-thirds of that in liquid without the Gravity Suit |
| Sonic Advance 2 | 2002 | One gravity | 42/256 px/frame² in a jump, held or not, three quarters of Sonic 1's |
| Super Mario Sunshine | 2002 | One gravity | a parameter, 0.8 an update by default, down to −75, with a lighter one in a spin jump's descent |
| Metroid: Zero Mission | 2004 | One gravity | 0.3125 px/frame² in air, held or not, halved in liquid without the Gravity Suit |
| Super Mario Bros. | 1985 | Switch on release | a light pull while A is held on the way up, a heavier one after |
| Super Mario Bros.: The Lost Levels | 1986 | Switch on release | Super Mario Bros.'s light pull while A is held on the way up, lighter still for Luigi |
| Super Castlevania IV | 1991 | Switch on release | gravity waits a few frames while the button is held, then slows the rise |
| Banjo-Kazooie | 1998 | Switch on release | −1350 units/s² through a held jump, −2700 once A is up on the rise, and past the peak only if A stays held |
| Super Mario Bros. 2 | 1988 | Lighter while held | each character has a lighter gravity for any frame the button is held |
| Super Mario Bros. 3 | 1988 | Lighter while held | 1/16 px/frame² while A is held on a fast rise, 5/16 otherwise |
| Super Mario World | 1990 | Lighter while held | a lighter gravity on any frame the button is held |
| Castlevania: Symphony of the Night | 1997 | Lighter while held | hold the button and he floats at the top of the jump |
| Celeste | 2018 | Lighter while held | one gravity, halved near the apex while jump is held |
Every claim about this mechanic, by game (63)
References
- ^ abcdeSimon's jump rises by a fixed table of per-frame steps, 5, 5, 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 1, 0, 0, 0, and 0 px, 36 px in all.Code“Castlevania (USA) (Rev 1)”
How we know
In the cartridge (“Castlevania (USA) (Rev 1)”): bank 6 $9B8D-$9BA4, the table's address, a $80 start marker, 20 signed steps ($FB = −5, up), and a $81 turn marker; bank 6 $9B1E-$9B8A, the routine that adds one step to Simon's Y each frame and moves the table pointer. We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abOnce the reversed table runs out, the arc routine moves Simon down 8 px every frame until he lands, so a jump that ends below its take-off point falls at 8 px per frame.Verified“Castlevania (USA) (Rev 1)”
How we know
In the cartridge (“Castlevania (USA) (Rev 1)”): bank 6 $9B43-$9B5E: on the $80 marker the step is $F8, negated while falling to +8, and the pointer stays put. We don't reproduce the bytes.
Measured by a script in MesenCE 2.2.1 (build 4b8a196), on Castlevania (USA) (Rev 1) (SHA-1
4e3ef47de86a…). It fails if the result disagrees with the claim.The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-22.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-22.
- ^ abDracula's Curse keeps Castlevania's jump for every character but Grant; the take-off starts the arc at entry 9 of a longer table whose entries from there are Castlevania's 20 rises, 5, 5, 3, 3, 3, 3, 3, 2, 2, 2, 1, 1, 1, 1, 0, 1, 0, 0, 0, and 0 px, and the 8 entries before it, 6 then 5 px, carry a fall below the take-off height down to 6 px/frame, where Castlevania falls at 8 px/frame once its table runs out.Codevinheim3/castlevania3-disasm · “Castlevania III - Dracula's Curse (USA)” · “Castlevania (USA) (Rev 1)”revised
How we know
3740playerState06_jumpStart_exceptGrant:code/playerStateProcessing_b1c.s lines 3740–3751 at 3272648 · upstream ↗ lda $9874, y … cmp #$81 … sta wEntityVertSpeed.w, x … inc $05d8, x … cmp #$80 … dec $05d8, x … eor #$ff … lda $9875, y
code/playerStateProcessing_b1c.s#L4187-L4225 · upstream ↗ 3242processTrevorState: ⋮ 3249 .dw playerState06_jumpStart_exceptGrant 3250 .dw playerState08_jumping_exceptGrant
code/playerStateProcessing_b1c.s lines 3242–3250 at 3272648 · upstream ↗ 4751processSyphaState: ⋮ 4758 .dw playerState06_jumpStart_exceptGrant
code/playerStateProcessing_b1c.s lines 4751–4759 at 3272648 · upstream ↗ 918processAlucardState: ⋮ 926 .dw playerState06_jumpStart_exceptGrant
code/playerStateProcessing_b1d.s lines 918–927 at 3272648 · upstream ↗ 4784processGrantState: ⋮ 4791 .dw playerState06_jumpStart_grant 4792 .dw playerState08_jumping_0c_grant
code/playerStateProcessing_b1c.s lines 4784–4792 at 3272648 · upstream ↗ In the cartridge (“Castlevania III - Dracula's Curse (USA)”): bank $1C $9874-$9891: $80, five $FA (−6), five $FB (−5), five $FD, three $FE, four $FF, $00, $FF, four $00, and $81; the disassembly lists these bytes partly as instructions. We don't reproduce the bytes.
In the cartridge (“Castlevania (USA) (Rev 1)”): Castlevania's table of 20 steps (castlevania/jump-table); Castlevania's 8 px fall past the table (castlevania/table-end-fall). We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
- ^ abSimon's Quest replaces Castlevania's step table with a speed and gravity; a jump from the ground takes off at 4 px/frame up, every airborne frame adds 0.21875 px/frame² of gravity, and a fall is capped at 3 px/frame, where Castlevania steps a fixed 20-entry table and falls past its end at 8 px/frame.Code“Castlevania II - Simon's Quest (USA)” · “Castlevania (USA) (Rev 1)”
How we know
In the cartridge (“Castlevania II - Simon's Quest (USA)”): bank 3 $88D9-$892A, the take-off: Y speed $036C.$037E = −4.0 ($FC.$00), the action set to jumping, and the held d-pad read into the X speed and facing; bank 3 $89D6-$8A0D, each jumping frame: zero the speed on a ceiling, add $38 to the speed's fraction ($DFE4), and cap a fall at 3.0; bank 7 $DFE4-$DFF9, a 16-bit add of $0008 to object X's Y speed. We don't reproduce the bytes.
In the cartridge (“Castlevania (USA) (Rev 1)”): Castlevania's jump table, 20 signed steps between a $80 and a $81 marker (castlevania/jump-table); Castlevania's fall past the table's end, 8 px per frame (castlevania/table-end-fall). We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^Each airborne frame takes
$40/256 = 0.25 px/frame off Mega Man's upward speed, and a fall is capped at 12 px/frame ($F4).Codelsmmega/mm1How we know
96@is_megaman_2: 97 LDA aobject_ycoord_speed_fraction, X 98 SBC #$40 99 STA aobject_ycoord_speed_fraction, X 100 LDA aobject_ycoord_speed, X 101 SBC #$00 102 BPL @normal_ycoord_speed 103 CMP #$F4 104 BCS @normal_ycoord_speed 105 LDA #$00 106 STA aobject_ycoord_speed_fraction, X 107 LDA #$F4 ⋮
engine/objects_vertical.asm lines 96–110 at b606a84 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abcGravity takes
$40/256 = 0.25 px/frame from Mega Man's upward speed each frame out of water ($1E/256 in water).Codelsmmega/mm2How we know
175tsa_ycoord_speed_accelerate_fraction_table: 176 .BYTE $40, $1E
engine/check_object_horizontal_move.asm lines 175–176 at 94f0bf3 · upstream ↗ 73@air: 74 SEC 75 LDA aobject_ycoord_speed_fraction 76 SBC z:zobject_ycoord_speed_accelerate_fraction 77 STA aobject_ycoord_speed_fraction 78 LDA aobject_ycoord_speed 79 SBC z:zobject_ycoord_speed_accelerate 80 STA aobject_ycoord_speed
engine/check_object_vertical_move.asm lines 73–80 at 94f0bf3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abc
_check_object_vertical_movefirst moves Mega Man by his 8.8 fixed-point speed, positive up, and then subtracts gravity.Codelsmmega/mm2How we know
13 SEC 14 LDA aobject_ycoord_fraction 15 SBC aobject_ycoord_speed_fraction 16 STA aobject_ycoord_fraction 17 LDA aobject_ycoord 18 SBC aobject_ycoord_speed 19 STA aobject_ycoord
engine/check_object_vertical_move.asm lines 12–19 at 94f0bf3 · upstream ↗ engine/check_object_vertical_move.asm#L73-L80 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abFalling speed is capped at 12 px/frame (
$F4).Codelsmmega/mm2How we know
81 BPL @skip 82 CMP #$F4 83 BCS @skip 84 LDA #$00 85 STA aobject_ycoord_speed_fraction 86 LDA #$F4 87 STA aobject_ycoord_speed
engine/check_object_vertical_move.asm lines 81–87 at 94f0bf3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abMega Man 3 raises the take-off speed from Mega Man 2's
$04.$DF(4.87 px/frame) to$04.$E5(4.89) and keeps gravity at$40, but caps a fall at 7 px/frame ($F9) where Mega Man 2 allows 12 ($F4).Codeplasticsmoke/megaman3-disassembly-ca65 · lsmmega/mm2How we know
74 lda #$E5 ; normal jump: Y vel = $04.E5 75 sta ent_yvel_sub,x ; store Y velocity sub-pixel 76 lda #$04 ; Y velocity whole = $04 77 sta ent_yvel,x ; store Y velocity whole
src/fixed/player_ground.asm lines 74–77 at 58ca1c3 · upstream ↗ 648prelude_setup_per_frame: lda #$40 ; gravity = $40 for player physics 649 sta gravity ; (process_sprites sets $55 for entities)
src/fixed/game_loop.asm lines 648–649 at 58ca1c3 · upstream ↗ 393apply_gravity_player_check: lda ent_yvel_sub,x ; Y sub velocity -= gravity 394 sec ; prepare for subtraction 395 sbc gravity ; subtract gravity value 396 sta ent_yvel_sub,x ; store new Y sub velocity 397 lda ent_yvel,x ; Y velocity -= borrow 398 sbc #$00 ; propagate borrow to whole byte 399 sta ent_yvel,x ; store new Y velocity 400 bpl apply_gravity_exit ; still positive (rising)? done 401 cmp #$F9 ; check against terminal velocity $F9 402 bcs apply_gravity_exit ; within limit (-7 to -1)? done
src/fixed/movement.asm lines 393–402 at 58ca1c3 · upstream ↗ 175tsa_ycoord_speed_accelerate_fraction_table: 176 .BYTE $40, $1E ⋮ 181tsa_regular_water_jump_speed_table: 182 .BYTE $04, $05 ⋮ 184tsa_regular_water_jump_speed_fraction_table: 185 .BYTE $DF, $80
engine/check_object_horizontal_move.asm lines 175–185 at 94f0bf3 · upstream ↗ 81 BPL @skip 82 CMP #$F4 83 BCS @skip 84 LDA #$00 85 STA aobject_ycoord_speed_fraction 86 LDA #$F4 87 STA aobject_ycoord_speed
engine/check_object_vertical_move.asm lines 81–87 at 94f0bf3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ ab
ObjectMoveAndFalladds$38subpixels/frame to Sonic's downward speed each airborne frame, and underwater the air modes take$28back, leaving$10.Codesonicretro/s2disasmHow we know
30216 move.w y_vel(a0),d0 ; load y speed 30217 addi.w #$38,y_vel(a0) ; increase vertical speed (apply gravity)
s2.asm lines 30216–30217 at 4ef457c · upstream ↗ 36582 subi.w #$28,y_vel(a0) ; reduce gravity by $28 ($38-$28=$10)s2.asm lines 36575–36582 at 4ef457c · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ ab
MoveSpriteadds$38subpixels/frame to a falling player's speed, Sonic 1's and Sonic 2's gravity, and underwater the air modes take$28back.Codesonicretro/skdisasm · sonicretro/s1disasm · sonicretro/s2disasmrevisedHow we know
36077 move.w y_vel(a0),d0 ; load y speed 36078 addi.w #$38,y_vel(a0) ; increase vertical speed (apply gravity)
sonic3k.asm lines 36077–36078 at 73de97c · upstream ↗ 22446 jsr (MoveSprite_TestGravity).l ⋮ 22449 subi.w #$28,y_vel(a0) ; reduce gravity by $28 ($38-$28=$10)
sonic3k.asm lines 22442–22449 at 73de97c · upstream ↗ gravity: equ $38
_incObj/sub ObjectFall & SpeedToPos.asm#L5 · upstream ↗ 30217 addi.w #$38,y_vel(a0) ; increase vertical speed (apply gravity)s2.asm line 30217 at 4ef457c · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
- ^ abSuper Castlevania IV's jump holds the take-off speed with no gravity while the jump button stays down, for up to 4 frames, then adds 0.375 px/frame² each frame until the rise stops, holds Simon still at the top for about 9 frames, and falls under the same gravity, capped at 8 px/frame.Code“Super Castlevania IV (USA)”
How we know
In the cartridge (“Super Castlevania IV (USA)”): $00:A3FA-$A409, state 4 each frame: animation, facing ($A792), air control ($A8DE), then the phase routine $A94D; $00:A94D-$A9CF: phases by $1F86. 0: while the button in $BE is held, count $0564 to 4, else go on; 1–2: gravity ($A739) until the speed is ≥ 0, then 0; 3–4: speed 0, count to 9; 5–6: gravity; $00:A739-$A769: Y speed + $0000.$6000 (0.375); a fall at or past 8.0 is set to 8.0. We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abcdEach frame
CODE_00D928adds 3/16 px/frame to Mario's vertical speed while A or B is held and 6/16 otherwise, rising or falling.CodeSMWDisXHow we know
10167DATA_00D7A5: ;! 10168 db $06,$03,$04,$10,$F4,$01,$03,$04 ;!
bank_00.asm lines 10167–10169 at 30643c7 · upstream ↗ 10439CODE_00D928: 10440 LDY.B #$01 10441 LDA.B byetudlrHold 10442 BMI + 10443CODE_00D92E: 10444 LDY.B #$00
bank_00.asm lines 10439–10444 at 30643c7 · upstream ↗ 10457CODE_00D948: ;! 10458 CLC ;! 10459 ADC.W DATA_00D7A5,Y ;!
bank_00.asm lines 10457–10459 at 30643c7 · upstream ↗ 821 + LDA.W axlr0000P1Hold,X ;\ 822 AND.B #!ButA|!ButX ;| Set up $15, sharing the top two bits of controller data 2 (for A/X). 823 ORA.W byetudlrP1Hold,X ;| 824 STA.B byetudlrHold ;/
bank_00.asm lines 821–824 at 30643c7 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abcGravity's routine cuts a downward speed above
$40(4 px/frame) back to$40before adding gravity, so Mario falls at most 70/16 px/frame, or 67/16 holding the button.VerifiedSMWDisXHow we know
10171DATA_00D7AF: ;! 10172 db $40,$40,$20,$40,$40,$40,$40,$40 ;!
bank_00.asm lines 10171–10173 at 30643c7 · upstream ↗ 10446 + LDA.B PlayerYSpeed+1 ;! \ If Mario's Y speed is negative (up), 10447 BMI CODE_00D948 ;! / branch to $D948 10448 CMP.W DATA_00D7AF,Y ;! 10449 BCC + ;! 10450 LDA.W DATA_00D7AF,Y ;!
bank_00.asm lines 10446–10450 at 30643c7 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ ab
CODE_00DC4Fadds a speed's low nybble to a subpixel byte and its high nybble, sign-extended, plus the carry to the 16-bit position, so Mario moves in sixteenths of a pixel.CodeSMWDisXHow we know
10909CODE_00DC4F: ;! 10910 LDA.B PlayerXSpeed+1,X ;! 10911 ASL A ;! 10912 ASL A ;! 10913 ASL A ;! 10914 ASL A ;! 10915 CLC ;! 10916 ADC.W PlayerXPosSpx,X ;! ⋮ 10920 LDA.B PlayerXSpeed+1,X ;! ⋮ 10930 ADC.B PlayerXPosNext,X ;!
bank_00.asm lines 10909–10933 at 30643c7 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abEach jumping frame adds 0.171875 px/frame² to Alucard's vertical speed, a fifth of that while Cross is held near the top (between 0.125 px/frame up and 0.375 down), and caps a fall at 7 px/frame.CodeXeeynamo/sotn-decomp
How we know
591 if (func_8010FDF8(0x11029)) {src/dra/71830.c line 591 at 2be55ee · upstream ↗ 17 if (branchFlags & 0x10000) { ⋮ 20 g_Player.padPressed & PAD_CROSS) { 21 YAccel = FIX(22.0 / 128 / 5); 22 } else { 23 YAccel = FIX(22.0 / 128); ⋮ 31 } else { 32 YAccel = FIX(22.0 / 128); ⋮ 40 PLAYER.velocityY += YAccel; ⋮ 42 if (PLAYER.velocityY > FIX(7)) { 43 PLAYER.velocityY = FIX(7);
src/dra/6FDF8.c lines 17–44 at 2be55ee · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abVertical motion is 8.8 fixed point; each frame,
ImposeGravityadds speed to position, the fraction via theYMF_Dummysubpixel byte, then gravity to speed.CodeXkeeper0/smb1How we know
6668 ADC SprObject_Y_MoveForce,x 6669 STA SprObject_YMF_Dummy,x ⋮ 6676 ADC SprObject_Y_Position,x ; add vertical position to vertical speed plus carry ⋮ 6683 ADC $00 ; add downward movement amount to contents of $0433 ⋮ 6685 LDA SprObject_Y_Speed,x ; add carry to vertical speed and store
src/prg.asm lines 6666–6687 at 1cc3c92 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-27.
- ^Each frame the player routine moves Mario by his current speed (
CODE_00DC2D), then handles a jump press (CODE_00D5F2), then adds gravity (CODE_00D7E4), so the press frame doesn't lift him and his first step up is the take-off speed plus held gravity.CodeSMWDisXHow we know
8897CODE_00CD24: ⋮ 8904 + JSR CODE_00DC2D 8905 JSR CODE_00E92B
bank_00.asm lines 8897–8905 at 30643c7 · upstream ↗ 8946CODE_00CD82: 8947 JSR CODE_00D5F2 8948 JSR CODE_00D062 8949 JSR CODE_00D7E4
bank_00.asm lines 8946–8949 at 30643c7 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abIn the running game,
ObjectFallandSpeedToPosmove Sonic's 32-bit position each frame by his speed shifted left 8 bits, X by this frame's X speed and Y, in the air, by the Y speed before gravity, so positions are 16.16 and speeds 8.8 fixed point.Verifiedsonicretro/s1disasm · Sonic Retro, “Sonic Physics Guide: Calculations (Pixel and Subpixel)”How we know
16 move.w obVelY(a0),d0 ; load vertical speed 17 addi.w #gravity,obVelY(a0) ; increase vertical speed (apply gravity) 18 ext.l d0 ; extend speed to longword 19 asl.l #8,d0 ; shift speed up a byte (16.16 fixed point) 20 add.l d0,d3 ; add speed to Y-axis position
_incObj/sub ObjectFall & SpeedToPos.asm lines 16–20 at 15dfa3a · upstream ↗ Each pixel is effectively split into 256 slices along both axis and this means the finest fidelity available for movement is 1/256th of a pixel (aka 0.00390625).
Pixel and Subpixel · archived copy ↗ Measured by a script. It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-25.
Checked by a second AI model, 2026-10-25.
- ^In each update,
Player.Updateticks both jump timers, the state machine runsNormalUpdate(gravity, hold, and new jump), and thenMoveVappliesSpeed.Y * Engine.DeltaTime.CodeNoelFB/Celeste · JamesMcMahon/monocle-engineHow we know
742 //Var Jump 743 if (varJumpTimer > 0) 744 varJumpTimer -= Engine.DeltaTime;
Source/Player/Player.cs lines 742–744 at 1b0ce45 · upstream ↗ 908 base.Update();Source/Player/Player.cs line 908 at 1b0ce45 · upstream ↗ 935 MoveV(Speed.Y * Engine.DeltaTime, onCollideV);Source/Player/Player.cs lines 934–935 at 1b0ce45 · upstream ↗ 323 StateMachine.SetCallbacks(StNormal, NormalUpdate, null, NormalBegin, NormalEnd);Source/Player/Player.cs lines 322–323 at 1b0ce45 · upstream ↗ 97 Components.Update();Monocle/Entity.cs lines 95–98 at 759c15a · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-27.
- ^While a jump rises with A held, gravity is
JumpMForceData's$20,$20,$1E,$28,$28subpixels/frame² for rows 0–4.CodeXkeeper0/smb1 · Jdaster64 n.d.How we know
4858JumpMForceData: 4859 .db $20, $20, $1e, $28, $28, $0d, $04
src/prg.asm lines 4858–4859 at 1cc3c92 · upstream ↗ 4966 LDA JumpMForceData,y ; store appropriate jump/swim 4967 STA VerticalForce ; data here
src/prg.asm lines 4966–4967 at 1cc3c92 · upstream ↗ 00200 | 001E0 | 00280
JUMPING/VERTICAL PHYSICS, Mario table, Holding “A” Gravity (+Y) · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-27.
- ^After the switch, gravity is
FallMForceData's$70,$70,$60,$90,$90subpixels/frame² for rows 0–4.CodeXkeeper0/smb1 · Jdaster64 n.d.How we know
4861FallMForceData: 4862 .db $70, $70, $60, $90, $90, $0a, $09
src/prg.asm lines 4861–4862 at 1cc3c92 · upstream ↗ 4968 LDA FallMForceData,y 4969 STA VerticalForceDown
src/prg.asm lines 4968–4969 at 1cc3c92 · upstream ↗ 00700 | 00600 | 00900
JUMPING/VERTICAL PHYSICS, Mario table, Falling Gravity (+Y) · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-27.
- ^
MovePlayerVerticallygivesImposeGravity4 px/frame as Mario's maximum fall speed; the clamp sets the speed back to 4 only when its whole part is at least 4 and its fraction byte at least$80.CodeXkeeper0/smb1 · Jdaster64 n.d.revisedHow we know
6549 LDA #$04 ; set maximum vertical speed here 6550 JMP ImposeGravitySprObj ; then jump to move player vertically
src/prg.asm lines 6547–6550 at 1cc3c92 · upstream ↗ 6688 CMP $02 ; compare to maximum speed ⋮ 6691 CMP #$80 ; if less positively than preset maximum, skip this part ⋮ 6694 STA SprObject_Y_Speed,x ; keep vertical speed within maximum value ⋮ 6696 STA SprObject_Y_MoveForce,x ; clear fractional
src/prg.asm lines 6688–6696 at 1cc3c92 · upstream ↗ their vertical downward velocity caps at 04800 in most cases, wrapping back to 04000 when exceeded
JUMPING/VERTICAL PHYSICS · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Revised after a check by a second AI model, 2026-10-27: The clamp sets the speed back to 4 only when its whole part is at least 4 and its fraction at least $80, so 4 px/frame alone overstated it.
- ^ abcIn the running game,
ObjectFall's gravity equate adds$38(0.21875 px/frame²) to Sonic's Y speed on every airborne frame, rising or falling, after a jump or off a ledge, button held or not.Verifiedsonicretro/s1disasm · Sonic Retro, “Sonic Physics Guide: Air State”How we know
5gravity: equ $38 ; gravity constant used by many objects_incObj/sub ObjectFall & SpeedToPos.asm line 5 at 15dfa3a · upstream ↗ 363 jsr (ObjectFall).l ; apply gravity and update Sonic's position based on his current velocities_incObj/01 Sonic.asm line 363 at 15dfa3a · upstream ↗ gravity_force 0.21875 (56 subpixels)
Constants · archived copy ↗ Measured by a script. It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-25.
Checked by a second AI model, 2026-10-25.
- ^In the running game, a Y speed written into a jump, −
$1100rising or$FC0falling, is neither capped nor clamped: gravity keeps adding$38, to −$10C8a frame later and to$1068before he lands, becauseSonic_JumpHeightskips its −$FC0cap after jumps (FixBugs = 0).Verifiedsonicretro/s1disasm · Sonic Retro, “Sonic Physics Guide: Air State”revisedHow we know
1291.return: 1292 if FixBugs=0 1293 ; This prevents the max Y-vel cap from running while jumping 1294 rts ; return ⋮ 1300 cmpi.w #-$FC0,obVelY(a0) ; is Sonic moving up just below the maximum screen scroll speed? (-$1000)
_incObj/01 Sonic.asm lines 1291–1302 at 15dfa3a · upstream ↗ In Sonic 1, the Player's Y Speed is not limited.
Top Y Speed · archived copy ↗ Measured by a script. It fails if the result disagrees with the claim.
The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-25.
Revised after a check by a second AI model, 2026-10-25.
- ^Celeste's gravity is 900 px/s²; each airborne update moves vertical speed toward the fall limit by
Gravity * mult * Engine.DeltaTime.CodeNoelFB/CelesteHow we know
24 private const float Gravity = 900f;Source/Player/Player.cs line 24 at 1b0ce45 · upstream ↗ 2957 Speed.Y = Calc.Approach(Speed.Y, max, Gravity * mult * Engine.DeltaTime);Source/Player/Player.cs line 2957 at 1b0ce45 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-27.
- ^
MaxFall, the normal limit on falling speed, is 160 px/s;NormalBeginstartsmaxFallthere and gravity approaches it.CodeNoelFB/CelesteHow we know
23 public const float MaxFall = 160f;Source/Player/Player.cs line 23 at 1b0ce45 · upstream ↗ 2762 maxFall = MaxFall;Source/Player/Player.cs lines 2760–2763 at 1b0ce45 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-27.
- ^Celeste's actors sit on whole pixels;
MoveVadds the float distance to a remainder, moves by its rounded value, and keeps the fraction.Dev blogThorson 2020 · NoelFB/CelesteHow we know
xRemainder += amount; int move = Round(xRemainder); if (move != 0) { xRemainder -= move;
Actor Basics · archived copy ↗ 935 MoveV(Speed.Y * Engine.DeltaTime, onCollideV);Source/Player/Player.cs line 935 at 1b0ce45 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-27.
- ^
ImposeGravityclamps a fall of 4 px/frame or more only when the fraction byte is at least$80.CodeXkeeper0/smb1 · Jdaster64 n.d.How we know
6688 CMP $02 ; compare to maximum speed 6689 BMI ChkUpM ; if less than preset value, skip this part 6690 LDA SprObject_Y_MoveForce,x 6691 CMP #$80 ; if less positively than preset maximum, skip this part 6692 BCC ChkUpM
src/prg.asm lines 6688–6696 at 1cc3c92 · upstream ↗ their vertical downward velocity caps at 04800 in most cases, wrapping back to 04000 when exceeded
JUMPING/VERTICAL PHYSICS · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-27.
- ^ ab
JumpSwimSubswaps in falling gravity, never back, once speed is zero or downward, or once the jump has risen at leastDiffToHaltJumpon a frame when A is not held, or was not held the frame before.CodeXkeeper0/smb1 · Jdaster64 n.d.revisedHow we know
4757 BPL DumpFall ; or moving downwards, branch to falling ⋮ 4760 AND PreviousA_B_Buttons ; and was pressed in previous frame 4761 BNE ProcSwim ; if so, branch elsewhere ⋮ 4765 CMP DiffToHaltJump ; compare to value set here to see if player is in mid-jump ⋮ 4768 LDA VerticalForceDown ; otherwise dump falling into main fractional 4769 STA VerticalForce
src/prg.asm lines 4756–4769 at 1cc3c92 · upstream ↗ so long as they are moving upward in a jump, holding “A” will make them rise more slowly
JUMPING/VERTICAL PHYSICS · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-27.
Revised after a check by a second AI model, 2026-10-27: "Not held both this frame and last" read two ways; held gravity stays only while A is held on both frames.
- ^Gravity halves while |
Speed.Y| is underHalfGravThresholdand jump is held (or auto-jump is on), so a held jump hangs at the top.CodeNoelFB/CelesteHow we know
2952 float mult = (Math.Abs(Speed.Y) < HalfGravThreshold && (Input.Jump.Check || AutoJump)) ? .5f : 1f;Source/Player/Player.cs line 2952 at 1b0ce45 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-27.
- ^A jump sets Banjo's vertical speed to 710 units/s (610 from water) and his gravity to −1350 units/s², half the usual −2700, and sets his horizontal speed at once to the target speed the stick gives on the ground (banjo-kazooie/walking-speed). On a frame of the jump with A up while he still rises,
bsjump_updateresets the gravity to −2700 for the rest of the jump; nothing sets −1350 again, and with A held the lighter gravity lasts past the peak. Until Banjo has learned the ability the code namesABILITY_A_HOLD_A_JUMP_HIGHER, it resets the gravity every frame. A jump entered from a peck sets neither the speed nor the gravity. A take-off from a spring pad sets a flag that skips the reset; the first frame with A up clears it after the check, so the reset starts the frame after. While that flag is set, the jump's second phase turns into the Shock Spring Jump's charge (BS_21_BSHOCK_CHARGE). Leaving the jump state for anything but a peck restores −2700. Computed without the frame steps, a held jump rises about 187 units in 0.53 s, and one released at once about 93. Super Mario 64 instead adds a quarter of the forward speed to its take-off (sm64/jump-speed) and divides the rise by 4 on each frame A is up while Mario rises faster than 20 units/frame (sm64/jump-release).Codebanjo.decomp/banjo-kazooie · n64decomp/sm64revisedHow we know
20f32 D_80364CD0 = 710.0f; 21f32 D_80364CD4 = -1350.0f;
src/core2/bs/jump.c lines 20–21 at e8d31fa · upstream ↗ 25f32 D_80364CE4 = 610.0f;src/core2/bs/jump.c line 25 at e8d31fa · upstream ↗ 41 D_8037D4C2 = baflag_isTrue(BA_FLAG_2_ON_SPRING_PAD);src/core2/bs/jump.c line 41 at e8d31fa · upstream ↗ 47 if(sp30 == BS_11_BPECK){ ⋮ 52 D_8037D4C0 = 1; ⋮ 54 else {
src/core2/bs/jump.c lines 47–54 at e8d31fa · upstream ↗ 55 D_8037D4C1 = (sp30 == BS_2D_SWIM_IDLE) || (sp30 == BS_2E_SWIM);src/core2/bs/jump.c line 55 at e8d31fa · upstream ↗ 69 func_802B6FA8(); 70 baphysics_set_horizontal_velocity(yaw_getIdeal(), baphysics_get_target_horizontal_velocity()); 71 if(D_8037D4C1){ 72 baphysics_set_vertical_velocity(D_80364CE4); 73 } else { 74 baphysics_set_vertical_velocity(D_80364CD0); ⋮ 76 baphysics_set_gravity(D_80364CD4);
src/core2/bs/jump.c lines 69–76 at e8d31fa · upstream ↗ 101 baphysics_get_velocity(velocity); 102 if((bakey_released(BUTTON_A) && 0.0f < velocity[1] && !D_8037D4C2) || !can_control_jump_height()){ 103 baphysics_reset_gravity();
src/core2/bs/jump.c lines 101–104 at e8d31fa · upstream ↗ 121 case 1://L802B14B4 122 if( 500.0f < (playerPosition_getY() - func_80294438())){ 123 sp34 = BS_2F_FALL; ⋮ 125 if(D_8037D4C2){ 126 D_8037D4C2 = 0; 127 sp34 = BS_21_BSHOCK_CHARGE;
src/core2/bs/jump.c lines 121–128 at e8d31fa · upstream ↗ 143 if(bakey_released(BUTTON_A)) 144 D_8037D4C2 = 0;
src/core2/bs/jump.c lines 143–144 at e8d31fa · upstream ↗ 171 if (bs_getNextState() != BS_11_BPECK) { 172 baphysics_reset_gravity();
src/core2/bs/jump.c lines 171–173 at e8d31fa · upstream ↗ 50 bakey.released_count[i] = bakey.pressed_count[i] 51 ? 0 52 : bakey.released_count[i] + 1;
src/core2/bakey.c lines 50–52 at e8d31fa · upstream ↗ 79int bakey_released(s32 button_indx){ 80 return bakey.released_count[button_indx];
src/core2/bakey.c lines 79–81 at e8d31fa · upstream ↗ 10f32 baphysics_default_gravity = -2700.0f; //defaultGravity 11f32 baphysics_default_terminal_velocity = -4000.0f;
src/core2/ba/physics.c lines 10–11 at e8d31fa · upstream ↗ 397void baphysics_reset_gravity(void){ 398 baphysics_set_gravity(baphysics_default_gravity);
src/core2/ba/physics.c lines 397–399 at e8d31fa · upstream ↗ 67s32 can_control_jump_height(void){ 68 return ability_hasLearned(ABILITY_A_HOLD_A_JUMP_HIGHER);
src/core2/playerutils.c lines 67–68 at e8d31fa · upstream ↗ 821 case ACT_JUMP: 822 case ACT_HOLD_JUMP: ⋮ 824 set_mario_y_vel_based_on_fspeed(m, 42.0f, 0.25f); 825 m->forwardVel *= 0.8f;
src/game/mario.c lines 821–826 at 9921382 · upstream ↗ 559 } else if (should_strengthen_gravity_for_jump_ascent(m)) { 560 m->vel[1] /= 4.0f;
src/game/mario_step.c lines 559–560 at 9921382 · upstream ↗ 528 if (!(m->input & INPUT_A_DOWN) && m->vel[1] > 20.0f) { 529 return (m->action & ACT_FLAG_CONTROL_JUMP_HEIGHT) != 0;
src/game/mario_step.c lines 528–529 at 9921382 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^ abEach frame of a jump, button held or not,
Player_JumpingaddsPLAYER_GRAVITY, 42/256 px/frame² (12/256 in water), to the vertical speed throughPLAYERFN_UPDATE_AIR_FALL_SPEED, except on a frame where Sonic's forward thrust or a mid-air move starts (Player_Sonic_TryForwardThrust,Player_TryMidAirAction):Player_Jumpingreturns before the gravity then. That is three quarters of the gravity Sonic 1's airborne-rolling mode,Sonic_MdJump2, adds throughObjectFall,$38(56/256) a frame (computed).CodeSAT-R/sa2 · sonicretro/s1disasmrevisedHow we know
18#define PLAYER_GRAVITY (42.0 / 256.0) 19#define PLAYER_GRAVITY_UNDER_WATER (12.0 / 256.0)
include/game/shared/parameters/characters.h lines 18–19 at 393357f · upstream ↗ 200#elif (GAME == GAME_SA2) 201#ifndef COLLECT_RINGS_ROM 202#define PLAYERFN_UPDATE_AIR_FALL_SPEED(player) \ 203 if (player->moveState & MOVESTATE_IN_WATER) { \ 204 player->qSpeedAirY += Q(PLAYER_GRAVITY_UNDER_WATER); \ 205 } else { \ 206 player->qSpeedAirY += Q(PLAYER_GRAVITY); \
src/game/shared/stage/player.c lines 200–207 at 393357f · upstream ↗ 7017 if (p->moveState & MOVESTATE_100) { 7018#ifndef COLLECT_RINGS_ROM 7019 if (gGameMode != GAME_MODE_MULTI_PLAYER_COLLECT_RINGS) 7020 if (Player_Sonic_TryForwardThrust(p) || Player_TryMidAirAction(p)) 7021 return;
src/game/shared/stage/player.c lines 7017–7021 at 393357f · upstream ↗ 7039 SA2_LABEL(sub_80232D0)(p); ⋮ 7041 PLAYERFN_UPDATE_AIR_FALL_SPEED(p); 7042 PLAYERFN_UPDATE_POSITION(p);
src/game/shared/stage/player.c lines 7039–7042 at 393357f · upstream ↗ 5gravity: equ $38 ; gravity constant used by many objects_incObj/sub ObjectFall & SpeedToPos.asm line 5 at 15dfa3a · upstream ↗ 359Sonic_MdJump2: ; While Sonic is in the air and rolling (usually, but not limited to, jumping) ⋮ 363 jsr (ObjectFall).l ; apply gravity and update Sonic's position based on his current velocities
_incObj/01 Sonic.asm lines 359–363 at 15dfa3a · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^Out of liquid,
SamusUpdatePhysicssets the vertical acceleration to 6 and the vertical speed cap to 128, andSamusUpdateVelocityPositiontakes 6 fromyVelocityon every frame of the airborne poses while the velocity is above -220, whether A is held or not: 0.1875 px/frame², with rises and falls both capped at 4 px/frame (computed). In water, lava, or acid without the Gravity Suit or the flag the decompilers nameSMF_SA_X_SUIT, the acceleration drops to 4 and the cap to 48, 0.125 px/frame² and 1.5 px/frame. Zero Mission's gravity is 10, 0.3125 px/frame², with the same 4 px/frame fall cap (computed).Codemetroidret/mf · metroidret/mzmHow we know
326#define SAMUS_Y_ACCELERATION (SUB_PIXEL_TO_VELOCITY(ONE_SUB_PIXEL * .75f)) 327#define SAMUS_Y_VELOCITY_CAP (SUB_PIXEL_TO_VELOCITY(QUARTER_BLOCK_SIZE)) ⋮ 335#define SAMUS_TERMINAL_VELOCITY (SUB_PIXEL_TO_VELOCITY(HALF_BLOCK_SIZE - PIXEL_SIZE - ONE_SUB_PIXEL / 2.f))
include/constants/samus.h lines 326–335 at a6d6187 · upstream ↗ 137 switch (currentHazard) ⋮ 139 case HAZARD_WATER: 140 gSamusUnderwaterFlag++; ⋮ 142 case HAZARD_LAVA: 143 case HAZARD_ACID: 144 if (!(gEquipment.suitMiscStatus & (SMF_GRAVITY_SUIT | SMF_SA_X_SUIT))) 145 slowed++; 146 break; ⋮ 151 slowed++; ⋮ 160 gSamusPhysics.yAcceleration = SAMUS_Y_ACCELERATION * 2.f / 3; 161 gSamusPhysics.yVelocityCap = SAMUS_Y_VELOCITY_CAP * 0.375f; ⋮ 174 gSamusPhysics.yAcceleration = SAMUS_Y_ACCELERATION; ⋮
src/samus.c lines 137–175 at a6d6187 · upstream ↗ 5526 // Check is within the bounds 5527 if (gSamusData.yVelocity > gSamusPhysics.yVelocityCap) ⋮ 5529 else if (gSamusData.yVelocity < -gSamusPhysics.yVelocityCap) 5530 velocity = VELOCITY_TO_SUB_PIXEL(-gSamusPhysics.yVelocityCap); 5531 else ⋮ 5534 // Apply acceleration 5535 if (gSamusData.yVelocity > -SAMUS_TERMINAL_VELOCITY) 5536 gSamusData.yVelocity -= gSamusPhysics.yAcceleration; ⋮ 5538 gSamusData.yPosition -= velocity;
src/samus.c lines 5526–5538 at a6d6187 · upstream ↗ 324#define SAMUS_Y_ACCELERATION 10 325#define SAMUS_Y_POSITIVE_VELOCITY_CAP 192 326#define SAMUS_Y_NEGATIVE_VELOCITY_CAP 128 327#define SAMUS_Y_SLOWED_VELOCITY_CAP 40
include/constants/samus.h lines 324–327 at 2aae289 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^Out of liquid (or in it with the Gravity Suit) and not held by a Metroid,
SamusUpdatePhysicssets the vertical acceleration to 10 each frame, andSamusUpdateVelocityPositiontakes it fromyVelocityon every frame of the airborne poses while the velocity is at least -231, whether A is held or not: 0.3125 px/frame² (computed). A fall moves at most 128, 4 px/frame. In water, lava, or acid without the Gravity Suit, or out of liquid in a Metroid's grip, the acceleration halves to 5 and both caps drop to 40, 1.25 px/frame. Metroid's jump gravity is 0.09375 px/frame² (0.0703 with the High Jump Boots), and its falls reach 5 px/frame.Codemetroidret/mzm · nmikstas/metroid-disassemblyHow we know
324#define SAMUS_Y_ACCELERATION 10 325#define SAMUS_Y_POSITIVE_VELOCITY_CAP 192 326#define SAMUS_Y_NEGATIVE_VELOCITY_CAP 128 327#define SAMUS_Y_SLOWED_VELOCITY_CAP 40
include/constants/samus.h lines 324–327 at 2aae289 · upstream ↗ 2649 case HAZARD_TYPE_WATER: 2650 case HAZARD_TYPE_LAVA: 2651 case HAZARD_TYPE_WEAK_ACID: 2652 case HAZARD_TYPE_STRONG_ACID: 2653 // In liquid, check has gravity to see if slowed 2654 if (!(pEquipment->suitMiscActivation & SMF_GRAVITY_SUIT)) 2655 slowed++; 2656#ifndef BUGFIX 2657 break; 2658#endif ⋮ 2660 default: 2661 // Check grabbed by metroid ⋮
src/samus.c lines 2649–2697 at 2aae289 · upstream ↗ 6762 else if (pData->yVelocity < -gSamusPhysics.negativeYVelocityCap) ⋮ 6764 velocity = DIV_SHIFT(-gSamusPhysics.negativeYVelocityCap, 8); ⋮ 6766 else ⋮ 6771 if (pData->yVelocity >= -231) ⋮ 6773 pData->yVelocity -= gSamusPhysics.yAcceleration; ⋮ 6776 pData->yPosition -= velocity;
src/samus.c lines 6762–6776 at 2aae289 · upstream ↗ 2693LCFF3: LDY #$18 ; gravity (high value -> low jump) 2694 LDA SamusGear 2695 AND #gr_HIGHJUMP 2696 BEQ + ; branch if Samus doesn't have High Jump 2697 LDY #$12 ; lower gravity value -> high jump! 2698* STY SamusGravity
Source_Files/Bank07.asm lines 2693–2698 at 4270d57 · upstream ↗ 5582;gravity used in the acceleration calculation. The higher the number, the more intense the gravity. 5583;The possible values for gravity are as follows: 5584;#$38-When Samus has been hit by an enemy. 5585;#$1A-When Samus is falling. 5586;#$18-Jump without high jump boots. 5587;#$12-Jump with high jump boots.
Source_Files/Bank07.asm lines 5582–5587 at 4270d57 · upstream ↗ 5628LE3C9:* cmp #$05 ;Has maximum downward speed been reached? 5629LE3CB:* bcc + ;If not, branch.
Source_Files/Bank07.asm lines 5628–5629 at 4270d57 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-25.
Checked by a second AI model, 2026-10-22.
Checked by a second AI model, 2026-10-25.
- ^With the
weightlessflag clear, a fall (action 4) adds 3 px per cycle to the kid's downward speed, up to 33 px per cycle (AccelGravity,TermVelocity); with it set, gravity is 1 and the cap 4 (WtlessGravity,WtlessTermVel). The fall sequences that start it set the speed to 15 (setfall). In any other action, including the jumps' (action 1) and a fall's first frames (action 3), gravity does nothing.Codejmechner/Prince-of-Persia-Apple-IIrevisedHow we know
1613TermVelocity = 33 1614AccelGravity = 3 1615WtlessTermVel = 4 1616WtlessGravity = 1 ⋮ 1618GRAVITY 1619 lda CharAction 1620 cmp #4 1621 bne ]rts ⋮ 1626 lda CharYVel 1627 clc 1628 adc #AccelGravity ⋮ 1630 cmp #TermVelocity ⋮
01 POP Source/Source/SUBS.S lines 1613–1644 at 2524355 · upstream ↗ 640stepfall ;from #8 (run-11) 641 db act,3 642 db chx,1,chy,3 ⋮ 646fall1 647 db 102,chx,2,chy,6 648 db 103,chx,-1,chy,9 649 db 104,chy,12 650 db 105,chx,-2 ⋮ 652 db setfall,1,15 653 db goto 654 dw freefall
01 POP Source/Source/SEQTABLE.S lines 640–654 at 2524355 · upstream ↗ 882freefall 883 db act,4 884:loop db 106
01 POP Source/Source/SEQTABLE.S lines 882–884 at 2524355 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
- ^ abIn the doldecomp decompilation of Super Mario Sunshine, most of Mario's movement constants are named parameters (
TParamRT), each built with a default in the code, in sets that each name a file, such as/Mario/Jump.prm.TParams::load, in a file configure.py marks as matching the game's code, reads the set's file from the scene's/map/paramsfolder if it is there and from theparamsarchive if not, and a record whose key and name match a parameter replaces that parameter's default; the rest keep theirs. The values the game plays with are data on the disc, which the atlas hasn't read, so the numbers in these claims are the code's defaults. The jump set's gravity,mGravity, defaults to 0.8. In the jumping states,jumpProcessin the decompilers' Player code, which doesn't yet match, moves Mario by a quarter of his velocity in one step per update. ThenfallProcesssubtractsmGravityfrom his vertical speed, except in a dive (the dive set's own gravity, with a cap of its own), in a spin jump's descent (mSpinJumpGravity, default 0.6), and when a release cuts the rise (sms/jump); in every case it then caps the fall at −75. Super Mario 64 also moves Mario a quarter of his velocity at a time, but in four steps a frame (sm64/units).Code notesdoldecomp/sms · n64decomp/sm64revisedHow we know
314Matching = True # Object matches and should be linked 315NonMatching = False # Object does not match and should not be linked
configure.py lines 314–315 at d2cc8f5 · upstream ↗ 879 Object(Matching, "System/Params.cpp"),configure.py line 879 at d2cc8f5 · upstream ↗ 950 Object(NonMatching, "Player/MarioPhysics.cpp"),configure.py line 950 at d2cc8f5 · upstream ↗ 964 PCHObject(NonMatching, "Player/MarioInit.cpp"),configure.py line 964 at d2cc8f5 · upstream ↗ 8#define PARAM_INIT(member, defaultValue) \ 9 member(this, defaultValue, JDrama::TNameRef::calcKeyCode(#member), #member)
include/System/ParamInst.hpp lines 8–9 at d2cc8f5 · upstream ↗ 12 if (mHead != nullptr) { 13 s32 length = stream.readS32(); 14 for (int i = 0; i < length; i++) { 15 u16 keyCode = stream.read16b(); ⋮ 21 if (keyCode == param->keyCode && !strcmp(buffer, param->name)) { 22 param->load(stream); 23 break; ⋮ 26 if (param == nullptr) { 27 s32 end = stream.read32b(); 28 stream.skip(end);
src/System/Params.cpp lines 12–29 at d2cc8f5 · upstream ↗ 54 if (mSceneArc != nullptr && mSceneArc->becomeCurrent(SceneParamsDir)) { 55 resource = mSceneArc->getResource(filename); ⋮ 64 if (mArc != nullptr) { 65 mArc->becomeCurrent("/"); 66 void* resource2 = mArc->getResource(filename);
src/System/Params.cpp lines 54–66 at d2cc8f5 · upstream ↗ 5static const char SceneParamsDir[] = "/map/params";src/System/Params.cpp line 5 at d2cc8f5 · upstream ↗ 544TMario::TJumpParams::TJumpParams() 545 : TParams("/Mario/Jump.prm") 546 , PARAM_INIT(mGravity, 0.8f) 547 , PARAM_INIT(mSpinJumpGravity, 0.6f)
src/Player/MarioInit.cpp lines 544–547 at d2cc8f5 · upstream ↗ 498 Vec next; 499 next.x = mPosition.x + 0.25f * mVel.x; 500 next.y = mPosition.y + 0.25f * mVel.y; 501 next.z = mPosition.z + 0.25f * mVel.z; 502 int ret = checkGroundAtJumping(next, param_1); ⋮ 509 fallProcess();
src/Player/MarioPhysics.cpp lines 498–509 at d2cc8f5 · upstream ↗ 464void TMario::fallProcess() ⋮ 466 if (mStatus == MARIO_STATUS_DIVE) { 467 mVel.y -= mDivingParams.mGravity.get(); 468 if (mVel.y < -75.0f) 469 mVel.y = -75.0f; 470 } else { 471 if (isFallCancel()) { 472 mVel.y *= 0.75f; 473 } else if ((mStatus == MARIO_STATUS_LEFT_ROTATE_JUMP 474 || mStatus == MARIO_STATUS_RIGHT_ROTATE_JUMP) 475 && mVel.y < 0.0f) { 476 mVel.y -= mJumpParams.mSpinJumpGravity.get(); ⋮
src/Player/MarioPhysics.cpp lines 464–485 at d2cc8f5 · upstream ↗ 618 for (i = 0; i < 4; i++) { 619 intendedPos[0] = m->pos[0] + m->vel[0] / 4.0f; 620 intendedPos[1] = m->pos[1] + m->vel[1] / 4.0f; 621 intendedPos[2] = m->pos[2] + m->vel[2] / 4.0f;
src/game/mario_step.c lines 618–621 at 9921382 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Revised after a check by a second AI model, 2026-10-22.
Sources
Code
- 1987. “Castlevania (USA) (Rev 1).” · licence, all uses
- doppelganger and Xkeeper. 2022. “smb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1).” Commit 1cc3c92. Xkeeper0/smb1 @ 1cc3c92 · licence, all uses
- lsmmega. 2026. “mm2: Mega Man 2 disassembly (lsmmega/mm2).” Commit 94f0bf3. lsmmega/mm2 @ 94f0bf3 · licence, all uses
- IsoFrieze, kaizoman666, mikeyk, and loveemu. 2026. “SMWDisX: Super Mario World disassembly (IsoFrieze/SMWDisX).” Commit 30643c7. IsoFrieze/SMWDisX @ 30643c7 · licence, all uses
- Sonic Retro contributors. 2026. “s1disasm: Sonic the Hedgehog (16-bit) disassembly (sonicretro/s1disasm).” Commit 15dfa3a. sonicretro/s1disasm @ 15dfa3a · licence, all uses
- Thorson, Maddy and Noel Berry. 2021. “Celeste: released class files (NoelFB/Celeste).” Commit 1b0ce45. NoelFB/Celeste @ 1b0ce45 · licence, all uses
- Thorson, Maddy. 2018. “Monocle Engine (public source, GitHub mirror JamesMcMahon/monocle-engine).” Commit 759c15a. JamesMcMahon/monocle-engine @ 759c15a · licence, all uses
- banjo.decomp. 2026. “banjo-kazooie: a decompilation of Banjo-Kazooie (banjo.decomp/banjo-kazooie).” Commit e8d31fa. banjo.decomp/banjo-kazooie @ e8d31fa · licence, all uses
- n64decomp. 2023. “sm64: a decompilation of Super Mario 64 (n64decomp/sm64).” Commit 9921382. n64decomp/sm64 @ 9921382 · licence, all uses
- SAT-R contributors. 2026. “sa2: a decompilation of Sonic Advance 1 and 2 (SAT-R/sa2).” Commit 393357f. SAT-R/sa2 @ 393357f · licence, all uses
- metroidret contributors. 2026. “mf: a decompilation of Metroid Fusion (metroidret/mf).” Commit a6d6187. metroidret/mf @ a6d6187 · licence, all uses
- metroidret contributors. 2026. “mzm: a decompilation of Metroid: Zero Mission (metroidret/mzm).” Commit 2aae289. metroidret/mzm @ 2aae289 · licence, all uses
- nmikstas and Kent Hansen. 2025. “metroid-disassembly: Metroid software disassembly.” Commit 4270d57. nmikstas/metroid-disassembly @ 4270d57 · licence, all uses
- Mechner, Jordan. 2024. “Prince of Persia Apple II source code (jmechner/Prince-of-Persia-Apple-II).” Commit 2524355. jmechner/Prince-of-Persia-Apple-II @ 2524355 · licence, all uses
- doldecomp. 2026. “sms: a decompilation of Super Mario Sunshine (doldecomp/sms).” Commit d2cc8f5. doldecomp/sms @ d2cc8f5 · licence, all uses
- plasticsmoke. 2026. “Mega Man 3 (U), annotated ca65 disassembly (plasticsmoke).” Commit 58ca1c3. plasticsmoke/megaman3-disassembly-ca65 @ 58ca1c3 · licence, all uses
- Sonic Retro contributors. 2026. “s2disasm: Sonic the Hedgehog 2 (16-bit) disassembly (sonicretro/s2disasm).” Commit 4ef457c. sonicretro/s2disasm @ 4ef457c · licence, all uses
- Sonic Retro contributors. 2026. “skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm).” Commit 73de97c. sonicretro/skdisasm @ 73de97c · licence, all uses
- 1988. “Castlevania II - Simon's Quest (USA).” · licence, all uses
- vinheim3. 2020. “castlevania3-disasm: a disassembly of Castlevania III: Dracula's Curse.” Commit 3272648. vinheim3/castlevania3-disasm @ 3272648 · licence, all uses
- 1990. “Castlevania III - Dracula's Curse (USA).” · licence, all uses
- 1991. “Super Castlevania IV (USA).” · licence, all uses
- Xeeynamo and sotn-decomp contributors. 2026. “sotn-decomp: a decompilation of Castlevania: Symphony of the Night.” Commit 2be55ee. Xeeynamo/sotn-decomp @ 2be55ee · licence, all uses
Primary
- Thorson, Maddy. 2020. “Celeste and TowerFall Physics.” Medium. original · archived · licence, all uses
Secondary
- Sonic Retro contributors. n.d. “Sonic Physics Guide: Calculations (Pixel and Subpixel).” Sonic Retro. original · archived · licence, all uses
- Jdaster64. n.d. “A Complete Guide to SMB's Physics Engine.” original · archived · licence, all uses
- Sonic Retro contributors. n.d. “Sonic Physics Guide: Air State.” Sonic Retro. original · archived · licence, all uses