nesdev.com
http://forums.nesdev.com/

corrupted sprites
http://forums.nesdev.com/viewtopic.php?f=10&t=17041
Page 1 of 1

Author:  instantaphex [ Thu Feb 08, 2018 9:32 pm ]
Post subject:  corrupted sprites

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:
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:
sprite_id_constants:
  .byte $00, $10, $20, $30, $40, $50, $60, $70


And here is my meta sprite drawing routine:

Code:
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:
.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?

Author:  Kasumi [ Thu Feb 08, 2018 9:45 pm ]
Post subject:  Re: corrupted sprites

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:
      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:
      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:
    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:
Quote:
; 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.

Author:  instantaphex [ Thu Feb 08, 2018 10:05 pm ]
Post subject:  Re: corrupted sprites

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:
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

Author:  Kasumi [ Thu Feb 08, 2018 10:24 pm ]
Post subject:  Re: corrupted sprites

Yeah, the double inx was one thing.

Another thing I see is totally my fault. This:
Code:
cpy #$10 ; loop four times, once per row
   bne :--
   rts

branches to here:
Code:
:
        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:
        ldy #$00
:

Would probably do it.

Author:  instantaphex [ Thu Feb 08, 2018 10:29 pm ]
Post subject:  Re: corrupted sprites

Kasumi wrote:
Code:
        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.

Page 1 of 1 All times are UTC - 7 hours
Powered by phpBB® Forum Software © phpBB Group
http://www.phpbb.com/