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

Working with 6502 Assembly Language was challenging as I had to learn addressing modes and memory mapping from scratch. Setting up delays to balance game speed required careful tuning since the loops had to be neither too fast nor too slow. Collision detection, particularly between the ball and the paddle, was tricky and needed multiple iterations to ensure accuracy, especially for edge cases where the ball hit the paddle's corners.


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

Popular posts from this blog

Project Stage 2

Lab1

Project Stage 1