corrupted sprites

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
instantaphex
Posts: 30
Joined: Sat Sep 27, 2014 10:10 pm
Location: Houston, TX

corrupted sprites

Post by instantaphex »

I'm trying to create a generic 2x2 meta sprite rendering system and I'm having an issue with it where if I store the hardware sprites anywhere but the beginning of my oam buffer I get a bunch of garbage sprites all over the screen. I'm using a data format like this:

Code: Select all

player_frame_1:
        ; byte 0 - meta sprite y offset, byte 1 - tile, byte 3 - attributes, byte 4 - meta sprite x offset
	.byte $00,$32,%00000000,$00
	.byte $00,$33,%00000000,$08
	.byte $08,$34,%00000000,$00
	.byte $08,$35,%00000000,$08
I've got some constants that I'm using to select between 16 byte sections of my oam buffer

Code: Select all

sprite_id_constants:
  .byte $00, $10, $20, $30, $40, $50, $60, $70
And here is my meta sprite drawing routine:

Code: Select all

LEFT = 1
RIGHT = 0

.proc draw_metasprite
    ; set up oam offset based on sprite id
    ldx sprite_id 
    ldy sprite_id_constants, x
	:
		; deal with byte 0 - y pos
		lda (sprite_addr), y
		clc
		adc sprite_y 
		sta oam, y

		; deal with byte 1 - tile
		iny
		lda (sprite_addr), y
		sta oam, y

		; deal with byte 2 - attributes
		iny
		lda sprite_direction
		cmp #LEFT
		beq set_flipped_horizontal
		lda #%00000000
		sta oam, y
		jmp done_flipping_sprite
set_flipped_horizontal:
		lda #%01000000
		sta oam, y
done_flipping_sprite:
		; deal with byte 3 - x pos
		iny
		; if player is facing left subtract offset if not, add it
		lda sprite_direction
		cmp #LEFT
		bne add_offset
subtract_offset:
		; put offset into tmp
		lda sprite_x ; (player_curr_sprite), y
		sec
		sbc (sprite_addr), y
		sta oam, y
		jmp :+
add_offset:
		lda (sprite_addr), y
		clc
		adc sprite_x 
		sta oam, y
        :
		; increase y by for to start at the next row	
		iny
		cpy #$10 ; loop four times, once per row
	bne :--
	rts
.endproc
and I'm calling my meta sprite drawing routine like this:

Code: Select all

.proc draw_player
	; this macro just sets a pointer to point to
        ; whichever animation frame I'd like to draw
	load_pointer sprite_addr, player_map

        ; set up x and y values
	lda player_x
	sta sprite_x
	lda player_y
	sta sprite_y

        ; flag that indicates whether or not to flip horizontal
	lda player_direction
	sta sprite_direction
        
        ; sprite_id tells the meta sprite drawing routine  which section of the oam buffer to 
        ; copy the meta sprite to
	lda #$01
	sta sprite_id

        ; build the buffer
	jsr draw_metasprite
	rts
.endproc
This works fine if in my meta sprite calling code I set my sprite_id to #$00, but if I set it to any of the other available ids I get a bunch of garbage all over the screen that moves with my sprite and gets horizontally flipped along with my sprite. Is there a reason I can't have gaps in my oam buffer or is there something really wrong with my code?
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Re: corrupted sprites

Post by Kasumi »

Because you're using y for both an offset in your OAM and an offset in your data.

Let's assume Y is 0.

Code: Select all

      lda (sprite_addr), y
      clc
      adc sprite_y
      sta oam, y
You load byte 0 of your sprite data, you store it to byte 0 of OAM. Awesome!
Let's assume Y is 64.

Code: Select all

      lda (sprite_addr), y
      clc
      adc sprite_y
      sta oam, y
You load entirely past your intended data because (sprite_addr), y is loading player_frame_1+64.
But it is stored in the right place in OAM.
The simple fix? Use both X and Y.

