Difference between revisions of "Subpixels"

From ALttP Speedrunning Wiki
Jump to: navigation, search
 
(57 intermediate revisions by 2 users not shown)
Line 1: Line 1:
This game uses subpixels for its movement. This is how Link gets the movement speed of 2-1-2-1 on normal ground etc. This mechanic is not fully understood yet, so there might be some errors on this page.
+
This game uses subpixels for its movement. This is how Link gets the movement speed of 2-1-2-1 on normal ground etc.
  
If you want to help figure this out, you can memory watch 7E002A and 7E002B in your emulator (might be 002A and 002B in some emulators). Those are the Y and X subpixels.
+
tl;dr: You have a "base speed" for any type of movement (0-4), and sometimes you get an extra pixel boost. If you move in the leftwards or upwards direction the pixel boost happens earlier (and in fact, it will always happen on the first frame of movement, this is why pumping is a thing).
  
== How subpixels are set ==
+
== How the coordinate and subpixel is updated during movement ==
  
* When moving in one direction, the subpixel is incremented or decremented depending on the surface Link is moving on, and which direction he is moving.
+
===Speed===
* Walking upwards or leftwards ''increments'' the corresponding X/Y subpixel, walking downwards or rightwards ''decrements'' the corresponding X/Y subpixel.
 
* The only way to "start over" (reset) the subpixel value, is by changing direction of movement. A movement after a standstill counts as changing the direction of movement.
 
* Starting/executing a dash will not move the subpixels at all. But canceling a dash with a movement (holding another direction for 2f or more) will count as normal movement from a standstill.
 
* If you start a dash with a certain subpixel, then transition and hold the dpad to move forward on the next screen, the subpixel is not reset - you continue where you left off before you started the dash.
 
  
== Explanation on why the movement works as it does ==
+
See the table below for what speed Link has in different situations.
  
This is not really verified in any other way than it fits what we can see when frame advancing while looking at the coordinate and subpixels.
+
The speed values only applies to one axis, so for diagonal movement or movement into a slope, the total speed {{WP|Pythagorean theorem|will be higher}}.
  
