How to delete / unload sprite? (nes 6502)

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
Pawel
Posts: 5
Joined: Tue Jan 18, 2022 7:38 pm

How to delete / unload sprite? (nes 6502)

Post by Pawel »

Hi,

I need help with very simple matter. I want to destroy bullet on collision. I have collision detection but I can't find any tutorial / code example on how to delete / remove / unload a sprite.

I suspect that what i need to do is clear the memory location containing number of tile from the pattern table or prevent sprite from being drawn on the screen.
User avatar
Memblers
Site Admin
Posts: 4044
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: How to delete / unload sprite? (nes 6502)

Post by Memblers »

The recommended way is to set the Y coordinates to $F0 or above, where the PPU will never reach them.
Drag
Posts: 1615
Joined: Mon Sep 27, 2004 2:57 pm
Contact:

Re: How to delete / unload sprite? (nes 6502)

Post by Drag »

Yep, setting the Y position anywhere between $F0-$FF is all you need to do; you can actually leave X position, tile number, and attribute alone if you want. :P
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: How to delete / unload sprite? (nes 6502)

Post by tokumaru »

Do note that most games do not bother with deleting specific sprites though, since they don't statically allocate OAM slots to specific objects.

In the vast majority of games, OAM slots start "empty" (Y > 239) every frame, and the function that draws meta-sprites uses OAM slots as needed, often in pseudo-random order, so that sprite priorities are cycled over time (creating sprite cycling instead of dropout).

Since the sprite list is rebuilt from scratch every frame, there's no need to "erase" specific objects, you just don't draw them at all.
Pawel
Posts: 5
Joined: Tue Jan 18, 2022 7:38 pm

Re: How to delete / unload sprite? (nes 6502)

Post by Pawel »

Thank you for your answers!
Copy_con^Z
Posts: 10
Joined: Tue May 04, 2021 8:49 pm

Re: How to delete / unload sprite? (nes 6502)

Post by Copy_con^Z »

tokumaru wrote: Wed Jan 19, 2022 1:54 pm In the vast majority of games, OAM slots start "empty" (Y > 239) every frame, and the function that draws meta-sprites uses OAM slots as needed, often in pseudo-random order, so that sprite priorities are cycled over time (creating sprite cycling instead of dropout).
Basic but nevertheless critical information for me! By doing this and handle all object logic outside the OAM-buffer I managed to solve a lot of the obstacles I ran into.

But I don’t know if my solution is the most optimal one. I have a loop in NMI that looks like this:


LDA FF
LDX 00
ClearOAM:
STA $200, X
INX
INX
INX
INX
BNE clearOAM

But that’s 960+ cycles every frame. Is that the way to go?
Fiskbit
Posts: 891
Joined: Sat Nov 18, 2017 9:15 pm

Re: How to delete / unload sprite? (nes 6502)

Post by Fiskbit »

That's 1027 cycles in total, which is indeed expensive. A common solution is to only hide the sprites you don't use, though that may be difficult depending on your sprite shuffling algorithm. The nice thing about this is that the cost of the function goes down as the number of sprites used goes up (so it's cheaper when your other CPU costs are higher).

Another option is to unroll the loop. For example, you could do something like this:

Code: Select all

  LDA #$FF
  LDX #$3C
loop:
  STA $0203,X
  STA $0243,X
  STA $0283,X
  STA $02C3,X
  DEX
  DEX
  DEX
  DEX
  BPL loop
That's only 499 cycles, a substantial improvement.

If you're willing to use an illegal instruction, the AXS #immediate instruction (opcode $CB: (A & X) - immediate) seems to be a reliable one and can cut down on this further:

Code: Select all

  LDA #$FF
  LDX #$3C
loop:
  STA $0200,X
  STA $0240,X
  STA $0280,X
  STA $02C0,X
  AXS #$04
  BPL loop
That's only 403 cycles.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: How to delete / unload sprite? (nes 6502)

Post by tokumaru »

Fiskbit wrote: Thu Apr 28, 2022 6:36 amA common solution is to only hide the sprites you don't use
That's what I always do. After all the game logic has been processed and all objects have generated their OAM entries, a simple loop puts any remaining sprites off screen. The exact implementation of this loop will vary depending on how you select free OAM slots for use (some games fill the OAM sequentially, others advance a prime number of slots after each sprite, etc.), but you can just use the same logic to keep selecting slots and hiding the sprites until there are no more free sprites.
Copy_con^Z
Posts: 10
Joined: Tue May 04, 2021 8:49 pm

Re: How to delete / unload sprite? (nes 6502)

Post by Copy_con^Z »

Thanks both of you! I will meditate on your replies. :D

I’ve learnt that figuring out things the hard way often pays off in the long run, but sometimes you run into a wall.
tokumaru wrote: Thu Apr 28, 2022 9:01 am
Fiskbit wrote: Thu Apr 28, 2022 6:36 amA common solution is to only hide the sprites you don't use
That's what I always do. After all the game logic has been processed and all objects have generated their OAM entries, a simple loop puts any remaining sprites off screen. The exact implementation of this loop will vary depending on how you select free OAM slots for use (some games fill the OAM sequentially, others advance a prime number of slots after each sprite, etc.), but you can just use the same logic to keep selecting slots and hiding the sprites until there are no more free sprites.
Drag
Posts: 1615
Joined: Mon Sep 27, 2004 2:57 pm
Contact:

Re: How to delete / unload sprite? (nes 6502)

Post by Drag »

tokumaru wrote: Thu Apr 28, 2022 9:01 am you can just use the same logic to keep selecting slots and hiding the sprites until there are no more free sprites.
Oh dang, I never thought of that! I wouldn't have expected this to make a huge difference, but it's still good to know.
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: How to delete / unload sprite? (nes 6502)

Post by DRW »

Copy_con^Z wrote: Thu Apr 28, 2022 5:46 am LDA FF
LDX 00
ClearOAM:
STA $200, X
INX
INX
INX
INX
BNE clearOAM

But that’s 960+ cycles every frame. Is that the way to go?

I found this too slow as well. That's why I used the other extreme:

Code: Select all

.repeat 64, spriteId
    STA Sprites + spriteId * 4
.endrepeat
It requires more ROM space, but it's the fastest method.
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
Drag
Posts: 1615
Joined: Mon Sep 27, 2004 2:57 pm
Contact:

Re: How to delete / unload sprite? (nes 6502)

Post by Drag »

I go half-and-half and use a partially unrolled loop (verbatim from my own code):

Code: Select all

; Clear all sprites (set y positions to FF) [Affects Y]
sprmanager_clear
 ldy #$00				;The ADC is the only thing that can modify C, so clear it out here
 clc					;(saves 2 cycles per loop, 16-2=14 (clc still happens once) in this case)
sprmanager_clear_loop
 lda #$ff				;It's quicker to just set all of the Y positions to FF
 sta spr_oam,y			;instead of actually clearing out the contents entirely.
 sta spr_oam+$4,y		;Partially unrolled loop for an additional speed boost
 sta spr_oam+$8,y
 sta spr_oam+$C,y
 sta spr_oam+$10,y
 sta spr_oam+$14,y
 sta spr_oam+$18,y
 sta spr_oam+$1C,y
 tya
 adc #$20
 tay
 bcc sprmanager_clear_loop
 lda spr_config			;This part is for OAM shuffling
 adc #$33				;If we get here, the carry bit MUST be set, so let's take advantage of it
 sta spr_config			;by leaving out the CLC again (woo hoo, another 2 cycles saved)
 sta spr_index
 rts
Post Reply