Originally posted by ThomasFirst things first, I'm not really sure what the rest of your sprite's code looks like, but unless you have a second part of that graphics routine, you're going to have some issues since you're not using PIXI's
%ClusterGetDrawInfo()
macro to set up $00/$01. So start by adding a call to that.
Past that, it's just a matter of writing your GFX routine in a loop to write all four tiles. Here's an example of the kind of routine you'd want:
CodeTilemap:
db $00,$02,$20,$22 ; frame 0
db $00,$02,$20,$22 ; frame 1
db $00,$02,$20,$22 ; frame 2
db $00,$02,$20,$22 ; frame 3
TilemapProps:
db $3A,$3A,$3A,$3A
db $3A,$3A,$3A,$3A
db $3A,$3A,$3A,$3A
db $3A,$3A,$3A,$3A
TilemapX: ; x offsets for each tile in the frame
db $00,$10,$00,$10
TilemapY: ; y offsets for each tile in the frame
db $00,$00,$10,$10
Graphics:
%ClusterGetDrawInfo()
BCC .return ; despawned offscreen
LDY #$00
JSR FindOAM
PHX
LDA !0F72,x ; frame ID
ASL #2
CLC : ADC #$03
STA $03
LDA #$03
STA $04
.loop:
LDX $04
LDA $00
CLC : ADC TilemapX,x
STA $0200|!addr,y
LDA $01
CLC : ADC TilemapY,x
STA $0201|!addr,y
LDX $03
LDA Tilemap,x
STA $0202|!addr,y
LDA TilemapProps,x
STA $0203|!addr,y
PHY
TYA : LSR #2 : TAY
LDA $02 ; x position high bit
ORA #$02 ; 16x16
STA $0420,y
PLY
INY #4
DEC $03
DEC $04
BPL .loop
PLX
.return:
RTS
In this code, the table at $0F72 is used to manage the frame number of the animation (0-3). Control those values outside of the routine with whatever logic you need. If you want to support flipping the sprite horizontally, you'll need to add some logic for that as well.
Well, I used this cluster sprite from Tunder Lakitu.
Code!Speed = $02 ; How many pixels to move per frame.
!YInteractSmOrDu = $20 ; How many pixels to interact with small or ducking Mario, vertically.
!YInteractSmNorDu = $30 ; How many pixels to interact with powerup Mario (not ducking), vertically.
; Properties table, per sprite. YXPPCCCT.
Properties:
db $05,$05
; Sprite tiles, per sprite.
Tiles:
db $42,$44
; Speed table, per sprite. Amount of pixels to move down each frame. 00 = still, 80-FF = rise, 01-7F = sink.
SpeedTable1:
db $FD,$03
OAMStuff:
db $40,$44
print "MAIN ",pc
Main:
LDA $14
LSR #2
AND #$01
BEQ .animate
LDA #$00
BRA .store
.animate
LDA #$01
.store
STA $01
SkipIntro:
LDA $9D ; \ Don't move if sprites are frozen.
BNE Immobile ; /
LDA !cluster_x_low,y ; \
CLC : ADC SpeedTable1,y ; | Movement.
STA !cluster_x_low,y ; /
LDA $94 ; \ Sprite <-> Mario collision routine starts here.
SEC ; | X collision = #$18 pixels. (#$0C left, #$0C right.)
SBC !cluster_x_low,y ; |
CLC : ADC #$0C ; |
CMP #$18 ; |
BCS Immobile ; /
LDA #!YInteractSmOrDu ; Y collision routine starting here.
LDX $73
BNE StoreToNill
LDX $19
BEQ StoreToNill
LDA #!YInteractSmNorDu
StoreToNill:
STA $00
LDA $96
SEC : SBC !cluster_y_low,y
CLC : ADC #$20
CMP $00
BCS Immobile
JSL $00F5B7|!BankB ; Hurt Mario if sprite is interacting.
Immobile: ; Graphics routine starts here.
LDX.w OAMStuff,y ; Get OAM index.
LDA !cluster_y_low,y ; \ Copy Y position relative to screen Y to OAM Y.
SEC : SBC $1C ; |
STA $0201|!Base2,x ; /
LDA !cluster_x_low,y ; \ Copy X position relative to screen X to OAM X.
SEC : SBC $1A ; |
STA $0200|!Base2,x ; /
PHX
LDA Tiles,y
CLC : ADC $01
STA Tiles,y
PLX
LDA Tiles,y ; \ Tile
STA $0202|!Base2,x
LDA Properties,y ; \ Properties per bolt.
STA $0203|!Base2,x ; /
PHX
TXA
LSR #2
TAX
LDA #$02
STA $0420|!Base2,x
PLX
LDA $0200|!Base2,x
CMP #$F0
BCC .return
LDA #$00
STA !cluster_num,y
.return
RTL
But when I put in your code, it fails.
Code!Speed = $02 ; How many pixels to move per frame.
!YInteractSmOrDu = $20 ; How many pixels to interact with small or ducking Mario, vertically.
!YInteractSmNorDu = $30 ; How many pixels to interact with powerup Mario (not ducking), vertically.
Tilemap:
db $00,$02,$20,$22 ; frame 0
db $30,$32,$40,$42 ; frame 1
db $60,$62,$70,$72 ; frame 2
db $80,$82,$90,$92 ; frame 3
TilemapProps:
db $00,$10,$20,$30
db $00,$10,$20,$30
db $00,$10,$20,$30
db $00,$10,$20,$30
TilemapX: ; x offsets for each tile in the frame
db $00,$10,$00,$10
TilemapY: ; y offsets for each tile in the frame
db $00,$00,$10,$10
SpeedTable1:
db $FD,$03
print "MAIN ",pc
Main:
LDA $14
LSR #2
AND #$01
BEQ .animate
LDA #$00
BRA .store
.animate
LDA #$01
.store
STA $01
SkipIntro:
LDA $9D ; \ Don't move if sprites are frozen.
BNE Immobile ; /
LDA !cluster_x_low,y ; \
CLC : ADC SpeedTable1,y ; | Movement.
STA !cluster_x_low,y ; /
LDA $94 ; \ Sprite <-> Mario collision routine starts here.
SEC ; | X collision = #$18 pixels. (#$0C left, #$0C right.)
SBC !cluster_x_low,y ; |
CLC : ADC #$0C ; |
CMP #$18 ; |
BCS Immobile ; /
LDA #!YInteractSmOrDu ; Y collision routine starting here.
LDX $73
BNE StoreToNill
LDX $19
BEQ StoreToNill
LDA #!YInteractSmNorDu
StoreToNill:
STA $00
LDA $96
SEC : SBC !cluster_y_low,y
CLC : ADC #$20
CMP $00
BCS Immobile
JSL $00F5B7|!BankB ; Hurt Mario if sprite is interacting.
RTS
Immobile: ; Graphics routine starts here.
%ClusterGetDrawInfo()
BCC .return ; despawned offscreen
LDY #$00
JSR FindOAM
PHX
LDA $0F72|!addr;,x ; frame ID
ASL #2
CLC : ADC #$03
STA $03
LDA #$03
STA $04
.loop:
LDX $04
LDA $00
CLC : ADC TilemapX,x
STA $0200|!addr,y
LDA $01
CLC : ADC TilemapY,x
STA $0201|!addr,y
LDX $03
LDA Tilemap,x
STA $0202|!addr,y
LDA TilemapProps,x
STA $0203|!addr,y
PHY
TYA : LSR #2 : TAY
LDA $02 ; x position high bit
ORA #$02 ; 16x16
STA $0420,y
PLY
INY #4
DEC $03
DEC $04
BPL .loop
PLX
.return:
RTL
FindOAM:
LDA $0201|!addr,y ; \ load in OAM Y position
CMP #$F0 ; | if it's offscreen (empty)
BEQ + ; | then we can use this as our index
INY #4 ; |
BNE FindOAM ; | if we didn't loop from the entire $0200-$02FF area of OAM, then we can keep searching for empty slots
LDY $15E9|!addr ; | restore cluster sprite index
LDA #$00 ; | since there's no available OAM slot (for some reason),
STA !cluster_num,y ; | kill the sprite
LDY #$00 ; | and just use an index of 0 and hope nothing breaks
+ ; |
RTS ; /
Just like in the image, he clones Mario and when he touches him it fails.
