actor: Added actor -> actor collision
authorLukas Krickl <lukas@krickl.dev>
Wed, 24 Sep 2025 07:50:15 +0000 (09:50 +0200)
committerLukas Krickl <lukas@krickl.dev>
Wed, 24 Sep 2025 07:50:15 +0000 (09:50 +0200)
src/actor.s
src/debug.s
src/enemy.s
src/map.s
src/player.s
src/video.s

index cbb23773b48f3fc1b144616ff315ce085b6c6004..acc72ce4354bdbc9104d2b0db00a5d8fbf749d24 100644 (file)
@@ -69,6 +69,11 @@ actor_update_draw_table:
        dw act_nop 
        dw player_update_and_draw
        dw act_guard_update_and_draw
+
+actor_collision_res_table:
+       dw act_nop
+       dw player_col_res
+       dw act_guard_col_res
        
        ; calls update for all actors
        ; and draws them
@@ -183,33 +188,131 @@ actor_write_default_collider:
        ;               a == 1: collision
        ;               hl: if collided with an actor points to the actor hit, otherwise NULL
 actor_test_movement:
+       push de
        ld [tmp_rect_mask], a
        ; check all static rectangles
        ld hl, rectangles
        ld b, RECT_MAX
        ld de, r_size
-@rect_test_loop:
-               ; pre-filter rectangle mask
-               ld a, [tmp_rect_mask]
-               call rect_test_mask
-               jp z,  @skip_rect 
-
-               ; test all corners of tmp_rect 
 
-               actor_test_movement_corner rect_bl, @rect_collision
-               actor_test_movement_corner rect_br, @rect_collision
-               actor_test_movement_corner rect_tl, @rect_collision
-               actor_test_movement_corner rect_tr, @rect_collision
+@rect_test_loop:
+       call actor_test_rect
+       cp a, 0
+       jp nz, @rect_collision
 @skip_rect:
                add hl, de ; next rect (de = r_size)
                dec b
                jp nz, @rect_test_loop
 
+       pop de
+       ld b, ACTS_MAX
+
+       ; start at player actor
+       ld hl, player
 
+@actor_test_loop:
+               ld a, [hl]
+               cp a, 0 ; check if type is 0
+               jp z, @skip_actor
+
+               ; check if current actor is in de
+               ld a, d
+               cp a, h
+               jr nz, @test_actor REL
+               ld a, e
+               cp a, l
+               jr z, @skip_actor REL
+
+@test_actor:
+               push de
+               push hl
+               ld de, act_rect
+               add hl, de ; hl = rectangle for actor
+               
+               call actor_test_rect
+               cp a, 0
+               pop hl
+               pop de
+               jp nz, @actor_collision
+
+@skip_actor:
+               push bc
+               ld bc, act_size
+               add hl, bc ; next actor
+               pop bc
+               dec b
+               jp nz, @actor_test_loop
+
+@no_collision:
+       ld hl, NULL
        xor a, a ; no collision
        ret
 @rect_collision:
-       pop_all
+       pop de
        ld hl, NULL
        ld a, 1
        ret
+@actor_collision:
+       ; hl = actor already 
+       ld a, 1
+       ret
+
+       ; tests a single rectangle against an actor 
+       ; inputs:
+       ;               tmp_rect: new collision rectangle
+       ;         tmp_rect_mask: mask to test agains
+       ;   hl: rectangle to test
+       ;       returns:
+       ;               a: 1 collision
+       ;                       a: 0 no collision
+actor_test_rect:
+       ; pre-filter rectangle mask
+       ld a, [tmp_rect_mask]
+       call rect_test_mask
+       ret z
+
+       ; test all corners of tmp_rect 
+
+       actor_test_movement_corner rect_bl, @rect_collision
+       actor_test_movement_corner rect_br, @rect_collision
+       actor_test_movement_corner rect_tl, @rect_collision
+       actor_test_movement_corner rect_tr, @rect_collision
+       
+       xor a, a
+       ret
+@rect_collision:
+       ; actor_test_movement does not pop all when the check 
+       ; passes
+       pop_all
+       ld a, 1
+       ret
+       
+       ; calls collision resolution 
+       ; inputs:
+       ;               de: event origin actor
+       ;               hl: actor collided with
+actor_col_res:
+       ld a, h
+       or a, l
+       cp a, 0
+       ret z ; do nothing if 0
+
+       ld a, [hl]
+       add a, a ; type * 2 as offset into table
+       
+       push hl
+
+       ld hl, actor_collision_res_table
+       ld b, 0
+       ld c, a
+       add hl, bc ; hl = routine ptr
+
+       ld a, [hl+]
+       ld b, a
+       ld a, [hl]
+       ld h, a
+       ld l, b
+
+       pop bc ; the rotuine wants collider in bc
+       call_hl
+       ret
index 644451f41b9d92b82ea2864a4d8c126266f32765..c0ba34854beefef8aa838e83c0b1db889fc81506 100644 (file)
@@ -106,7 +106,7 @@ dbg_rect_draw:
        call dbg_rect_draw_ptr
        
        ; always draw player rectangle
