xxxxxxxxxx
192
// Voice Pong! by Peyman Majidi
// Youtube Channel: @peymanx
// youtube.com/@peymanx/
// In this video, I explain how to make Voice Pong
// Related to this video (In Persian):
// https://www.youtube.com/watch?v=ZQfCJCBOFMk&t=186s&ab_channel=PeymanMajidiMoein
// Inspired by CodingTrain, Daniel Shiffman
// https://thecodingtrain.com/tracks/sound
// https://thecodingtrain.com/tracks/sound/sound/8-microphone-input
// Define global variables for game objects and settings
var player, computer, ball; // The player, computer, and ball sprites
var paddles; // Group for paddles (player & computer)
var computerPos; // Store previous computer positions for smooth movement
var scoreText; // Text for displaying the score
let mic; // Microphone input for controlling paddle
let intro = 100; // Countdown for intro screen
let h = 0; // Placeholder for unused variable
let x, y; // Ball position coordinates
let target, force; // Target for paddle control and force from mic
const canvasDimensions = [800, 500]; // Dimensions of the canvas
const RAD2DEG = 180 / Math.PI; // Convert radians to degrees
const DEG2RAD = Math.PI / 180; // Convert degrees to radians
// Random number generator function
function rand(a, b) {
return a + Math.random() * (b - a);
}
// Setup function to initialize game elements
function setup() {
// Initialize microphone input and start listening
mic = new p5.AudioIn();
mic.start();
// Set initial positions for the ball and paddles
x = 10;
target = 200; // Target position for paddle control
y = 200; // Ball's initial vertical position
force = 120; // Force multiplier for mic input
paddleHeight = 150; // Height of the paddles
// Create the canvas and background
createCanvas(canvasDimensions[0], canvasDimensions[1]);
background(20);
// Set text alignment
fill(255);
textAlign(CENTER);
// Create group for paddles
paddles = new Group();
// Create player paddle on the left
player = createSprite(20, height / 2, 20, paddleHeight);
player.shapeColor = "white";
paddles.add(player);
// Create computer paddle on the right
computer = createSprite(width - 20, height / 2, 20, paddleHeight);
computer.shapeColor = "white";
paddles.add(computer);
// Create ball sprite
ball = createSprite(width / 2, height / 2, 30, 30);
ball.shapeColor = "#c6ed2c";
// Initialize computer positions (for smooth movement)
computerPos = Array.apply(null, Array(10)).map(
Number.prototype.valueOf,
height / 2
);
// Initialize score
score = [0, 0];
// Set initial ball speed and direction
ball.setSpeed(3, rand(-20, 20));
}
// Main game loop
function draw() {
if (intro > 0) {
introScreen(); // Display intro screen
intro--; // Decrease intro countdown
ball.position.x = width / 2 + 100; // Position ball off-screen during intro
ball.position.y = height / 2;
return;
}
// Clear background and draw paddles and ball
background(20);
backdrop();
drawSprites();
// Set player's paddle position based on microphone input
target -= 7; // Smooth out the paddle position (slows down target movement)
let vol = mic.getLevel(); // Get microphone volume level
// Adjust target position with microphone input (more force = faster paddle movement)
target += vol * force;
y = lerp(y, target, 0.14); // Smooth interpolation for paddle movement
// Ensure paddle stays within bounds
target = max(paddleHeight / 2, min(height - paddleHeight / 2, target));
player.position.y = y;
// Simulate a "perfect" computer player (commented out)
// computer.position.y = ball.position.y;
// Simulate a delayed computer player (stores past positions for smooth movement)
computerPos.push(ball.position.y);
computer.position.y = computerPos.shift();
// Ball wall collisions (bounce off top/bottom)
if (ball.position.y < 4 || ball.position.y > height - 4) {
ball.velocity.y *= -1; // Reverse vertical velocity
}
// Ball goal collisions (score and reset ball position)
if (ball.position.x < 4) {
score[1]++; // Computer scores a point
resetBall();
} else if (ball.position.x > width - 4) {
score[0]++; // Player scores a point
resetBall();
}
// Ball-paddle collisions (bounce ball off paddles)
ball.overlap(paddles, function (ball, paddle) {
ball.velocity.x *= -1.01; // Reverse horizontal velocity and add a little spin
ball.velocity.y += (ball.position.y - paddle.position.y) / 20; // Add vertical spin based on paddle hit position
});
}
// Function to reset the ball's position after a goal
function resetBall() {
ball.position.x = width / 2;
ball.position.y = height / 2;
ball.setSpeed(3, rand(-20, 20)); // Randomize ball direction
target = y = 300; // Reset target and player paddle position
intro = 100; // Reset intro countdown to show the ready screen
}
// Function to draw the game backdrop (dotted line in the center)
function backdrop() {
textFont("ArcadeClassic");
stroke(80);
strokeWeight(8);
let dottedLength = 20; // Length of the dots
let y = dottedLength / 2;
// Draw dotted line in the center of the canvas
while (y < height) {
line(width / 2, y, width / 2, y + dottedLength);
y += dottedLength * 2;
}
// Draw the score text on the canvas
textSize(150);
noStroke();
fill(80);
textAlign(RIGHT, TOP);
text(score[0], width / 2 - 50, 10); // Player's score
textAlign(LEFT);
text(score[1], width / 2 + 50, 10); // Computer's score
}
// Function to display the intro screen (Ready message)
function introScreen() {
textFont("ArcadeClassic");
stroke(80);
strokeWeight(8);
textSize(200);
noStroke();
fill(200);
textAlign(CENTER, TOP);
text("Ready", width / 2, height / 2 - 100); // Show "Ready" text in the center
}