Page 1 of 2
Too many spirtes - overcoming sprite scanline limitations
Posted: Tue Jan 30, 2007 4:19 pm
by Cypherr
Hello all. Before I start, let me say that I have played around with nes development a bit, but it has been a little while since I have done anything so excuse me if my terminology is slightly off or if my questions end up having trivial answers.
I am currently working on a BurgerTime-esque game, just as a project to be working on and something to give me a chance to get familiar with making a larger project for the NES. The problem I have currently run into has to do with the number of sprites allowed using sprite DMA, as well as the number of sprites allowed on a scanline.
Not even including the player sprite(s) and enemy sprite(s), there is a potential for at least 16 sprite tiles - the burger parts - to be on the same scanline. Since there are only allowed 8 tiles (64 pixels) of sprites to be on a particular line at a given time, I attempted to use vblanks to alternate between sets of sprite DMA - for example 5 for the player/enemies and 6 for the burger parts - displaying the required number of tiles. This "works" however it is not a real option as the sprites flicker.
Is there an easy or practical way to put more than 8 sprite tiles on a particular line without this flickering? or should the burger parts be part of the background?
If they should be part of the background, I do not see an easy way to dynamically change the background. For example, how would a burger part be moved down once the player has performed the necessary action if it is part of the background?
I can post small parts of my code if needed, such as how I am attempting to display the larger number of sprites.
Any help, suggestions, or pointing me in the right direction are appreciated. And sorry again if this is a newbish question.
Re: Too many spirtes - overcoming sprite scanline limitation
Posted: Tue Jan 30, 2007 5:49 pm
by tepples
Cypherr wrote:Is there an easy or practical way to put more than 8 sprite tiles on a particular line without this flickering?
Yes. Just abandon the NES in favor of, say, the Game Boy Advance

