In the last post, I got the hero sprite moving. But there’s a problem: she can walk through walls. I need to add collision detection with background tiles. Collision detection with the background can be summed up like this:

if the player tries to move:
    check the space they want to move to
    if that space is solid/blocked:
        don't move
    else:
        move

The looks pretty easy, but it can actually be quite complicated. Here are some issues:

  1. The hero sprite has x and y coordinates, which are on the pixel level. My room tile data is stored in ram on the metatile level. We need to make a conversion there.
  2. There isn’t any one point on the hero that is a catch-all for movement checks. If the player tries to move left, we will want to check for a collision with the left side of the hero. If the player tries to move right, we want to check for a collision with the right side of the hero. So we will need to make a hit box.
  3. Each side of the hit box will have a length > 1, so we may have to check for a collision with more than one background tile. For example, say the player wants to move right. We will check using the right side of the hit box. But it’s possible that the top half of the hit box will be adjacent to one tile, while the bottom half is adjacent to another.
    If we only checked the top-right corner of this hit box for collision, it would show the way as clear.  But it really isn't, because the bottom half of the hit box collides with a solid tile.

    If we only checked the top-right corner of this hit box for collision, it would show the way as clear. But it really isn't, because the bottom half of the hit box collides with a solid tile.

Step 1

First thing I want to do is make a hit box. I’m going to put it around the hero sprite’s feet. I define where the edges are relative to the hero’s X/Y coords, then make a subroutine to calculate the box every frame:

;collision box for the hero sprite (box around the feet)
HERO_MOVEMENT_BOX_TOP = 26
HERO_MOVEMENT_BOX_BOTTOM = 31
HERO_MOVEMENT_BOX_LEFT = 5
HERO_MOVEMENT_BOX_RIGHT = 11

hero_box: .res 4 ;top bottom left right

set_hero_box:
    lda hero_x
    clc
    adc #HERO_MOVEMENT_BOX_LEFT
    sta hero_box+2
    lda hero_x
    clc
    adc #HERO_MOVEMENT_BOX_RIGHT
    sta hero_box+3
    lda hero_y
    clc
    adc #HERO_MOVEMENT_BOX_TOP
    sta hero_box
    lda hero_y
    clc
    adc #HERO_MOVEMENT_BOX_BOTTOM
    sta hero_box+1
    rts

Movement within a metatile

Since every metatile is 16 pixels wide and 16 pixels tall, I can take a shortcut if I determine that the player is not at the edge of a tile. Check out these two cases:

We don't need to check for a collision in the left case.  The player is already on a walkable tile, and will remain on that tile if they move a pixel to the right.

We don't need to check for a collision in the left case. The player is already on a walkable tile, and will remain on that tile if they move a pixel to the right.

Let’s assume the player is trying to move right. The player is on a walkable tile in both cases. In the first case, they are in the middle of the tile. In the second case they are at the edge. We only need to check for a collision in the second case. Checking the first case would be a waste of time, because we’d be checking the tile the player is already on for walkability, but we know it must be walkable since the player is already on it. So right away we can skip over a collision check if we determine the player to be in the middle of the tile (ie, not on the edge).

This is very easy to pull off with 16×16 metatiles. In all cases, the left edge of a metatile will have an x-coord of $x0, and the right edge will be $xF. The top edge of a metatile will have a y-coord of $x0 and the bottom will be $xF. So in our collision detection routines, we can do something like this:

can_move_right:
    ldx hero_box+3 ;right edge of movement box
    inx ;we want to peek at the next pixel over
    txa

    and #$0F ;isolate right nibble,
         ; tells us where we are WITHIN a tile

    bne @move_ok ;not on the edge.  movement within current
                 ;square OK (in other words, if the right
                 ;nibble is 0, we are on the left edge of the
                 ;NEXT tile, and therefore need to check
                 ;for collision)

    ;... check for collisions

@move_ok:
    sec  ;return a 1 if movement is OK
    rts

I use a similar check at the beginning of can_move_left, can_move_up and can_move_down.