* When the subpixel wraps, your movement speed gets a -1.  
+
{{#css:
* On normal ground, the default movement speed is 2.
+
.right-3 td:nth-child(3) {
* On stairs, the default movement speed is 1.
+
text-align: right;
 +
}
 +
}}
 +
{| class="wikitable sortable right-3"
 +
! Where
 +
! Movement
 +
! Speed (hex)
 +
! Pattern
 +
! Speed (pixels/frame)
 +
|-
 +
| Ground
 +
| Cardinal
 +
| {{HEX2|18}}
 +
| {{Subp|18}}
 +
| 1.5
 +
|-
 +
| Ground
 +
| Diagonal
 +
| {{HEX2|10}}
 +
| {{Subp|10}}
 +
| 1.0
 +
|-
 +
| Ground
 +
| Dashing
 +
| {{HEX2|40}}
 +
| {{Subp|40}}
 +
| 4.0
 +
|-
 +
| Ground
 +
| Sword out, Cardinal
 +
| {{HEX2|14}}
 +
| {{Subp|14}}
 +
| 1.25
 +
|-
 +
| Ground
 +
| Sword out, Diagonal
 +
| {{HEX2|0D}}
 +
| {{Subp|0D}}
 +
| 0.8125
 +
|-
 +
| Ground
 +
| Holding object, Cardinal
 +
| {{HEX2|14}}
 +
| {{Subp|14}}
 +
| 1.25
 +
|-
 +
| Ground
 +
| Holding object, Diagonal
 +
| {{HEX2|0D}}
 +
| {{Subp|0D}}
 +
| 0.8125
 +
|-
 +
| Ground
 +
| Spinspeed, Cardinal
 +
| {{HEX2|40}}
 +
| {{Subp|40}}
 +
| 4.0
 +
|-
 +
| Ground
 +
| Spinspeed, Diagonal
 +
| {{HEX2|2A}}
 +
| {{Subp|2A}}
 +
| 2.625
 +
|-
 +
| Ground
 +
| Pushing statue, Cardinal
 +
| {{HEX2|0C}}
 +
| {{Subp|0C}}
 +
| 0.75
 +
|-
 +
| Ground
 +
| Pushing statue, Diagonal
 +
| {{HEX2|10}}
 +
| {{Subp|10}}
 +
| 1.0
 +
|-
 +
| Ground
 +
| Pushing statue, Sword out, Cardinal
 +
| {{HEX2|14}}
 +
| {{Subp|14}}
 +
| 1.25
 +
|-
 +
| Ground
 +
| Pushing statue, Sword out, Diagonal
 +
| {{HEX2|0D}}
 +
| {{Subp|0D}}
 +
| 0.8125
 +
|-
 +
| Ground
 +
| Pulling statue
 +
| {{HEX2|04}}
 +
| {{Subp|04}}
 +
| 0.25
  
'''Example: Walking on ground (movement speed is 2), upwards'''
+
|-
* frame 1: Subpixel = 0x00 + 0x80 = 0x80. Doesn't wrap, so you get 2.
+
| Ground, Slope
* frame 2: Subpixel = 0x80 + 0x80 = 0x00. Wraps, so you get 2 - 1 = 1.
+
| Cardinal
* Repeats
+
| {{HEX2|10}}
 +
| {{Subp|10}}
 +
| 1.0
 +
|-
 +
| Ground, Slope
 +
| Dashing
 +
| {{HEX2|2A}}
 +
| {{Subp|2A}}
 +
| 2.625
 +
|-
 +
| Ground, Slope
 +
| Sword out, Cardinal
 +
| {{HEX2|0D}}
 +
| {{Subp|0D}}
 +
| 0.8125
 +
|-
 +
| Ground, Slope
 +
| Holding object, Cardinal
 +
| {{HEX2|0D}}
 +
| {{Subp|0D}}
 +
| 0.8125
  
'''Example: Walking on ground (movement speed is 2), downwards'''
+
|-
* frame 1: Subpixel = 0x00 - 0x80 = 0x80. Wraps, so you get 1.
+
| Stairs
* frame 2: Subpixel = 0x80 - 0x80 = 0x00. Doesn't wrap, so you get 2.
+
| Cardinal
* Repeats
+
| {{HEX2|0B}}
 +
| {{Subp|0B}}
 +
| 0.6875
 +
|-
 +
| Stairs
 +
| Diagonal
 +
| {{HEX2|0B}}
 +
| {{Subp|0B}}
 +
| 0.6875
 +
|-
 +
| Stairs
 +
| Dashing
 +
| {{HEX2|0A}}
 +
| {{Subp|0A}}
 +
| 0.625
 +
|-
 +
| Stairs
 +
| Sword out, Cardinal
 +
| {{HEX2|0B}}
 +
| {{Subp|0B}}
 +
| 0.6875
 +
|-
 +
| Stairs
 +
| Sword out, Diagonal
 +
| {{HEX2|0B}}
 +
| {{Subp|0B}}
 +
| 0.6875
 +
|-
 +
| Stairs
 +
| Holding object, Cardinal
 +
| {{HEX2|0B}}
 +
| {{Subp|0B}}
 +
| 0.6875
 +
|-
 +
| Stairs
 +
| Holding object, Diagonal
 +
| {{HEX2|0B}}
 +
| {{Subp|0B}}
 +
| 0.6875
 +
|-
 +
| Stairs
 +
| Spinspeed, Cardinal
 +
| {{HEX2|0A}}
 +
| {{Subp|0A}}
 +
| 0.625
 +
|-
 +
| Stairs
 +
| Spinspeed, Diagonal
 +
| {{HEX2|18}}
 +
| {{Subp|18}}
 +
| 1.5
  
'''Example: Walking on stairs (movement speed is 1), upwards'''
+
|-
* frame 1: Subpixel = 0x00 + 0x50 = 0x50. Doesn't wrap, so you get 1.
+
| Shallow water/Grass
* frame 2: Subpixel = 0x50 + 0x50 = 0xA0. Doesn't wrap, so you get 1.
+
| Cardinal
* frame 3: Subpixel = 0xA0 + 0x50 = 0xF0. Doesn't wrap, so you get 1.
+
| {{HEX2|14}}
* frame 4: Subpixel = 0xF0 + 0x50 = 0x40. Wraps, so you get 1 - 1 = 0.
+
| {{Subp|14}}
 +
| 1.25
 +
|-
 +
| Shallow water/Grass
 +
| Diagonal
 +
| {{HEX2|0D}}
 +
| {{Subp|0D}}
 +
| 0.8125
 +
|-
 +
| Shallow water/Grass
 +
| Dashing
 +
| {{HEX2|30}}
 +
| {{Subp|30}}
 +
| 3.0
 +
|-
 +
| Shallow water/Grass
 +
| Sword out, Cardinal
 +
| {{HEX2|10}}
 +
| {{Subp|10}}
 +
| 1.0
 +
|-
 +
| Shallow water/Grass
 +
| Sword out, Diagonal
 +
| {{HEX2|08}}
 +
| {{Subp|08}}
 +
| 0.5
 +
|-
 +
| Shallow water/Grass
 +
| Holding object, Cardinal
 +
| {{HEX2|14}}
 +
| {{Subp|14}}
 +
| 1.25
 +
|-
 +
| Shallow water/Grass
 +
| Holding object, Diagonal
 +
| {{HEX2|0D}}
 +
| {{Subp|0D}}
 +
| 0.8125
 +
|-
 +
| Shallow water/Grass
 +
| Spinspeed, Cardinal
 +
| {{HEX2|30}}
 +
| {{Subp|30}}
 +
| 3.0
 +
|-
 +
| Shallow water/Grass
 +
| Spinspeed, Diagonal
 +
| {{HEX2|18}}
 +
| {{Subp|18}}
 +
| 1.5
  
'''Example: Walking on stairs (movement speed is 1), downwards'''
+
|-
* frame 1: Subpixel = 0x00 - 0x50 = 0xB0. Wraps, so you get 1 - 1 = 0.
+
| Old man follower, Ground
* frame 2: Subpixel = 0xB0 - 0x50 = 0x60. Doesn't wrap, so you get 1.
+
| Cardinal
* frame 3: Subpixel = 0x60 - 0x50 = 0x10. Doesn't wrap, so you get 1.
+
| {{HEX2|14}}
* frame 4: Subpixel = 0x10 - 0x50 = 0xC0. Wraps, so you get 1 - 1 = 0.
+
| {{Subp|14}}
 +
| 1.25
 +
|-
 +
| Old man follower, Ground
 +
| Diagonal
 +
| {{HEX2|0D}}
 +
| {{Subp|0D}}
 +
| 0.8125
 +
|-
 +
| Old man follower, Ground
 +
| Dashing
 +
| {{HEX2|14}}
 +
| {{Subp|14}}
 +
| 1.25
 +
|-
 +
| Old man follower, Ground
 +
| Sword out, Cardinal
 +
| {{HEX2|14}}
 +
| {{Subp|14}}
 +
| 1.25
 +
|-
 +
| Old man follower, Ground
 +
| Sword out, Diagonal
 +
| {{HEX2|0D}}
 +
| {{Subp|0D}}
 +
| 0.8125
 +
|-
 +
| Old man follower, Slope
 +
| Cardinal
 +
| {{HEX2|0D}}
 +
| {{Subp|0D}}
 +
| 0.8125
 +
|-
 +
| Old man follower, Slope
 +
| Dashing
 +
| {{HEX2|0D}}
 +
| {{Subp|0D}}
 +
| 0.8125
 +
|-
 +
| Old man follower, Slope
 +
| Sword out, Cardinal
 +
| {{HEX2|0D}}
 +
| {{Subp|0D}}
 +
| 0.8125
 +
|}
  
