Skip to content

Instantly share code, notes, and snippets.

@dragfire
Created April 1, 2014 19:39
Show Gist options
  • Save dragfire/9921456 to your computer and use it in GitHub Desktop.
Save dragfire/9921456 to your computer and use it in GitHub Desktop.
A Pen by devasem.
<canvas id="display" width="600" height="480" style="border:1px solid black;"></canvas>
<div id="control">
<p>Use <u>UP</u> Right Paddle Up</p>
<p>Use <u>DOWN </u>Right Paddle Down</p>
<p>Use <u>W</u> Left Paddle Up</p>
<p>Use <u>S</u> Left Paddle Down</p>
<p>Click <u>Toggle AI</u> To Play with Computer</p>
<p>Click <u>Restart</u> To restart the Game</p>
</div>
window.onload = function () {
var canvas = document.getElementById("display"),
frame = canvas.getContext("2d");
CanvasRenderingContext2D.prototype.draw_image = function(image,center,srcSize,dstPos,dstSize,angle){
if(angle == undefined || angle == null || angle ===0)
this.drawImage(image,Math.floor(center[0]/srcSize[0])*srcSize[0],Math.floor(center[1]/srcSize[1])*srcSize[1],srcSize[0],srcSize[1],dstPos[0],dstPos[1],dstSize[0],dstSize[1]);
else{
this.save();
var x = dstPos[0],
y = dstPos[1],
halfWidth = srcSize[0]/2,
halfHeight = srcSize[1]/2,
angleInRads = angle * Math.PI / 180;
this.translate(x+halfWidth,y+halfHeight);
this.rotate(angleInRads);
this.drawImage(image,Math.floor(center[0]/srcSize[0])*srcSize[0],Math.floor(center[1]/srcSize[1])*srcSize[1],srcSize[0],srcSize[1],-halfWidth,-halfHeight,dstSize[0],dstSize[1]);
this.restore();
}
};
//Line Drawing
CanvasRenderingContext2D.prototype.drawLine = function(start,end,width,color){
this.strokeStyle= color;
this.lineWidth = width;
this.lineCap = "square";
this.beginPath();
this.moveTo(start[0],start[1]);
this.lineTo(end[0],end[1]);
this.stroke();
this.closePath();
};
var div = document.createElement("div"),
b1= document.createElement("button");
document.body.appendChild(div);
b1.innerHTML = "Restart";
b1.setAttribute("class","controls");
div.appendChild(b1);
b1.onclick = function(){
restart();
};
var b2 = document.createElement("button");
b2.innerHTML="Toggle AI";
b2.setAttribute("class","controls")
div.appendChild(b2);
b2.onclick = function(){
toggle_ai();
if(comp_AI) h1.innerHTML = "Computer AI : ON";
else h1.innerHTML = "Computer AI : OFF";
};
var h1 = document.createElement("h1");
document.body.appendChild(h1);
h1.innerHTML = "Computer AI : OFF";
var width = 600,
height = 480,
speed_increase = 0.1,
i= 0,
soundPool=[],
MAX_SOUNDS= 6,
resLoaded = 0,
totalRes = 5,
keydown=false,
max_particles = 10;
var paddle = {
width: 20,
height: 80,
half_width: 10,
half_height: 40,
speed: 5
};
var ball = {
width:40,
height:40,
radius: 20,
max_speed: 600
},
ball_vel=[0,0],
ball_pos=[0,0],
pad1_pos=0,
pad2_pos=0,
pad1_vel= 0,
pad2_vel= 0,
score1= 0,
score2= 0,
isRunning = false
;
var ball_effects = {
effect1_width: 120,
effect1_height: 120,
effect2_width: 600,
effect2_height: 600
};
var comp_AI = false,
gutter_count = 0,
collision_effect_timer,
trail_timer,
image_load_timer,
trail = [];
var images = {
background: "https://dl.dropboxusercontent.com/u/8367729/codeskulptor/pong/background.png",
pad: "https://dl.dropboxusercontent.com/u/224687431/paddle.png",
ball: "https://dl.dropboxusercontent.com/u/8367729/codeskulptor/pong/ball.png",
b_eff1: "https://dl.dropboxusercontent.com/u/8367729/codeskulptor/pong/ball_effect1.png",
b_eff2: "https://dl.dropboxusercontent.com/u/8367729/codeskulptor/pong/ball_effect2.png",
loader: "https://dl.dropboxusercontent.com/u/224687431/spinner_large_sprites36%402x.png"
},
background_img = new Image(),
paddle_img = new Image(),
ball_img = new Image(),
ball_eff1_img = new Image(),
ball_effect2_img = new Image(),
animLoader = new Image(),
images_loaded = false;
background_img.src = images.background;
paddle_img.src = images.pad;
ball_img.src = images.ball;
ball_eff1_img.src = images.b_eff1;
ball_effect2_img.src = images.b_eff2;
animLoader.src = images.loader;
// sounds
var electric_sound = "https://dl.dropboxusercontent.com/u/8367729/codeskulptor/pong/zap.ogg",
beepSound = "https://dl.dropboxusercontent.com/u/8367729/codeskulptor/pong/beep.ogg";
// loading onload
background_img.onload = function(){loading();};
paddle_img.onload = function(){loading();};
ball_img.onload = function(){loading();};
ball_eff1_img.onload = function(){loading();};
ball_effect2_img.onload = function(){loading();};
// electric_sound.onload = function(){loading();};
// beepSound.onload = function(){loading();};
function playSound(sound,volume){
var soundFound = false;
var soundIndex =0;
var tempSound;
if(soundPool.length>0){
while(!soundFound && soundIndex<soundPool.length){
var tSound = soundPool[soundIndex];
if(tSound.ended){
soundFound = true;
}
else{
soundIndex++;
}
}
}
if(soundFound){
tempSound = soundPool[soundIndex];
tempSound.setAttribute("src",sound);
tempSound.loop = false;
tempSound.volume = volume;
tempSound.play();
}
else if(soundPool.length<MAX_SOUNDS){
tempSound = document.createElement("audio");
tempSound.setAttribute("src",sound);
tempSound.volume = volume;
tempSound.loop = false;
tempSound.play();
soundPool.push(tempSound);
}
}
function loading(){
resLoaded++;
if(resLoaded===totalRes) {
images_loaded=true;
render();
}
}
window.addEventListener("keydown",keyDown,false);
window.addEventListener("keyup",keyUp,false);
function keyDown(e){
var key = e.keyCode;
keydown=true;
if (!comp_AI){
if(key == 87) pad1_vel = - paddle.speed;
else if(key == 83) pad1_vel = paddle.speed;
}
if(key ==38) pad2_vel = -paddle.speed;
else if(key ==40 ) pad2_vel = paddle.speed;
}
function keyUp(e){
var key = e.keyCode;
keydown=false;
if(!comp_AI){
if(key == 87) pad1_vel =0;
else if (key == 83) pad1_vel=0;
}
if(key == 38) pad2_vel=0;
else if(key == 40) pad2_vel=0;
}
function ballInit(right){
trail=[];
ball_pos = [width / 2-ball.radius, height / 2-ball.radius];
ball_vel = [random(140, 280) / 60.0, -random(80, 200) / 60.0];
// console.log((random(120, 240) / 60.0)+" "+(-random(60, 180) / 60.0));
if (!right)
ball_vel[0] = -ball_vel[0];
pad1_pos = height / 2;
pad2_pos = height / 2;
}
function newGame() {
pad1_vel = 0.0;
pad2_vel = 0.0;
score1 = 0;
score2 = 0;
var result = randomSelect();
ballInit(result);
//timer
trail_timer = setInterval(trail_timer_tick,500);
console.log("New game started.");
}
function random(min, max) {
return Math.floor(Math.random() * max + min - 1);
}
function randomSelect() {
var sel = random(1, 2);
if (sel === 1) return true;
else return false;
}
function start_electric_effect() {
//timer
isRunning = true;
collision_effect_timer = setInterval(Collision_effect_tick,200);
}
function clamp(value, min_val, max_val) {
return Math.max(Math.min(value, max_val), min_val);
}
function magnitude(vel) {
return Math.sqrt(Math.pow(vel[0], 2) + Math.pow(vel[1], 2));
}
function angle(x1, y1, x2, y2) {
return Math.atan2(y2 - y1, x2 - x1);
}
function set_ball_angle(angle) {
var speed = magnitude(ball_vel);
ball_vel[0] = speed * Math.cos(angle);
ball_vel[1] = speed * Math.sin(angle);
}
function speed_up_ball() {
ball_vel[0] = clamp(ball_vel[0] + ball_vel[0] * speed_increase, -ball.max_speed, ball.max_speed)
ball_vel[1] = clamp(ball_vel[1] + ball_vel[1] * speed_increase, -ball.max_speed, ball.max_speed)
}
function updateBall() {
ball_pos[0] += ball_vel[0];
ball_pos[1] += ball_vel[1];
// check for top or bottom collision
if (ball_pos[1] < 0) {
ball_pos[1] = ball.radius;
ball_vel[1] = -ball_vel[1];
} else if (ball_pos[1] > height - ball.radius) {
ball_pos[1] = height - ball.radius;
ball_vel[1] = -ball_vel[1];
}
//check left gutter
if (ball_pos[0] < paddle.width ) {
// check for paddle
if (pad1_pos-paddle.half_height-ball.radius<= ball_pos[1] && ball_pos[1]<= pad1_pos + paddle.half_height+ball.radius) {
// p2 score
// bounce
console.log("Hit paddle");
ball_pos[0] = paddle.width ;
speed_up_ball();
// set ball angle equal to the angle from the paddle to the ball
//if the ball is nearer the edge of the paddle it gets deflected at a greater angle
set_ball_angle(angle(paddle.half_width, pad1_pos, ball_pos[0], ball_pos[1]));
start_electric_effect();
}
else {
console.log("!Hit");
score2 += 1;
playSound(beepSound,0.9);
ballInit(ball_pos[0] < width / 2);
}
}
//
// check right gutter
else if (ball_pos[0]> width-paddle.width-ball.width) {
// check for paddle
if (pad2_pos-paddle.half_height-ball.radius<= ball_pos[1] && ball_pos[1]<= pad2_pos + paddle.half_height+ball.radius){
// bounce
console.log("Hit paddle");
ball_pos[0] = width - paddle.width-ball.width;
speed_up_ball();
set_ball_angle(angle(width - paddle.half_width, pad2_pos, ball_pos[0], ball_pos[1]));
start_electric_effect();
} else {
console.log("!hit");
score1 += 1;
playSound(beepSound,0.9);
ballInit(ball_pos[0] < width / 2);
}
}
}
function update_paddles() {
if (comp_AI) //and ball_pos[0] < WIDTH / 2:
if (pad1_pos + paddle.half_height < ball_pos[1]) pad1_vel = paddle.speed;
else if (pad1_pos - paddle.half_height > ball_pos[1]) pad1_vel = -paddle.speed;
else pad1_vel = 0;
// paddle 1
pad1_pos += pad1_vel;
if(pad1_pos < paddle.height/2) pad1_pos = paddle.height/2;
else if (pad1_pos > height-paddle.height/2) pad1_pos = height-paddle.height/2;
// paddle 2
pad2_pos += pad2_vel;
if (pad2_pos < paddle.height/2) pad2_pos =paddle.height/2;
else if (pad2_pos > height-paddle.height/2 ) pad2_pos = height-paddle.height/2;
}
function render(){
if(images_loaded){
frame.drawImage(background_img,0,0,width,height,0,0,width,height);
update_paddles();
//mid lines
frame.drawLine([width/2,gutter_count],[width/2,gutter_count+10],1,"red");
frame.drawLine([width/2,height-gutter_count],[width/2,height-gutter_count-10],1,"red");
//gutter left
frame.drawLine([paddle.width,gutter_count],[paddle.width,gutter_count+10],1,"red");
frame.drawLine([width - paddle.width,gutter_count],[width-paddle.width,gutter_count+10],1,"red");
frame.drawLine([width - paddle.width,gutter_count],[width-paddle.width,gutter_count+10],1,"red");
// gutter right
frame.drawLine( [paddle.width,height-gutter_count],[paddle.width,height-gutter_count-10],1,"red");
frame.drawLine([width - paddle.width,height-gutter_count],[width-paddle.width,height-gutter_count-10],1,"red");
frame.drawLine([width - paddle.width,height-gutter_count],[width-paddle.width,height-gutter_count-10],1,"red");
// frame.drawLine([10,60],[100,240],4,"red");
gutter_count = (gutter_count+10)%height;
// draw paddles
frame.draw_image(ball_eff1_img,[0,0], [ball_effects.effect1_width, ball_effects.effect1_height],[ball_pos[0]-40,ball_pos[1]-40], [ball_effects.effect1_width, ball_effects.effect1_height],random(1,360));
frame.drawImage(paddle_img,0,0,paddle.width,paddle.height,0,pad1_pos-paddle.height/2,paddle.width,paddle.height);
frame.draw_image(paddle_img,[0,0],[paddle.width,paddle.height],[width-paddle.width,pad2_pos-paddle.height/2],[paddle.width,paddle.height],180);
updateBall();
// var item;
// for(var j=trail.length-1;j>=0;j--){
// item = trail[j];
// frame.draw_image(ball_eff1_img,[0,0],[ball_effects.effect1_width,ball_effects.effect1_height],item,[ball_effects.effect1_width/2,ball_effects.effect1_height/2]);
// frame.draw_image(ball_effect2_img,[0,0],[ball_effects.effect2_width,ball_effects.effect1_height],item,[ball_effects.effect1_width/2,ball_effects.effect1_height/2]);
// console.log(item);
// }
if(isRunning){
playSound(electric_sound,0.9);
frame.draw_image(ball_effect2_img,[0,0], [ball_effects.effect2_width, ball_effects.effect2_height],[ball_pos[0]-280,ball_pos[1]-280], [ball_effects.effect2_width, ball_effects.effect2_height],random(1,360));
}
frame.draw_image(ball_img,[0,0],[ball.radius*2,ball.radius*2],ball_pos,[ball.radius*2,ball.radius*2],random(1,360));
frame.draw_image(ball_img,[0,0],[ball.radius*2,ball.radius*2],ball_pos,[ball.radius*2,ball.radius*2],random(45,360));
// scores
frame.font = "18px digitek";
frame.fillStyle="red";
frame.fillText("SCORE : "+score1,60,30);
frame.fillText("SCORE : "+score2,380,30);
frame.fill();
}
else{
frame.save();
frame.fillStyle = "black";
frame.fillRect(0,0,canvas.width,canvas.height);
frame.drawImage(animLoader,72*i,0,72,72,canvas.width/2-36,canvas.height/2-36,72,72);
frame.fillStyle = "red";
frame.font="24px slicker";
frame.shadowOffsetX=0;
frame.shadowOffsetY=1;
frame.shadowBlur=0;
frame.shadowColor="grey";
frame.beginPath();
frame.fillText("Please wait....",250-20,250+60);
frame.fillStyle = "aqua";
frame.shadowColor="darkgreen";
frame.fillText("Loading Resources : "+resLoaded+"/"+totalRes,170,250+90);
frame.font="34px potter";
frame.fillStyle="red";
frame.fillText("PONG CLASSIC",190,130);
frame.restore();
i++;
if(i>9) i=0;
}
}
function restart(){
comp_AI = false;
h1.innerHTML = "Computer AI : OFF";
newGame();
}
function toggle_ai(){
comp_AI = !comp_AI;
// set Text
if(comp_AI)keydown=true;
else keydown = false;
newGame();
}
// timers
function Collision_effect_tick(){
window.clearInterval(collision_effect_timer);
isRunning = false;
}
function trail_timer_tick(){
randomVal = random(1,5);
if(randomVal<3){
if(trail.length<max_particles) trail.push(ball_pos);
}
else if(trail.length>0){
trail.splice(random(0,trail.length),1);
}
}
newGame();
window.setInterval(render,33);
};
@font-face {
font-family: digitek;
src: url("https://dl.dropboxusercontent.com/u/224687431/DIGITEK.TTF");
}
@font-face {
font-family: slicker;
src: url("https://dl.dropboxusercontent.com/u/224687431/Slicker.ttf");
}
@font-face {
font-family: potter;
src: url("https://dl.dropboxusercontent.com/u/224687431/Harry%20Potter.ttf");
}
h1{
font-family: slicker;
color:crimson;
font-size:20px;
position: absolute;
width:250px;
height: 50px;
text-align: center;
top:500px;
left: 225px;
}
.controls{
background:linear-gradient(to left,black,grey,black);
box-shadow: none;
color:black;
font: 20px bold, slicker;
width: 120px;
height: 50px;
border: 1px solid grey;
text-shadow: 0px 1px 0px white;
}
.controls:hover{
color: aqua;
background:linear-gradient(to top,black,grey,black);
text-shadow: 0px 1px 0px black;
cursor: pointer;
}
#control{
top: 120px;
font-weight:bold;
font-family: Tahoma "Gloria Hallelujah" !important;
float:right;
position: absolute;
left:710px;
border: 1px solid black;
border-radius:30px 0px 30px 0px ;
padding:10px;
box-shadow: 2px 3px 18px black;
}
#control:hover{
cursor: crosshair;
border-radius: 40px;
border:2px dashed crimson;
}
div p u{
color:green;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment