New Project

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
New Project
by on (#79989)
2 days ago I began my adventures In Nes Game Development

And today i begin my first project, a space shooter with no save feature ! Yeyyy!! Anyway, i know you are like "look at this noob that thinks hes going to just make a game with no knowledge, typical idiot" I know man, i know. I learn programming best by just digging in and learning as i Go, its just me, that is how i learned AS3 in like a week.

Now lets get to the point, In a year or two, i SHOULD have something similar to this:

-One title screen (Press Start type thing with the title)
-A Ship Sprite That can move horizontally and shoot a bullet
-5 Stages of enemy Waves (enemies shoot bullets too of course)

And that is all that is planned for now. Of course the complete game will have more than 5 Waves, and most likely will have at LEAST 3 boss ships, but adding all of this in a year just seems unrealistic to me. In fact, doing the three things i mentioned in year or two as well, seems a bit unrealistic but i have way to much spare time on my hands, spare meaning greater than 6 hours a day.

Tools
Flat Assembler (Just to write the .ASM file, not to compile)
Notepad ++ (Same as above)
NESASM3 (compiles the. ASM file into a .NES Rom)
Nesread (breaks up the .NES Rom into a .PRG and .CHR file)
YYChar (Chr editor)

Any tips would be nice :)

by on (#79990)
Since you're starting out, I would recommend you go with a different assembler than NESASM3, like say, asm6. That is to say: use an assembler that works better, rather than one that has weird syntax quirks and known bugs (with no updates). The author of asm6 (Loopy) does hang out here on the board regularly.

Be aware that with asm6 (which just builds the actual PRG parts) you'll need to make your own iNES header (16 bytes at the start of the ROM), but that should be a one-time shot. Make the 16-byte file in a hex editor or the like, then do something like (in a "make.bat" or equivalent):

Code:
COPY /B HEADER.BIN+PRG00.BIN MYGAME.NES


...and you'll be good to go. You can add your CHR banks as you go on too (don't forget to update your iNES header!), e.g.:

Code:
COPY /B HEADER.BIN+PRG00.BIN+CHR00.BIN+CHR01.BIN MYGAME.NES


6502 assembly and NES development is significantly different than AS3. There's absolutely nothing "scripty" or object-oriented about the console (like AS3), so put all of that aside. Think bare-bones as much as possible.

Good luck, I look forward to seeing your work in the future!

