step 14 - add animation
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.
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
It works, but the players move so fast they look spastic.
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.
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
ROM
Source:

0 Comments
Recommended Comments
There are no comments to display.