Hello all,
I'm currently working on a single level smb style demo to try to understand nesdev so that one day I might be able to take this noob hat off. My road block now deals with scrolling and a static status bar. Currently my entire screen (including the status bar) scrolls when the player moves. The status bar is at the top of the screen and I'm not using any memory mappers (as I don't know enough about them yet). I spoke briefly with Memblers about it and he gave me a little bit of direction ... suggesting to me to use sprite #0 hit. I understand the whole sprite #0 feature and how to read it ... just not sure where to go in stopping the very top part of the screen from scrolling. Any information, documentation links, and suggestions would greatly be appreciated. I'll put my noob cap back on and sit in the corner now. Thanks.
Okay, I had this problem before, but I think I can help you. What you need to do is make sprite #0 be at least 1 colored pixel, because if there's no pixel, the hit will never read. Well anyways, you'd want to make the sprites y coord line up with where you want the scroll to stop. But you have to make sure that a pixel in sprite #0 is colliding with a solid background pixel, and not just the first color of every pallete.
You'd want to restore the scroll at the beggining of every NMI. You'd probably want to keep the scroll location of the level in some variable, and store that into the scroll after every hit. I don't know how your code works, so I don't know what you plan to do. But restore the scroll at the beggining of every NMI. Then wait for a sprite #0 hit. After the hit, do what you want with the scroll. But just remember to restore the scroll, it's what stops the status bar from scrolling.
And make sure that sprite #0 hits with a solid background pixel! Otherwise, it will wait forever and ever and ever in your NMI! Do you understand how to do this?
Celius wrote:
Well anyways, you'd want to make the sprites y coord line up with where you want the scroll to stop.
Thanks for the reply. I'm not sure what exactly youre saying here. Here is a cryptic drawing
of what my screen looks like:
Code:
|----------------------------------------|
| status bar
|----------------------------------------| <--- ceiling tiles
O < -- weak guy drawing
/\
|----------------------------------------| < -- ground
sprite 0 would be in the top left of his face right now. So you're saying line up Y with what??
In other words, your screen doesn't look much different from this:
First off, change your demo so that the end of vblank code scrolls the screen to (0, 0). In this state, without scrolling, make sure that a non-transparent pixel of the status bar overlaps a non-transparent part of sprite 0;
Super Mario Bros. uses part of the coin image for that.
Then wait for sprite 0 with a bit $2002 bvc loop, and when it finishes, scroll the screen by writing once to $2000 (select nametable, etc.) and once to $2005 (to set the horizontal scroll), and then read $2002 (to reset the first/second byte latch used by $2005 and $2006).
Oh, that can't happen if you're going to use sprite #0 hits. Move the sprites that make up the character to different sprite numbers, so if this is your sprite:
0 1
2 3
4 5
make it:
1 2
3 4
5 6
Because sprite 0 has to be up by where the status bar ends. like this:
Code:
-------------------------------------------
Status Bar
-------------------------------------------
0
Sprite
_______________________________
See where the 0 is? That's where you want sprite #0 to be. Because what you are doing is every frame, you restore the scroll to #$00 until the PPU detects sprite #0 hitting a solid background pixel. When the PPU detects sprite #0, you can then update the scroll if your character is moving, or whatever you want to do scrolling-wise that doesn't involve the status bar. But make sure that a pixel in sprite #0 hits a solid pixel on the status bar. What you are doing is kind of an advanced thing, but if you really think about what you're doing, you can figure it out.
Just line up the solid sprite pixel with a solid background pixel on the status bar, and leave the scroll set to #$00 until the PPU detects that a solid sprite pixel and a solid background pixel are coliding. Is that a little more helpful.
If your level is scrolling only horizontally, is is really really easy.
If so, you'll most likely be using vertical mirroring
Keep your status bar in nametable zero (for example). Your level data will change from nametable zero and 1 while scrolling, and the scroll value will change. But, at the end of VBlank, always write your scrolls so the bar show up (so, write $00, $00 to $2005 and anything with bit 0 clear to $2000).
Then wait for sprite-zero hit. You can perfor your hit easily since the status bar won't moove, find a trick to hide the sprite.
Then, once it's hit, write your new horizontal scroll to $2005 (only one write is necesary, the second one won't affect scrolling if there is any), and write the proper nametable selection bit to $2000.
If scrolling verticaly, look at Brad Taylor's PPU adressing doc to know how to merge $2006 and $2005 writes to scroll vertically.
Thanks for all the replies. I think I pretty much have a handle on what everyone is trying to say here. I've moved my sprite 0 to the top and aligned it with where I want my scroll to stop. I've setup a bvc loop looking for the sprite 0 hit. Where my problem comes in, I think, is with scrolling (sadly). I think my problem comes in with the way I've done my past scrolling.
Here is what I've come up with. All my logic is done in NMI. Here it is:
Code:
nmi:
lda #%10001000
sta $2000
lda scrollPos
ldx #$00
sta $2005
stx $2005
jsr dmatrans
jsr controlStrobe
jsr sprite_hit
sprite_hit:
bit $2002
bvc sprite_hit
lda scrollPos
sta $2005
lda $2002
rts
I think my problem is (and please correct me if Im wrong) the way I've been executing my scroll. What I have been doing is using scrollPos to store the value of my scroll position. When the user presses left or right the background scrolled and sprites legs moved giving the appearance that the sprite was actually moving through the scene (and scrollPos is either inc or dec based on direction). If I understood correctly (tepples) what you were saying ... I need to write $00 to 2005 at the beginning of my nmi routine (which currently writes scrollPos to the horz and 00 to vertical). If I do that then the sprite doesnt move at all. So I guess my question is ... how does one
correctly make the sprite "walk". Also, would the rest of above be correctly if the scroll parts were right?
Any good docs on this whole scrolling thing would be good if you could reference me to them.
Thanks again.
You are writing scrollPos to $2005 in the NMI. Then you write the same value again after the sprite hit. You are simply not spliting the screen at all.
The first time, you have to write the position of the status bar, wich most likely is 0, 0, in nametable 0, if you're doing as people said. This way, every time a frame starts, it will show your status bar. After the status bar is over, the sprite hit will happen and only then you want to write your scrollPos to $2005.
As for the sprite moving, I guess you already know the scroll values only affect the background, for any movement of the sprites you have to update their individual X and Y positions.
EDIT: You said the background didn't move at all when you changed the first write to $2005 to 0. You changed only the first write, right? If you changed all writes to 0 there is no way anything will scroll. After the hit you have to write scrollPos.
lynxsolaris wrote:
Any good docs on this whole scrolling thing would be good if you could reference me to them.
Documents usually cover the actual tech aspects of the console, they hardly ever explain any "tricks" that are actually used in game making. For this kind of info you'll pretty much have to ask around, or look for a place where someone has already asked about it.
I decided to write this in another post because I think many people run into this kind of problem. If you don't know squat about game programming, you'll have 2 barriers when learning NES programming: you have to learn how the system works and then learn how a game works.
I made a few games before I got into NES programming, so it wasn't quite lost, but many people have no idea of how to start coding an engine. Many don't even know what an engine is, with all the point-and-click/object-oriented/visual crap of nowadays.
Well, I'm saying this because maybe there should be some links related to actual game programming concepts avaliable to NES programmers somewhere. Not that the status bar is a very good example of it, it just reminded me of the subject. That's it.
tokumaru wrote:
You are writing scrollPos to $2005 in the NMI. Then you write the same value again after the sprite hit. You are simply not spliting the screen at all.
So which would be better .. remove it from NMI or from the inside of the sprite_hit detection?
tokumaru wrote:
The first time, you have to write the position of the status bar, wich most likely is 0, 0, in nametable 0, if you're doing as people said. This way, every time a frame starts, it will show your status bar. After the status bar is over, the sprite hit will happen and only then you want to write your scrollPos to $2005.
Ok I guess I dont understand that part? 0,0? When I write the first status bar object its written to $2061 of the nametable ....
tokumaru wrote:
As for the sprite moving, I guess you already know the scroll values only affect the background, for any movement of the sprites you have to update their individual X and Y positions.
Gotcha. Just making sure I was doing it the right way.
tokumaru wrote:
EDIT: You said the background didn't move at all when you changed the first write to $2005 to 0. You changed only the first write, right? If you changed all writes to 0 there is no way anything will scroll. After the hit you have to write scrollPos.
I only changed the values only in the NMI section at the begining to 0 (which I didnt show in the above code) and nowhere else.
Thanks.
tokumaru wrote:
lynxsolaris wrote:
Any good docs on this whole scrolling thing would be good if you could reference me to them.
Documents usually cover the actual tech aspects of the console, they hardly ever explain any "tricks" that are actually used in game making. For this kind of info you'll pretty much have to ask around, or look for a place where someone has already asked about it.
I decided to write this in another post because I think many people run into this kind of problem. If you don't know squat about game programming, you'll have 2 barriers when learning NES programming: you have to learn how the system works and then learn how a game works.
I made a few games before I got into NES programming, so it wasn't quite lost, but many people have no idea of how to start coding an engine. Many don't even know what an engine is, with all the point-and-click/object-oriented/visual crap of nowadays.
Well, I'm saying this because maybe there should be some links related to actual game programming concepts avaliable to NES programmers somewhere. Not that the status bar is a very good example of it, it just reminded me of the subject. That's it.
Ive messed around with some game programming using C and OpenGL. This is about my second month in nesdev.... I've seen somethings on the web ... but its very very basic stuff ... haven't found anything like the stuff you guys talk about here. I do use the docs on nesdev.com.
I'm sorry, I really hate to say this, I feel kind of rude, but... Would you be so kind as to not double-post? It would be better if you copy/pasted the info from your last post into your old post. There's a thread here where I like triple post ALL throughout the topic, and it really annoyed people, so I stopped. And now I tell people to not double/triple post.
Did you reset the scroll after or before the sprite #0 hit read?
tokumaru wrote:
Documents usually cover the actual tech aspects of the console, they hardly ever explain any "tricks" that are actually used in game making. For this kind of info you'll pretty much have to ask around, or look for a place where someone has already asked about it.
So if you know of tricks, please put them in the
new wiki.
Celius wrote:
I'm sorry, I really hate to say this, I feel kind of rude, but... Would you be so kind as to not double-post? It would be better if you copy/pasted the info from your last post into your old post. There's a thread here where I like triple post ALL throughout the topic, and it really annoyed people, so I stopped. And now I tell people to not double/triple post.
Did you reset the scroll after or before the sprite #0 hit read?
Yeah sorry about the double post .. apparently we were both writing each other at the same time.
I'm sorry ... reset the scroll to what?
Problem is that if you post, then someone else quickly quotes you, then you edit your old post, you can get inconsistent quoting.
lynxsolaris wrote:
So which would be better .. remove it from NMI or from the inside of the sprite_hit detection?
You don't remove any of them, both are necessary, but you have to write different values each time, or there would be no meaning in writing twice. The first time (in the NMI after you have done all writes, if any) you have to write the position of the status bar. That is, write to $2000 with the 2 lower bits holding the index of the name table (00) and then write 0 twice to $2005.
Then, after the sprite 0 hit, write to $2000 (if you're using vertical mirroring, if not, don't bother) and to $2005 again, but now with the values referent to the position within the "level/map". The scrollPos variable would be written to $2005. If you're using vertical mirroring, you have 2 screens side by side, and together they are 512 pixels wide. You need 9 bits to represent that, so the 9th bit goes in bit 1 of $2002. If you're using horizontal your screen is 256 pixels wide, so 8 bits is enough.
Quote:
I only changed the values only in the NMI section at the begining to 0 (which I didnt show in the above code) and nowhere else.
Well that was supposed to work. Could you post the current code?
tokumaru wrote:
Well that was supposed to work. Could you post the current code?
Absolutely!
Code:
nmi:
lda #%10001000
sta $2000
lda #$00
sta $2005
sta $2005
jsr dmatrans
jsr controlStrobe
jsr sprite_hit
int:
rti
sprite_hit:
bit $2002
bvc sprite_hit
lda scrollPos
sta $2005
lda $2002
rts
Is this all you need? In the state above, the sprite moves and when it detects a sprite hit then whole screen "jumps"....
Thanks for helping a noob...
I don't know if the sprite DMA can affect the PPU address in any way, but maybe you should set $2000 and $2005 after the DMA. Realistically, this (setting the scroll) wouldn't be the first thing in your NMI. You should set the scroll after all other PPU operations are done, since they mess with the PPU address (wich means they mess with the scrolling).
Maybe this changes something?
lynxsolaris wrote:
In the state above, the sprite moves and when it detects a sprite hit then whole screen "jumps"....
What do you mean? Does it look OK if you don't try to walk? I can't understand exactly what's happening, what kind of effect you're getting... Do the status bar and the lower part of the screen at least appear to be separated from each other?
tokumaru wrote:
What do you mean? Does it look OK if you don't try to walk? I can't understand exactly what's happening, what kind of effect you're getting... Do the status bar and the lower part of the screen at least appear to be separated from each other?
At first everything is fine. When I move left or right and sprite #0 hits a black transparent area it jumps back and forth between the transparent area and the non-transparent area it started from. It doesn't seem to be splitting the screen. The entire thing jumps to the left and then back to the right ... left ... right ... etc...
Sprite 0 should always be set at a fixed location in the non-transparent part of your status bar. For instance, sprite 0 in Super Mario Bros. is a sliver of the coin image. Use sprites 1-63 for game objects.
Yeah, you don't want to be moving sprite #0 around if you are dealing with sprite #0 hits. I was wondering, can you change sprite #0's position multiple times in a frame? Because if you did this, you'd be able to do some cool tricks, I'm sure.
Celius wrote:
I was wondering, can you change sprite #0's position multiple times in a frame? Because if you did this, you'd be able to do some cool tricks, I'm sure.
I wondered this myself a while ago. It turns out you can't have more than 1 sprite 0 hit per frame. I don't think you can even move the sprite, but even if you could, the hit flag is raised when the hit happens and it will remain like this until the next frame. The flag only changes it's state once in a frame. That was the answer I got.
If you want more than one split, you have to use other methods.
Well, i was trying to use this sort of method to use both pattern tables for BG. I've done it with sprite #0 hits. For the status bar in FFVII NES, I have the status bar graphics in the sprites side of the Pattern Table, then I place sprite #0 in the appropriate place, and I wait for the hit, then I switch pattern tables. I just restore them at the beggining of each NMI, then I wait for the hit and change it. It's actually quite handy, because I get way more space for enemies and such. I haven't actually made the battle engine for it yet, I just made the demo with the status bar.
i did read that smb use sprite 0 hit, and sprite 0 is hidden in "upper money status". But what is the reason of detect sprite 0 hit, here???
Sprite #0 hit is used in Super Mario Bros. to tell when the status bar has ended in the current video frame.
tepples wrote:
Sprite 0 should always be set at a fixed location in the non-transparent part of your status bar. For instance, sprite 0 in Super Mario Bros. is a sliver of the coin image. Use sprites 1-63 for game objects.
I've done this for sprite #0
Code:
lda #22
sta SPRITE0.Y
lda #120
sta SPRITE0.X
lda #$48
sta SPRITE0.T
so that it stays in that one location on the status bar. When everything first starts up and the player is still ... its directly on top of the non-transparent background. However, when you press left (and the background scrolls right) the non-transparent background moves out from under sprite 0 and thats when the "jumping" I described above starts.
for what is necessary, knowing when status bar has ended being drawed in smb1??.. it's because down of status bar, screen start making scroll???
Yes, lord_Chile, you must detect when rendering has got to that part of the screen because the top part (status bar) is static but the bottom part moves.
The sprite 0 hit marks the point where the screen is to be divided. You just have to set a new scrolling value at the proper time, indicated by the hit.
lynxsolaris wrote:
so that it stays in that one location on the status bar. When everything first starts up and the player is still ... its directly on top of the non-transparent background. However, when you press left (and the background scrolls right) the non-transparent background moves out from under sprite 0 and thats when the "jumping" I described above starts.
But if you're putting the sprite over non-transparent pixels of the status bar and are reseting the scroll to (0, 0) before every frame starts, the status bar shouldn't be moving and should always stay aligned with the sprite. It makes no sense. If you reset the scroll in every NMI there is no way the status bar will move...
tokumaru .. did you get my pm?
OK, found the problem and answered your message. When waiting for the sprite hit, you were doing the following:
Code:
BIT $2002
BVC $8533
BIT $2002
BVS $8538
The flag is set after the hit happens, wich means you were waiting for the hit (branching back while the flag was clear) and then waiting for it to clear again, wich only happened after the whole frame was already rendered, meaning you just ignored the hit. And worse than that: By now, another VBlank has already started, meaning another NMI started before the previous one could end. And that made the writes to the scrolling registers all messy.
The solution is just to wait for no hit, and then wait for the hit:
Code:
BIT $2002
BVS $8533
BIT $2002
BVC $8538
This way the NMI's will not overlap since one always ends it's business before the next one starts.
Good luck!
Tokumaru,
Thanks for the help there. I've made the changes (bvc/bvs) and it works. Thanks for the explaination. Thanks to everyone else who posted too.
Ok, glad I could help. The demo looks cool, you should keep working on it. Or on something else you feel like, of course! =)
tokumaru wrote:
Ok, glad I could help. The demo looks cool, you should keep working on it. Or on something else you feel like, of course! =)
Thanks! Plan to continue to work on it ... still so much to learn, though.