I put off doing attributes for a long time because I didn’t want to face the nightmare. When I finally sat down to do it the other day, it was extremely fast and easy to implement. The reason? No scrolling.

What’s an Attribute?

The NES has 4 screen-sized pages that you can draw background tiles to. These pages are called nametables. Each nametable has an attribute table associated with it. An attribute table specifies what palettes are used for the different tiles in the nametable. So basically the nametables control what tiles are seen, and attribute tables control what colors those tiles are.

The NES PPU (Picture Processing Unit) maps the attribute tables to the nametables in a very unintuitive way (see this tutorial), which makes working with attribute data a real pain. This is especially true when scrolling is involved as you may have portions of two different nametables on the screen at the same time. The ultimate nightmare is four-way scrolling where you can cross horizontal and vertical screen boundaries at the same time. I foolishly attempted a four-way scrolling engine as my first NES project and attribute tables left a bad taste in my mouth. So I wasn’t looking forward to dealing with them again.

Leftover attribute nightmare from my first attempt at a 4-way scrolling engine.

Leftover attribute nightmare from my first attempt at a 4-way scrolling engine.

But as I mentioned, attributes aren’t so bad when there is no scrolling going on. The Explorer game I’m writing shows one room at a time, and I don’t think scrolling will be necessary when changing rooms. I think I will be able to get away with turning off the PPU, drawing the new room in one go, and then turning the PPU back on. This will cause the screen to black out when changing rooms, but only for a second. I don’t think it will be too distracting. We can take a peek at Sivak’s platformer demo to see how this method looks:

Looks just fine to me! So Plan A is to ditch scrolling altogether and instead toggle the PPU off and on when changing rooms. This should save me some headaches when dealing with the attribute tables.

Implementation

When I load a new room, I turn off the PPU. Then I draw the room. Then I color the room (write the attribute data to the attribute table). Then I turn the PPU on. The trickiest part of this process is figuring out what to write to the attribute table.

My test data consists of rooms built from seven possible 2×2 metatiles (16×16 pixels). The first thing I do is assign each metatile a palette number. I don’t like to hardcode any number values in my data, so I give everything an alias using ca65’s .ENUM directive. First the tiles ids, which are used in the map data:

.enum
    floor       ;these are my tiles, numbered $00-$06
    wall
    block
    water
    block_breakable
    stairs_up
    stairs_down
.endenum

Then the palette ids:

.enum
    orange ;my four bg palettes from $00-$03
    gray
    blue
    brown
.endenum

Finally, the attribute assignments for each tile in order:

tile_attribs:
    .byte gray    ;floor
    .byte brown   ;wall
    .byte orange  ;block
    .byte blue    ;water
    .byte orange  ;block_breakable
    .byte gray    ;stairs_up
    .byte gray    ;stairs_down

With this setup, I can read a tile number from my map data and then use that value as an index into the tile_attribs table. Once I’ve read the palette number from the tile_attribs table, I can do a shift/roll combo to sneak that 2-bit value into an attribute byte:

;-------------------------------
; make_attrib takes a map index in x and creates an attribute
; byte for the metatile box (32x32 px). x is the top-left tile.
make_attrib:
    lda room, x  ;top left
    tay
    lda tile_attribs, y  ;get the palette number
    sta map_temp2
    lsr map_temp2  ;shift a bit into the carry flag
    ror map_temp1  ;roll the carry flag into a temp var
    lsr map_temp2  ;and repeat for the second bit
    ror map_temp1

    lda room+1, x  ;top right
    tay
    lda tile_attribs, y
    sta map_temp2
    lsr map_temp2
    ror map_temp1
    lsr map_temp2
    ror map_temp1

    lda room+16, x   ;bottom left
    tay
    lda tile_attribs, y
    sta map_temp2
    lsr map_temp2
    ror map_temp1
    lsr map_temp2
    ror map_temp1

    lda room+17, x     ;bottom right
    tay
    lda tile_attribs, y
    sta map_temp2
    lsr map_temp2
    ror map_temp1
    lsr map_temp2
    ror map_temp1
    rts
    

Looping across the room data I can build a full attribute table in RAM. Then I can simply copy it over to the PPU when PPU rendering is off. It works!

Before:

A room before attributes

Here's what a room looks like before attributes

After:

A room after attributes

Here's how the room looks with proper attribute data.

Please forgive the ugly tiles. I’m no artist. They will all be replaced in the future. :)

Conclusion

Attributes are done! Room decompression works! I can display rooms correctly! The next step is to design a multi-floor, multi-room test level and make it possible to navigate between rooms. That will likely take me some time, so my next few posts will be about my room data format.

5 Responses to “Explorer: 2 – Attributes”

  1. Rob says:

    Awesome man, it will be cool to see how you do things. I grabbed your RSS : )

    I’ve been really busy lately and haven’t had time to do much devving, so that’s a bummer. Oh well, there will be time some time! haha

  2. Thomas says:

    @Rob: Thanks for checking the blog out! Feel free to comment anytime. My wife has no interest at all in NESdev, so I don’t get a chance to discuss my project with anyone very often :)

    Btw, are you still working on that zombie game?

  3. Rob says:

    All my devving is on hold for lots of reasons right now; computer time is limited! But yes, it’s still in the works and what-not. I have some stuff to recode though, as I learned newer techniques that I wasn’t employing when I started the project. So is the way of things haha!

  4. [...] Tummai Games development blog for NES games « Explorer: 2 – Attributes [...]

  5. Thomas says:

    @Rob: I hear you. Family life comes first :) I’m a little lucky that I can get some nesdev time in at work. There’s quite a bit of downtime teaching English in a Japanese Jr. High School. It’s only going to increase too once summer vacation starts in a week :)

    Hope you can get back into coding your game someday. That intro looked great!

Leave a Reply