Fix the camera follow bug
From Sonic Retro
(Original guide by MarkeyJester)
This bug is almost unnoticable in the original game, if you are to write your own special screen movements that cause the screen to move away from Sonic, and then let the engine move the screen back to Sonic, then it can become noticable
Contents
Explaining the issue
The engine that allows the screen to follow Sonic has the responsibility of ensuring that the screen does not move more than 10 (hex) pixels any direction at one time, this is to allow the draw code to draw the lines of 16x16 blocks correctly without skipping any lines, this means that if Sonic is away from the screen's "central box" position by less than 10 (hex) pixels, then the screen's "central box" will move directly to Sonic, if however, Sonic is further than that, the screen will move at a maximum of 10 (hex) pixels in the direction it is suppose to be moving to. The routine "ScrollVertical:" handles this for moving the screen up and down, "ScrollHoriz:" on the other hand (or should I say "ScrollHoriz2:") handles this for the screen moving right, but not when moving left.
Fixing the issue
Observe the code for right movement:
loc_65CC:
cmpi.w #$10,d0 ; <- Restriction
bcs.s loc_65D6 ; <- Restriction
move.w #$10,d0 ; <- Restriction
loc_65D6:
add.w ($FFFFF700).w,d0
cmp.w ($FFFFF72A).w,d0
blt.s loc_65E4
move.w ($FFFFF72A).w,d0
As you can see by the code marked "Restriction", this is to prevent the screen from moving right by 10 pixels, thereas if we look at the code for left movement:
loc_65F6:
add.w ($FFFFF700).w,d0
cmp.w ($FFFFF728).w,d0
bgt.s loc_65E4
move.w ($FFFFF728).w,d0
bra.s loc_65E4
The "Restriction" does not exist, the fix is moderately simple:
loc_65F6:
cmpi.w #$FFF0,d0 ; has the screen moved more than 10 pixels left?
bcc.s Left_NoMax ; if not, branch
move.w #$FFF0,d0 ; set the maximum move distance to 10 pixels left
Left_NoMax:
add.w ($FFFFF700).w,d0
cmp.w ($FFFFF728).w,d0
bgt.s loc_65E4
move.w ($FFFFF728).w,d0
bra.s loc_65E4
Horizontal Wrap Bug Fix
Hivebrain Disassembly
This version of the guide is for Hivebrain's 2005 disassembly.
There is another bug related to this which funnily enough is also related to the good old "screen wrapping vertically" bug in Sonic 2 and up, but this is to do with horizontal rather than vertical, at routing "ScrollHoriz2:" we have:
ScrollHoriz2: ; XREF: ScrollHoriz
move.w ($FFFFD008).w,d0
sub.w ($FFFFF700).w,d0
subi.w #$90,d0
bcs.s loc_65F6
subi.w #$10,d0
bcc.s loc_65CC
clr.w ($FFFFF73A).w
rts
bcc and bcs are unsigned branches, the problem here is that if Sonic is behind the screen (I.e. to the left), the result will be negative (I.e. a value from 8000 to FFFF), but with the unsigned branches it will obviously treat 8000 to FFFF as positive and higher than 7FFF, thus it believes it has to move right rather than left, the fix is also simple, change the unsigned branch conditions with signed branch conditions:
ScrollHoriz2: ; XREF: ScrollHoriz
move.w ($FFFFD008).w,d0
sub.w ($FFFFF700).w,d0
subi.w #$90,d0
bmi.s loc_65F6 ; cs to mi (for negative)
subi.w #$10,d0
bpl.s loc_65CC ; cc to pl (for negative)
clr.w ($FFFFF73A).w
rts
The cc to pl should not matter, but it's best to be safe.
GitHub Disassembly
This version of the guide is for the GitHub disassembly.
Navigate to _inc\DeformLayers.asm (Rev 00) or _inc\DeformLayers (JP1).asm (Rev 01) and do the following.
Change this:
MoveScreenHoriz:
move.w (v_player+obX).w,d0
sub.w (v_screenposx).w,d0 ; Sonic's distance from left edge of screen
subi.w #144,d0 ; is distance less than 144px?
bcs.s SH_BehindMid ; if yes, branch
subi.w #16,d0 ; is distance more than 160px?
bcc.s SH_AheadOfMid ; if yes, branch
clr.w (v_scrshiftx).w
rts
To this:
MoveScreenHoriz:
move.w (v_player+obX).w,d0
sub.w (v_screenposx).w,d0 ; Sonic's distance from left edge of screen
subi.w #144,d0 ; is distance less than 144px?
bmi.s SH_BehindMid ; if yes, branch <---- cs to mi (for negative)
subi.w #16,d0 ; is distance more than 160px?
bpl.s SH_AheadOfMid ; if yes, branch <---- cc to pl (for negative)
clr.w (v_scrshiftx).w
rts
The cc to pl should not matter, but it's best to be safe.
|Fix the camera follow bug]]