Hitbox
The shape a game tests to decide whether a character touches the level or another object.
On this page
A hitbox is the shape a game tests to decide what a character touches. Most of the games here test the level and other objects separately: the level at a few points around the character, objects with a box. Metroid uses one box, sized by each animation frame, for both1. The movement lab draws each game’s box. On a ledge, the points against the level decide when the character falls, whatever the box shows.
- PointsCastlevania (1986). A few points meet the level: two under his feet, a column at each side, three over his head.2
- BoxMetroid (1986). Radii from each animation frame, 8 × 30 px against the level, tested at every 8 px tile the box spans.1,3,4Mega Man 2 (1988). One box against walls and floors.5
- Points and a boxSuper Mario Bros. (1985). Points at his head, feet, and sides meet the level, and a box meets enemies.6,7,8,9Super Mario World (1990). Six points against blocks, and a box against sprites.10,11Metroid II: Return of Samus (1991). Up to five points per side against the background, a box against enemies.12Sonic the Hedgehog (1991). Points that touch the level, and a 16 px wide box that touches enemies.13,14Sonic the Hedgehog 2 (1992). Points that touch the level, and a 16 px wide box that touches enemies.15,16Sonic 3 & Knuckles (1994). Ducking no longer shrinks his box, and the insta-shield widens it.17,18
#Across games
| Against the level | Against objects | |
|---|---|---|
| Super Mario Bros. | head, feet, and side points6 | 12×24 px big, 10×12 small, 12×12 crouching7 |
| Castlevania | floor, wall, and ceiling points2 | not read yet |
| Metroid | a box of radii set by each animation frame1 | the same radii1 |
| Mega Man 2 | 16×24 px (walls ±8, floor and ceiling ±12)5 | the enemy’s own distance table5 |
| Super Mario World | six points, feet 6 px apart10 | 12×26 px big, 12×12 small or ducking11 |
| Sonic the Hedgehog | sensors, 19 × 39 px standing, 15 × 29 px curled13 | a separate box14 |
| Metroid II | points set by pose12 | a box whose top is set by pose12 |
#Quirks
- In both Mario games crouching or ducking shrinks the object box to 12 px tall7,11.
- Super Mario Bros.’ feet points sit 9 px apart while its side points are 11 px apart, so Mario’s footing is narrower than his body6.
- Ducking shrinks the object box in Sonic the Hedgehog but not in Sonic 3 & Knuckles14,17. Sonic the Hedgehog 2 keeps Sonic’s box, but with the disassembly’s
fixBugsoff its 20 px ducking box applies only on one mapping frame,$4D15,14. Celeste’s box is 8 × 11 px, 8 × 6 px ducked19.
Games
| Game | Year | How | Note |
|---|---|---|---|
| Castlevania | 1986 | Points | a few points meet the level: two under his feet, a column at each side, three over his head |
| Metroid | 1986 | Box | radii from each animation frame, 8 × 30 px against the level, tested at every 8 px tile the box spans |
| Mega Man 2 | 1988 | Box | one box against walls and floors |
| Super Mario Bros. | 1985 | Points and a box | points at his head, feet, and sides meet the level, and a box meets enemies |
| Super Mario World | 1990 | Points and a box | six points against blocks, and a box against sprites |
| Metroid II: Return of Samus | 1991 | Points and a box | up to five points per side against the background, a box against enemies |
| Sonic the Hedgehog | 1991 | Points and a box | points that touch the level, and a 16 px wide box that touches enemies |
| Sonic the Hedgehog 2 | 1992 | Points and a box | points that touch the level, and a 16 px wide box that touches enemies |
| Sonic 3 & Knuckles | 1994 | Points and a box | ducking no longer shrinks his box, and the insta-shield widens it |
Every claim about this mechanic, by game (98)
References
- ^ abcdSamus is a box around her center: each animation frame's data sets
ObjRadYandObjRadX, the distances from her center to her top or bottom and to her sides. The level checks add these radii to her position, and so does the distance check between her and an enemy.Codenmikstas/metroid-disassemblyHow we know
287.alias ObjRadY $0301 ;Distance in pixels from object center to top or bottom. 288.alias ObjRadX $0302 ;Distance in pixels from object center to left or right side.
Source_Files/Metroid_Defines.asm lines 287–288 at 4270d57 · upstream ↗ 4812LDEC1: sta ObjRadY,x ;Get verticle radius in pixles of object. ⋮ 4815LDEC7: lda ($00),y ;Get horizontal radius in pixels of object. 4816LDEC9: sta ObjRadX,x ;
Source_Files/Bank07.asm lines 4810–4816 at 4270d57 · upstream ↗ 5594LE384: lda ObjectY ; 5595LE387: clc ; 5596LE388: adc ObjRadY ;Check is Samus is obstructed downwards on y room
Source_Files/Bank07.asm lines 5594–5597 at 4270d57 · upstream ↗ 5981MoveSamusLeft: 5982LE626: lda ObjectX 5983 sec 5984 sbc ObjRadX 5985 and #$07 5986 bne + ; only call crash detection every 8th pixel 5987 jsr CheckMoveLeft ; check if player is obstructed to the LEFT
Source_Files/Bank07.asm lines 5981–5987 at 4270d57 · upstream ↗ 7802DistFromObj0ToEn1: 7803LF1B3: lda ObjRadY,x 7804 jsr LF1E7 7805 lda ObjRadX,x
Source_Files/Bank07.asm lines 7802–7806 at 4270d57 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abSimon's floor is tested at x−4 and x+4, 16 px below his Y; walls at x+8 or x−8 at five heights from 9 px above to 15 px below it; and a jump needs clear space 19 px above at x−7, x, and x+7.Code“Castlevania (USA) (Rev 1)”
How we know
In the cartridge (“Castlevania (USA) (Rev 1)”): bank 6 $9E70-$9ECA: the floor test at (x−4, y+16), then (x+4, y+16); bank 6 $9ECE-$9F79: the wall test at x+8 moving right or x−8 moving left, at y plus each of the table's $0F, $08, $00, $F7, $FC (or $10 for $0F while a jump falls); bank 6 $9998-$99ED: the take-off's ceiling test at y−19, x−7, x, and x+7. 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.
- ^In Brinstar's bank, the frames of Samus's running, standing, jumping, and somersault animations all give the radii
$0Fand$04: 15 px from her center to her top or bottom and 4 px to either side, so her box is 30 px tall and 8 wide (computed).Codenmikstas/metroid-disassemblyHow we know
679;Samus run animation. 680L8572: .byte $03, $04, $05, $FF ⋮ 688;Samus Stand animation. 689L8579: .byte $08, $FF ⋮ 697;Samus Jump animation. 698L857E: .byte $10, $FF ⋮ 700;Samus summersault animation. 701L8580: .byte $17, $18, $19, $1A, $FF
Source_Files/Bank01.asm lines 679–701 at 4270d57 · upstream ↗ 789FramePtrTable: 790L860B: .word $87CB, $87CB, $87CB, $87CB, $87DD, $87F0, $8802, $8802 791L861B: .word $8818, $882C, $882C, $882C, $882C, $883E, $8851, $8863 792L862B: .word $8863, $8874, $8874, $8885, $8885, $8885, $8885, $8885 793L863B: .word $888F, $8899, $88A3, $88AD, $88B8, $88C3, $88CE, $88D9
Source_Files/Bank01.asm lines 789–793 at 4270d57 · upstream ↗ 1157;current frame. The second byte is saved as the object's y radius and the third byte is saved 1158;as the object's x radius. ⋮ 1160;Samus run. 1161L87CB: .byte $40, $0F, $04, $00, $01, $FD, $20, $FE, $41, $40, $FD, $60, $20, $21, $FE, $FE
Source_Files/Bank01.asm lines 1157–1161 at 4270d57 · upstream ↗ 1176;Samus stand. 1177L8818: .byte $40, $0F, $04, $FD, $20, $0E, $0D, $FE, $1E, $1D, $2E, $2D, $FE, $FD, $60, $3B
Source_Files/Bank01.asm lines 1176–1177 at 4270d57 · upstream ↗ 1192;Samus stand and jump. 1193L8863: .byte $40, $0F, $04, $00, $01, $FD, $20, $FE, $41, $40, $FD, $60, $22, $07, $08, $32 ⋮ 1200;Samus summersault. 1201L8885: .byte $41, $0F, $04, $52, $53, $62, $63, $72, $73, $FF ⋮ 1203;Samus summersault. 1204L888F: .byte $42, $0F, $04, $54, $55, $56, $64, $65, $66, $FF ⋮ 1206;Samus summersault. 1207L8899: .byte $81, $0F, $04, $52, $53, $62, $63, $72, $73, $FF ⋮ 1209;Samus summersault. 1210L88A3: .byte $82, $0F, $04, $54, $55, $56, $64, $65, $66, $FF
Source_Files/Bank01.asm lines 1192–1210 at 4270d57 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-25.
Checked by a second AI model, 2026-10-27.
- ^Samus moves one pixel at a time, and a step tests the room's 8 px tiles only when the edge she moves toward lies on a tile boundary:
MoveSamusUp,MoveSamusDown,MoveSamusLeft, andMoveSamusRightcall the crash check only when her center less or plus her radius is a multiple of 8. The check tests the row of tiles above her top or below her bottom, or the column beside her side, across every tile her box spans. On the ground,VertAcceleratemakes the same test under her each frame.Codenmikstas/metroid-disassemblyHow we know
5713MoveSamusUp: 5714LE457: lda ObjectY ;Get Samus' y position in room. 5715 sec ; 5716 sbc ObjRadY ;Subtract Samus' vertical radius. 5717LE45E: and #$07 ;Check if result is a multiple of 8. If so, branch to 5718LE460: bne + ;Only call crash detection every 8th pixel. 5719LE462: jsr CheckMoveUp ;($E7A2)Check if Samus obstructed UPWARDS.
Source_Files/Bank07.asm lines 5713–5720 at 4270d57 · upstream ↗ 5751MoveSamusDown: 5752 lda ObjectY 5753 clc 5754 adc ObjRadY 5755 and #$07 5756 bne + ; only call crash detection every 8th pixel 5757 jsr CheckMoveDown ; check if Samus obstructed DOWNWARDS
Source_Files/Bank07.asm lines 5751–5757 at 4270d57 · upstream ↗ 6215CheckMoveUp: 6216LE7A2: ldx PageIndex 6217 lda ObjRadY,x 6218 clc 6219 adc #$08 6220 jmp + ⋮ 6222CheckMoveDown: 6223 ldx PageIndex 6224 lda #$00 6225 sec 6226 sbc ObjRadY,x 6227* sta $02 ⋮
Source_Files/Bank07.asm lines 6215–6229 at 4270d57 · upstream ↗ 6234* sta $03 6235 tay 6236 ldx #$00 6237 lda $09 6238 sec 6239 sbc $03 6240 and #$07 6241 beq + 6242 inx 6243* jsr LE8CE 6244 sta $04 6245 jsr LE90F
Source_Files/Bank07.asm lines 6234–6245 at 4270d57 · upstream ↗ 6280* dex 6281 beq + 6282 jsr LE98E 6283 jmp LE7E6
Source_Files/Bank07.asm lines 6280–6283 at 4270d57 · upstream ↗ 6341CheckMoveLeft: 6342 ldx PageIndex 6343 lda ObjRadX,x 6344 clc 6345 adc #$08 6346 jmp + ⋮ 6348CheckMoveRight: 6349 ldx PageIndex 6350 lda #$00 6351 sec 6352 sbc ObjRadX,x
Source_Files/Bank07.asm lines 6341–6352 at 4270d57 · upstream ↗ 5594LE384: lda ObjectY ; 5595LE387: clc ; 5596LE388: adc ObjRadY ;Check is Samus is obstructed downwards on y room 5597LE38B: and #$07 ;positions divisible by 8(every 8th pixel). 5598LE38D: bne + ; 5599LE38F: jsr CheckMoveDown ;($E7AD)Is Samus obstructed downwards? 5600LE392: bcc ++ ;Branch if yes.
Source_Files/Bank07.asm lines 5594–5600 at 4270d57 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-25.
Checked by a second AI model, 2026-10-27.
- ^ abcMega Man's position is his center; the floor and ceiling are tested at x−7 and x+7, 12 px below or above it, and walls at x+8 or x−8 at 12 px and 4 px above and 11 px below it.Codelsmmega/mm2
How we know
47 LDA aobject_ycoord_speed 48 BMI @down 49 SEC 50 LDA aobject_ycoord 51 SBC #$0C 52 STA z:z0A 53 LDA z:zout_of_screen 54 SBC #$00 55 STA z:z0B 56 JSR _check_vertical_collision
engine/check_object_vertical_move.asm lines 47–56 at 94f0bf3 · upstream ↗ 92@down: 93 CLC 94 LDA aobject_ycoord 95 ADC #$0C
engine/check_object_vertical_move.asm lines 92–100 at 94f0bf3 · upstream ↗ 212check_vertical_collision_xcoord_offset: 213 .BYTE +7, -7
engine/check_object_vertical_move.asm lines 212–213 at 94f0bf3 · upstream ↗ 32 CLC 33 LDA aobject_xcoord 34 ADC #$08 35 STA z:z08
engine/check_object_horizontal_move.asm lines 32–35 at 94f0bf3 · upstream ↗ 198check_horizontal_collision_ycoord_offset: 199 .BYTE -12, -4, +11
engine/check_object_horizontal_move.asm lines 198–199 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.
- ^ abcAgainst the level,
PlayerBGCollisiontests a head point at x+8, feet at x+3 and x+12 (y+32), and sides at x+2 and x+13, at y+8 and y+24 when big and both at y+24 when small or crouching.CodeXkeeper0/smb1revisedHow we know
12295BlockBufferAdderData: 12296 .db $00, $07, $0e ⋮ 12298BlockBuffer_X_Adder: 12299 .db $08, $03, $0c, $02, $02, $0d, $0d, $08 12300 .db $03, $0c, $02, $02, $0d, $0d, $08, $03 12301 .db $0c, $02, $02, $0d, $0d, $08, $00, $10 ⋮ 12304BlockBuffer_Y_Adder: 12305 .db $04, $20, $20, $08, $18, $08, $18, $02 12306 .db $20, $20, $08, $18, $08, $18, $12, $20 12307 .db $20, $18, $18, $18, $18, $18, $14, $14
src/prg.asm lines 12295–12309 at 1cc3c92 · upstream ↗ 11131ChkCollSize: 11132 LDY #$02 ; load default offset 11133 LDA CrouchingFlag 11134 BNE GBBAdr ; if player crouching, skip ahead 11135 LDA PlayerSize 11136 BNE GBBAdr ; if player small, skip ahead 11137 DEY ; otherwise decrement offset for big player not crouching 11138 LDA SwimmingFlag 11139 BNE GBBAdr ; if swimming flag set, skip ahead 11140 DEY ; otherwise decrement offset 11141GBBAdr: 11142 LDA BlockBufferAdderData,y ; get value using offset
src/prg.asm lines 11131–11142 at 1cc3c92 · 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.
- ^ abc
BoundBoxCtrlDatagives Mario a box for touching objects from 2 to 14 px across his sprite, and 8 to 32 px down when big or 20 to 32 px crouching; small Mario's runs from 3 to 13 across and 20 to 32 down.CodeXkeeper0/smb1How we know
12024; this data added to relative coordinates of sprite objects 12025; stored in order: left edge, top edge, right edge, bottom edge 12026BoundBoxCtrlData: 12027 .db $02, $08, $0e, $20 12028 .db $03, $14, $0d, $20 12029 .db $02, $14, $0e, $20
src/prg.asm lines 12024–12029 at 1cc3c92 · upstream ↗ 4393 LDY #$01 ; is player small? 4394 LDA PlayerSize 4395 BNE ChkMoveDir 4396 LDY #$00 ; check for if crouching 4397 LDA CrouchingFlag 4398 BEQ ChkMoveDir ; if not, branch ahead 4399 LDY #$02 ; if big and crouching, load y with 2 4400ChkMoveDir: 4401 STY Player_BoundBoxCtrl ; set contents of Y as player's bounding box size control
src/prg.asm lines 4393–4401 at 1cc3c92 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^When a foot point finds an ordinary solid block and Mario isn't moving up,
PlayerBGCollisionlands him if his Y is less than 5 px into the block's 16 px row; 5 px or more, it callsImpedePlayerMovein his moving direction instead, which pushes him 1 px back unless he is already moving away, and leaves without checking his sides.CodeXkeeper0/smb1revisedHow we know
11202ChkFootMTile: ⋮ 11205 LDY Player_Y_Speed ; check player's vertical speed 11206 BMI DoPlayerSideCheck ; if player moving upwards, branch ⋮ 11215 LDY $04 ; check lower nybble of vertical coordinate returned 11216 CPY #$05 ; from collision detection routine 11217 BCC LandPlyr ; if lower nybble < 5, branch 11218 LDA Player_MovingDir 11219 STA $00 ; use player's moving direction as temp variable 11220 JMP ImpedePlayerMove ; jump to impede player's movement in that direction
src/prg.asm lines 11202–11220 at 1cc3c92 · 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.
- ^A side point in a block calls
ImpedePlayerMove, which moves Mario 1 px away from the block and zeroes his speed byte, unless he is already moving away; either way it clears that side's d-pad bit inPlayer_CollisionBits, which the next frame'sImposeFrictionANDs with the d-pad, so the next frame's friction ignores the direction into the wall.VerifiedXkeeper0/smb1How we know
11547ImpedePlayerMove: 11548 LDA #$00 ; initialize value here 11549 LDY Player_X_Speed ; get player's horizontal speed 11550 LDX $00 ; check value set earlier for 11551 DEX ; left side collision 11552 BNE RImpd ; if right side collision, skip this part 11553 INX ; return value to X 11554 CPY #$00 ; if player moving to the left, 11555 BMI ExIPM ; branch to invert bit and leave 11556 LDA #$ff ; otherwise load A with value to be used later ⋮ 11566 LDY #$00 11567 STY Player_X_Speed ; nullify player's horizontal speed ⋮
src/prg.asm lines 11547–11584 at 1cc3c92 · upstream ↗ 5091ImposeFriction: 5092 AND Player_CollisionBits ; perform AND between left/right controller bits and collision flag 5093 CMP #$00 ; then compare to zero (this instruction is redundant)
src/prg.asm lines 5091–5093 at 1cc3c92 · 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-22.
Checked by a second AI model, 2026-10-22.
- ^ abAgainst blocks Mario tests six points, a center, two side points, a head, and two feet at x+5 and x+11, y+32; big Mario's head point is at y+8 and small Mario's at y+16.CodeSMWDisX
How we know
11671PlayerXHitboxPoints: 11672 db $0C,$0E,$08,$00,$0E,$00,$0E,$00 11673 db $08,$00,$05,$00,$0B,$00,$08,$00 ⋮ 11676 db $08,$00,$05,$00,$0B,$00,$08,$00 ⋮ 11679 db $08,$00,$05,$00,$0B,$00,$08,$00 ⋮ 11682 db $08,$00,$05,$00,$0B,$00,$08,$00 ⋮ 11687PlayerYHitboxPoints: 11688 db $08,$00,$18,$00,$1A,$00,$16,$00 11689DATA_00E8A4: 11690 db $10,$00,$20,$00,$20,$00,$18,$00
bank_00.asm lines 11671–11690 at 30643c7 · upstream ↗ 12042NormalCollision: 12043 LDX.B #$00 ⋮ 12048 LDX.B #$18 ; If player is big and not ducking, index = $18 ⋮ 12066 ADC.B #$0B ; if on the right, index += $0B ⋮ 12074 JSR GetBlockAtPlayer ; Interaction point 0 (Center)
bank_00.asm lines 12042–12074 at 30643c7 · upstream ↗ 13273GetBlockAtPlayer: ; X = position offset idx 13274 INX 13275 INX 13276 REP #$20 ; A->16 13277 LDA.B PlayerXPosNext 13278 CLC 13279 ADC.W PlayerXHitboxPoints,X ⋮ 13282 CLC
bank_00.asm lines 13273–13284 at 30643c7 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-22.
- ^ abc
GetMarioClippinggives Mario a box for touching sprites 12 px wide from x+2, 26 px tall from y+6 when big, and 12 px tall from y+20 when small or ducking.CodeSMWDisXHow we know
6941MairoClipDispY: 6942 db $06,$14,$10,$18 ⋮ 6944MarioClippingHeight: 6945 db $1A,$0C,$20,$18 ⋮ 6949 LDA.B PlayerXPosNext ; \ 6950 CLC ; | 6951 ADC.B #$02 ; | ⋮ 6956 LDA.B #$0C ; \ $06 = Clipping width X (#$0C) ⋮ 6958 LDX.B #$00 ; \ If mario small or ducking, X = #$01 ⋮ 6972 CLC ; |
bank_03.asm lines 6941–6977 at 30643c7 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abcAgainst the background, Samus is tested at points, one x for the side she moves toward and a list of up to five y offsets for her pose. Against enemies,
collision_samusEnemiesruns first and compares each enemy's hitbox with Samus's, whose top is set per pose.Codealex-west/M2RoSHow we know
4981 ; Get offset for right side 4982 ldh a, [hSamusXPixel] 4983 add OAM_X_OFS + samusOriginX_toRight ⋮ 4986 ; Do sprite collision 4987 call collision_samusEnemies.horizontal ⋮ 4990 ; Get base address to the first entry for the pose's y offset list
SRC/bank_000.asm lines 4981–4996 at 031aea3 · upstream ↗ 5543collision_samusHorizontalYOffsetLists: ;{ 00:20FF - Y-Offset collision lists per pose ($80 terminated) 5544; Note: Due to limitations of the function that read this 5545; despite each row being 8 bytes long, only 5 offsets are supported
SRC/bank_000.asm lines 5543–5545 at 031aea3 · upstream ↗ 9481collision_samusSpriteHitboxTopTable: ;{ 00:369B - Offset for the top of Samus's hitbox per pose (for sprite collisions)SRC/bank_000.asm line 9481 at 031aea3 · upstream ↗ 8708 ; Get hitbox pointer of enemy ⋮ 8714 ld hl, enemyHitboxPointers
SRC/bank_000.asm lines 8708–8714 at 031aea3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abStanding, Sonic's floor and ceiling sensors sit 19 px above and below his center and 9 px to each side, a 19 × 39 px box; curled up, 14 and 7, 15 × 29 px.Codesonicretro/s1disasm · Sonic Retro, “Sonic Physics Guide: Characters”
How we know
311sonic_width: equ 18/2 ; Sonic's width 312sonic_height: equ 38/2 ; Sonic's height 313sonic_roll_width: equ 14/2 ; Sonic's width (rolling) 314sonic_roll_height: equ 28/2 ; Sonic's height (rolling) ⋮ 318sonic_quick_size: equ 20/2 ; Sonic's size (quick terrain find)
_Constants.asm lines 311–318 at 15dfa3a · upstream ↗ 113Sonic_FindFloor: 114 move.w obY(a0),d2 115 move.w obX(a0),d3 116 moveq #0,d0 117 move.b obHeight(a0),d0 118 ext.w d0 119 add.w d0,d2 ; d2 = y pos. of Sonic's bottom edge 120 move.b obWidth(a0),d0 121 ext.w d0 122 add.w d0,d3 ; d3 = x pos. of Sonic's right edge
_incObj/Sonic Collision.asm lines 113–123 at 15dfa3a · upstream ↗ When standing, Sonic's Width Radius is 9 and his Height Radius is 19 … resulting in 19 pixels wide and 39 pixels tall.
Sonic · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-27.
- ^ abcdAgainst objects Sonic is a 16 px wide box whose half-height is his height radius minus 3: 32 px tall standing, 22 px curled, 20 px on the ducking frame; the level sees separate sensors (collision-box).Codesonicretro/s1disasm
How we know
17 subq.w #sonic_react_width,d2 ; d2 = X-position of Sonic's left edge ⋮ 21 subq.b #3,d5 ; shrink by 3px ⋮ 38 moveq #sonic_duck_height,d5 ; use alternate hitbox extent ⋮ 41 move.w #sonic_react_width*2,d4 ; d4 = Sonic's hitbox width
_incObj/Sonic ReactToItem.asm lines 15–41 at 15dfa3a · upstream ↗ 316sonic_react_width: equ 16/2 ; Sonic's width (object collision)_Constants.asm lines 316–317 at 15dfa3a · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^ abAgainst objects Sonic is a 16 px wide box whose half-height is his height radius minus 3: 32 px tall standing, 22 px curled up.Codesonicretro/s2disasm · sonicretro/s1disasmrevised
How we know
85231 subi_.w #8,d2 85232 moveq #0,d5 85233 move.b y_radius(a0),d5 85234 subq.b #3,d5 85235 sub.w d5,d3 ⋮ 85249 move.w #$10,d4 85250 add.w d5,d5
s2.asm lines 85229–85250 at 4ef457c · upstream ↗ move.b #$13,y_radius(a0)
s2.asm#L36226-L36227 · upstream ↗ subq.w #sonic_react_width,d2 … subq.b #3,d5 … move.w #sonic_react_width*2,d4
_incObj/Sonic ReactToItem.asm#L17-L41 · 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.
- ^Sonic's level collision radii are 9 × 19 px standing and 7 × 14 curled, set by
Obj01_Init, the jump, the roll, and the spin dash, and his wall sensors sit 10 px from his center: Sonic 1's sizes.Codesonicretro/s2disasm · sonicretro/s1disasmrevisedHow we know
36226 move.b #$13,y_radius(a0) ; this sets Sonic's collision height (2*pixels) 36227 move.b #9,x_radius(a0) ; this sets Sonic's Collision width (2*pixels)
s2.asm lines 36226–36227 at 4ef457c · upstream ↗ 37436 move.b #$E,y_radius(a0) 37437 move.b #7,x_radius(a0) 37438 move.b #AniIDSonAni_Roll,anim(a0) ; use "jumping" animation 37439 bset #status.player.rolling,status(a0) 37440 addq.w #5,y_pos(a0)
s2.asm lines 37436–37440 at 4ef457c · upstream ↗ 44375CheckRightWallDist_Part2: 44376 addi.w #$A,d3
s2.asm lines 44375–44376 at 4ef457c · upstream ↗ 44566CheckLeftWallDist_Part2: 44567 subi.w #$A,d3
s2.asm lines 44566–44567 at 4ef457c · upstream ↗ 311sonic_width: equ 18/2 ; Sonic's width 312sonic_height: equ 38/2 ; Sonic's height 313sonic_roll_width: equ 14/2 ; Sonic's width (rolling) 314sonic_roll_height: equ 28/2 ; Sonic's height (rolling) 315sonic_solid_width: equ 22/2 ; Sonic's width (solid object collision) 316sonic_react_width: equ 16/2 ; Sonic's width (object collision) 317sonic_duck_height: equ 20/2 ; Sonic's height (object collision, ducking) 318sonic_quick_size: equ 20/2 ; Sonic's size (quick terrain find)
_Constants.asm lines 311–318 at 15dfa3a · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-26.
Revised after a check by a second AI model, 2026-10-26.
- ^ abAgainst objects the player is still a 16 px wide box whose half-height is his height radius minus 3, and ducking no longer shrinks it.Codesonicretro/skdisasm · sonicretro/s2disasm · sonicretro/s1disasmrevised
How we know
20681 subi.w #8,d2 ; Subtract Obj_Sonic's x_radius-1 from x_pos (becomes player's left collision boundary) 20682 moveq #0,d5 20683 move.b y_radius(a0),d5 20684 subq.b #3,d5 ; Now player's collision height ⋮ 20687 ; Height is no longer reduced by ducking 20688 move.w #$10,d4 ; Player's collision width
sonic3k.asm lines 20679–20689 at 73de97c · upstream ↗ 85231 subi_.w #8,d2 ⋮ 85234 subq.b #3,d5 ⋮ 85249 move.w #$10,d4
s2.asm lines 85229–85250 at 4ef457c · upstream ↗ subq.w #sonic_react_width,d2 … subq.b #3,d5 … move.w #sonic_react_width*2,d4
_incObj/Sonic ReactToItem.asm#L17-L41 · 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.
- ^With no shield, the press gives Sonic the insta-shield, which while active makes him invincible and widens his hit box to 48 × 48 px.Codesonicretro/skdisasm
How we know
23509 btst #Status_Shield,status_secondary(a0) ; does Sonic have an S2 shield? (the elementals were already filtered out at this point) 23510 bne.s locret_11A14 ; if yes, branch 23511 move.b #1,(Shield+anim).w 23512 move.b #1,double_jump_flag(a0)
sonic3k.asm lines 23508–23514 at 73de97c · upstream ↗ 20656 cmpi.b #1,double_jump_flag(a0) ; Is the Insta-Shield currently in its 'attacking' mode? ⋮ 20660 bset #Status_Invincible,status_secondary(a0) ; Make the player invincible ⋮ 20665 move.w #$30,d4 ; Player's width 20666 move.w #$30,d5 ; Player's height
sonic3k.asm lines 20656–20666 at 73de97c · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^Madeline's hitbox is 8 px wide and 11 px tall, centered on her X with her position at its bottom; ducking shrinks it to 8 × 6 px.CodeNoelFB/Celesterevised
How we know
263 private readonly Hitbox normalHitbox = new Hitbox(8, 11, -4, -11); 264 private readonly Hitbox duckHitbox = new Hitbox(8, 6, -4, -6); 265 private readonly Hitbox normalHurtbox = new Hitbox(8, 9, -4, -11); 266 private readonly Hitbox duckHurtbox = new Hitbox(8, 4, -4, -6);
Source/Player/Player.cs lines 263–266 at 1b0ce45 · upstream ↗ 2113 public bool Ducking ⋮ 2124 Collider = duckHitbox; 2125 hurtbox = duckHurtbox;
Source/Player/Player.cs lines 2113–2131 at 1b0ce45 · 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.
Sources
Code
- nmikstas and Kent Hansen. 2025. “metroid-disassembly: Metroid software disassembly.” Commit 4270d57. nmikstas/metroid-disassembly @ 4270d57 · licence, all uses
- doppelganger and Xkeeper. 2022. “smb1: Super Mario Bros. disassembly for asm6f (Xkeeper0/smb1).” Commit 1cc3c92. Xkeeper0/smb1 @ 1cc3c92 · licence, all uses
- 1987. “Castlevania (USA) (Rev 1).” · 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
- alex-west. 2026. “M2RoS: Return of Samus Disassembly.” Commit 031aea3. alex-west/M2RoS @ 031aea3 · licence, all uses
- Sonic Retro contributors. 2026. “skdisasm: Sonic 3 & Knuckles disassembly (sonicretro/skdisasm).” Commit 73de97c. sonicretro/skdisasm @ 73de97c · 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
- Thorson, Maddy and Noel Berry. 2021. “Celeste: released class files (NoelFB/Celeste).” Commit 1b0ce45. NoelFB/Celeste @ 1b0ce45 · licence, all uses
Secondary
- Sonic Retro contributors. n.d. “Sonic Physics Guide: Characters.” Sonic Retro. original · archived · licence, all uses