Language…
11 users online: 35TCB77,  Anorakun, camila00,  cardboardcell, Cracka, Hidincuzimsmokin, JamesTall, JPhanto, lean4, pakkie, tOaO - Guests: 220 - Bots: 132
Users: 70,436 (2,478 active)
Latest user: infinitys_end

32x32 graphics for a sprite cluster. Help

Hi, how are you? I was wondering how I can make a sprite cluster have a 32x32 fragment size, and with a 4-frame animation.

Can you help me please?

Code
	!cluster_tile         = $0F72|!addr
	!cluster_props        = $0F86|!addr

Graphics:
	LDY #$00
	JSR FindOAM							; rather than loading a fixed OAM slot based on sprite index, let's just find a free one
	
	LDA $00								; \ load screen position so the sprite can be drawn in the right spot
	STA $0200|!addr,y					; |
	LDA $02								; |
	STA $0201|!addr,y					; /
	
	PHY									; \ draw tile
	LDY $15E9|!addr						; |
	LDA !cluster_tile,y					; |
	PLY									; |
	STA $0202|!addr,y					; /
	
	PHY									; \ set props
	LDY $15E9|!addr						; |
	LDA !cluster_props,y				; |
	PLY									; |
	STA $0203|!addr,y					; /
	
	TYA
	LSR #2
	TAY
	
	LDA #$02							; \ set the size to 16x16
	STA $0420|!addr,y					; /
	
	RTS
	
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									; /]


First 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:
Code
Tilemap:
	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.

Professional frame-by-frame time wizard. YouTube - Bluesky - SMW Glitch List - SMW Randomizer
Originally posted by Thomas
First 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:
Code
Tilemap:
	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.