Basically it works like an "anti subpixel".
+
* Getting damage boosted/recoiled gives different speeds for different angels. Each axis can move in a maximum of {{HEX2|18}} or 1.5px/f. The best angle in terms of speed would be a completely diagonal one, which would give {{HEX2|18}}/{{HEX2|18}}.
 +
* When walking leftwards or upwards, the speed is reversed ({{HEX2|18}} becomes {{HEX2|E8}})
 +
* The most significant digit (1 in the case of walking on normal ground) is added to the coordinate directly, no matter what.
 +
* The least significant digit (8 in the case of walking on normal ground) is shifted left four times (8 becomes {{HEX2|80}}), and added first to the subpixel. If this causes the subpixel to overflow/wrap, we add an additional pixel to the coordinate.
 +
* Example: The speed value of 16 (or {{HEX2|10}} in hex) represents a clean 1 pixel per frame. 17 ({{HEX2|11}} in hex) would be 1 pixel per frame, with an additional pixel being added every 16th frame.
 +
 
 +
===Subpixel===
 +
 
 +
* The game will reset Link's subpixel whenever you change direction of movement. A movement after a standstill counts as changing the direction of movement.
 +
** The game only looks at your dpad to find out if the direction changed. So if you walk upwards alongside a wall, and then press up and rightwards into the wall, it will treat this as a change of direction, even though Link is still moving upwards.
 +