How many checks?

Do I need to check one bg tile for collision or two? It depends on the hero sprite’s position. Imagine the player is moving right again. If the top and bottom edges of the hit box are both within the boundaries of a single tile, we only need to check one bg tile for collision. But check this picture (should look familiar):

moving right, the top and bottom edges of the hit box touch two different bg tiles.  We need to make two checks.

moving right, the top and bottom edges of the hit box touch two different bg tiles. We need to make two checks.

In this case, the top and bottom edges of our hit box line up with two different bg tiles. So we need to check both. If either of them are unwalkable, we don’t allow movement.

So, two checks or one check? There are a couple of ways to determine if the top and bottom edges of our hit box touch different tiles. I do it this way:

    ;find how many tiles to check (1 or 2)
    lda hero_box ;top edge of movement hit box

    ora #$F0 ;we are going to add the box height,
             ;so set us up to check for a FF->00 transition

    adc #HERO_MOVEMENT_BOX_HEIGHT ;negative means our box is
                                  ;h-aligned with one tile.
                                  ;positive = 2 tiles
    bmi @not_two

    ;... check a tile

@not_two:
    ;... check a tile

I do similar tests for the other directions, but for can_move_up and can_move_down I will check the left and right edges instead of the top and bottom edges.

Hero pixel coords to a room coords

I need to turn the hero’s pixel coordinates into room coordinates so that I can find which bg tiles to check. Here’s my subroutine to do that:

;------------------------------
; set_hero_map_coords finds the x and y room coords for the 
; topleft pixel of the player's movement hit box
set_hero_map_coords:
    lda hero_box+2 ;left
    ldx #$00
    sec
:
    sbc #$10
    bcc :+
    inx
    jmp :-
:
    stx hero_map_x

    lda hero_box ;top
    ldx #$00
    sec
:
    sbc #$10
    bcc :+
    inx
    jmp :-
:
    dex
    dex ;correct y for the status bar
    stx hero_map_y
    rts

Once I have the hero’s room coordinates, I can add to or subtract from them to find the coordinates for the adjacent tiles I want to check for walkability.

Walkability

How do I check for walkability? With a lookup table:

;tile ids
.enum
    floor
    wall
    block
    water
    block_breakable
    stairs_up
    stairs_down
    pitfall
.endenum

.enum ;walkability
    unwalkable
    walkable
.endenum

tile_walkability:
    .byte walkable, unwalkable, unwalkable, unwalkable
    .byte unwalkable, walkable, walkable, walkable

I read a tile id from the room map in RAM and use it to index into the tile_walkability table.

Here’s a simplified can_move_right. (I took out checks for room boundaries to make it more readable):

can_move_right:
    ldx hero_box+3 ;right edge of movement box
    inx
    txa

    and #$0F ;isolate right nibble, where are we WITHIN a tile?

    bne @move_ok ;not on edge. move within current square OK

    ;how many tiles to check (1 or 2)
    lda hero_box ;top edge of movement box
    ora #$F0
    adc #HERO_MOVEMENT_BOX_HEIGHT
    bmi @not_two

    ldy hero_map_y
    iny
    ldx hero_map_x
    inx
    jsr get_room_offset ;takes x/y room coords and returns an
                        ;array index in y

    lda room, y
    tay
    lda tile_walkability, y
    beq @no_move

@not_two:
    ldy hero_map_y
    ldx hero_map_x
    inx
    jsr get_room_offset

    lda room, y
    tay
    lda tile_walkability, y
    beq @no_move
@move_ok:
    sec return 1 in the carry if we can move
    rts
@no_move:
    clc return 0 in the carry if we can't move
    rts

I have seperate routines for the other 3 directions. They are all very similar. The last step is to update my move_hero subroutine to call these collision detection routines before moving, and then skip movement on carry clear.

Conclusion

Now I have a sprite that changes direction, moves, animates and bumps into walls. Here’s the latest video demo:

Ok, I got the hero to change directions based on user input. Now it’s time to move her. The first step for this is to have a hero_moving flag that the input handler will set if there is d-pad input:

