moving the :p cursor

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

Post Reply
Tompis1995
Posts: 17
Joined: Fri Feb 22, 2019 10:05 am

moving the :p cursor

Post by Tompis1995 » Sat Mar 02, 2019 6:40 am

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: Select all

.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.
Attachments
ball.chr
(8 KiB) Downloaded 157 times

User avatar
gravelstudios
Posts: 89
Joined: Mon Mar 13, 2017 5:21 pm
Contact:

Re: moving the :p cursor

Post by gravelstudios » Sat Mar 02, 2019 6:59 am

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: Select all

	.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: Select all

		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.

Tompis1995
Posts: 17
Joined: Fri Feb 22, 2019 10:05 am

Re: moving the :p cursor

Post by Tompis1995 » Sat Mar 02, 2019 7:10 am

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: Select all

	.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: Select all

		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?

User avatar
tokumaru
Posts: 11990
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: moving the :p cursor

Post by tokumaru » Sat Mar 02, 2019 7:53 am

"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.

User avatar
nesrocks
Posts: 481
Joined: Thu Aug 13, 2015 4:40 pm
Location: Rio de Janeiro - Brazil
Contact:

Re: moving the :p cursor

Post by nesrocks » Sat Mar 02, 2019 8:02 am

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.
https://twitter.com/bitinkstudios <- Follow me on twitter! Thanks!

Post Reply