Page 1 of 2

My NES Question

Posted: Sat Jul 15, 2006 4:17 am
by nineTENdo
Wassup everyone,
I figured id do this to save threads. Anyways I have a questions about sprites. I copied and pasted 8 of the same sprites in YY_CHR but when i run them in a demo every other sprite is rotated 180 degrees, has a different color, and goes behind the backround in the nametable. What is up here. Also to have a sprite change colors back and fourth would i use sprite attributes.

Thanks
EL

Posted: Sat Jul 15, 2006 7:44 am
by Disch
You must not be setting the sprite attributes properly.

Each sprite has 4 bytes in SPR-RAM which tells how to display the sprite:

0) Y coord
1) Tile number to use
2) Attributes
3) X coord

The Attributes byte is reponsible for putting sprites 'underneath' the background, assigning palettes to the sprite, and flipping the sprite horizontally and vertically.

For reference:

http://nesdevwiki.ath.cx/index.php/NES_PPU#OAM

Posted: Sat Jul 15, 2006 8:07 am
by tepples
One popular emulator fills the CPU's RAM with $00 $00 $00 $00 $FF $FF $FF $FF, which would cause the attribute alternation you describe. Fill your shadow-OAM page with $00 at reset for the behavior that you expect.

Posted: Sat Jul 15, 2006 8:58 am
by nineTENdo
tepples wrote: Fill your shadow-OAM page with $00 at reset for the behavior that you expect.
#$00 in 4014 you mean right.

Posted: Sat Jul 15, 2006 9:02 am
by tepples
No, I meant #$00 in $0200-$02FF (your shadow OAM page) and #$02 (the address of your shadow OAM page) in $4014.

This will produce an artifact in the top left corner. Once you understand how to display things as you want them, I'll show you how to lose the artifact.

Posted: Sat Jul 15, 2006 9:16 am
by nineTENdo
Also how does the Bank ($0000 or $1000) work. Ive seen it for BG and Sprite stuff and i was just curious.

Posted: Sat Jul 15, 2006 9:40 am
by nineTENdo
What is the shadow OAM page mainly used for? What else can it be used for?

Posted: Sat Jul 15, 2006 9:53 am
by Disch
Sounds like you need a breakdown:

Sprite RAM (aka "OAM") is what the PPU uses to display your sprites. In OAM, there is 256 bytes, which is enough room for 64 sprites (with each sprite having 4 bytes of information). Sprite RAM is not anywhere in CPU addressing space (that is, you cannot really access it directly). However it is possible to perform a "DMA" which will copy 256-byte chunk from CPU RAM (which IS directly accessable) to OAM.

This 256-byte chunk in CPU RAM is the "shadow OAM page" tepples was talking about. Most games put this page in $0200-02FF in CPU RAM, others put it at $0700-$07FF.

The "DMA" which copies that shadow OAM into the real OAM is done on a $4014 write. The value you write to $4014 determines which 256-byte block gets copied to OAM.

If you write $00 to $4014, $0000-00FF gets copied to OAM
If you write $01 to $4014, $0100-01FF gets copied
$02 ... $0200-02FF
$03 ... $0300-03FF
etc


Your problem may be caused by you copying an entire 256 byte block (by writing to $4014) without having set every byte in that block. Therefore several bytes are filled with random garbage, which causes unwanted sprites to be displayed with the weird properties you're describing.


If you want to avoid this... you should make sure you have every byte in that block set to what you want before you DMA it to OAM.

Posted: Sat Jul 15, 2006 10:02 am
by nineTENdo
Disch wrote: If you want to avoid this... you should make sure you have every byte in that block set to what you want before you DMA it to OAM.
Every byte!!! What if i clear #$2 store lets say on 4 sprite in #$7 would that clear all the crap i dont need. Is that how Shadow RAM works.

Posted: Sat Jul 15, 2006 10:31 am
by Disch
I don't understand your question at all.

All the 'shadow RAM' is, is just an easily accessable version of what you want to be copied to OAM. Whatever is in your Shadow OAM page WILL be displayed as sprite graphics data the next time you perform the DMA (by writing to $4014).

For example... say you only want two sprites on the screen, so you change $0200-$0207 to the desired sprite information (which will set sprites 0 and 1 the way you want them). But let's say you leave $0208-$02FF unchanged (and let's say it's filled with random garbage). When you write a value of $02 to $4014, the entire $0200-$02FF page gets copied to OAM -- including $0208-02FF, which you didn't set. Therefore, since those bytes were random garbage, you're getting random garbage sprites on screen. If you don't want this to happen you must configure every sprite so that they will either be displayed as you want them, or make it so they won't be displayed at all (by moving them offscreen by setting their Y value to $FF)

Posted: Sat Jul 15, 2006 1:38 pm
by Bregalad
1 - Always fill the whole SPRRAM with $f0 or any value between $f0 and $ff when not using it
2 - Upload correct values for the sprite attibute byte ($202,X) as well as you do for vertical position, tile number and horizontal position (respectivly $200,X , $201,X , $203,X) assuming you use page $2 for your sprite DMA. Just replace $2 per another number if you use another page.

Posted: Sat Jul 15, 2006 10:31 pm
by nineTENdo
Disch wrote:If you don't want this to happen you must configure every sprite so that they will either be displayed as you want them, or make it so they won't be displayed at all (by moving them offscreen by setting their Y value to $FF)
Ok i get it now. No wonder ive seen some demos where there is #$FF stored in some of the unused OAM locations. How would i clear or lets say fill i.e. $0208-$02FF with #$FF. Would i use some addressing technique?

Posted: Sun Jul 16, 2006 12:30 am
by Bregalad
Here you are the code I wrote to handle that :

Code: Select all

ClrSprRam		;Clears the Sprite buffer at $200
	ldx #$00

;This does just clears the unused sprites in $200-$2ff
ClearRemainingSprites
	lda #$f0
-	sta $200,X
	inx
	bne -
_endClrSprRam
	inc SpriteDMAFlag
	rts
ClrSprRam will fill the OAM with all blank sprites. ClearRemainingSprites will just continue to clear the sprites that are unused, assuming that X holds the adress of the first unused sprite in the sprite buffer.
At the end the SpriteDMAFlag is set to tell the NMI routine that the sprite buffer is ready to be copied to OAM via $4014

Posted: Sun Jul 16, 2006 7:47 am
by tepples
Or for better speed, unroll the loop and clear only the bytes specifying the Y coordinate:

Code: Select all

ClrSprRam		;Clears the Sprite buffer at $200
	ldx #$00

;This does just clears the unused sprites in $200-$2ff
ClearRemainingSprites
	lda #$f0
-	sta $200,X
	inx
	inx
	inx
	inx
	bne -
_endClrSprRam
	inc SpriteDMAFlag
	rts

Posted: Sun Jul 16, 2006 3:38 pm
by tokumaru
If you are doing this frequently (i.e. every frame) it's certainly better to go for speed.

I guess I'd do it like this: I'd go through the list of active objects, rendering each one to the OAM (shadow), and when all objects are done, I'd fill the rest (Y position only) with $f0.

Before the game starts it doesn't matter if it's quick or slow.