I have always been interested in video games, and I thought I would try my hand at creating one. Since I was starting at the beginning, I thought it was only fitting that I create a early game, thus PONG. I looked at building the game using the DOM vs the Canvas tag but settled on the Canvas. Not only would this give me more practice with something I hadn’t used as often, it would be fun. To spice up the basic Pong I decided to style it after the the show “Pawn Stars”, except this time it would be “Pong Stars”, hey I know it’s lame. Below is the code, please feel free to take a look and make any suggestions on how I might improve it and if you’d like to play the game its available here.
var screenWidth = 700;
var screenHeight = 700;
var pi = Math.PI;
var canvas = document.getElementById("pongCanvas");
var ctx = canvas.getContext("2d");
var keystate;
var upArrow = 38;
var downArrow = 40;
var upKey = 56;
var downKey = 50;
var onePlayerGame = true;
var onePlayer = document.getElementById("OnePlayer");
var twoPlayers = document.getElementById("TwoPlayers");
var playerScore = document.getElementById("playerScore");
var computerScore = document.getElementById("computerScore");
var winnerWindow = document.getElementById("winnerWindow");
// Images
var ricksHead = new Image();
ricksHead.src = "ricks_head.png";
var historyLogo = new Image();
historyLogo.src = "History-Logo.jpg";
var dollarSign = new Image();
dollarSign.src = "dollarSign.png";
var running = true;
var showBonus = false;
var winningScore = 5;
// Game Objects
var audio = document.createElement('audio');
function playSound(audioSource)
{
audio.src = audioSource;
audio.play();
}
var bonus = {
x : null,
y : null,
width : 50,
height : 50,
show : false,
waitTime : function()
{
var randTime = this.randomTime() * 1000;
setTimeout(function(){
bonus.show = true;
bonus.set();
}, randTime );
},
randomTime : function()
{
return Math.round(Math.random()*10)+10;
},
set : function()
{
this.x = Math.round( (Math.random()* screenWidth) - this.width);
this.y = Math.round( (Math.random()* screenHeight) - this.height);
},
update : function()
{
if(this.show)
{
}
},
draw : function()
{
if(this.show)
{
ctx.drawImage(dollarSign, this.x, this.y, this.width, this.height);
}
}
};
var player = {
name : "player",
x : null,
y : null,
width : 20,
height : 100,
score : 0,
bonus : false,
update : function(){
if(keystate[upArrow])
{
this.y -= 7;
}
if(keystate[downArrow])
{
this.y += 7;
}
if(this.bonus)
{
this.height = 200;
}
else
{
this.height = 100;
}
playerScore.innerHTML = this.score;
if(this.score === winningScore)
{
endGame("Player One");
}
},
draw : function(){
ctx.fillRect(this.x, this.y, this.width, this.height);
}
};
var playerTwo = {
name : "playerTwo",
x : null,
y : null,
width : 20,
height : 100,
score : 0,
bonus : false,
update : function(){
if(keystate[upKey])
{
this.y -= 7;
}
if(keystate[downKey])
{
this.y += 7;
}
if(this.bonus)
{
this.height = 200;
}
else
{
this.height = 100;
}
computerScore.innerHTML = this.score;
if(this.score === winningScore)
{
endGame("Player Two");
}
},
draw : function(){
ctx.fillRect(this.x, this.y, this.width, this.height);
}
};
var ai = {
name : "ai",
x : null,
y : null,
width : 20,
height : 100,
score : 0,
bonus : false,
update : function()
{
var desty = ball.y - (this.height - ball.height)*0.5; // Move the AI paddle to where the ball is
this.y += (desty - this.y) * 0.08; // This makes the paddle slower so its not perfect
if(this.bonus)
{
this.height = 200;
}
else
{
this.height = 100;
}
computerScore.innerHTML = this.score;
if(this.score === winningScore)
{
endGame("Computer");
}
},
draw : function(){
ctx.fillRect(this.x, this.y, this.width, this.height);
}
};
var ball = {
x : null,
y : null,
width : 50,
height : 50,
speed : 5,
serve : function(width, height)
{
var r = Math.random();
if(onePlayerGame)
{
this.x = width === 1 ? player.x : ai.x - this.width;
}
else
{
this.x = width === 1 ? player.x : playerTwo.x - this.width;
}
this.y = (screenHeight - this.height) * r;
var phi = 0.1*pi*(1-2*r);
this.vel = {
x : width*this.speed*Math.cos(phi),
y : this.speed*Math.sin(phi)
};
},
update : function()
{
this.x += this.vel.x;
this.y += this.vel.y;
if(0 > this.y || this.y+this.height > screenHeight) // if y is greater than 0 or y + the height of the ball is greater than the screen reverse;
{
var offset = this.vel.y < 0 ? 0 - this.y : screenHeight - (this.y+this.height); // This is so it hits the border when moving faster, not sure of the math.
this.y += 2*offset;
this.vel.y *= -1;
}
var aabbIntersect = function(ax, ay, aw, ah, bx, by, bw, bh) // ax, ay, aw, ah are the players paddles x, y, width and height.
// bx, by, bw, bh are checking the balls.
{
return ax < bx+bw && ay < by+bh && bx < ax+aw && by < ay+ah; // this is checking for ball collisions with the paddles
};
if(onePlayerGame)
{
var paddle = this.vel.x < 0 ? player : ai;
}
else
{
var paddle = this.vel.x < 0 ? player : playerTwo;
}
// If the balls velocity is less than 0 its heading toward the player, otherwise its headed toward the computer. This sets the value of paddle to player or ai.
if( aabbIntersect(paddle.x, paddle.y, paddle.width, paddle.height, this.x, this.y, this.width, this.height ))
{
if(onePlayerGame)
{
this.x = paddle === player ? player.x+player.width : ai.x - this.width;
}
else
{
this.x = paddle === player ? player.x+player.width : playerTwo.x - this.width;
}
var n = (this.y+this.height - paddle.y)/(paddle.height+this.height); // get a number based on where the ball hits the paddle
var phi = 0.25*pi*(2*n - 1); // Get an angle based on where it hits
var smash = Math.abs(phi) > 0.2*pi ? 1.5 : 1; // Create a smash hit when on a strong angle
this.vel.x = smash*(paddle === player ? 1 : -1)*this.speed*Math.cos(phi); // If the paddle is the player times by 1 else by -1
this.vel.y = smash*this.speed*Math.sin(phi);
playSound("ping_pong_8bit_beeep.wav");
this.speed = this.speed + 1;
}
if(bonus.show)
{
if(aabbIntersect(bonus.x, bonus.y, bonus.width, bonus.height, this.x, this.y, this.width, this.height))
{
playSound("cash.wav");
if(onePlayerGame)
{
paddle === player ? ai.bonus = true : player.bonus = true;
}
else
{
paddle === player ? playerTwo.bonus = true : player.bonus = true;
}
bonus.show = false;
}
}
if(0 > this.x+this.width || this.x > screenWidth) // If ball goes past right or left reset ball
{
//console.log(paddle.name);
playSound("Rick Harrison.mp3");
if(onePlayerGame)
{
paddle === ai ? player.score++ : ai.score++;
}
else
{
paddle === playerTwo ? player.score++ : playerTwo.score++;
}
this.speed = 5;
player.bonus = false;
playerTwo.bonus = false;
ai.bonus = false;
this.serve(paddle === player ? 1 : -1);
if(bonus.show === false)
{
bonus.waitTime();
}
}
},
draw : function(){
ctx.drawImage(ricksHead, this.x, this.y, this.width, this.height);
//ctx.fillRect(this.x, this.y, this.width, this.height);
}
};
// Functions
function main(){
canvas.width = screenWidth;
canvas.height = screenHeight;
keystate = {};
onePlayer.addEventListener("click", function()
{
onePlayerGame = true;
running = true;
window.requestAnimationFrame(loop);
player.score = 0;
ai.score = 0;
onePlayer.style.display = "none";
twoPlayers.style.display = "none";
winnerWindow.style.display = "none";
bonus.waitTime();
init();
});
twoPlayers.addEventListener("click", function()
{
onePlayerGame = false;
running = true;
window.requestAnimationFrame(loop);
player.score = 0;
playerTwo.score = 0;
onePlayer.style.display = "none";
twoPlayers.style.display = "none";
winnerWindow.style.display = "none";
bonus.waitTime();
init();
});
document.addEventListener("keydown", function(evt){
keystate[evt.keyCode] = true;
}); // Add keycode to keystate and set value to true
document.addEventListener("keyup", function(evt){
delete keystate[evt.keyCode];
}); // delete keycode from keystate
}
var loop = function()
{
if(running)
{
update();
draw();
window.requestAnimationFrame(loop);
}
};
function init()
{
player.x = player.width;
player.y = (screenHeight - player.height)/2;
if(onePlayerGame)
{
ai.x = screenWidth - (player.width + ai.width);
ai.y = (screenHeight - ai.height)/2;
}
else
{
playerTwo.x = screenWidth - (player.width + playerTwo.width);
playerTwo.y = (screenHeight - playerTwo.height)/2;
}
ball.serve(-1, -1);
}
function update()
{
ball.update();
player.update();
if(onePlayerGame)
{
ai.update();
}
else
{
playerTwo.update();
}
bonus.update();
}
function draw()
{
//ctx.fillRect(0,0,screenWidth, screenHeight); // Clears canvas
ctx.drawImage(historyLogo, 0, 0, screenWidth, screenHeight); // Prints background to clear
ctx.save(); // Saves current styles
ctx.fillStyle = "#FFD700";
ball.draw();
player.draw();
if(onePlayerGame)
{
ai.draw();
}
else
{
playerTwo.draw();
}
bonus.draw();
// Drawing the center net
var w = 4;
var x = (screenWidth - w)*0.5;
var y = 0;
var step = screenHeight/20;
while(y < screenHeight)
{
ctx.fillRect(x, y+step*0.25, w, step*0.5); // create a rectangle based on screen size
y += step; // Move y position for next rectangle
}
ctx.restore(); // restore ctx to save
}
function endGame(winner)
{
running = false;
onePlayer.style.display = "block";
twoPlayers.style.display = "block";
winnerWindow.style.display = "block";
winnerWindow.innerHTML = winner + " Wins!";
}
main();