Skip to content

Instantly share code, notes, and snippets.

@sempostma
Last active February 7, 2019 13:15
Show Gist options
  • Save sempostma/fe2e45ca98f5d85a1e8bd2663d273fc9 to your computer and use it in GitHub Desktop.
Save sempostma/fe2e45ca98f5d85a1e8bd2663d273fc9 to your computer and use it in GitHub Desktop.
final-approach.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Game</title>
<style>
body {
margin: 0;
}
html {
overflow: hidden;
background: #000;
}
* {
font-family: monospace;
font-size: 16px;
}
canvas {
position: absolute;
}
#stack {
position: absolute;
left: 0;
top: 0;
color: #fff;
background: #001600;
border: 1px solid #003600;
padding: 3px;
border-radius: 4px;
}
#stack>div {
margin-bottom: 3px;
}
#stack>div:last-of-type {
margin-bottom: 0;
}
input {
background: #002000;
border: 1px solid #005500;
border-radius: 4px;
padding: 3px;
outline: none;
color: #fff;
}
button {
background: #002000;
border: 1px solid #005500;
border-radius: 4px;
padding: 3px;
outline: none;
margin-left: 2px;
color: #fff;
}
button:hover {
background: #003000;
}
button:active {
background: #005500;
}
input:hover {
background: #003000;
}
input:active {
background: #005500;
}
.callsign {
width: 80px;
margin-left: 5px;
display: inline-block;
vertical-align: middle;
vertical-align: baseline;
}
#mistakes {
color: #005500;
position: fixed;
right: 5px;
top: 2px;
font-size: 30px;
font-weight: bold;
}
fieldset {
appearance: none;
border: none;
background: transparent;
}
</style>
</head>
<body>
<canvas id="c"></canvas>
<fieldset>
<div id="stack">
</div>
</fieldset>
<div id="mistakes"></div>
<script>
var stack = document.getElementById('stack');
var mistakesElement = document.getElementById('mistakes');
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var globalSpeed = .005;
var spawnSpeed = .5;
var dotSpeed = .05;
var dotAmount = 20;
var airplanes = [];
var sepRadius = 50;
var sepRadiusSq = sepRadius * sepRadius;
var rm = [];
var airlines = ['KLM', 'DLT', 'JBU'];
var i = 0;
var j = 0;
var highlight = null;
var mistakes = 0;
resize();
window.addEventListener('resize', resize);
window.addEventListener('orientationchange', resize);
document.addEventListener('click', unfocus);
document.addEventListener('mouseover', unfocus);
function unfocus() {
if (highlight) {
highlight = null;
requestAnimationFrame(render);
}
}
window.addEventListener('keydown', function (e) {
if (e.key === 'ArrowLeft') globalSpeed /= 1.3;
if (e.key === 'ArrowRight') globalSpeed *= 1.3;
});
newPlane();
setInterval(update, 1000 / 10); // 10 fps
function getRandHeight() {
var mid = canvas.height / 2;
return mid + (Math.random() - .5) * canvas.width;
}
function newPlane() {
var item = document.createElement('div');
var speedRnd = 200 + Math.floor(Math.random() * 4) * 10;
var airplane = {
x: canvas.width,
y: getRandHeight(),
speed: speedRnd,
tgtSpeed: speedRnd,
callsign: airlines[Math.floor(Math.random() * airlines.length)] + Math.floor(Math.random() * 1000),
stack: item
};
airplane.dots = [[airplane.x, airplane.y]];
var callsign = document.createElement('span');
callsign.appendChild(document.createTextNode(airplane.callsign));
callsign.setAttribute('class', 'callsign');
item.appendChild(callsign);
var input = document.createElement('input');
input.value = airplane.tgtSpeed;
input.addEventListener('keydown', function (e) {
if (e.key === 'Enter') go();
});
input.addEventListener('focus', focus)
var btn = document.createElement('button');
btn.tabIndex = -1;
btn.innerText = 'GO';
btn.addEventListener('click', go);
item.addEventListener('mouseover', focus);
item.addEventListener('click', focus);
item.appendChild(input);
item.appendChild(btn);
stack.appendChild(item);
airplanes.push(airplane);
function focus(e) {
if (highlight !== airplane) {
highlight = airplane;
requestAnimationFrame(render);
}
e.stopPropagation();
}
function go() {
airplane.tgtSpeed = Math.min(Math.max(input.value, 160), 250);
input.value = airplane.tgtSpeed;
}
}
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
function update() {
if ((i += globalSpeed) > spawnSpeed) {
i = 0;
newPlane();
}
rm.splice(0, rm.length);
airplanes.forEach(function (airplane) {
airplane.speed -= Math.min(Math.max(airplane.speed - airplane.tgtSpeed, -globalSpeed * 100), globalSpeed * 100);
var deltaFromCenter = canvas.height / 2 - airplane.y;
var distFromCenter = deltaFromCenter / Math.abs(deltaFromCenter);
var yDelta = distFromCenter * Math.min(Math.abs(deltaFromCenter), globalSpeed * airplane.speed * 0.6);
if (Math.abs(deltaFromCenter) < 25) yDelta /= 1 + (25 - Math.abs(deltaFromCenter)) / 10;
var xDelta = airplane.speed * globalSpeed;
airplane.x -= xDelta - Math.abs(yDelta) * .5;
airplane.y += yDelta;
for (var i = 0; i < airplanes.length; i++) {
if (airplane === airplanes[i]) continue;
var x = Math.abs(airplanes[i].x - airplane.x);
var y = Math.abs(airplanes[i].y - airplane.y);
if ((x * x) + (y * y) < sepRadiusSq) {
mistakes += globalSpeed;
break;
}
}
if (airplane.x < 80) {
rm.push(airplane);
}
});
if ((j += globalSpeed) > dotSpeed) {
j = 0;
airplanes.forEach(function (airplane) {
airplane.dots.unshift([airplane.x, airplane.y]);
if (airplane.dots.length > dotAmount) airplane.dots.pop();
});
}
rm.forEach(function (r) {
stack.removeChild(r.stack);
airplanes.splice(airplanes.indexOf(r), 1);
});
requestAnimationFrame(render);
}
function render() {
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, canvas.clientWidth, canvas.clientHeight);
ctx.fillStyle = '#ffffff';
ctx.fillRect(50, canvas.clientHeight / 2, 40, 2);
ctx.fillText('09', 40, canvas.height / 2 - 2);
ctx.fillText('27', 80, canvas.height / 2 - 2);
ctx.fillStyle = ctx.strokeStyle = '#005500';
mistakesElement.innerText = mistakes;
airplanes.forEach(function (airplane) {
for (var i = 0; i < airplanes.length; i++) {
if (airplane === airplanes[i]) continue;
var x = Math.abs(airplanes[i].x - airplane.x);
var y = Math.abs(airplanes[i].y - airplane.y);
if ((x * x) + (y * y) < sepRadiusSq) {
ctx.beginPath();
ctx.arc(airplane.x, airplane.y, sepRadius, 0, Math.PI * 2, false);
ctx.fillStyle = 'rgba(255,0,0,0.2)';
ctx.fill();
break;
}
}
ctx.fillRect(airplane.x, airplane.y, 4, 4);
ctx.beginPath();
ctx.moveTo(airplane.x, airplane.y);
if (highlight === airplane) {
ctx.font = "Bold 15px Arial";
} else {
ctx.font = "15px Arial";
}
ctx.lineTo(airplane.x - 50, airplane.y - 50, 150);
ctx.stroke();
ctx.fillText(airplane.callsign, airplane.x - 80, airplane.y - 70);
ctx.fillText(Math.round(airplane.speed), airplane.x - 80, airplane.y - 55);
airplane.dots.forEach(function (dot) {
ctx.fillStyle = ctx.strokeStyle = '#005500';
ctx.fillRect(dot[0], dot[1], 2, 2)
});
});
mistakesElement.innerText = Math.ceil(mistakes) + ' ERRORS';
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment