On this page
  1. Across games
  2. Quirks
  3. Related
  4. Games
  5. References
  6. Sources

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.

Interactive: movement-lab (needs JavaScript)

Walking off a ledge. The scene holds on the frame each player walks off.
  • 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 levelAgainst objects
Super Mario Bros.head, feet, and side points612×24 px big, 10×12 small, 12×12 crouching7
Castlevaniafloor, wall, and ceiling points2not read yet
Metroida box of radii set by each animation frame1the same radii1
Mega Man 216×24 px (walls ±8, floor and ceiling ±12)5the enemy’s own distance table5
Super Mario Worldsix points, feet 6 px apart1012×26 px big, 12×12 small or ducking11
Sonic the Hedgehogsensors, 19 × 39 px standing, 15 × 29 px curled13a separate box14
Metroid IIpoints set by pose12a 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 fixBugs off 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

GameYearHowNote
Castlevania1986Pointsa few points meet the level: two under his feet, a column at each side, three over his head
Metroid1986Boxradii from each animation frame, 8 × 30 px against the level, tested at every 8 px tile the box spans
Mega Man 21988Boxone box against walls and floors
Super Mario Bros.1985Points and a boxpoints at his head, feet, and sides meet the level, and a box meets enemies
Super Mario World1990Points and a boxsix points against blocks, and a box against sprites
Metroid II: Return of Samus1991Points and a boxup to five points per side against the background, a box against enemies
Sonic the Hedgehog1991Points and a boxpoints that touch the level, and a 16 px wide box that touches enemies
Sonic the Hedgehog 21992Points and a boxpoints that touch the level, and a 16 px wide box that touches enemies
Sonic 3 & Knuckles1994Points and a boxducking no longer shrinks his box, and the insta-shield widens it
Every claim about this mechanic, by game (98)
Space Invaders 1978Nothing tests for shields as such. Every shot is drawn with DrawSprCollision, which ANDs each byte of the shifted sprite with the screen before ORing it in and sets the collision flag if any pixel was already lit, so a shot hits a shield when its newly drawn sprite overlaps a lit shield pixel. The player's shot is 1 px wide and 4 px long and moves 4 px a step, so it is tested against every pixel row on its path (computed). A player's shot that collides below the rack takes status 3, the code for a hit on something other than an alien.Code
Super Mario Bros. 1985BoundBoxCtrlData gives 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.Code
Against the level, PlayerBGCollision tests 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.Code
BlockBufferCollision turns a point into a block lookup: it adds the point's offsets to Mario's position, takes the block column from X ÷ 16 and the block row from (Y & $F0) − 32, and returns the metatile stored there, with the low nybble of Mario's Y (head and feet) or X (sides) as the point's place inside its block.Code
PlayerBGCollision runs after the frame's movement (smb1/frame-order). It first sets a grounded Mario's state to falling (2), then tests the head, then the two foot points, then the side points, the left pair before the right; the first side point that hits ends the check.Code
When a foot point finds an ordinary solid block and Mario isn't moving up, PlayerBGCollision lands him if his Y is less than 5 px into the block's 16 px row; 5 px or more, it calls ImpedePlayerMove in his moving direction instead, which pushes him 1 px back unless he is already moving away, and leaves without checking his sides.Code
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 in Player_CollisionBits, which the next frame's ImposeFriction ANDs with the d-pad, so the next frame's friction ignores the direction into the wall.Verified
While Mario moves up, PlayerBGCollision tests a single head point, the first of its point set (smb1/bg-points), after the frame's movement and before the feet. It acts only if his vertical speed byte is negative, the low nybble of his own Y is 4 or more, and his Y is at least $20 (big) or $10 (small, or big and crouching), and only if the point's metatile is nonzero and not a coin. So one block at most is hit per frame: when his head spans two blocks, the one under the point is hit and the other is ignored. Measured: big Mario under a brick that covered only his box's left part rose past it untouched.Verified
When the head point finds a block in the solid ranges (smb1/head-kinds), PlayerBGCollision sets Mario's vertical speed byte to 1 and plays the bump sound; his position and the speed's fraction are left as they are, so the frame ends with his head inside the block and he starts down on the next. In water levels, and while BlockBounceTimer runs (smb1/bounce-timer), a brick or ? block gets the same speed of 1 without the sound and without being hit.Verified
CheckForSolidMTiles splits what a head can meet by the metatile's top two bits: at or above $10, $61, $88, or $C4 in its group is solid (smb1/head-solid); below is hit (PlayerHeadCollision). The collision map stores nothing below $10, $51, $88, and $C0 in the same groups, so the hit kinds are $51–$60 (bricks, the cracked-rock ground, bricks with items, hidden blocks) and $C0–$C1 (? blocks); a used block ($C4), the solid blocks from $61, and pipes are solid.Code
During a bounce, and on the frame after a brick breaks, the block's cell holds $23, and every test of PlayerBGCollision takes its solid path for it: the head check's solid range starts at $10 in group 0; the foot check's exceptions (climbable from $24, the axe $C5, hidden blocks $5F and $60) miss it, so it lands Mario or pushes him back; and the side check's exceptions (hidden blocks, climbable, coins $C2 and $C3, jumpspring $67 and $68, the pipe openings) miss it, so it ends in StopPlayerMove.Code
Castlevania 1986Simon'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
A wall stops Simon without pushing him out. Before each move, in the standing, jumping, and falling states, the direction routine tests the wall points on the side he's moving toward; if any is in solid ground it clears his direction bits, so he doesn't move that frame and nothing else changes. A jump keeps rising and falling, and moves on again once the points are clear.Verified
Metroid 1986Samus is a box around her center: each animation frame's data sets ObjRadY and ObjRadX, 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.Code
In Brinstar's bank, the frames of Samus's running, standing, jumping, and somersault animations all give the radii $0F and $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).Code
Super Mario Bros.: The Lost Levels 1986The collision code (FireballEnemyCollision through BlockBufferCollision) is Super Mario Bros.'s with the upside-down piranha plant, the poison mushroom and the renumbered metatiles added: the fireball, enemy, background and stomp checks treat the upside-down plant like a piranha plant; HandlePowerUpCollision injures the player on power-up type 4; InjurePlayer also does nothing while the star's StarInvincibleTimer runs; HandlePECollisions checks for the cannon's Bullet Bill before the piranha plants and Podoboo, where Super Mario Bros. checks it after them; PlayerEnemyCollision decides a stomp with LDY, DEY, BPL on the vertical speed where Super Mario Bros. uses BMI and BNE (the two disagree only at speed $80); every stomp bounces the player through a new SetBounce, at vertical speed $FA, or $F8 off red paratroopas and flying green paratroopas, where Super Mario Bros. sets $FD after a stomp that defeats an enemy and $FC after one that demotes a paratroopa or knocks an enemy into its shell; HandleClimbing gives a life for grabbing the flagpole when the coin tally's digits and the timer's last digit match; HandlePipeEntry sends the player to the warp zone's one destination whichever pipe they take, where Super Mario Bros. picks by the pipe's x position; HandleCoinMetatile's axe restores Mario's physics; ChkForLandJumpSpring sets VerticalForceDown to $70 as well as VerticalForce; PlayerHammerCollision also skips while the player is off screen; HandleEToBGCollision bounces a power-up on a bumped block without stunning it and never demotes a piranha plant; CheckPlayerVertical drops its test of how far down the screen the player is; one bounding box grows from $14 to $16. The platform collisions, LandEnemyProperly, the side checks and BlockBufferCollision differ only in their addresses, and three regions, PlayerCollisionCore among them, are byte for byte the same.Code
Mega Man 1987Mega 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, toward his facing, at 12 px and 4 px above and 11 px below it. Every animation he has on foot or in the air uses these offsets.Code
_check_special_blockset_or_tsa_collision turns a test point into a tile: X / 32 and Y / 32 pick a 32 px block of the screen's map, bit 4 of Y and of X pick one of its four 16 px tiles, and the tile's top two bits give its kind through a per-stage table: background, block, and two of ladder, spike, ice, and water.Code
Each frame on foot or in the air, _run_megaman_on_stage moves Mega Man horizontally first, testing for a wall, then vertically, testing the floor under a fall or the ceiling over a rise, and only then checks for a jump or lands, runs, slides, or stands, so a frame's floor test uses that frame's new X. The one change made before the move is a Left or Right pressed fresh, which sets the first step's animation (ground-states).Code
When the horizontal move puts the wall point ahead in a solid tile, _objects_rightward or _objects_leftward puts x + 8 on that tile's first column moving right, or x − 8 on the first column past it moving left, and keeps the X fraction of the move; his speed and animation are untouched, so he runs in place.Verified
When a rising Mega Man's move puts a ceiling point, x − 7 or x + 7 at 12 px above his center, in a block, _objects_vertical_moving puts that point on the first row under the block's 16 px tile, zeroes the Y fraction, and sets his speed to −0.75 px/frame, the speed a landing gets; _run_megaman_on_stage then returns before the release test and before setting the jumping animation, and he falls from the next frame. Measured in Mesen at the start of Bomb Man's stage, under 16 px blocks that the probe adds to the stage's collision.Verified
Mega Man 2 1988Mega 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.Code
_tsa_collision turns a test point into a tile: X / 32 and Y / 32 pick a 32 px block of the stage map, bit 4 of X and of Y pick one of its four 16 px tiles, and the tile's top two bits give its kind, background, block, or one of a per-stage pair such as ladder and spike.Code
Each of Mega Man's grounded and jumping states moves him horizontally first, testing for a wall, then vertically, testing the floor under a fall or the ceiling over a rise, and only then changes state or checks for a jump, so a frame's floor test uses that frame's new X.Code
When the horizontal move puts the wall point ahead in a solid tile, _check_object_horizontal_move zeroes Mega Man's X fraction and pushes him back by the point's depth into the tile, so x + 8 ends on the wall's first column moving right and x − 8 on the first column past it moving left; his speed and state are untouched, so he runs in place.Verified
A pit has no floor of its own; once Mega Man's Y passes $E8 on the screen, _check_object_vertical_move asks for a downward scroll, and _check_scroll kills him where the stage doesn't scroll down.Code
When a rising Mega Man's move puts a ceiling point, x − 7 or x + 7 at 12 px above his center, in a block, _check_object_vertical_move zeroes his Y fraction and adds 16 − ((Y − 12) mod 16) to Y, which puts that point on the first row under the block's 16 px tile, then zeroes his speed and takes one step of gravity from it; he stays in the jumping state and falls from the next frame, starting at 0.25 px/frame.Verified
Mega Man 3 1990Mega Man's position is his center. A fall tests the floor at x − 7, x, and x + 7, 12 px below it, and a rise tests the ceiling at x − 7 and x + 7, 12 px above it; a horizontal move tests x + 8 or x − 8 at 11 px above, level with, and 11 px below the center. Each point reads the 16 px tile holding it.Code
When a horizontal move puts a wall point in a solid tile, the move routine pushes Mega Man back by the point's depth into the tile, so x + 8 ends on the wall's first column moving right and x − 8 on the first column past it moving left. The X fraction stays as it was, and his speed and state are untouched, so he walks in place against the wall.Code
When a rise puts a ceiling point, x − 7 or x + 7 at 12 px above his center, in a solid tile, snap_y_to_ceil adds 16 − ((Y − 12) mod 16) to Mega Man's Y pixel, which puts that point on the row under the tile, keeps the Y fraction, and sets the resting speed, 0.25 px/frame down; he stays airborne. Since a jump runs the airborne routine on its press frame, a ceiling within the first frame's 4.89 px is met on that frame.Code
Super Mario World 1990GetMarioClipping gives 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.Code
Against 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.Code
GetBlockAtPlayer adds a point's offsets to Mario's position and reads the block holding that pixel, x ÷ 16 for the column and y with its low 4 bits cleared for the row; in a horizontal level's layer 1, every point below y $1B0 (432 px) reads as air. Side points stop at blocks $111–$16D, and a falling foot lands on $100–$16D.Code
With Mario's x in the left half of a block column (PlayerBlockXSide 0), collision tests his side points at x+14, and unless he's flush at x mod 16 = 2 marks him blocked on the right; in the right half (1), it tests those at x+2, flush at 13, blocked on the left. After all six points, it moves him 1 px back out of the wall and, if his speed points into the wall, zeroes its high byte but not its low byte.Verified
Mario's head point (x+8, and y+8 big or y+16 small; block-points) is the fourth of collision's six points, after the center and side points and before the feet. In the air, when it is in a solid block, collision moves him down by 15 minus the point's row in the block, keeping the subpixel, so the point ends on the block's bottom row, and zeroes his vertical speed if he was rising. Gravity then acts on that frame as usual. A turn block hit this way skips the move on that frame (turn-block-hit).Verified
On the ground, a head point in a solid block's upper 9 rows (0–8) ejects Mario left: collision marks him blocked on the right and zeroes his horizontal speed's high byte, and the wall push then moves him 1 px left a frame (side-push). In rows 9–15 he isn't moved. Either way it sets the top-blocked bit, and while that bit is set a jump press on the ground doesn't jump.Verified
A turn block ($11E) under the head point is hit from below like any functional block: it becomes bounce sprite 7, the turning turn block. That path doesn't read Powerup, and it breaks a block only when the block's IntBlk_BounceSprite entry is 7; the turn block's entry is 6 (its sprite number is 7), so a plain head hit never breaks a turn block, big or small. On the hit frame collision skips the head's downward move and only zeroes a rising speed.Verified
A ? block under the head point (tile $124, a coin, in the probe) is hit from below: it gives its contents and bounces (block-bounce), and collision then treats it as solid, moving Mario down onto its bottom row and stopping his rise on the same frame (head-hit). When the bounce timer runs out, 7 frames after the hit frame, the cell becomes a used block ($132), which is solid and is never hit again.Verified
Metroid II: Return of Samus 1991Against 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_samusEnemies runs first and compares each enemy's hitbox with Samus's, whose top is set per pose.Code
Sonic the Hedgehog 1991Standing, 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.Code
Against 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).Code
Sonic 1's level collision is 16 × 16 px blocks; a floor sensor reads the solid height of its pixel column in a block, a wall sensor the solid width of its pixel row, and each search looks in the sensor's block and at most one more.Code
On a flat floor, after each ground move, Sonic_AnglePos reads two floor sensors, at his center's X ± his width radius and his center's Y + his height radius (9 and 19 px standing, 7 and 14 curled); the nearer floor counts, and within 14 px either way he snaps to it.Code
In the running game, walking and rolling off steps down built from Green Hill's 9, 10, and 11 px blocks, Sonic stayed on the ground over a 14 px step, his feet dropping 14 px on the frame his trailing floor sensor passed its edge; over a 15 px step he was in the air on that frame, with a Y speed of 0, no jump flag, and still curled if rolling, and the next frame's gravity made his Y speed $38.Verified
In the running game, on flat ground Sonic's wall sensor sat 10 px ahead of where the frame's X speed would put his center and 8 px below it: standing on Green Hill's 14 px blocks (feet on row 961), its 10 px block ahead (top row 950) stopped him and its 9 px block (top row 951) didn't, and curled on its 9 px blocks (feet on row 966), a full block (top row 960) stopped him and a 14 px one (top row 962) didn't. In the air, after the move, his side sensors sat 10 px to either side of his center.Verified
In the running game, walking and rolling into walls of Green Hill's full blocks on flat ground, in 44 runs at speeds up to $A00 (10 of them coasting from $A00 written into his ground speed), a wall at the sensor ahead cut Sonic's X speed by the sensor's depth in whole pixels, 1 to 10 px, so that frame's move stopped the sensor 1 px short of the wall, his center 11 px from its face, and it set his ground speed to 0.Verified
In the running game, Sonic in the air counted as moving mostly down or up by his speeds after gravity: falling rightward or rising leftward once his Y speed was at least 250/256 of his X speed, and falling leftward or rising rightward only once his X speed was under 250/256 of his Y speed. Placed beside a wall of Green Hill's full blocks on the side away from his X motion, which only the down and up checks reach, he was pushed at those Y speeds and not at 1 less, all four ways.Verified
In the running game, with Sonic's position, speeds, and size written into RAM in the air beside walls of Green Hill's full blocks and one frame played, a wall at a side sensor pushed Sonic out by whole pixels, his center 11 px from its face, and set his X speed to 0; moving mostly down or up he was pushed by a wall on either side, moving mostly left or right only by one on that side, and that push ended the frame's checks: with his feet 3 px into the floor he stayed in the air beside the wall and landed away from it.Verified
In the running game, written into the air above Green Hill's blocks, Sonic falling mostly down landed when a floor sensor was inside the ground unless both were deeper than his Y speed in whole pixels plus 8, and moved up by the deeper one's depth: at Y speed $100 he landed 9 px deep and not 10, at $500 13 and not 14, and with one sensor over a pit, or on a block 5 px lower, 12 px deep. Moving mostly sideways and not rising, he landed 19 px deep, and not 20, where his center's row is in the floor; rising, he didn't land.Verified
In the running game, under Green Hill's full blocks, in one standing jump and in one-frame cases whose position and speeds the probe wrote into RAM, Sonic's head sensors met a ceiling only while he moved mostly up or mostly sideways: inside one, he moved down by the depth, his head sensors to the row below it. Moving mostly up, his Y speed became 0 under a flat block, and under its full $A0 block he landed on the ceiling, taking its angle and a ground speed from his Y speed. Moving sideways, his Y speed became 0 if he was rising and stayed if he was falling, and with his feet in the floor he didn't land that frame. Moving mostly down with his head in a block, he wasn't moved.Verified
In the running game, walking and rolling under rows of Green Hill's full blocks 16 and 32 px above the floor, Sonic stayed on the ground with his feet on row 959 and part of himself inside the blocks, and every frame's ground speed matched the flat-ground model.Verified
Standing on flat ground, not on an object, with ground speed 0 after the left and right steps (before friction) and the floor under his center 12 px or more below his feet, Sonic turns to face right if last frame's right floor sensor met no block, or else left if the left one met none, and plays his balancing animation.Code
On stages built in Green Hill Act 1 from the act's full flat 16 × 16 block, the movement lab's Sonic model matches Sonic the Hedgehog itself, run in MAME, on every frame of 100 random stages with random input scripts, three in four with floating blocks, and of the lab's stage presets, until a fall into a pit kills him at the bottom boundary or he nears the end of the built floor.Verified
Mega Man 5 1992Mega Man's position is his center. Standing, walking, and in the air his floor points are 12 px below it at x−7, x, and x+7; his ceiling points 10 px above it at x−7 and x+7; and his wall points 8 px to the side he moves toward, at 9 px above, level with, and 11 px below his center. Tiles are 16 px.Code
When the horizontal move puts a wall point in a solid tile, the move routine pushes Mega Man back by the point's depth into that 16 px tile, so x+8 ends on the wall's first column moving right and x−8 on the first column past it moving left. The X fraction, his speed, and his pose stay, so he walks in place against it.Code
When a rising Mega Man's move puts a ceiling point, x−7 or x+7 at 10 px above his center, in a solid tile, LEEDD adds 15 minus the point's depth into the tile to his Y pixel, which leaves the point on the tile's bottom row, and entity_stop_y sets his speed to −1 px/frame; he stays in the air and falls from the next frame.Code
Sonic the Hedgehog 2 1992Against 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.Code
On stages built in Emerald Hill Act 1 from the act's full flat 16 × 16 block, solid on the collision path Sonic starts on, the movement lab's Sonic 2 model matches Sonic the Hedgehog 2 itself, run in MAME, on every frame of 100 random stages with random input scripts, three in four with floating blocks, and of the lab's stage presets, until a fall into a pit kills him at the bottom boundary or he nears the end of the built floor.Verified
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.Code
Sonic 2's level collision is 16 × 16 px blocks whose layout words carry solidity bits for two collision paths; Sonic starts on the first, testing bit $C for floors and $D for walls and ceilings. As in Sonic 1, each search looks in the sensor's block and at most one more.Code
On flat ground and not on an object, after each ground move AnglePos sets both angle buffers to 3, then reads two floor sensors at his feet, X ± his width radius, each writing its buffer when it meets a block; the nearer distance counts, and a floor up to 14 px above his feet lifts him onto it. Standing on an object, it sets both buffers to 0 and reads no sensors; on a wall or a ceiling it turns the sensors to match (Sonic_WalkVertL, Sonic_WalkCeiling, Sonic_WalkVertR).Code
When both floor sensors are above the floor after a ground move, AnglePos moves Sonic down onto it if it's within his X speed's whole pixels plus 4, at most 14; any farther and he's in the air. Sonic 1 reaches down 14 px at every speed.Code
On the ground, the wall check looks from where this frame's X speed will put him, 10 px ahead of his center and 8 px below it on flat ground, as in Sonic 1 (whose 10 px is sonic_quick_size).Code
On the ground with nonzero ground speed, a wall found ahead (the sensor of wall-sensors inside a block) cuts this frame's X speed so he stops beside it, and sets his ground speed to 0, as in Sonic 1.Code
In the air Sonic_DoLevelCollision picks one of four checks by the direction of his speed: CalcAngle of X and Y speed less $20, to a quarter, as in Sonic 1, with the same angle table.Code
In the air, a wall sensor 10 px from his center inside a block pushes Sonic out by whole pixels and sets his X speed to 0; moving mostly sideways, that ends the frame's checks, as in Sonic 1.Code
Falling mostly down, Sonic lands only if one floor sensor is no deeper in the floor than his Y speed's whole pixels plus 8, as in Sonic 1; moving mostly sideways he lands at any depth while not rising, with fixBugs off.Code
Moving mostly up, a head sensor inside a block moves Sonic down out of it and sets his Y speed to 0 on a flat ceiling; moving mostly sideways it moves him down and stops a rise, and skips the floor check that frame, as in Sonic 1.Code
On the ground nothing checks above Sonic except a jump press; standing or rolling into a block's underside leaves him inside it, as in Sonic 1.Code
Standing on flat ground, not on an object, not sliding, and with d-pad control (move_lock 0), with ground speed 0 after the left and right steps and the floor under his center 12 px or more below his feet, Sonic balances on the side whose floor sensor met no block last frame (the right first). He turns to face that side only when he faces away from it and the floor 6 px back from his center is also 12 px or more below; Sonic 1 turns him at any such edge.Code
Mega Man 6 1993Mega Man 6 tests the tiles at points around his center, from the table at $9119 (X) and $912D (Y): falling or standing, his floor at 12 px below the center, at the center and 7 px to each side; rising, his head at 9 px above it, at the same three; and walls 7 px to the side he moves toward, at 7 px below the center (level with it when rising), 9 px above, and 10 px below. In a slide the high wall point and the head's two side points drop to 3 px above the center (the head's center point stays 9 above), and the low wall point to 12 below. Each point reads the 16 px tile holding it.Code
After each move Mega Man 6 tests his points in a fixed order: the center floor or head point, then the wall point at mid height, then, if he moves sideways, the high wall point, then the two floor or head corners, and last one more wall point, the low one if he moves sideways or the high one if not. A floor or ceiling found pushes him out at once, so the points after it test from where it left him; a wall found ends the frame's tests.Code
When a floor or head point finds a solid tile, Mega Man 6 is pushed out of it by the point's depth in its 16 px tile: from the tile's top half up to the row above it, from its bottom half down to the row below it; his Y fraction stays. Falling or standing, his vertical speed is set to 0; rising, only its whole byte (ceiling-hit). After the frame's tests a push moves him 1 px back down, so a standing Mega Man's floor point lies in the floor's top row. Standing, gravity adds $40 to his speed and his Y every frame and the floor pushes him back, so his Y fraction drifts by $40 a frame while his whole Y stays. Measured in Mesen from power-on near the start of Tomahawk Man's stage, a walk, a slide, and a jump off the ledge at X 160 each landed with his floor point on the top row of the lower floor (row 160, 32 px below the start floor's top row, 128), the speed 0.Verified
When a wall point finds a solid tile, Mega Man 6 is pushed back out across by the point's depth in its 16 px tile, from its left half to the column left of it, from its right half to the column right of it; his X fraction stays, and the frame's other tile tests are skipped. The push also ends a slide. Measured in Mesen from power-on near the start of Tomahawk Man's stage, walking left on the lower floor into the face of the ledge at X 160 held his X at 167, his left wall points on column 160, right of the face, while he kept walking.Verified
At the end of every frame Mega Man 6 holds Mega Man on the screen: his X is kept from 16 px ($A8, which his routine's start sets to $10) to 244 px right of the camera's left edge, with its fraction left as it is, and a Y of 240 or more on the screen's own rows kills him. Measured in Mesen from power-on near the start of Tomahawk Man's stage, where the camera can't scroll left, walking left stopped at X 16 while his X fraction kept changing.Verified
Sonic 3 & Knuckles 1994Against 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.Code
Standing, 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; his wall sensors sit 10 px to either side. These are Sonic 2's sizes.Code
The lab's stages are built of Angel Island Act 1's block 1, a full 16 × 16 px block solid from every side; Sonic 3 & Knuckles's level collision is 16 × 16 px blocks, and a sensor's search looks in its block and at most one more.Code
On a flat floor, not standing on an object, after each ground move, Player_AnglePos reads two floor sensors, at his center's X ± his width radius and his center's Y + his height radius; the nearer floor counts, and from 1 to 14 px into it he moves up to its surface.Code
On flat ground, not on an object, when both floor sensors find the floor more than |X speed's high byte| + 4 px below, at most 14, Sonic leaves the ground with his speeds as they are, unless stick_to_convex is set; closer than that, he moves down to it. Sonic 2 has the same rule; Sonic 1 used a flat 14 px.Code
Outside Competition mode, on flat ground with a ground speed, Sonic's wall sensor sits 10 px ahead of where the frame's speeds would put his center and 8 px below it; in the air his side sensors sit 10 px to either side of his center at its height.Code
On flat ground, with a ground speed and bit 6 of object_control clear (no object carrying him), a wall at the sensor ahead cuts the frame's X speed by the sensor's depth in whole pixels, so the move stops him beside it, and sets the ground speed to 0.Code
In the air SonicKnux_DoLevelCollision picks one of four checks by the direction of his speeds after gravity, from GetArcTan less $20: mostly down, mostly up, mostly left, or mostly right. The arctangent table puts the split where the smaller speed is 250/256 of the larger.Code
Moving mostly down or up, both side sensors push Sonic out of a wall and stop his X speed; moving mostly left or right, only that side's does, and it also sets his ground speed to his Y speed. Unlike Sonic 2, a push moving left or right doesn't end the checks: the ceiling and then the floor are still tested.Code
Sonic's head sensors are read in the air only while he moves mostly up, left, or right. Inside a ceiling he moves down by the depth; moving up under a flat ceiling his Y speed becomes 0, moving sideways only if he was rising, and the floor isn't tested that frame. Moving mostly left, a head 20 px or more inside a ceiling is instead pushed off a wall on his right, a check Sonic 2 lacks.Code
Falling mostly down, Sonic lands when a floor sensor is inside the ground unless both are deeper than his Y speed's whole pixels plus 8, and moves up by the deeper one's depth; moving mostly left or right and not rising, any depth lands him; rising, he doesn't land, except in a wind tunnel.Code
Standing on flat ground, not on an object, not Super or Hyper, with no move_lock or infinite-inertia flag, with ground speed 0 after the left and right steps, and the floor under his center 12 px or more below his feet, Sonic turns to face right if last frame's right floor sensor met no block, or else left if the left one met none, and balances; otherwise Down crouches. Sonic 2 turned him only if the floor 6 px back the other way was also that far down.Code
On the ground, while Background_collision_flag is clear, nothing but a jump press looks above Sonic: walking or rolling under a block that overlaps him, he stays on the ground.Code
On stages built in Angel Island Act 1 from the act's full 16 × 16 block, the movement lab's Sonic 3 & Knuckles model matches the game itself, run in MAME, on every frame of 100 random stages with random input scripts, three in four with floating blocks, and of the lab's stage presets, until a fall into a pit kills him at the bottom boundary or he nears the end of the built floor.Verified
On flat ground, Sonic 3 & Knuckles changes when Sonic rolls and stands: Down curls him only from $100, not Sonic 2's $80, and, off objects, crouches him while he is still moving slower, where Sonic 2 crouched only from a standstill; a roll stands up under $80 with that speed kept, where Sonic 2's rolls on to 0 (both outside pinball mode). In the air he keeps a speed above the top while steering, where Sonic 2 pulled him down to it; a second press after a roll jump gives back steering, which Sonic 2's jump never did; a wall push moving sideways no longer ends the frame's checks; and a head 20 px into a ceiling moving left is pushed off a right wall instead, a check Sonic 2 lacks. Standing over a drop, not Super, he turns toward it at once, where Sonic 2 turned only if the floor 6 px the other way was also low.Code
Celeste 2018Each update starts by looking for ground; while Speed.Y is 0 or more, Madeline is on the ground if her hitbox, moved 1 px down, overlaps a solid or a jump-through platform.Code
Madeline moves one pixel at a time and stops at the pixel before a solid, then the collision callback runs.Dev blog
When Madeline hits a solid sideways in the normal state, OnCollideH zeroes her horizontal speed, unless, while she's dash-attacking, a dash block rebounds, bounces, or ignores her, or a dream block takes her in.Code
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.Code
When Madeline rises into a solid in the normal state, she is moved 1 px up and 1 to 4 px (UpwardCornerCorrection) sideways to the first spot where her hitbox fits, keeping her speed. She tries leftward first unless she is moving right, then rightward unless she is moving left.Code
When Madeline rises into a solid in the normal state and no corner correction fits, her vertical speed is zeroed. The variable-jump timer is zeroed too, unless it still reads at least VarJumpTime − CeilingVarJumpGrace, 0.2 − 0.05 s, which spares hits in the jump's first 0.05 s.Code
Madeline stands up from a duck only where her standing 8 × 11 px hitbox fits (CanUnDuck). Under a solid that's too low, releasing Down on the ground in the normal state, or starting to fall, leaves her ducked. On the ground in the normal state, if she is stopped, she slides at 50 px/s toward room within 4 px.Code
On stages with floating blocks, a frame-by-frame model of Madeline rising into solids, her ducking box, and CanUnDuck matches a statement-by-statement float32 simulation of the released code on every frame of random stages and input scripts.Code

References

  1. ^ abcdSamus is a box around her center: each animation frame's data sets ObjRadY and ObjRadX, 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-disassembly
    How 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.

    In the claim ledger

  2. ^ 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 the claim ledger

  3. ^In Brinstar's bank, the frames of Samus's running, standing, jumping, and somersault animations all give the radii $0F and $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-disassembly
    How 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.

    In the claim ledger

  4. ^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, and MoveSamusRight call 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, VertAccelerate makes the same test under her each frame.Codenmikstas/metroid-disassembly
    How 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.

    In the claim ledger

  5. ^ 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.

    In the claim ledger

  6. ^ abcAgainst the level, PlayerBGCollision tests 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/smb1revised
    How 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.

    In the claim ledger

  7. ^ abcBoundBoxCtrlData gives 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/smb1
    How 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.

    In the claim ledger

  8. ^When a foot point finds an ordinary solid block and Mario isn't moving up, PlayerBGCollision lands him if his Y is less than 5 px into the block's 16 px row; 5 px or more, it calls ImpedePlayerMove in his moving direction instead, which pushes him 1 px back unless he is already moving away, and leaves without checking his sides.CodeXkeeper0/smb1revised
    How 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.

    In the claim ledger

  9. ^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 in Player_CollisionBits, which the next frame's ImposeFriction ANDs with the d-pad, so the next frame's friction ignores the direction into the wall.VerifiedXkeeper0/smb1
    How 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.

    In the claim ledger

  10. ^ 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.

    In the claim ledger

  11. ^ abcGetMarioClipping gives 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.CodeSMWDisX
    How 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.

    In the claim ledger

  12. ^ 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_samusEnemies runs first and compares each enemy's hitbox with Samus's, whose top is set per pose.Codealex-west/M2RoS
    How 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.

    In the claim ledger

  13. ^ 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.

    In the claim ledger

  14. ^ 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.

    In the claim ledger

  15. ^ 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.

    In the claim ledger

  16. ^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/s1disasmrevised
    How 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.

    In the claim ledger

  17. ^ 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.

    In the claim ledger

  18. ^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.

    In the claim ledger

  19. ^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.

    In the claim ledger

Sources

Code

Secondary