:: This means that pumping into a wall will function as two pumps, both when you press (from {{B|^}} to {{B|^>}}) and when you release (from {{B|^>}} to {{B|^}}).
 +
* Starting/executing a dash will not reset the subpixel. But if you cancel the dash with a movement, it will be reset.
 +
** If you however start a dash that ends up transitioning to another screen, the subpixel is not reset unless you start moving in a different direction on the next screen.
 +
* Some items resets your subpixel and others do not.
 +
** Does not reset subpixel: Using sword, boomerang, hammer, rod, hookshot, dropping a bomb or picking it up.
 +
** Resets subpixel: Using medallion, powder.
 +
 
 +
===Example: Walking on ground (movement speed is {{HEX2|18}})===
 +
 
 +
* Downwards
 +
** frame 1: Subpixel = {{HEX|00}} + {{HEX|80}} = {{HEX|80}}. Coordinate = 0 + 1 + 0 = 1
 +
** frame 2: Subpixel = {{HEX|80}} + {{HEX|80}} = {{HEX|00}}. Coordinate = 1 + 1 + 1 = 3  (subpixel overflow)
 +
** frame 3: Subpixel = {{HEX|00}} + {{HEX|80}} = {{HEX|80}}. Coordinate = 3 + 1 + 0 = 4
 +
** frame 4: Subpixel = {{HEX|80}} + {{HEX|80}} = {{HEX|00}}. Coordinate = 4 + 1 + 1 = 6  (subpixel overflow)
 +
** Etc
 +
 
 +
* Upwards
 +
** frame 1: Subpixel = {{HEX|00}} - {{HEX|80}} = {{HEX|80}}. Coordinate = 0 + 1 + 1 = 2  (subpixel overflow)
 +
** frame 2: Subpixel = {{HEX|80}} - {{HEX|80}} = {{HEX|00}}. Coordinate = 2 + 1 + 0 = 3
 +
** Etc
 +
 
 +
'''Example: Walking on stairs (movement speed is {{HEX2|0B}})'''
 +
 
 +
* Downwards
 +
** frame 1: Subpixel = {{HEX|00}} + {{HEX|B0}} = {{HEX|B0}}. Coordinate = 0 + 0 + 0 = 0
 +
** frame 2: Subpixel = {{HEX|B0}} + {{HEX|B0}} = {{HEX|60}}. Coordinate = 0 + 0 + 1 = 1  (subpixel overflow)
 +
** frame 3: Subpixel = {{HEX|60}} + {{HEX|B0}} = {{HEX|10}}. Coordinate = 1 + 0 + 1 = 2  (subpixel overflow)
 +
** frame 4: Subpixel = {{HEX|10}} + {{HEX|B0}} = {{HEX|C0}}. Coordinate = 2 + 0 + 0 = 2
 +
** Etc
 +
 
 +
* Upwards
 +
** frame 1: Subpixel = {{HEX|00}} - {{HEX|B0}} = {{HEX|50}}. Coordinate = 0 + 0 + 1 = 1  (subpixel overflow)
 +
** frame 2: Subpixel = {{HEX|50}} - {{HEX|B0}} = {{HEX|A0}}. Coordinate = 1 + 0 + 1 = 2  (subpixel overflow)
 +
** frame 3: Subpixel = {{HEX|A0}} - {{HEX|B0}} = {{HEX|F0}}. Coordinate = 2 + 0 + 1 = 3  (subpixel overflow)
 +
** frame 4: Subpixel = {{HEX|F0}} - {{HEX|B0}} = {{HEX|40}}. Coordinate = 3 + 0 + 0 = 3
 +
** Etc
  
 
== How it affects slope dashes ==
 
== How it affects slope dashes ==
  
