All RAM should be
initialized before using. Sometimes this means zeroing it out, sometimes it doesn't. For debugging purposes, I clear RAM before using it so I can see which variables are being used and which ones aren't. If a value that should be $00 isn't $00, I know it's being used. But otherwise, a good programmer would ultimately conclude this is a waste of time and space, since they shouldn't "assume" a value is $00.
For PAL music, don't be lazy and use the same pre-calculated values as NTSC. I've created tables found
here that will show you the 11-bit tone values for square and triangle for PAL and NTSC.
Good organization skills are essential in creating a big project. Eventually, when trying to add stuff on if you're not organized, you'll find yourself in a hopeless mess and maybe scrap the project. Try as much as you can to encapsulate (I think this is the right term) certain things so that everything isn't so global/public. So make sure you're aware of what variables are open and can/should be used by most areas of the program, and which ones are private and never to be touched.
Make everything as easy to modify as possible. For example, don't write "STA $88" all over the place, define a name for the variable so that you can assign it a different value later if you need to, and you'll only have to modify 1 thing. So variable naming isn't just important so that each value has a name assigned so you can easily remember what it's for; it's important for ease of modification.
Again, good organization skills are important. You want everything to be as easy as possible to drag-and-drop. Like I make a music engine for multiple games, for example. I want to make this as easy as possible to stick into a game. Sometimes this isn't so easy, and I have trouble doing this myself.
And what tepples mentioned about separating register writes and game logic is completely true. I refer to these two parts as the "Window" and the "Game World". The "Game World" contains all the AI logic, etc. and everything happens in this world. The "Window" is what lets us see it/hear it. There should be a number of buffers that the Game World writes to which the Window code will read and write to registers. You should never directly tie logic to what's written to the registers; that makes sloppy programming. Even this example is sloppy:
Code:
;OAM page is $300
inc $300
To move a sprite 1 pixel to the left. That's too hard-coded. You want to have the concept of an object in the game world that the "Window" puts on the screen somehow. The OAM page should never be tied directly to game logic. This is a hard concept to explain sometimes; sorry if it makes no sense.
tokumaru wrote:
Yes, because in forced blanking the colors pointed by PPUADDR get displayed, and it looks like junk.
Sorry to be a little off topic, but is that all that happens? I thought it was physically impossible to write to the palette during unnatural Vblank...
EDIT: Also, for naming variables, I use kind of a class system (I'm newish to higher level languages, so forgive me if my terminology is wrong). For example, if a variable belongs to my sound engine, I'll name it something like:
Sound.Square1.Note
So it's really apparent what that represents. Also when making sub-engines (like a music engine, or a scrolling engine, etc.) I make sure to include like a "read me" that says exactly how to include it in a project. I will usually write how to use it, too, because usually I'll forget little things after coming back to it a month or so later. This "read me" will tell me exactly what the sub-engine needs in terms of ROM/RAM consumption, and what variables I may need to redefine and what I can redefine them as. For example, I tell myself I need:
$C0 consecutive bytes of non-zero page RAM
$40 consecutive bytes of non-zero page RAM
$19 individual bytes of zero page RAM
or something similar. It's important to state whether you need consecutive bytes or individual bytes if you choose to do something like this.
I guess I also failed to mention that it's good to design things separately and combine them later. Doing this ensures that every individual part works by itself. Though make sure it can work as part of something and not just as a stand-alone program.