-       ld de, player+act_rect
+       ld de, actors+act_rect
        call dbg_rect_draw_ptr
 
        ret
@@ -140,7 +140,6 @@ dbg_rect_draw_ptr:
        ld a, [de]
        cp a, 0
        jp z, @rect_not_alloced
-       
        push de
        ld a, 4
        call oamalloc
index 4c22a6712269cf0466d14df58cb9fb8aa45b9e95..77903ed1f8fd73da6fa85aff96218bb68cb61cb4 100644 (file)
@@ -8,6 +8,19 @@ act_enemy_guard:
        ; inputs:
        ;               de: actor ptr
 act_guard_update:
+       ; load position
+       ld hl, act_pos_y
+       add hl, de
+       ld a, [hl+]
+       ld b, a
+       ld a, [hl+]
+       ld c, a
+       
+       ; write collision shape
+       ld hl, act_rect
+       add hl, de
+       ld a, RF_ENEMY
+       call actor_write_default_collider
        ret
        
        ; draws the guard enemy
@@ -34,5 +47,21 @@ act_guard_draw:
        
        ; combination of update and draw call
 act_guard_update_and_draw:
+       push de
        call act_guard_draw
+       pop de
        jp act_guard_update
+       
+       ; collision resolution between guard and another actor 
+       ; inputs:
+       ;               de: even origin actor
+       ;               bc: guard
+act_guard_col_res:
+       ld hl, act_hp
+       add hl, de
+
+       ; test take damage
+       ld a, [hl]
+       dec a
+       ld [hl], a
+       ret
index c96684626706a59869c19a6ed25f94798a20f9db..641595052a6bc3e0590e25c42295d4c4b2521ef4 100644 (file)
--- a/src/map.s
+++ b/src/map.s
@@ -253,6 +253,9 @@ l1_objs:
 
        modef MOT_SET_PAT, 0, 10, pat_center_grass 
        modef MOT_SET_PAT, 0, 18, pat_center_empty_wall
+
+       modef MOT_RECT, 0, 18, 0x080F
+
        modef MOT_SET_PAT, 0, 0x1E, pat_empty 
        modef MOT_DISABLE_SCROLL, 0, 0x20, 0
        modef MOT_NOP, 0, 0xFF, 0
index 2a840240cfe31aaa43628d2501c4e1053b065b06..b7966c371283e7c68d84e23828880cc06a3f7c8f 100644 (file)
@@ -185,9 +185,12 @@ player_try_move:
        ld de, player
        call actor_test_movement
        pop bc
+       
+       ; hl should be NULL or an actor ptr
+       push af
+       call actor_col_res
+       pop af
 
-       ; TODO: handle collision with another actor 
-       ; if hl != NULL
        cp a, 0
        ret nz
 
@@ -222,3 +225,11 @@ player_draw:
 player_update_and_draw:
        call player_draw
        jp player_update
+       
+       ; collision resolution between player
+       ; and other actor
+       ; inputs:
+       ;               de: origin actor
+       ;               bc: player
+player_col_res:
+       ret
index 81e75e657988d2eebe838883fd09715f91df9a18..ec390d033472448f5e7b3db1d2c71be1d2fa6c17 100644 (file)
@@ -145,7 +145,7 @@ scroll_up_adjust:
 
                pop de
                push de
-               cp a, 0xB
+               cp a, 0xA
                call nc, rect_despawn
 
 @no_rect_despawn: