animation: Refactored animation code
authorLukas Krickl <lukas@krickl.dev>
Mon, 8 Sep 2025 21:00:38 +0000 (23:00 +0200)
committerLukas Krickl <lukas@krickl.dev>
Mon, 8 Sep 2025 21:00:38 +0000 (23:00 +0200)
The new system allows defintion of tables.
Tables can be loaded and contain up to 3 objects.

src/animation.s
src/defs.s
src/macros.inc
src/main.s
src/player.s
src/unit.s
src/unit_demo.s

index c8fad8a2e71b6250f056eeba147eebdde4ce060e..604be83875b584507c268e60b1678b5dd6429e3c 100644 (file)
@@ -1,9 +1,25 @@
-player_anim_header:
-       anim_header 2, ANIM_HEAD_F_LOOP, 1, player_anim_table, NULL
-
 player_anim_table:
-       anim_ent 0x8C, 0x00, 0, 0
-       anim_ent 0x8C, 0x00, 0, 0
+       anim_ent 0, 8, 0x8C, OAM_FXFLIP 
+       anim_ent 0, 0, 0x8E, OAM_FXFLIP
+       anim_ent 0, 0, 0x00, 0
+       dw player_anim_table
+
+       
+       ; translates tile to screen
+       ; inputs:
+       ;               $1: Y/X offset
+       ;               $2: register containing scroll
+       ;                a: tile position
+#macro tile_to_scrn
+  mul16 a
+  add a, $1 
+  sub a, $2 
+#endmacro
+       
+       ; performs no drawing
+unit_nop_draw:
+       ldnull bc
+       ret
 
 
   ; calls unit's draw function
@@ -57,42 +73,135 @@ get_left_tile_offset2:
   ld a, 8
   ret
        
-       ; draws the unit's tile
-       ; based on the set oam tile 
-       ; and the currently set offset 
-       ; each actor has 2 tiles drawn here
-       ; tile 1 is the selected tile
-       ; tile 2 is the tile next (+1) to the selected tile
+       ; draws a unit's animation table
+       ; draws all 3 tables based on animation timer
+       ; and animation max value (first item in table)
   ; inputs
   ;   de: actor
 unit_draw:
-  push de
-  ld hl, act_oam_tile
-  add hl, de ; hl = tile 
-  ld a, [hl+]
+       ; load anim entries
+       ld hl, act_anim_table
+       add hl, de ; hl = entry 1
+       ld a, [hl+]
+       push af
+       ld a, [hl]
+       ld h, a
+       pop af
+       ld l, a
+       push hl
+       pop bc ; bc = anim talbe entry
 
-  ld b, a ; base tile
-  ld a, [hl+]
-  ld c, a ; flags
-       ld a, [hl] ; a = tile offset
-       add a, b ; base tile + offset
-       ld b, a ; b = real tile
-
-       ld a, c ; c = oam flags for offset call
-  call get_left_tile_offset1
-  push bc
-  call unit_generic_draw
-  
-  ; draw same tile again 
-  pop bc
-  pop de
-  push de
-  inc b  
-  inc b ; b+=2
-  ld a, c ; a = flags
-  call get_left_tile_offset2
-  call unit_generic_draw 
-  pop de
-
-  ldnull bc
+       call unit_draw_obj
+       call unit_draw_obj
+       call unit_draw_obj
+
+       ; load next anim table
+       ld hl, act_anim_table
+       ld a, [bc]
+       ld [hl+], a
+       inc bc
+       ld a, [bc]
+       ld [hl], a
   ret
