As discussed in the previous blog post, i am interested in a reasonably reusable animation engine which allows me to call a SetAnimation function to initialise a new animation then use generic UpdateAnimation and DrawAnimation functions to process it regardless of what i need animating. I need to set the total frames, the speed of the animation (by screen update generally), the frame to display and any positional (x and y) change.
When starting this game I followed a few example games across the forum for inspiration which generally make use of the gosub ... to set the specific frame to the sprite required with a number of lookup data tables. The one benefit of this game is the animation will process and finish before the next check is required which does simplify everything just a bit - I don't need (thankfully) to make changes during the animation (might make a nice engine for something like Lode Runner maybe). As I want to eventually make this a 2 player game I want to reuse the animation frames when required but I didn't want to just duplicate it all.
As noted in the previous blog I found this forum post discussing how to make this a little more dynamic (but due to pointers it still carries a bit of duplication per sprite). So armed with this I setup the following:
dim player0AnimationId = k
dim player0AnimationFrame = m
dim player0AnimationSpeed = n
dim player0IsAnimating = o
const ANIMATION_STATIONARY = 0
const ANIMATION_FALL = 1
const ANIMATION_HANG = 2
const ANIMATION_MOVE = 3
const ANIMATION_CHANGE_DIRECTION = 4
const ANIMATION_JUMP_UP = 5
const ANIMATION_CLIMB_UP = 6
const ANIMATION_CLIMB_DOWN = 7
const ANIMATION_JUMP_SMALL = 8
const ANIMATION_JUMP_LARGE = 9
function SetPlayer0Animation
rem temp1=AnimationId
player0AnimationId = temp1
player0IsAnimating = 1
player0AnimationFrame = 0
player0AnimationSpeed = 0
return
function UpdatePlayer0Animation
rem validate
if !player0IsAnimating then return
rem prepare (got offset)
ftemp1 = PL_ANIMATION_OFFSET[player0AnimationId]
rem update position? (only on 0)
if player0AnimationSpeed > 0 then goto _SKIP_UPDATEPLAYER0ANIMATION_MOVE
rem read x and y to offset
rem data is TotalFrames,TotalSpeed(+2),Frame(+0),X(+1),Y(+2)
rem update x
fresult = ftemp1 + 2 + (player0AnimationFrame * 3) + 1
ftemp2 = PL_ANIMATION[fresult]
if _Bit2_Player0_Dir_Left{2} then player0x = player0x - ftemp2 else player0x = player0x + ftemp2
rem update y
fresult = fresult + 1
ftemp2 = PL_ANIMATION[fresult]
player0y = player0y + ftemp2
_SKIP_UPDATEPLAYER0ANIMATION_MOVE
rem increment speed
player0AnimationSpeed = player0AnimationSpeed + 1
;fresult = ftemp1 + 1 : if player0AnimationSpeed < 50 then goto _SKIP_UPDATEPLAYER0ANIMATION_FRAME
fresult = ftemp1 + 1 : if player0AnimationSpeed < PL_ANIMATION[fresult] then goto _SKIP_UPDATEPLAYER0ANIMATION_FRAME
player0AnimationSpeed = 0
rem increment frames
player0AnimationFrame = player0AnimationFrame + 1
fresult = ftemp1 : if player0AnimationFrame < PL_ANIMATION[fresult] then goto _SKIP_UPDATEPLAYER0ANIMATION_FRAME
rem complete
player0IsAnimating = 0 : player0AnimationFrame = 0 : player0AnimationSpeed = 0
...
_SKIP_UPDATEPLAYER0ANIMATION_FRAME
return
function DrawPlayer0Animation
rem prepare
ftemp1 = PL_ANIMATION_OFFSET[player0AnimationId]
fresult = ftemp1 + 2 + (player0AnimationFrame*3) + 0 : ftemp2 = PL_ANIMATION[fresult]
rem get frame pointer
asm
LDX #<PL_ANIMATION_FRAMES
STX ftemp5
end
rem get frame
player0pointerlo = ftemp5+(ftemp2*8 )
asm
LDA #((>PL_ANIMATION_FRAMES) & $0f) | (((>PL_ANIMATION_FRAMES) / 2) & $70)
STA player0pointerhi
end
return
I then configured the data as below. The offset gives me the location in the PL_ANIMATION table for the active animation. From there I can look up the Total Frames and Speed, then for the current animation frame I can grab the frame to display and the x and y offset for the frame.
rem ANIMATION
rem 0-0 Stationary
rem 1-5 Fall
rem 2-31 Hang
rem 3-36 Move
rem 4-62 Change Direction
rem 5-79 Jump (up)
rem 6-87 Climb (up)
rem 7-113 Climb (down)
rem 8-139 Jump (small)
rem 9-153 Jump (large)
data PL_ANIMATION_OFFSET
0,
5,
31,
36,
62,
79,
87,
113,
139,
153
end
data PL_ANIMATION
1,1, 0,0,0,
8,2, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1, 1,0,1,
1,2, 2,0,0,
8,1, 0,1,0, 3,1,0, 4,1,-1, 5,1,0, 6,1,0, 7,1,0, 8,1,1, 9,1,0,
5,2, 10,0,0, 11,0,0, 12,0,0, 13,0,0, 14,0,0,
2,3, 15,0,0, 16,0,0,
8,3, 17,1,0, 18,0,-1, 19,1,-1, 20,2,0, 21,1,-2, 22,1,-2, 22,1,-1, 22,1,-1,
8,3, 22,-1,1, 22,-1,1, 22,-1,2, 21,-1,2, 20,-2,0, 19,-1,1, 18,0,1, 17,-1,0,
4,2, 23,0,0, 24,0,0, 25,0,0, 26,0,0,
8,2, 23,1,-1, 23,1,0, 24,1,0, 24,1,0, 25,1,0, 25,1,1, 26,1,0, 2,1,0
end
data PL_ANIMATION_FRAMES
%00011000
%00000100
%00011000
%00111100
%01011010
%00011000
%00101000
%00100100
%01000010
%01011010
%00100100
%00011000
%00011000
%00111000
%00101110
%00100000
%10000000
%10110000
%01000000
%01110000
%01101000
%01101000
%10100000
%10100000
...
end
So i've got some further ideas about how this could work for a 2 player game (or multiple sprites such as enemies) using the same code by storing/restoring the state of the active object via some additional vars or DPC+ ram.
If anyone has any suggestions to tiding up this further I'd be grateful - it has saved me about 700 bytes so far. I do find I'm needing to use a lot of temp variable declarations particularly around calculations. I guess I can't be too hard - being able to do this quickly in basic is pretty cool!
-
entries
7 -
comments
0 -
views
2,551
-
Recently Browsing 0 members
- No registered users viewing this page.
0 Comments
Recommended Comments
There are no comments to display.