Сайт Влада

Как исправить баги при смене уровней

Автор гида: 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

Вот и все! Серия багов исправлена одним действием.