It is currently Sun Oct 22, 2017 6:00 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 21 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: BUTTONS
PostPosted: Sat Aug 08, 2015 12:55 pm 
Offline

Joined: Sat Aug 08, 2015 12:39 pm
Posts: 3
I'm relatively new to programming and I have question regarding the buttons moving the sprites in my code posted below. The A button functions as I want it too but the B button does not. Essentially my A button moves my sprite to right which is I WANT it do however the B button will only move the sprite LEFT if press A and B at the same time. My question is how do I get the B button to move the sprite WITHOUT the having to press A.

essentially I want A button = Move right
B button = Move Left

here's the code

Code:
  .inesprg 1   ; 1x 16KB PRG code
  .ineschr 1   ; 1x  8KB CHR data
  .inesmap 0   ; mapper 0 = NROM, no bank swapping
  .inesmir 1   ; background mirroring
 

;;;;;;;;;;;;;;;

   
  .bank 0
  .org $C000
RESET:
  SEI          ; disable IRQs
  CLD          ; disable decimal mode
  LDX #$40
  STX $4017    ; disable APU frame IRQ
  LDX #$FF
  TXS          ; Set up stack
  INX          ; now X = 0
  STX $2000    ; disable NMI
  STX $2001    ; disable rendering
  STX $4010    ; disable DMC IRQs

vblankwait1:       ; First wait for vblank to make sure PPU is ready
  BIT $2002
  BPL vblankwait1

clrmem:
  LDA #$00
  STA $0000, x
  STA $0100, x
  STA $0200, x
  STA $0400, x
  STA $0500, x
  STA $0600, x
  STA $0700, x
  LDA #$FE
  STA $0300, x
  INX
  BNE clrmem
   
vblankwait2:      ; Second wait for vblank, PPU is ready after this
  BIT $2002
  BPL vblankwait2


LoadPalettes:
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA #$3F
  STA $2006             ; write the high byte of $3F00 address
  LDA #$00
  STA $2006             ; write the low byte of $3F00 address
  LDX #$00              ; start out at 0
LoadPalettesLoop:
  LDA palette, x        ; load data from address (palette + the value in x)
                          ; 1st time through loop it will load palette+0
                          ; 2nd time through loop it will load palette+1
                          ; 3rd time through loop it will load palette+2
                          ; etc
  STA $2007             ; write to PPU
  INX                   ; X = X + 1
  CPX #$20              ; Compare X to hex $10, decimal 16 - copying 16 bytes = 4 sprites
  BNE LoadPalettesLoop  ; Branch to LoadPalettesLoop if compare was Not Equal to zero
                        ; if compare was equal to 32, keep going down



LoadSprites:
  LDX #$00              ; start at 0
LoadSpritesLoop:
  LDA sprites, x        ; load data from address (sprites +  x)
  STA $0200, x          ; store into RAM address ($0200 + x)
  INX                   ; X = X + 1
  CPX #$99              ; Compare X to hex $20, decimal 32
  BNE LoadSpritesLoop   ; Branch to LoadSpritesLoop if compare was Not Equal to zero
                        ; if compare was equal to 32, keep going down
             
             

  LDA #%10000000   ; enable NMI, sprites from Pattern Table 1
  STA $2000

  LDA #%00010000   ; enable sprites
  STA $2001

Forever:
  JMP Forever     ;jump back to Forever, infinite loop
 
 

NMI:
  LDA #$00
  STA $2003       ; set the low byte (00) of the RAM address
  LDA #$02
  STA $4014       ; set the high byte (02) of the RAM address, start the transfer


LatchController:
  LDA #$01
  STA $4016
  LDA #$00
  STA $4016      ; tell both the controllers to latch buttons


ReadA:
  LDA $4016       ; player 1 - B
  AND #%00000001  ; only look at bit 0


