It’s been a while since I posted here. I took a break from my homebrew to write some tutorials on how to code a sound engine for the NES. You can find them here: NES Sound Tutorials.

After a long break I finally got back to some homebrew coding. I worked in 6502 for a few hours today. I didn’t work on Explorer, but rather a different game project that is less ambitious. I’ll introduce the game properly in a future post.

What I Did Today

Button Combos

One thing that I needed for the new game project was a way to detect button combinations like up+A or right+B – the kind that you use to select plays in TecmoBowl. It was a little tricky to pull off. For one thing, if the player presses something like up+left+A, I need to resolve that to either up+A or left+A. I need to work that out for all possible combinations of button presses. This includes taking care of cases where A+B are pressed at the same time.

Another issue is with holding buttons. If the player holds B down and makes circles around the dpad, I only want it to catch the first combination. To do two combos in a row, they should release the B button and press it again. But what if the player hits up+B, and then while still holding B they press A+left? Does the holding of B stop the 2nd combination from being picked up or not? There are a lot of possible cases since the controller reading routine is called 60 times per second. The player can’t control their input on a frame-by-frame scale. Sliding from B to A might very well contain several frames (fraction of a second) where both buttons are held down before the B button is released. Not impossible to solve, but it wasn’t as straightforward as I had expected.

Sound Engine

Another thing I did today was port my sound engine to ca65. I wrote my NES sound tutorials for the NESASM assembler. My tutorials are a continuation of another set of tutorials which use NESASM and I wanted to stay consistent. Plus most new nesdevers start with NESASM as it is very newbie-friendly.

My tutorial sound engine was an improvement over the one I had previously written in ca65, so I wanted to replace the old with the new. So I spent some time today porting my sound engine from NESASM to ca65. I was sure everything was going to break as soon as I got all the syntax converted. But it didn’t! Once I got it to assemble it worked perfectly on the first try! That was a relief.

Scopes

ca65 lets you define scopes. Scopes enable you to keep parts of your program hidden from the other parts of your program. It’s good to separate modules, especially in large programs, so that you don’t have variable conflicts and the like. These bugs are the hardest to trace in assembly language.

I didn’t use scopes before because I didn’t really know how. But I found a great thread on nesdev about ca65 scopes that told me how to do it, so I spent some time today separating my sound and controller reading modules from the main program. Everything feels much … cleaner now. Like washing your hands after working outside on a summer day. I can physically feel how much easier things are going to be in the future for me with scopes.

New NES

I bought an NES! Ordered it on Yahoo Auctions on Saturday and it arrived at my house on Sunday! All I need now is a PowerPak and I can start testing my programs on real hardware. I can’t wait!

I’m too lazy to upload pictures here, but you can see the ones I posted to twitter here:

My new NES 1
My new NES 2

Took some time away from work and hobbies to spend some time with the family. Before I left I was working on adding some enemies into the game. I made three different monsters and added enemy-loading logic to the room-loading routines. The enemies display onscreen fine and die when you shoot their HP to 0. Tomorrow I’m going to work on some movement patterns.

I felt I should do some kind of update though, so here are the terrifying monsters I whipped up in GIMP. Turn on the lights before looking at them or you might die in your sleep:

  1. Purple Tongue Head
    When you see it coming, the shit runs down your leg.

    When you see it coming, the shit runs down your leg.

  2. Eyeball
    It's looking for something to KILL!

    It's looking for something to KILL!

  3. Shuriken
    It's pointy.

    It's pointy.

I haven’t posted in a few days and that’s because I’ve been spending my time doing research. I’ve been peeking at other games and seeing how they handle sprite objects. By sprite object, I mean entities in a game that are represented on screen with sprites: enemies, projectiles, powerups, etc. When I was trying to code bullets, I didn’t really know how to go about it. Should I keep them separate from other sobjects (sprite objects) or are there enough similarities to lump them together?

If you think about it, a bullet isn’t much different from an enemy. It has an x and a y. It has a speed and a movement pattern. It has a palette. It has a hit box. The main difference is what you check for collision against. Enemies collide with the hero. Hero bullets don’t. They collide with enemies instead.

So some logic is different, but the data (or rather type of data stored) is the same! As far as turning the sobject data into actual sprites, bullets can be treated just the same as enemies (the hero too). Why do I care? If I am able to lump them all together, I can make all the sprites in a single loop. Here’s an example of what I mean:

Sobjects to Sprites

Let’s say I have a hero. That’s one sobject. He can shoot bullets. Let’s say I want to allow 3 bullets maximum on the screen at a time. That’s three more potential sobjects. Then enemies. Just pulling a number out of the air, lets say I want there to be 10 enemies on the screen at a time maximum. That’s ten more potential sobjects.

1 hero + 3 bullets + 10 enemies = 14.

So I have 14 sobjects that could be represented on the screen at any one time. If I treat them all the same, I can hold all of the data in arrays, like this:

sobj_id: .res 14
sobj_hp: .res 14
sobj_x: .res 14
sobj_y: .res 14
sobj_hitbox_top: .res 14
sobj_hitbox_bottom: .res 14
...etc

Then whenever I need to turn them into sprites, I can just loop through them all using an index register:

sobjects_to_sprites:
    ldx #$00
@loop:
    lda sobj_id, x
    ;do stuff
    ;calculate y, CHR#, attrib and x
    ;for each sprite of the sprite object
    ;and store in DMA sprite RAM

    inx
    cpx #.sizeof(sobj_id) ;loop through all 14
    bne @loop
    rts

And that will cover all my sobjects as far as turning their data into sprites. I don’t need to write more than one routine!

To differentiate between sobject types (bullet vs. enemy vs. hero), I can just have their index range set. For example, hero is always index 0. Bullets are always 1-3. And enemies are always 4-13. This way I always know what to test for collisions against: enemies will always test against index 0 (hero) and deal damage on a collision. Enemies will also test against index 1-3 (bullets) and receive damage on a collision.

With defined index ranges, limit testing is easy too: If the player presses the fire button, check sobjects 1-3. If they are full already, don’t create a new bullet. If there is an open space there, create a new bullet.

Conclusion

I think I finally figured out how I’m going to arrange sprite objects. Today I rewired all of my previous hero-moving code to fit into this new data model and I think I have it working. Tomorrow I’m going to try to add bullets for real!

I originally started working on this game as an entry for a coding competition. The genre was puzzle games and I thought a switch-throwing maze game would be fun to write. I missed the deadline for the contest long ago but I kept working on the game anyway. Now I’m thinking about taking the game in a new direction.

The decision to make a maze-only game was made because there was a deadline, and because the genre for the contest was “puzzle”. But now that I have as much time and freedom as I want, I think I’m going to expand the game beyond just finding your way through a maze. Specifically, here are some things I want to add that weren’t in the original plan:

  1. Enemies and bosses
  2. Weapons
  3. A way to die (ie, health bar)
  4. A way to improve (more weapons. powerups… level ups?)

In addition to these changes, I’m also going to change the setting and storyline completely. No more treasure hunting archaeologist. I haven’t worked out all the details but I think it’s going to be somewhat sci-fi, with the hero as a cyborg (ie, guns not swords). I think using the Guardian Legend girl as my test sprite has influenced me in some way. :).

Anyway, this comes at just the right time. I just got switches and doors working and the next thing I was going to write was a way to break the breakable blocks. In the original maze-game concept there was going to be an item (like a hammer) that the archaeologist hero would find to allow him to break blocks. Now I think it will be a powerup that makes your gun blast stronger.

Next objective: make the hero shoot a projectile when pressing A.

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: