<!
DOCTYPE html>
<html>
<head>
<title>Basic Helicopter HTML Game</title>
<meta charset="UTF-8">
<style>
html, body {
height: 100%;
margin: 0;
}
body {
background: black;
display: flex;
align-items: center;
justify-content: center;
}
</style>
</head>
<body>
<canvas width="800" height="550" id="game"></canvas>
<script>
const canvas = [Link]('game');
const context = [Link]('2d');
const minTunnelWidth = 400;
const maxTunnelWidth = [Link];
const minHeight = 10;
const maxHeight = 100;
const obstacleWidth = 65;
const obstacleHeight = 135;
// how fast the background moves
const moveSpeed = 7;
// downward acceleration
const gravity = 0.35;
// keep track of the spacebar being pressed so we can move the
// helicopter up when pressed and down when not pressed
let spacePressed = false;
// clamp a number between min and max values
function clamp(num, min, max) {
return [Link]( [Link](min, num), max);
}
// return a random integer between min (inclusive) and max (inclusive)
// @see [Link]
function randInt(min, max) {
return [Link]([Link]() * (max - min + 1)) + min;
}
const helicopter = {
x: 200,
y: 100,
width: 100,
height: 60,
dy: 0, // velocity
ddy: 0 // acceleration
};
// just keep track of a tunnel wall current x position, width, start
// and end height. the top and bottom wall are mirrored, so we only
// need to keep track of one of them
let tunnels = [{
x: 0,
width: [Link],
start: 50,
end: 50
},
{
x: [Link],
width: randInt(minTunnelWidth, maxTunnelWidth),
start: 50,
end: randInt(minHeight, maxHeight)
}];
// for the obstacles in the path just need to keep track of the
// position as they are always the same size
let obstacles = [{
x: [Link],
y: [Link] / 2
},
{
x: [Link] * 2,
y: [Link] / 2
}];
// tunnel wall color and rgb value
const wallColor = 'green';
[Link] = wallColor;
[Link](0, 0, 1, 1);
// getImageData returns a data object which is a flat array of every
// pixel of the canvas in the specified rect (x, y, width, height).
// every 4 indices of the array is a single pixel's r,g,b,a values
const wallData = [Link](0, 0, 1, 1);
// destructure the image data array to get the rgb values of the wall
// @see [Link]
Operators/Destructuring_assignment
const [ wallRed, wallGreen, wallBlue ] = [Link];
// game loop
let rAF;
function loop() {
rAF = requestAnimationFrame(loop);
[Link](0,0,[Link],[Link]);
if (spacePressed) {
[Link] = -0.7;
}
else {
[Link] = 0;
}
// update position based on acceleration and velocity
[Link] += [Link] + gravity;
// clamp velocity
[Link] = clamp([Link], -8, 8);
helicopter.y += [Link];
// draw the helicopter
[Link] = 'white';
[Link](helicopter.x, helicopter.y, [Link],
[Link]);
// draw the tunnel walls over the helicopter
[Link] = 'green';
[Link]((tunnel, index) => {
tunnel.x -= moveSpeed;
// if the last tunnel is fully on screen, we need to spawn a new
// tunnel segment off screen
if (
index === [Link] - 1 &&
tunnel.x + [Link] <= [Link]
) {
[Link]({
x: tunnel.x + [Link],
width: randInt(minTunnelWidth, maxTunnelWidth),
start: [Link],
end: randInt(minHeight, maxHeight)
});
}
// top tunnel wall
[Link]();
[Link](tunnel.x, 0);
[Link](tunnel.x, [Link]);
[Link](tunnel.x + [Link], [Link]);
[Link](tunnel.x + [Link], 0);
[Link]();
[Link]();
// bottom tunnel wall
[Link]();
[Link](tunnel.x, [Link]);
[Link](tunnel.x, [Link] + 450);
[Link](tunnel.x + [Link], [Link] + 450);
[Link](tunnel.x + [Link], [Link]);
[Link]();
[Link]();
});
// draw obstacles
[Link]((obstacle, index) => {
obstacle.x -= moveSpeed;
[Link](obstacle.x, obstacle.y, obstacleWidth, obstacleHeight);
// if the last obstacle is fully on screen, we need to spawn a new
// one off screen
if (
index === [Link] - 1 &&
obstacle.x + obstacleWidth <= [Link]
) {
[Link]({
x: [Link] * 2,
y: randInt(maxHeight + 50, [Link] - obstacleHeight - maxHeight - 50)
});
}
});
// remove any tunnel segments or obstacles that are off screen
tunnels = [Link](tunnel => tunnel.x + [Link] > 0);
obstacles = [Link](obstacle => obstacle.x + obstacleWidth > 0);
// pixel perfect collision detection
// get the pixels of the canvas at the helicopter rect and look for
// any pixels that match the wall color. the wall has to be drawn
// above the helicopter in order for this to work
const { data } = [Link](helicopter.x, helicopter.y,
[Link], [Link]);
for (let i = 0; i < [Link]; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// if we match the tunnel wall color we have a collision
if (r === wallRed && g === wallGreen && b === wallBlue) {
// draw a dotted red circle around the helicopter when it
// crashes
[Link] = 'red';
[Link]([5, 15])
[Link] = 4;
[Link]();
[Link](helicopter.x + [Link] / 2, helicopter.y +
[Link] / 2, [Link], 0, 2 * [Link]);
[Link]();
cancelAnimationFrame(rAF);
}
}
}
// listen to keyboard events to move the helicopter
[Link]('keydown', function(e) {
// spacebar
if ([Link] === 'Space') {
spacePressed = true;
}
});
[Link]('keyup', function(e) {
// spacebar
if ([Link] === 'Space') {
spacePressed = false;
}
});
// start the game
rAF = requestAnimationFrame(loop);
</script>
</body>
</html>