This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

moving the :p cursor

moving the :p cursor
by on (#235237)
Now that I know how to draw a sprite on the screen, as well as how to animate it in a simple way, My next goal is for FCEUX to respond to controls. I have not inserted any code related to the controller inputs; I'm simply giving the code for making the sprite appear:
Code:
.segment "HEADER"
    .byte "NES"
    .byte $1a
    .byte $02
    .byte $01
    .byte %00000000
    .byte $00
    .byte $00
    .byte $00
    .byte $00
    .byte $00,$00,$00,$00,$00

.segment "STARTUP"
.segment "CODE"

WAITVBLANK:
:
    BIT $2002
    BPL :-
    RTS

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

  JSR WAITVBLANK

clrmem:
  LDA #$00
  STA $0000, x
  STA $0100, x
  STA $0200, x
  STA $0400, x
  STA $0500, x
  STA $0600, x
  STA $0700, x
  STA $0300, x
  INX
  BNE clrmem

JSR WAITVBLANK

Main:
LDX #$00
JSR StartupSprite
JSR LoadSprite
LDA #%10010000
STA $2000
LDA #%00010000
STA $2001

Forever:
JMP Forever

StartupSprite:
LDA #$80      ;Y coordinate
STA $10
LDA #$80      ;X coordinate
STA $11
RTS

LoadSprite:
LoadSpritePalette:
LDA #$3F
STA $2006
LDA #$00
STA $2006
LDA #$0F
STA $2007
LDA #$28
STA $2007
LDA #$16
STA $2007
LoadSpriteProperties:
LDA $10
STA $0200
LDA #$20
STA $0201
LDA #$00
STA $0202
LDA $11
STA $0203
RTS

VBLANK:         ;What should happen during a v-blank or nmi?
LDA #$00     
STA $2003
LDA #$02
STA $4014
RTI


.segment "VECTORS"
    .word VBLANK
    .word RESET
    .word 0

.segment "CHARS" 
   .incbin "ball.chr"


What code should I add to enable the capability to control the sprite looking like a tongue face (:p)? I've heard something about register $4016, but whenever I press the assigned keys, nothing happens nor do the values change in the hex editor for that address. Can someone help me with this? Thanks!

P.S.
I've attached the "ball.chr" just in case anyone is interested.
Re: moving the :p cursor
by on (#235238)
Just reading $4016 isn't enough (it would be nice if it were though). You need to tell $4016 that you want it to give you the data from the controller:

Code:
   .LatchController: ;Storing 1 then 0 to $4016 tells the controllers to send button data
     LDA #$01
     STA $4016
     LDA #$00
     STA $4016       ; tell both the controllers to latch buttons


Then you need to read $4016 in a loop to get the button data. each time you read $4016, it will tell you whether a particular button is pressed in bit 0. it's in this order: A, B, Select, Start, Up, Down, Left, Right. There are different ways to write the loop, but something simple like this would work fine:

Code:
      LDX #$08      ; prepare X for 8 button inputs for controller 1
      GetControllerLoop: ; Store buttons from controller 1 in a byte
         ASL controller ;shift existing bits left to make room for the next button press.
         LDA $4016, Y ;to get controller 2, set Y to 1
         AND #%00000001 ;bit 0 is the data for standard controller buttons.
         ORA controller ;combine it with the existing button presses.
         STA controller
         DEX
         BNE GetControllerLoop


I think I got this from Nerdy Nights, but I might have modified it, I don't remember.
Re: moving the :p cursor
by on (#235240)
gravelstudios wrote:
Just reading $4016 isn't enough (it would be nice if it were though). You need to tell $4016 that you want it to give you the data from the controller:

Code:
   .LatchController: ;Storing 1 then 0 to $4016 tells the controllers to send button data
     LDA #$01
     STA $4016
     LDA #$00
     STA $4016       ; tell both the controllers to latch buttons


Then you need to read $4016 in a loop to get the button data. each time you read $4016, it will tell you whether a particular button is pressed in bit 0. it's in this order: A, B, Select, Start, Up, Down, Left, Right. There are different ways to write the loop, but something simple like this would work fine:

Code:
      LDX #$08      ; prepare X for 8 button inputs for controller 1
      GetControllerLoop: ; Store buttons from controller 1 in a byte
         ASL controller ;shift existing bits left to make room for the next button press.
         LDA $4016, Y ;to get controller 2, set Y to 1
         AND #%00000001 ;bit 0 is the data for standard controller buttons.
         ORA controller ;combine it with the existing button presses.
         STA controller
         DEX
         BNE GetControllerLoop


I think I got this from Nerdy Nights, but I might have modified it, I don't remember.

OK. But, where is the "controller" address? Is it $4016 or is it something like .res 1?
Re: moving the :p cursor
by on (#235242)
"controller" is a variable that can be wherever you want in RAM. If you normally define your variables using .res, then that's how you should define this one.
Re: moving the :p cursor
by on (#235244)
edit: I guess I misunderstood the question. Yeah, "controller" is just a label that was defined before in a line in the ZEROPAGE or RAM segments. Like:
controller: .res 1
".res" simply indicates the length in bytes to be reserved in memory for that label, in this case 1 byte.

My original post may still be useful, so I keep it:

You read from 4016 after latching, exactly as gravelstudios wrote. The buttons come in a certain order, so you read them and store into memory addresses (labeled "controller" in the example posted) so you can use later. Some people store each button in a byte (some could say it's easier to read) or in a bit inside the same byte (8x more optimized RAM space), you choose which you prefer. In gralvestudios example, it's storing it all in a single byte, so when you read from it you need to AND with a number to see if a specific button is pressed.

The numbers you need to AND to check are as follows (if this is wrong someone correct me please):
binary: 10000000 hex: $80 button: A
binary: 01000000 hex: $40 button: B
binary: 00100000 hex: $20 button: Select
binary: 00010000 hex: $10 button: Start
binary: 00001000 hex: $08 button: Up
binary: 00000100 hex: $04 button: Down
binary: 00000010 hex: $02 button: Left
binary: 00000001 hex: $01 button: Right

So, let's say you want to check "Up" in your game logic, you will read the "controller" RAM address, which was written to by the code above. That will store the controller's contents into A. Then you AND A with $08 (which is a number which only has the "Up" bit set), and if A is 0, "Up" isn't pressed so you branch there.