//Balazs Sinko
//October 10th, 2020
//Pong game
#include<Arduboy2.h>
Arduboy2 arduboy;
const uint8_t PROGMEM logo[] = {
64, 25,
0x00, 0xe0, 0x18, 0x04, 0x06, 0x02, 0x01, 0xc1, 0xa1, 0xe1, 0x01, 0x01, 0x02, 0x06, 0x0c, 0xfe, 0x02, 0x03, 0x01, 0x01, 0x03, 0x02, 0x06, 0x0c, 0x1c, 0x76, 0xc1, 0x01, 0x01, 0x03, 0x0e, 0x3c, 0x70, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0xf0, 0x1e, 0x03, 0x01, 0x01, 0x03, 0x0e, 0xfc, 0x06, 0x02, 0x02, 0x03, 0x01, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0xc2, 0xe2, 0xfc, 0xf0, 0xe0, 0x80,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf0, 0xf0, 0x98, 0x08, 0x0c, 0x06, 0x03, 0x00, 0xf8, 0xfc, 0x7c, 0x38, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xc7, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xc7, 0xc7, 0x87, 0x07, 0x07, 0x0f, 0x0f, 0x1f, 0x17, 0xe7, 0x87, 0x03, 0x01,
0x01, 0x1f, 0x70, 0xc0, 0xc0, 0xc0, 0xe0, 0xf8, 0xff, 0xff, 0x3f, 0x03, 0x0c, 0x18, 0x30, 0x60, 0x40, 0xc1, 0xc3, 0xc2, 0xc3, 0xc1, 0xc0, 0xe0, 0xf8, 0xfe, 0x61, 0x40, 0x40, 0x40, 0xc0, 0xfe, 0xff, 0xfe, 0xfc, 0xf0, 0x70, 0x20, 0x60, 0xc0, 0xc0, 0xc0, 0xf0, 0xfe, 0xf9, 0xe0, 0x60, 0x20, 0x40, 0x40, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xf0, 0xfe, 0x7f, 0x7f, 0x3f, 0x1c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}; //PONG sprite
const uint8_t PROGMEM spike[] = {
5, 4,
0x08, 0x08, 0x05, 0x02, 0x02,
}; //spike sprite
const uint8_t PROGMEM boom[] = {
8, 8,
0x66, 0xd1, 0x05, 0x00, 0x80, 0x92, 0xc1, 0x23,
}; //ball explosion sprite
int gameState = 0;
float ballX = 64; //ball initial X position
float ballY = 32; //ball initial Y position
float gameSpeed = 0.4; //game speed (on level 1)
float ballDX = gameSpeed; //ball speed - X direction
float ballDY = gameSpeed; //ball speed - Y direction
int paddleHeight = 14; //paddle height (on level 1)
int playerY = 0; //player paddle initial Y position
float computerY = 0; //computer paddle initial Y position
int playerScore = 0; //player initial score
int computerScore = 0; //computer initial score
float factor = 1; //bounce direction modifier initial value (=1 no change, <1 more flat, >1 more steep)
int level = 1; //initial level
void resetGame(){ //variables set to original at game restart
ballX = 64;
ballY = 32;
playerScore = 0;
computerScore = 0;
ballDX = gameSpeed;
ballDY = gameSpeed;
factor = 1;
level = 1;
paddleHeight = 14;
}
void bounceVariation(){ //ball bounce direction modifier algorythm - just playing with the speed in the Y direction
factor = 1 + 0.1 * random(-3, 4); //random factor (0.7 - 1.3)
if((abs(ballDY / ballDX) < 0.8 && factor < 1) || abs((ballDY / ballDX) > 1.25 && factor > 1)){ //if the alignment is too flat or steep and the factor make it worse then it change the factor to make opposite effect
factor = 1 / factor;
}
ballDY = ballDY * factor; //apply the factor on the Y direction speed
}
void setup() {
arduboy.begin();
arduboy.initRandomSeed();
arduboy.clear();
arduboy.setFrameRate(60);
}
void loop() {
if (!arduboy.nextFrame()){
return;
}
arduboy.clear();
arduboy.pollButtons();
switch (gameState){
case 0: //initial display
Sprites::drawOverwrite(30, 12, logo, 0); //PONG logo
arduboy.setCursor(20, 55);
arduboy.print("Select level: "); //ask level selection
arduboy.print(level);
if (arduboy.justPressed(UP_BUTTON) && level < 3){ //up button add +1 level up to 3
level = level + 1;
}
if (arduboy.justPressed(DOWN_BUTTON) && level > 1){ //down button lowers the level
level = level -1;
}
if (arduboy.justPressed(A_BUTTON)){ //level selection confirmation with A button
ballDX = ballDX * (1+ 0.5 * (level-1)); //increase the X direction speed based on selected level (0, 50, 100%)
ballDY = ballDY * (1+ 0.5 * (level-1)); //increase the Y direction speed based on selected level (0, 50, 100%)
paddleHeight = paddleHeight -(level - 1); //lowers the paddles height based on selected level (0, -1, -2)
gameState = 1; //switch to game start
}
break;
case 1: //game display
//display scoring
arduboy.setCursor(20, 2);
arduboy.print(playerScore);
arduboy.setCursor(101, 2);
arduboy.print(computerScore);
//frame drawing
for (int i = 0; i < 65; i = i +4){
Sprites::drawOverwrite(0, i, spike, 0); //spikes arrayed on the left side
Sprites::drawOverwrite(122, i, spike, 0); //spikes arrayed on the right side
}
arduboy.drawLine (0, 0, 127, 0, WHITE); //upper frame
arduboy.drawLine (0, 63, 127, 63, WHITE); //bottom frame
//ball drawing
arduboy.drawCircle(ballX, ballY, 2, WHITE); //drawing of the ball
ballX = ballX + ballDX; //add the X speed to the X position
ballY = ballY + ballDY; //add the Y speed to the Y position
if (ballX <= 7 && playerY < ballY + 2 && playerY + paddleHeight > ballY - 2){ //ball collision detection with the player's paddle
ballDX = abs(ballDX); //the ball X direction is changed to positive, so the ball is bounced on the paddle
bounceVariation(); //calling of the ball bounce direction modifier algorythm
}
if (ballX >= 120 && computerY < ballY + 2 && computerY + paddleHeight > ballY -2){ //ball collision detection with the computer's paddle
ballDX = -abs(ballDX); //the ball X direction is changed to negative, so the ball is bounced on the paddle
bounceVariation(); //calling of the ball bounce direction modifier algorythm
}
if (ballY <= 3 || ballY >= 60){ //collision detection on the top and the bottom
ballDY = -ballDY; //the ball Y direction inverterted, so the ball is bounced
}
//player paddle drawing
arduboy.drawRect(0, playerY, 5, paddleHeight, WHITE); //player paddle is a rectangle
if (arduboy.pressed(UP_BUTTON) && playerY > 0){ //if up button pressed the paddle moves up (until reach 0)
playerY = playerY - 1;
}
if (arduboy.pressed(DOWN_BUTTON) && playerY + paddleHeight < 63){ //if down button pressed the paddle moves own (until reach the bottom)
playerY = playerY + 1;
}
//computer paddle drawing
arduboy.drawRect(122, computerY, 5, paddleHeight, WHITE);
if (ballX > 105 - 15 * (level-1) || random(0, 22)==1){ //this sets from which X coordinate starts the computer follow the ball (depend on the level: 105, 90, 75), plus add random following factor
if (computerY > ballY){ //if the ball is higher than the computer's paddle
computerY = computerY - (1 + 0.25 * (level - 1)) * gameSpeed; //the paddle goes higher (follow the ball), the following speed depend on the selected level (100, 125, 150%) and of course on the general gamespeed
}
if (computerY + paddleHeight < ballY + 4){ //if the ball is lower than the computer's paddle
computerY = computerY + (1 + 0.25 * (level - 1)) * gameSpeed; //the paddle goes lower (follow the ball), the following speed depend on the selected level (100, 125, 150%) and of course on the general gamespeed
}
}
if (ballX < 6){ //when the ball moves to the left and doesn't bounced on the player's paddle, then it will reach the spikes
Sprites::drawOverwrite(ballX - 2, ballY - 2, boom, 0); //the ball changed to a small explosion drawing
arduboy.display();
delay(1000); //little pause
ballX = 64; //ball initial position
ballDX = -ballDX; //ball goes to the computer direction
computerScore = computerScore + 1; //computer gain 1 point
}
if (ballX > 121){ //ball reach the spikes on the computers side
Sprites::drawOverwrite(ballX - 2, ballY - 2, boom, 0); //explosion
arduboy.display();
delay(1000);
ballX = 63; //ball initial position
ballDX = -ballDX; //ball goes to the player direction
playerScore = playerScore + 1; //player gain 1 point
}
if (computerScore == 5){ //if computer reach 5 points
gameState = 3; //call "YOU LOST" display
}
if (playerScore == 5){ //if player reach 5 points
gameState = 2; //call "YOU WON" display
}
break;
case 2: //"YOU LOST" display
arduboy.setCursor (random (38, 42), random(22, 26)); //text in diferent random positions (look like vibrating)
arduboy.print("YOU WON");
if (arduboy.justPressed(A_BUTTON)){
resetGame();
gameState = 0; //A button calls the initial display
}
break;
case 3: //"YOU LOST" display
arduboy.setCursor (random (38, 42), random(22, 26)); //text in diferent random positions (look like vibrating)
arduboy.print("YOU LOST");
if (arduboy.justPressed(A_BUTTON)){
resetGame();
gameState = 0; //A button calls the initial display
}
break;
}
arduboy.display();
}
Comments