In almost any NES game we can imagine, we used a controller to move one of the sprites around on the screen. Let’s tap into the directional buttons to move our spaceship around.

If you would like to follow along in my git repository, download or clone the following repository:

https://github.com/jonmoody/nes-tutorial

Then to see the code for this tutorial specifically, checkout the branch tutorial-5:

git checkout -b tutorial-5 remotes/origin/tutorial-5

Reading from the Controller

Hooking into the controller is relatively simple. There are two ports that we can use to access the controllers. Port $4016 will be used for player 1, and $4017 will be used for player 2. Let’s start writing a method to read the controller input for player 1:

ReadPlayerOneControls:
  LDA #$01
  STA $4016
  LDA #$00
  STA $4016

The code above is used to latch buttons for both controllers. Even though we are writing the values $01 and $00 to the port for controller 1, this initial bit of setup code will prepare both controllers to be read. Once we do this, we are ready to read each button for controller 1:

  LDA $4016       ; Player 1 - A
  LDA $4016       ; Player 1 - B
  LDA $4016       ; Player 1 - Select
  LDA $4016       ; Player 1 - Start
  LDA $4016       ; Player 1 - Up
  LDA $4016       ; Player 1 - Down
  LDA $4016       ; Player 1 - Left
  LDA $4016       ; Player 1 - Right

You will notice something odd about the code above. The same line of code is repeated eight times. However, the comment next to each line tells us that each load of that memory address is reading a different button. It’s important to know that the buttons are read in this fixed sequence (A, B, Select, Start, Up, Down, Left, Right). This means that if we want to do something when the player presses Start, we will need to load this memory address four times, regardless of whether or not we care about any of the previous buttons in the sequence.

Checking Button Input

That code alone won’t really do anything. We need to actually check the value that came back from the controller to see if the button has been pressed or not. Let’s check the Up button:

ReadUp:
  LDA $4016       ; Player 1 - Up
  AND #%00000001
  BEQ EndReadUp

  ; Do stuff here if the button is pressed
EndReadUp:

Once we read the Up button, we will perform an AND operation on the value that came back. We only care about the first bit, so by placing a 1 in the first bit of our AND operation, the result will be 1 if the button is pressed, otherwise the value is 0. Then, we will use the BEQ (branch if equal) operation to decide if we need to execute the following code or skip over it. If we don’t use a CMP (compare) operation before using BEQ, it will branch if the value is equal to zero.

Moving Sprites with the Controller

Now we want to actually move the spaceship up when we press the Up button. When we loaded our sprites starting at memory address $0300, remember that each sprite has 4 bytes of data. The first byte of that data is the vertical position. We will have to modify this byte for all six sprites that make up our spaceship. Dealing with memory addresses can quickly become out of control, so let’s create some variables for the vertical positions of all our spaceship sprites. Add these to the top of the file after where we added our background pointers:

shipTile1Y = $0300
shipTile2Y = $0304
shipTile3Y = $0308
shipTile4Y = $030C
shipTile5Y = $0310
shipTile6Y = $0314

Now, back in the code where we read the Up button, if the button is pressed we want to simultaneously move all sprites up one pixel:

ReadUp:
  LDA $4016       ; Player 1 - Up
  AND #%00000001
  BEQ EndReadUp

  LDA shipTile1Y
  SEC
  SBC #$01
  STA shipTile1Y
  STA shipTile2Y
  STA shipTile3Y

  LDA shipTile4Y
  SEC
  SBC #$01
  STA shipTile4Y
  STA shipTile5Y
  STA shipTile6Y
EndReadUp:

In the code above, we are reading in the current vertical position of the first tile of the spaceship. Then, we add an SEC (set carry) operation to set the carry flag to make borrowing possible for subtraction. After that, we use the SBC (subtract with carry) operation to subtract 1 from the current vertical position of the sprite. Once we have this new value, we store that in the memory locations of the first three sprites (since they should all have the same vertical position). This will move the first row of sprites in our spaceship up by one pixel. The next chunk of code does the same thing, except for the second row of sprites in the spaceship.

Now, let’s add the code necessary to be able to move the spaceship down:

ReadDown:
  LDA $4016       ; Player 1 - Down
  AND #%00000001
  BEQ EndReadDown

  LDA shipTile1Y
  CLC
  ADC #$01
  STA shipTile1Y
  STA shipTile2Y
  STA shipTile3Y

  LDA shipTile4Y
  CLC
  ADC #$01
  STA shipTile4Y
  STA shipTile5Y
  STA shipTile6Y
EndReadDown:

The code for the Down button is basically the same as the Up code. The only difference here is that we use the CLC (clear carry) operation instead of the SEC (set carry) operation, since we don’t need it set for addition. Then we use the ADC (add with carry) operation to add 1 to the current vertical position of the sprites.

Moving sprites horizontally works just about the same as moving them vertically, except there is a separate byte for each sprite’s horizontal position. Let’s add more variables for the horizontal positions:

shipTile1X = $0303
shipTile2X = $0307
shipTile3X = $030B
shipTile4X = $030F
shipTile5X = $0313
shipTile6X = $0317

The code for moving the spaceship left has a similar structure:

ReadLeft:
  LDA $4016       ; Player 1 - Left
  AND #%00000001
  BEQ EndReadLeft

  LDA shipTile1X
  SEC
  SBC #$01
  STA shipTile1X
  STA shipTile4X

  LDA shipTile2X
  SEC
  SBC #$01
  STA shipTile2X
  STA shipTile5X

  LDA shipTile3X
  SEC
  SBC #$01
  STA shipTile3X
  STA shipTile6X
EndReadLeft:

There are three chunks of code in there instead of two because there are three columns of sprites in our spaceship. Each chunk of code will move the two sprites in the column to the left by one pixel.

For completeness, let’s add the code for reading the Right button and wrap up this method with an RTS (return from subroutine) operation:

ReadRight:
  LDA $4016       ; Player 1 - Right
  AND #%00000001
  BEQ EndReadRight

  LDA shipTile1X
  CLC
  ADC #$01
  STA shipTile1X
  STA shipTile4X

  LDA shipTile2X
  CLC
  ADC #$01
  STA shipTile2X
  STA shipTile5X

  LDA shipTile3X
  CLC
  ADC #$01
  STA shipTile3X
  STA shipTile6X
EndReadRight:

  RTS

Cool! So now all we have to do is call this method from the NMI:

  JSR ReadPlayerOneControls

By doing this, the code to read from our controller will get called on each frame.

Player 2

If the game we’re creating happens to be a two-player game, all the stuff we did above is the same except we use port $4017 for player 2 instead of $4016.

The Spaceship Moves!

Once we assemble our game and launch it in the emulator, we should be able to use the directional buttons to move the spaceship around on the screen! The emulator will map buttons on your keyboard to the controller buttons. Additionally, you can plug in a usb controller and map the buttons on an actual controller.

One thing you may notice is that the ship can travel off the sides of the screen and appear on the opposite side. The next post will go over some basic collision detection so we can resolve this issue.