The Core Animation Loop

Creating animation is a three-step process repeated every game frame (ideally synchronized with VSync, as discussed in Part 25):

  1. Erase: Write the background over the sprite’s current location.
  2. Update: Change the sprite’s X/Y coordinates and/or its graphical frame number.
  3. Draw: Render the sprite at its new location.

Updating Sprite Coordinates

To move a sprite, you modify the X-Coordinate and Y-Coordinate fields within its memory descriptor (from Part 31).

Example: Moving a Sprite Right by One Pixel

We use the Index Register ($IX$) to point to the sprite’s data block, and the INC instruction for a fast 16-bit increment of the X-coordinate.

SPRITE_X_ADDR EQU +0        ; X-coordinate starts at offset 0
SPRITE_Y_ADDR EQU +2        ; Y-coordinate starts at offset 2

MOVE_RIGHT:
    LD   IX, SPRITE_1_ADDR  ; IX points to the sprite control block
    
    ; Increment the 16-bit X-coordinate (bytes at IX+0 and IX+1)
    INC  (IX + SPRITE_X_ADDR) ; Increment the low byte of X
    JR   NZ, NO_CARRY_X     ; No carry? Skip high byte
    INC  (IX + SPRITE_X_ADDR + 1) ; Increment the high byte of X
NO_CARRY_X:
    RET

Movement Speed: For smoother motion, you would typically use a separate velocity value (e.g., DX, DY) and add that velocity to the X and Y coordinates using a full 16-bit addition routine (`ADD HL, DE′).

Frame-Based Graphics Animation

For effects like walking or firing, you cycle the sprite through a short sequence of pre-drawn graphics (frames).

Method:

  1. Define a sequence of frame addresses (a lookup table).
  2. In the game loop, increment the sprite’s Frame Number field (e.g., offset +6).
  3. Use the Frame Number as an index into the lookup table to get the address of the next graphic.
  4. Update the Sprite Graphic Address field (offset +4) with the new address.

Example: Cycling the Frame Number

SPRITE_FRAME_NUM EQU +6     ; Frame number at offset 6

NEXT_FRAME:
    LD   IX, SPRITE_1_ADDR
    
    ; Increment the 8-bit Frame Number
    INC  (IX + SPRITE_FRAME_NUM)
    
    ; Check if the frame number has passed the maximum (e.g., 4 frames)
    LD   A, (IX + SPRITE_FRAME_NUM)
    CP   4                 ; Compare A with max frame count
    JP   C, DONE_CYCLE     ; If Carry is NOT set (A < 4), we're done
    
    ; Reset frame counter to 0 if max is reached
    LD   (IX + SPRITE_FRAME_NUM), 0
DONE_CYCLE:
    RET