Page 3 of 8

Posted: Thu Jul 28, 2005 11:53 pm
by Disch
C/C++ won't help you much/at all in your efforts to program the NES. Break out your 6502 references and start reading. Get a copy of nestech.txt for the register descriptions, and maybe pick up a tutorial or two.

http://www.obelisk.demon.co.uk/6502/reference.html <--- one of the best 6502 references. It won't teach you 6502 but is great for looking up quick stuff.

http://nesdev.com/ndox200.zip <--- nestech -- not exactly 100% at times, but still gives you a pretty good idea of what you need to know. The $2xxx register descriptions in it are a 'must-know'

I don't have any recommendataions for tutorials. GBAGuy made one which I hear is decent -- however it's the only one I know of and I've never actually looked at it so I don't know if it's any good or not.

Posted: Fri Jul 29, 2005 12:09 am
by Celius
Well, I downloaded nestech a long time ago, and I've read gbaguy's tutorial, but I don't know if I've been to that other link you have there. I am just not sure what to do for designing levels, every method seems to be innacurate, except for one which I know is really accurate, which I AM NOT going to use. This is it:

lda #$00
sta $2007
lda #$01
sta $2007
etc..

loading one tile at a time. Very accurate, A ROM HOG. I'm pretty sure it works on every emulator. I don't know. I just wish that frickin' method would work. I hope I stumble upon a good method someday. I want alot of background data in my game, and I don't want to have to do something dumb to make backgrounds. Yeah, I'm going to have ALOT of background data in my game, so I NEED to find a good method. There has to be one good method at least. incbining nam files SUCKS. UNRELIABLE. I will maybe have to look in SMB1's source, and see they're method, if I can. the only problem is it's SUCH A BIG CODE! I don't even want to think of Final Fantasy 3s. Well, if you get a reliable method, let me know, I'll be here on the computer until I die. Or have to go to school and work.

Posted: Fri Jul 29, 2005 12:19 am
by Disch
You need to get familiar with other addressing modes. And employ some looping:

Absolute,X:

Code: Select all


SomeLevelData:
.db $15, $32, $52, $53, $64


YourLevelLoadingCode:

LDX #$00  ; start out index at 0

loop:
  LDA SomeLevelData,X  ; load from SomeLevelData, indexed by X register
  STA $2007            ; draw it
  INX                  ; increment X (so next time we'll load the next tile
  CPX #$05             ; only do 5 tiles (that's all I listed up there)
  BNE loop             ; jump back to loop until X reaches $05
That code will copy the 5 bytes from 'SomeLevelData' (those 5 bytes listed there) and write them to $2007 in order. If you need further details on how that code works I can try to explain it better.

Posted: Fri Jul 29, 2005 12:21 am
by Quietust
I've looked through the tutorials by GBAGuy, and I can safely tell you that they are NOT any good - they pretty much rely on substandard emulators like nesticle and will NOT run properly on real hardware. To name a few examples I've seen:

* Not waiting 2 frames on startup
* Not disabling frame IRQs
* Writing to VRAM while the PPU is trying to render

It also has some significant errors in the instructions:
* It labels $2000.6 as "Execute NMI on Sprite Hit" (supposed to be PPU master/slave toggle, which has no effect on the NES)
* It claims you can only set one color emphasis bit at once (probably straight from Marat's documents)
* It claims the SPR-RAM address register $2003 is 16-bit (double-write) like $2005/$2006
* It initially tells you to write to SPR-RAM one byte at a time to $2004 (but later tells you how to do it properly via Sprite DMA, neglecting to tell you that you STILL have to specify the initial SPR-RAM address)
* It tells you to use .db to declare variables in RAM and suggests that it will actually use the initial value
* It claims the first $2005 write is vertical scroll and that the 2nd write is horizontal - in reality, it's the other way around
* It initially tells you to handle joypad input by reading $4016 and checking each bit individually (though it eventually teaches you to do it properly)
* The author CAN'T SPELL
* The author expresses LOTS of uncertainty throughout the tutorial, leading to the conclusion that he doesn't actually know anything about the NES in the first place.

The tutorials are very, VERY outdated, and I would not recommend using them.

If you want a decent tutorial, I would recommend McMartin's NES 101 tutorial. Though it assumes that you know 6502 assembly reasonably well, it is reasonably up to date with current knowledge of how the NES works and, as a bonus, it will actually work on a real NES!

Posted: Fri Jul 29, 2005 12:22 am
by tokumaru
Celius wrote:I think i understand scrolling now. I think I am going to make a couple programs for my current projects. I could design them, I just am not so good with programming opening files and saving files. Do you think it will be alright to make programs with C, and not C++? Because I only know C at the moment. I am not sure how to just jump right into hibber jibber, and ouput stuff on the screen. I don't know how to make a program open a .chr file and put the data on the screen! Is it really hard? Do you know where I could find out how to?

Hi, Celius. Any programming language/tool you choose is fine, as long as you can write to files with it. One of the easiest tools to build level editor is qbasic (old basic interpreter from microsoft wich came with DOS and Win95), wich I used for quite a while. Reading from and writing to files is very easy with it. I use Delphi now, since it is easier to make graphical stuff that more advanced level editors need.

To build your level editor you'll first need to decide what will your level format be. You must think how your game is going to work: Will the screen move horizontally? Vertically? Both? How long will the levels be? How will you handle the objects in it? - All this stuff impacts on how your level editor works. Large levels will most likely need some kind of compression, you must decide a way to define objects (sprites and bg), etc. etc.

The easiest level format is a 2-dimensional array of blocks (I am assuming you can work with arrays in C or whatever). Sit down a minute and decide what kinds of blocks your levels will use. Rocks, grass, sky, water, bricks, etc. All blocks must be the same size (in this simple case, 16x16 pixels, or 2x2 tiles), so if you need larger things they'll have to be made of smaller pieces.

After you have decided all the blocks you're going to use, you must assign a number to each block. Now all you have to do is write a program to "draw" your level. This program is only a friendly interface, so that when you place a sky block at the top of the screen it writes the correct number to an array.

In this simple case you could just write the block numbers to .db statements (althoug it would be very boring) and not write a program for it at all, but in more complicated level designs (like in SMB1, where the levels are compressed, so things aren't quite aligned for a human to see very well) you'll certainly need a level design program to aid you.

Anyway, when you're past this level making part, you must worry on how to implement the reading of the level format you idealized. In this case you'll most likely have to build a table, describing the tiles that make up every block, and the palette they use. So, when reading this level from ROM you'll have to get the block number, check on your table what tiles that block uses, write the tiles to the name table and write the palette entries to the attribute table.

Deciding on a level format is one of the hardest things when making a full game, especially when it's a scrolling game.

You said you'd use a "scanline" something to trigger the drawing of the next part of the level, but that isn't necessary. Just do it like this: If your charecter (player) moved 16 pixels to the right, you draw a new column of blocks to the right. Just draw as your player walks, because there is not enough time in vblank to draw an entire screen. You should draw it little by little.

Here's an advice: Download FCEUXD (or you could use your beloved Nesticle...=D) and use it's nametable viewing capabilities to watch how commercial games draw their levels little by little as you walk, and you might just get some ideas.

Watch games like Kirby (sometimes it scrolls 4-ways!), Little Mermaid (uses a very interesting level format), or even Somari (scrolls everywhere and can be usefull, even beeing a glitchy pirate). Try to figure out how people do stuff and you'll learn a lot.

And remember, the NES does not do anything "automatically", like scrolling or such. The NES is not like Macromedia Flash os anything like this. YOU have to tell the NES what to do on EVERY frame (or even in the middle of a frame!). It doesn't have "built-in animation", YOU make anymation by positioning things in different places every frame. This is great because it puts you in control of everything. If it had such easy commands like "scroll till this point" it wouldn't be fun at all and all games would look the same.

Good luck with your projects! (I can't seem to finish any of mine!)

-tokumaru-

Posted: Fri Jul 29, 2005 12:31 am
by tokumaru
Quietust wrote: * Not disabling frame IRQs
Sorry to ask but... how you do that again?
This is not yet printed in my brain as one of the things to do on start-up! =)
Is this the thing you do by writing something to $4017 (really wild guess on the address here, since I have to resort to a document every time I'm doing NES stuff, but my brain does say something about a 17!)

-tokumaru-

Posted: Fri Jul 29, 2005 5:29 am
by blargg
This is not yet printed in my brain as one of the things to do on start-up! =)
Based on my tests, you don't need to do anything at startup (at least for basic mappers). The I flag is set on power-up (sei), and the NMI is disabled ($2000.7 = 0).

At power-up it is as if $00 were written to $4017 so if you do nothing the frame IRQ flag will be set in about 1/60 second. This is fine until you go to enable interrupts (cli); if you neglect to clear the frame IRQ flag (either by writing $40/$c0 to $4017 or reading $4015) you'll get an immediate IRQ.

I code the latter way, since it makes no assumption about how things were set up before:

Code: Select all

lda #$40
sta $4017
cli
...

Posted: Fri Jul 29, 2005 6:25 am
by beneficii
tokumaru wrote:
Quietust wrote: * Not disabling frame IRQs
Sorry to ask but... how you do that again?
This is not yet printed in my brain as one of the things to do on start-up! =)
Is this the thing you do by writing something to $4017 (really wild guess on the address here, since I have to resort to a document every time I'm doing NES stuff, but my brain does say something about a 17!)

-tokumaru-
You write #$40 to $4017 (that is, set byte 6) to disable frame IRQs.

Posted: Fri Jul 29, 2005 6:27 am
by beneficii
Quietust wrote:
beneficii wrote:You also have to set $2006 as well to your current nametable.
No you don't - when you want to set your current nametable for rendering, you write to $2000 and specify your desired nametable in the bottom 2 bits (do this along with the reading $2002 and writing $2005 stuff).
Write the two lower bytes. One I'm talking about is what you set $2006 to in the NMI: $0000 if you're using the upper left nametable, $0800 if you're using the lower left, etc. It's a simplification, but it does work.

Posted: Fri Jul 29, 2005 8:15 am
by mbrenaman
Sorry to butt in, but this is the first I'm hearing of having to read from $2002 before using $2005/6. I tried adding "bit $2002" before my writes to them in the scroller I'm making and it went from working fine to scrolling very jerky in Nintendulator. The only time I read from $2002 is when my main code is wait for the next NMI. Very weird that it went from working fine to scrolling jerky. Am I really supposed to read from $2002 every single time I use $2006 or will just once every NMI be fine?

EDIT : I'm confused.

Posted: Fri Jul 29, 2005 8:47 am
by Disch
beneficii wrote:Write the two lower bytes. One I'm talking about is what you set $2006 to in the NMI: $0000 if you're using the upper left nametable, $0800 if you're using the lower left, etc. It's a simplification, but it does work.
But that's what the two low bits of $2000 are for. $2006 is not needed for this process (not to mention is harder to use and wastes CPU time)

Though, yes -- writing $2006 in this manner would work.



@ Mr. Brenaman:

You shouldnt' have to do it before every one. Once at the start of VBlank should be fine -- and once for every time you split the screen to change scrolling. Basically I'd do it any time you leave $2005/$2006 unextended for a long period of time.

Posted: Fri Jul 29, 2005 8:52 am
by Guest
Disch, thank you. I thought my just the read before Vblank was working hehe. Thanks :) ..... Hehe Mr. Brenaman.

Posted: Fri Jul 29, 2005 8:58 am
by Disch
oh whoops... 'mbrenaman' -- not Mr. Brenaman. haaha sorry XD I coulda swore it said 'mr'.

Posted: Fri Jul 29, 2005 9:54 am
by Celius
Dude, Gba guy's tutorials SUCK. He's just like, "Oh yeah, I don't know how this works, but i would be very greatful if someone found out how." Yeah, that sucks. He always uses these crap methods of doing stuff I think his example of Vblank routines is BAD. And everything else. If you want to be really good with 6502, read something else. :wink:

Posted: Fri Jul 29, 2005 10:08 am
by beneficii
Disch wrote:
beneficii wrote:Write the two lower bytes. One I'm talking about is what you set $2006 to in the NMI: $0000 if you're using the upper left nametable, $0800 if you're using the lower left, etc. It's a simplification, but it does work.
But that's what the two low bits of $2000 are for. $2006 is not needed for this process (not to mention is harder to use and wastes CPU time)

Though, yes -- writing $2006 in this manner would work.



@ Mr. Brenaman:

You shouldnt' have to do it before every one. Once at the start of VBlank should be fine -- and once for every time you split the screen to change scrolling. Basically I'd do it any time you leave $2005/$2006 unextended for a long period of time.
Oh, OK. I'll try that out.