Kasumi wrote:There are better ways to do this which I hope I'll remember to list in another post, but I have something to do like right now.
That errand is now complete, so back to this. An easy to wait for vblank is this:
Code: Select all
main:;checks for collision
lda vblankoccurred;A new variable you must define
mainvblankwait:
cmp vblankoccurred
beq mainvblankwait
It loads the value of vblankoccurred in A before the loop, then compares that value to vblankoccurred. It counts on the NMI to change vblankoccurred during the loop. So in your NMI, you just need this somewhere to break that loop:
Code: Select all
inc vblankoccurred;whatever it was, it's now different so the loop will break
It's also good to do this because using bit $2002, bpl can occasionally miss frames.
With your main loop now running once per frame instead of constantly, you can move the code that animates your character to the main loop instead of the NMI. It doesn't matter much in this case, but it's good practice to have nothing in the NMI that doesn't absolutely need to be there. (Sprite DMA, tile updates that need to be done during gameplay need to be there. Music engine doesn't need to be but is cool to put there after the required stuff is done, just so music won't slow down if your main loop is running too many things.)
Already covered lsr/clc, ror. One other tiny note is that you occasionally compare with 0 when it isn't required.
In that case you can remove the cmp and the program will work exactly the same, because lda will set the zero flag if what was loaded is equal to zero.
The last thing to mention is (indexed),y addressing which may help you avoid large cmp, branch trees when your game gets larger. It allows you to load from an address you can change, rather than one specified at compile time the way a label's is.
Code: Select all
lda #<level0;Low byte of this label's address
sta addr;Addr pointing to the first of two bytes of zero page RAM
lda #>level0;high byte of this label's address
sta addr+1;Addr+1 is the second of two bytes of zero page RAM
;With the label's address now in contiguous zero page RAM, the following statements will get the same value in A
lda level0,y
lda (addr),y
This is useful. Right now, you have your one screen broken up into 4 labels to access more than 256 bytes. Instead, you could use (indexed),y and change the location of the pointer to go further than 256 bytes under the label. (But you have to use y instead of x like you're doing now since indexed,x does something different.)
Code: Select all
lda ypos
lsr
lsr
lsr
tax
beq skipaddressfix
addressfixloop:
inc addr+1;(this adds 256 bytes to the pointer, so each time the ypos divided goes up one, the pointer will access the next 256 bytes of data)
dex
bne addressfixloop
skipaddressfix:
Doing this and using (indexed),y allows you avoid all the quadrupled up code underneath le1, le2, and le3. With le0 using indexed, it's all you'd need. And again, it doesn't matter much in this case, but once your game has more data having to evenly space labels would get tedious, so that's a good thing to learn about.
SNgamer wrote:
is it really necessary to enable NMI at the end of every frame? or is this in order to reset scroll position?
Solely to set the scrolling nametable again, heh. It's a bit sloppy. A nicer way to do it is to keep the last value in $2000 in a mirror in RAM. Then you can perform bitwise logic to it.
Code: Select all
lda mirror2000
and #%11111100;The first nametable is ensured, nothing else is changed
sta $2000
sta mirror2000