Code: Select all

    ldy sprite_id
    lda sprite_id_constants, y
    tax
   :
      ; deal with byte 0 - y pos
      ldy #0;Start at the beginning of the data in the pointer
      lda (sprite_addr), y
      clc
      adc sprite_y
      sta oam, x

      ; deal with byte 1 - tile
      iny
      inx
      lda (sprite_addr), y
      sta oam, x
;etc
;You now need iny and inx
;you lda (sprite_addr), y
;and you sta oam, x
;in the other places in the code
I... also have to mention this:
; byte 0 - meta sprite y offset, byte 1 - tile, byte 3 - attributes, byte 4 - meta sprite x offset
0, 1, 3, 4. Please change that to either 0, 1, 2, 3 or 1, 2, 3, 4

Edit: An explanation without code: You always want to copy FROM the same bytes (relative to the pointer), but you want to change where you're copying TO (relative to OAM). If you use Y for both, you can't change where you copy TO without also changing where you copy FROM. That's why X is needed.
Last edited by Kasumi on Thu Feb 08, 2018 10:06 pm, edited 1 time in total.
User avatar
instantaphex
Posts: 30
Joined: Sat Sep 27, 2014 10:10 pm
Location: Houston, TX

Re: corrupted sprites

Post by instantaphex »

Edit: I noticed I had an extra inx at the end. Now that I've removed that I've only got 1/4 of my meta sprite. I'm looking into this now

Edit2: as for your second comment... :oops: yeah I wrote that comment quickly for the post. I didn't have a comment there in my code, but I see what you're saying

That makes sense. I tried altering my meta sprite drawing code and I've got a similar problem but now it seems to be messing with the tile and palette and moving diagonally. Here is the updated code:

Code: Select all

LEFT = 1
RIGHT = 0

.proc draw_metasprite
    ; set up oam offset based on sprite id
    ldy sprite_id ; sprite id 0
    lda sprite_id_constants, y ; low byte for oam offset
    tax
	:
        ldy #$00
		; deal with byte 0 - y pos
		lda (sprite_addr), y
		clc
		adc sprite_y 
		sta oam, x

		; deal with byte 1 - tile
		iny
        inx
		lda (sprite_addr), y
		sta oam, x

		; deal with byte 2 - attributes
		iny
        inx
		lda sprite_direction
		cmp #LEFT
		beq set_flipped_horizontal
		; if we don't need to flip, just set whats defaulted
		lda #%00000000 ; (player_curr_sprite), y
		sta oam, x
		jmp done_flipping_sprite
set_flipped_horizontal:
		lda #%01000000
		sta oam, x
done_flipping_sprite:

		; deal with byte 3 - x pos
		iny
        inx
		; if player is facing left subtract offset if not, add it
		lda sprite_direction
		cmp #LEFT
		bne add_offset
subtract_offset:
		; put offset into tmp
		lda sprite_x ; (player_curr_sprite), y
		sec
		sbc (sprite_addr), y
		sta oam, x
		jmp :+
add_offset:
		lda (sprite_addr), y
		clc
		adc sprite_x 
		sta oam, x
        :
		; increase y by for to start at the next row	
		iny
        inx
        ; increase x for oam
        inx
		cpy #$10 ; loop four times, once per row
	bne :--
	rts
.endproc
User avatar
Kasumi
Posts: 1293
Joined: Wed Apr 02, 2008 2:09 pm

Re: corrupted sprites

Post by Kasumi »

Yeah, the double inx was one thing.

Another thing I see is totally my fault. This:

Code: Select all

cpy #$10 ; loop four times, once per row
   bne :--
   rts
branches to here:

Code: Select all

:
        ldy #$00
So your loop keeps reloading Y with 0 and it never stops branching. That's my bad, I don't use nameless labels. They look like comments. So:

Code: Select all

        ldy #$00
:
Would probably do it.
User avatar
instantaphex
Posts: 30
Joined: Sat Sep 27, 2014 10:10 pm
Location: Houston, TX

Re: corrupted sprites

Post by instantaphex »

Kasumi wrote:

Code: Select all

        ldy #$00
:
Would probably do it.
Sweet thanks a lot man. That did it. I'm now reconsidering my use of anonymous labels. They're kind of confusing me too when I read my own code.
Post Reply