Dashing on a slope is a fairly volatile thing when you frame advance through it. Link will move anything from 0 to 3 pixels in both the horizontal or vertical direction, seemingly at random. We're not sure the exact rules, but it looks like different parts of the slope will give different pixel boosts.
+
Dashing on a slope is a fairly volatile thing when you frame advance through it. Link will move anything from 0 to 3 pixels in both the horizontal or vertical direction, seemingly at random. And you will get random 1px/f in only one direction, and sometimes 0px/f in both directions. It is not completely understood.
 +
 
 +
One cause for the slowdowns seems to be the same mechanic as "corner nudging". The game thinks Link needs to be better aligned (too close to the wall in one direction) and moves him 1px in one direction away from the wall. This seems to happen less if your subpixels for both axes are the same, and you are moving in either a "pumping direction" or "antipumping direction" for both axes ({{B|<^}} or {{B|v>}}). The main reason for this is that Link's coordinates updates equally in both directions in this case, since the subpixel will overflow/wrap at the same time throughout the length of the dash. So when the game auto-corrects Link's position, the dashing pattern doesn't mess with it afterwards. It still can happen though.
 +
 
 +
Another cause for slowdowns seems to happen when Link hits the very first pixel of a 8x8 corner tile (when his hex coordinates ends with 0 or 8). This can cause a 1px movement and sometimes a 0px movement.
  
Another factor is subpixels. Depending on what subpixel you have, you might or might not get an extra pixel boost at any point during the slope dash. This means that even if you start your dash from the exact same coordinate, the slopedash can go fast or slow depending on the subpixel value.
+
What is certain is that the subpixel you have when a dash is started will affect how the slope dash ends up working out. You can get pixel boosts in either directions quicker/slower depending on what the subpixels are when you hit the corner, which would alter the path Link takes through the slope and create a {{WP|Butteryfly effect}}. So even if you start your dash from the exact same coordinate, the slope dash can go fast or slow depending what the subpixel value is before the dash.
  
One way to make sure you get the same subpixel is to hit diagonal before starting the dash.
+
One way to make sure you get the same subpixel every time is to hit diagonal before starting the dash (Link would actually have to move diagonally too) This is because you 1. get a change in direction, resetting the subpixels, and 2. diagonal movement is a clean 1px/f so the subpixel will remain 0.
  
 
=== Bomb Clips ===
 
=== Bomb Clips ===
  
Since a criteria for performing a [[Bomb Clip]] is that you are positioned exactly below the explosion, your subpixel value will matter just as much as your coordinate, since different paths through the slope might or might not include the coordinate where Link is directly below.
+
Since a criteria for performing a [[Bomb Clip]] is that you are positioned ''exactly'' below the explosion, your subpixel value will matter just as much as your coordinate when you start the slope dash, since different paths through the slope might or might not include the coordinate you need to visit.
 +
 
 +
Some setups works the same for all subpixels, in which case only the coordinate matters.
 +
 
 +
== Swimming ==
 +
 
 +
The below is mostly just some observations from frame advancing in emulator, and might not be 100% accurate.
  
Some setups works the same for both subpixel=0x00 and subpixel=0x80, in which case it doesn't matter.
+
* Swimming is 100% acceleration based.
 +
* The acceleration seems to be around 1/32 pixels per frame. So after 4 frames of holding {{B|>}}, you will have the speed 1/8 pixels per frame (or 0.125 pixels per frame).
 +
* Deacceleration seems to be around 3/64 pixels per frame.
 +
* The acceleration does not change by pressing {{B|A|/|B|/|Y}}, instead you get a higher max speed.
 +
* Max speeds:
 +
** Dpad movement, Cardinal: ~0.9px/f
 +
** Dpad movement, Diagonal: ~0.65px/f
 +
** Mash {{B|A|/|B|/|Y}}, Cardinal: 1.5px/f
 +
** Mash {{B|A|/|B|/|Y}}, Diagonal: 1px/f
 +
* Since pressing {{B|A|/|B|/|Y}} doesn't change ''how fast'' you get to ~0.9px/f, you should wait until you've hit the normal max speed (0.9px/f) before starting to mash. That way you will stay longer at the higher max speed before having to mash again.
 +
