On my titlescreen, I want it to display a message, and then scroll down to the titlescreen after about ten seconds. How do you program timing, and stuff like that? and could you show me an example? thanks.
Well, you could trick by counting VBlanks. You know that reading 2002 isn't a good idea, since it clears the VBlank flag and causes a premature frame ending. This way, well... try NMI triggering instead. Just set up a countdown variable.
Fx3 is right. An NMI (if enabled via $2000) will fire at the start of every VBlank (frame). There are approx. 60 frames per second, so if you want to have a 10 second wait for something, set a counter to 600 (60 frames per sec * 10 second) -- every NMI, decrement that counter. When it hits zero, you know ten seconds have passed and you can change your program flow as necessary.
As Fx3 mentioned, polling $2002 to find VBlank is unreliable on the real system as you will occasionally miss a frame here and there with that method. NMIs are very reliable.
Disch wrote:
so if you want to have a 10 second wait for something, set a counter to 600 (60 frames per sec * 10 second) -- every NMI, decrement that counter. When it hits zero, you know ten seconds have passed
Correct. You will have to use a 16-bit counter for delays longer than about four seconds (five seconds in Europe).
I'm sorry, I must seem like I'm clueless, but I have one really dumb question. How would I set the counter to 600....? I am so sorry, I am really dumb sometimes, and I am dumb today at this moment. Thanks for all the help you guys gave me, especially disch. Thanks.
Am I correct in assuming you have basic programming concepts understood? To keep a counter all you need is an area in RAM. For a 16-bit counter, you'd need two bytes. You can declare them in RAM somewhere with something like the following:
Code:
counter_low = $80
counter_high = $81
to store a number in this counter, you can load it to A with LDA -- then store it to the variable with STA:
Code:
LDA #$58 ; low byte is $58, put that in A
STA counter_low ;write A (currently $58) to the low byte of the counter
LDA #$02 ; high byte is $02
STA counter_high ;write it to the high byte of the counter
If you treat 'counter_high' as the high byte and 'counter_low' as the low byte, them combined is $258 or 600 decimal. You count that counter down every frame -- and when both counter_low and counter_high reach zero, you'll know 10 seconds have passed.
There might be a more friendly way to do this. I'm unsure about whatever assembler you're using but you might be able to write the above as:
Code:
LDA <600
STA counter_low
LDA >600
STA counter_high
a bit easier to read -- much more clear that you're setting the counter to 600. But I'm not sure if nesasm or whatever you're using does it like that. You might want to check your assembler's documentation.
Yeah, I know like most of the commands, because I have a document that states what each one does. For some stupid reason, When I tried out the example you showed, the top part of this code:
lda <600
sta counter_low
lda >600
sta counter_high
is the part that is correct in my code, but when I put it in NESASM, it says that "lda >600" has a syntax error in expression. But the top part works, which is confusing... How do you know that $258 equals 600 in decimal? is there a math thing to figuring out what each one is in hex? because 600 times .43 equals 258. can you use that to figure the other ones out...?
< and > symbols aren't really standard -- they're used in some assemblers to signal which byte you want. 600 cannot be represented in one byte, it needs two bytes... so "<600" means "give me the low byte of 600" and ">600" means "give me the high byte of 600". Like I said, if nesasm has this option, it might have a different syntax. To see if nesasm has a lo-byte/hi-byte option, check its documentation -- I mean nesasm's documentation... not 6502 docs. Knowing how to use an assembler means more than just knowing 6502.
Hex digits (preceeded by a '$' symbol) are base 16. Normal decimal is base 10:
Code:
dec = hex
0 = 00
1 = 01
2 = 02
...
9 = 09
10 = 0A
11 = 0B
12 = 0C
13 = 0D
14 = 0E
15 = 0F
16 = 10
17 = 11
...
255 = FF
For quick and easy conversion, you can use Windows' calculator. Just go to View | Scientific -- select the "Dec" radio button. Type in a number, then hit the "Hex" radio button and it will convert it automatically. You can also convert to and from Binary with it.
okay, so I tried doing what you said, and the screen just scrolls at the speed of sound, and never stops. How do you slow this down?
Oh boy...
Do you wanna a piece of cake?
Are you actually counting down that var and waiting for 600 frames? Or are you just setting it to 600 and then not doing anything with it afterward? Are you still using that example scrolling code I told you about 500 times not to use? =P
You're not going to get anywhere like this. I recommend picking up some beginner tutorials and follow along with them -- there are several in the "NES" section on the main site. Maybe even view some simple demo source code as examples until you understand the idea. I don't mind answering questions but it seems the only things you're taking from my posts are the example code -- which you copy paste into your program and then say "it doesn't work". Examples are meant to show the idea, which you don't seem to be getting... they're not meant to really be copy/pastable. I mean I guess I could write the whole program for you, but what would be the point of that? It wouldn't teach you anything.
So yeah -- download some tutorials which cover the basics and follow along with them. Don't worry about the more complicated areas for now (scrolling, sound) -- just focus on the basics. I will still answer questions but I will no longer provide example code unless absolutly necessary -- you have to start understanding the concept so that you can write your own code -- just taking the code we provide you isn't helping you at all.
Here's the kind of code I use for counting vblanks. A very basic example of simply syncing the main loop to the display. Assuming you only INC the scroll value, it shouldn't scroll more than 60 pixels per second if your code is synced.
Code:
vb_hit = $00 ; RAM variable
lda #$80
sta $2000 ; enable NMIs
mainloop:
lda vb_hit
beq mainloop
lda #0
sta vb_hit
; (insert your run once-per-frame code here)
jmp mainloop
nmi:
inc vb_hit
rti
Whoa. I've heard that reading $2002 resets the VBlank flag, and I've even heard that reading it resets the flipflop that decides which byte of $2005/2006 gets read to/written from, but I've never heard anything about it ending a frame prematurely. WTF?
it does not end a frame prematurely, but on the hardware, if you read it just as the flag is being set, it will clear the vblank flag without the vblank flag being returned (or something like that). So if you use $2002 reading for timing, you may occasionally miss a frame here and there -- hence why it's not recommended.
Of course it will probably be very reliable in emus -- but on the real thing it's not a good idea. Which is why you should stick to NMIs. NMIs will reliably fire every VBlank -- as long as they're enabled (and as long as you don't do constant $2002 polling)
And yeah -- reading $2002 does reset the $2005/2006 flip-flop (although neither $2005 nor $2006 are readable)
Hmm... This is quite interesting. I could use it to convert PAL -> NTSC in a few cases when the main loop is correctly spotted & hacked.
But that's just a vague idea...
Oh crap, I should have read through before hitting "submit". Thank you for spotting that error. I didn't realize I'd make such a blunder about $2005/$2006.
Well, anyway, I'm sure if you use the VBLANK flag of $2002 to control execution, it *would* be a bad idea. I myself have only put LDA $2002 in to reset the internal flipflop and check for sprite 0 hits.
On a more minor note, if you have to tell somebody about the hexadecimal number system, they shouldn't even be messing around with the NES until they understand the 6502's assembly language.