Custom Tiles
Design better tile graphics for the arena.
What You’re Building
Custom-designed tiles that make the arena look polished.

The border has a brick pattern. The corners have diagonal edges. The floor has a subtle grid.
How NES Tiles Work
Each tile is 8×8 pixels with 4 possible colours. The pattern table stores tiles as two bit-planes:
- Low plane: 8 bytes, one per row
- High plane: 8 bytes, one per row
- Combine bits from both planes: 0-3 selects palette colour
Low bit: 1 High bit: 0 → Colour 1
Low bit: 0 High bit: 1 → Colour 2
Low bit: 1 High bit: 1 → Colour 3
Low bit: 0 High bit: 0 → Colour 0 (transparent/background)
Designing the Border Tile
A brick pattern alternates between solid rows and rows with gaps:
; Tile 1: Border (brick pattern)
.byte %11111111 ; Row 0: solid
.byte %10000001 ; Row 1: edges only
.byte %10000001 ; Row 2: edges only
.byte %11111111 ; Row 3: solid
.byte %11111111 ; Row 4: solid
.byte %00010001 ; Row 5: offset gaps
.byte %00010001 ; Row 6: offset gaps
.byte %11111111 ; Row 7: solid
The high plane adds colour variation within the tile.
Corner Tiles
Diagonal corners make the arena look less blocky:
; Tile 3: Corner TL (diagonal from top-left)
.byte %11111111 ; Row 0
.byte %11000000 ; Row 1
.byte %10100000 ; Row 2
.byte %10010000 ; Row 3
.byte %10001000 ; Row 4
.byte %10000100 ; Row 5
.byte %10000010 ; Row 6
.byte %10000001 ; Row 7
Four corner tiles (TL, TR, BL, BR) are mirrored versions of each other.
The Floor Tile
A subtle grid pattern adds visual texture without being distracting:
; Tile 2: Floor (subtle grid)
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %10000001 ; Small dots at corners
Drawing Corners
The arena drawing code now places corner tiles at the four corners:
@top_row:
lda row_counter
cmp #0
bne @top_row_inner
; Very top row with corners
lda #TILE_CORNER_TL
sta PPUDATA
lda #TILE_BORDER
ldx #30
@top_fill:
sta PPUDATA
dex
bne @top_fill
lda #TILE_CORNER_TR
sta PPUDATA
jmp @next_row
The Code
; =============================================================================
; NEON NEXUS - Unit 5: Custom Tiles
; =============================================================================
; Design better tile graphics for the arena.
; =============================================================================
; -----------------------------------------------------------------------------
; NES Hardware Addresses
; -----------------------------------------------------------------------------
PPUCTRL = $2000
PPUMASK = $2001
PPUSTATUS = $2002
OAMADDR = $2003
PPUSCROLL = $2005
PPUADDR = $2006
PPUDATA = $2007
OAMDMA = $4014
JOYPAD1 = $4016
JOYPAD2 = $4017
; Controller buttons
BTN_A = %10000000
BTN_B = %01000000
BTN_SELECT = %00100000
BTN_START = %00010000
BTN_UP = %00001000
BTN_DOWN = %00000100
BTN_LEFT = %00000010
BTN_RIGHT = %00000001
; -----------------------------------------------------------------------------
; Game Constants
; -----------------------------------------------------------------------------
PLAYER_START_X = 124
PLAYER_START_Y = 116
PLAYER_SPEED = 2
; Tile indices (background)
TILE_EMPTY = 0
TILE_BORDER = 1
TILE_FLOOR = 2
TILE_CORNER_TL = 3 ; Top-left corner
TILE_CORNER_TR = 4 ; Top-right corner
TILE_CORNER_BL = 5 ; Bottom-left corner
TILE_CORNER_BR = 6 ; Bottom-right corner
; Sprite tiles (after background tiles in pattern table 0)
SPRITE_PLAYER = 7
; Arena boundaries
ARENA_LEFT = 16
ARENA_RIGHT = 232
ARENA_TOP = 16
ARENA_BOTTOM = 208
BG_COLOUR = $0F
; -----------------------------------------------------------------------------
; Memory Layout
; -----------------------------------------------------------------------------
.segment "ZEROPAGE"
player_x: .res 1
player_y: .res 1
buttons: .res 1
temp: .res 1
row_counter: .res 1
.segment "OAM"
oam_buffer: .res 256
.segment "BSS"
; -----------------------------------------------------------------------------
; iNES Header
; -----------------------------------------------------------------------------
.segment "HEADER"
.byte "NES", $1A
.byte 2
.byte 1
.byte $01
.byte $00
.byte 0,0,0,0,0,0,0,0
; -----------------------------------------------------------------------------
; Code
; -----------------------------------------------------------------------------
.segment "CODE"
reset:
sei
cld
ldx #$40
stx $4017
ldx #$FF
txs
inx
stx PPUCTRL
stx PPUMASK
stx $4010
@vblank1:
bit PPUSTATUS
bpl @vblank1
lda #0
@clear_ram:
sta $0000, x
sta $0100, x
sta $0200, x
sta $0300, x
sta $0400, x
sta $0500, x
sta $0600, x
sta $0700, x
inx
bne @clear_ram
@vblank2:
bit PPUSTATUS
bpl @vblank2
jsr load_palette
jsr draw_arena
; Set up player
lda #PLAYER_START_X
sta player_x
lda #PLAYER_START_Y
sta player_y
; Initialise player sprite
lda player_y
sta oam_buffer+0
lda #SPRITE_PLAYER
sta oam_buffer+1
lda #0
sta oam_buffer+2
lda player_x
sta oam_buffer+3
; Hide other sprites
lda #$FF
ldx #4
@hide_sprites:
sta oam_buffer, x
inx
bne @hide_sprites
lda #0
sta PPUSCROLL
sta PPUSCROLL
; Enable rendering - both background and sprites from pattern table 0
lda #%10000000
sta PPUCTRL
lda #%00011110
sta PPUMASK
main_loop:
jsr read_controller
jsr move_player
jmp main_loop
; -----------------------------------------------------------------------------
; Load Palette
; -----------------------------------------------------------------------------
load_palette:
bit PPUSTATUS
lda #$3F
sta PPUADDR
lda #$00
sta PPUADDR
ldx #0
@loop:
lda palette_data, x
sta PPUDATA
inx
cpx #32
bne @loop
rts
; -----------------------------------------------------------------------------
; Draw Arena (with corner tiles)
; -----------------------------------------------------------------------------
draw_arena:
bit PPUSTATUS
lda #$20
sta PPUADDR
lda #$00
sta PPUADDR
lda #0
sta row_counter
@draw_row:
lda row_counter
; Row 0: top border with corners
cmp #0
beq @top_row
cmp #1
beq @top_row
; Row 28-29: bottom border with corners
cmp #28
beq @bottom_row
cmp #29
beq @bottom_row
; Middle rows
jmp @middle_row
@top_row:
lda row_counter
cmp #0
bne @top_row_inner
; Very top row with corners
lda #TILE_CORNER_TL
sta PPUDATA
lda #TILE_BORDER
ldx #30
@top_fill:
sta PPUDATA
dex
bne @top_fill
lda #TILE_CORNER_TR
sta PPUDATA
jmp @next_row
@top_row_inner:
; Second row - all border
lda #TILE_BORDER
ldx #32
@top_inner_fill:
sta PPUDATA
dex
bne @top_inner_fill
jmp @next_row
@bottom_row:
lda row_counter
cmp #29
bne @bottom_row_inner
; Very bottom row with corners
lda #TILE_CORNER_BL
sta PPUDATA
lda #TILE_BORDER
ldx #30
@bottom_fill:
sta PPUDATA
dex
bne @bottom_fill
lda #TILE_CORNER_BR
sta PPUDATA
jmp @next_row
@bottom_row_inner:
; Row 28 - all border
lda #TILE_BORDER
ldx #32
@bottom_inner_fill:
sta PPUDATA
dex
bne @bottom_inner_fill
jmp @next_row
@middle_row:
; Left border
lda #TILE_BORDER
sta PPUDATA
sta PPUDATA
; Floor
lda #TILE_FLOOR
ldx #28
@floor_fill:
sta PPUDATA
dex
bne @floor_fill
; Right border
lda #TILE_BORDER
sta PPUDATA
sta PPUDATA
@next_row:
inc row_counter
lda row_counter
cmp #30
beq @done_drawing
jmp @draw_row
@done_drawing:
rts
; -----------------------------------------------------------------------------
; Read Controller
; -----------------------------------------------------------------------------
read_controller:
lda #1
sta JOYPAD1
lda #0
sta JOYPAD1
ldx #8
@read_loop:
lda JOYPAD1
lsr a
rol buttons
dex
bne @read_loop
rts
; -----------------------------------------------------------------------------
; Move Player
; -----------------------------------------------------------------------------
move_player:
lda buttons
and #BTN_UP
beq @check_down
lda player_y
sec
sbc #PLAYER_SPEED
cmp #ARENA_TOP
bcc @check_down
sta player_y
@check_down:
lda buttons
and #BTN_DOWN
beq @check_left
lda player_y
clc
adc #PLAYER_SPEED
cmp #ARENA_BOTTOM
bcs @check_left
sta player_y
@check_left:
lda buttons
and #BTN_LEFT
beq @check_right
lda player_x
sec
sbc #PLAYER_SPEED
cmp #ARENA_LEFT
bcc @check_right
sta player_x
@check_right:
lda buttons
and #BTN_RIGHT
beq @done
lda player_x
clc
adc #PLAYER_SPEED
cmp #ARENA_RIGHT
bcs @done
sta player_x
@done:
rts
; === NMI ===
nmi:
pha
txa
pha
tya
pha
lda #0
sta OAMADDR
lda #>oam_buffer
sta OAMDMA
lda player_y
sta oam_buffer+0
lda player_x
sta oam_buffer+3
lda #0
sta PPUSCROLL
sta PPUSCROLL
pla
tay
pla
tax
pla
rti
irq:
rti
; -----------------------------------------------------------------------------
; Data
; -----------------------------------------------------------------------------
palette_data:
; Background palettes - neon theme
.byte BG_COLOUR, $11, $21, $31 ; Blue gradient
.byte BG_COLOUR, $11, $21, $31
.byte BG_COLOUR, $11, $21, $31
.byte BG_COLOUR, $11, $21, $31
; Sprite palettes
.byte BG_COLOUR, $30, $27, $17 ; White, orange, brown
.byte BG_COLOUR, $30, $27, $17
.byte BG_COLOUR, $30, $27, $17
.byte BG_COLOUR, $30, $27, $17
; -----------------------------------------------------------------------------
; Vectors
; -----------------------------------------------------------------------------
.segment "VECTORS"
.word nmi
.word reset
.word irq
; -----------------------------------------------------------------------------
; CHR-ROM - Background Tiles (Pattern Table 0)
; -----------------------------------------------------------------------------
.segment "CHARS"
; Tile 0: Empty
.byte $00,$00,$00,$00,$00,$00,$00,$00
.byte $00,$00,$00,$00,$00,$00,$00,$00
; Tile 1: Border (brick pattern)
.byte %11111111 ; Row 0
.byte %10000001 ; Row 1
.byte %10000001 ; Row 2
.byte %11111111 ; Row 3
.byte %11111111 ; Row 4
.byte %00010001 ; Row 5
.byte %00010001 ; Row 6
.byte %11111111 ; Row 7
; High plane - add colour variation
.byte %00000000
.byte %01111110
.byte %01111110
.byte %00000000
.byte %00000000
.byte %11101110
.byte %11101110
.byte %00000000
; Tile 2: Floor (subtle grid)
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %10000001
; High plane
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
; Tile 3: Corner TL
.byte %11111111
.byte %11000000
.byte %10100000
.byte %10010000
.byte %10001000
.byte %10000100
.byte %10000010
.byte %10000001
.byte %00000000
.byte %00111111
.byte %01011111
.byte %01101111
.byte %01110111
.byte %01111011
.byte %01111101
.byte %01111110
; Tile 4: Corner TR
.byte %11111111
.byte %00000011
.byte %00000101
.byte %00001001
.byte %00010001
.byte %00100001
.byte %01000001
.byte %10000001
.byte %00000000
.byte %11111100
.byte %11111010
.byte %11110110
.byte %11101110
.byte %11011110
.byte %10111110
.byte %01111110
; Tile 5: Corner BL
.byte %10000001
.byte %10000010
.byte %10000100
.byte %10001000
.byte %10010000
.byte %10100000
.byte %11000000
.byte %11111111
.byte %01111110
.byte %01111101
.byte %01111011
.byte %01110111
.byte %01101111
.byte %01011111
.byte %00111111
.byte %00000000
; Tile 6: Corner BR
.byte %10000001
.byte %01000001
.byte %00100001
.byte %00010001
.byte %00001001
.byte %00000101
.byte %00000011
.byte %11111111
.byte %01111110
.byte %10111110
.byte %11011110
.byte %11101110
.byte %11110110
.byte %11111010
.byte %11111100
.byte %00000000
; Sprite 0: Player (better ship design) - at tile index 0 in sprite table
; This goes immediately after background tiles
.byte %00011000 ; Row 0
.byte %00011000 ; Row 1
.byte %00111100 ; Row 2
.byte %01111110 ; Row 3
.byte %11111111 ; Row 4
.byte %10111101 ; Row 5
.byte %00100100 ; Row 6
.byte %00100100 ; Row 7
; High plane
.byte %00000000
.byte %00011000
.byte %00011000
.byte %00111100
.byte %01000010
.byte %01000010
.byte %00011000
.byte %00000000
; Fill rest of CHR-ROM (8KB total = 8192 bytes, used 128 so far)
.res 8192 - 128, $00
Build It
ca65 nexus.asm -o nexus.o
ld65 -C nes.cfg nexus.o -o nexus.nes
The arena now has character. Custom tiles transform a functional border into something that looks designed.
Next
The tiles look good but use only one palette. Unit 6 adds colour regions with the attribute table.
What Changed
| 1 | 1 | ; ============================================================================= | |
| 2 | - | ; NEON NEXUS - Unit 4: The Background | |
| 2 | + | ; NEON NEXUS - Unit 5: Custom Tiles | |
| 3 | 3 | ; ============================================================================= | |
| 4 | - | ; Add a bordered arena using the nametable. | |
| 4 | + | ; Design better tile graphics for the arena. | |
| 5 | 5 | ; ============================================================================= | |
| 6 | 6 | | |
| 7 | 7 | ; ----------------------------------------------------------------------------- | |
| ... | |||
| 36 | 36 | PLAYER_START_Y = 116 | |
| 37 | 37 | PLAYER_SPEED = 2 | |
| 38 | 38 | | |
| 39 | - | ; Tile indices | |
| 40 | - | TILE_EMPTY = 0 | |
| 41 | - | TILE_BORDER = 1 | |
| 42 | - | TILE_FLOOR = 2 | |
| 43 | - | TILE_PLAYER = 3 | |
| 39 | + | ; Tile indices (background) | |
| 40 | + | TILE_EMPTY = 0 | |
| 41 | + | TILE_BORDER = 1 | |
| 42 | + | TILE_FLOOR = 2 | |
| 43 | + | TILE_CORNER_TL = 3 ; Top-left corner | |
| 44 | + | TILE_CORNER_TR = 4 ; Top-right corner | |
| 45 | + | TILE_CORNER_BL = 5 ; Bottom-left corner | |
| 46 | + | TILE_CORNER_BR = 6 ; Bottom-right corner | |
| 44 | 47 | | |
| 45 | - | ; Arena boundaries (in pixels, accounting for border) | |
| 46 | - | ARENA_LEFT = 16 ; 2 border tiles × 8 | |
| 47 | - | ARENA_RIGHT = 232 ; 256 - 16 - 8 (sprite width) | |
| 48 | + | ; Sprite tiles (after background tiles in pattern table 0) | |
| 49 | + | SPRITE_PLAYER = 7 | |
| 50 | + | | |
| 51 | + | ; Arena boundaries | |
| 52 | + | ARENA_LEFT = 16 | |
| 53 | + | ARENA_RIGHT = 232 | |
| 48 | 54 | ARENA_TOP = 16 | |
| 49 | - | ARENA_BOTTOM = 208 ; 240 - 16 - 16 (overscan + border) | |
| 55 | + | ARENA_BOTTOM = 208 | |
| 50 | 56 | | |
| 51 | - | ; Palette | |
| 52 | - | BG_COLOUR = $0F ; Black background | |
| 57 | + | BG_COLOUR = $0F | |
| 53 | 58 | | |
| 54 | 59 | ; ----------------------------------------------------------------------------- | |
| 55 | 60 | ; Memory Layout | |
| ... | |||
| 59 | 64 | player_y: .res 1 | |
| 60 | 65 | buttons: .res 1 | |
| 61 | 66 | temp: .res 1 | |
| 67 | + | row_counter: .res 1 | |
| 62 | 68 | | |
| 63 | 69 | .segment "OAM" | |
| 64 | 70 | oam_buffer: .res 256 | |
| ... | |||
| 114 | 120 | bit PPUSTATUS | |
| 115 | 121 | bpl @vblank2 | |
| 116 | 122 | | |
| 117 | - | ; Load palette | |
| 118 | 123 | jsr load_palette | |
| 119 | - | | |
| 120 | - | ; Draw the arena | |
| 121 | 124 | jsr draw_arena | |
| 122 | 125 | | |
| 123 | 126 | ; Set up player | |
| ... | |||
| 129 | 132 | ; Initialise player sprite | |
| 130 | 133 | lda player_y | |
| 131 | 134 | sta oam_buffer+0 | |
| 132 | - | lda #TILE_PLAYER | |
| 135 | + | lda #SPRITE_PLAYER | |
| 133 | 136 | sta oam_buffer+1 | |
| 134 | 137 | lda #0 | |
| 135 | 138 | sta oam_buffer+2 | |
| ... | |||
| 144 | 147 | inx | |
| 145 | 148 | bne @hide_sprites | |
| 146 | 149 | | |
| 147 | - | ; Reset scroll | |
| 148 | 150 | lda #0 | |
| 149 | 151 | sta PPUSCROLL | |
| 150 | 152 | sta PPUSCROLL | |
| 151 | 153 | | |
| 152 | - | ; Enable rendering | |
| 153 | - | lda #%10000000 ; NMI on, background and sprites from pattern table 0 | |
| 154 | + | ; Enable rendering - both background and sprites from pattern table 0 | |
| 155 | + | lda #%10000000 | |
| 154 | 156 | sta PPUCTRL | |
| 155 | - | lda #%00011110 ; Show sprites and background | |
| 157 | + | lda #%00011110 | |
| 156 | 158 | sta PPUMASK | |
| 157 | 159 | | |
| 158 | - | ; === Main Loop === | |
| 159 | 160 | main_loop: | |
| 160 | 161 | jsr read_controller | |
| 161 | 162 | jsr move_player | |
| ... | |||
| 181 | 182 | rts | |
| 182 | 183 | | |
| 183 | 184 | ; ----------------------------------------------------------------------------- | |
| 184 | - | ; Draw Arena | |
| 185 | + | ; Draw Arena (with corner tiles) | |
| 185 | 186 | ; ----------------------------------------------------------------------------- | |
| 186 | 187 | draw_arena: | |
| 187 | - | ; Set PPU address to start of nametable ($2000) | |
| 188 | 188 | bit PPUSTATUS | |
| 189 | 189 | lda #$20 | |
| 190 | 190 | sta PPUADDR | |
| 191 | 191 | lda #$00 | |
| 192 | 192 | sta PPUADDR | |
| 193 | 193 | | |
| 194 | - | ; Draw 30 rows | |
| 195 | - | ldy #0 ; Row counter | |
| 194 | + | lda #0 | |
| 195 | + | sta row_counter | |
| 196 | 196 | | |
| 197 | 197 | @draw_row: | |
| 198 | - | ; Check if first row, last row, or middle | |
| 199 | - | cpy #0 | |
| 200 | - | beq @border_row | |
| 201 | - | cpy #1 | |
| 202 | - | beq @border_row | |
| 203 | - | cpy #28 | |
| 204 | - | beq @border_row | |
| 205 | - | cpy #29 | |
| 206 | - | beq @border_row | |
| 198 | + | lda row_counter | |
| 207 | 199 | | |
| 208 | - | ; Middle row: border + floor + border | |
| 200 | + | ; Row 0: top border with corners | |
| 201 | + | cmp #0 | |
| 202 | + | beq @top_row | |
| 203 | + | cmp #1 | |
| 204 | + | beq @top_row | |
| 205 | + | | |
| 206 | + | ; Row 28-29: bottom border with corners | |
| 207 | + | cmp #28 | |
| 208 | + | beq @bottom_row | |
| 209 | + | cmp #29 | |
| 210 | + | beq @bottom_row | |
| 211 | + | | |
| 212 | + | ; Middle rows | |
| 209 | 213 | jmp @middle_row | |
| 210 | 214 | | |
| 211 | - | @border_row: | |
| 212 | - | ; All border tiles | |
| 215 | + | @top_row: | |
| 216 | + | lda row_counter | |
| 217 | + | cmp #0 | |
| 218 | + | bne @top_row_inner | |
| 219 | + | | |
| 220 | + | ; Very top row with corners | |
| 221 | + | lda #TILE_CORNER_TL | |
| 222 | + | sta PPUDATA | |
| 223 | + | lda #TILE_BORDER | |
| 224 | + | ldx #30 | |
| 225 | + | @top_fill: | |
| 226 | + | sta PPUDATA | |
| 227 | + | dex | |
| 228 | + | bne @top_fill | |
| 229 | + | lda #TILE_CORNER_TR | |
| 230 | + | sta PPUDATA | |
| 231 | + | jmp @next_row | |
| 232 | + | | |
| 233 | + | @top_row_inner: | |
| 234 | + | ; Second row - all border | |
| 235 | + | lda #TILE_BORDER | |
| 213 | 236 | ldx #32 | |
| 214 | - | @border_loop: | |
| 237 | + | @top_inner_fill: | |
| 238 | + | sta PPUDATA | |
| 239 | + | dex | |
| 240 | + | bne @top_inner_fill | |
| 241 | + | jmp @next_row | |
| 242 | + | | |
| 243 | + | @bottom_row: | |
| 244 | + | lda row_counter | |
| 245 | + | cmp #29 | |
| 246 | + | bne @bottom_row_inner | |
| 247 | + | | |
| 248 | + | ; Very bottom row with corners | |
| 249 | + | lda #TILE_CORNER_BL | |
| 250 | + | sta PPUDATA | |
| 215 | 251 | lda #TILE_BORDER | |
| 252 | + | ldx #30 | |
| 253 | + | @bottom_fill: | |
| 216 | 254 | sta PPUDATA | |
| 217 | 255 | dex | |
| 218 | - | bne @border_loop | |
| 256 | + | bne @bottom_fill | |
| 257 | + | lda #TILE_CORNER_BR | |
| 258 | + | sta PPUDATA | |
| 259 | + | jmp @next_row | |
| 260 | + | | |
| 261 | + | @bottom_row_inner: | |
| 262 | + | ; Row 28 - all border | |
| 263 | + | lda #TILE_BORDER | |
| 264 | + | ldx #32 | |
| 265 | + | @bottom_inner_fill: | |
| 266 | + | sta PPUDATA | |
| 267 | + | dex | |
| 268 | + | bne @bottom_inner_fill | |
| 219 | 269 | jmp @next_row | |
| 220 | 270 | | |
| 221 | 271 | @middle_row: | |
| 222 | - | ; Left border (2 tiles) | |
| 272 | + | ; Left border | |
| 223 | 273 | lda #TILE_BORDER | |
| 224 | 274 | sta PPUDATA | |
| 225 | 275 | sta PPUDATA | |
| 226 | 276 | | |
| 227 | - | ; Floor (28 tiles) | |
| 228 | - | ldx #28 | |
| 229 | - | @floor_loop: | |
| 277 | + | ; Floor | |
| 230 | 278 | lda #TILE_FLOOR | |
| 279 | + | ldx #28 | |
| 280 | + | @floor_fill: | |
| 231 | 281 | sta PPUDATA | |
| 232 | 282 | dex | |
| 233 | - | bne @floor_loop | |
| 283 | + | bne @floor_fill | |
| 234 | 284 | | |
| 235 | - | ; Right border (2 tiles) | |
| 285 | + | ; Right border | |
| 236 | 286 | lda #TILE_BORDER | |
| 237 | 287 | sta PPUDATA | |
| 238 | 288 | sta PPUDATA | |
| 239 | 289 | | |
| 240 | 290 | @next_row: | |
| 241 | - | iny | |
| 242 | - | cpy #30 | |
| 243 | - | bne @draw_row | |
| 291 | + | inc row_counter | |
| 292 | + | lda row_counter | |
| 293 | + | cmp #30 | |
| 294 | + | beq @done_drawing | |
| 295 | + | jmp @draw_row | |
| 244 | 296 | | |
| 297 | + | @done_drawing: | |
| 245 | 298 | rts | |
| 246 | 299 | | |
| 247 | 300 | ; ----------------------------------------------------------------------------- | |
| ... | |||
| 266 | 319 | ; Move Player | |
| 267 | 320 | ; ----------------------------------------------------------------------------- | |
| 268 | 321 | move_player: | |
| 269 | - | ; UP | |
| 270 | 322 | lda buttons | |
| 271 | 323 | and #BTN_UP | |
| 272 | 324 | beq @check_down | |
| ... | |||
| 321 | 373 | tya | |
| 322 | 374 | pha | |
| 323 | 375 | | |
| 324 | - | ; DMA sprites | |
| 325 | 376 | lda #0 | |
| 326 | 377 | sta OAMADDR | |
| 327 | 378 | lda #>oam_buffer | |
| 328 | 379 | sta OAMDMA | |
| 329 | 380 | | |
| 330 | - | ; Update sprite position | |
| 331 | 381 | lda player_y | |
| 332 | 382 | sta oam_buffer+0 | |
| 333 | 383 | lda player_x | |
| 334 | 384 | sta oam_buffer+3 | |
| 335 | 385 | | |
| 336 | - | ; Reset scroll (important after any PPU access) | |
| 337 | 386 | lda #0 | |
| 338 | 387 | sta PPUSCROLL | |
| 339 | 388 | sta PPUSCROLL | |
| ... | |||
| 352 | 401 | ; Data | |
| 353 | 402 | ; ----------------------------------------------------------------------------- | |
| 354 | 403 | palette_data: | |
| 355 | - | ; Background palettes | |
| 356 | - | .byte BG_COLOUR, $12, $21, $30 ; Palette 0: black, blue, cyan (border), white | |
| 357 | - | .byte BG_COLOUR, $12, $21, $30 ; Palette 1 | |
| 358 | - | .byte BG_COLOUR, $12, $21, $30 ; Palette 2 | |
| 359 | - | .byte BG_COLOUR, $12, $21, $30 ; Palette 3 | |
| 404 | + | ; Background palettes - neon theme | |
| 405 | + | .byte BG_COLOUR, $11, $21, $31 ; Blue gradient | |
| 406 | + | .byte BG_COLOUR, $11, $21, $31 | |
| 407 | + | .byte BG_COLOUR, $11, $21, $31 | |
| 408 | + | .byte BG_COLOUR, $11, $21, $31 | |
| 360 | 409 | ; Sprite palettes | |
| 361 | - | .byte BG_COLOUR, $30, $20, $16 ; Palette 0: black, white, red, orange | |
| 362 | - | .byte BG_COLOUR, $30, $20, $16 ; Palette 1 | |
| 363 | - | .byte BG_COLOUR, $30, $20, $16 ; Palette 2 | |
| 364 | - | .byte BG_COLOUR, $30, $20, $16 ; Palette 3 | |
| 410 | + | .byte BG_COLOUR, $30, $27, $17 ; White, orange, brown | |
| 411 | + | .byte BG_COLOUR, $30, $27, $17 | |
| 412 | + | .byte BG_COLOUR, $30, $27, $17 | |
| 413 | + | .byte BG_COLOUR, $30, $27, $17 | |
| 365 | 414 | | |
| 366 | 415 | ; ----------------------------------------------------------------------------- | |
| 367 | 416 | ; Vectors | |
| ... | |||
| 372 | 421 | .word irq | |
| 373 | 422 | | |
| 374 | 423 | ; ----------------------------------------------------------------------------- | |
| 375 | - | ; CHR-ROM | |
| 424 | + | ; CHR-ROM - Background Tiles (Pattern Table 0) | |
| 376 | 425 | ; ----------------------------------------------------------------------------- | |
| 377 | 426 | .segment "CHARS" | |
| 378 | - | | |
| 379 | - | ; Tile 0: Empty (transparent) | |
| 380 | - | .byte $00,$00,$00,$00,$00,$00,$00,$00 | |
| 381 | - | .byte $00,$00,$00,$00,$00,$00,$00,$00 | |
| 382 | - | | |
| 383 | - | ; Tile 1: Border (solid cyan block) | |
| 384 | - | .byte $00,$00,$00,$00,$00,$00,$00,$00 ; Low plane = 0 | |
| 385 | - | .byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; High plane = 1 (colour 2 = cyan) | |
| 386 | 427 | | |
| 387 | - | ; Tile 2: Floor (empty/dark) | |
| 428 | + | ; Tile 0: Empty | |
| 388 | 429 | .byte $00,$00,$00,$00,$00,$00,$00,$00 | |
| 389 | 430 | .byte $00,$00,$00,$00,$00,$00,$00,$00 | |
| 390 | 431 | | |
| 391 | - | ; Tile 3: Player sprite (arrow) | |
| 392 | - | .byte %00011000 | |
| 393 | - | .byte %00111100 | |
| 432 | + | ; Tile 1: Border (brick pattern) | |
| 433 | + | .byte %11111111 ; Row 0 | |
| 434 | + | .byte %10000001 ; Row 1 | |
| 435 | + | .byte %10000001 ; Row 2 | |
| 436 | + | .byte %11111111 ; Row 3 | |
| 437 | + | .byte %11111111 ; Row 4 | |
| 438 | + | .byte %00010001 ; Row 5 | |
| 439 | + | .byte %00010001 ; Row 6 | |
| 440 | + | .byte %11111111 ; Row 7 | |
| 441 | + | ; High plane - add colour variation | |
| 442 | + | .byte %00000000 | |
| 394 | 443 | .byte %01111110 | |
| 395 | - | .byte %11111111 | |
| 396 | - | .byte %00111100 | |
| 397 | - | .byte %00111100 | |
| 398 | - | .byte %00111100 | |
| 399 | - | .byte %00111100 | |
| 444 | + | .byte %01111110 | |
| 445 | + | .byte %00000000 | |
| 446 | + | .byte %00000000 | |
| 447 | + | .byte %11101110 | |
| 448 | + | .byte %11101110 | |
| 449 | + | .byte %00000000 | |
| 450 | + | | |
| 451 | + | ; Tile 2: Floor (subtle grid) | |
| 452 | + | .byte %00000000 | |
| 453 | + | .byte %00000000 | |
| 454 | + | .byte %00000000 | |
| 455 | + | .byte %00000000 | |
| 456 | + | .byte %00000000 | |
| 457 | + | .byte %00000000 | |
| 458 | + | .byte %00000000 | |
| 459 | + | .byte %10000001 | |
| 460 | + | ; High plane | |
| 400 | 461 | .byte %00000000 | |
| 401 | 462 | .byte %00000000 | |
| 402 | 463 | .byte %00000000 | |
| ... | |||
| 406 | 467 | .byte %00000000 | |
| 407 | 468 | .byte %00000000 | |
| 408 | 469 | | |
| 409 | - | ; Fill rest of CHR-ROM | |
| 410 | - | .res 8192 - 64, $00 | |
| 470 | + | ; Tile 3: Corner TL | |
| 471 | + | .byte %11111111 | |
| 472 | + | .byte %11000000 | |
| 473 | + | .byte %10100000 | |
| 474 | + | .byte %10010000 | |
| 475 | + | .byte %10001000 | |
| 476 | + | .byte %10000100 | |
| 477 | + | .byte %10000010 | |
| 478 | + | .byte %10000001 | |
| 479 | + | .byte %00000000 | |
| 480 | + | .byte %00111111 | |
| 481 | + | .byte %01011111 | |
| 482 | + | .byte %01101111 | |
| 483 | + | .byte %01110111 | |
| 484 | + | .byte %01111011 | |
| 485 | + | .byte %01111101 | |
| 486 | + | .byte %01111110 | |
| 487 | + | | |
| 488 | + | ; Tile 4: Corner TR | |
| 489 | + | .byte %11111111 | |
| 490 | + | .byte %00000011 | |
| 491 | + | .byte %00000101 | |
| 492 | + | .byte %00001001 | |
| 493 | + | .byte %00010001 | |
| 494 | + | .byte %00100001 | |
| 495 | + | .byte %01000001 | |
| 496 | + | .byte %10000001 | |
| 497 | + | .byte %00000000 | |
| 498 | + | .byte %11111100 | |
| 499 | + | .byte %11111010 | |
| 500 | + | .byte %11110110 | |
| 501 | + | .byte %11101110 | |
| 502 | + | .byte %11011110 | |
| 503 | + | .byte %10111110 | |
| 504 | + | .byte %01111110 | |
| 505 | + | | |
| 506 | + | ; Tile 5: Corner BL | |
| 507 | + | .byte %10000001 | |
| 508 | + | .byte %10000010 | |
| 509 | + | .byte %10000100 | |
| 510 | + | .byte %10001000 | |
| 511 | + | .byte %10010000 | |
| 512 | + | .byte %10100000 | |
| 513 | + | .byte %11000000 | |
| 514 | + | .byte %11111111 | |
| 515 | + | .byte %01111110 | |
| 516 | + | .byte %01111101 | |
| 517 | + | .byte %01111011 | |
| 518 | + | .byte %01110111 | |
| 519 | + | .byte %01101111 | |
| 520 | + | .byte %01011111 | |
| 521 | + | .byte %00111111 | |
| 522 | + | .byte %00000000 | |
| 523 | + | | |
| 524 | + | ; Tile 6: Corner BR | |
| 525 | + | .byte %10000001 | |
| 526 | + | .byte %01000001 | |
| 527 | + | .byte %00100001 | |
| 528 | + | .byte %00010001 | |
| 529 | + | .byte %00001001 | |
| 530 | + | .byte %00000101 | |
| 531 | + | .byte %00000011 | |
| 532 | + | .byte %11111111 | |
| 533 | + | .byte %01111110 | |
| 534 | + | .byte %10111110 | |
| 535 | + | .byte %11011110 | |
| 536 | + | .byte %11101110 | |
| 537 | + | .byte %11110110 | |
| 538 | + | .byte %11111010 | |
| 539 | + | .byte %11111100 | |
| 540 | + | .byte %00000000 | |
| 541 | + | | |
| 542 | + | ; Sprite 0: Player (better ship design) - at tile index 0 in sprite table | |
| 543 | + | ; This goes immediately after background tiles | |
| 544 | + | .byte %00011000 ; Row 0 | |
| 545 | + | .byte %00011000 ; Row 1 | |
| 546 | + | .byte %00111100 ; Row 2 | |
| 547 | + | .byte %01111110 ; Row 3 | |
| 548 | + | .byte %11111111 ; Row 4 | |
| 549 | + | .byte %10111101 ; Row 5 | |
| 550 | + | .byte %00100100 ; Row 6 | |
| 551 | + | .byte %00100100 ; Row 7 | |
| 552 | + | ; High plane | |
| 553 | + | .byte %00000000 | |
| 554 | + | .byte %00011000 | |
| 555 | + | .byte %00011000 | |
| 556 | + | .byte %00111100 | |
| 557 | + | .byte %01000010 | |
| 558 | + | .byte %01000010 | |
| 559 | + | .byte %00011000 | |
| 560 | + | .byte %00000000 | |
| 561 | + | | |
| 562 | + | ; Fill rest of CHR-ROM (8KB total = 8192 bytes, used 128 so far) | |
| 563 | + | .res 8192 - 128, $00 | |
| 411 | 564 | |