: Worst case (pressing {{B|A}} right after pressing {{B|dpad}} from a standstill) you only spend 1f on 1.5px/f. It takes around 31f from a standstill to reach 0.9px/f.
 +
* After reaching absolute max speed (1.5px/f) and it starts decelerating back to 0.9px/f, repressing {{B|A|/|B|/|Y}} works weirldy: If you press it at 23/16 pixels per frame, you get back up at 24/16 (or 1.5px/f). But if you press it at e.g. 21/16 pixels per frame, the next max speed will be 22/16 (1.375px/f). Basically it rounds up to the next even sixteenth.
 +
: Worst case, if you let Link deaccelerate for ~12f before repressing {{B|A|/|B|/|Y}} you will be stuck with a max speed of ~1px/f for a while, until it deaccelerates down to 0.9px/f again.
 +
: So there's multiple reasons to mash as fast as you can when swimming (or time it).
  
If a setup requires a specific subpixel, you would need to go from a standstill to a movement for an exact amount of frames, before starting the dash (for example hit > + A on the same frame).
+
[[Category:Tech]]

Latest revision as of 11:02, 22 May 2019

This game uses subpixels for its movement. This is how Link gets the movement speed of 2-1-2-1 on normal ground etc.

tl;dr: You have a "base speed" for any type of movement (0-4), and sometimes you get an extra pixel boost. If you move in the leftwards or upwards direction the pixel boost happens earlier (and in fact, it will always happen on the first frame of movement, this is why pumping is a thing).

How the coordinate and subpixel is updated during movement

Speed

See the table below for what speed Link has in different situations.

The speed values only applies to one axis, so for diagonal movement or movement into a slope, the total speed will be higherWikipedia logo.svg.


Where Movement Speed (hex) Pattern Speed (pixels/frame)
Ground Cardinal $18 2, 1, 2, 1 1.5
Ground Diagonal $10 1, 1, 1, 1 1.0
Ground Dashing $40 4, 4, 4, 4 4.0
Ground Sword out, Cardinal $14 2, 1, 1, 1 1.25
Ground Sword out, Diagonal $0D 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 0.8125
Ground Holding object, Cardinal $14 2, 1, 1, 1 1.25
Ground Holding object, Diagonal $0D 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 0.8125
Ground Spinspeed, Cardinal $40 4, 4, 4, 4 4.0
Ground Spinspeed, Diagonal $2A 3, 3, 2, 3, 3, 2, 3, 2 2.625
Ground Pushing statue, Cardinal $0C 1, 1, 1, 0 0.75
Ground Pushing statue, Diagonal $10 1, 1, 1, 1 1.0
Ground Pushing statue, Sword out, Cardinal $14 2, 1, 1, 1 1.25
Ground Pushing statue, Sword out, Diagonal $0D 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 0.8125
Ground Pulling statue $04 1, 0, 0, 0 0.25
Ground, Slope Cardinal $10 1, 1, 1, 1 1.0
Ground, Slope Dashing $2A 3, 3, 2, 3, 3, 2, 3, 2 2.625
Ground, Slope Sword out, Cardinal $0D 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 0.8125
Ground, Slope Holding object, Cardinal $0D 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 0.8125
Stairs Cardinal $0B 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0 0.6875
Stairs Diagonal $0B 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0 0.6875
Stairs Dashing $0A 1, 1, 0, 1, 1, 0, 1, 0 0.625
Stairs Sword out, Cardinal $0B 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0 0.6875
Stairs Sword out, Diagonal $0B 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0 0.6875
Stairs Holding object, Cardinal $0B 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0 0.6875
Stairs Holding object, Diagonal $0B 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0 0.6875
Stairs Spinspeed, Cardinal $0A 1, 1, 0, 1, 1, 0, 1, 0 0.625
Stairs Spinspeed, Diagonal $18 2, 1, 2, 1 1.5
Shallow water/Grass Cardinal $14 2, 1, 1, 1 1.25
Shallow water/Grass Diagonal $0D 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 0.8125
Shallow water/Grass Dashing $30 3, 3, 3, 3 3.0
Shallow water/Grass Sword out, Cardinal $10 1, 1, 1, 1 1.0
Shallow water/Grass Sword out, Diagonal $08 1, 0, 1, 0 0.5
Shallow water/Grass Holding object, Cardinal $14 2, 1, 1, 1 1.25
Shallow water/Grass Holding object, Diagonal $0D 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 0.8125
Shallow water/Grass Spinspeed, Cardinal $30 3, 3, 3, 3 3.0
Shallow water/Grass Spinspeed, Diagonal $18 2, 1, 2, 1 1.5
Old man follower, Ground Cardinal $14 2, 1, 1, 1 1.25
Old man follower, Ground Diagonal $0D 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 0.8125
Old man follower, Ground Dashing $14 2, 1, 1, 1 1.25
Old man follower, Ground Sword out, Cardinal $14 2, 1, 1, 1 1.25
Old man follower, Ground Sword out, Diagonal $0D 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 0.8125
Old man follower, Slope Cardinal $0D 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 0.8125
Old man follower, Slope Dashing $0D 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 0.8125
Old man follower, Slope Sword out, Cardinal $0D 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 0.8125
  • Getting damage boosted/recoiled gives different speeds for different angels. Each axis can move in a maximum of $18 or 1.5px/f. The best angle in terms of speed would be a completely diagonal one, which would give $18/$18.
  • When walking leftwards or upwards, the speed is reversed ($18 becomes $E8)
  • The most significant digit (1 in the case of walking on normal ground) is added to the coordinate directly, no matter what.
  • The least significant digit (8 in the case of walking on normal ground) is shifted left four times (8 becomes $80), and added first to the subpixel. If this causes the subpixel to overflow/wrap, we add an additional pixel to the coordinate.
  • Example: The speed value of 16 (or $10 in hex) represents a clean 1 pixel per frame. 17 ($11 in hex) would be 1 pixel per frame, with an additional pixel being added every 16th frame.