+
+       ; draws a single object 
+       ; in the current animation table
+       ; inputs:
+       ;               de: actor
+       ;               bc: anim table entry
+       ;       returns:
+       ;               bc: next entry
+unit_draw_obj:
+#define TMP_SCROLL_Y scratch
+#define TMP_SCROLL_X scratch+1
+#define TMP_A scratch+2
+       ; skip if tile is 0x00
+       inc bc
+       inc bc
+       ld a, [bc]
+       dec bc
+       dec bc
+       cp a, 0
+       jp z, @skip_ent
+
+       push de
+
+       ; hl = pos y
+       ld hl, act_pos_y 
+       add hl, de
+       push hl
+       pop de ; de = pos y
+
+       push bc
+       push de
+
+       call load_scroll
+       ld a, b
+       ld [TMP_SCROLL_Y], a
+       ld a, c 
+       ld [TMP_SCROLL_X], a
+
+       call load_unit_obj
+
+       pop de
+       
+       ; set y position
+       ld a, [TMP_SCROLL_Y]
+       ld b, a ; b = y scroll
+       ld a, [de]
+       tile_to_scrn OBJ_OFF_Y, b ; scroll offset
+       ld [TMP_A], a
+
+       ; apply anim entry y offset
+       pop bc
+       ld a, [bc]
+       push bc
+       ld b, a 
+       ld a, [TMP_A]
+       add a, b ; a += y offset
+       ; write result to obj
+       ld [hl+], a
+
+       
+       ; set x position
+       inc de
+       ld a, [TMP_SCROLL_X]
+       ld c, a ; c = scroll x
+       ld a, [de]
+       tile_to_scrn OBJ_OFF_X, c
+       ld [TMP_A], a
+       
+       ; apply anim entry x offset
+       pop bc
+       inc bc ; next entry
+       ld a, [bc]
+       push bc
+       ld b, a
+       ld a, [TMP_A]
+       add a, b ; a += x offset
+       ; write result to obj
+       ld [hl+], a
+
+       pop bc
+       inc bc ; bc = tile index
+       ; write tile from table
+       ld a, [bc]
+       ld [hl+], a
+
+       ; write flags
+       inc bc
+       ld a, [bc]
+       ld [hl+], a
+       inc bc
+       
+       pop de
+       ret
+@skip_ent:
+       inc bc
+       inc bc
+       inc bc
+       inc bc
+       ret
+#undefine TMP_SCROLL_Y
+#undefine TMP_SCROLL_X
+#undefine TMP_A
index 39bf082200616915244edc736c06c3d91c880c6d..70e2e86079fbbf240086303de5b2f84f64792112 100644 (file)
        ; can be used for animations or other relevant timers
        ; state switching may change this value.
 .de act_rt_timer, 1
-
-  ; sub-tile drawing vars
-  ; during this animation the actor is already technically in its new 
-  ; location. the real location offset can be calculated with 
-  ; the st_time in the actor if sub tile enable is set
-  ; ab0de000: direction bits (a == 1 -> up; b == 1 -> down; d == 1 -> left; e == 1 -> right)
-  ; 00c00000: c: sub tile enabled
-.de act_rt_sub_tile, 1
-
+       
   ; stats1
 .de act_level, 1
 .de act_hp, stat_size
   ; returns:
   ;   bc: null
 .de act_draw, 2
-  
-  ; act_oam_tile + flags
-  ; if using generic draw:
-  ;   2 tiles are used
-  ;   tile 1 is the tile specified here
-  ;   tile 2 is the tile following tile 1
-  ;   flags are used for both tiles
-  ; optional:
-  ;   tile + flags may be a pointer to a
-  ;   tile table. This can be implemented as needed
-.de act_oam_tile, 1
-.de act_oam_flags, 1
-       
-       ; offset from the currently selected tile
-       ; animations work by applying this offset
-       ; to the selected base tile
-       ; this allows runtime configuration
-       ; of the frames
-       ; e.g. the offset could be switched to 0/2 based 
-       ; on the current frame count
-       ; to make an idel animation
-       ; note: the offset should always be an even number
-       ; due to the use of 8x16 objects
-.de act_rt_oam_tile_offset, 1
-  
+.de act_anim_table, 2   
 .de act_size, 0
   
        ; actor save game data
 .se 0
 .de action_st_action_ptr, 2
 .de action_size, 0 
-       
-; animation header struct
-.se 0
-       ; how many objects can an animation draw
-       ; valid values are 1, 2, 3, 4
-.de anim_header_objs, 1
-.de anim_header_flags, 1
-.de anim_header_frames, 1
-.de anim_header_table, 1
-.de anim_header_next, 2 ; next animation if not looping
-
-; animation header flags
-.se 1
-       ; loop the animation
-       ; if set to 0 return to next animation
-.de ANIM_HEAD_F_LOOP, 1
-
 
 ; animation entry struct
+; an animation table is *always* 
+; 3 entries followed by a next ptr
+; if the tile is 0x00 the entry is not rendered
 .se 0
+.de anim_ent_y_offset, 1
+.de anim_ent_x_offset, 1
 .de anim_ent_oam_tile, 1
 .de anim_ent_oam_flags, 1
