So, I'm getting into NESdev..

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
So, I'm getting into NESdev..
by on (#60777)
And I have a good idea for a game I want to write. I've taken some steps to get started. I picked up the following books:

Programming the 6502 by Rodnay Zaks
6502 Assembly Language Programming by Lance A. Leventhal
6502 Assembly Language Subroutines by Lance A. Leventhal & Winthrop Saville

I've read over a few of the chapters in Zaks' book, but they are mostly centered around mathematical programs, and not games. Are there any beginner tutorials specifically for developing for the NES? Any other reading material I should know about? I know to stay away from GBAguy because I've been reading the forums here for some time before I made this post.

Just to introduce myself, I'm Austen Frazier, and I'm 16. I hang out on the NESdev IRC under the same username that I use here (unless I get disconnected, in which case it's acfgotdc). I plan on having my game completed within the next 6 months or so (mostly working on it in every bit of my free time, which these days is a lot), so I hope to learn quickly as I have with some other programming languages. I know some VB (version 6), HTML (if you can even consider that a language anymore), PHP, and I dabbled a bit in C#, C++, and SQL. Now I know most people say they're going to have their game done by x time but it never comes to fruition, but I fully intend on making one of the best games there's been in quite a long time. I just need some place to begin. So I'm asking you, please enlighten me on where to start.

by on (#60781)
I've been starting with Zack's book as well. I know it's annoying that it starts with math when you want to get results immediately. However, programming a game is, in the low level, doing a lot of comparaisons/additions/shifts, etc... and then "output the results" to the screen and speaker.

So it is necessary to know how to do arithmetical and logical operations on the 6502,cand to know how to deal with the PPU in order to do start doing any NES program.

by on (#60783)
Yeah another 16 year old :P Cooooool ^_^



I definently think if you allreayd know assembly just learn it as you go but since you don't list it IO don't think you know it so definently just pick up any 6502 book and get going :D


Once you do that it's just learning the NES's registers and how to put stuff on the screen, sound, etc. Which truthfully every little piece is kinda easy but putting it together is a....you know.


Wow man, HTML and no javascript? I've gotta teach you that XD
Re: So, I'm getting into NESdev..
by on (#60792)
acfrazier wrote:
Any other reading material I should know about?

http://nesdev.com/bbs/viewtopi ... 0710#60710
Re: So, I'm getting into NESdev..
by on (#60794)
koitsu wrote:
acfrazier wrote:
Any other reading material I should know about?

http://nesdev.com/bbs/viewtopi ... 0710#60710


Eek, $44.20+shipping for a used copy @ http://www.amazon.com/gp/offer-listing/ ... ition=used

I don't have that kind of cash for a book :(

by on (#60797)
IMO, books about the 6502 won't help you much when making NES games. Sure you have to master 6502 assembly, but that comes with practice, not from reading a book.

If you have a book, by all means, read it. But if you don't, there is no need to spend a lot of cash on one: find a couple of 6502 references on the internet, grab a copy of the 6502 simulator and start studying the instructions interactively. It worked pretty damn well for me (the first time I came across a book about the 6502 I already knew everything).

I honestly think that knowing 6502 assembly is at most 10% of what's necessary to make a NES game. Mastering the PPU and the concepts of game logic are way more important, and harder.

by on (#60805)
tokumaru wrote:
I honestly think that knowing 6502 assembly is at most 10% of what's necessary to make a NES game. Mastering the PPU and the concepts of game logic are way more important, and harder.

But you do need to understand the 6502 in depth in order to implement game logic that doesn't slow down when more than three critters are in play:
  • How to organize your data, because the 6502 prefers structure-of-arrays logic over array-of-structures logic
  • How to perform coordinate math efficiently, including implementing your own multiplication, division, and trigonometry in order to get a critter to aim at something
  • How to make the best use of registers X and Y vs. local variables in zero page

by on (#60809)
I agree with you, and part of my point is that you'll hardly learn those things from a book. At least the ones I've seen were too superficial and wouldn't talk about those subjects in depth, or at all. By experimenting, you tend to find the best way to do things naturally, because you run into the problems yourself. In my opinion, this gives a person better understanding of why things are done a certain way than if they were simply told that way is correct.

I think it's important that coders go through all the steps. It's important that their first programs aren't very efficient, and that they realize that arrays-of-structures are a pain to work with. If you simply tell them that structures-of-arrays are better they will just think that "this is the weird way the 6502 works and we must all follow blindly" (look at GBAGuy's tutorials for example: they are full of "this is how the NES works, I don't know why but here it is lol").

The rest of my point is that it's still just a language, a way to communicate. Of course it is important to learn how to communicate with the system, but I think it's more important to know what you are going to communicate then how you are gonna do it. If you don't have anything to say, there is no point in learning the language. This is just my opinion though, I'm sure others will give different levels of importance to the components needed to make a NES game.

by on (#60847)
For starting out, once you understand 2 vital instructions instructions (LDA immediate, STA absolute) you could in theory blast out an entire hello world program (LDA #$00 / STA $2007 basically in tons of variations). That's kind of like how I did everything when I started out, which proves that one can program the NES without really knowing 6502, heheh.

I think it would help to look at other people's sources, try messing around with those maybe, once you can get it to assemble.

Yeah I pretty much agree with what tokumaru's latter point, seems like 80% of the challenge is making the PPU do what you want, within it's limitations. There's no immediately obvious limitation to the CPU, you really have to be doing a lot of stuff to run out of time during a frame.

So yeah the program logic doesn't need to be efficient usually (if you start near a slow-down point in worst-case situations, that's when to go back and optimize), however when it comes to using the PPU there are some time limits (vblank time) involved, so in that case you do need to write optimized code pretty much all the time.

For a first program though you can just turn the screen off (LDA #0 / STA $2000 / STA $2001) and be safe doing whatever you want with the PPU, before turning the screen on.

I guess it depends on what you want to do first too. I got into it because I wanted to write music for it (before Nerdtracker, Famitracker, and NTRQ existed).

by on (#60853)
Work through the first series of Nerdy Nights tutorials. They have pictures and are very good for explaining how to work with the PPU: http://nintendoage.com/forum/messagevie ... eadid=7155

And stay far far away from GBAGuy's tutorials.

by on (#60856)
One of the most important things you'll need is to actually get started with an Assembler so you can start writing code. In my opinion real world experience is going to help you out more than any formal reading alone will.

I recommend ASM6 along with one of the templates Tokumaru posted. http://nesdev.com/bbs/viewtopic.php?t=6160

If you understand the concept of programming then so long as you do something rather than nothing you'll make progress. You want to avoid things that cause you to just idle and not really do anything. Don't expect to crank out something like Super Mario Bros 3 right away. Set reasonable goals and set out to achieve them. One of the easiest things to do to get used to the NES would be to make a Pong/Table Tennis game. It's simple but will allow you to learn to deal with drawing characters (sprites) to the screen, input from the player, game logic, perhaps a background, program flow, etc.

Just build up from there.

Also for larger projects it's VERY useful to have some kind of PC programming experience so you can make applications to create data for your game. Almost any language will do, BASIC, C, C++, C#, whatever. This way you can program something like a level editor.

You could make these tools as separate NES programs but it's probably easier if you can make PC programs.

by on (#61027)
tepples wrote:
tokumaru wrote:
I honestly think that knowing 6502 assembly is at most 10% of what's necessary to make a NES game. Mastering the PPU and the concepts of game logic are way more important, and harder.

But you do need to understand the 6502 in depth in order to implement game logic that doesn't slow down when more than three critters are in play:
  • How to organize your data, because the 6502 prefers structure-of-arrays logic over array-of-structures logic
  • How to perform coordinate math efficiently, including implementing your own multiplication, division, and trigonometry in order to get a critter to aim at something
  • How to make the best use of registers X and Y vs. local variables in zero page


Could you or tokumaru explain the difference between arrays of structures and structures of arrays? I haven't heard these specific terms before. Could you give some examples? From the names, I think I may be using arrays of structures in a lot of my code. If there's a strong reason for not doing this, I'd definitely like to learn what that is!

by on (#61028)
Gradualore wrote:
Could you or tokumaru explain the difference between arrays of structures and structures of arrays?

You probably know the difference, but not these names.

Array of structures:

Code:
Metatiles:
   .db $00, $01, $02, $03
   .db $04, $05, $06, $07
   .db $08, $09, $0a, $0b
   .db $0c, $0d, $0e, $0f
   .db $10, $11, $12, $13
   .db $14, $15, $16, $17
   (...)


Structure of arrays:

Code:
Metatiles:
   .db $00, $04, $08, $0c, $10, $14, (...)
   .db $01, $05, $09, $0d, $11, $15, (...)
   .db $02, $06, $0a, $0e, $12, $16, (...)
   .db $03, $07, $0b, $0f, $13, $17, (...)


The difference is that in an array of structures each element of the array is an structure (duh), and since structures can be kinda large the array grows pretty quickly as information is added to it, which means you can't access it quickly by using indexed addressing, you have to use pointers, which wastes RAM and CPU cycles.

By using structures of arrays instead you reduce the size of each element of the array by splitting it into several arrays, which you can easily access using indexed addressing if you know which element of the structure you need to access.

by on (#61029)
Hmm, I think I am using arrays of structures then. I have some reserved locations in RAM comprised of 16 byte chunks of data, each being an "instance" of a structure. I guess what you're saying is that it would be better to have several arrays, one for each "member" of the struct, and avoid having to add the size of your struct to your index register in every iteration of a loop? Or is there more to it?

by on (#61030)
I had that problem when I first started out. I'd store my objects like so:

Code:
obj0_status:    .rs 1
obj0_fracX:     .rs 1
obj0_fineX:     .rs 1
obj0_coarseX:   .rs 1
obj0_fracY:     .rs 1
obj0_fineY:     .rs 1
obj0_coarseY:   .rs 1

obj1_status:    .rs 1
...
...


When it came time to do anything useful (collision detection) I had to use indirection to access the data fields. In the end it became a nightmare to maintain and the code was just all around slower.

Now I structure my objects like so:

Code:
obj_status:     .rs MAX_NUM_OBJ
obj_fracX:      .rs MAX_NUM_OBJ
obj_fineX:      .rs MAX_NUM_OBJ
obj_coarseX:    .rs MAX_NUM_OBJ
obj_fracY:      .rs MAX_NUM_OBJ
obj_fineY:      .rs MAX_NUM_OBJ
obj_coarseY:    .rs MAX_NUM_OBJ


Using indexing to access data fields simplified the code.

I do agree that making these types of "mistakes" was helpful because I understood the why behind it.

by on (#61031)
Gradualore wrote:
I guess what you're saying is that it would be better to have several arrays, one for each "member" of the struct, and avoid having to add the size of your struct to your index register in every iteration of a loop?

Yeah, that's exactly it. Instead of worrying about the size of the structure you can just INX or INY to access the next item.

You still have to use pointers if you need dynamic access to the different members though. But even then this way is better because you can access up to 256 items before having to mess with the pointers again. The downside is that you'd need a pointer for each member.

It's not always that structures of arrays are better, there are times when the other way is simpler. I don't think quicker though, just simpler.

by on (#61032)
never-obsolete, I handle my objects exactly like that.

never-obsolete wrote:
I do agree that making these types of "mistakes" was helpful because I understood the why behind it.

I strongly believe that in order to be a good coder a person has to go through all of it, they can't take shortcuts, or else they are being trained, not taught, and will not have full understanding of what they are doing.

by on (#61108)
tokumaru wrote:
Gradualore wrote:
Could you or tokumaru explain the difference between arrays of structures and structures of arrays?

You probably know the difference, but not these names.

Array of structures:

Code:
Metatiles:
   .db $00, $01, $02, $03
   .db $04, $05, $06, $07
   .db $08, $09, $0a, $0b
   .db $0c, $0d, $0e, $0f
   .db $10, $11, $12, $13
   .db $14, $15, $16, $17
   (...)


Structure of arrays:

Code:
Metatiles:
   .db $00, $04, $08, $0c, $10, $14, (...)
   .db $01, $05, $09, $0d, $11, $15, (...)
   .db $02, $06, $0a, $0e, $12, $16, (...)
   .db $03, $07, $0b, $0f, $13, $17, (...)


No offence intended, but these terms you've created don't make any sense. Terms that make sense would be something like "row-based data set" vs. "column-based data set". You can replace the word "data set" with "structure" if you want, but it'll probably confuse people. Why? Because there's no explanation of what the "data set" *or* "structure" means -- if there's a length associated with them (e.g. "16 bytes of pointers"), what each byte or word represents, what each row represents, etc... Comments are incredibly important here.

Worse, when C programmers see the term "array of structures", they're going to think "struct foo blah[4]". When they see the term "structure of arrays", they're going to think "struct foobar { char *arrA[16]; char *arrB[16]; };" (though technically this is a "structure of array of pointers").

And when perl programmers see the term "array of structures" or "structure of arrays", they're probably going to think of an "array of X" (where X is either scalars, arrays, or hashes).

:-)

by on (#61110)
koitsu wrote:
No offence intended, but these terms you've created don't make any sense. Terms that make sense would be something like "row-based data set" vs. "column-based data set".

I think your opinion is purely based on the simple example I gave, because your proposed terms would hardly suit all possibilities. If you consider that structures can be more complex than several single-byte fields, or that due to memory limitations these tables could be scattered all around RAM and ROM, you'll see that not always the data will look like neatly organized rows and columns.

Quote:
...when C programmers see...

Quote:
...when perl programmers see...


But this is assembly, and if C and pearl programmers already disagree between themselves there will hardly be universal terms understood by everyone. I didn't come up with these terms, but I think they are pretty descriptive (the first time I heard them I knew exactly what they meant).

by on (#61119)
koitsu wrote:
Terms that make sense would be something like "row-based data set" vs. "column-based data set".

In most languages, "column-oriented" connotes 2-dimensional arrays with two integer indices that represent two axes along which measurements are taken, as seen in Fortran's column-major order. But column-oriented might be more familiar to people with experience in, say, SQL, where a record is called a "row" and a field is called a "column". In this case, the rows represent different things and the columns represent different aspects of the things.
Quote:
When they see the term "structure of arrays", they're going to think "struct foobar { char *arrA[16]; char *arrB[16]; };"

struct foobar { int x[16]; int y[16]; int dx[16]; int dy[16]; }; is how a column-oriented or SoA store of coordinates might look.

by on (#61152)
I have to agree with koitsu, it makes a lot more sense to think of it as being organized in columns vs. rows, not structure vs. array.

I also don't see much difference either way; if you've got incrementing x and y variables for stepping through it, one way you'll increment x and the other you'll use y.