Responsive collision, on the other hand, can be attained by calling the Add_SpriteToCollisionResponseList function:
Add_SpriteToCollisionResponseList:
lea (Collision_response_list).w,a1
cmpi.w #$7E,(a1) ; Is list full?
bhs.s locret_1041C ; If so, return
addq.w #2,(a1) ; Count this new entry
adda.w (a1),a1 ; Offset into right area of list
move.w a0,(a1) ; Store RAM address in list
locret_1041C:
rts
Much like with the Draw_Sprite function, responsive collision works in a subscription-based model: calling the function simply adds the object to a list of items to be processed in the future. The actual work of performing bound checks and producing the appropriate effects is deferred to the next frame, where it is done by the player object.(Note that the collision response list is actually processed twice in a Sonic and Tails game, once per player object. This will become relevant later. Foreshadowing: the sign of a quality blog.)
For this reason, the collision parameters cannot be passed through registers; instead, a single byte of the solid object's SST is reserved for this purpose:
collision_flags = $28 ; byte ; TT SSSSSS ; TT = collision type, SSSSSS = sizeThe decision to stuff everything in a single byte, presumably to save space on the SST, has a couple of consequences. First off, the collision_flags attribute carries information about both the collision size and the collision type. As a result, each time the game needs to read either value, it must clear out the remaining bits.
Touch_Loop:
movea.w (a4)+,a1 ; Get address of first object's RAM
move.b collision_flags(a1),d0 ; Get its collision_flags
bne.s Touch_Width ; If it actually has collision, branch
...
Touch_Width:
andi.w #$3F,d0 ; Get only collision size
add.w d0,d0 ; Turn into index
lea Touch_Sizes(pc,d0.w),a2
moveq #0,d1
move.b (a2)+,d1 ; Get width value from Touch_Sizes
move.w x_pos(a1),d0 ; Get object's x_pos
sub.w d1,d0 ; Subtract object's width
...
Then, because six bits are obviously not enough to store the actual dimensions of the object's hitbox, the collision size is really just an index to a lookup table of hardcoded size definitions, stored in pairs of width by height.Touch_Sizes:
dc.b 4, 4
dc.b $14, $14
dc.b $C, $14
dc.b $14, $C
dc.b 4, $10
dc.b $C, $12
dc.b $10, $10
...
Collision type, on the other hand, is fairly straightforward. There are four collision types, and the appropriate behavior is selected by a series of branches; no fancypants arithmetic involved.Touch_ChkValue:
move.b collision_flags(a1),d1 ; Get its collision_flags
andi.b #$C0,d1 ; Get only collision type bits
beq.w Touch_Enemy ; If 00, enemy, branch
cmpi.b #$C0,d1
beq.w Touch_Special ; If 11, "special thing for starpole", branch
tst.b d1
bmi.w Touch_ChkHurt ; If 10, "harmful", branch
... ; If 01...
Next time, we'll continue our foray into responsive collision by taking a look at the implementation of each collision type.
No comments:
Post a Comment