After Image in Sonic 1
Here a compiled ROM with this tutorial applied.
http://goo.gl/nKwIW
Tutorial made to Hivebrain's 2005 disassembly.
----------------------------
The After Image is a "copy", "shadow" of the character (Sonic), using the same character's sprite, but without collisions and other things, is a object that is only the character's sprite.
As the sprite need to be the same of the character, all the information about the animation, map, art, horizontal / vertical mirror ...... will be the same of the character.
I will create the object 8D to do the After Image, if you have used the Object 8D, use another object that has not been used, or create other like 8E, 8F...
This After Image that i will show is based on inertia like Sonic Advance 2, and if you want, you can program it to be based on X-Velocity, Y-Velocity, or what you think better.
----------------------------
Above the Obj0A, add this code:
In Sonic_Display, change this:
As we created the object 8D, we need add it in object pointers.
In _inc\Object pointers.asm Add this line in end of the file:
If you want that "each after image" use a different pallet line, change this:
How this work?
This After Image Method is like 8 Objects, all with After Image, but each is in a different frame, like below:
In each frame, the Sonic_Display create 1 After Image, and after 8 frames (in the 9th frame), this After Image is deleted.
After 9 frames activated, it get a cycle, 1 deleted and 1 created in same frame.
This After Image Method uses a Sonic' frozen image, that still stalled until be deleted.
In a time line we can see this:
You can change the Obj8D_Index like you want, to get the better effect and without create a lot of After Images, because this can cause many lost frames (lag).
Why change the sprite priority?
For older After Images be behind than new After Images.
Why using a random number?
For the condition that say if the After Image need or not be showed, not be always the same.
Here a compiled ROM with this tutorial applied.
http://goo.gl/nKwIW
Tutorial made to Hivebrain's 2005 disassembly.
----------------------------
The After Image is a "copy", "shadow" of the character (Sonic), using the same character's sprite, but without collisions and other things, is a object that is only the character's sprite.
As the sprite need to be the same of the character, all the information about the animation, map, art, horizontal / vertical mirror ...... will be the same of the character.
I will create the object 8D to do the After Image, if you have used the Object 8D, use another object that has not been used, or create other like 8E, 8F...
This After Image that i will show is based on inertia like Sonic Advance 2, and if you want, you can program it to be based on X-Velocity, Y-Velocity, or what you think better.
----------------------------
Above the Obj0A, add this code:
- Code:
; ---------------------------------------------------------------------------
; Object 8D - After Image
; ---------------------------------------------------------------------------
Obj8D: ; XREF: Obj_Index
cmpi.b #$18,($FFFFD01C).w ; is "death" animation?
beq.w Obj8D_Delete ; if yes, delete the After Image
moveq #0,d0
move.b $24(a0),d0
move.w Obj8D_Index(pc,d0.w),d1
jmp Obj8D_Index(pc,d1.w)
; ===========================================================================
Obj8D_Index:
dc.w Obj8D_NoShow-Obj8D_Index
dc.w Obj8D_NoShow-Obj8D_Index
dc.w Obj8D_NoShow-Obj8D_Index
dc.w Obj8D_Sprite_priority_start-Obj8D_Index
dc.w Obj8D_NoShow-Obj8D_Index
dc.w Obj8D_NoShow-Obj8D_Index
dc.w Obj8D_Sprite_priority_next-Obj8D_Index
dc.w Obj8D_Delete-Obj8D_Index
; ===========================================================================
Obj8D_NoShow:
addq.b #2,$24(a0) ; go to next item of index, at the next frame
rts
; ===========================================================================
Obj8D_Sprite_priority_start:
move.b #2,$18(a0) ; set sprite priority to 2
bra.s Obj8D_Show
; ===========================================================================
Obj8D_Sprite_priority_next:
addq.b #1,$18(a0) ; set a lower sprite priority
; ===========================================================================
Obj8D_Show:
addq.b #2,$24(a0) ; go to next item of index
jsr (RandomNumber).l ; get a random number
andi.b #2,d0 ; get a number equal or lower than 2 (0 until 2)
bne.s Obj8D_Show_exception ; if is not 0, branch
rts ; if is 0, don't show the after-image
Obj8D_Show_exception:
move.w ($FFFFD002).w,2(a0) ; copy Sonic map to after-image map
move.b ($FFFFD001).w,1(a0) ; copy Sonic frame infos (horizontal/vertical mirror, coordinate system......)
move.l ($FFFFD01A).w,$1A(a0) ; copy the Sonic animation frame
jmp DisplaySprite
; ===========================================================================
Obj8D_Delete:
jmp DeleteObject
; ===========================================================================
In Sonic_Display, change this:
- Code:
Sonic_Display: ; XREF: loc_12C7E
move.w $30(a0),d0
beq.s Obj01_Display
subq.w #1,$30(a0)
lsr.w #3,d0
bcc.s Obj01_ChkInvin
Obj01_Display:
jsr DisplaySprite
- Code:
Sonic_Display: ; XREF: loc_12C7E
move.w $30(a0),d0
beq.s Obj01_Display_AfterImage
subq.w #1,$30(a0)
lsr.w #3,d0
bcc.s Obj01_ChkInvin
Obj01_Display_AfterImage:
move.w $14(a0),d0 ; get inertia
tst.w d0 ; is inertia greater than 0?
bge.s Obj01_AfterImage_Start ; if yes, don't negate it
neg d0 ; if not, negate it
Obj01_AfterImage_Start:
cmpi.w #$600,d0 ; is the sonic inertia greater than 600?
blt.s Obj01_Display ; if not, don't show the After Image
bsr.w SingleObjLoad ; search a free space in object RAM
bne.s Obj01_Display ; if not have, don't load the After Image
move.b #$8D,0(a1) ; load after-image object
move.l 4(a0),4(a1) ; copy Sonic mappings to after-image mappings
move.w 8(a0),8(a1) ; copy Sonic x-pos to after-image x-pos
move.w $C(a0),$C(a1) ; copy Sonic y-pos to after-image y-pos
Obj01_Display:
jsr DisplaySprite
As we created the object 8D, we need add it in object pointers.
In _inc\Object pointers.asm Add this line in end of the file:
- Code:
dc.l Obj8D
If you want that "each after image" use a different pallet line, change this:
- Code:
Obj8D_Show:
addq.b #2,$24(a0) ; go to next item of index
jsr (RandomNumber).l ; get a random number
andi.b #2,d0 ; get a number equal or lower than 2 (0 until 2)
bne.s Obj8D_Show_exception ; if is not 0, branch
rts ; if is 0, don't show the after-image
Obj8D_Show_exception:
move.w ($FFFFD002).w,2(a0) ; copy Sonic map to after-image map
move.b ($FFFFD001).w,1(a0) ; copy Sonic frame infos (horizontal/vertical mirror, coordinate system......)
move.l ($FFFFD01A).w,$1A(a0) ; copy the Sonic animation frame
jmp DisplaySprite
- Code:
Obj8D_Show:
addq.b #2,$24(a0) ; go to next item of index
jsr (RandomNumber).l ; get a random number
andi.b #3,d0 ; get a number equal or lower than 3 (0 until 3)
bne.s Obj8D_Show_exception ; if is not 0, branch
rts ; if is 0, don't show the after-image
Obj8D_Show_exception:
lsl.w #8,d0 ; multiply by 2000
lsl.w #5,d0
move.w ($FFFFD002).w,2(a0) ; copy Sonic map to after-image map
add.w d0,2(a0) ; set any pallet line
move.b ($FFFFD001).w,1(a0) ; copy Sonic frame infos (horizontal/vertical mirror, coordinate system......)
move.l ($FFFFD01A).w,$1A(a0) ; copy the Sonic animation frame
jmp DisplaySprite
How this work?
This After Image Method is like 8 Objects, all with After Image, but each is in a different frame, like below:
- Code:
is being created on Sonic_Display ; 1st frame
dc.w Obj8D_NoShow-Obj8D_Index ; 2nd frame
dc.w Obj8D_NoShow-Obj8D_Index ; 3rd frame
dc.w Obj8D_NoShow-Obj8D_Index ; 4th frame
dc.w Obj8D_Sprite_priority_start-Obj8D_Index ; 5th frame
dc.w Obj8D_NoShow-Obj8D_Index ; 6th frame
dc.w Obj8D_NoShow-Obj8D_Index ; 7th frame
dc.w Obj8D_Sprite_priority_next-Obj8D_Index ; 8th frame
dc.w Obj8D_Delete-Obj8D_Index ; 9th frame
In each frame, the Sonic_Display create 1 After Image, and after 8 frames (in the 9th frame), this After Image is deleted.
After 9 frames activated, it get a cycle, 1 deleted and 1 created in same frame.
This After Image Method uses a Sonic' frozen image, that still stalled until be deleted.
In a time line we can see this:
Note: the sequence (time line), only will be like this if the Obj8D_Index be same than my tutorial.1st frame - created
2nd frame - not showed
3rd frame - not showed
4th frame - not showed
5th frame - showed
6th frame - not showed
7th frame - not showed
8th frame - showed
9th frame - deleted
You can change the Obj8D_Index like you want, to get the better effect and without create a lot of After Images, because this can cause many lost frames (lag).
Why change the sprite priority?
For older After Images be behind than new After Images.
Why using a random number?
For the condition that say if the After Image need or not be showed, not be always the same.