Stream 3 Step By Step: Bowling Ball
Step 1: Create frames on Dyzen
Step 2: Create Animation on Dyzen
Step 3: Create Interaction on Dyzen
Step 4: Extracting Resources from Dyzen
Move the sprite generated by the tool to the Sprite Folder of Pixi
Step 5: Doing the CFG
Use CFG.exe to do the CFG for the sprite. I used Object Clipping 07. We will use 3 extra bytes.
Step 6: Convert Sprite From Giepy to Pixi
This step is necessary because Dyzen use Giepy by default, on the future it will use Pixi.
We change the following lines to pixi:
CodeJSL SubOffScreen -> %SubOffScreen()
JSL GetDrawInfo -> %GetDrawInfo()
JSL SubHorzPos -> %SubHorzPos()
JSL SubVertPos -> %SubVertPos()
Also in this zone:
Code %SubVertPos()
LDA !ScratchE
We replace:
For:
Also we will use Extra Bytes, then we must change the defines of the sprite because it use Giepy ExtraBytes by default, you must change this:
Code!ExtraByte1 = $4000A4 -> !ExtraByte1 = $400099
!ExtraByte2 = $4000BA -> !ExtraByte2 = $4000AF
!ExtraByte3 = $4000D0 -> !ExtraByte3 = $4000C5
!ExtraByte4 = $4000E6 -> !ExtraByte4 = $4000DB
Step 7: Inserting the sprite with pixi
Step 8: Creating interaction
This step is the same as Bloody Grinder, Check
Bloody Grinder Log
Step 9: Main Routine
On the SpriteCode routine we will call a routine Called MainRoutine after interaction with player:
Code JSR InteractMarioSprite
;After this routine, if the sprite interact with mario, Carry is Set.
JSR MainRoutine
;Here you can write your sprite code routine
;This will be excecuted once per frame excepts when
;the animation is locked or when sprite status is not #$08
Now on the Sub Routine Space we create the MainRoutine:
Step 10: Bounce
On the Main routine we call update sprite position with gravity routine $01802A:
CodeMainRoutine:
JSL $01802A|!rom ;Update X and Y Position
RTS
Remember includes |!rom for sa1 compatibility.
Now we create a routine Bounce, the logic of this routine is:
-Each frame we save the last blocked status of the floor on a misc table.
-If the sprite is falling (Y Speed > 0), sprite y speed is more than a minimum speed for bounce, the sprite is touching the floor and on the last blocked status the sprite wasn't touching the floor, then the sprite bounce.
-For bounce we save the half of the current Y Speed and then we invert it, basically New Y Speed = -(Old Y Speed/2). Also we play a sound effect, shake the earth and do the stun.
Then the first step is create a constant on the top of the file for minimum Y speed required for bounce:
Code;Constant
!MinYSpeedBounce = #$20 ;Must be between #$00 and #$7F
Then on the defines space we create the last frame floor blocked status:
Code;######################################
;############## Defines ###############
;######################################
!FrameIndex = !SpriteMiscTable1
!AnimationTimer = !SpriteDecTimer1
!AnimationIndex = !SpriteMiscTable2
!AnimationFrameIndex = !SpriteMiscTable3
!LocalFlip = !SpriteMiscTable4
!GlobalFlip = !SpriteMiscTable5
!LastBlockedFloorState = !SpriteMiscTable6
This must start with 0, then on the Init we set it to zero:
Code;######################################
;########### Init Routine #############
;######################################
print "INIT ",pc
LDA #$00
STA !GlobalFlip,x
STA !LastBlockedFloorState,x
JSL InitWrapperChangeAnimationFromStart
RTL
Now we create a bounce routine:
First step is know if the sprite is falling, for that we check if Y Speed > 0.
CodeBounce:
LDA !SpriteYSpeed,x
BMI .ret
BEQ .ret ;if Sprite is falling
.ret
RTS
Now we must check if the Y Speed >= !MinYSpeedBounce
CodeBounce:
LDA !SpriteYSpeed,x
BMI .ret
BEQ .ret ;if Sprite is falling
CMP !MinYSpeedBounce
BCC .ret ;if Y Speed >= !MinYSpeedBounce
.ret
RTS
Now we check if the sprite is touching the floor:
CodeBounce:
LDA !SpriteYSpeed,x
BMI .ret
BEQ .ret ;if Sprite is falling
CMP !MinYSpeedBounce
BCC .ret ;if Y Speed >= !MinYSpeedBounce
LDA !SpriteBlockedStatus_ASB0UDLR,x
AND #$04 ;0000 0D00;
BEQ .ret ;If sprite is touching the floor
.ret
RTS
Now we check if the last floor blocked status was on the floor or in the air:
CodeBounce:
LDA !SpriteYSpeed,x
BMI .ret
BEQ .ret ;if Sprite is falling
CMP !MinYSpeedBounce
BCC .ret ;if Y Speed >= !MinYSpeedBounce
LDA !SpriteBlockedStatus_ASB0UDLR,x
AND #$04 ;0000 0D00;
BEQ .ret ;If sprite is touching the floor
CMP !LastBlockedFloorState,x
BEQ .ret ;If sprite doesn't touch the floor the last frame
.ret
RTS
Now we do the sprite bounce, play the sound and shake the earth, for sound we use $1DFC and for earthquake we set the timer on $1887:
CodeBounce:
LDA !SpriteYSpeed,x
BMI .ret
BEQ .ret ;if Sprite is falling
CMP !MinYSpeedBounce
BCC .ret ;if Y Speed >= !MinYSpeedBounce
LDA !SpriteBlockedStatus_ASB0UDLR,x
AND #$04 ;0000 0D00;
BEQ .ret ;If sprite is touching the floor
CMP !LastBlockedFloorState,x
BEQ .ret ;If sprite doesn't touch the floor the last frame
LDA #$25
STA $1DFC|!addr ;Reproduce Sound
LDA !SpriteYSpeed,x
LSR
STA !Scratch0 ;!Scratch0 = YSpeed /2
STA $1887|!addr ;Set the Earthquake
LDA #$00
SEC
SBC !Scratch0
STA !SpriteYSpeed,x ;!SpriteYSpeed,x = -!SpriteYSpeed,x
.ret
RTS
For stun we check player floor blocked status and then we set the stun:
CodeBounce:
LDA !SpriteYSpeed,x
BMI .ret
BEQ .ret ;if Sprite is falling
CMP !MinYSpeedBounce
BCC .ret ;if Y Speed >= !MinYSpeedBounce
LDA !SpriteBlockedStatus_ASB0UDLR,x
AND #$04 ;0000 0D00;
BEQ .ret ;If sprite is touching the floor
CMP !LastBlockedFloorState,x
BEQ .ret ;If sprite doesn't touch the floor the last frame
LDA #$25
STA $1DFC|!addr ;Reproduce Sound
LDA !SpriteYSpeed,x
LSR
STA !Scratch0 ;!Scratch0 = YSpeed /2
STA $1887|!addr ;Set the Earthquake
LDA #$00
SEC
SBC !Scratch0
STA !SpriteYSpeed,x ;!SpriteYSpeed,x = -!SpriteYSpeed,x
LDA !PlayerBlockedStatus_S00MUDLR
AND #$04
BEQ + ;If player is touching the floor
LDA !Scratch0
STA $18BD|!addr ;Set Stun Time
+
.ret
RTS
As last step we update the last floor blocked status:
CodeBounce:
LDA !SpriteYSpeed,x
BMI .ret
BEQ .ret ;if Sprite is falling
CMP !MinYSpeedBounce
BCC .ret
LDA !SpriteBlockedStatus_ASB0UDLR,x
AND #$04 ;0000 0D00;
BEQ .ret ;If sprite is touching the floor
CMP !LastBlockedFloorState,x
BEQ .ret ;If sprite doesn't touch the floor the last frame
LDA #$25
STA $1DFC|!addr ;Reproduce Sound
LDA !SpriteYSpeed,x
LSR
STA !Scratch0 ;!Scratch0 = YSpeed /2
STA $1887|!addr ;Set the Earthquake
LDA !PlayerBlockedStatus_S00MUDLR
AND #$04
BEQ + ;If player is touching the floor
LDA !Scratch0
STA $18BD|!addr ;Set Stun Time
+
LDA #$00
SEC
SBC !Scratch0
STA !SpriteYSpeed,x ;!SpriteYSpeed,x = -!SpriteYSpeed,x
.ret
LDA !SpriteBlockedStatus_ASB0UDLR,x
AND #$04 ;0000 0D00;
STA !LastBlockedFloorState,x
RTS
Then we call the routine on the MainRoutine before update position:
CodeMainRoutine:
JSR Bounce
JSL $01802A|!rom ;Update X and Y Position
RTS
Step 11: Basic X Speed
For this step we create 2 constants: !RotationTime and !XSpeed.
-!RotationTime: Will be used to set how fast the sprite will rotate, it is the time to update the current frame of the animation. More Time, slower rotation.
-!XSpeed: X Speed of the sprite when it touch the floor for the first time.
Then we create both on the top of the file:
Code;Constant
!MinYSpeedBounce = #$20 ;Minimum Sprite Y Speed to Bounce (Must be between #$00 and #$7F)
!RotationTime = $04 ;Time to update animation
!XSpeed = #$22 ;X Speed that have the sprite when it touch the floor for the first time.
Now we will create a routine called XMovement that we will use it to set the X Speed, for that routine we will need a misc table to know when the sprite touch the floor for the first time.
Code;######################################
;############## Defines ###############
;######################################
!FrameIndex = !SpriteMiscTable1
!AnimationTimer = !SpriteDecTimer1
!AnimationIndex = !SpriteMiscTable2
!AnimationFrameIndex = !SpriteMiscTable3
!LocalFlip = !SpriteMiscTable4
!GlobalFlip = !SpriteMiscTable5
!LastBlockedFloorState = !SpriteMiscTable6
!TouchedFloorFlag = !SpriteMiscTable7
This misc must start with 0:
Code;######################################
;########### Init Routine #############
;######################################
print "INIT ",pc
LDA #$00
STA !GlobalFlip,x
STA !LastBlockedFloorState,x
STA !TouchedFloorFlag,x
JSL InitWrapperChangeAnimationFromStart
;Here you can write your Init Code
;This will be excecuted when the sprite is spawned
RTL
Now we create the routine on the sub routine space:
The logic of this routine is:
-If The sprite never touched the floor and now the sprite is touching the floor then we update the !TouchedFloorFlag and we set the speed.
-If the sprite is touching a wall then invert the Xspeed (!SpriteXSpeed,x = -!SpriteXSpeed,x)
Then first we check the !TouchedFloorFlag to know if it never touched the floor:
CodeXMovement:
LDA !TouchedFloorFlag,x
BEQ +
+
RTS
Now we check if the sprite is touching the floor, update !TouchedFloorFlag and Xspeed:
CodeXMovement:
LDA !TouchedFloorFlag,x
BNE +
LDA !SpriteBlockedStatus_ASB0UDLR,x
AND #$04 ;0000 00LR
BEQ + ;If sprite is touching the floor
LDA #$01
STA !TouchedFloorFlag,x
LDA !XSpeed
STA !SpriteXSpeed,x
+
RTS
Now we check the walls and invert X Speed:
CodeXMovement:
LDA !TouchedFloorFlag,x
BNE +
LDA !SpriteBlockedStatus_ASB0UDLR,x
AND #$04 ;0000 00LR
BEQ + ;If sprite is touching the floor
LDA #$01
STA !TouchedFloorFlag,x
LDA !XSpeed
STA !SpriteXSpeed,x
+
LDA !SpriteBlockedStatus_ASB0UDLR,x
AND #$03 ;0000 00LR
BEQ + ;Check Walls
LDA #$00
SEC
SBC !SpriteXSpeed,x
STA !SpriteXSpeed,x ;!SpriteXSpeed,x = -!SpriteXSpeed,x
+
RTS
Now we call the routine on the MainRoutine after bounce:
CodeMainRoutine:
JSR Bounce
JSR XMovement
JSL $01802A|!rom ;Update X and Y Position
RTS
If you insert the sprite now the sprite will do the movement fine but the animation will not flip, usually for a normal sprite you flip the sprite using !GlobalFlip,x, basically if it is 0 then it is not flipped and if it 1 then the sprite is flipped, but that for this sprite is not a good idea because it won't looks fine. To do this sprite flip, we will go to the animation routine to this zone:
Code REP #$30 ;A,X/Y of 16 bits
LDX !Scratch4 ;X = sprite index in 16 bits
LDA !Scratch0
ASL
TAY ;Y = 2*Animation index
INC !Scratch2 ;New Animation Frame Index = Animation Frame Index + 1
LDA !Scratch2 ;if Animation Frame index < Animation Lenght then Animation Frame index++
CMP AnimationLenght,y ;else go to the frame where start the loop.
BCC +
LDA AnimationLastTransition,y
STA !Scratch2 ;New Animation Frame Index = first frame of the loop.
+
LDA !Scratch2
CLC
ADC AnimationIndexer,y
TAY ;Y = Position of the first frame of the animation + animation frame index
SEP #$20 ;A of 8 bits
In this Zone the Scratch2 have the index current frame that the sprite must show, by default frame always Increase in 1 and when it is the last frame (in this case frame #$000B then it is set to 0). We will change that to allows decrease or increase frame depends on XSpeed. Then for that on this zone:
CodeAnimationRoutine:
LDA !AnimationTimer,x
BEQ +
RTS
+
We will use ScratchE to save the sign of the speed. it will be 0 if the speed is positive and 80 if negative:
CodeAnimationRoutine:
LDA !AnimationTimer,x
BEQ +
RTS
+
STZ !ScratchF
LDA !SpriteXSpeed,x
AND #$80
STA !ScratchE
Now on the other zone we will make the following:
-If Sprite X Speed < 0 then Frame Increase and if the current frame > last frame then is 0 otherwise Frame Decrease and if the frame is negative then now is the last frame
Code REP #$30 ;A7X/Y of 16 bits
LDX !Scratch4 ;X = sprite index in 16 bits
LDA !Scratch0
ASL
TAY ;Y = 2*Animation index
LDA !ScratchE
BNE +
DEC !Scratch2
LDA !Scratch2
BPL ++
LDA #$000B
STA !Scratch2
BRA ++
+
INC !Scratch2 ;New Animation Frame Index = Animation Frame Index + 1
LDA !Scratch2 ;if Animation Frame index < Animation Lenght then Animation Frame index++
CMP AnimationLenght,y ;else go to the frame where start the loop.
BCC ++
LDA AnimationLastTransition,y
STA !Scratch2 ;New Animation Frame Index = first frame of the loop.
++
LDA !Scratch2
CLC
ADC AnimationIndexer,y
TAY ;Y = Position of the first frame of the animation + animation frame index
SEP #$20 ;A of 8 bits
Also we will go to the table Times:
CodeTimes:
Animation0_Animation0_Times:
db $04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$04
And we will replace all $04 for !RotationTime:
CodeTimes:
Animation0_Animation0_Times:
db !RotationTime,!RotationTime,!RotationTime,!RotationTime,!RotationTime,!RotationTime
db !RotationTime,!RotationTime,!RotationTime,!RotationTime,!RotationTime,!RotationTime
Now you user can customize !XSpeed and !RotationTime.
Step 12: Explosion
For explosion we will create 2 constants: !MaxTime and !FlashMinTime.
-!MaxTime: Time for do the sprite explode.
-!FlashMinTime: Time for do the sprite flash before explode.
Then we add them with the others constants:
Code;Constant
!MinYSpeedBounce = #$20 ;Minimum Sprite Y Speed to Bounce (Must be between #$00 and #$7F)
!RotationTime = $04 ;Time to update animation
!XSpeed = #$22 ;X Speed that have the sprite when it touch the floor for the first time.
!MaxTime = #$FF ;FF = 4 seconds
!FlashMinTime = #$30 ;Minimum Time to start to flash
Also we need a timer for explosion, for that we add it to the defines:
Code;######################################
;############## Defines ###############
;######################################
!FrameIndex = !SpriteMiscTable1
!AnimationTimer = !SpriteDecTimer1
!AnimationIndex = !SpriteMiscTable2
!AnimationFrameIndex = !SpriteMiscTable3
!LocalFlip = !SpriteMiscTable4
!GlobalFlip = !SpriteMiscTable5
!LastBlockedFloorState = !SpriteMiscTable6
!TouchedFloorFlag = !SpriteMiscTable7
!ExplosionTimer = !SpriteDecTimer2
You always use DecTimers for timers. Now we must se the timer on the init:
Code;######################################
;########### Init Routine #############
;######################################
print "INIT ",pc
LDA #$00
STA !GlobalFlip,x
STA !LastBlockedFloorState,x
STA !TouchedFloorFlag,x
JSL InitWrapperChangeAnimationFromStart
LDA !MaxTime
STA !ExplosionTimer,x
RTL
And we will copy paste this routine on the sub routine space:
Codebobomb:
LDA #$15
STA $1887|!addr ; shake the ground
LDA #$0D ;/
STA !SpriteNumber,x ;\ Sprite = Bob-omb.
LDA #$08 ;/
STA !SpriteStatus,x ;\ Set status for new sprite.
JSL $07F7D2|!rom ;/ Reset sprite tables (sprite becomes bob-omb)..
LDA #$01 ;\ .. and flag explosion status.
STA !SpriteMiscTable8,x ;/
LDA #$40 ;\ Time for explosion.
STA !SpriteDecTimer1,x
LDA #$09 ;\
STA $1DFC|!addr ;/ Sound effect.
LDA #$1B
STA !SpriteTweaker167A_DPMKSPIS,x
RTS
That routine replace the sprite with a bob omb exploding.
Now we create a Explosion routine:
The logic of this routine is:
-If Explode Timer == 0 then call bobomb and it will move it 16 pixels to right (this is to center the explosion).
CodeExplode:
LDA !ExplosionTimer,x
BNE + ;if timer is 0
JSR bobomb ;Explode
LDA !SpriteXHigh,x
STA !Scratch1
LDA !SpriteXLow,x
STA !Scratch0
REP #$20
LDA !Scratch0
CLC
ADC #$0010
STA !Scratch0
SEP #$20
LDA !Scratch0
STA !SpriteXLow,x
LDA !Scratch1
STA !SpriteXHigh,x ;Moves 16 pixels to right
+
RTS
Also we will add an Extra byte for explosion, Extra Byte 3 will be used for explosion, if it is 0 then explode and if it is not 0 then dont explode, For that on the defines we will define the extra byte:
Code;######################################
;############## Defines ###############
;######################################
!FrameIndex = !SpriteMiscTable1
!AnimationTimer = !SpriteDecTimer1
!AnimationIndex = !SpriteMiscTable2
!AnimationFrameIndex = !SpriteMiscTable3
!LocalFlip = !SpriteMiscTable4
!GlobalFlip = !SpriteMiscTable5
!LastBlockedFloorState = !SpriteMiscTable6
!TouchedFloorFlag = !SpriteMiscTable7
!ExplosionTimer = !SpriteDecTimer2
!Explode = !ExtraByte3
Then we add that only explode if !Explode is 0:
CodeExplode:
LDA !Explode,x
BEQ + ;Check Extra Byte
LDA !ExplosionTimer,x
BNE + ;if timer is 0
JSR bobomb ;Explode
LDA !SpriteXHigh,x
STA !Scratch1
LDA !SpriteXLow,x
STA !Scratch0
REP #$20
LDA !Scratch0
CLC
ADC #$0010
STA !Scratch0
SEP #$20
LDA !Scratch0
STA !SpriteXLow,x
LDA !Scratch1
STA !SpriteXHigh,x ;Moves 16 pixels to right
+
RTS
Now we call that routine on the Main Routine After XMovement:
CodeMainRoutine:
JSR Bounce
JSR XMovement
JSR Explode
JSL $01802A|!rom ;Update X and Y Position
RTS
If you insert the sprite, the sprite wont flash but will do all other things. To make it Flash we go to the Graphic Routine to this zone:
Code LDA Properties,x
STA !TileProperty,y ;Set the Tile property of the tile Y
That zone set the properties of the Tile, Properties follows the format YXPPCCCT:
-Y = If 0 then it doesn't flip in Y, if it is 1 it flip in Y
-X = If 0 then it doesn't flip in X , if it is 1 it flip in X
-PP = Priority vs Layers (00 behind all layer, 01 in front layer 2 but behind layer 2, 10 = in front layer 1 and 3, 11 = in front of all)
-CCC = Palette (In this case we use Palette E when doesn't flash and F when it flashes, that is equivalent to 6 and 7)
T = If 0 it uses SP1/2 if 1 it uses SP3/4.
In this case the logic will be clear all CCC bits and replace them with CCC bits of a Scratch.
Then at the start of Graphic Routine we add this:
CodeGraphicRoutine:
%GetDrawInfo() ;Calls GetDrawInfo to get the free slot and the XDisp and YDisp
LDA #$0C
STA !ScratchE
ScratchE will be C in the normal case, because C is equivalent to CCC = 110 = 6.
To do the Flash, we will check ExplosionTimer, if it less than !FlashMinTime we will make it Flash.
For Flash we will do an AND #$02, that will alternate the palette every 2 frames, if you want to alternate every 1 frame then you put 1, Valid Values for that and is 01,02,04,08,10,20,40 and 80, Higher value slower flash.
CodeGraphicRoutine:
%GetDrawInfo() ;Calls GetDrawInfo to get the free slot and the XDisp and YDisp
LDA #$0C
STA !ScratchE
LDA !Explode,x
BEQ + ;If can explode (check extra byte)
LDA !ExplosionTimer,x
CMP !FlashMinTime ;if !ExplosionTimer,x<!FlashMinTime
BCS +
AND #$02
BNE + ;If is !ExplosionTimer,x Bitwise AND #$02 0
LDA #$0E
STA !ScratchE ;Use Palette 7
+
Then we change the other zone for this:
Code LDA Properties,x
AND #$F1 ;YXPP000T
ORA !ScratchE
STA !TileProperty,y ;Set the Tile property of the tile Y
Now the Sprite is Finished.
EXTRA STEP: X Speed Depends on Rotation Time
This step is more complex. Basically we will transform !RotationTime into !XSpeed when the sprite touch the floor for the first time.
For this we will require some Physics knowledge.
This !RotationTime is the time to change the frame, the angle changes in 30°, for that the Complete Period is 12*!RotationTime, because in that time the sprite will do a complete rotation, it is called the Period.
Angular Speed is Equals to (2*Pi)/Period, then that is how we get the Angular Speed.
The Regular Speed is = Angular Speed * Ratio, in this case Ratio of the sprite is 24 pixels. This Regular Speed will be on Pixels / Frame. To transform it to SMW Speed Units we must Multiply by 16.
Obviusly all this calculus is very slow to do on snes, for that we will calculate all those values on a program or excel and create a table based on that. If you do that you will get a table that transform Rotation time into X Speed, Here is the table:
CodeRotToSpeedTable:
db $FF,$C9,$65,$43,$32,$28,$22,$1D,$19,$16,$14,$12,$11,$0F,$0E,$0D
db $0D,$0C,$0B,$0B,$0A,$0A,$09,$09,$08,$08,$08,$07,$07,$07,$07,$06
db $06,$06,$06,$06,$06,$05,$05,$05,$05,$05,$05,$05,$05,$04,$04,$04
db $04,$04,$04,$04,$04,$04,$04,$04,$04,$04,$03,$03,$03,$03,$03,$03
db $03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03
db $03,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02
db $02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02
db $02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02
db $02,$02,$02,$02,$02,$02,$02,$01,$01,$01,$01,$01,$01,$01,$01,$01
Now We will create a Define for Rotation Direction, If it is zero rotation will be to left, other wise will be right.
Code;######################################
;############## Defines ###############
;######################################
!FrameIndex = !SpriteMiscTable1
!AnimationTimer = !SpriteDecTimer1
!AnimationIndex = !SpriteMiscTable2
!AnimationFrameIndex = !SpriteMiscTable3
!LocalFlip = !SpriteMiscTable4
!GlobalFlip = !SpriteMiscTable5
!LastBlockedFloorState = !SpriteMiscTable6
!TouchedFloorFlag = !SpriteMiscTable7
!ExplosionTimer = !SpriteDecTimer2
!RotationDirection = !SpriteMiscTable8
!Explode = !ExtraByte3
Also we will do that this depends on Extra Bit:
Code;######################################
;########### Init Routine #############
;######################################
print "INIT ",pc
LDA #$00
STA !GlobalFlip,x
STA !LastBlockedFloorState,x
STA !TouchedFloorFlag,x
JSL InitWrapperChangeAnimationFromStart
LDA !MaxTime
STA !ExplosionTimer,x
LDA !ExtraBits,x
BEQ +
LDA #$01
STA !RotationDirection,x
+
;Here you can write your Init Code
;This will be excecuted when the sprite is spawned
RTL
Also to do the sprite easier to customize we will change !RotationTime and !XSpeed to Extra bytes.
Code;######################################
;############## Defines ###############
;######################################
!FrameIndex = !SpriteMiscTable1
!AnimationTimer = !SpriteDecTimer1
!AnimationIndex = !SpriteMiscTable2
!AnimationFrameIndex = !SpriteMiscTable3
!LocalFlip = !SpriteMiscTable4
!GlobalFlip = !SpriteMiscTable5
!LastBlockedFloorState = !SpriteMiscTable6
!TouchedFloorFlag = !SpriteMiscTable7
!ExplosionTimer = !SpriteDecTimer2
!RotationDirection = !SpriteMiscTable8
!RotationTime = !ExtraByte1
!XSpeed = !ExtraByte2
!Explode = !ExtraByte3
Also now the !XSpeed will be the initial X Speed of the sprite.
Code;######################################
;########### Init Routine #############
;######################################
print "INIT ",pc
LDA #$00
STA !GlobalFlip,x
STA !LastBlockedFloorState,x
STA !TouchedFloorFlag,x
JSL InitWrapperChangeAnimationFromStart
LDA !MaxTime
STA !ExplosionTimer,x
LDA !ExtraBits,x
BEQ +
LDA #$01
STA !RotationDirection,x
+
LDA !XSpeed,x
STA !SpriteXSpeed,x
;Here you can write your Init Code
;This will be excecuted when the sprite is spawned
RTL
Now we will create a routine that use the table, that will transform !RotationTime into Sprite X Speed.
CodeRotationTimeToSpeed:
RTS
The logic of this routine is:
-You can see that the first 2 values are not valid for Speed, because X Speed should be between 00 and 7F, Then we only can index the table starting with 2.
-We will index the table, for that we load !RotationTime into Y register and use it to set the X Speed.
-If Rotation Direction is to Left (0) we invert X Speed.
CodeRotationTimeToSpeed:
LDA !RotationTime,x
CMP #$02
BCS + ;Minimum Index of the table must be 2
LDA #$02 ;If less than 2 then use 2.
+
TAY ;Y = Rotation Time
LDA RotToSpeedTable,y
STA !SpriteXSpeed,x ;Transform Rotation Time into X Speed using the table
LDA !RotationDirection,x
BEQ + ;If rotation is to left then invert sprite x speed
LDA #$00
SEC
SBC !SpriteXSpeed,x
STA !SpriteXSpeed,x ;!SpriteXSpeed,x=-!SpriteXSpeed,x
+
RTS
Now on XMovement routine:
CodeXMovement:
LDA !TouchedFloorFlag,x
BNE +
LDA !SpriteBlockedStatus_ASB0UDLR,x
AND #$04 ;0000 00LR
BEQ + ;If sprite is touching the floor
LDA #$01
STA !TouchedFloorFlag,x
LDA !XSpeed
STA !SpriteXSpeed,x
+
LDA !SpriteBlockedStatus_ASB0UDLR,x
AND #$03 ;0000 00LR
BEQ + ;Check Walls
LDA #$00
SEC
SBC !SpriteXSpeed,x
STA !SpriteXSpeed,x ;!SpriteXSpeed,x = -!SpriteXSpeed,x
+
RTS
We change lines that set speed calling the routine RotationTimeToSpeed, also we only invert RotationDirection when it touch a wall:
CodeXMovement:
LDA !TouchedFloorFlag,x
BNE +
LDA !SpriteBlockedStatus_ASB0UDLR,x
AND #$04 ;0000 00LR
BEQ + ;If sprite is touching the floor
LDA #$01
STA !TouchedFloorFlag,x
JSR RotationTimeToSpeed
+
LDA !SpriteBlockedStatus_ASB0UDLR,x
AND #$03 ;0000 00LR
BEQ +
LDA !RotationDirection,x
EOR #$01
STA !RotationDirection,x
JSR RotationTimeToSpeed
+
RTS
Also we must change some things on the animation routine, the first is on the ChangeAnimationFromStart, we must do that Times now use only !RotationTime, for that we go to this zone:
CodeChangeAnimationFromStart:
STZ !AnimationFrameIndex,x
and we add this:
CodeChangeAnimationFromStart:
STZ !AnimationFrameIndex,x
LDA !RotationTime,x
STA !ScratchD
Now !ScratchD will be the rotation time, that scratch must be used to change the time, then we go to this line:
Code LDA Times,y
STA !AnimationTimer,x ;Time = Times[New Animation Frame Index]
And Replace it by:
Code LDA !ScratchD
STA !AnimationTimer,x ;Time = Times[New Animation Frame Index]
We must do almost the same on the animation routine, we go to this zone:
CodeAnimationRoutine:
LDA !AnimationTimer,x
BEQ +
RTS
+
STZ !ScratchF
LDA !SpriteXSpeed,x
AND #$80
STA !ScratchE
and we add change it by:
CodeAnimationRoutine:
LDA !AnimationTimer,x
BEQ +
RTS
+
LDA !RotationTime,x
STA !ScratchD
STZ !ScratchF
LDA !SpriteXSpeed,x
AND #$80
STA !ScratchE
Now we change the line of time:
Code LDA !ScratchD
STA !AnimationTimer,x ;Time = Times[New Animation Frame Index]
Also we must
delete Times Table.
And now the animation depends on Rotation Direction and not on Sprite X Speed then we must change this:
CodeAnimationRoutine:
LDA !AnimationTimer,x
BEQ +
RTS
+
LDA !RotationTime,x
STA !ScratchD
STZ !ScratchF
LDA !RotationDirection,x
STA !ScratchE ;!ScratchE = 0 if Speed is positive and not if it is negative
And now the sprite is finished and customizable by the user.
Result:
------------------------------------------------------
Youtube
Twitter
SMWControlLibX GitHub
My Discord Server
Snestorage where you can download my resources