by on (#79991)
I'd stick with NESASM3 as you'll probably still need to hit up the nerdy nights. Plus what other assemblers offer [Which I haven't found useful besides +/- labels.] is useless right now. I also have a fixed version of ReadNES that you're using, as the readnes program online is broken. Mail me if you want it myscreenname at gmail dot com.

And yeah, assembly is something that even some high-level programmers can't grasp. You have to throw put what you know about standard programming and just think of it a different way.

You can mail me for any questions you don't want to post or just post for more responses. Truthfully though I'd probably say before you start a game, do some mini-projects. Like moving a sprite with the controller before you do anything else. Sounds easy, and it is decently simple, but it'll give you a amazing idea of what programming the system will be all about and give you the best grasp about the NES without doing anything big.

by on (#79995)
Welcome to the community! I think you'll find us very inviting and supportive. We very rarely have any drama around here, at least recently. We're a pretty chill group.

In case you missed the link, we have an extensive wiki featuring hardware and software documentation, example projects and all kinds of reference material. What we don't seem to have is a good instruction set reference, but the one I just linked to is great :wink:

As for choice of assembler I would recommend QASM, which is the assembler I wrote :D If you don't feel comforitable with that, try CA65, but it's got a very steep learning curve.

The reason I recommend these two assemblers is that they both generate source-level debugging files for use with Nintendulator Debug Extensions by TheFox, a board member. This allows you to single-step through your program while looking at your source code, rather than just the raw disassembly. This greatly speeds up the write-compile-test cycle.

QASM also has lexical scoping like AS3 does, so it might make a little more sense to you. I have a very strong JavaScript background and I was trying to make it make sense to me :D

If you do want to use QASM I can post some template projects to get you going. That's not a bad idea anyway...

As for the ROM splitter I've got a Python script that does that. I've been meaning to post it somewhere. I'll have to do that tonight.

by on (#79999)
My turn to plug... 8)

If you're into the whole "IDE experience" thing and you're developing your game on a Windows platform (or, soon, OSX and Linux), you could try NESICIDE. It uses the CC65 toolchain, so yeah you'll want to get familiar with that (download it, install it, find an example built using it online), but realistically it's not that complicated. NESICIDE will generate the makefile for you and there are a few good examples of linker configuration files to use (one is the nes.ini included in the above linked package). Add it to your NESICIDE project (in Project Properties, Linker tab), and you're good to start adding source to your new creation. You could even start with the source provided in the above link as a learning tool...change this line of code, recompile, reload, run, see what happens, lather, rinse, repeat.

[ASIDE: Hopefully tepples doesn't mind me using his project as an example, but it's one of the simplest out there for a new dev to start with!]

You can add/edit source files, add/edit CHR-ROM bank configurations (currently using externally-generated graphic data only). NESICIDE will glue it all together for you.

NESICIDE will also generate the .nes and debug information files and allow you to source step through your code, watch symbols, set breakpoints, etc. It has a built-in emulator and lots of handy debuggers. But since it exports the .nes and debug information you can take that and run it wherever you want, also.

It is an evolving IDE and its author [me] is constantly adding new stuff.
Roulette plays YOU!
by on (#80003)
cpow wrote:
If you're into the whole "IDE experience" thing and you're developing your game on a Windows platform (or, soon, OSX and Linux), you could try NESICIDE. It uses the CC65 toolchain, so yeah you'll want to get familiar with that (download it, install it, find an example built using it online), but realistically it's not that complicated.
[...]
[ASIDE: Hopefully tepples doesn't mind me using his project as an example, but it's one of the simplest out there for a new dev to start with!]

Go ahead; it's perfectly fine by me. I'm glad someone has found a use for what has been called a disappointingly text-based game.

by on (#80004)
Oh yea, I forgot about NESICIDE. That's definitely a great choice for a first-timer. You should have no trouble at all creating a space shooter with it and YYCHR.

Good work cpow :D
Thanks for the replies!
by on (#80014)
Thank you all for the extremely quick, thorough, helpful replies guys. 'Tis a good way to welcome a n00b!

I did however decide to stick with my current setup using NESASM3 and readnes. If i have any problems with readnes, i will ask you guys.

@everyone that said AS3 is nothing like ASM
i was just using AS3 as an example of a language i learned, not comparing it to ASM

@everyone
thanks again, wish me luck!!!

Also, i am starting just by adding a sprite to the screen, then adding controls (left and right OR up and down depending on which i choose after concept drawings). And then i'll commit suicide trying to add in a title screen and enemies!
Re: Thanks for the replies!
by on (#80017)
dsv101 wrote:
And then i'll commit suicide trying to add in a title screen and enemies!


Haha that reminds me of the tagline I came up with:

"Why just ROM hack when you can commit NESICIDE?!"

Anyone else come up with catchy phrases for their tools?

<MOD: splitz!>

by on (#80025)
Make sure to give your game a controversial name, like "Shoot Your Load", or "Double Penetration". :V

In all seriousness though, to get you started, an NES game will need subroutines for the following things:
  • Reading the joypad
  • PPU data pipelining (Storing PPU data to a buffer that gets uploaded to the PPU during Vblank)
  • Waiting for the Vblank NMI
  • Sprite mapping (taking several 8x8 or 8x16 sprites and assembling them into a larger metasprite)
  • Collision detection
  • Actors (actors are the underlying "beings" that you represent with sprites.)


Those last two points are usually where people get stuck, so make sure you ask if you need help with those.

by on (#80028)
thanks man :)
A Sprite already!?!
by on (#80057)
I managed to display a sprite with a custom palette! check it out ---> http://dl.dropbox.com/u/7898392/nes_shot.png

Its a full resolution picture so its a bit big to post :)

Anyway, now i just have to figure out what the heck i did. I have two questions, since this is pretty much nerdy nights week 3 you can refrence that.
-Where do i set which 4 bit palette to use from the 16 bit palette set, im having trouble finding this saddly :(
-Where do i decide which sprite to use, like i use sprite 0 from my char file, how do i set this to use sprite ?

Thanks :)
Sorry for that last post
by on (#80060)
Im an idiot, i will not ask stupid questions like those again, i promise :)

BTW, TRIPLE POST PWNAGE!!!!

by on (#80062)
The palette is the lower 2 bits of what would be $0202 in that code. Also to select one of the 256 tile numbers, that would be the byte at $0201.

My first 'original' NES game project was a space shooter too. It was "Attack of the 3-Eyed Space Nazis". :)

BTW a warning with NESASM, there are some undocumented bugs in the assembler. It's happened to me (it was the first assembler I used) and other people as well, where it can create a bad ROM but not give an error or warning. Does seem to happen to everyone, but it can be extremely annoying if it does. It can be spotted when it happens by disassembling your code (usually helpful to do that if you're having a problem anyways).

by on (#80075)
Drag wrote:
Make sure to give your game a controversial name, like "Shoot Your Load", or "Double Penetration". :V


Why not just name it Rape Games 2? ;-)

by on (#80079)
Lets wait until i have some gameplay before a creative name (that doenst have to do with anything sexual you freaks)!

by on (#80119)
Okay, so what i am looking to do is add shooting in to my game.

Checklist:
Store Bullet off screen (When A is not pressed) - Check :)
When A is pressed a variable is set to 1 and the bullets x = the players x - :(
If that var = 1, bullets y SBC #02 - :(
if bullet off screen, stop moving and set shooting var to 0 - :(

I guess my question here is how i can use the variable system here efficiently.

So far i can just figure out how to set a var

Code:
.rsset $0000
shooting .rs 1 ;this reserves one bit to this var, correct?

by on (#80129)
NESASM3 uses some very weird terminology for things. It really would help if you were using an assembler that the rest of the community commonly used (asm6, ca65, or qasm); it would make helping you a lot easier, and we wouldn't be fighting over assembler idiocy like this. :-)

I STRONGLY suggest avoiding using .RSSET and .RS. These pseudo-ops are confusing as hell; I've read the documentation (and its examples) 4 or 5 times now, and although I think I get it, they really don't make any sense. Awful awful awful.

Please use something like this instead:

Code:
Snakes   = $0500   ; Number of snakes (8-bit)
Rocks    = $0501   ; Number of rocks  (16-bit)
Kites    = $0503   ; Number of kites  (8-bit)

.org $c000         ; Our program starts at $C000 in ROM (PRG)

; Variable initialisation

   lda #0          ; We don't want any kites
   sta Kites
   lda #8          ; We want 8 rocks (low byte of 16-bit value)
   sta Rocks
   lda #0          ; Upper byte of 16-bit value
   sta Rocks+1
   lda #$2a        ; We want 42 snakes
   sta Snakes

; Let's do something with Kites, which is easy since it's an
; 8-bit value

   lda Kites       ; Load number of kites (from $0503) into accumulator
   clc
   adc #4          ; Add 4 to it (so we should now have 4 kites)
   sta Kites       ; ...and store it back in $0503


Let's talk about the Kites stuff first. Sure, adding 4 to Kites works fine, because we're adding 4 to 0, which makes 4. But what if Kites had been initialised with value 254 and we wanted to add 4 to that (258 kites)? We'd have a big problem.

254 + 4 = 258. But an 8-bit value can only hold from 0 to 255... so guess what gets written to Kites in that case? 258-256 = 2. You expected 258 kites, but you suddenly have 2.

Welcome to 6502 and 8-bit architectures! :-)

If you actually want to see or validate this in real-time, you can do so by using the virtual 6502 simulator over at 6502asm.com. Put this code into the text box, compile it, then run it. You'll see a dark red dot in the middle of the screen (dark red = $02). Try messing around with the initialisation value for Kites to see what happens.

Code:
; Initialisation

init:
lda #254
sta Kites

lda Kites
clc
adc #4
sta Kites

; Show results in middle of screen as a pixel
; colour ANDed with $0F (see Help)
sta $3EF

; Infinitely loop
jmp init

Kites: dcb 0


Next, note that I explicitly did not mess with Rocks here, meaning I did not show how to, say, add 455 rocks to the existing value. The reason is that working with 16-bit values is a little tricky on the 6502 since all registers are 8-bit. You have to "split up" a 16-bit value into two 8-bit portions and handle them/treat them separately.

In the case of the initialisation routine, for example, if we wanted to have 378 rocks instead of just 8, we'd have done this instead:

Code:
   lda #122         ; We want 378 rocks, so store 122 (378-256) in the low byte
   sta Rocks
   lda #1          ; ...and store 1 (e.g. 256) in the upper byte
   sta Rocks+1


This might be an easier way of looking at it:

Decimal value 378 is written $17A in hexadecimal -- or, to pad things out, written as $017A in hexadecimal. The "lower byte" (e.g. Rocks) would therefore be $7A, and the "upper byte" (e.g. Rocks+1) would therefore be $01.

Doing real-time (e.g. not static/pre-calculated numbers) 16-bit arithmetic gets a little tricky at times, but you'll have to learn that as you go.

My advice right now: try to keep everything within 8 bits (range 0 to 255) if you can. It'll make learning a lot easier. When I say "everything", I mean your counters/variables (number of lives, ships, X/Y offsets, etc.). You're still learning, so keep it simple. :-)

by on (#80138)
thanks man, for this game i am probably keeping everything 4 bit or 1 bit because that is all i will probably need.

now i just have to figure out how to compare values which wont be to hard :)

by on (#80139)
koitsu wrote:
Code:
Snakes   = $0500   ; Number of snakes (8-bit)
Rocks    = $0501   ; Number of rocks  (16-bit)
Kites    = $0503   ; Number of kites  (8-bit)

Sorry, but I have to disagree. Declaring variables like this is fine in small programs, but once your games get complex and you have hundreds of variables this is hell to manage. Every time you need to move variables around (and you will need to do this a few times during development, I assure you) you'll have to manually change hundreds of addresses. Not cool. Not to mention that it's really easy to make mistakes and end up with overlapping variables.

Really, what dsv101 used in his example is much better. He can just reserve bytes starting from a base address, guaranteeing that no variables will overlap, and if he wants to rearrange some variables he can just copy/paste them and be done with it.

by on (#80141)
koitsu wrote:
I STRONGLY suggest avoiding using .RSSET and .RS. These pseudo-ops are confusing as hell; I've read the documentation (and its examples) 4 or 5 times now, and although I think I get it, they really don't make any sense. Awful awful awful.

Not really true (if I'm not misunderstanding how to use .rsset and .rs -- it has been ~5 years ago since the last time I used NESASM...)

Your example would be something like this when using .rs:
Code:
  .rsset $500
Snakes .rs 1
Rocks  .rs 2
Kites  .rs 1

This is better because now it's much easier to move stuff around or change variable sizes.

by on (#80142)
Seems like .reset is equivalent to ASM6's .enum feature, but I think the .enum feature is more clever in how it works.

by on (#80143)
that was my only concern with what he mentioned, if i reserve bytes to a variable, i will have no problems later. But what is the instruction to compare vars?

i pretty much have to do an IF then statement in 6502 ASM

Like:

Code:
ReadA:
  LDA $4016
  AND #%00000001
  BEQ ReadADone

   if shooting = $00   ;how would i do this typoe of line in 6502 ASM?   

   LDA #$01
   STA shooting

ReadADone:


Code:
If shooting = $01 then

LDA $0207
CLC
ADC #$01
STA $0207


and also

Code:
if $0207 < $00

LDA #$00
STA shooting
[/code]

by on (#80144)
You use CMP to compare. CMP is a subtract operation that does not change A. There's also CPX and CPY instructions available, which compare X or Y against a constant value, or a value in memory.

When A == byte, the result of the subtraction is Zero. So that sets the Zero flag, and BEQ (branch if equal) is the instruction you use to branch when Zero is set.

When A >= Byte, carry flag is set, use BCS (branch carry set)
When A < Byte, carry flag is clear, use BCC (branch carry clear)
When A != Byte, zero flag is clear, use BNE (branch not equal)

by on (#80146)
that should do the trick, ill make a post if i have any more problems related to variables in the near future

by on (#80149)
lol, its the near future. can you show me some example code please

something under A's push action like

If A then

LDA #$01
STA shooting

else

LDA #$00
STA shooting

by on (#80157)
Do you know how to read the controller? When you read the controller, you typically end up with a variable that contains the state of all the buttons (each bit is a button). What you need to do is look at a specific bit in this variable (the bit that corresponds to the button you want to check) and make a decision based on it. Something like this:

Code:
   lda ControllerState
   and #%00000001 ;<- change this depending on the button you want to check
   beq ButtonNotPressed
   
   ;BUTTON IS PRESSED

   jmp Done ;<- this is needed to skip over the "not pressed" code

ButtonNotPressed:

   ;BUTTON IS NOT PRESSED

Done:

This is the basic structure of an "IF" in assembly, but the beuty of assembly is that you are not restricted to these basic structures, and you can take shortcuts. In this particular case, you could do something like this:

Code:
   ldx #$00 ;assume "Shooting" will be 0
   lda ControllerState
   and #BUTTON_A ;I'm using a constant here
   beq StoreShooting ;branch if it really is supposed to be 0
   inx ;A is pressed, so "Shooting" needs to be 1
StoreShooting:
   stx Shooting

by on (#80158)
lol, i got reading the controller down already, i was just typing If a to type less :)

by on (#80159)
do you know how to do what i asked though?

by on (#80160)
I edited my post with more useful info.

by on (#80162)
I don't think this is the best way to control the shooting though. The "shooting" variable will be set to 1 when the player presses A, but since he will release it soon after, "shooting" will become 0. According to the logic you posted before that would stop the bullet.

I think your frame logic should be more like this:

Code:
IF A IS PRESSED AND THERE ARE FREE BULLETS
   RESET THE NEXT FREE BULLET TO THE PLAYER'S POSITION
   ACTIVATE THAT BULLET
END IF

FOR EACH ACTIVE BULLET
   MOVE BULLET UP
   IF BULLET COLLIDED WITH ENEMY
      KILL ENEMY
      DEACTIVATE BULLET
   END IF
NEXT BULLET


EDIT: Also, be sure to read this post and the ones after it, because they explain how to avoid repeated button detection. If you don't do what's explained in that thread, whenever someone presses "A" at least 5 or so bullets will be shot at once. Ideally, you will only fire bullets when the fire button transitions from not pressed to pressed, and those posts explain how to detect that transition.

by on (#80170)
I dont know why, i just cant get this to work, ill figure it out though, hopefully :)

And i already know how to avoid joypad issues such as multiple frame detection and such

by on (#80181)
The if statement thing you were asking about goes like this:

Code:
    lda shooting
    cmp #1
    bne skip_shooting_down
    lda #0
    sta shooting
skip_shooting_down:


For an if-then-else, you would do it more like this:

Code:
    lda shooting
    cmp #1
    bne else_clause
    ; DO STUFF
    jmp end_else
else_clause:
    ; DO OTHER STUFF
end_else:

by on (#80191)
ill try this in a few days, im busy for now

but thanks :)

by on (#80535)
Well, i've been pretty busy lately but recently, like 10 minutes ago, i sat down to work on this. I am starting to understand variables pretty well now, and how how they work in 6502 ASM. I decided to go with the .rsset and .rs method because it seems to be the best to use. This is what i cam up with for my problem (this will most likely be changed as the shooting system will be more efficient, in fact there isnt even one yet :) ):

Code:
ReadA:
  LDA $4016
  AND #%00000001
  BEQ ReadADone

  LDA #$01
  STA shooting

  LDA #$00
  CMP shooting
  BEQ DontShoot

  LDA #$01
  CMP shooting
  BEQ Shoot

DontShoot:
  LDA #$FE
  STA $0204

Shoot:
  LDA #$80
  STA $0204

ReadADone:


this just stores a bullet off screen when a is not pressed, then when it is it moves to the middle of the screen. Next i will set up a shooting system.

by on (#80539)
Make a controller reading routine that stores button states in a variable. I think tutorials and notes should be put up somewhere, as it seems nobody new to programming uses them at all. They just hardwire it into the engine. You reading GBAGuys or whoevers tutorials? Heh, but I guess it works. :)

by on (#80540)
I used nerdy nights to get started, i also have many txt files and stuff i read. I like this way of reading a controller, but hey, knowing another way wont hurt :D

by on (#80541)
dsv101 wrote:
I used nerdy nights to get started, i also have many txt files and stuff i read. I like this way of reading a controller, but hey, knowing another way wont hurt :D


This won't translate well to any game of size though, I'd suggest you do a JSR to a controller reading routine and then just read the button states and edit it there. There's no game to my knowledge that does hard coding of it like that, it's a doomed way to write it. Heh. :P

by on (#80542)
lol, for now, this, later that :)

by on (#80543)
I'm sure all other decent programmers will advise against that.

by on (#80552)
The only reason beginners find this weird method of controller reading easy is because some famous beginner tutorial uses it, but in reality it makes no sense at all to use that.

The simplest and most common way to read controller is to shift the states of all buttons into a variable and check that variable for the rest of the frame. There are 8 buttons, there are 8 bits in a byte, the most logical thing to do is use a bit to indicate the state of each button.

Also, it's good practice to separate the game logic from the hardware interactions. Say that for some reason you decide to convert your game to another platform that uses a 6502. As your code is now, you'll have to scan through all of the code looking for interactions with the $4016 register and change each one, because there will be a lot of them. If instead you made a separate subroutine whose only purpose was to read $4016 and put the button states in a byte, that would be all you'd have to change, because your game logic would only need that byte, regardless of where its contents came from. Your game logic wouldn't be tied to the hardware anymore, it's just common sense.

The same goes for video and audio. You must have a set of routines to deal with the PPU and the APU, but they should be as separated from the game logic as possible. For example, if your game uses missiles, the code that moves the missiles shouldn't be the same code that configures the OAM to display the missiles' sprites... The missile code should call a routine that draws sprites based on a set of parameters (such as a pointer to the meta-sprite definition), and this routine alone should mess with the OAM.

This is how professional games work. Even in AS3 (which you mentioned you know) you should work like this. If you program everything carelessly just to get results on the screen ASAP you'll end up with unmaintainable code, and this is one of the big reasons people give up on projects.

by on (#80567)
Here you go, controller reading routine: (I feel like a type this a lot.)

Code:
[Put this in RAM somewhere]
ControllerButtonStates: .rs 0; Reserve a byte for the 8 button state bits from $4016.

LDX #$01
STX $4016
DEX
STX $4016
LDX #$08
ControllerReadUpdateLoop:
LDA $4016 ;Get controller button.
LSR A ;Put into the CARRY bit.
ROL ControllerButtonStates ;Update the button state. Once done 8 times, the value will be updated completely.
DEX ;X=X-1
BNE ControllerReadUpdateLoop ;Make it loop 8 times. If not done, get more button states.
RTS ;Done, ControllerButtonStates now holds all button states.


And now, you have a controller reading program for every game that uses just the brick controller. All you have to do is a JSR and you read the buttons you need them. What happens when you have to read and see if left+right are pressed? With this, instead of doing the right 4016 read, another 4016 read, a 4016 reset then shift back to where you were, it's rediculous. With this, you can check multiple states easily and you're not hoping back and forth on 4016, which you'll run into later following that way.

by on (#80568)
If you make a controller reading routine like the one 3gengames posted, to check a button you just have to do something like this:

Code:
   LDA ControllerButtonStates ;get the button states
   AND #%00010000 ;check the 5th bit (don't remember which button this is, sorry!)
   BEQ NotPressed ;skip if the button is not pressed

   ;THE BUTTON IS PRESSED! DO SOMETHING HERE!

NotPressed:

Much simpler than reading $4016 a million times per frame, don't you think?

by on (#80585)
Guys Guys Guys, i said id do that later, by later i meant not right then, not as in i don't care ill keep it my way for now.

Anyway, thanks for the information and the example code :)

by on (#80588)
We're just trying to keep you from creating bad habits. What you currently have is pretty bad, and even in a tech demo will probably get out of hand soon. "Do it right from the start" is the advice we're giving you.

If you take a minute (literally) to carefully read what we told you (instead of just ignoring it or saving it for later), I seriously doubt you'll fail to see the advantages of doing it the proper way.

by on (#80592)
i read it all, i just have to do some other things to get me familiar with NES Programming which what you told me will come into my code soon.

I never ignore advice, good or bad, it's just how i am :)

Now i feel that im creating a bad vibe with you guys, i'm sorry :/

by on (#80594)
Thank you tokumaru and 3gengames for the positive encouragement here! :D

by on (#80595)
dsv101 wrote:
Now i feel that im creating a bad vibe with you guys, i'm sorry :/

No bad vibe, don't worry...

You can do as you want now that the advice is given. If you have read what we said and still think that for now you should read the controller your way, then that's your choice. Sometimes we need first hand experience to understand why something is good/bad as opposed to just trusting others.

I assure you that soon you'll feel the need to switch to the other method! 8)

by on (#80599)
If you make the routine use Y for the counter and X to loop which controller to read, then you can also read both controllers if you save another byte and on the ROL and LSR use the mode $4016,X and then ControllerButtons,X and read both controllers inside one loop with about 5 extra lines of code. My game read 4 controllers going through only 2 loops and then passes them to my main program. It a huge help to be able to do so much with a simple JSR, you'll learn the significance of using these types of techniques as your programs get bigger and you get more experienced.

by on (#80604)
thanks or the advice guys :)

by on (#80612)
It's possible to use the output byte itself as the counter by prefilling it with $01. The ROL clears the carry until after the eighth read, when it sets the carry to true.

In addition, systems with hardwired controllers (such as the original Family Computer sold in Japan) put the hardwired controller on bit 0 and the plugged-in controller on bit 1. Reading the pad produces $x1 if a button on a hardwired controller is pressed or $x2 if the corresponding button on the plugged-in controller is pressed. So AND with $03 to ignore all other bits and compare with 1 to set carry if one or both of the buttons is pressed.

Here's the code I use, which modifies neither X nor Y (for various reasons related to postprocessing that I'll teach about later):
Code:
JOY1 = $4016
JOY2 = $4017

read_both_pads:
  lda #$01
  sta keys_held_2p  ; set up so that the 8th ROL will SEC
  sta JOY1          ; latch button states into the pads'
  lda #0            ; shift registers
  sta JOY1
  loop:
    lda JOY1
    and #$03   ; on Famicom, 1 means a press on the hardwired
    cmp #1     ; pad and 2 means a press on a plugged-in pad
    rol keys_held_1p
    lda JOY2
    and #$03
    cmp #1
    rol keys_held_2p  ; after eight of these, the 1 bit from
    bcc loop          ; $01 has made its way to carry
  rts

by on (#80619)
I've never even though of clearing the pads before, that's a great idea! I'm about to do that in my code. :D But even I am confused on the AND #$03 and then CMP #$01. Shouldn't you can the big you want since any unwanted bit read from DB2 will make a true read on the single value since it wasn't cleared from the AND? And in that case, it'd just be better to LDA and then ROL, right?

by on (#80621)
3gengames wrote:
I am confused on the AND #$03 and then CMP #$01

Some Famicom controllers return the button states in bit 1 instead of bit 0, so the AND #$03 is meant to keep the two bits that can possibly contain button states. The CMP #$01 detects whether a button is pressed regardless of the bit. If either bit is set, the button is pressed.

by on (#80624)
tokumaru wrote:
3gengames wrote:
I am confused on the AND #$03 and then CMP #$01

Some Famicom controllers return the button states in bit 1 instead of bit 0, so the AND #$03 is meant to keep the two bits that can possibly contain button states. The CMP #$01 detects whether a button is pressed regardless of the bit. If either bit is set, the button is pressed.


Okay, but the controllers are hardwired on, wouldn't that mean any controller attached to the expansion port would interfere wit hthe hardwired controller and vice versa?

by on (#80627)
Conventionally, the hardwired controllers on an original Famicom (or the ones plugged into the front ports on the AV model) are numbered 1 and 2, and the plug-in controllers 3 and 4. Player 1 may use controller 1 (first hardwired controller) or 3 (first plug-in controller), and player 2 may use controller 2 or 4. As I understand it, only a four-player game treats all four as distinct input sources.

by on (#80628)
Okay, I guess that makes sense, although on NES I guess the data bits are different, so that's why it was confusing. Okay, cool.

by on (#80630)
tokumaru wrote:
3gengames wrote:
I am confused on the AND #$03 and then CMP #$01

Some Famicom controllers return the button states in bit 1 instead of bit 0, so the AND #$03 is meant to keep the two bits that can possibly contain button states. The CMP #$01 detects whether a button is pressed regardless of the bit. If either bit is set, the button is pressed.


CMP is magical? :? How does CMP #$01 detect whether a button is pressed rehgardless of the bit?

by on (#80632)
unregistered wrote:
CMP is magical? :? How does CMP #$01 detect whether a button is pressed rehgardless of the bit?

The "magic" is that CMP #$01 is basically equivalent to C <- !Z and CMP #$80 is basically equivalent to C <- N

You can quite often make your code smaller/faster using those two tricks.

by on (#80634)
I haven't looked at the code, but I suspect it is using BCS (Branch if Carry Set). After the CMP (CoMPare) instruction if the value in the A register is greater than or equal to the value in memory (in this case the value 1) the Carry flag will be set.

So basically this lets you say "if the controller data is greater than zero".

There's a faster way though. After your lda instruction, use BEQ (Branch if EQual) or BNE (Branch if Not Equal). After a load instruction the Zero flag will be set if the value loaded is zero, clear otherwise.

Example:

Code:
ldx #8
polling_loop:
  asl controller_state
  lda reg_ctrl_port1
  beq next
  inc controller_state
next:
  dex
  bne polling_loop

by on (#80637)
qbradq wrote:
There's a faster way though. After your lda instruction, use BEQ (Branch if EQual) or BNE (Branch if Not Equal). After a load instruction the Zero flag will be set if the value loaded is zero, clear otherwise.

Nope, that doesn't work, you have to use AND because the top bits are not connected when reading $4016, so they usually (if cart doesn't have resistors on the data bus, like PowerPak) return the top bits of the value that was previously on the data bus (most often $4x). See http://nesdev.com/rom.txt for more details.

by on (#80639)
Oh, wow, thanks for the info TheFox :D

So then the code I posted becomes this:

Code:
ldx #8
polling_loop:
  asl controller_state
  lda reg_ctrl_port1
  and #$89
  beq next
  inc controller_state
next:
  dex
  bne polling_loop


Or should the AND mask be different?

by on (#80640)
unregistered wrote:
How does CMP #$01 detect whether a button is pressed rehgardless of the bit?

The AND #$03 clears all bits but the lowest 2, which means that the possible values for the result are:

%00000000 (decimal 0) (no button pressed on either controller)
%00000001 (decimal 1) (pressed on controller 1, not pressed on controller 3)
%00000010 (decimal 2) (not pressed on controller 1, pressed on controller 3)
%00000011 (decimal 3) (pressed on both controller)

The CMP instruction is a subtraction, if the result of the subtraction is positive the carry will be set. Since we're subtracting 1, the only way the result will be negative is when the value is 0, i.e. no button is pressed on either controller. In the other 3 cases the carry will be set, accurately reflecting the fact that the button is pressed on at least one of the controllers..

by on (#80642)
Bregalad wrote:
The "magic" is that CMP #$01 is basically equivalent to C <- Z and CMP #$80 is basically equivalent to C <- N

You can quite often make your code smaller/faster using those two tricks.


Ooh, i get it now. C stands for the carry flag, Z is zero flag, and N stands for the non-zero flag. Now I need to read tokumaru's reply again. :)

by on (#80644)
unregistered wrote:
and N stands for the non-zero flag

Not quite, it stands for the Negative flag.

And qbradq don't post some nonsense code like that. There is no way any of it will ever work. You need to write 1->0 to $4016, and read it 8 times, there is no way arround that.
DON'T EVER use RMW instructions on registers.
The only faster thing you can do is do it in an unrolled loop.

by on (#80657)
Bregalad wrote:
And qbradq don't post some nonsense code like that. There is no way any of it will ever work. You need to write 1->0 to $4016, and read it 8 times, there is no way arround that.
DON'T EVER use RMW instructions on registers.
The only faster thing you can do is do it in an unrolled loop.


I think you're being a little harsh there. I didn't say that was a complete example. That's just the reading loop. And I didn't use a Read Modify Write instruction on a register. The only instruction that touches a register is LDA.

by on (#80658)
Bregalad wrote:
DON'T EVER use RMW instructions on registers.


I forgot about that when I suggested something like that for a faster controller reading routine, didn't think about it, but yeah don't use them, like me. And that code is pretty dumb truthfully. And using X to store the value 1 then 0 to 4016 is used by stuff and isn't widely used, I wish that was noted somewhere, instead of just using A and losing a whole 1 byte, heh. Just kidding, but it seems worth the gain when you're strapped for ROM. Although there's probably many more ways to go around with this stuff, in the mean time lets post them all and figure out another topic to blow up! :D :wink: lol

by on (#80667)
tokumaru wrote:
unregistered wrote:
How does CMP #$01 detect whether a button is pressed rehgardless of the bit?

The AND #$03 clears all bits but the lowest 2, which means that the possible values for the result are:

%00000000 (decimal 0) (no button pressed on either controller)
%00000001 (decimal 1) (pressed on controller 1, not pressed on controller 3)
%00000010 (decimal 2) (not pressed on controller 1, pressed on controller 3)
%00000011 (decimal 3) (pressed on both controller)

The CMP instruction is a subtraction, if the result of the subtraction is positive the carry will be set. Since we're subtracting 1, the only way the result will be negative is when the value is 0, i.e. no button is pressed on either controller. In the other 3 cases the carry will be set, accurately reflecting the fact that the button is pressed on at least one of the controllers..


Thanks! :D

by on (#80668)
Update Post:

I have a new member involved. His s/n is Cooshinator.

We have to go through a concept conversation and stuff, but the game may end up not being a space shooter, or it may. Who knows?

Anyway, our jobs are as follows

Me: Programmer

Cooshinator: GFX and Music

Time to restart, pay attention to every detail, and try that controller read loop and stuff you guys recommend highly :)

by on (#80682)
Quote:
I think you're being a little harsh there. I didn't say that was a complete example. That's just the reading loop. And I didn't use a Read Modify Write instruction on a register. The only instruction that touches a register is LDA.

Forget it, I just was in a very bad mood the other day because of a stupid physics exam.

For some reason I thought controller_state was some hardware resister but of course it's not. That's what I like to use plain register adress so that you can immediately see it's a register and avoid the confusion (and I'm dumb too). Also if you really inist on using a label instead of using $4016, it's a good idea to make the label all in caps which is commonly used for constants.

So yeah if you replace the and #$89 by and #$03 I think this will actually work. Although I'm not sure it's faster to tepples' solution (which happens to also be my solution). So yeah the AND mask should be different.

by on (#80689)
Honestly I didn't read pages 2 and 3 (and most of 4) so I probably shouldn't have said anything anyway. My actual controller reading routine is much different that this as well, but it only handles data on D0 ($4016 READ bit 0).

I made up the register name of the fly because I couldn't be bothered to look up the address :D

by on (#80744)
Me and Cooshinator came up with a question, how do you set a backgroud color and key out a color in sprites? I found a tutorial for putting tiles in the background, but i figured you should be able to set a background color.

by on (#80745)
The background color is always color 0. Which paint program or tile editor are you using to create your sprite cels?

by on (#80746)
yychr of course :)

by on (#80747)
also, it seems as if the first color of the palette is always keyed out, is this true?

by on (#80748)
dsv101 wrote:
Me and Cooshinator came up with a question, how do you set a backgroud color and key out a color in sprites? I found a tutorial for putting tiles in the background, but i figured you should be able to set a background color.

When background tiles use color 0, no matter the palette, the background color is displayed (color 0 of the first background palette). For sprites, the transparent color is always color 0. You can't even set an actual color for it when writing the palette, there is no internal memory to hold that information. Actually, if you try to set those colors, they'll be written to the corresponding places in the background palette, overwriting whatever you wrote there previously.

Also, note that even though there is physical memory to hold a different color 0 for each background palette, the one that always gets displayed is the one in the first palette. The others are never displayed during normal rendering.

by on (#80759)
ok cool, i think i got this :)

by on (#80762)
since a byte = 8 bits, how do i access each individual bit if i want to?

by on (#80763)
In short, you use AND to clear bits, ORA to set bits, and EOR to invert bits.

You can also use ASL/LSR/ROL/ROR to move a bit into the carry flag and check the carry flag (BCC/BCS), and using BPL/BMI is a common trick to check the state of the highest bit (even without any other operation, after an LDA is fine, such as you see with the common LDA $2002 / BPL loop)

by on (#80765)
ok man :)
Some sprites wont show
by on (#81594)
Some sprites wont show, and i dont see why.
The second set of 6 wont show, is my compiler screwing up, or am I an idiot?

Code:
sprites:                    ; y tile atr x

  .db $10, $00, $01, $10    ; $0200-$0203 Ship left half
  .db $10, $01, $01, $18    ; $0204-$0207 Shtp Second Half

  .db $10, $03, $01, $20    ; $0208-$020B Bullet
  .db $10, $03, $01, $28    ; $020C-$020F Bullet
  .db $10, $03, $01, $30    ; $0210-$0213 Bullet
  .db $10, $02, $01, $38    ; $0214-$0217 Bullet
  .db $10, $02, $01, $40    ; $0218-$021B Bullet
  .db $10, $02, $01, $48    ; $021C-$021F Bullet

  .db $20, $03, $01, $20    ; $0220-$0223 Bullet
  .db $20, $03, $01, $28    ; $0224-$0227 Bullet
  .db $20, $03, $01, $30    ; $0228-$022B Bullet
  .db $20, $02, $01, $38    ; $022C-$022F Bullet
  .db $20, $02, $01, $40    ; $0230-$0233 Bullet
  .db $20, $02, $01, $48    ; $0234-$0237 Bullet
Re: Some sprites wont show
by on (#81595)
dsv101 wrote:
Some sprites wont show, and i dont see why.
The second set of 6 wont show, is my compiler screwing up, or am I an idiot?


The data looks OK to me, how about pasting the code that's putting it in RAM and DMAing (or copying via $2003/$2004 perhaps) it to the PPU?

by on (#81596)
Open the ROM in Nintendulator (or some other debugger with PPU viewer) and see if the sprites appear in the sprite list. If not, single step through your code to find out why.

by on (#81597)
Are you enabling rendering, loading the palettes, and such?

by on (#81618)
Code:
LoadPalettes:
  LDA $2002
  LDA #$3F
  STA $2006
  LDA #$00
  STA $2006
  LDX #$00
LoadPalettesLoop:
  LDA palette, x
  STA $2007
  INX
  CPX #$20
  BNE LoadPalettesLoop



LoadSprites:
  LDX #$00
LoadSpritesLoop:
  LDA sprites, x
  STA $0200, x
  INX
  CPX #$20
  BNE LoadSpritesLoop

  LDA #%10000000
  STA $2000

  LDA #%00010000
  STA $2001

by on (#81619)
Are the sprites in the 1st graphics table? Other than that, looks perfectly fine to me.

by on (#81620)
Where's the:
Code:
   lda #2
   sta $4014


There's only code there to set up the sprite RAM area. Not that that is the problem...it's just hard to tell what might be wrong with only snippets.

EDIT: Nevermind in this case the problem is obvious after looking again:

Code:
LoadSpritesLoop:
  LDA sprites, x
  STA $0200, x
  INX
  CPX #$20
  BNE LoadSpritesLoop


You have way more than 32 bytes of sprite data...so you're cutting off the copy loop too early.

by on (#81621)
Do you see the "cpx #$20" line? That controls how many bytes you are loading into your sprite RAM. $20 is 32 in decimal, or 8 sprite's worth of data. You have 56 bytes of data for 14 sprites. So change the "cpx #$20" to "cpx #56" and it should all work.

Each time you add or remove sprites from that table you'll need to change that line. Sounds like a great use for an EQU statment.

Example:

Code:
.equ sprite_data_length 56
; 56 bytes of sprite data

; ...In your loading loop...
cpx #sprite_data_length


That way you'll only have to change the EQU line and not have to go hunting through your code.

Got ninja'ed, but yea

by on (#81622)
Damn, didn't think that was the problem. Sorry dude. But anyway, CPX compares X to a number, you go that right? When the INX and it ups it by 1, you compare to find the end. That makes sense right?

by on (#81624)
yes 3gen, i know what that does. I didnt cacy that #$20 in there like i should have, thanks guys.

by on (#81628)
Okay, just wanted to make sure you understood that. Is it working now okay?

by on (#81680)
indeed :)
Update
by on (#83091)
Okay, so this project has been avoided for quite some time by me, I plan to start back up as soon as these first few weeks of schools go by. I believe my graphics designer is starting a game development club, since I will join, I can work on the game at least once a week, regardless if I am busy or not.

Sorry peoples who were waiting to see some progress :)