Subpixel

  • The game will reset Link's subpixel whenever you change direction of movement. A movement after a standstill counts as changing the direction of movement.
    • The game only looks at your dpad to find out if the direction changed. So if you walk upwards alongside a wall, and then press up and rightwards into the wall, it will treat this as a change of direction, even though Link is still moving upwards.
This means that pumping into a wall will function as two pumps, both when you press (from ^ to ^>) and when you release (from ^> to ^).
  • Starting/executing a dash will not reset the subpixel. But if you cancel the dash with a movement, it will be reset.
    • If you however start a dash that ends up transitioning to another screen, the subpixel is not reset unless you start moving in a different direction on the next screen.
  • Some items resets your subpixel and others do not.
    • Does not reset subpixel: Using sword, boomerang, hammer, rod, hookshot, dropping a bomb or picking it up.
    • Resets subpixel: Using medallion, powder.

Example: Walking on ground (movement speed is $18)

  • Downwards
    • frame 1: Subpixel = 0x00 + 0x80 = 0x80. Coordinate = 0 + 1 + 0 = 1
    • frame 2: Subpixel = 0x80 + 0x80 = 0x00. Coordinate = 1 + 1 + 1 = 3 (subpixel overflow)
    • frame 3: Subpixel = 0x00 + 0x80 = 0x80. Coordinate = 3 + 1 + 0 = 4
    • frame 4: Subpixel = 0x80 + 0x80 = 0x00. Coordinate = 4 + 1 + 1 = 6 (subpixel overflow)
    • Etc
  • Upwards
    • frame 1: Subpixel = 0x00 - 0x80 = 0x80. Coordinate = 0 + 1 + 1 = 2 (subpixel overflow)
    • frame 2: Subpixel = 0x80 - 0x80 = 0x00. Coordinate = 2 + 1 + 0 = 3
    • Etc

Example: Walking on stairs (movement speed is $0B)

  • Downwards
    • frame 1: Subpixel = 0x00 + 0xB0 = 0xB0. Coordinate = 0 + 0 + 0 = 0
    • frame 2: Subpixel = 0xB0 + 0xB0 = 0x60. Coordinate = 0 + 0 + 1 = 1 (subpixel overflow)
    • frame 3: Subpixel = 0x60 + 0xB0 = 0x10. Coordinate = 1 + 0 + 1 = 2 (subpixel overflow)
    • frame 4: Subpixel = 0x10 + 0xB0 = 0xC0. Coordinate = 2 + 0 + 0 = 2
    • Etc
  • Upwards
    • frame 1: Subpixel = 0x00 - 0xB0 = 0x50. Coordinate = 0 + 0 + 1 = 1 (subpixel overflow)
    • frame 2: Subpixel = 0x50 - 0xB0 = 0xA0. Coordinate = 1 + 0 + 1 = 2 (subpixel overflow)
    • frame 3: Subpixel = 0xA0 - 0xB0 = 0xF0. Coordinate = 2 + 0 + 1 = 3 (subpixel overflow)
    • frame 4: Subpixel = 0xF0 - 0xB0 = 0x40. Coordinate = 3 + 0 + 0 = 3
    • Etc

