Jump to content





step 14 - add animation

Posted by SpiceWare, in Collect 14 July 2014 · 1,482 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.
Attached Image
 
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
 
 
Attached Image


It works, but the players move so fast they look spastic.
Attached File  collect_20140714_toofast.bin (2KB)
downloads: 136

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
 
 
Attached File  collect_20140714_speedtest.bin (2KB)
downloads: 130

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.
Attached Image

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
 
 
Attached Image


ROM
Attached File  collect_20140714.bin (2KB)
downloads: 194
 
Source:
Attached File  Collect_20140714.zip (66.06KB)
downloads: 269




Search My Blog

Recent Entries

Recent Comments

Latest Visitors

0 user(s) viewing

0 members, 0 guests, 0 anonymous users