Moving the Player
Add controller input — move your sprite with the D-pad.
What You’re Building
The sprite now moves. Press the D-pad and watch it respond.

This is the moment it becomes a game.
The Code
; =============================================================================
; NEON NEXUS - Unit 2: Moving the Player
; =============================================================================
; The player sprite now moves with the D-pad.
; Press Up, Down, Left, Right to move around the screen.
; =============================================================================
; -----------------------------------------------------------------------------
; NES Hardware Addresses
; -----------------------------------------------------------------------------
PPUCTRL = $2000
PPUMASK = $2001
PPUSTATUS = $2002
OAMADDR = $2003
PPUADDR = $2006
PPUDATA = $2007
OAMDMA = $4014
JOYPAD1 = $4016 ; Controller 1
JOYPAD2 = $4017 ; Controller 2
; Controller button masks
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_TILE = 1
BG_COLOUR = $12
PLAYER_SPEED = 2 ; Pixels per frame (try 1, 2, or 3)
; Screen boundaries
SCREEN_LEFT = 0
SCREEN_RIGHT = 248 ; 256 - 8 (sprite width)
SCREEN_TOP = 0
SCREEN_BOTTOM = 224 ; 240 - 16 (sprite height + overscan)
; -----------------------------------------------------------------------------
; Memory Layout
; -----------------------------------------------------------------------------
.segment "ZEROPAGE"
player_x: .res 1
player_y: .res 1
buttons: .res 1 ; Current button state
.segment "OAM"
oam_buffer: .res 256
.segment "BSS"
; -----------------------------------------------------------------------------
; iNES Header
; -----------------------------------------------------------------------------
.segment "HEADER"
.byte "NES", $1A
.byte 2 ; 32KB PRG-ROM
.byte 1 ; 8KB CHR-ROM
.byte $01 ; Mapper 0, vertical mirroring
.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
; Load palette
bit PPUSTATUS
lda #$3F
sta PPUADDR
lda #$00
sta PPUADDR
ldx #0
@load_palette:
lda palette_data, x
sta PPUDATA
inx
cpx #32
bne @load_palette
; 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 #PLAYER_TILE
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
; Enable rendering
lda #%10010000
sta PPUCTRL
lda #%00011110
sta PPUMASK
; === Main Loop ===
main_loop:
; Read controller
jsr read_controller
; Move player based on input
jsr move_player
jmp main_loop
; -----------------------------------------------------------------------------
; Read Controller
; -----------------------------------------------------------------------------
read_controller:
; Strobe the controller
lda #1
sta JOYPAD1
lda #0
sta JOYPAD1
; Read 8 buttons into 'buttons' variable
ldx #8
@read_loop:
lda JOYPAD1
lsr a ; Bit 0 -> Carry
rol buttons ; Carry -> buttons
dex
bne @read_loop
rts
; -----------------------------------------------------------------------------
; Move Player
; -----------------------------------------------------------------------------
move_player:
; Check UP
lda buttons
and #BTN_UP
beq @check_down
lda player_y
sec
sbc #PLAYER_SPEED
cmp #SCREEN_TOP
bcc @check_down ; Don't go above top
sta player_y
@check_down:
lda buttons
and #BTN_DOWN
beq @check_left
lda player_y
clc
adc #PLAYER_SPEED
cmp #SCREEN_BOTTOM
bcs @check_left ; Don't go below bottom
sta player_y
@check_left:
lda buttons
and #BTN_LEFT
beq @check_right
lda player_x
sec
sbc #PLAYER_SPEED
cmp #SCREEN_LEFT
bcc @check_right ; Don't go past left edge
sta player_x
@check_right:
lda buttons
and #BTN_RIGHT
beq @done
lda player_x
clc
adc #PLAYER_SPEED
cmp #SCREEN_RIGHT
bcs @done ; Don't go past right edge
sta player_x
@done:
rts
; === NMI ===
nmi:
pha
txa
pha
tya
pha
; DMA sprites
lda #0
sta OAMADDR
lda #>oam_buffer
sta OAMDMA
; Update sprite from player position
lda player_y
sta oam_buffer+0
lda player_x
sta oam_buffer+3
pla
tay
pla
tax
pla
rti
irq:
rti
; -----------------------------------------------------------------------------
; Data
; -----------------------------------------------------------------------------
palette_data:
.byte BG_COLOUR, $00, $10, $20
.byte BG_COLOUR, $00, $10, $20
.byte BG_COLOUR, $00, $10, $20
.byte BG_COLOUR, $00, $10, $20
.byte BG_COLOUR, $30, $20, $0F
.byte BG_COLOUR, $30, $16, $0F
.byte BG_COLOUR, $30, $12, $0F
.byte BG_COLOUR, $30, $14, $0F
; -----------------------------------------------------------------------------
; Vectors
; -----------------------------------------------------------------------------
.segment "VECTORS"
.word nmi
.word reset
.word irq
; -----------------------------------------------------------------------------
; CHR-ROM
; -----------------------------------------------------------------------------
.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: Player sprite
.byte %00011000
.byte %00111100
.byte %01111110
.byte %11111111
.byte %00111100
.byte %00111100
.byte %00111100
.byte %00111100
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.byte %00000000
.res 8192 - 32, $00
Build and Run
ca65 nexus.asm -o nexus.o
ld65 -C nes.cfg nexus.o -o nexus.nes
Use the D-pad (arrow keys in most emulators) to move the sprite around.
What’s New
Two things changed from Unit 1:
1. Reading the Controller
read_controller:
lda #1
sta JOYPAD1 ; Strobe controller
lda #0
sta JOYPAD1
ldx #8
@read_loop:
lda JOYPAD1 ; Read one bit
lsr a ; Shift into Carry
rol buttons ; Rotate into buttons
dex
bne @read_loop
rts
The NES controller sends button states one bit at a time. Strobe it, then read 8 times.
2. Moving Based on Input
move_player:
lda buttons
and #BTN_UP ; Is UP pressed?
beq @check_down ; No? Skip
lda player_y
sec
sbc #PLAYER_SPEED ; Move up
sta player_y
@check_down:
; ... same pattern for other directions
Check each button. If pressed, adjust position. Boundary checks prevent going off screen.
Try This
-
Change speed — Find
PLAYER_SPEED = 2and try1(slow) or4(fast) -
Remove boundaries — Delete the
cmpandbcc/bcslines. Now you can wrap around the screen. -
Invert controls — Swap
BTN_UPwithBTN_DOWNin the movement code.
The Main Loop
Notice the structure:
main_loop:
jsr read_controller
jsr move_player
jmp main_loop
Read input, update game state, repeat. This is a game loop. Every NES game has one.
Next
Unit 3 explains how all this works — the PPU, VBlank, and why the code is structured this way.
What Changed
| 1 | 1 | ; ============================================================================= | |
| 2 | - | ; NEON NEXUS - Unit 1: Hello NES | |
| 2 | + | ; NEON NEXUS - Unit 2: Moving the Player | |
| 3 | 3 | ; ============================================================================= | |
| 4 | - | ; Your first NES program. A sprite on a coloured background. | |
| 5 | - | ; Run it. Change the colours. Move the sprite. Make it yours. | |
| 4 | + | ; The player sprite now moves with the D-pad. | |
| 5 | + | ; Press Up, Down, Left, Right to move around the screen. | |
| 6 | 6 | ; ============================================================================= | |
| 7 | 7 | | |
| 8 | 8 | ; ----------------------------------------------------------------------------- | |
| 9 | 9 | ; NES Hardware Addresses | |
| 10 | 10 | ; ----------------------------------------------------------------------------- | |
| 11 | - | PPUCTRL = $2000 ; PPU control register | |
| 12 | - | PPUMASK = $2001 ; PPU mask register | |
| 13 | - | PPUSTATUS = $2002 ; PPU status register | |
| 14 | - | OAMADDR = $2003 ; OAM address | |
| 15 | - | PPUADDR = $2006 ; PPU address | |
| 16 | - | PPUDATA = $2007 ; PPU data | |
| 17 | - | OAMDMA = $4014 ; OAM DMA register | |
| 11 | + | PPUCTRL = $2000 | |
| 12 | + | PPUMASK = $2001 | |
| 13 | + | PPUSTATUS = $2002 | |
| 14 | + | OAMADDR = $2003 | |
| 15 | + | PPUADDR = $2006 | |
| 16 | + | PPUDATA = $2007 | |
| 17 | + | OAMDMA = $4014 | |
| 18 | + | | |
| 19 | + | JOYPAD1 = $4016 ; Controller 1 | |
| 20 | + | JOYPAD2 = $4017 ; Controller 2 | |
| 21 | + | | |
| 22 | + | ; Controller button masks | |
| 23 | + | BTN_A = %10000000 | |
| 24 | + | BTN_B = %01000000 | |
| 25 | + | BTN_SELECT = %00100000 | |
| 26 | + | BTN_START = %00010000 | |
| 27 | + | BTN_UP = %00001000 | |
| 28 | + | BTN_DOWN = %00000100 | |
| 29 | + | BTN_LEFT = %00000010 | |
| 30 | + | BTN_RIGHT = %00000001 | |
| 18 | 31 | | |
| 19 | 32 | ; ----------------------------------------------------------------------------- | |
| 20 | 33 | ; Game Constants | |
| 21 | 34 | ; ----------------------------------------------------------------------------- | |
| 22 | - | ; Try changing these values and see what happens! | |
| 23 | - | PLAYER_START_X = 124 ; Player X position (0-247) | |
| 24 | - | PLAYER_START_Y = 116 ; Player Y position (0-231) | |
| 25 | - | PLAYER_TILE = 1 ; Which tile to use for the player | |
| 26 | - | BG_COLOUR = $12 ; Background colour (try $01, $21, $31, $0F) | |
| 35 | + | PLAYER_START_X = 124 | |
| 36 | + | PLAYER_START_Y = 116 | |
| 37 | + | PLAYER_TILE = 1 | |
| 38 | + | BG_COLOUR = $12 | |
| 39 | + | | |
| 40 | + | PLAYER_SPEED = 2 ; Pixels per frame (try 1, 2, or 3) | |
| 41 | + | | |
| 42 | + | ; Screen boundaries | |
| 43 | + | SCREEN_LEFT = 0 | |
| 44 | + | SCREEN_RIGHT = 248 ; 256 - 8 (sprite width) | |
| 45 | + | SCREEN_TOP = 0 | |
| 46 | + | SCREEN_BOTTOM = 224 ; 240 - 16 (sprite height + overscan) | |
| 27 | 47 | | |
| 28 | 48 | ; ----------------------------------------------------------------------------- | |
| 29 | 49 | ; Memory Layout | |
| 30 | 50 | ; ----------------------------------------------------------------------------- | |
| 31 | 51 | .segment "ZEROPAGE" | |
| 32 | - | player_x: .res 1 ; Player X position | |
| 33 | - | player_y: .res 1 ; Player Y position | |
| 52 | + | player_x: .res 1 | |
| 53 | + | player_y: .res 1 | |
| 54 | + | buttons: .res 1 ; Current button state | |
| 34 | 55 | | |
| 35 | 56 | .segment "OAM" | |
| 36 | - | oam_buffer: .res 256 ; Sprite data (copied to PPU each frame) | |
| 57 | + | oam_buffer: .res 256 | |
| 37 | 58 | | |
| 38 | 59 | .segment "BSS" | |
| 39 | - | ; General RAM variables go here | |
| 40 | 60 | | |
| 41 | 61 | ; ----------------------------------------------------------------------------- | |
| 42 | 62 | ; iNES Header | |
| 43 | 63 | ; ----------------------------------------------------------------------------- | |
| 44 | 64 | .segment "HEADER" | |
| 45 | - | .byte "NES", $1A ; iNES identifier | |
| 46 | - | .byte 2 ; 2x 16KB PRG-ROM = 32KB | |
| 47 | - | .byte 1 ; 1x 8KB CHR-ROM = 8KB | |
| 65 | + | .byte "NES", $1A | |
| 66 | + | .byte 2 ; 32KB PRG-ROM | |
| 67 | + | .byte 1 ; 8KB CHR-ROM | |
| 48 | 68 | .byte $01 ; Mapper 0, vertical mirroring | |
| 49 | - | .byte $00 ; Mapper 0 | |
| 50 | - | .byte 0,0,0,0,0,0,0,0 ; Padding | |
| 69 | + | .byte $00 | |
| 70 | + | .byte 0,0,0,0,0,0,0,0 | |
| 51 | 71 | | |
| 52 | 72 | ; ----------------------------------------------------------------------------- | |
| 53 | 73 | ; Code | |
| 54 | 74 | ; ----------------------------------------------------------------------------- | |
| 55 | 75 | .segment "CODE" | |
| 56 | 76 | | |
| 57 | - | ; === RESET: Called when NES powers on === | |
| 58 | 77 | reset: | |
| 59 | - | sei ; Disable interrupts | |
| 60 | - | cld ; Clear decimal mode | |
| 78 | + | sei | |
| 79 | + | cld | |
| 61 | 80 | ldx #$40 | |
| 62 | - | stx $4017 ; Disable APU frame IRQ | |
| 81 | + | stx $4017 | |
| 63 | 82 | ldx #$FF | |
| 64 | - | txs ; Set up stack | |
| 65 | - | inx ; X = 0 | |
| 66 | - | stx PPUCTRL ; Disable NMI | |
| 67 | - | stx PPUMASK ; Disable rendering | |
| 68 | - | stx $4010 ; Disable DMC IRQs | |
| 83 | + | txs | |
| 84 | + | inx | |
| 85 | + | stx PPUCTRL | |
| 86 | + | stx PPUMASK | |
| 87 | + | stx $4010 | |
| 69 | 88 | | |
| 70 | - | ; Wait for PPU to stabilise (first wait) | |
| 71 | 89 | @vblank1: | |
| 72 | 90 | bit PPUSTATUS | |
| 73 | 91 | bpl @vblank1 | |
| 74 | 92 | | |
| 75 | - | ; Clear RAM while we wait | |
| 76 | 93 | lda #0 | |
| 77 | 94 | @clear_ram: | |
| 78 | 95 | sta $0000, x | |
| ... | |||
| 86 | 103 | inx | |
| 87 | 104 | bne @clear_ram | |
| 88 | 105 | | |
| 89 | - | ; Wait for PPU (second wait) | |
| 90 | 106 | @vblank2: | |
| 91 | 107 | bit PPUSTATUS | |
| 92 | 108 | bpl @vblank2 | |
| 93 | - | | |
| 94 | - | ; === PPU is ready - set up graphics === | |
| 95 | 109 | | |
| 96 | 110 | ; Load palette | |
| 97 | - | bit PPUSTATUS ; Reset PPU address latch | |
| 111 | + | bit PPUSTATUS | |
| 98 | 112 | lda #$3F | |
| 99 | 113 | sta PPUADDR | |
| 100 | 114 | lda #$00 | |
| 101 | - | sta PPUADDR ; PPU address = $3F00 (palette) | |
| 115 | + | sta PPUADDR | |
| 102 | 116 | | |
| 103 | 117 | ldx #0 | |
| 104 | 118 | @load_palette: | |
| ... | |||
| 108 | 122 | cpx #32 | |
| 109 | 123 | bne @load_palette | |
| 110 | 124 | | |
| 111 | - | ; Set up player sprite | |
| 125 | + | ; Set up player | |
| 112 | 126 | lda #PLAYER_START_X | |
| 113 | 127 | sta player_x | |
| 114 | 128 | lda #PLAYER_START_Y | |
| 115 | 129 | sta player_y | |
| 116 | 130 | | |
| 117 | - | ; Initialise sprite in OAM buffer | |
| 131 | + | ; Initialise player sprite | |
| 118 | 132 | lda player_y | |
| 119 | - | sta oam_buffer+0 ; Y position | |
| 133 | + | sta oam_buffer+0 | |
| 120 | 134 | lda #PLAYER_TILE | |
| 121 | - | sta oam_buffer+1 ; Tile number | |
| 135 | + | sta oam_buffer+1 | |
| 122 | 136 | lda #0 | |
| 123 | - | sta oam_buffer+2 ; Attributes (palette 0, no flip) | |
| 137 | + | sta oam_buffer+2 | |
| 124 | 138 | lda player_x | |
| 125 | - | sta oam_buffer+3 ; X position | |
| 139 | + | sta oam_buffer+3 | |
| 126 | 140 | | |
| 127 | - | ; Hide all other sprites (move off screen) | |
| 141 | + | ; Hide other sprites | |
| 128 | 142 | lda #$FF | |
| 129 | 143 | ldx #4 | |
| 130 | 144 | @hide_sprites: | |
| ... | |||
| 133 | 147 | bne @hide_sprites | |
| 134 | 148 | | |
| 135 | 149 | ; Enable rendering | |
| 136 | - | lda #%10010000 ; Enable NMI, sprites from pattern table 1 | |
| 150 | + | lda #%10010000 | |
| 137 | 151 | sta PPUCTRL | |
| 138 | - | lda #%00011110 ; Show sprites and background | |
| 152 | + | lda #%00011110 | |
| 139 | 153 | sta PPUMASK | |
| 140 | 154 | | |
| 141 | - | ; === Main Loop === | |
| 155 | + | ; === Main Loop === | |
| 142 | 156 | main_loop: | |
| 143 | - | jmp main_loop ; Wait for NMI (nothing to do yet!) | |
| 157 | + | ; Read controller | |
| 158 | + | jsr read_controller | |
| 144 | 159 | | |
| 145 | - | ; === NMI: Called every frame during VBlank === | |
| 160 | + | ; Move player based on input | |
| 161 | + | jsr move_player | |
| 162 | + | | |
| 163 | + | jmp main_loop | |
| 164 | + | | |
| 165 | + | ; ----------------------------------------------------------------------------- | |
| 166 | + | ; Read Controller | |
| 167 | + | ; ----------------------------------------------------------------------------- | |
| 168 | + | read_controller: | |
| 169 | + | ; Strobe the controller | |
| 170 | + | lda #1 | |
| 171 | + | sta JOYPAD1 | |
| 172 | + | lda #0 | |
| 173 | + | sta JOYPAD1 | |
| 174 | + | | |
| 175 | + | ; Read 8 buttons into 'buttons' variable | |
| 176 | + | ldx #8 | |
| 177 | + | @read_loop: | |
| 178 | + | lda JOYPAD1 | |
| 179 | + | lsr a ; Bit 0 -> Carry | |
| 180 | + | rol buttons ; Carry -> buttons | |
| 181 | + | dex | |
| 182 | + | bne @read_loop | |
| 183 | + | | |
| 184 | + | rts | |
| 185 | + | | |
| 186 | + | ; ----------------------------------------------------------------------------- | |
| 187 | + | ; Move Player | |
| 188 | + | ; ----------------------------------------------------------------------------- | |
| 189 | + | move_player: | |
| 190 | + | ; Check UP | |
| 191 | + | lda buttons | |
| 192 | + | and #BTN_UP | |
| 193 | + | beq @check_down | |
| 194 | + | | |
| 195 | + | lda player_y | |
| 196 | + | sec | |
| 197 | + | sbc #PLAYER_SPEED | |
| 198 | + | cmp #SCREEN_TOP | |
| 199 | + | bcc @check_down ; Don't go above top | |
| 200 | + | sta player_y | |
| 201 | + | | |
| 202 | + | @check_down: | |
| 203 | + | lda buttons | |
| 204 | + | and #BTN_DOWN | |
| 205 | + | beq @check_left | |
| 206 | + | | |
| 207 | + | lda player_y | |
| 208 | + | clc | |
| 209 | + | adc #PLAYER_SPEED | |
| 210 | + | cmp #SCREEN_BOTTOM | |
| 211 | + | bcs @check_left ; Don't go below bottom | |
| 212 | + | sta player_y | |
| 213 | + | | |
| 214 | + | @check_left: | |
| 215 | + | lda buttons | |
| 216 | + | and #BTN_LEFT | |
| 217 | + | beq @check_right | |
| 218 | + | | |
| 219 | + | lda player_x | |
| 220 | + | sec | |
| 221 | + | sbc #PLAYER_SPEED | |
| 222 | + | cmp #SCREEN_LEFT | |
| 223 | + | bcc @check_right ; Don't go past left edge | |
| 224 | + | sta player_x | |
| 225 | + | | |
| 226 | + | @check_right: | |
| 227 | + | lda buttons | |
| 228 | + | and #BTN_RIGHT | |
| 229 | + | beq @done | |
| 230 | + | | |
| 231 | + | lda player_x | |
| 232 | + | clc | |
| 233 | + | adc #PLAYER_SPEED | |
| 234 | + | cmp #SCREEN_RIGHT | |
| 235 | + | bcs @done ; Don't go past right edge | |
| 236 | + | sta player_x | |
| 237 | + | | |
| 238 | + | @done: | |
| 239 | + | rts | |
| 240 | + | | |
| 241 | + | ; === NMI === | |
| 146 | 242 | nmi: | |
| 147 | - | pha ; Save registers | |
| 243 | + | pha | |
| 148 | 244 | txa | |
| 149 | 245 | pha | |
| 150 | 246 | tya | |
| 151 | 247 | pha | |
| 152 | 248 | | |
| 153 | - | ; Copy sprite data to PPU | |
| 249 | + | ; DMA sprites | |
| 154 | 250 | lda #0 | |
| 155 | 251 | sta OAMADDR | |
| 156 | - | lda #>oam_buffer ; High byte of $0200 | |
| 157 | - | sta OAMDMA ; Triggers DMA transfer | |
| 252 | + | lda #>oam_buffer | |
| 253 | + | sta OAMDMA | |
| 158 | 254 | | |
| 159 | - | ; Update sprite position from variables | |
| 255 | + | ; Update sprite from player position | |
| 160 | 256 | lda player_y | |
| 161 | 257 | sta oam_buffer+0 | |
| 162 | 258 | lda player_x | |
| 163 | 259 | sta oam_buffer+3 | |
| 164 | 260 | | |
| 165 | - | pla ; Restore registers | |
| 261 | + | pla | |
| 166 | 262 | tay | |
| 167 | 263 | pla | |
| 168 | 264 | tax | |
| 169 | 265 | pla | |
| 170 | 266 | rti | |
| 171 | 267 | | |
| 172 | - | ; === IRQ: Not used === | |
| 173 | 268 | irq: | |
| 174 | 269 | rti | |
| 175 | 270 | | |
| 176 | 271 | ; ----------------------------------------------------------------------------- | |
| 177 | 272 | ; Data | |
| 178 | 273 | ; ----------------------------------------------------------------------------- | |
| 179 | - | | |
| 180 | - | ; Palette data: 4 background palettes + 4 sprite palettes | |
| 181 | 274 | palette_data: | |
| 182 | - | ; Background palettes | |
| 183 | - | .byte BG_COLOUR, $00, $10, $20 ; Palette 0 (background colour) | |
| 184 | - | .byte BG_COLOUR, $00, $10, $20 ; Palette 1 | |
| 185 | - | .byte BG_COLOUR, $00, $10, $20 ; Palette 2 | |
| 186 | - | .byte BG_COLOUR, $00, $10, $20 ; Palette 3 | |
| 187 | - | ; Sprite palettes | |
| 188 | - | .byte BG_COLOUR, $30, $20, $0F ; Palette 0 (player: white, red, black) | |
| 189 | - | .byte BG_COLOUR, $30, $16, $0F ; Palette 1 | |
| 190 | - | .byte BG_COLOUR, $30, $12, $0F ; Palette 2 | |
| 191 | - | .byte BG_COLOUR, $30, $14, $0F ; Palette 3 | |
| 275 | + | .byte BG_COLOUR, $00, $10, $20 | |
| 276 | + | .byte BG_COLOUR, $00, $10, $20 | |
| 277 | + | .byte BG_COLOUR, $00, $10, $20 | |
| 278 | + | .byte BG_COLOUR, $00, $10, $20 | |
| 279 | + | .byte BG_COLOUR, $30, $20, $0F | |
| 280 | + | .byte BG_COLOUR, $30, $16, $0F | |
| 281 | + | .byte BG_COLOUR, $30, $12, $0F | |
| 282 | + | .byte BG_COLOUR, $30, $14, $0F | |
| 192 | 283 | | |
| 193 | 284 | ; ----------------------------------------------------------------------------- | |
| 194 | 285 | ; Vectors | |
| 195 | 286 | ; ----------------------------------------------------------------------------- | |
| 196 | 287 | .segment "VECTORS" | |
| 197 | - | .word nmi ; NMI vector | |
| 198 | - | .word reset ; Reset vector | |
| 199 | - | .word irq ; IRQ vector | |
| 288 | + | .word nmi | |
| 289 | + | .word reset | |
| 290 | + | .word irq | |
| 200 | 291 | | |
| 201 | 292 | ; ----------------------------------------------------------------------------- | |
| 202 | - | ; CHR-ROM (Graphics) | |
| 293 | + | ; CHR-ROM | |
| 203 | 294 | ; ----------------------------------------------------------------------------- | |
| 204 | 295 | .segment "CHARS" | |
| 205 | 296 | | |
| 206 | - | ; Tile 0: Empty (8x8 pixels, all zeros) | |
| 297 | + | ; Tile 0: Empty | |
| 207 | 298 | .byte $00,$00,$00,$00,$00,$00,$00,$00 | |
| 208 | 299 | .byte $00,$00,$00,$00,$00,$00,$00,$00 | |
| 209 | 300 | | |
| 210 | - | ; Tile 1: Player sprite (simple arrow shape) | |
| 211 | - | ; Each tile is 16 bytes: 8 bytes low plane + 8 bytes high plane | |
| 212 | - | ; Colours: 00=transparent, 01=colour 1, 10=colour 2, 11=colour 3 | |
| 213 | - | .byte %00011000 ; Row 0 | |
| 214 | - | .byte %00111100 ; Row 1 | |
| 215 | - | .byte %01111110 ; Row 2 | |
| 216 | - | .byte %11111111 ; Row 3 | |
| 217 | - | .byte %00111100 ; Row 4 | |
| 218 | - | .byte %00111100 ; Row 5 | |
| 219 | - | .byte %00111100 ; Row 6 | |
| 220 | - | .byte %00111100 ; Row 7 | |
| 221 | - | ; High plane (all zeros = use colour 1 only) | |
| 301 | + | ; Tile 1: Player sprite | |
| 302 | + | .byte %00011000 | |
| 303 | + | .byte %00111100 | |
| 304 | + | .byte %01111110 | |
| 305 | + | .byte %11111111 | |
| 306 | + | .byte %00111100 | |
| 307 | + | .byte %00111100 | |
| 308 | + | .byte %00111100 | |
| 309 | + | .byte %00111100 | |
| 222 | 310 | .byte %00000000 | |
| 223 | 311 | .byte %00000000 | |
| 224 | 312 | .byte %00000000 | |
| ... | |||
| 228 | 316 | .byte %00000000 | |
| 229 | 317 | .byte %00000000 | |
| 230 | 318 | | |
| 231 | - | ; Fill rest of CHR-ROM with empty tiles | |
| 232 | 319 | .res 8192 - 32, $00 | |
| 233 | 320 | |