Pong pong pong pong pong ping. Pong pong ping pong pong pong ping.
A Pen by Gerard Ferrandez on CodePen.
<div id="screen"></div> |
!function() { | |
"use strict"; | |
// variables | |
var acc = 1.01; | |
var speed = 0.025; | |
var angle = 15; | |
var pong1, pong2, pong3; | |
var timeP = new Date(); | |
// def audio | |
if (window.Audio) { | |
var base = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/222599/"; | |
var notlogical = new Audio(base + 'Door_entry_notification.mp3'); | |
notlogical.play(); | |
pong1 = new Audio(base + 'pong1.mp3'); | |
pong2 = new Audio(base + 'pong2.mp3'); | |
pong3 = new Audio(base + 'pong3.mp3'); | |
} | |
// def screen | |
var screen = { | |
elem: document.getElementById('screen'), | |
left: 0, | |
width: 0, | |
height: 0, | |
scaleX: 0, | |
scaleY: 0 | |
} | |
// append html elements helper | |
screen.elem.append = function (tag, att, css) { | |
var object = document.createElement(tag); | |
for (var i in att) object[i] = att[i]; | |
for (var i in css) object.style[i] = css[i]; | |
this.appendChild(object); | |
object.append = screen.elem.append; | |
return object; | |
} | |
// resize | |
screen.resize = function () { | |
// screen size and position | |
var o = screen.elem; | |
for (screen.left = 0; o != null; o = o.offsetParent) screen.left += o.offsetLeft; | |
screen.width = screen.elem.offsetWidth; | |
screen.height = screen.elem.offsetHeight; | |
// scale pixels size | |
screen.scaleX = screen.width * 0.03; | |
screen.scaleY = screen.height * 0.25; | |
// ball and pads | |
ball.style.width = ball.style.height = Math.round(screen.scaleX) + 'px'; | |
pad[0].style.width = pad[1].style.width = Math.round(screen.scaleX) + 'px'; | |
pad[0].style.height = pad[1].style.height = Math.round(screen.scaleY) + 'px'; | |
pad[0].style.left = Math.round(screen.scaleX) + "px"; | |
pad[1].style.left = Math.round(screen.width - screen.scaleX * 2) + "px"; | |
// scores | |
for (var i = 0; i < 4; i++) { | |
var o = score[i].elem.style; | |
o.width = o.height = Math.round(3 * screen.scaleX) + 'px'; | |
o.left = Math.round(score[i].d > 0 ? screen.width * 0.5 + 2 * screen.scaleX : screen.width * 0.4 - 2 * screen.scaleX) + 'px'; | |
o.top = Math.round(i < 2 ? screen.scaleX : screen.height - 4 * screen.scaleX) + 'px'; | |
} | |
// separation | |
sp.style.width = Math.round(screen.scaleX) + 'px'; | |
sp.style.left = Math.round(screen.width * 0.5 - screen.scaleX * 0.5) + 'px'; | |
sp.innerHTML = ""; | |
for (var i = 0; i < screen.height; i += screen.scaleX * 2) { | |
sp.append('span', false, { | |
'top': Math.round(i) + 'px', | |
'width': Math.round(screen.scaleX) + 'px', | |
'height': Math.round(screen.scaleX) + 'px' | |
}); | |
} | |
} | |
// move pads | |
screen.move = function (e, touch) { | |
e.preventDefault(); | |
var pointer = touch ? e.touches[0] : e; | |
var y = screen.height - screen.scaleY; | |
var x = (pointer.clientX - screen.left) / screen.width; | |
pad[0].y = Math.min(screen.height - screen.scaleY, Math.max(0, x * y * 2 - y * 0.5)); | |
pad[1].y = Math.min(screen.height - screen.scaleY, Math.max(0, (1 - x) * y * 2 - y * 0.5)); | |
} | |
// launch new ball | |
screen.down = function (e, touch) { | |
e.preventDefault(); | |
if (player >= 0) { | |
pong1 && pong1.play(); | |
ball.vx = screen.scaleX * speed; | |
ball.vy = (Math.random() - 0.5) * screen.height * 0.01; | |
if (player === 1) ball.vx = -ball.vx; | |
player = -1; | |
} | |
} | |
// def scores | |
var score = [ | |
{s:0, d:-1}, | |
{s:0, d: 1}, | |
{s:0, d:-1}, | |
{s:0, d: 1} | |
]; | |
score.chrono = function (score) { | |
var dir = score.d; | |
var txt = score.s + ""; | |
score.elem.innerHTML = ""; | |
var a = [119,36,93,109,46,107,123,37,127,111]; | |
var s = { | |
1: [0,0,99,20], | |
2: [0,0,33,45], | |
4: [67,0,33,45], | |
8: [0,40,100,20], | |
16:[0,40,33,60], | |
32:[67,40,33,60], | |
64:[0,80,99,20] | |
}; | |
for (var i = 0, n = txt.length; i < n; i++) { | |
var c = txt.charAt(dir > 0 ? i : n - i - 1); | |
var p = a[c]; | |
if (p) { | |
var d = score.elem.append('div', false, { | |
'height': '100%', | |
'width': '100%', | |
'left': (120 * i * dir) + '%' | |
}); | |
for (var j in s) { | |
var k = s[j]; | |
if (p & j) d.append('span', false, { | |
'left': k[0] + '%', | |
'top': k[1] + '%', | |
'width': k[2] + '%', | |
'height': k[3] + '%' | |
}); | |
} | |
} | |
} | |
} | |
score.forEach(function (s) { | |
s.elem = screen.elem.append('div'); | |
score.chrono(s); | |
}); | |
// pads | |
var pad = []; | |
pad.ping = function () { | |
if (ball.y + screen.scaleX > this.y && ball.y < this.y + screen.scaleY) { | |
pong1 && pong1.play(); | |
// inc scores | |
score[2].s++; | |
score.chrono(score[2]); | |
if(score[2].s > score[3].s) { | |
score[3].s = score[2].s; | |
score.chrono(score[3]); | |
} | |
// bounce | |
ball.vx = -ball.vx * acc; | |
ball.x = this.x; | |
if (ball.y < this.y) { | |
ball.vy = ball.vx * -this.s * angle + Math.random() * 0.1; | |
} else if (ball.y > this.y + screen.scaleY - screen.scaleX) { | |
ball.vy = ball.vx * this.s * angle + Math.random() * 0.1; | |
} else { | |
ball.vy = (Math.random() - 0.5) * ball.vx * angle; | |
} | |
} | |
} | |
// first pad | |
pad.push({ | |
y: 0, | |
s: 1, | |
ping: pad.ping, | |
get x () { | |
return screen.scaleX * 2; | |
} | |
}); | |
// second pad | |
pad.push({ | |
y: 0, | |
s:-1, | |
ping: pad.ping, | |
get x () { | |
return screen.width - screen.scaleX * 3; | |
} | |
}); | |
pad[0].style = screen.elem.append('span').style; | |
pad[1].style = screen.elem.append('span').style; | |
// ball | |
var ball = { | |
vx: 0, | |
vy: 0, | |
x: 0, | |
y: 0, | |
w: 0 | |
} | |
ball.style = screen.elem.append('span').style; | |
// separation line | |
var sp = screen.elem.append('div', false, { | |
'height': '100%' | |
}); | |
var player = 0; | |
// mouse/touch events | |
if ('ontouchstart' in window) { | |
screen.elem.ontouchstart = function(e) { screen.down(e, true); }; | |
screen.elem.ontouchmove = function(e) { screen.move(e, true); }; | |
} | |
window.addEventListener("mousemove", function(e) { screen.move(e, false); }, false ); | |
screen.elem.addEventListener("click", function(e) { screen.down(e, false); }, false); | |
// screen resize | |
window.addEventListener("resize", screen.resize, false ); | |
screen.resize(); | |
// player wins | |
function win (p) { | |
pong3 && pong3.play(); | |
score[1 - p].s++; | |
score.chrono(score[1 - p]); | |
score[2].s = 0; | |
score.chrono(score[2]); | |
player = p; | |
} | |
// main loop | |
function run () { | |
requestAnimationFrame(run); | |
var time = new Date(); | |
var vx = ball.vx * (time - timeP); | |
// playing | |
if (player < 0) { | |
ball.x += vx; | |
ball.y += ball.vy; | |
} else { | |
ball.x = pad[player].x; | |
ball.y = pad[player].y + screen.scaleY * 0.5 - screen.scaleX * 0.5; | |
} | |
timeP = time; | |
// collisions | |
if (ball.vx > 0) { | |
if (ball.x > screen.width + screen.scaleX) win(1); | |
else if (ball.x > screen.width - screen.scaleX * 3) pad[1].ping(); | |
} else { | |
if (ball.x < -screen.scaleX) win(0); | |
else if (ball.x < screen.scaleX * 2) pad[0].ping(); | |
} | |
if (ball.y > screen.height - screen.scaleX || ball.y < 0) { | |
pong2 && pong2.play(); | |
ball.vy = -ball.vy; | |
} | |
// DOM animation | |
pad[0].style.top = Math.round(pad[0].y) + 'px'; | |
pad[1].style.top = Math.round(pad[1].y) + 'px'; | |
ball.style.left = Math.round(ball.x) + 'px'; | |
ball.style.top = Math.round(ball.y) + 'px'; | |
} | |
// go go go ! | |
run(); | |
}(); |
Pong pong pong pong pong ping. Pong pong ping pong pong pong ping.
A Pen by Gerard Ferrandez on CodePen.
html { | |
overflow: hidden; | |
touch-action: none; | |
content-zooming: none; | |
} | |
body { | |
position: absolute; | |
margin: 0; | |
padding: 0; | |
background: #222; | |
width: 100%; | |
height: 100%; | |
} | |
#screen { | |
width: 100vw; | |
height: 56.25vw; /* 100/56.25 = 1.778 */ | |
background: #000; | |
max-height: 100vh; | |
max-width: 177.78vh; /* 16/9 = 1.778 */ | |
margin: auto; | |
position: absolute; | |
top:0; /* vertical center */ | |
bottom:0; | |
left:0; /* horizontal center */ | |
right:0; | |
overflow: hidden; | |
cursor: crosshair; | |
} | |
#screen div { | |
position: absolute; | |
overflow: hidden; | |
} | |
#screen span { | |
position: absolute; | |
background: #FFF; | |
overflow:hidden; | |
} |