Midterm Project – Pong (Blindspot Version)

Sketch

Sketch Link: https://editor.p5js.org/swostikpati/full/ShPga9v6_

Inspiration

As a lover of classic arcade games, I have always been fascinated by the simple yet addictive gameplay of Pong. Originally developed in the 1970s by Atari, Pong started as a simple slot machine game before becoming the first commercially successful video game. Its simplicity, accessibility, and fun factor quickly made it a favorite among gamers of all ages.

My inspiration for creating a Pong game on p5.js stemmed from my desire to learn more about game development and to challenge myself to create a game that was both simplistic, visually appealing, and fun to play. Even while doing so, I wanted to add my own creative touch to the game while still retaining its classic feel.

Concept

The concept of the project is simple – to implement the Pong game. But I had to add some unique elements to the game to make it a different experience from the existing pong video games. I thought of revving up the difficulty and consequently the adrenaline rush of the game by adding a “blindspot” in the middle of the screen where the ball disappears and continues to travel in the same trajectory until it appears again from the other side of the blindspot. As the players continue through each rally, the blindspot region keeps increasing and so does the speed of the moving ball making it more and more difficult for both players.

Implementation

The game implementation has two parts to it – the creative process and the technical implementation.

Creative Design

The creative design part of the implementation focuses on the visual aspects of the game, including the graphics, sound effects, animation, and user interface (color choices, font choices, etc).

The game’s colors are kept minimal with almost all the elements switching between absolute black and white.

There are three screens in total – the Start Screen, the Game Screen, and the End (Game Over) Screen.

The Start screen displays the rules of the game with the least bit of information possible as players generally skip the instructions. The controls are shown on a separate half of the page in order for the players to at least get the most essential information required (as the other parts can soon be figured out intuitively). This screen also features a ball moving around the screen just to give a feel of the game before the user starts playing.

The game screen has a background board with two rectangular paddles, one on each side of the screen, and a ball in the center. For the animation, I added smooth movement to the paddles and the ball to give the game a more polished feel. The ball moves in a straight line until it hits a paddle or wall (the top and bottom walls only), at which point it bounces off at an angle based on where it made contact. When the ball hits either the right or left wall, a point is scored, and the ball resets to the center of the screen. I have also made sure that at the start of every rally, the blindspot is temporarily disabled so that the players are able to view the ball at the center of the screen. As soon as the ball makes contact with a paddle, the blindspot is reactivated and the usual gameplay continues. I added a score tracker on the top of the screen for each player. The score is displayed in a large, bold font that is easy to read.

The final screen is the Game Over screen. This screen displays the player who won with a trophy. It also contains a button that gives the user the option to restart the game. The user doesn’t need to refresh the page for this.

I included several sound effects throughout the game to enrich the user experience. There were different sound effects used for a ball tap against the wall or a paddle, a point score, and game over. The fonts that were used at  different places were carefully thought about. The background images that have been imported into the sketch and used in different screens were designed by me on Canva.

The game was tested several times, with several paddle speeds, ball speeds, ball speed increments, blindspots and blindspot increments to make sure there were no glitches or bugs. All in all, every design decision throughout the game was carefully thought about to enhance the overall user experience of the game.

Technical Design

The technical implementation of the game included designing the switch between game screens, implementing the mechanics of the pong game itself with the enhancements as proposed that included paddle and ball movements, collision detection and response, adding sound effects at particular times, etc.

The entire code was written in an object-oriented fashion with classes of ball and paddles, and several functions were used to increase code reusability and modularity.

The code snippets below are used to implement important functionalities in the game.

Paddle Class

// Paddle class
class Paddle {
  constructor(x, y) {
    //     Stores the position of the paddles
    this.x = x;
    this.y = y;

    //     Flags to define whether the paddles are currently moving or not
    this.up = false;
    this.down = false;
  }

  //   displays the paddles(as rects) based on their x and y positions
  draw() {
    rectMode(CENTER);
    fill(255);
    noStroke();
    rect(this.x, this.y, paddleWidth, paddleHeight);
  }

  //   updates the position of paddles based on their movement
  update() {
    //     paddles move up or down by 10 units based on which key is clicked
    if (this.up) {
      this.y -= paddleSpeed;
    }
    if (this.down) {
      this.y += paddleSpeed;
    }
    this.y = constrain(this.y, paddleHeight / 2, height - paddleHeight / 2);
  }
}

Snippets from Ball Class

update() {
    //game over condition
    if (rightScore >= maxScore || leftScore >= maxScore) {
      gameWinSound.play();
      //       storing the winner
      if (rightScore == maxScore) {
        winner = 1; //Player A won
      } else {
        winner = 0; //Player B won
      }
      // print(winner);
      //       transitioning to the gameover screen
      screenView = 2;
    }

    //     updating current position of the ball
    this.x += this.speedX;
    this.y += this.speedY;

    // check for collisions with paddles
    if (
      this.x - ballSize / 2 <= paddleWidth &&
      this.y >= leftPaddle.y - paddleHeight / 2 &&
      this.y <= leftPaddle.y + paddleHeight / 2
    ) {
      //       plays collision sound
      ballHitSound.play();
      //       increments ball speed in a particular rally
      this.speedX = abs(this.speedX) + ballSpeedInr;
      //       increments the blindspot region - there is an upper limit set as well to prevent it from covering too much of the screen
      blindSpot = Math.min(blindSpotInr + blindSpot, maxBlindSpot);
    }
    
}

 

// check for scoring - one side
    if (this.x - ballSize / 2 <= 0) {
      //       sound effect when a player scores
      scoreSound.play();

      //       ball is brought back to the center of the screen
      this.x = width / 2;
      this.y = height / 2;

      //       speedX and speedY are reset to the original ball speed
      this.speedX = ballSpeed;
      this.speedY = ballSpeed;

      //       score of the corresponding player is incremented
      rightScore++;

      //       to switch off blindspot just till the game starts
      ballFlag = false;

      //       resetting the blindspot region
      blindSpot = 50;
    }

Screen Switching

function draw() {
  // Switches between game screens based on the variable screenView
  if (0 === screenView) {
    startScreen();
  }
  if (1 === screenView) {
    playScreen();
  }
  if (2 === screenView) {
    endScreen();
  }
}

Event Listeners

// listens for key presses to start motion of paddles
function keyPressed() {
  //   listens for up and down movements by player A using up down arrow keys
  if (keyCode === UP_ARROW) {
    rightPaddle.up = true;
  } else if (keyCode === DOWN_ARROW) {
    rightPaddle.down = true;
  }
  //   listening for up and down movements by player B using "W" and "S" keys
  else if (keyCode === 87) {
    leftPaddle.up = true;
  } else if (keyCode === 83) {
    leftPaddle.down = true;
  }
}

// listens for when the keys are released to stop motion of paddles
function keyReleased() {
  if (keyCode === UP_ARROW) {
    rightPaddle.up = false;
  } else if (keyCode === DOWN_ARROW) {
    rightPaddle.down = false;
  } else if (keyCode === 87) {
    leftPaddle.up = false;
  } else if (keyCode === 83) {
    leftPaddle.down = false;
  }
}

// listens for mouse clicks
function mouseClicked() {
  //   transitions from Start Screen to Game Screen and starts the game
  if (0 === screenView) {
    leftScore = 0;
    rightScore = 0;
    ball.x = width / 2;
    ball.y = height / 2;
    screenView = 1;
  }

  //   transitions from End Screen to Start Screen to help user to restart a game without reloading. This happens on clicking the button on the end screen
  if (
    2 === screenView &&
    mouseX > width / 2 - buttonWidth / 2 &&
    mouseX < width / 2 + buttonWidth / 2 &&
    mouseY > height - 100 - buttonHeight / 2 &&
    mouseY < height - 100 + buttonHeight / 2
  ) {
    screenView = 0;
  }
}

Key Challenges and Solutions

  • Implementing different screen views and navigating around them – It took some time for me to figure out the navigation across different screen views – especially returning back to the “Start Screen” from the “Game over” screen without refreshing the sketch. In the end, I implemented a simple flag-based mechanism to do so.
  • Identifying the paddle and ball speeds, increments, and blindspot regions – If even one among the paddles or the ball moved too slow or too fast, it would take away a lot from the overall user experience of the game. Even the increments in speed and the blindspot region had to be decided on carefully. The game had to be the right amount of “challenging” and stimulating for it to hook the users. Too easy and the users get bored. Too difficult and the users get frustrated. The game had to be the right mix of challenging and rewarding. This might feel like a simple thing of deciding a few numbers but it does have a huge impact on the overall gameplay and user experience. I spent quite some time playing around and extensively testing several mixes of numbers before arriving at the ones used in the final code.
  • Figuring out the Game Mechanics and the collision detection algorithm (the most frightening part) – I had talked about this in my previous post where I shared my progress in the midterm project. This was the most frightening part initially as the game was nothing without these two elements figured out and working perfectly.
  • Integrating more features while still keeping the minimalistic feel intact – It was a challenge to maintain the simple and minimalistic feel to the game intact and at the same time integrate more features into it. The balance was key as I wanted to preserve the game as it has been for ages and still make the experience a completely new one.

Potential Developments

  • Giving the option to the players to add their names in the Start screen rather than going by “Player A” and “Player B”.
  • Integrating a database to store high scores and user accounts. This would allow me to also have a leaderboard in the end that could be fetched based on the data from the database.
  • Adding more elements to the game including game animations during scoring and powerups like freezing the opponent’s paddle for a while or combo points for a rally, etc.
  • Making the blindspot region generate at any random position throughout the screen and making it move will add a new layer of challenge to the game.

Reflections

Throughout the development of this project, I have learned a lot about the process of game design and the intricacies that go into creating a simple yet engaging game. I had to experiment with different approaches and techniques to achieve the desired functionality. I was also able to create an algorithm that worked effectively and provided a satisfying gameplay experience. I made sure to focus both on the technical implementation and the creative design process of developing the game. The experience has been both challenging and rewarding, and I am proud of the final product that I have created.

Screens

Start Screen
Game Screen
Game Over Screen

Leave a Reply