Ajax Loader
HTML
<canvas id="canvas"></canvas>
1
<canvas id="canvas"></canvas>
2
<audio preload="true" id="collide">
3
  <source src="http://dl.dropbox.com/u/26141789/canvas/pingpong/Metal%20Cling%20-%20Hit.mp3" />
4
  <source src="http://dl.dropbox.com/u/26141789/canvas/pingpong/Metal%20Cling%20-%20Hit.wav" />
5
</audio>
 
CSS
body {padding: 0; margin: 0; overflow: hidden;}
1
body {padding: 0; margin: 0; overflow: hidden;}
 
JavaScript
// RequestAnimFrame: a browser API for getting smooth animations
1
// RequestAnimFrame: a browser API for getting smooth animations
2
window.requestAnimFrame = (function(){
3
  return  window.requestAnimationFrame       || 
4
    window.webkitRequestAnimationFrame || 
5
    window.mozRequestAnimationFrame    || 
6
    window.oRequestAnimationFrame      || 
7
    window.msRequestAnimationFrame     ||  
8
    function( callback ){
9
      return window.setTimeout(callback, 1000 / 60);
10
    };
11
})();
12
 
13
window.cancelRequestAnimFrame = ( function() {
14
  return window.cancelAnimationFrame          ||
15
    window.webkitCancelRequestAnimationFrame    ||
16
    window.mozCancelRequestAnimationFrame       ||
17
    window.oCancelRequestAnimationFrame     ||
18
    window.msCancelRequestAnimationFrame        ||
19
    clearTimeout
20
} )();
21
 
22
 
23
// Initialize canvas and required variables
24
var canvas = document.getElementById("canvas"),
25
    ctx = canvas.getContext("2d"), // Create canvas context
26
    W = window.innerWidth, // Window's width
27
    H = window.innerHeight, // Window's height
28
    particles = [], // Array containing particles
29
    ball = {}, // Ball object
30
    paddles = [2], // Array containing two paddles
31
    mouse = {}, // Mouse object to store it's current position
32
    points = 0, // Varialbe to store points
33
    fps = 60, // Max FPS (frames per second)
34
    particlesCount = 20, // Number of sparks when ball strikes the paddle
35
    flag = 0, // Flag variable which is changed on collision
36
    particlePos = {}, // Object to contain the position of collision 
37
    multipler = 1, // Varialbe to control the direction of sparks
38
    startBtn = {}, // Start button object
39
    restartBtn = {}, // Restart button object
40
    over = 0, // flag varialbe, cahnged when the game is over
41
    init, // variable to initialize animation
42
    paddleHit;
43
 
44
// Add mousemove and mousedown events to the canvas
45
canvas.addEventListener("mousemove", trackPosition, true);
46
canvas.addEventListener("mousedown", btnClick, true);
47
 
48
// Initialise the collision sound
49
collision = document.getElementById("collide");
50
 
51
// Set the canvas's height and width to full screen
52
canvas.width = W;
53
canvas.height = H;
54
 
55
// Function to paint canvas
56
function paintCanvas() {
57
  ctx.fillStyle = "black";
58
  ctx.fillRect(0, 0, W, H);
59
}
60
 
61
// Function for creating paddles
62
function Paddle(pos) {
63
  // Height and width
64
  this.h = 5;
65
  this.w = 150;
66
  
67
  // Paddle's position
68
  this.x = W/2 - this.w/2;
69
  this.y = (pos == "top") ? 0 : H - this.h;
70
  
71
}
72
 
73
// Push two new paddles into the paddles[] array
74
paddles.push(new Paddle("bottom"));
75
paddles.push(new Paddle("top"));
76
 
77
// Ball object
78
ball = {
79
  x: 50,
80
  y: 50, 
81
  r: 5,
82
  c: "white",
83
  vx: 4,
84
  vy: 8,
85
  
86
  // Function for drawing ball on canvas
87
  draw: function() {
88
    ctx.beginPath();
89
    ctx.fillStyle = this.c;
90
    ctx.arc(this.x, this.y, this.r, 0, Math.PI*2, false);
91
    ctx.fill();
92
  }
93
};
94
 
95
 
96
// Start Button object
97
startBtn = {
98
  w: 100,
99
  h: 50,
100
  x: W/2 - 50,
101
  y: H/2 - 25,
102
  
103
  draw: function() {
104
    ctx.strokeStyle = "white";
105
    ctx.lineWidth = "2";
106
    ctx.strokeRect(this.x, this.y, this.w, this.h);
107
    
108
    ctx.font = "18px Arial, sans-serif";
109
    ctx.textAlign = "center";
110
    ctx.textBaseline = "middle";
111
    ctx.fillStlye = "white";
112
    ctx.fillText("Start", W/2, H/2 );
113
  }
114
};
115
 
116
// Restart Button object
117
restartBtn = {
118
  w: 100,
119
  h: 50,
120
  x: W/2 - 50,
121
  y: H/2 - 50,
122
  
123
  draw: function() {
124
    ctx.strokeStyle = "white";
125
    ctx.lineWidth = "2";
126
    ctx.strokeRect(this.x, this.y, this.w, this.h);
127
    
128
    ctx.font = "18px Arial, sans-serif";
129
    ctx.textAlign = "center";
130
    ctx.textBaseline = "middle";
131
    ctx.fillStlye = "white";
132
    ctx.fillText("Restart", W/2, H/2 - 25 );
133
  }
134
};
135
 
136
// Function for creating particles object
137
function createParticles(x, y, m) {
138
  this.x = x || 0;
139
  this.y = y || 0;
140
  
141
  this.radius = 1.2;
142
  
143
  this.vx = -1.5 + Math.random()*3;
144
  this.vy = m * Math.random()*1.5;
145
}
146
 
147
// Draw everything on canvas
148
function draw() {
149
  paintCanvas();
150
  for(var i = 0; i < paddles.length; i++) {
151
    p = paddles[i];
152
    
153
    ctx.fillStyle = "white";
154
    ctx.fillRect(p.x, p.y, p.w, p.h);
155
  }
156
  
157
  ball.draw();
158
  update();
159
}
160
 
161
// Function to increase speed after every 5 points
162
function increaseSpd() {
163
  if(points % 4 == 0) {
164
    if(Math.abs(ball.vx) < 15) {
165
      ball.vx += (ball.vx < 0) ? -1 : 1;
166
      ball.vy += (ball.vy < 0) ? -2 : 2;
167
    }
168
  }
169
}
170
 
171
// Track the position of mouse cursor
172
function trackPosition(e) {
173
  mouse.x = e.pageX;
174
  mouse.y = e.pageY;
175
}
176
 
177
// Function to update positions, score and everything.
178
// Basically, the main game logic is defined here
179
function update() {
180
  
181
  // Update scores
182
  updateScore(); 
183
  
184
  // Move the paddles on mouse move
185
  if(mouse.x && mouse.y) {
186
    for(var i = 1; i < paddles.length; i++) {
187
      p = paddles[i];
188
      p.x = mouse.x - p.w/2;
189
    }   
190
  }
191
  
192
  // Move the ball
193
  ball.x += ball.vx;
194
  ball.y += ball.vy;
195
  
196
  // Collision with paddles
197
  p1 = paddles[1];
198
  p2 = paddles[2];
199
  
200
  // If the ball strikes with paddles,
201
  // invert the y-velocity vector of ball,
202
  // increment the points, play the collision sound,
203
  // save collision's position so that sparks can be
204
  // emitted from that position, set the flag variable,
205
  // and change the multiplier
206
  if(collides(ball, p1)) {
207
    collideAction(ball, p1);
208
  }
209
  
210
  
211
  else if(collides(ball, p2)) {
212
    collideAction(ball, p2);
213
  } 
214
  
215
  else {
216
    // Collide with walls, If the ball hits the top/bottom,
217
    // walls, run gameOver() function
218
    if(ball.y + ball.r > H) {
219
      ball.y = H - ball.r;
220
      gameOver();
221
    } 
222
    
223
    else if(ball.y < 0) {
224
      ball.y = ball.r;
225
      gameOver();
226
    }
227
    
228
    // If ball strikes the vertical walls, invert the 
229
    // x-velocity vector of ball
230
    if(ball.x + ball.r > W) {
231
      ball.vx = -ball.vx;
232
      ball.x = W - ball.r;
233
    }
234
    
235
    else if(ball.x -ball.r < 0) {
236
      ball.vx = -ball.vx;
237
      ball.x = ball.r;
238
    }
239
  }
240
  
241
  
242
  
243
  // If flag is set, push the particles
244
  if(flag == 1) { 
245
    for(var k = 0; k < particlesCount; k++) {
246
      particles.push(new createParticles(particlePos.x, particlePos.y, multiplier));
247
    }
248
  } 
249
  
250
  // Emit particles/sparks
251
  emitParticles();
252
  
253
  // reset flag
254
  flag = 0;
255
}
256
 
257
//Function to check collision between ball and one of
258
//the paddles
259
function collides(b, p) {
260
  if(b.x + ball.r >= p.x && b.x - ball.r <=p.x + p.w) {
261
    if(b.y >= (p.y - p.h) && p.y > 0){
262
      paddleHit = 1;
263
      return true;
264
    }
265
    
266
    else if(b.y <= p.h && p.y == 0) {
267
      paddleHit = 2;
268
      return true;
269
    }
270
    
271
    else return false;
272
  }
273
}
274
 
275
//Do this when collides == true
276
function collideAction(ball, p) {
277
  ball.vy = -ball.vy;
278
  
279
  if(paddleHit == 1) {
280
    ball.y = p.y - p.h;
281
    particlePos.y = ball.y + ball.r;
282
    multiplier = -1;  
283
  }
284
  
285
  else if(paddleHit == 2) {
286
    ball.y = p.h + ball.r;
287
    particlePos.y = ball.y - ball.r;
288
    multiplier = 1; 
289
  }
290
  
291
  points++;
292
  increaseSpd();
293
  
294
  if(collision) {
295
    if(points > 0) 
296
      collision.pause();
297
    
298
    collision.currentTime = 0;
299
    collision.play();
300
  }
301
  
302
  particlePos.x = ball.x;
303
  flag = 1;
304
}
305
 
306
// Function for emitting particles
307
function emitParticles() { 
308
  for(var j = 0; j < particles.length; j++) {
309
    par = particles[j];
310
    
311
    ctx.beginPath(); 
312
    ctx.fillStyle = "white";
313
    if (par.radius > 0) {
314
      ctx.arc(par.x, par.y, par.radius, 0, Math.PI*2, false);
315
    }
316
    ctx.fill();  
317
    
318
    par.x += par.vx; 
319
    par.y += par.vy; 
320
    
321
    // Reduce radius so that the particles die after a few seconds
322
    par.radius = Math.max(par.radius - 0.05, 0.0); 
323
    
324
  } 
325
}
326
 
327
// Function for updating score
328
function updateScore() {
329
  ctx.fillStlye = "white";
330
  ctx.font = "16px Arial, sans-serif";
331
  ctx.textAlign = "left";
332
  ctx.textBaseline = "top";
333
  ctx.fillText("Score: " + points, 20, 20 );
334
}
335
 
336
// Function to run when the game overs
337
function gameOver() {
338
  ctx.fillStlye = "white";
339
  ctx.font = "20px Arial, sans-serif";
340
  ctx.textAlign = "center";
341
  ctx.textBaseline = "middle";
342
  ctx.fillText("Game Over - You scored "+points+" points!", W/2, H/2 + 25 );
343
  
344
  // Stop the Animation
345
  cancelRequestAnimFrame(init);
346
  
347
  // Set the over flag
348
  over = 1;
349
  
350
  // Show the restart button
351
  restartBtn.draw();
352
}
353
 
354
// Function for running the whole animation
355
function animloop() {
356
  init = requestAnimFrame(animloop);
357
  draw();
358
}
359
 
360
// Function to execute at startup
361
function startScreen() {
362
  draw();
363
  startBtn.draw();
364
}
365
 
366
// On button click (Restart and start)
367
function btnClick(e) {
368
  
369
  // Variables for storing mouse position on click
370
  var mx = e.pageX,
371
      my = e.pageY;
372
  
373
  // Click start button
374
  if(mx >= startBtn.x && mx <= startBtn.x + startBtn.w) {
375
    animloop();
376
    
377
    // Delete the start button after clicking it
378
    startBtn = {};
379
  }
380
  
381
  // If the game is over, and the restart button is clicked
382
  if(over == 1) {
383
    if(mx >= restartBtn.x && mx <= restartBtn.x + restartBtn.w) {
384
      ball.x = 20;
385
      ball.y = 20;
386
      points = 0;
387
      ball.vx = 4;
388
      ball.vy = 8;
389
      animloop();
390
      
391
      over = 0;
392
    }
393
  }
394
}
395
 
396
// Show the start screen
397
startScreen();
 

Ping-Pong Game Tutorial with HTML5 Canvas and Sounds

CSSDeck G+