Page 1 of 2
Displaying Multiple Sprites
Posted: Tue Jun 27, 2006 5:32 pm
by Cypherr
I am having some problems having more than one sprite display at the same time. I have no problem displaying the first one, but as soon as I attempt to display more than one, none of the sprites are displayed.
Code: Select all
.inesprg 1
.ineschr 1
.inesmir 1
.inesmap 0
.bank 1
.org $FFFA
.dw 0
.dw start
.dw 0
.bank 0
.org $8000
start:
lda #%00001000
sta $2000
lda #%00011110
sta $2001
jsr waitblank
jsr waitblank
lda #$3F
sta $2006
lda #$00
sta $2006
ldx #$00
loadpal:
lda tilepal, x
sta $2007
inx
cpx #32
bne loadpal
ldx #$00
mainloop:
jsr waitblank
jsr drawsprite
;jsr joystick
jmp mainloop
waitblank:
lda $2002 ; load A with value at location $2002
bpl waitblank ; if bit 7 is not set (not VBlank) keep checking
rts
drawsprite:
lda #$00
sta $2003
sta $2003
lda #$50
sta $2004
lda #$00
sta $2004
lda #%00000000
sta $2004
lda #$50
sta $2004
lda #$08
sta $2004
lda #$00
sta $2004
lda #%00000000
sta $2004
lda #$18
sta $2004
rts
tilepal: ;.incbin "test.pal"
.db $3F,$00,$10,$30,$3F,$00,$10,$30,$3F,$00,$10,$30,$3F,$00,$10,$30
.db $3F,$00,$10,$30,$3F,$00,$10,$30,$3F,$00,$10,$30,$3F,$00,$10,$30
.bank 2
.org $0000
.incbin "testbkg.chr"
.incbin "testspr.chr"
Is there anything in my code that is outright wrong? Any help to point me in the right direction or figure out why I can not display more than one sprite would be appreciated.
If I comment out the second part of the drawsprite routine - one sprite will appear.
Code: Select all
lda #$08
sta $2004
lda #$00
sta $2004
lda #%00000000
sta $2004
lda #$18
sta $2004
However, with that code not-commented out, neither of the sprites will show. I am new to NES development so I'm sorry if the answer to my problem is obvious.
Thanks
Posted: Tue Jun 27, 2006 5:46 pm
by Celius
I only tried using that method of sprite output like once. Doing it that way isn't very efficiant, so you should try using sprite DMA. What you do, is you take a section in RAM, $100 bytes, and store the sprite data the same way in that section. Say, take $500-$5FF, and store your sprite data like so:
$500 - Sprite 0 Y pos
$501 - Sprite 0 Tile #
$502 - Sprite 0 Attribute
$503 - Sprite 0 X pos
$504 - Sprite 1 Y pos
$505 - Sprite 1 Tile #
....
Okay, so you get that? And now, in your NMI routine, or once every Vblank, store #5 in $4014, because #5 is the high byte of $500. Do you understand?
Posted: Tue Jun 27, 2006 6:11 pm
by Cypherr
thanks for the reply.
i think i understand. but now i am getting three sprites displayed instead of the two i expect. this may be something i am overlooking but i don't see why there is there.
the two sprites i expect to show up are at 120,120 and 8,18 as expected. however, there is another one at 0,0.
Code: Select all
sprite_x = 0
sprite_y = 1
.inesprg 1
.ineschr 1
.inesmir 1
.inesmap 0
.bank 1
.org $FFFA
.dw 0
.dw start
.dw 0
.bank 0
.org $8000
start:
lda #%00001000
sta $2000
lda #%00011110
sta $2001
jsr init_vars
jsr waitblank
jsr waitblank
lda #$3F
sta $2006
lda #$00
sta $2006
ldx #$00
loadpal:
lda tilepal, x
sta $2007
inx
cpx #32
bne loadpal
ldx #$00
mainloop:
jsr waitblank
jsr drawsprite
;jsr joystick
jmp mainloop
waitblank:
lda $2002
bpl waitblank
rts
drawsprite:
lda #5
sta $4014
rts
init_vars:
lda #120
sta sprite_x
sta sprite_y
lda sprite_y
sta $500
lda #$00
sta $501
lda #%00000000
sta $502
lda sprite_x
sta $503
lda #$08
sta $504
lda #$00
sta $505
lda #%00000000
sta $506
lda #$18
sta $507
rts
tilepal: ;.incbin "test.pal" ; include and label our pallete
.db $3F,$00,$10,$30,$3F,$00,$10,$30,$3F,$00,$10,$30,$3F,$00,$10,$30
.db $3F,$00,$10,$30,$3F,$00,$10,$30,$3F,$00,$10,$30,$3F,$00,$10,$30
.bank 2
.org $0000
.incbin "testbkg.chr"
.incbin "testspr.chr"
Any additional help is appreciated and thanks again for your initial help
Posted: Tue Jun 27, 2006 6:36 pm
by never-obsolete
DMA writes 255 bytes whether all are being used or not. so it still writes repetive zeros. you need to either:
1. set tile $00 in the sprite pattern table to be blank so that all the unused sprites are blank by default
or
2. set the tile data of each unused sprite in the DMA to whatever tile in your pattern table is blank
option 1 would be the easiest.
Posted: Tue Jun 27, 2006 6:39 pm
by Celius
Easy enough to explain, I believe.
You must have a something drawn in tile #0 in your pattern tables. You see that the rest of the sprites are all just $00s and $FFs, right? Because you didn't do anything to the rest of the RAM that's being stored into $4014. If it's all 00s, you are storing sprite with tile #0 at 0,0 with attribute 0. So of course the sprite will show up at the top corner of the screen.
I actually was wondering that at one point, and then it dawned on me that that was the problem. So if you don't want it to be seen, just move the stuff that's in tile #0 in your pattern tables. There will always be 64 sprites on the screen with this method, there are complicated ways around this, But most games always have 64 sprites on screen, as most games use sprite DMA. Does that help?
Edit: Oh, never-obsolete answered before me! Oh well, it's best to have 2 explanations anyways.
Posted: Tue Jun 27, 2006 6:50 pm
by Cypherr
thanks for both your replies. definitely makes sense to me now.
i was trying to understand the whole sprite dma all day today, but all it took was a matter of minutes from you guys. thanks
Posted: Tue Jun 27, 2006 7:00 pm
by Quietust
Actually, the proper way to hide unused sprites is to set their Y-coordinate to any value between $F0 and $FF (inclusive), thereby placing it off the bottom of the screen.
(edit: F0-F7 is also valid; technically, EF is too)
Posted: Tue Jun 27, 2006 7:32 pm
by Celius
Well, if you are testing on the real NES, you won't be able to see sprites in the corner, will you? Actually, at least not the whole thing, the bottom 8 pixels, correct? I would just stick with not using tile #0. If you want to use it for sprite #0 hits, just put a line of pixels on the top of the tile, so you won't be able to see it on the real system, but it still is usable for doing that.
Posted: Tue Jun 27, 2006 7:55 pm
by Disch
Celius wrote:Well, if you are testing on the real NES, you won't be able to see sprites in the corner, will you?
But you'll overflow sprites on that scanline, destroying the possibility of using $2002.5 (not like that's paticularly useful). Plus any sprite you WANT visible on the top of the screen might not be, since the other sprites may be found first. Plus then you have to keep a blank tile in CHR at all times, which you might not want to do with sprites (kind of a waste of a tile).
It's better all around to do what Q said and just put the sprites off-screen.
Posted: Tue Jun 27, 2006 8:31 pm
by Celius
Oh! I forgot, the screen is shorter than it is wide, so yeah, them not being on screen is a better idea.
Posted: Tue Jun 27, 2006 10:40 pm
by Dwedit
Depending on your TV, you might see the top 8 pixels, or you might not.
Posted: Wed Jun 28, 2006 8:50 am
by Bregalad
I think full the whole SPR RAM with $f0 is a proper way to blank it.
Then, setup all sprites you need, and if you don't use all 64 sprites, wich is most likely to be the case, unused sprites will never be fetch, since the last scanline is 240, wich is $f0 in hexadecimal. Since sprites are fetched one scanline late, sprites with $f0 as their vertical position will never be fetch, and so it is technically as if they wouldn't exist at all.
$f1-$ff will work as well, if you prefer $f8, $ff or whathever for any reason, go for it.
Posted: Wed Jun 28, 2006 9:41 am
by Memblers
Dwedit wrote:Depending on your TV, you might see the top 8 pixels, or you might not.
That's true, with the programs I've designed I just consider the top and bottom 8 lines to be a loss. I've played on some bad TVs, so I can see why not to put anything important on the edges.
Posted: Wed Jun 28, 2006 10:40 am
by tepples
Celius wrote:Well, if you are testing on the real NES, you won't be able to see sprites in the corner, will you?
In Europe you can, as European TVs have more visible scanlines. The NES image is always 240 scanlines tall, but an image 240 scanlines tall on a PAL TV is as tall as something 200 scanlines tall on an NTSC or PAL60 TV: easily within the
safe area.
Posted: Wed Jun 28, 2006 10:47 am
by Bregalad
Most commercial NES games were devlopped assuming that the top and bottom 8 pixels are not visible to the user, causing graphical glitches in PAL.
For this reason, I think have emulator hide top and bottom borders is a good thing, even if it doesn't really emulate the hardware, blah, blah, blah, it is looking what most games were designed for.