Moving with Fixed-Point Numbers

Gives coordinates and velocities a fractional part so characters can move with sub-pixel precision.

Why a fractional part is needed

If coordinates are kept only in whole pixels, velocity can only take discrete steps such as “1 pixel per frame” or “2 pixels per frame.” To create motion such as slow acceleration or gradually falling under gravity, you need a unit finer than one pixel (a subpixel).

Here we use a unit that divides one pixel into 256 parts.

VariableSizeContents
$101 byteFractional part of the X coordinate (in units of 1/256 pixel)
$11/$122 bytesInteger part of the X coordinate (pixels)
$14/$152 bytesVelocity in the X direction (signed, in units of 1/256 pixel)

$10-$12 is treated as a 24-bit value in units of 1/256 pixel.

Adding velocity to the coordinate

The velocity is a signed 16-bit value, so when adding it to the 24-bit coordinate, fill the high byte with the sign (sign-extend it) before adding.

; add the velocity to the X coordinate
    REP #$20
    CLC
    LDA $10
    ADC $14         ; low 16 bits of the coordinate + velocity
    STA $10
    SEP #$20
    LDA.b #$00
    BIT $15         ; check the sign of the velocity (bit 7)
    BPL .plus
    DEC A           ; for a negative velocity the high byte is $FF
.plus
    ADC $12         ; add the carry and the sign-extended high byte
    STA $12

The LDA, BIT and DEC instructions do not change the carry flag, so the carry from the first ADC instruction is passed straight to the last ADC instruction.

Acceleration and gravity

Acceleration and gravity are expressed by adding a small value to the velocity every frame as well.

; add gravity to the Y velocity ($18/$19) and cap it at the maximum fall speed
    REP #$20
    LDA $18
    CLC
    ADC.w #$0040    ; accelerate by 0.25 pixels/frame each frame
    BMI .store      ; leave it as is while rising (negative velocity)
    CMP.w #$0400    ; maximum fall speed: 4 pixels/frame
    BCC .store
    LDA.w #$0400
.store
    STA $18

Displaying on screen

Only the integer part is written to the sprite’s OAM.

    SEP #$20
    LDA $11
    SEC
    SBC $40         ; subtract the camera X coordinate to get the on-screen coordinate
    STA $0200       ; X coordinate in the OAM copy

See also

Multi-precision addition, subtraction and comparison
Handling signed values
Displaying sprites