I've finally finished Pong, getting the ball to work was really annoying and I had to rewrite that whole section, but after that it was mostly smooth sailing. I'd say about 70% of the source code is my own work compared to 30% I copy / pasted from tutorials (eg: the "FetchPixel" and "RandomNumberGenerator" procedures). My ultimate assembly goal is to make a full-fledged RPG for the 83+, but this project taught me that I still have quite a while until I'll be good enough to tackle that. My code is below, and I'd really appreciate any feedback since it's a bit of a mess.
Code: .nolist
#include "ti83plus.inc"
.list
.org userMem-2
.db $BB,$6D
Start:
LD (RandData), DE
BCALL(_ClrLCDFull)
BCALL(_HomeUp)
LD HL, TitleScreenText
BCALL(_PutS)
BCALL(_GetKey)
LD A, 0
LD (LeftPaddleScore), A
LD (RightPaddleScore), A ; Sets up intial values
SetUpGame:
LD A, 40
LD (LeftPaddleYPosition), A
LD (RightPaddleYPosition), A
LD A, 48
LD (BallXPosition), A
LD A, 32
LD (BallYPosition), A ; Sets up intial coordinates
LD A, 0
LD (BallHorizontalDirection), A ; 0 = going left, 1 = going right
LD (BallVerticalDirection), A ; 0 = going up, 1 = going down
LD (BallOutOfBounds), A ; Sets up values for start of game state
BCALL(_ClrLCDFull)
CALL DrawPaddles
CALL DrawBall
BCALL(_GrBufCpy)
LD A, 0
LD (CurRow), A
LD A, 0
LD (CurCol), A
LD HL, PromptText
BCALL(_PutS)
LD A, (LeftPaddleScore)
CP 0
JR Z, ZeroLeftPaddle
CP 1
JR Z, OneLeftPaddle
CP 2
JR Z, TwoLeftPaddle
CP 3
JR Z, ThreeLeftPaddle
CP 4
JR Z, FourLeftPaddle
CP 5
JR Z, FiveLeftPaddle
ZeroLeftPaddle:
LD A, 48
LD (LeftPaddleScoreAscii), A
JR ContinueAsciiConversion
OneLeftPaddle:
LD A, 49
LD (LeftPaddleScoreAscii), A
JR ContinueAsciiConversion
TwoLeftPaddle:
LD A, 50
LD (LeftPaddleScoreAscii), A
JR ContinueAsciiConversion
ThreeLeftPaddle:
LD A, 51
LD (LeftPaddleScoreAscii), A
JR ContinueAsciiConversion
FourLeftPaddle
LD A, 52
LD (LeftPaddleScoreAscii), A
JR ContinueAsciiConversion
FiveLeftPaddle:
LD A, 53
LD (LeftPaddleScoreAscii), A
ContinueAsciiConversion:
LD A, (RightPaddleScore)
CP 0
JR Z, ZeroRightPaddle
CP 1
JR Z, OneRightPaddle
CP 2
JR Z, TwoRightPaddle
CP 3
JR Z, ThreeRightPaddle
CP 4
JR Z, FourRightPaddle
CP 5
JR Z, FiveRightPaddle
ZeroRightPaddle:
LD A, 48
LD (RightPaddleScoreAscii), A
JR ContinueSetupGame
OneRightPaddle:
LD A, 49
LD (RightPaddleScoreAscii), A
JR ContinueSetupGame
TwoRightPaddle:
LD A, 50
LD (RightPaddleScoreAscii), A
JR ContinueSetupGame
ThreeRightPaddle:
LD A, 51
LD (RightPaddleScoreAscii), A
JR ContinueSetupGame
FourRightPaddle
LD A, 52
LD (RightPaddleScoreAscii), A
JR ContinueSetupGame
FiveRightPaddle:
LD A, 53
LD (RightPaddleScoreAscii), A ; Super inefficient but it gets the job done and idk how to write a decimal-to-ASCII algorithm
ContinueSetupGame:
LD A, 3
LD (CurCol), A
LD A, 3
LD (CurRow), A
LD A, (LeftPaddleScoreAscii)
BCALL(_PutC)
LD A, 12
LD (CurCol), A
LD A, (RightPaddleScoreAscii)
BCALL(_PutC)
BCALL(_GetKey)
CALL DrawPaddles
CALL DrawBall
GameLoop:
CALL DrawPaddles
CALL DrawBall
BCALL(_GrBufCpy) ; Draws stuff with coordinates from last loop
CALL DrawPaddles
CALL DrawBall ; Clears sprites so there's no overlap when they're drawn again with new coordinates
LD A, %11111110
OUT (1), A
NOP
NOP
IN A, (1)
CP %11110111
CALL Z, LeftPaddleUp
CP %11111110
CALL Z, LeftPaddleDown ; Reads key input
CALL UpdateBallPosition
CALL UpdateRightPaddlePosition
LD A, (BallOutOfBounds)
CP 1
JR Z, ChangeScore
JR GameLoop
ChangeScore:
LD A, (BallXPosition)
CP 86
JR Z, LeftPaddleScoreUp
RightPaddleScoreUp:
LD A, (RightPaddleScore)
INC A
LD (RightPaddleScore), A
CP 6
JP Z, EndGameRightPaddleWon
JP SetupGame
LeftPaddleScoreUp:
LD A, (LeftPaddleScore)
INC A
LD (LeftPaddleScore), A
CP 6
JP Z, EndGameLeftPaddleWon
JP SetupGame
;Handles updating the right paddle's position
;--------------------------------
UpdateRightPaddlePosition:
CALL RandomNumberGenerator
CP 175
JR NC, WrongChoice
LD A, (BallVerticalDirection)
CP 0
JR Z, MoveRightPaddleUp
CP 1
JR Z, MoveRightPaddleDown
MoveRightPaddleUp:
LD HL, (RightPaddleYPosition)
DEC L
LD A, L
CP 14
JR NZ, ContinueRightPaddleUp
LD A, 15
ContinueRightPaddleUp:
LD (RightPaddleYPosition), A
RET
MoveRightPaddleDown:
LD HL, (RightPaddleYPosition)
INC L
LD A, L
CP 65
JR NZ, ContinueRightPaddleDown
LD A, 64
ContinueRightPaddleDown:
LD (RightPaddleYPosition), A
RET
WrongChoice:
LD A, (BallVerticalDirection)
CP 0
JR Z, MoveRightPaddleDown
CP 1
JR Z, MoveRightPaddleUp
;--------------------------------
;Handles updating the ball's position - WORKING
;--------------------------------
UpdateBallPosition:
UpdateBallHorizontalPosition:
LD A, (BallHorizontalDirection)
CP 1
JR Z, MoveBallRight
MoveBallLeft:
LD A, (BallXPosition)
DEC A
LD (BallXPosition), A
JR UpdateBallVerticalPosition
MoveBallRight:
LD A, (BallXPosition)
INC A
LD (BallXPosition), A
UpdateBallVerticalPosition
LD A, (BallVerticalDirection)
CP 1
JR Z, MoveBallDown
MoveBallUp:
LD A, (BallYPosition)
DEC A
LD (BallYPosition), A
JR CheckVerticalFlip
MoveBallDown
LD A, (BallYPosition)
INC A
LD (BallYPosition), A
CheckVerticalFlip:
LD A, (BallYPosition)
CP 1
JR Z, FlipDown
CP 64
JR Z, FlipUp
JR CheckHorizontalFlip
FlipDown:
LD A, 1
LD (BallVerticalDirection), A
JR CheckHorizontalFlip
FlipUp:
LD A, 0
LD (BallVerticalDirection), A
CheckHorizontalFlip:
LD A, (BallXPosition)
CP 9
JR Z, CheckIfLeftPaddleIsColliding
CP 86
JR Z, CheckIfRightPaddleIsColliding
RET
CheckIfLeftPaddleIsColliding:
LD A, (BallYPosition)
LD HL, (LeftPaddleYPosition)
LD B, 15 ; The paddles are 20px wide, so we'll need to loop 15 times to check all of them
CheckIfLeftPaddleIsCollidingLoop:
CP L
JR Z, FlipRight
DEC L
DJNZ CheckIfLeftPaddleIsCollidingLoop
LD A, 1
LD (BallOutOfBounds), A
RET
FlipRight:
LD A, 1
LD (BallHorizontalDirection), A
RET
CheckIfRightPaddleIsColliding:
LD A, (BallYPosition)
LD HL, (RightPaddleYPosition)
LD B, 15 ; The paddles are 15px wide, so we'll need to loop 20 times to check all of them
CheckIfRightPaddleIsCollidingLoop:
CP L
JR Z, FlipLeft
DEC L
DJNZ CheckIfRightPaddleIsCollidingLoop
LD A, 1
LD (BallOutOfBounds), A
RET
FlipLeft:
LD A, 0
LD (BallHorizontalDirection), A
RET
;--------------------------------
; Draws paddles - WORKING
;--------------------------------
DrawPaddles:
LD DE, (LeftPaddleYPosition)
LD D, 9
LD A, E
SUB 15
LD L, A ; Puts (E - 15) in L
CALL DrawVerticalLine
LD DE, (RightPaddleYPosition)
LD D, 86
LD A, E
SUB 15
LD L, A
CALL DrawVerticalLine
RET
;--------------------------------
; Draws ball - WORKING
;--------------------------------
DrawBall:
LD HL, (BallXPosition)
LD A, L
LD L, H
CALL FetchPixel
XOR (HL)
LD (HL), A
RET
;--------------------------------
;Handles left paddle movement - WORKING
;--------------------------------
LeftPaddleUp:
LD HL, (LeftPaddleYPosition)
DEC L
LD A, L
CP 14
JR NZ, ContinueLeftPaddleUp
LD A, 15
ContinueLeftPaddleUp:
LD (LeftPaddleYPosition), A
RET
LeftPaddleDown:
LD HL, (LeftPaddleYPosition)
INC L
LD A, L
CP 65
JR NZ, ContinueLeftPaddleDown
LD A, 64
ContinueLeftPaddleDown:
LD (LeftPaddleYPosition), A
RET
;--------------------------------
EndGameLeftPaddleWon:
BCALL(_ClrLCDFull)
BCALL(_HomeUp)
LD HL, LeftPaddleWonText
BCALL(_PutS)
RET
EndGameRightPaddleWon:
BCALL(_ClrLCDFull)
BCALL(_HomeUp)
LD HL, RightPaddleWonText
BCALL(_PutS)
RET
;Handles rendering - WORKING
;--------------------------------
DrawVerticalLine: ; Draws vertical line, column from D, Y1 from E, Y2 from L
LD A, E
SUB L
RET Z
PUSH AF ; A is storing the length of the line, E needs to be a higher value than L
LD A, D
CALL FetchPixel
POP BC ; Puts A into B, which lets the DJNZ loop draw the right amount of pixels
LD DE, 12 ; There are 12 bytes in each row, so adding 12 each time means pixels will always be drawn in the same column
LD C, A
DrawVerticalLineLoop:
LD A, C
XOR (HL)
LD (HL), A
ADD HL, DE
DJNZ DrawVerticalLineLoop
RET
FetchPixel: ; Takes Y in L and X in A - Returns address in HL and a bitmask in A
LD H, 0
LD D, H
LD E, L
ADD HL, HL
ADD HL, DE
ADD HL, HL
ADD HL, HL
LD E, A
SRL E
SRL E
SRL E
ADD HL, DE
LD DE, PlotSScreen
ADD HL, DE
AND 7
LD B, A
LD A, $80
RET Z
FetchPixelLoop:
RRCA
DJNZ FetchPixelLoop
RET
;--------------------------------
RandomNumberGenerator: ; Copy & pasted from WikiTI
PUSH HL
PUSH DE
LD DE,(randData)
LD A, R
LD D, A
LD E, (HL)
ADD HL, DE
ADD A, L
XOR H
LD (randData), HL
POP DE
POP HL
RET
;Data
;--------------------------------
LeftPaddleYPosition:
.EQU AppData ; 1 byte
RightPaddleYPosition:
.EQU AppData + 1 ; 1 byte
BallXPosition:
.EQU AppData + 2 ; 1 byte
BallYPosition:
.EQU AppData + 3 ; 1 byte
BallHorizontalDirection:; Vertical direction
.EQU AppData + 4 ; 1 byte
BallVerticalDirection: ; Horizontal direction
.EQU AppData + 5 ; 1 byte
BallOutOfBounds:
.EQU AppData + 6 ; 1 byte
LeftPaddleScore:
.EQU AppData + 7 ; 1 byte
RightPaddleScore:
.EQU AppData + 8 ; 1 byte
LeftPaddleScoreAscii:
.EQU AppData + 9 ; 1 byte
RightPaddleScoreAscii:
.EQU AppData + 10 ; 1 byte
RandData:
.EQU AppData + 11 ; 2 bytes
TitleScreenText:
.DB " PONG "
.DB "BY: JOHN CAMOU "
.DB "PRESS ANY BUTTON",0
PromptText:
.DB "PRESS ANY "
.DB " TO START",0
LeftPaddleWonText:
.DB "LEFT WINS",0
RightPaddleWonText:
.DB "RIGHT WINS",0