Lab3
Introduction
In this lab, I implemented a Pong game in 6502 Assembly Language. Pong is a classic game, and recreating it provided me with an opportunity to dive deep into assembly programming while learning how to handle graphics, input, and game logic efficiently.
This blog post outlines the implementation, key challenges faced, and my reflections on the project.
Project Overview
The goal of this project was to create a functional version of Pong in 6502 Assembly Language. This involved three key objectives: first, to display a moving ball on the screen with smooth updates; second, to allow the player to control a paddle using arrow keys for interaction; and third, to implement collision detection to ensure the ball bounces off walls and the paddle accurately, creating a playable and engaging game.
Code Implementation
; Memory Locations
define ROW $20 ; Ball's vertical position
define COL $21 ; Ball's horizontal position
define DELTAX $30 ; Ball's horizontal movement increment
define DELTAY $31 ; Ball's vertical movement increment
define PADDLEL $40 ; Left edge of paddle
define PADDLER $41 ; Right edge of paddle
define DOT $01 ; Ball pixel value
define PADDLE $05 ; Paddle pixel value
define SCORE $24 ; Player's score counter
; Program Entry Point
start:
ldy #$00
display_help:
lda help, y
beq initialize_game
sta $f000, y
iny
bne display_help
initialize_game:
lda #$10 ; Start ball in the middle vertically
sta ROW
lda #$10 ; Start ball in the middle horizontally
sta COL
lda #$01 ; Ball's initial horizontal direction
sta DELTAX
lda #$01 ; Ball's initial vertical direction
sta DELTAY
lda #$08 ; Paddle's left edge position
sta PADDLEL
lda #$12 ; Paddle's right edge position
sta PADDLER
lda #$00 ; Reset player score
sta SCORE
; Main Game Loop
main_loop:
jsr erase_ball ; Remove ball from previous position
jsr move_ball ; Update ball position based on direction
jsr render_ball ; Draw ball at new position
jsr process_input ; Handle paddle movement
jsr render_paddle ; Redraw paddle
jsr check_bounces ; Check for collisions
jsr timing_delay ; Control game speed
jmp main_loop
; Remove ball from its current position on the screen
erase_ball:
ldy ROW
lda table_low, y
sta $10
lda table_high, y
sta $11
ldy COL
lda #$00 ; Reset to background color
sta ($10), y
rts
; Draw ball at its new position
render_ball:
ldy ROW
lda table_low, y
sta $10
lda table_high, y
sta $11
ldy COL
lda #DOT ; Ball pixel value
sta ($10), y
rts
; Redraw paddle at the bottom of the screen
render_paddle:
ldy #$1F ; Row for paddle
lda table_low, y
sta $10
lda table_high, y
sta $11
ldy PADDLEL
paddle_draw_loop:
lda #PADDLE
sta ($10), y
iny
cpy PADDLER
bne paddle_draw_loop
rts
; Update ball position based on movement deltas
move_ball:
lda COL
clc
adc DELTAX
sta COL
lda ROW
clc
adc DELTAY
sta ROW
rts
; Check for collisions with screen edges or paddle
check_bounces:
lda COL
cmp #$1F ; Right edge
bcc check_left
lda #$FF ; Reverse horizontal movement
sta DELTAX
check_left:
lda COL
cmp #$00 ; Left edge
bcs check_bottom
lda #$01 ; Reverse horizontal movement
sta DELTAX
check_bottom:
lda ROW
cmp #$1E ; Bottom edge
bcc check_top
jsr paddle_collision
lda #$FF ; Reverse vertical movement
sta DELTAY
check_top:
lda ROW
cmp #$00 ; Top edge
bcs done_bounce
lda #$01 ; Reverse vertical movement
sta DELTAY
done_bounce:
rts
; Handle paddle collision logic
paddle_collision:
lda COL
cmp PADDLEL
bcc miss_paddle
cmp PADDLER
bcs miss_paddle
lda #$01
sta DELTAY ; Reverse vertical movement on paddle hit
inc SCORE ; Increment player score
lda $FF ; Slightly randomize horizontal movement
and #$03
sta DELTAX
rts
miss_paddle:
jsr end_game
rts
; Handle keyboard input to move paddle
process_input:
lda $FF
cmp #$81 ; Right arrow key
bne move_left
lda PADDLER
cmp #$1F ; Right boundary
bcs input_done
inc PADDLEL ; Move paddle right
inc PADDLER
rts
move_left:
cmp #$83 ; Left arrow key
bne input_done
lda PADDLEL
cmp #$00 ; Left boundary
bcs input_done
dec PADDLEL ; Move paddle left
dec PADDLER
input_done:
rts
; Timing delay to control game speed
timing_delay:
ldx #$7F
ldy #$0F
delay_outer:
dex
bne delay_inner
dey
bne delay_outer
rts
delay_inner:
jmp delay_outer
; Clear the screen and end the game
end_game:
lda $F000 ; Clear the screen
jsr screen_clear
lda #$00
sta $F010 ; Display "Game Over"
brk
; Reset screen to blank
screen_clear:
ldx #$00
clear_loop:
lda #$00
sta $F000, x
inx
cpx #$FF
bne clear_loop
rts
; Address tables for screen memory
table_high:
dcb $02, $02, $02, $02, $02, $02, $02, $02
dcb $03, $03, $03, $03, $03, $03, $03, $03
dcb $04, $04, $04, $04, $04, $04, $04, $04
dcb $05, $05, $05, $05, $05, $05, $05, $05
table_low:
dcb $00, $20, $40, $60, $80, $A0, $C0, $E0
dcb $00, $20, $40, $60, $80, $A0, $C0, $E0
dcb $00, $20, $40, $60, $80, $A0, $C0, $E0
dcb $00, $20, $40, $60, $80, $A0, $C0, $E0
Challenges Faced
Reflections
This project was a rewarding experience that helped me appreciate the complexity of low-level programming. I learned how important modular design is, even in assembly, to manage code efficiently. The process also highlighted how simple games require precise implementation of timing, memory management, and user input handling for smooth gameplay.
Comments
Post a Comment