Jayextee, on 15 June 2012 - 10:21 AM, said:
I don't recall, has anyone ever fixed the collision? -- when Sonic (or Tails) is colliding with two objects at once, only one registers? This is why Sonic walks through certain badniks in ARZ when he's scattering leaves, and why he can't collect dropped rings in lava without jumping.
Like I said earlier, it probably wouldn't be good performance-wise to check every object each frame, but there's another way to get around this problem:
Fix collisions with the lava collision maker object
The Bug:
The way object collisions work, it's impossible to collide with two objects at once unless the object itself does the collision checks. That's what we're going to do here.
The Fix:
We're going to be editing object 31, the lava collision maker. First locate the label
Obj31_Init (loc_20E02):
; byte_20DFE:
Obj31_CollisionFlagsBySubtype:
dc.b $96 ; 0
dc.b $94 ; 1
dc.b $95 ; 2
dc.b 0 ; 3
; ===========================================================================
; loc_20E02:
Obj31_Init:
addq.b #2,routine(a0) ; => Obj31_Main
moveq #0,d0
move.b subtype(a0),d0
move.b Obj31_CollisionFlagsBySubtype(pc,d0.w),collision_flags(a0) ; <-------
move.l #Obj31_MapUnc_20E6C,mappings(a0)
tst.w (Debug_placement_mode).w
beq.s +
move.l #Obj31_MapUnc_20E74,mappings(a0)
+
move.w #make_art_tile(ArtTile_ArtNem_Powerups,0,1),art_tile(a0)
move.b #$84,render_flags(a0)
move.b #$80,width_pixels(a0)
move.b #4,priority(a0)
move.b subtype(a0),mapping_frame(a0)
Now, we replace the data table
Obj31_CollisionFlagsBySubtype and the line that uses it with the following:
Obj31_Widths:
dc.b $20 ; 0
dc.b $40 ; 1
dc.b $80 ; 2
dc.b 4 ; 3
; ===========================================================================
(...)
move.b Obj31_Widths(pc,d0.w),x_radius(a0)
Next, we need to add our own collision check. Here's the routine, place it anywhere close to the object's code. I put it between
Obj31_Main and the object's mappings.
Obj31_TestCollisions:
lea (MainCharacter).w,a1
bsr.s +
lea (Sidekick).w,a1
+
; test horizontal
moveq #0,d1
move.b x_radius(a0),d1
; left edge
move.w x_pos(a1),d0
sub.w x_pos(a0),d0
add.w d1,d0
bmi.s Obj31_NoCollision
; right edge
add.w d1,d1
cmp.w d1,d0
bcc.s Obj31_NoCollision
; test vertical
moveq #$20,d1 ; we assume a constant y_radius of 32 pixels
add.b y_radius(a1),d1
; top edge
move.w y_pos(a1),d0
sub.w y_pos(a0),d0
add.w d1,d0
bmi.s Obj31_NoCollision
; bottom edge
add.w d1,d1
cmp.w d1,d0
bcc.s Obj31_NoCollision
; hurt player
move.l a0,-(sp) ; save object address
exg a0,a1 ; switch object and player addresses
jsr Touch_ChkHurt
movea.l (sp)+,a0 ; load 0bj address
Obj31_NoCollision:
rts
; ===========================================================================
Now we need the object to call this routine. Right after the label
Obj31_Main, add this:
tst.w (Debug_placement_mode).w
bne.s + ; skip collision checks if in object placement mode mode
bsr.s Obj31_TestCollisions
+
Done.
Now, I'm no expert on coding bounding box checks, so if someone can come up with a better collision checking routine that uses less cycles, post away. This does have the potential to slow the game down a little, so every little bit helps.
What really helps is s3k's collision checking routine. Instead of going through the entire object list, it only checks objects that add themselves to a specific list. This means objects that have no collisions or ones that do the checks themselves will be skipped.
The fix for the ARZ leaf makers should work the same way, but I'd need to check first to be sure.