-.de anim_ent_x_offset, 1
-.de anim_ent_y_offset, 1
+.de anim_ent_size, 0
 
 ; special text commands
 
index 27a21f25c707cb5bb8ddd0583b718e225d1f1e0c..f446c0e29131c7553b9a0246a7c7f0ba6f2fc76b 100644 (file)
  ; defines actor meta data call for actor
  ; inputs:
  ;    $1: draw call
- ;    $2: default tiles
- ;    $3: default oam flags
+ ;             $2: animation header ptr
 #macro act_def_meta
   dw $1
-  .db $2
-  .db $3
-       ; tile offset
-       .db 0 
+       dw $2
 #endmacro
 
   ; define an actor without state
        .db 0, 0, 0
   ; act_rt_collided_with
   dw 0 
-  .db 0  ; act_rt_sub_tile 
        ; act_rt_action_dat1/2
        .db 0, 0
        
        ld b, a
 #endmacro
 
-       ; animation header
-       ; inputs:
-       ;               $1: obj count (1, 2, 3, 4) 
-       ;               $2: flags
-       ;               $3: number of frames
-       ;   $4: animation table
-       ;               $5: next animation
-#macro anim_header
-       .db $1
-       .db $2
-       .db $3
-       dw $4
-       dw $5
-#endmacro
-
        ; animation entry
        ; inputs:
-       ;               $1: tile
-       ;               $2: oam flags
-       ;               $3: x offset
-       ;               $4: y offset
+       ;               $1: y offset
+       ;               $2: x offset
+       ;               $3: tile
+       ;               $4: oam flags
 #macro anim_ent
        .db $1
        .db $2
index 9478d3093fe971a8fed78a49f456e31b5a5b9992..6585a40c0d0c79db7651a9bf16c8f0a2ce7316df 100644 (file)
@@ -63,6 +63,7 @@ main:
 #include "map.s"
 #include "math.s"
 
+#include "animation.s"
 #include "roompatterns.s"
 #include "mapgen.s"
 #include "state.s"
@@ -83,7 +84,6 @@ main:
 #include "shoot.s"
 #include "action_menu.s"
 #include "select_menu.s"
-#include "animation.s"
 
 ; fill bank
 .fill 0xFF, 0x4000 - $
index 876c9e99b73ab069a838e09c37bbe3d3a288fc31..1c37328dc750beb450d9dd2ba13605bf33eea92a 100644 (file)
@@ -29,14 +29,6 @@ unit_player_update:
        cp a, 0
        ret nz
 
-  push de
-  ld hl, act_oam_flags
-  add hl, de
-  ld a, [hl]
-  or a, OAM_FXFLIP 
-  ld [hl], a
-  pop de
-
        ; check if the player is currently
        ; on a convered tile or not
        push de
@@ -331,7 +323,7 @@ unit_player:
   act_stat_def1 1, 3, 1, 1
   act_stat_def2 1, 1, 90, 1 
   act_st_def st_unit_player_update, st_unit_idle
-  act_def_meta player_draw, 0x8C, OAM_FPRIO 
+  act_def_meta player_draw, player_anim_table
 
 st_unit_player_update:
   st_def 0x00, unit_player_update, st_unit_player_update 
index a64eff721103ff6616a1c8a2501adde4a86ea4c8..79518914249e55b06d9cb61b7a36143d746745b9 100644 (file)
@@ -45,148 +45,6 @@ units_update:
     jr nz, @loop REL
 
   ret
-
-  ; adjust an object's position 
-  ; based on sub-tile state
-  ; inputs:
-  ;   de: actor
-  ;   hl: object in shadow oam
-unit_generic_draw_adjust_subtile:
-  ; check if actor is in sub-tile mode
-  push hl
-  push de
-  
-  ld hl, act_rt_sub_tile
-  add hl, de
-  ld a, [hl] ; a = rt_sub_tile value
-  pop de ; de = actor st_time
-  pop hl ; hl = obj
-  ld b, a ; b = rt_sub_tile value
-  cp a, 0
-  ; if this value is 0 we are not moving
-  jp z, @done 
-
-  ld a, [de] ; load timer
-  div8 a ; a = timer/8 giving us a pixel offset
-  ld c, a ; c = timer/8
-
-  ; test bit 7 for up
-  bit 7, b
-  jr z, @not_up REL
-    ld a, [hl] ; a = obj y
-    add a, c ; a += offset
-    ld [hl], a
-@not_up:
-  
-  ; test bit 6 for down
-  bit 6, b
-  jr z, @not_down REL
-    ld a, [hl]
-    sub a, c ; a -= offset
-    ld [hl], a
-@not_down:
-  
-  inc hl ; hl = x position
-
-  ; test bit 4 for left
-  bit 4, b
-  jr z, @not_left REL
-    ld a, [hl]
-    add a, c ; a += offset
-    ld [hl], a
-@not_left:
-
-  ; test bit 3 for right
-  bit 3, b
-  jr z, @not_right REL
-    ld a, [hl]
-    sub a, c ; a += offset
-    ld [hl], a
-@not_right:
-
-@done:
-
-  ret
-       
-       ; translates tile to screen
-       ; inputs:
-       ;               $1: Y/X offset
-       ;               $2: register containing scroll
-       ;                a: tile position
-#macro tile_to_scrn
-  mul16 a
-  add a, $1 
-  sub a, $2 
-#endmacro
-       
-       ; performs no drawing
-unit_nop_draw:
-       ldnull bc
-       ret
-
-  ; draws any unit
-  ; inputs:
-  ;  de: actor
-  ;   a: x-offset for tiles
-  ;   b: tile1
-  ;   c: flags
-unit_generic_draw:
-#define TMP_OAMFLAG_PRIO scratch
-#define TMP_X_OFFSET scratch+1
-  ld [TMP_X_OFFSET], a ; save for later
-
-  push de ; save actor
-
-  xor a, a
-  ld [TMP_OAMFLAG_PRIO], a
-
-  push bc
-
-  ld hl, act_pos_y
-  add hl, de ; hl = act_pos_y
-  push hl
-
-  call load_scroll
-  call load_unit_obj
-  
-  pop de ; de = act_pos_y
-  
-  ; set y pos
-  ld a, [de]
-       tile_to_scrn OBJ_OFF_Y, b
-  ld [hl+], a
-
-  ; set x pos
-  inc de
-  ld a, [de]
-       tile_to_scrn OBJ_OFF_X, c 
-  ld c, a 
-  ld a, [TMP_X_OFFSET]
-  add a, c
-  ld [hl+], a
-  
-  pop bc ; bc = inputs again
-
-  ; set tile 
-  ld a, b
-  ld [hl+], a
-
-
-  ; set flags
-  ld a, [TMP_OAMFLAG_PRIO]
-  or a, c
-  ld [hl], a
-  
-  dec hl
-  dec hl
-  dec hl ; object - 3 go back to start
-  pop de
-  call unit_generic_draw_adjust_subtile
-
-  ldnull bc
-  ret
-#undefine TMP_OAMFLAG_PRIO
-#undefine TMP_X_OFFSET
        
        ; sets player turn taken flag
 unit_set_player_turn_taken:
@@ -425,35 +283,6 @@ unit_collides_with_any_other:
   ret
 #undefine scratch_loop_i
  
-  ; sets st_unit_delay_to_active speed to unit's move speed
-  ; (STAT_MAX-stat_calc_speed)
-  ; inputs:
-  ;   de: actor
-  ;    a: mask for rt_sub_tile
-  ;       rt_subtile |= a
-unit_set_delay_to_active_speed:
-  push de
-  ld hl, act_rt_sub_tile 
-  add hl, de ; hl = ptr to sub_tile
-
-  ld b, a
-  ld a, [hl]
-  or a, b ; apply the mask
-  ld [hl], a ; store new value
-
-  ; get movement speed 
-  pop de
-  call stat_calc_speed
-  ld de, st_unit_delay_to_active ; de == st_time
-  ; this overwrites the wait time 
-  ; by calculating the movement speed
-  ; and subtracting it from STAT_MAX
-  ld b, a ; b = current speed
-  ld a, STAT_MAX
-  ; a - b
-  sub a, b
-  ld [de], a ; delay timer is now speed
-  ret
 
   ; moves a unit up
   ; moves are aborted 
@@ -466,12 +295,6 @@ unit_set_delay_to_active_speed:
   ;   actor initiative based on tile flags
   ;   actor position
 unit_try_move_up:
-  ; enable subtile up
-  ld a, 0b10100000
-  push de
-  call unit_set_delay_to_active_speed
-  pop de
-
   ; y - 1
   unit_test_collision dec b, CF_COLLISION
 
