High Score
Give players a target. Tracking and displaying the best score creates replayability and personal challenge.
The Target
A game without a high score is a game without memory. Each session exists in isolation — players have no sense of progress, no target to beat, no reason to replay.
The high score changes everything. Now there’s a goal beyond “finish the song.” Players compete against their past selves, pushing for that extra perfect hit, taking risks to maintain their multiplier.
Storage
High score needs two bytes — same as the regular score. But unlike the regular score, it persists across games within a session:
; High score variables (Unit 14)
high_score_lo: !byte $00 ; Best score low byte (persists between games)
high_score_hi: !byte $00 ; Best score high byte
Note what we’re NOT doing: saving to disk. That’s complexity we don’t need. The high score persists as long as the program runs. Turn off the machine, it resets. This is how most arcade games worked — and it’s enough to create that competitive tension.
Comparison
After each game ends, we compare the current score against the high score. This requires 16-bit comparison — check the high byte first, only compare low bytes if the high bytes are equal:
check_high_score:
; Compare high byte first
lda score_hi
cmp high_score_hi
bcc chs_done ; Current < high, done
bne chs_new_high ; Current > high, new record
; High bytes equal, compare low bytes
lda score_lo
cmp high_score_lo
bcc chs_done ; Current < high, done
beq chs_done ; Current = high, done
chs_new_high:
; New high score!
lda score_lo
sta high_score_lo
lda score_hi
sta high_score_hi
chs_done:
rts
The logic flow:
- Compare high bytes
- If current high byte is less, we’re done (not a record)
- If current high byte is greater, it’s a new record
- If equal, compare low bytes
- Only update if current is strictly greater
Triggering the Check
The high score check happens at game end — both victory and game over:
; No notes left - victory!
jsr silence_all
jsr check_high_score ; Check for new high score
lda #STATE_VICTORY
sta game_state
jsr draw_victory_screen
; Game over!
jsr silence_all
jsr check_high_score ; Check for new high score
lda #STATE_GAMEOVER
sta game_state
jsr draw_gameover_screen
Display
The end screens now show both the current score and the high score. We draw the high score in yellow to distinguish it:
; Draw "High: NNNNNN"
ldx #$00
dfs_high:
lda highscore_text,x
beq dfs_high_done
sta SCREEN + (14 * 40) + 14,x
lda #COL_YELLOW
sta COLOUR + (14 * 40) + 14,x
inx
bne dfs_high
dfs_high_done:
Converting the high score to digits reuses our existing convert_score routine. We temporarily swap the high score into the score variables, convert, then restore:
; Save current score temporarily
lda score_lo
pha
lda score_hi
pha
; Put high score into score for conversion
lda high_score_lo
sta score_lo
lda high_score_hi
sta score_hi
jsr convert_score
; Restore current score
pla
sta score_hi
pla
sta score_lo
This technique — temporarily using existing variables for a different purpose — is common in 6502 programming. It saves memory and avoids duplicating conversion logic.
The Psychology
Watch how players behave with a high score:
- First game: They’re learning, score doesn’t matter
- Second game: Now they have a target — their first score
- Third game: They beat it! New target set
- Fourth game: They fall short. Frustration drives one more try…
This loop is addictive. The high score turns a five-minute game into a thirty-minute session. Players aren’t just playing — they’re competing.
Why Not Save to Disk?
Saving to disk would make the high score truly persistent. But consider:
- Complexity: File I/O on the C64 involves serial communication, error handling, and file management
- Speed: Disk operations are slow and would interrupt the flow
- Authenticity: Arcade games didn’t save high scores (mostly)
- Scope: This is Unit 14 of 16 — we have other features to add
The simple approach works. Save disk I/O for a later lesson.
What’s Next
The game now tracks achievements across plays. In Unit 15, we add pause functionality — letting players take a break mid-song without losing progress.