hero_moving: .res 1
handle_joypad:
    lda joypad1
    and #$F0
    beq @end
    lsr
    lsr
    lsr
    lsr
    tay
    lda direction_change_table, y
    sta hero_direction
    lda #$01
    sta hero_moving
    rts
@end:
    lda #$00
    sta hero_moving
    rts

With this updated input handler, the hero_moving flag will be 1 when the d-pad is pressed, and 0 when it is not. And as before, our hero’s direction will be stored in hero_direction.

Next, I need to check the hero moving flag in my update_hero_sprite routine, which is called every frame:

update_hero_sprite:
    lda hero_moving
    beq @hero_moving_done

    jsr move_hero
@hero_moving_done:
    ;...
    ;write sprite data to RAM as before

Now that I have the foundation laid, I need to write the move_hero routine.

move_hero

There are 8 possible directions the hero could be facing. The current direction is stored in a variable called hero_direction. The possible values for this variable are 0-7, as assigned by these constants:

;direction indexes for tables
SPRITE_UP =         $00
SPRITE_DOWN =       $01
SPRITE_LEFT =       $02
SPRITE_RIGHT =      $03
SPRITE_UP_LEFT =    $04
SPRITE_UP_RIGHT =   $05
SPRITE_DOWN_LEFT =  $06
SPRITE_DOWN_RIGHT = $07

I need to alter the hero’s coordinates based on the direction the player is moving. If they are moving left, I need to subtract from hero_x. If they are moving right, I need to add to hero_x. If they are moving up, I need to subtract from hero_y. If they are moving down, I need to add to hero_y. If they are moving diagonally, I need to update both hero_x and hero_y. There are many possibilities, and rather than have a million branch instructions, I’ll use table lookups again. I will have one table for horizontal movement and one table for vertical movement. I will index into these tables using hero_direction. The tables look like this:

;up, down, left, right, up_left, up_right, down_left, down_rt
hero_movement_x:
    .byte $00, $00, $FF, $01, $FF, $01, $FF, $01

hero_movement_y:
    .byte $FF, $01, $00, $00, $FF, $FF, $01, $01

My move_hero routine will read from these tables and add to the hero coordinates. Note that adding $FF to a number (on an 8-bit system) is the same as subtracting 1, since it will wrap around from $FF to $00. Here is move_hero:

move_hero:
    ldy hero_direction
    lda hero_movement_x, y
    clc
    adc hero_x
    sta hero_x

    ldy hero_direction
    lda hero_movement_y, y
    clc
    adc hero_y
    sta hero_y

    rts

And now she’s moving.

miau pointed out in a comment that diagonal movement should really alter x and y by SQRT(2) rather than 1 (see Pythagorean Theorum). This is something I didn’t consider before, so my hero covers ground a little more quickly when moving diagonally. I’m not sure yet if this is undesirable behavior or not. If I keep it a simple maze-solving game, it probably won’t be an issue. If I get more ambitious and change it to a more action-oriented game with enemies (something I’ve been seriously thinking about), it may be an issue. We’ll see :).

Animation

I want to talk very briefly about animating the sprite. To do animation, I need a few things:

  1. Graphics for the various frames of animation
  2. A counter to tell me when to change animation frames
  3. A variable telling me the current animation frame

I already have the graphics for my test sprite. The other two I need to make myself.

frame_counter: .res 1
hero_anim_frame: .res 1

The animation is a walking animation, so I don’t want the hero to animate unless she is moving. It makes sense then to do the animation frame-changing logic in the move_hero routine. The Guardian Legend hero sprite has a 4-frame walking animation, so here’s how I do it:

move_hero:
    ldy hero_direction
    lda hero_movement_x, y
    clc
    adc hero_x
    sta hero_x

    ldy hero_direction
    lda hero_movement_y, y
    clc
    adc hero_y
    sta hero_y

    inc frame_counter
    lda frame_counter
    cmp #$0B ;change anim frame every 11 "moving frames"
             ;found this number by trial and error
    bcc @end

    lda #$00
    sta frame_counter ;reset counter
    inc hero_anim_frame ;go to next anim frame
    lda hero_anim_frame ;make sure we stay between 0 and 3
    and #$03
    sta hero_anim_frame
@end:
    rts

Then I will modify my CHR tile lookup tables to handle graphics for all four frames of animation for all 8 directions. Then I will update my update_hero_sprite routine to read from these tables based on the values of hero_anim_frame and hero_direction. I’m not going to post the code, because it’s a little long and there are a lot of tables. If anybody wants me to elaborate more, let me know in the comments :)

BTW, before I forget! When adding new variables, it’s a good idea to initialize them. Here is my updated initialize_hero_sprite routine:

initialize_hero_sprite:
    lda #$50
    sta hero_x
    sta hero_y

    lda #$00
    sta hero_moving
    sta hero_anim_frame
    sta frame_counter

    lda #SPRITE_DOWN
    sta hero_direction

    jsr update_hero_sprite

    rts

Conclusion

Whew. I covered a lot of ground today. I probably should have made this two posts instead of one, but I want to hurry up and get to collision detection so I can put up the next demo video. :)

You may have noticed by now that I use hero_direction a lot to index into lookup tables. This is because everything changes based on the hero’s direction, and lookup tables are a great alternative to long sections of compare/branch code. Often when I find myself writing a lot of branching code I’ll see if I can come up with some scheme to turn the test value into a table index.

See you next time!

Last time I wrote code to put a hero sprite onscreen. In my first (pre-sprite) video demo, I had room changes triggered directly by player input. Today I’m going to recode the input handler to alter the hero instead, specifically the hero’s direction.

Joypad revisited

I posted my joypad reading code in a previous post, but here it is again for easy reference:

update_joypad_data: ;props to blargg for A-only joypad read.
    lda joypad1
    sta joypad1_old
    lda #%01111111
    sta joypad1
    sta $4016
    asl a
    sta $4016
@loop:
    lda $4016
    and #$03  ;props to Disch for Famicom support
    cmp #$01
    ror joypad1 ;right, left, down, up, start, select, B, A
    bcs @loop

    lda joypad1_old
    eor #$FF
    and joypad1
    sta joypad1_pressed ;this tracks off-to-on transitions.

    lda joypad1
    eor #$FF
    and joypad1_old
    sta joypad1_released ;this tracks on-to-off transitions
    rts

Before, I was checking joypad_pressed to determine whether or not to change a room. This was so that if the player held down a button, it would only change rooms once (instead of once per frame held). But now that I’m going to be using input to control the sprite, it makes more sense to check joypad1 and use every frame’s input. If the player holds down the d-pad, the sprite should keep moving.

But I’m not quite ready to move yet!

Changing Direction

I want to rewrite my input handler so that it takes d-pad input and uses it to set the hero’s direction. This sounds pretty straightforward, but there are some special cases I need to be wary of: what happens if the player presses left+right? or up+down? This isn’t likely to happen on a real controller, but most people play Nintendo games on emulators these days. If you don’t protect against these strange key combinations, you open yourself up to some pretty bizarre glitches, like the Zelda 2 acceleration glitch (commentator talks about it around the 4:20 mark):

I’m going to work around this problem by assigning a single direction to these weird combinations. But first we need to look at our input. In my joypad reading routine above, I store the button states in a variable called joypad1. The left 4 bits of joypad1 will hold the d-pad states and the right 4 bits will hold the states of the other four buttons. First I want to isolate the d-pad bits:

    lda joypad1
    and #$F0
    beq @end
    lsr
    lsr
    lsr
    lsr
    ;now the d-pad button states are in the right nibble.
    ;do change direction stuff here.
@end:
    rts

The right nibble of the A register now holds the d-pad button states. Next I will build a look-up table, assigning a direction to each possible combination of d-pad presses. Let’s look at the combinations. There are sixteen possibilities in all:

0000xxxx
    ||||
    |||+--up
    ||+---down
    |+----left
    +-----right

0000 = no arrows pressed (will never happen)
0001 = up
0010 = down
0011 = up+down
0100 = left
0101 = left+up
0110 = left+down
0111 = left+up+down
1000 = right
1001 = right+up
1010 = right+down
1011 = right+up+down
1100 = right+left
1101 = right+left+up
1110 = right+left+down
1111 = right+left+down+up

The highlighted ones are the problem combinations. I will need to assign a single, specific direction to them. For example in the case of right+left, I will just choose one: left. Let’s turn this into a lookup table. Recall that I have a set of constants assigning a value to each direction (for indexing into CHR lookup tables among other things):

;direction indexes for tables
SPRITE_UP =         $00
SPRITE_DOWN =       $01
SPRITE_LEFT =       $02
SPRITE_RIGHT =      $03
SPRITE_UP_LEFT =    $04
SPRITE_UP_RIGHT =   $05
SPRITE_DOWN_LEFT =  $06
SPRITE_DOWN_RIGHT = $07

Now I will make a lookup table assigning these constant values to the various button combinations:

direction_change_table:
    .byte $FF               ;0000 dummy value
    .byte SPRITE_UP         ;0001, up
    .byte SPRITE_DOWN       ;0010, down
    .byte SPRITE_UP         ;0011, up+down
    .byte SPRITE_LEFT       ;0100, left
    .byte SPRITE_UP_LEFT    ;0101, left+up
    .byte SPRITE_DOWN_LEFT  ;0110, left+down
    .byte SPRITE_UP_LEFT    ;0111, left+up+down
    .byte SPRITE_RIGHT      ;1000, right
    .byte SPRITE_UP_RIGHT   ;1001, right+up
    .byte SPRITE_DOWN_RIGHT ;1010, right+down
    .byte SPRITE_DOWN_RIGHT ;1011, right+up+down
    .byte SPRITE_LEFT       ;1100, left+right
    .byte SPRITE_UP_RIGHT   ;1101, left+right+up
    .byte SPRITE_DOWN_RIGHT ;1110, left+right+down
    .byte SPRITE_DOWN_LEFT  ;1111, left+right+up+down

Now all button combinations have a single direction associated with each of them. All that I have left to do is read from this table and set the hero’s direction, like so:

handle_joypad:
    lda joypad1
    and #$F0
    beq @end
    lsr
    lsr
    lsr
    lsr
    tay ;right nibble has the d-pad button states. use as index
    lda direction_change_table, y
    sta hero_direction
@end:
    rts

Changing the sprite

The rest of the work is already done for me. I already have a routine update_hero_sprite (see last post) that takes hero_direction and uses it to index into some CHR lookup tables. I don’t have to change anything to get the new sprites to display. It works! (you can see the input in the bottom left of each picture):

If I press up, the sprite faces up.

If I press up, the sprite faces up.

Pressing down+right makes her face southeast

Pressing down+right makes her face southeast

Left+Right gets mapped to left.

Left+Right gets mapped to left.

up+down+left+right

up+down+left+right

Conclusion

My hero sprite is now capable of looking in 8 directions. I use a lookup table to assign a specific direction to each possible d-pad button combination. The next step is to actually move her in the direction she is facing. And when she is moving, I will want to animate her. Stay tuned!

Now that I have some test rooms and can navigate between them, it’s time to stick a sprite in the game. I couldn’t draw a rock to save my life, much less a cool character sprite, so for now I am going to rip one from another game to use for testing. Here she is:

She's from The Guardian Legend.

She's from The Guardian Legend.

This is the sprite from The Guardian Legend. I chose her as my test sprite for a few reasons:

  1. Her dimensions. She is 16×32, which is the size I want for my game’s hero sprite.
  2. Her proportions. Specifically her feet. I have narrow 16 pixel passages that the player will need to fit through. I want to allow a small amount of left-to-right and up-to-down movement within those 16 pixel hallways. If the sprite is too fat it will look like they are stomping on the walls.
  3. Her directions. She can face 8 different directions, which is what I want for my game.
  4. Her animation. She has a 4-frame animation that looks smooth and is CHR-efficient. Something I want to imitate.

Getting a sprite onscreen

First things first I need some variables for the hero. Right off the bat I know I will need to track her coordinates and direction:

.segment "ZP": zeropage
hero_x: .res 1 ;based on top left of sprite
hero_y: .res 1
hero_direction: .res 1

Next I will need to initialize those variables. This subroutine will be called when the game engine is loaded:

;direction indexes for tables
SPRITE_UP =         $00
SPRITE_DOWN =       $01
SPRITE_LEFT =       $02
SPRITE_RIGHT =      $03
SPRITE_UP_LEFT =    $04
SPRITE_UP_RIGHT =   $05
SPRITE_DOWN_LEFT =  $06
SPRITE_DOWN_RIGHT = $07

initialize_hero:
    lda #$50    ;place her somewhere on the map
    sta hero_x
    sta hero_y

    lda #SPRITE_DOWN
    sta hero_direction

    jsr update_hero_sprite

    rts

The hero will have a different appearance based on the direction she is facing. I will have lookup tables to find which CHR tile number to use. I index into these tables with a direction index. Those constants at the top define the direction indexes (indices? whatever).

update_hero_sprite is a routine that will be called every frame. It’s job will be to calculate the sprites’ x, y, tile number and flip/palette settings and store them in RAM. Later, in the NMI we will copy those values to the PPU (Picture Processing Unit) using DMA transfer.

Speaking of which, the hero sprite is actually made up of 4 sprites. On the NES, you have a choice between 8×8 sprites and 8×16 sprites. I will be using 8×16 sprites. The hero is 16×32, which is 4 8×16 sprites:

This character sprite is actually made up of 4 8x16 sprites

This character sprite is actually made up of 4 8x16 sprites

So let’s get her on the screen:

update_hero_sprite:
    lda hero_direction
    tax       ;we use this index to read from tables

    lda #hero_top_left  ;sprite number.
    asl
    asl     ;each sprite has 4 bytes of data
    tay     ;we use this index to write sprite data to RAM

    ;sprite data is stored, in order: y, tile #, attrib, x
    lda hero_y
    sta sprite_RAM, y

    lda hero_x
    sta sprite_RAM+3, y

    lda sprite_tiles_top_left, x
    sta sprite_RAM+1, y

    lda hero_sprite_flips, x  ;right, up_right and down_right 
                              ;are just flips of left, up_left
                              ;and down_left. Flip values are
                              ; stored in a table
    sta sprite_RAM+2, y

    lda #hero_top_right    ;top right, sprite #
    asl
    asl
    tay

    lda hero_y
    sta sprite_RAM, y

    lda hero_x
    clc
    adc #$08    ;8 pixels to the right of the top left sprite
    sta sprite_RAM+3, y

    lda sprite_tiles_top_right, x
    sta sprite_RAM+1, y

    lda hero_sprite_flips, x
    sta sprite_RAM+2, y

    lda #hero_bottom_left    ;bottom left, sprite #

    ....
    ;etc.  add 16 to hero_y for the bottom two sprites

    rts
    

And in the NMI:

    ;sprite DMA transfer
    bit $2002
    lda #$00
    sta $2003
    lda #>sprite_RAM
    sta $4014
    

And she’s on the screen!

She's wearing green today.

She's wearing green today.

Conclusion

Today’s post was short and sweet. Getting the hero sprite on the screen was pretty easy. My next step is to change her direction based on joypad input. See you then!

Now that I have the ability to make some rooms, and connect them together into floors, it would be nice if I had some mechanism to go from one room to another. To do this, I will need some subroutines that will change the room coordinates in RAM and then load the new room. This is really easy to code:

move_east:
    ldx floor_roomx
    inx
    ldy floor_roomy
    jsr floor_load_room ;this subroutine takes coords in x and
                        ;y and loads the room at those
                        ;coordinates (within the same floor).
    rts

move_west:
    ldx floor_roomx
    dex
    ldy floor_roomy
    jsr floor_load_room
    rts

Subroutines for moving north and south look similar. But there’s room for improvement here. Notice that I load the new room coordinates into x and y in both subroutines. I can save some bytes if I shorten it up a little bit:

move_west:
    dec floor_roomx ;current room x coord for the floor
    jmp :+
move_east:
    inc floor_roomx
:
    ldx floor_roomx
    ldy floor_roomy
    jsr floor_load_room
    rts

If I really wanted to I could probably replace that JMP instruction with a BPL (branch if positive) and save an extra byte. I’ll leave it how it is for now for readability. I’ll save optimizations for the very end if I need them.

Changing Floors

Changing floors isn’t much harder. First I’ll have to load the new floor, and then I’ll have to load a room within that floor. Good thing I have the load_floor and load_room subroutines already written. Having a good foundation to build upon makes things easy:

floor_down:
    dec map_floor ;this var holds the current floor.
    jmp :+
floor_up:
    inc map_floor
:
    lda map_floor
    jsr load_floor ;loads the floor, setting up room ptrs, etc
    ldy floor_roomy
    ldx floor_roomx
    jsr floor_load_room
    rts

Floor Boundaries

The thing I need to watch out for now is the floor boundaries. I don’t want to call move_west when I’m currently at x=0 or my game will try to load a room at x=FF, which probably isn’t there. When the game tries to move west, I will want to check if x==0 or not. If it is, I will skip the call. If the game tries to move east, I will want to check if x is equal to floor’s x-dimension – 1. If I’m in the eastern-most room, skip the call. Likewise for moving downstairs or upstairs. I will want to check the current floor number against 0 or the top floor number, respectively.

Triggering a Room Change

I have everything set up to change rooms. Now I need something to trigger the room changes. Most games trigger room changes based on sprite position/collision. If the user moves their character sprite to the edge of the screen, change the room. I haven’t coded sprite-support in yet, so for testing purposes I’m going to trigger room changes directly to the input. Pressing right will move east. Pressing down will move south. Pressing left will move west. Pressing up will move north. I’ll use B and A for going downstairs and upstairs.

Reading Input

First I need a joypad reading routine. The one I’m using is based off a really cool one that blargg posted on a nesdev thread. It preserves both x and y.

update_joypad_data: ;thanks to blargg for this A-only joypad
                    ;read routine.
    lda joypad1
    sta joypad1_old  ;save previous joypad data
    lda #%01111111
    sta joypad1
    sta $4016
    asl a
    sta $4016
@loop:
    lda $4016
    and #$03  ;props to Disch for Famicon support
    cmp #$01
    ror joypad1 ;right, left, down, up, start, select, B, A
    bcs @loop

    lda joypad1_old
    eor #$FF
    and joypad1
    sta joypad1_pressed ;this tracks off-to-on transitions.

    lda joypad1
    eor #$FF
    and joypad1_old
    sta joypad1_released ;this tracks on-to-off transitions
    rts

For changing rooms I will want to check joypad1_pressed. This variable tracks off-to-on transitions for the buttons. Using joypad1_pressed instead of joypad1 ensures that I will only move once per button press.

The joypad reading routine is called once per frame. There are many frames in a second. If the player presses up for a second, the variable joypad1 will report an up press for each frame the button was held. That’s a lot of ups. joypad1_pressed will only report one up press – the first one. I only want to move once per button-press, so I’ll check my input using joypad1_pressed.

So I read the joypad, then I perform actions based on the input. If left was pressed I’ll check to make sure that our room x-coord isn’t 0, and then I’ll call move_west. If up was pressed I’ll check to make sure our room y-coord isn’t 0, then call move_north if it isn’t. ETC..

Take a look

I made a demo video showing room navigation. I hope to make several videos like this as I code the game. I think it will be cool to document the making of an NES game like this. Anyway, take a look:

Conclusion

Room navigation works great. The next step is to put a movable sprite into the game and have room changes triggered by that sprite’s coordinates. Then it will start to look like a real game!