The GBA allows more sprites, larger sprites, and up to 950 sprite pixels per line. This allows you to do Pengo-style maps, where everything is a sprite, including the walls of the playfield. But seriously:
Cypherr wrote:or should the burger parts be part of the background?
Yes. It's the same situation as all falling block games for NES/Famicom (such as BPS
Tetris, Tengen
Tetяis, Nintendo
Tetris, Pin Eight
Tetramino, Tengen
Klax, Nintendo
Dr. Mario, Compile
Puyo Puyo, Nintendo
Wario's Woods): the blocks in the playfield are drawn as tiles in the background. If you have Nintendulator (or VisualBoyAdvance+PocketNES) and the
Burger Time ROM, you might want to bring up the nametable viewer to see how it does things.
Cypherr wrote:If they should be part of the background, I do not see an easy way to dynamically change the background. For example, how would a burger part be moved down once the player has performed the necessary action if it is part of the background?
Wait for vblank, then turn off rendering (lda #0 sta PPUMASK). Erase the top row of the burger part by drawing empty cells to VRAM, and then draw the burger part one cell lower. Set the scroll, and turn on rendering. Repeat these until the burger part has fallen enough rows that it has landed on the part below.
Posted: Tue Jan 30, 2007 5:52 pm
by blargg
There is no way to have more than 8 sprites on a line, so the burger parts will probably have to be part of the background. To move them in the background, have different sets of tiles for each vertical position they can be in, with respect to the tile size. As I remember the game, the food items can either be sitting on a platform, partially "flattened", or falling. You could handle the first two states using two sets of tiles (for each type), and sprites when one is falling to a lower platform.
BTW, if you think you do have a newbie question, post to the newbie forum (though some retard(s) will still sometimes complain).
Posted: Tue Jan 30, 2007 10:07 pm
by Cypherr
Thank you for the replies. I assumed I would have to put the burger parts into the background but I just wanted to make sure.
Just need a little clarification on dealing with the background.
Is there a way to update only a single tile in the background, without having to reload the whole background into $2007? If so can someone please explain it, in a decent amount of detail as I am not as knowledgeable about some of this stuff as I would like to be.
Sorry for not posting this in the newbie section, I actually thought I was in there so any admin can feel free to move this thread.
Thanks again for any additional help.
Posted: Tue Jan 30, 2007 10:49 pm
by tepples
Cypherr wrote:Is there a way to update only a single tile in the background, without having to reload the whole background into $2007?
Yes. You seek to one part of the map in VRAM using PPUADDR ($2006), and then you rewrite tiles using PPUDATA ($2007). For example,
Super Mario Bros. does this every time you bash a

.
If so can someone please explain it, in a decent amount of detail as I am not as knowledgeable about some of this stuff as I would like to be.
Code: Select all
; Seek to VRAM $2136, or x=22 y=9
lda #$21
sta PPUADDR
lda #$36
sta PPUADDR
; Rewrite a row of tiles
ldx #BURGER_TOP_LEFT_TILE
stx PPUDATA
ldx #BURGER_TOP_LEFT_CENTER_TILE
stx PPUDATA
ldx #BURGER_TOP_RIGHT_CENTER_TILE
stx PPUDATA
ldx #BURGER_TOP_RIGHT_TILE
stx PPUDATA
Sorry for not posting this in the newbie section, I actually thought I was in there so any admin can feel free to move this thread.
Done.
Posted: Tue Jan 30, 2007 10:56 pm
by tokumaru
Cypherr wrote:Is there a way to update only a single tile in the background, without having to reload the whole background into $2007?
Of course there is!
If so can someone please explain it, in a decent amount of detail as I am not as knowledgeable about some of this stuff as I would like to be.
I'm guessing that you are writing the full background at one and that's itm right? If so, you're probably setting $2006 to point to the start of the name table, and then dumping all the tiles through $2007.
To update just a few tiles all you have to do is have $2006 point to the tile you want to change, and then write the new tile values to $2007.
There is a simple formula to convert X and Y tile coordinates into the exact address of the tile: BASE + Y * 32 + X
BASE is the base address of the name table, so if it is the first one this is $2000. X should be in the range 0 to 31 and Y should be between 0 and 29.
So, after having $2006 point to the first tile you want to change, you can start writing the tile values to $2007. Since burger parts seem to be wider than taller, it would be smart to set the PPU increment value to 1 (instead of 32), to draw the new tiles in rows. You have to set the address again for each row of tiles you need to update.
If your burger parts use different palettes, you'll also have to mess with the attribute tables. This is a bit harder. You can also use a formula to find the address of interest, but since a byte is used to define the attributes of many tiles, you'd have to also calculate some sort of mask to clear only the bits you want to change, change the bits and write the value back.
Of course, depending on what you have in mind it can be simpler. I never really played this game, and probably some of it's characteristics can be taken into account for making the background updates easier. If all burger parts used the same palette that sure would make things easier, but also uglier.
Posted: Tue Jan 30, 2007 11:17 pm
by Cypherr
thanks again for the replies.
i had previously tried to write to $2006 the position that i wanted to start updating backgrounds tiles to as i thought this should work, and according to you both it should.
however, when i try to have $2006 point to a a tile other than the first one for example doing as tepples showed in his example
Code: Select all
lda #$21
sta $2006
lda #$26
sta $2006
the background jumps to another position. if i set $2006 to #$2040 for example, the whole background moves up vertically.
Obviously i am doing something wrong, but i am not quite sure what would cause this. As a worse case, I suppose I could post my code, or parts at least, but I don't want to trouble anyone with trying to read through all of that code.
Is there anyone obvious that i could be doing - or not doing - that would cause this behavior?
Thanks again.
Posted: Wed Jan 31, 2007 5:39 am
by loopy
Posted: Wed Jan 31, 2007 6:24 am
by tokumaru
Be sure to mess with $2006 and $2007 only during vblank. So do it as the very first thing in your NMI routine. And after you're done with them, be sure to set the scroll correctly by writing the proper values to $2000 and $2005 before vblank ends. Do anything differently than that and you get the effect you described.
Posted: Wed Jan 31, 2007 7:20 am
by Cypherr
Ahhh, I seem to have it working now. Thanks to everyone who offered help.
I was not writing to $2005 and that was causing the shift in the background.
I
should be good to go now, at least until the next stumbling block

Posted: Wed Jan 31, 2007 10:29 am
by WedNESday
Can you imagine if we could have just ten sprites per scanline? Why were Nintendo so tight when it came to temporary sprite memory, what would an extra 8 bytes (32 + 8 = 40) have cost when it would have prevented so much flickering and we could have expanded the graphics a little. If it were down to cost, then why not allocate less CPU RAM, and give it to the temporary sprite memory. I mean, sixteen sprites per scanline would just be fantastic, I suppose that's where emulators really do shine, as we can support as many sprites as we like!
Posted: Wed Jan 31, 2007 10:36 am
by kyuusaku
Because CPU WRAM isn't on the PPU die like OAM.
Posted: Wed Jan 31, 2007 11:08 am
by Bregalad
I suppose that's where emulators really do shine, as we can support as many sprites as we like!
No, because you cannot have more than 64 sprites overall regardless where they are on screen, and some games still suffer from this (but far less than the 8 sprites per scaline limit).
Can you imagine if we could have just ten sprites per scanline?
That's just what the Gameboy and Gameboy Color have.
Posted: Wed Jan 31, 2007 12:49 pm
by WedNESday
kyuusaku wrote:Because CPU WRAM isn't on the PPU die like OAM.
I aint stupid. That aint what I meant. Never mind, bless.
Bregalad wrote:I suppose that's where emulators really do shine, as we can support as many sprites as we like!
No, because you cannot have more than 64 sprites overall regardless where they are on screen, and some games still suffer from this (but far less than the 8 sprites per scaline limit).
Again! That is not what I meant, what I mean is if we were to put 64 sprites on a scanline we could render each one (obviously this would means just 4 pixels per sprite, MAX). And I also know that the programmer limits the amount of sprites that it puts on a scanline anyway.
Posted: Wed Jan 31, 2007 1:25 pm
by tokumaru
Doesn't this limit have to do with time rather than bytes? Isn't it like this because the PPU is not fast enough to fetch more than 8 rows of patterns? Maybe I'm stupid, but this just went through my mind.