1+ ;###############################################
2+ ;
3+ ; Copyright 2018-2019 0x8BitDev ( MIT license )
4+ ;
5+ ;###############################################
6+ ;
7+ ; Animation frames switching code
8+ ; LIMITATION: max 32 frames in animation
9+ ;
10+
11+ .struct runtime_anm_data
12+ curr_tick .byte ; 0
13+ num_ticks .byte ; 1 num ticks to change a frame
14+ curr_frame .byte ; 2
15+ num_frames .byte ; 3 num frames to loop an animation
16+ loop_frame .byte ; 4
17+ frames_ptr .word ; 5
18+ .endstruct
19+
20+ .struct static_anm_data
21+ num_ticks .byte
22+ num_frames .byte
23+ loop_frame .byte
24+ frames_ptr .word
25+ .endstruct
26+
27+ .struct frame_data
28+ gfx_ptr .word
29+ data_size .byte
30+ chr_id .byte
31+ .endstruct
32+
33+ .segment "ZP"
34+
35+ anm_pos_x: .res 1
36+ anm_pos_y: .res 1
37+
38+ ppu_sprite_CHR_bank: .res 1
39+
40+ .scope inner_vars
41+ tick_frame: .res 1
42+ tmp_anm_addr: .res 2
43+ .endscope
44+
45+
46+ .segment "CODE"
47+
48+ ; *** animation data init ***
49+ ; IN:
50+ ; X - LOW byte of anm data
51+ ; Y - HIGH byte of anm data
52+ ; data_addr - address at which animation will be initialized
53+ anm_init:
54+ stx inner_vars::tmp_anm_addr
55+ sty inner_vars::tmp_anm_addr + 1
56+
57+ lda # $ 00
58+
59+ ldy #runtime_anm_data::curr_tick
60+ sta (<data_addr) , y
61+
62+ ldy #runtime_anm_data::curr_frame
63+ sta (<data_addr) , y
64+
65+ ldy #static_anm_data::num_ticks
66+ lda (<inner_vars::tmp_anm_addr) , y
67+
68+ ldy #runtime_anm_data::num_ticks
69+ sta (<data_addr) , y
70+
71+ ldy #static_anm_data::num_frames
72+ lda (<inner_vars::tmp_anm_addr) , y
73+ ldy #runtime_anm_data::num_frames
74+ sta (<data_addr) , y
75+
76+ ldy #static_anm_data::loop_frame
77+ lda (<inner_vars::tmp_anm_addr) , y
78+ ldy #runtime_anm_data::loop_frame
79+ sta (<data_addr) , y
80+
81+ ldy #static_anm_data::frames_ptr
82+ lda (<inner_vars::tmp_anm_addr) , y
83+ ldy #runtime_anm_data::frames_ptr
84+ sta (<data_addr) , y
85+
86+ ldy #static_anm_data::frames_ptr + 1
87+ lda (<inner_vars::tmp_anm_addr) , y
88+ ldy #runtime_anm_data::frames_ptr + 1
89+ sta (<data_addr) , y
90+
91+ rts
92+
93+ ; *** update animation frame and prepare to render ***
94+ ; IN:
95+ ; X - LOW byte of anm addr
96+ ; Y - HIGH byte of anm addr
97+ ; anm_pos_x - X coord
98+ ; anm_pos_y - Y coord
99+ anm_update_frame:
100+ jsr _anm_get_updated_frame_addr
101+ ; inner_vars::tmp_anm_addr - current animation frame address
102+
103+ ; preparing sprite data for transfer to PPU
104+ ldy #frame_data::gfx_ptr
105+ lda (<inner_vars::tmp_anm_addr) , y
106+ sta data_addr
107+ ldy #frame_data::gfx_ptr + 1
108+ lda (<inner_vars::tmp_anm_addr) , y
109+ sta data_addr + 1
110+ ldy #frame_data::data_size
111+ lda (<inner_vars::tmp_anm_addr) , y
112+ sta data_size
113+
114+ ldy #frame_data::chr_id
115+ lda (<inner_vars::tmp_anm_addr) , y ; CHR bank index
116+ sta ppu_sprite_CHR_bank
117+
118+ lda anm_pos_x
119+ tax
120+ lda anm_pos_y
121+ tay
122+
123+ jsr ppu_load_sprite_0x0200
124+
125+ ; set data ready flag
126+ ppu_set_dma_state ppu_dma_flag_data_ready
127+
128+ rts
129+
130+ ; *** load address of a current frame to the inner_vars::tmp_anm_addr ***
131+ ; IN:
132+ ; X - LOW byte of anm addr
133+ ; Y - HIGH byte of anm addr
134+ ; OUT:
135+ ; inner_vars::tmp_anm_addr - current animation frame address
136+ _anm_get_updated_frame_addr:
137+ jsr _anm_get_frame_ind
138+
139+ ; A - current anm frame
140+ ; A *= 4 ( .sizeof( frame_data ) )
141+ clc
142+ rol a
143+ rol a
144+
145+ ; add offset to frames start address
146+ ldy #runtime_anm_data::frames_ptr
147+ adc (<inner_vars::tmp_anm_addr) , y
148+ pha
149+ iny
150+ lda # $ 00
151+ adc (<inner_vars::tmp_anm_addr) , y
152+
153+ ; save the result to the inner_vars::tmp_anm_addr
154+ sta inner_vars::tmp_anm_addr + 1
155+ pla
156+ sta inner_vars::tmp_anm_addr
157+
158+ rts
159+
160+ ; *** get index of a current frame ***
161+ ; IN:
162+ ; X - LOW byte of anm addr
163+ ; Y - HIGH byte of anm addr
164+ ; OUT:
165+ ; A - current frame index
166+ _anm_get_frame_ind:
167+ ; save animation address
168+ stx inner_vars::tmp_anm_addr
169+ sty inner_vars::tmp_anm_addr + 1
170+
171+ ldy #runtime_anm_data::curr_tick
172+ lda (<inner_vars::tmp_anm_addr) , y ; A - current tick
173+ tax
174+ inx ; inc tick counter
175+ stx inner_vars::tick_frame ; save to the temp var
176+
177+ ldy #runtime_anm_data::num_ticks
178+ lda (<inner_vars::tmp_anm_addr) , y ; A - number of ticks to change the frame
179+
180+ cmp inner_vars::tick_frame ; tick - A
181+ beq _switch_frame ; if _tick == delay_ticks -> go to the next frame
182+
183+ ldy #runtime_anm_data::curr_tick
184+ lda inner_vars::tick_frame
185+ sta (<inner_vars::tmp_anm_addr) , y ; save new tick value
186+
187+ ldy #runtime_anm_data::curr_frame
188+ lda (<inner_vars::tmp_anm_addr) , y ; get current frame value
189+
190+ rts
191+
192+ _switch_frame:
193+ ldy #runtime_anm_data::curr_tick
194+ lda # $ 00
195+ sta (<inner_vars::tmp_anm_addr) , y ; save the new tick value
196+
197+ ;iny
198+ ldy #runtime_anm_data::curr_frame
199+ lda (<inner_vars::tmp_anm_addr) , y ; get current frame value
200+ tax
201+ inx
202+ stx inner_vars::tick_frame ; save new frame value
203+
204+ ldy #runtime_anm_data::num_frames
205+ lda (<inner_vars::tmp_anm_addr) , y ; get the MAX number of animation frames
206+ cmp inner_vars::tick_frame
207+ bne _save_next_frame
208+
209+ ldy #runtime_anm_data::loop_frame ; begin animation from loop frame
210+ lda (<inner_vars::tmp_anm_addr) , y
211+
212+ ldy #runtime_anm_data::curr_frame
213+ sta (<inner_vars::tmp_anm_addr) , y
214+
215+ rts
216+
217+ _save_next_frame:
218+ ldy #runtime_anm_data::curr_frame
219+ lda inner_vars::tick_frame
220+ sta (<inner_vars::tmp_anm_addr) , y
221+
222+ rts
0 commit comments