@@ -492,12 +315,6 @@ unit_try_move_up:
   ret
 
 unit_try_move_down:
-  ; enable subtile down
-  push de
-  ld a, 0b01100000
-  call unit_set_delay_to_active_speed
-  pop de
-
   ; y + 1
   unit_test_collision inc b, CF_COLLISION
 
@@ -514,12 +331,6 @@ unit_try_move_down:
   ret
 
 unit_try_move_left:
-  ; enable subtile left
-  push de
-  ld a, 0b00110000
-  call unit_set_delay_to_active_speed
-  pop de
-
   ; x - 1
   unit_test_collision dec c, CF_COLLISION
 
@@ -536,12 +347,6 @@ unit_try_move_left:
   ret
 
 unit_try_move_right:
-  ; enable subtile right
-  push de
-  ld a, 0b00101000
-  call unit_set_delay_to_active_speed
-  pop de
-
   ; x + 1
   unit_test_collision inc c, CF_COLLISION
 
@@ -615,13 +420,6 @@ unit_scroll_center:
        ;       returns:
        ;               bc: new state
 unit_switch_to_active:
-  push de
-  ld hl, act_rt_sub_tile
-  add hl, de
-  xor a, a
-  ld [hl], a ; clear sub_tile values
-  pop de
-
   ld hl, act_st_active
   add hl, de ; hl = st_active ptr
   ld a, [hl+]
index b71443d68d48b19874300b2e988d6d1ffd6d6174..1af0db1d4461d653ee417ca97e1f1105077926cd 100644 (file)
@@ -1,3 +1,20 @@
+unit_demo_guard_anim_table:
+       anim_ent 0, 0, 0x88, 0
+       anim_ent 0, 8, 0x8A, 0
+       anim_ent 0, 0, 0x00, 0
+       dw unit_demo_guard_anim_table
+
+unit_demo_dog_anim_table:
+       anim_ent 0, 0, 0x90, 0
+       anim_ent 0, 8, 0x92, 0
+       anim_ent 0, 0, 0x00, 0
+       dw unit_demo_dog_anim_table
+
+unit_demo_hazmat_anim_table:
+       anim_ent 0, 0, 0x94, 0
+       anim_ent 0, 8, 0x96, 0
+       anim_ent 0, 0, 0x00, 0
+       dw unit_demo_hazmat_anim_table
 
 unit_demo_1_init:
   ldnull bc
@@ -21,15 +38,7 @@ unit_demo_guard:
   act_stat_def1 1, 3, 1, 1 
   act_stat_def2 1, 1, 32, 1
   act_st_def st_unit_demo_1_cpu_update, st_unit_idle
-  act_def_meta unit_draw, 0x88, OAM_FPRIO
-
-unit_demo_agent:
-  st_def 0x00, unit_demo_1_init, st_unit_demo_1_cpu_update
-  act_def ACT_T_DEMO_1, 0, 9, 9, 0 
-  act_stat_def1 1, 1, 1, 1 
-  act_stat_def2 1, 1, 32, 1
-  act_st_def st_unit_demo_1_cpu_update, st_unit_idle
-  act_def_meta unit_draw, 0x8C, OAM_FPRIO
+  act_def_meta unit_draw, unit_demo_guard_anim_table
 
 unit_demo_dog:
   st_def 0x00, unit_demo_1_init, st_unit_demo_1_cpu_update
@@ -37,7 +46,7 @@ unit_demo_dog:
   act_stat_def1 1, 2, 1, 1 
   act_stat_def2 1, 1, 32, 1
   act_st_def st_unit_demo_1_cpu_update, st_unit_idle
-  act_def_meta unit_draw, 0x90, OAM_FPRIO
+  act_def_meta unit_draw, unit_demo_dog_anim_table 
 
 
 unit_demo_hazmat:
@@ -46,7 +55,7 @@ unit_demo_hazmat:
   act_stat_def1 1, 1, 1, 1 
   act_stat_def2 1, 1, 32, 1
   act_st_def st_unit_demo_1_cpu_update, st_unit_idle
-  act_def_meta unit_draw, 0x94, OAM_FPRIO
+  act_def_meta unit_draw, unit_demo_hazmat_anim_table 
 
 
 st_unit_demo_1_cpu_update: