This is mostly work by @crait from his Pong Tutorial. After posting my variations in the comments for that post I was encouraged by other members to make my own thread for it.
Having completed the tutorial series I wanted to play around with the code a bit and came up with the following.
Gameplay changes:
- The direction of the ball is randomised after each point is scored.
- The player paddle moves twice as fast (I prefer how this feels).
- The score is shown at the bottom of the screen with a slightly smaller play area that doesn’t overlap the score.
Additions:
- Title Screen with mode select
- Different gameplay modes (1 player, 2 player, endless)
- Text for the win/lose screens
note: I moved chunks of the code to different functions as that helped my brain when I was editing it.
Gameplay modes:
- 1 Player
- you vs the CPU!
- first to 10 wins the game
- 2 Player
- you vs a friend
- first to 10 wins the game
- player 1 is up/down
- player 2 is a/b
- designed for 2 people sitting facing each other with the Arduboy held sideways between them
- Endless
- the computer will return every shot without fail
- you score a point for each shot you return
- miss one and shot it’s all over!
- gives your score and the current highscore after each game
- note: the highscore is lost when the Arduboy is turned off
Here is the code!
// Tom Bedford (oldmantom)
// July 22nd 2017
// PONG DX
// variations on Jonathan Holmes (crait)'s Pong
// see: https://community.arduboy.com/t/make-your-own-arduboy-game-part-7-make-pong-from-scratch/2615
#include <Arduboy.h>
Arduboy arduboy;
// variables declared here
int gamestate = 0;
int gametype = 0;
int screenwidth = 127;
int screenheight = 47;
// button press buffers
int buffera = 0;
int bufferb = 0;
int bufferup = 0;
int bufferdown = 0;
int bufferleft = 0;
int bufferright = 0;
// ball variables
int ballx = 62; // ball x position
int bally = 0; // ball y position
int ballsize = 4; // ball size
int ballright = 1; // ball horizontal direction
int balldown = 1; // ball vertical direction
// paddle / player variables
int paddlewidth = 4;
int paddleheight = 9;
int playerx = 0;
int playery = 0;
// AI variables
int computery = 0; // default = top
int computerx = screenwidth - paddlewidth; // default = far right - paddlewidth
// scoring
int playerscore = 0;
int computerscore = 0;
int player2score = 0;
int neededtowin = 10; // score needed to win 1 or 2 player
int highscore = 0; // highscore for endless rally
void setup() {
// start arduboy
arduboy.begin();
// seed the random number generator
srand(7/8);
// set the frame rate to 60 FPS
arduboy.setFrameRate(60);
// randomise the horizontal direction of the first ball for the game
randomballright();
// clear the screen
arduboy.clear();
}
void loop() {
// prevent the game from running too fast (i.e. if not ready to display next frame, wait)
if(!arduboy.nextFrame()) {
return;
}
arduboy.clear();
// game code here
switch(gamestate) {
case 0:
// title screen
gameselect();
break;
case 1:
// game screen
gameplay();
break;
case 2:
// win screen
win();
if(arduboy.pressed(A_BUTTON) and buffera == 0) {
buffera = 1;
resetgame();
gamestate = 0;
}
break;
case 3:
// game over screen
gameover();
if(arduboy.pressed(A_BUTTON) and buffera == 0) {
buffera = 1;
resetgame();
gamestate = 0;
}
break;
}
resetbuttonbuffers();
arduboy.display();
}
void gameplay() {
if (gametype == 0) {
arduboy.setCursor(40, 52);
arduboy.print(" VS CPU ");
}
if (gametype == 1) {
arduboy.setCursor(40, 52);
arduboy.print(" VS ");
}
if (gametype == 2) {
arduboy.setCursor(40, 52);
arduboy.print("ENDLESS");
}
// display the player score
arduboy.setCursor(4, 52);
arduboy.print(playerscore);
// display the computer/player2 score
if (gametype == 0 or gametype == 1) {
arduboy.setCursor(115, 52);
arduboy.print(computerscore);
}
// draw the ball
arduboy.fillRect(ballx, bally, ballsize, ballsize, WHITE); // draw the ball
// horizontal movement
if(ballright == 1) {
ballx = ballx +1; // move right
}
if(ballright == -1) {
ballx = ballx -1; // move left
}
// // horizontal bounces
// if(ballx == 0) { // if at left edge of screen
// ballright = 1; // move right
// }
// if(ballx + ballsize == screenwidth) { // if at right edge of screen
// ballright = -1; // move left
// }
// vertical movement
if(balldown == 1) {
bally = bally + 1; // move down
}
if(balldown == -1) {
bally = bally - 1; // move up
}
// vertical bounces
if(bally == 0) { // if at top of screen
balldown = 1; // move down
}
if(bally + ballsize == screenheight) { // if at bottom of screen
balldown = -1; // move up
}
// draw the paddle
arduboy.fillRect(playerx, playery, paddlewidth, paddleheight, WHITE);
// move the paddle with arrows
if (arduboy.pressed(UP_BUTTON) and playery > 0 ) { // if up pressed and not at top
playery = playery - 2;
}
if (arduboy.pressed(DOWN_BUTTON) and playery + paddleheight < screenheight) { // if down pressed and not at bottom
playery = playery + 2;
}
// draw the computer's paddle
arduboy.fillRect(computerx, computery, paddlewidth, paddleheight, WHITE);
// 1 Player (computer will lose sometimes)
if (gametype == 0) {
// computer AI (won't always win)
if (ballx > 115 or rand()% 20 == 1) { // originally... ballx > 115 or rand()% 20 i.e. if ball on right or ~1/20 frames
// if ball is...
// ...towards right hand side of screen (i.e ballx > position on screen)
// ...or if our random number is equal to 1 or random number of frames passed
if(bally < computery ) { // if the ball is higher than the computer
computery = computery - 2; // raise the computer paddle
}
if(bally + ballsize > computery + paddleheight ) { // if the ball is lower than the computer
computery = computery + 2; // lower the computer paddle
}
}
}
// 2 Player (A and B control computer paddle)
if (gametype == 1) {
// move the paddle with A and B
if (arduboy.pressed(B_BUTTON) and computery > 0 ) { // if B pressed and not at top
computery = computery - 2; // raise the computer paddle
}
if (arduboy.pressed(A_BUTTON) and computery + paddleheight < screenheight) { // if A pressed and not at bottom
computery = computery + 2;
}
}
// Endless Rally (computer will always win)
if (gametype == 2) {
// computer AI (will always win)
if(bally < computery ) { // if the ball is higher than the computer
computery = computery - 1; // raise the computer paddle
}
if(bally + ballsize > computery + paddleheight ) { // if the ball is lower than the computer
computery = computery + 1; // lower the computer paddle
}
}
// if the ball moves off the left end of the screen...
if (ballx < -10) {
if (gametype == 2) {
gamestate = 3; // lose screen - you lost the endless rally!
}
ballx = screenwidth / 2; // move the ball to the middle
randomballright(); // randomise ball horizontal direction
// scoring for 1 or 2 player
if (gametype == 0 or gametype == 1) {
computerscore = computerscore + 1; // give the computer/player2 a point
}
}
// if the ball moves off the right end of the screen...
if (ballx > 130) {
ballx = screenwidth / 2; // move the ball to the middle
randomballright(); // randomise ball horizontal direction
// scoring for 1 or 2 player
if (gametype == 0 or gametype == 1) {
playerscore = playerscore + 1; // give the player a point
}
}
// check if player has won
if (playerscore == neededtowin) {
gamestate = 2; // win screen
}
// check if computer has won
if (computerscore == neededtowin) {
gamestate = 3; // lose screen
}
// bounce off player paddle (left side)
if (ballx == playerx + paddlewidth and playery < bally + ballsize and playery + paddleheight > bally) {
// if the ball is at the horizontal position of the paddle...
// ...and the ball is at the vertical position of the paddle...
ballright = 1; // ...bounce off left paddle (i.e. move right)
// scoring for endless rally (add 1 for each return shot)
if (gametype == 2) {
playerscore = playerscore + 1;
}
}
// bounce of computer paddle (right side)
if (ballx + ballsize == computerx and computery < bally + ballsize and computery + paddleheight > bally) {
// if the ball is at the horizontal position of the computer paddle...
// ...and the ball is at the vertical position of the computer paddle...
ballright = -1; // ...bounce off right paddle (i.e. move left)
}
}
void gameselect() {
// print title
arduboy.setCursor(0,0);
arduboy.print("PONG DX");
// show gametypes
arduboy.setCursor(0,16);
arduboy.print(" 1 Player");
arduboy.setCursor(0,32);
arduboy.print(" 2 Player");
arduboy.setCursor(0,48);
arduboy.print(" Endless");
// set the cursor position for the gametype
if (gametype == 0) {
arduboy.setCursor(0,16);
}
if (gametype == 1) {
arduboy.setCursor(0,32);
}
if (gametype == 2) {
arduboy.setCursor(0,48);
}
// print the indicator for the gametype
arduboy.print(">");
// change gametype when up/down pressed
if(arduboy.pressed(UP_BUTTON) and bufferup == 0 and gametype > 0) {
bufferup = 1;
gametype = gametype - 1;
}
if(arduboy.pressed(DOWN_BUTTON) and bufferdown == 0 and gametype < 2) {
bufferdown = 1;
gametype = gametype + 1;
}
// advance to gameplay if A pressed
if(arduboy.pressed(A_BUTTON) and buffera == 0) {
buffera = 1;
gamestate = 1;
}
}
void randomballright() {
// randomise the horizontal direction of the ball
int randomnumber = rand() % 2;
if (randomnumber == 0) {
ballright = 1;
}
if (randomnumber == 1) {
ballright = -1;
}
}
void resetgame() {
ballx = screenwidth / 2;
if (gametype == 2) {
if (playerscore > highscore) {
// set the new highscore
highscore = playerscore;
}
}
playerscore = 0;
computerscore = 0;
// gametype = 0;
// I used to reset the gametype...
// ...but I think people are more likely to want to replay same gametype
}
void resetbuttonbuffers() {
// reset buffer state
if(arduboy.notPressed(A_BUTTON)){
buffera = 0;
}
if(arduboy.notPressed(B_BUTTON)){
bufferb = 0;
}
if(arduboy.notPressed(UP_BUTTON)){
bufferup = 0;
}
if(arduboy.notPressed(DOWN_BUTTON)){
bufferdown = 0;
}
if(arduboy.notPressed(LEFT_BUTTON)){
bufferleft = 0;
}
if(arduboy.notPressed(RIGHT_BUTTON)){
bufferright = 0;
}
}
void win() {
// 1 player
if (gametype == 0) {
arduboy.setCursor(0,0);
arduboy.print("You Won");
arduboy.setCursor(0,32);
arduboy.print("Congratulations!");
arduboy.setCursor(0,48);
arduboy.print("Can you do it again?");
}
// 2 player
if (gametype == 1) {
arduboy.setCursor(0,0);
arduboy.print("Game Over");
arduboy.setCursor(0,32);
arduboy.print("Player 1 Wins!");
arduboy.setCursor(0,48);
arduboy.print("Player 2 Loses!");
}
// endless
if (gametype == 2) {
arduboy.setCursor(0,0);
arduboy.print("This is wrong...");
arduboy.setCursor(0,32);
arduboy.print("How did you win?");
arduboy.setCursor(0,48);
arduboy.print("It's not endless?");
}
}
void gameover() {
// show game over
arduboy.setCursor(0,0);
arduboy.print("Game Over");
// 1 player
if (gametype == 0) {
arduboy.setCursor(0,32);
arduboy.print("Better luck");
arduboy.setCursor(0,48);
arduboy.print("next time...");
}
// 2 player
if (gametype == 1) {
arduboy.setCursor(0,32);
arduboy.print("Player 2 Wins!");
arduboy.setCursor(0,48);
arduboy.print("Player 1 Loses!");
}
// endless
if (gametype == 2) {
arduboy.setCursor(0,32);
arduboy.print("You scored: ");
arduboy.print(playerscore);
arduboy.setCursor(0,48);
if (playerscore > highscore) {
arduboy.print("New highscore!");
} else {
arduboy.print("The highscore is: ");
arduboy.print(highscore);
}
}
}
This time around I didn’t implement:
- different difficulties
- “art”
- sounds
- screensaver mode (CPU vs CPU)
I’ve had a lot of fun playing around with this today. I hope this code is helpful for some of you and perhaps you will enjoy playing it! I think the 2 player mode is the most fun, or taking turns with someone in endless mode.