Как исправить баги при смене уровней
Автор гида: vladikcomperВ Соник 1, при смене уровня, можно заметить несколько неприятных багов, когда экран затухает.
1) При переходе в новую зону, деформация задника (BG) может сбиться. Это заметно при переходе от GHZ3 к MZ1, сравните два скриншота, показывающих состояние до затухания экрана и во время него:
Это может быть незаметно в других зонах — все зависит от того, как деформация задника работает в следующем уровне.
2) Если конечная позиция в текущем уровне совпадает с позицией босса в следующем, загрузится босс и заиграет музыка босса, но тут же остановится, так все звуки затухают вместе с экраном.
Этот баг не встречался в оригинальной игре, так как акты 2 были короче актов 3. Однако, если вы продлите уровни, вы можете довольно легко столкнуться с этим багом.
3) При смене зон, циклы палитр для новой зоны сработают как только начнется затухание. Из-за этого некоторые цвета на экране могут испортиться. Это можно заметить при переходе MZ3—SYZ1.
Все эти баги происходят из-за того, что условие рестарта уровня расположено в неподходящем месте. Когда объект "SONIC HAS PASSED" переключает уровень, многие процедуры, такие как процедуры деформации задника, циклов палитр, успевают сработать до того, как сработает условие рестарта уровня. Поскольку номер уровня к этому моменту уже обновился, все эти процедуры будут деформировать задник, загружать объекты и циклы палитр для следующего уровня, что и выливается в баги, описанные выше.
Найдите лейбел Level_MainLoop, вы увидите следующий код:
Level_MainLoop: bsr.w PauseGame move.b #8,($FFFFF62A).w bsr.w DelayProgram addq.w #1,($FFFFFE04).w ; add 1 to level timer bsr.w MoveSonicInDemo bsr.w LZWaterEffects jsr ObjectsLoad tst.w ($FFFFFE08).w bne.s loc_3B10 cmpi.b #6,($FFFFD024).w ; is Sonic dying? bcc.s loc_3B14 ; if yes, branch loc_3B10: bsr.w DeformBgLayer loc_3B14: jsr BuildSprites jsr ObjPosLoad bsr.w PalCycle_Load bsr.w RunPLC_RAM bsr.w OscillateNumDo bsr.w ChangeRingFrame bsr.w SignpostArtLoad tst.w ($FFFFFE02).w ; is the level set to restart? bne.w Level ; if yes, branch cmpi.b #8,($FFFFF600).w beq.s Level_ChkDemo ; if screen mode is 08 (demo), branch cmpi.b #$C,($FFFFF600).w beq.w Level_MainLoop ; if screen mode is $0C (level), branch rts ; quit
А вот и наш бранч на рестарт уровня:
tst.w ($FFFFFE02).w ; is the level set to restart? bne.w Level ; if yes, branch
Он переходит к процедуре Level для затухания экрана и перезагрузки уровня. Все вроде бы хорошо, но посмотрите сколько ненужных процедур работает после смены номера уровня (во время работы ObjectsLoad, так как переключается объектом) и до того, как встречается этот переход.
Для исправления бага, переместите условие рестарта на несколько строк вышел, прямо за строкой:
jsr ObjectsLoad
В результате код примет вид:
Level_MainLoop: bsr.w PauseGame move.b #8,($FFFFF62A).w bsr.w DelayProgram addq.w #1,($FFFFFE04).w ; add 1 to level timer bsr.w MoveSonicInDemo bsr.w LZWaterEffects jsr ObjectsLoad tst.w ($FFFFFE02).w ; is the level set to restart? bne.w Level ; if yes, branch tst.w ($FFFFFE08).w bne.s loc_3B10 cmpi.b #6,($FFFFD024).w ; is Sonic dying? bcc.s loc_3B14 ; if yes, branch loc_3B10: bsr.w DeformBgLayer loc_3B14: jsr BuildSprites jsr ObjPosLoad bsr.w PalCycle_Load bsr.w RunPLC_RAM bsr.w OscillateNumDo bsr.w ChangeRingFrame bsr.w SignpostArtLoad cmpi.b #8,($FFFFF600).w beq.s Level_ChkDemo ; if screen mode is 08 (demo), branch cmpi.b #$C,($FFFFF600).w beq.w Level_MainLoop ; if screen mode is $0C (level), branch rts ; quit
Вот и все! Серия багов исправлена одним действием.