ReadA1:
  BEQ ReadA1
  LDA $0203 ; load sprite 1 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $0203 ; save sprite 1 position
  LDA $0207 ; load sprite 2 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $0207 ; save sprite 2 position
  LDA $020B ; load sprite 3 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $020B ; save sprite 3 position
  LDA $020F ; load sprite 4 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $020F ; save sprite 4 position
  LDA $0213 ; load sprite 5 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $0213 ; save sprite 5 position
  LDA $0217 ; load sprite 6 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $0217 ; save sprite 6 position
  LDA $021B ; load sprite 7 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $021B ; save sprite 7 position
  LDA $021F ; load sprite 8 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $021F ; save sprite 8 position
  LDA $0223 ; load sprite 9 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $0223 ; save sprite 9 position
  LDA $0227 ; load sprite 10 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $0227 ; save sprite 10 position
  LDA $022B ; load sprite 11 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $022B ; save sprite 11 position
  LDA $022F ; load sprite 12 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $022F ; save sprite 12 position
  LDA $0233 ; load sprite 13 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $0233 ; save sprite 13 position
  LDA $0237 ; load sprite 14 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $0237 ; save sprite 14 position
  LDA $023B ; load sprite 15 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $023B ; save sprite 15 position
  LDA $023F ; load sprite 16 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $023F ; save sprite 16 position
  LDA $0243 ; load sprite 17 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $0243 ; save sprite 17 position
  LDA $0247 ; load sprite 18 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $0247 ; save sprite 18 position

ReadB:
  LDA $4016       ; player 1 - B
  AND #%00000001  ; only look at bit 0

ReadB1

  BEQ ReadB1
  LDA $0203 ; load sprite 1 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $0203 ; save sprite 1 position
  LDA $0207 ; load sprite 2 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $0207 ; save sprite 2 position
  LDA $020B ; load sprite 3 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $020B ; save sprite 3 position
  LDA $020F ; load sprite 4 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $020F ; save sprite 4 position
  LDA $0213 ; load sprite 5 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $0213 ; save sprite 5 position
  LDA $0217 ; load sprite 6 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $0217 ; save sprite 6 position
  LDA $021B ; load sprite 7 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $021B ; save sprite 7 position
  LDA $021F ; load sprite 8 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $021F ; save sprite 8 position
  LDA $0223 ; load sprite 9 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $0223 ; save sprite 9 position
  LDA $0227 ; load sprite 10 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $0227 ; save sprite 10 position
  LDA $022B ; load sprite 11 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $022B ; save sprite 11 position
  LDA $022F ; load sprite 12 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $022F ; save sprite 12 position
  LDA $0233 ; load sprite 13 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $0233 ; save sprite 13 position
  LDA $0237 ; load sprite 14 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $0237 ; save sprite 14 position
  LDA $023B ; load sprite 15 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $023B ; save sprite 15 position
  LDA $023F ; load sprite 16 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $023F ; save sprite 16 position
  LDA $0243 ; load sprite 17 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $0243 ; save sprite 17 position
  LDA $0247 ; load sprite 18 position
  SEC ; make sure carry flag is set
  SBC #$02 ; A = A - 1
  STA $0247 ; save sprite 18 position
ReadBDone:        ; handling this button is done



 
  RTI             ; return from interrupt
 
;;;;;;;;;;;;;; 
 
 
 
  .bank 1
  .org $E000
palette:
   .byte $33,$36,$30,$0F,$30,$0F,$0F,$0F,$33,$0F,$0F,$0F,$33,$0F,$0F,$0F
   .byte $33,$36,$30,$0F,$30,$0F,$0F,$0F,$33,$0F,$0F,$0F,$33,$0F,$0F,$0F

sprites:
     ;vert tile attr horiz
  .db $80, $00, $00, $80   ;sprite 0
  .db $80, $01, $00, $88   ;sprite 1
  .db $80, $02, $00, $90   ;sprite 2
  .db $88, $0F, $00, $80   ;sprite 3
  .db $88, $10, $00, $88   ;sprite 4
  .db $88, $11, $00, $90   ;sprite 5
  .db $90, $1E, $00, $80   ;sprite 6
  .db $90, $1F, $00, $88   ;sprite 7
  .db $90, $20, $00, $90   ;sprite 8
  .db $98, $2F, $00, $80   ;sprite 9
  .db $98, $30, $00, $88   ;sprite 10
  .db $98, $31, $00, $90   ;sprite 11
  .db $A0, $43, $00, $80   ;sprite 12
  .db $A0, $44, $00, $88   ;sprite 13
  .db $A0, $45, $00, $90   ;sprite 14
  .db $A8, $58, $00, $80   ;sprite 15
  .db $A8, $59, $00, $88   ;sprite 16
  .db $A8, $5A, $00, $90   ;sprite 17

  .org $FFFA     ;first of the three vectors starts here
  .dw NMI        ;when an NMI happens (once per frame if enabled) the
                   ;processor will jump to the label NMI:
  .dw RESET      ;when the processor first turns on or is reset, it will jump
                   ;to the label RESET:
  .dw 0          ;external interrupt IRQ is not used in this tutorial
 
 
;;;;;;;;;;;;;; 
 
 
  .bank 2
  .org $0000
  .incbin "test.chr"   ;includes 8KB graphics file from SMB1


Top
 Profile  
 
 Post subject: Re: BUTTONS
PostPosted: Sat Aug 08, 2015 2:05 pm 
Offline
User avatar

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 1020
Code:
ReadA:
  LDA $4016       ; player 1 - B
  AND #%00000001  ; only look at bit 0


ReadA1:
  BEQ ReadA1


You read A button. AND it to only look at bit zero. If bit 0 is 1 (A button is pressed) the code continues down below (that is to say that it does not branch, because the result of the AND was non zero). If bit 0 is 0 (A button is not pressed), your code gets trapped in an infinite loop (that is to say that it does branch, because the result of the AND was zero). It branches to A1 which is directly above the branch, and there's nothing to change the zero flag in between A1 and the branch. So it branches to the label right above the branch, branches again, etc.

You probably want something more like this:
Code:
ReadA:
  LDA $4016       ; player 1 - B
  AND #%00000001  ; only look at bit 0
  BEQ ReadB

This make is so that if A is pressed, it won't branch and run the code underneath. If A is pressed, it will skip that stuff and try to read B.

Note that you have a similar infinite loop trap for B, so you'll have to branch to readbdone for that.

_________________
https://kasumi.itch.io/indivisible


Top
 Profile  
 
 Post subject: Re: BUTTONS
PostPosted: Sat Aug 08, 2015 2:07 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1785
Location: DIGDUG
You have an infinite loop if A isn't pressed.

Code:
ReadA1:
  BEQ ReadA1


Edit: the only reason it doesn't crash your program completely, is that a new NMI is triggered inside the old NMI. Your stack is probably going crazy as well, because 60 times a second it's writing return addresses to the stack, but never returning to them.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
 Post subject: Re: BUTTONS
PostPosted: Sun Aug 09, 2015 12:53 am 
Offline

Joined: Sat Apr 12, 2014 12:11 pm
Posts: 120
Location: Gothenburg, Sweden
Ah. The good old NESASM3. How I miss that. :wink:
I noticed this

Code:
clrmem:
  LDA #$00
(..)
  LDA #$FE
  STA $0300, x
  INX
  BNE clrmem


while your NMI does this
Code:
  LDA #$00
  STA $2003       ; set the low byte (00) of the RAM address
  LDA #$02        ;<- .. shouldn't this be #$03 instead?
  STA $4014       ; set the high byte (02) of the RAM address, start the transfer


I don't want to post code snippets that will probably be over your head at this stage.
All I can say is that you should not have these kinds of conditional branches in your NMI.

_________________
I´ve got %01100011 problems but the BITs aint one.


Top
 Profile  
 
 Post subject: Re: BUTTONS
PostPosted: Sun Aug 09, 2015 5:18 am 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 808
Location: Sweden
Although not related to your problem but you should read both bit 0 and bit 1 of $4016 and $4017, so that external controllers are also read. It's something that Nerdy Nights doesn't teach you, but it's good practice.

Code:
  LDA $4016
  AND #%00000011  ; only look at bit 0 and bit 1


This allows us with external controllers to play your game as well.


Top
 Profile  
 
 Post subject: Re: BUTTONS
PostPosted: Sun Aug 09, 2015 8:26 pm 
Offline

Joined: Sat Aug 08, 2015 12:39 pm
Posts: 3
Thanks for the help. After browsing around various forums I found what I believed to be the answer to my problem with the buttons and sure enough it was the answer. This is what I ended up doing to get the buttons to work the way I wanted.

Code:
 ................
.......................
ReadA:
  LDA $4016       ; player 1 - B
  AND #%00000011  ; only look at bit 0
  BNE ReadA1
  JMP ReadB
ReadA1:
  LDA $0203 ; load sprite 1 position
  CLC ; make sure carry flag is set
  ADC #$01 ; A = A - 1
  STA $0203 ; save sprite 1 position
........................
........................


Top
 Profile  
 
 Post subject: Re: BUTTONS
PostPosted: Sun Aug 09, 2015 8:29 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1785
Location: DIGDUG
Not to be too picky. But CLC makes sure the carry flag is "clear", ie 0.

You seem to be using it correctly, your comment about it was wrong.

Also, I don't think you fully grasp how button reads work...

(...edited out...)

nevermind. maybe I don't either. I was going to post code, but I think I'll review it again.

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Last edited by dougeff on Sun Aug 09, 2015 8:45 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: BUTTONS
PostPosted: Sun Aug 09, 2015 8:53 pm 
Offline

Joined: Sat Aug 08, 2015 12:39 pm
Posts: 3
You are correct in your assumption that I don't fully understand how button reads work. Like I said earlier though I am fairly new and rather inexperienced when it comes to programming but i am willing to learn and not opposed to criticism.


Top
 Profile  
 
 Post subject: Re: BUTTONS
PostPosted: Sun Aug 09, 2015 9:06 pm 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1785
Location: DIGDUG
Anyway...the standard way to read button presses is to read 8 times and roll / shift the right-most bit into a RAM location. Then you have this information until the next frame. Each read is for each of the 8 buttons (on controller 1)

http://wiki.nesdev.com/w/index.php/Controller_Reading

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
 Post subject: Re: BUTTONS
PostPosted: Sun Aug 09, 2015 9:43 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10066
Location: Rio de Janeiro - Brazil
I'm starting to think that the way these beginner tutorials approach such basic tasks does more harm than good sometimes. Most of what is taught is done in a messy way that doesn't expand gracefully into a full game.

Reading buttons and taking actions based on their states is a good example of this. A lot of people come here with this kind of spaghetti code, with button reads mixed with direct OAM manipulation that is totally impractical to maintain. I can't even accept that this is easier for a beginner to understand than if the whole thing was broken up in smaller tasks, like just reading the controller, then just moving the objects, and finally just drawing the sprites. I simply can't accept that someone would think that mixing those 3 things together could result in something that's easier to comprehend than if the tasks were dealt with separately in a modular way.

Another example of bad program design used in beginner tutorials is having the whole "game" logic inside the NMI, before the PPU updates. The NES is already a relatively slow machine, where you normally have about 27,500 cycles for the game logic and about 2,273 cycles for PPU updates every frame, but the way these tutorial setup things you end up with only the 2,273 cycles for both logic and updates! You can't possibly turn that into a decent game.

As I see it, the correct approach to input handling is this:

First, just read the controller. Simply do 8 reads from the controller port and shift the bits into a buffer byte (an NES controller has 8 buttons, a byte has 8 bits - it's a perfect match). There's no need to take any actions based on those buttons right away. This not only makes your code easier to understand an maintain, but it also gives you more possibilities... having the states of the buttons saved somewhere you can easily check for the rest of the frame is a way to allow different (and organized!) parts of your program to peek into those states and reacting to them, each at the more appropriate time and even multiple times if necessary, instead of shoving everything together in an impossible to follow sequence of decisions.

Then, just process the game entities. If there's an enemy that moves around, write some AI code for it so it can make its own decisions and move accordingly. As for the play, now is the time to peek into the controller byte and move it according to that. Normally you'd also consider physics, collisions and the player's state as well, depending on the style of the game. Note that this is about game entities, we're not talking about sprites yet. A sprite is a visual representation of a game object, but it's important to note that they shouldn't be the same thing.

OK, now that the player exists in the game world and can be moved around, it's time to draw it. This is when sprites come into play. We know the player's coordinates, so it's perfect possible for us to draw some sprites around those coordinates to represent it. This is normally done with a table of sprite tiles and offsets (i.e. metasprites), where the offsets are added to the object's coordinates to generate the final sprite coordinates.


Top
 Profile  
 
 Post subject: Re: BUTTONS
PostPosted: Mon Aug 10, 2015 3:31 am 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 808
Location: Sweden
tokumaru wrote:
I'm starting to think that the way these beginner tutorials approach such basic tasks does more harm than good sometimes. Most of what is taught is done in a messy way that doesn't expand gracefully into a full game.

Having learned from Nerdy Nights myself I both agree and disagree with you. It's not ideal but it's the best newbie tutorials I found for making NES games. Some of this spaghetti is necessary stepping stones before you can learn to make more efficient and readable controller reading and input handling code. If you look in the first tutorials you can see that they teach you how to draw BG graphics manually without loops just so you understand what you are doing. Later they teach you how to do it much faster and smaller with loops. The everything in NMI approach is probably chosen because it's the simplest approach. But personally I thought it would make more sense to use that "Forever" loop for logic (since that's what you would do in high level programming where you don't have to use interrupts).

Although when you are about to make your Pong game at the end of the tutorial your code will be a large mess (especially for such a simple game like Pong), and you just have to learn how to make it more efficient yourself by reading forums like this and the Nesdev wiki.

The sound tutorial on Nerdy Nights however, besides teaching you how to make a pretty advanced sound engine, DOES teach you (although indirectly since it's mostly about sound) how to separate game logic and graphics drawing, and also how to use draw buffers and stuff.


Top
 Profile  
 
 Post subject: Re: BUTTONS
PostPosted: Mon Aug 10, 2015 5:59 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10066
Location: Rio de Janeiro - Brazil
Pokun wrote:
Having learned from Nerdy Nights myself I both agree and disagree with you. It's not ideal but it's the best newbie tutorials I found for making NES games.

Yeah, it definitely has its merits, I just can't help noticing that a lot of people come here having trouble with the far from ideal program structure used in that tutorial.

And when I say "far from ideal" I don't mean "unoptimized code so newbies can understand it better", I really mean harder to maintain and understand, and thus poorly suited to be expanded into a real game. I honestly believe that teaching the tasks separately (and keeping them that way, not just introducing the concepts separately only to throw everything together in a messy routine soon after) makes things not only easier to understand but also makes the code easier to maintain and more similar to an actual game.

Quote:
Some of this spaghetti is necessary stepping stones before you can learn to make more efficient and readable controller reading and input handling code.

I disagree. I'm not talking about efficiency, I'm talking about chaining smaller, self-contained tasks rather than mixing them into a code soup. I fail to see how spagetti code can make something simpler to understand... Newbies often can't follow 6502 code very well yet, and I hardly think that branching like crazy and doing multiple things at the same time helps.

Quote:
The everything in NMI approach is probably chosen because it's the simplest approach.

Everything in the NMI is a perfectly valid approach, running the game logic during VBlank isn't. It violates a very basic NES develoment rule and is completely unsuited for doing anything more complex than moving a dumb sprite around. It scales poorly.

Quote:
But personally I thought it would make more sense to use that "Forever" loop for logic (since that's what you would do in high level programming where you don't have to use interrupts).

Personally I'd get rid of the confusing forever loop (it looks like a dead end) and have actual game logic there, with the NMI simply setting a flag to indicate when VBlank starts. Having the game logic and the VBlank handler in the main thread is much more versatile, scales much better, and is equaly simple. It only breaks when the game logic starts taking longer than a frame to finish.


Top
 Profile  
 
 Post subject: Re: BUTTONS
PostPosted: Mon Aug 10, 2015 6:18 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19115
Location: NE Indiana, USA (NTSC)
Pokun wrote:
The everything in NMI approach is probably chosen because it's the simplest approach.

But how simple is it to explain that you have to do it in what is conceptually a 4, 1, 2, 3 order?

NMI entry:
Push all registers
4. Push video memory updates to PPU
1. Read controller
2. Move game objects
3. Prepare video memory updates
Pop all registers
Return


Top
 Profile  
 
 Post subject: Re: BUTTONS
PostPosted: Mon Aug 10, 2015 7:27 am 
Offline
User avatar

Joined: Fri May 08, 2015 7:17 pm
Posts: 1785
Location: DIGDUG
Not to confuse the OP. But, when I commented earlier, I looked up some actual games and how they do button reads, (SMB3), and noticed that it shifts 2 bits each read...the R bit into one RAM address, the next to right bit into a different one. Why is this? My guess would be to accommodate 3rd party controllers. There's also some comment somewhere about expansion controllers for the Famicom using that bit. ?

_________________
nesdoug.com -- blog/tutorial on programming for the NES


Top
 Profile  
 
 Post subject: Re: BUTTONS
PostPosted: Mon Aug 10, 2015 7:47 am 
Offline

Joined: Tue May 28, 2013 5:49 am
Posts: 808
Location: Sweden
Yes it's for the Famicom's expansion port. Unless you make a 3 or 4 player game you should always read both bits. Otherwise Famicom owners like me can't use any other controllers than the built-in ones. Sometimes I want to use an arcade stick but it only works with games that have proper controller reading.

tokumaru wrote:
Quote:
Some of this spaghetti is necessary stepping stones before you can learn to make more efficient and readable controller reading and input handling code.

I disagree. I'm not talking about efficiency, I'm talking about chaining smaller, self-contained tasks rather than mixing them into a code soup. I fail to see how spagetti code can make something simpler to understand... Newbies often can't follow 6502 code very well yet, and I hardly think that branching like crazy and doing multiple things at the same time helps.

What I mean is the part where he reads the controller buttons separately in order to teach you that the buttons are read in a certain order, instead of using ROL and stuff. It's similar of how he teaches you to load graphics manually until he teaches loops (with the exception that he never teaches a good controller reading routine in the end).
Otherwise I agree with you, there's really no point in mixing controller reading with input handling and object moving logic even when teaching (took me some time to get things structured enough in my Pong game). This is probably one of the bigger flaws of Nerdy Nights.

Quote:
Quote:
The everything in NMI approach is probably chosen because it's the simplest approach.

Everything in the NMI is a perfectly valid approach, running the game logic during VBlank isn't. It violates a very basic NES develoment rule and is completely unsuited for doing anything more complex than moving a dumb sprite around. It scales poorly.

Now I see what you mean, and I fully agree with you. You mean that he mixes things that needs to be in vblank with stuff that doesn't, inside the NMI. Instead of doing the graphics first, then the logic.

Quote:
Quote:
But personally I thought it would make more sense to use that "Forever" loop for logic (since that's what you would do in high level programming where you don't have to use interrupts).

Personally I'd get rid of the confusing forever loop (it looks like a dead end) and have actual game logic there, with the NMI simply setting a flag to indicate when VBlank starts. Having the game logic and the VBlank handler in the main thread is much more versatile, scales much better, and is equaly simple. It only breaks when the game logic starts taking longer than a frame to finish.

Sounds more like you just change the name of the main loop, then add some things that's necessary when doing this approach.
But yeah the "forever" label is a bit confusing, why not just call it "main" as that's a more common name for it.


Another flaw of Nerdy Nights is that he doesn't say a word about the init code he puts in each program you write. This makes you wonder if you missed something.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 21 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group