How it affects slope dashes

Dashing on a slope is a fairly volatile thing when you frame advance through it. Link will move anything from 0 to 3 pixels in both the horizontal or vertical direction, seemingly at random. And you will get random 1px/f in only one direction, and sometimes 0px/f in both directions. It is not completely understood.

One cause for the slowdowns seems to be the same mechanic as "corner nudging". The game thinks Link needs to be better aligned (too close to the wall in one direction) and moves him 1px in one direction away from the wall. This seems to happen less if your subpixels for both axes are the same, and you are moving in either a "pumping direction" or "antipumping direction" for both axes (<^ or v>). The main reason for this is that Link's coordinates updates equally in both directions in this case, since the subpixel will overflow/wrap at the same time throughout the length of the dash. So when the game auto-corrects Link's position, the dashing pattern doesn't mess with it afterwards. It still can happen though.

Another cause for slowdowns seems to happen when Link hits the very first pixel of a 8x8 corner tile (when his hex coordinates ends with 0 or 8). This can cause a 1px movement and sometimes a 0px movement.

What is certain is that the subpixel you have when a dash is started will affect how the slope dash ends up working out. You can get pixel boosts in either directions quicker/slower depending on what the subpixels are when you hit the corner, which would alter the path Link takes through the slope and create a Butteryfly effectWikipedia logo.svg. So even if you start your dash from the exact same coordinate, the slope dash can go fast or slow depending what the subpixel value is before the dash.

One way to make sure you get the same subpixel every time is to hit diagonal before starting the dash (Link would actually have to move diagonally too) This is because you 1. get a change in direction, resetting the subpixels, and 2. diagonal movement is a clean 1px/f so the subpixel will remain 0.

Bomb Clips

Since a criteria for performing a Bomb Clip is that you are positioned exactly below the explosion, your subpixel value will matter just as much as your coordinate when you start the slope dash, since different paths through the slope might or might not include the coordinate you need to visit.

Some setups works the same for all subpixels, in which case only the coordinate matters.

Swimming

The below is mostly just some observations from frame advancing in emulator, and might not be 100% accurate.

  • Swimming is 100% acceleration based.
  • The acceleration seems to be around 1/32 pixels per frame. So after 4 frames of holding >, you will have the speed 1/8 pixels per frame (or 0.125 pixels per frame).
  • Deacceleration seems to be around 3/64 pixels per frame.
  • The acceleration does not change by pressing A/B/Y, instead you get a higher max speed.
  • Max speeds:
    • Dpad movement, Cardinal: ~0.9px/f
    • Dpad movement, Diagonal: ~0.65px/f
    • Mash A/B/Y, Cardinal: 1.5px/f
    • Mash A/B/Y, Diagonal: 1px/f
  • Since pressing A/B/Y doesn't change how fast you get to ~0.9px/f, you should wait until you've hit the normal max speed (0.9px/f) before starting to mash. That way you will stay longer at the higher max speed before having to mash again.
Worst case (pressing A right after pressing dpad from a standstill) you only spend 1f on 1.5px/f. It takes around 31f from a standstill to reach 0.9px/f.
  • After reaching absolute max speed (1.5px/f) and it starts decelerating back to 0.9px/f, repressing A/B/Y works weirldy: If you press it at 23/16 pixels per frame, you get back up at 24/16 (or 1.5px/f). But if you press it at e.g. 21/16 pixels per frame, the next max speed will be 22/16 (1.375px/f). Basically it rounds up to the next even sixteenth.
Worst case, if you let Link deaccelerate for ~12f before repressing A/B/Y you will be stuck with a max speed of ~1px/f for a while, until it deaccelerates down to 0.9px/f again.
So there's multiple reasons to mash as fast as you can when swimming (or time it).