Jump to content
  • entries
    656
  • comments
    2,682
  • views
    894,252

step 14 - add animation


SpiceWare

2,905 views

Static images that just slide around the screen work OK, but we can do better - so for this update we'll add a couple new images so we can animate the players as they run around the arena.

blogentry-3056-0-13920700-1405376934_thumb.png

 

While you can have as many frames of animation as you'd like, the code is most efficient if the number of frames is a power of 2 (2, 4, 8, 16, etc). The code that cycles through 4 frames is this:

Example:
        inc frame
        lda frame
        and #3       ; limits values from 0-3, if A was 4 it becomes 0 after the and
        sta frame
 

 

Just change the #3 to #7 (8 frames), #15 (16 frames) and so on. If you wanted to cycle thru a non-power of 2 count, say for example 5 frames, the code would look like this:

Example:
        ldx frame
        inx
        cpx #5
        bne save
        ldx #0
save:   stx frame
 

 

For Collect we're going to use 4 frames. You might be wondering why there's only 3 humanoid images - it's because we're going to use 1 of the images twice:

  • HumanGfx
  • HumanRunning0
  • HumanRunning1
  • HumanRunning0

 

In order to animate the players we'll need to keep track of which frame they're showing, so let's add 2 new RAM variables:

    ; indexes for player animation sequences
Animation0:     ds 1    ; stored in $B3
Animation1:     ds 1    ; stored in $B4
 

Then modify PositionObjects so it will animate the images when it preps the variables for the 2LK, but only when the player is in motion:

PositionObjects:
...
    ; select image to show for Player0
        lda ObjectX         ; get current X location for player 0
        cmp SavedX          ;   compare with prior X location
        bne Animate0        ;   if different, animate player 0
        lda ObjectY         ; otherwise check current Y location
        cmp SavedY          ;   against prior Y location
        bne Animate0        ;   and animate player 0 if they're different
        lda #0              ; if X and Y didn't change then select 0, the
        beq SaveFrame0      ;   stationary image, and save it
Animate0:
        inc Animation0      ; increment to select the next frame
        lda Animation0      ; load it
        and #3              ; limit to 0-3 (if it was 4, it's now 0)
SaveFrame0:
        sta Animation0      ; save it
        tax                 ; Transfer A to X
    ; Player0Ptr = HumanGfx + HUMAN_HEIGHT - 1 - Y position
        lda ShapePtrLow,x   ; select image as specified in X
        sec
        sbc Temp
        sta Player0Ptr
        lda ShapePtrHi,x    ; select image as specified in X
        sbc #0
        sta Player0Ptr+1
...
ShapePtrLow:
        .byte <(HumanGfx + HUMAN_HEIGHT - 1)
        .byte <(HumanRunning0 + HUMAN_HEIGHT - 1)
        .byte <(HumanRunning1 + HUMAN_HEIGHT - 1)
        .byte <(HumanRunning0 + HUMAN_HEIGHT - 1)
        .byte <(BoxGfx + HUMAN_HEIGHT - 1)
        
ShapePtrHi:
        .byte >(HumanGfx + HUMAN_HEIGHT - 1)
        .byte >(HumanRunning0 + HUMAN_HEIGHT - 1)
        .byte >(HumanRunning1 + HUMAN_HEIGHT - 1)
        .byte >(HumanRunning0 + HUMAN_HEIGHT - 1)
        .byte >(BoxGfx + HUMAN_HEIGHT - 1)
 

The code for player 1 is almost the same, though it adds a test so the box image will be displayed for one player game variations:

    ; select image to show for Player1        
        bit Players         
        bpl UseBoxImage     ; if 1 player game then draw the box
        lda ObjectX+1       ; get current X location for player 1
        cmp SavedX+1        ;   compare with prior X location
        bne Animate1        ;   if different, animate player 1
        lda ObjectY+1       ; otherwise check current Y location
        cmp SavedY+1        ;   against prior Y location
        bne Animate1        ;   and animate player 1 if they're different
        lda #0              ; if X and Y didn't change then select 0, the
        beq SaveFrame1      ;   stationary image, and save it
Animate1:
        inc Animation1      ; increment to select the next frame
        lda Animation1      ; load it
        and #3              ; limit to 0-3 (if it was 4, it's now 0)
SaveFrame1:
        sta Animation1      ; save it
        tax                 ; Transfer A to X
        .byte $2C           ; $2C = BIT with absolute addressing, trick that
                            ; causes the ldx #4 to be skipped over
UseBoxImage:
        ldx #4              ; select the Box Image
    ; Player1Ptr = BoxGfx + HUMAN_HEIGHT - 1 - Y position
        lda ShapePtrLow,x   ; select image as specified in X
        sec
        sbc Temp
        sta Player1Ptr
        lda ShapePtrHi,x    ; select image as specified in X
        sbc #0
        sta Player1Ptr+1
 

 

blogentry-3056-0-64428200-1405376912_thumb.png

 

 

It works, but the players move so fast they look spastic.

 

collect_20140714_toofast.bin

 

To fix that, well revise it to use an image over multiple frames. For testing, we'll make the left player use each image for 2 frames while the right uses each image for 4:

Animate0:
        inc Animation0      ; increment to select the next frame
        lda Animation0      ; load it
        and #7              ; limit to 0-7 (if it was 8, it's now 0)
SaveFrame0:
        sta Animation0      ; save it
        lsr                 ; divide by 2 for 0-3 - this means we show the same
                            ; image twice in succession
        tax                 ; Transfer A to X
...
Animate1:
        inc Animation1      ; increment to select the next frame
        lda Animation1      ; load it
        and #15             ; limit to 0-15 (if it was 16, it's now 0)
SaveFrame1:
        sta Animation1      ; save it
        lsr                 ; divide by 4 for 0-3 - this means we show the same
        lsr                 ; image four times in succession
        tax                 ; Transfer A to X
 

 

collect_20140714_speedtest.bin

 

Both look OK, though I think the left player looks a little better so the final version will use each image twice. One minor thing happens when the game is over - if the players were in motion, the animation keeps on going even though the players are no longer in motion.

blogentry-3056-0-12236600-1405376921_thumb.png

 

To fix that, well add a Game Over check (same logic was added for Player1) that will select the stationary image:

    ; select image to show for Player0
        bit GameState
        bpl StopAnimation0  ; if game is inactive, stop animation
        lda ObjectX         ; get current X location for player 0
        cmp SavedX          ;   compare with prior X location
        bne Animate0        ;   if different, animate player 0
        lda ObjectY         ; otherwise check current Y location
        cmp SavedY          ;   against prior Y location
        bne Animate0        ;   and animate player 0 if they're different
StopAnimation0:        
        lda #0              ; if X and Y didn't change then select 0, the
        beq SaveFrame0      ;   stationary image, and save it
 

 

blogentry-3056-0-05036900-1405385739_thumb.png

 

 

ROM

 

collect_20140714.bin

 

Source:

 

Collect_20140714.zip

 

COLLECT TUTORIAL NAVIGATION
<PREVIOUS> <INDEX> <NEXT>
 

0 Comments


Recommended Comments

There are no comments to display.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...