platformer/script.js
Glitch (glitch-hello-website) 32fd1dde91 🔦🎤 Checkpoint
./script.js:9517054/301
2022-03-06 01:31:07 +00:00

231 lines
5.5 KiB
JavaScript

import game from "/data.js"; // import the game data
// import elements from html
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
// resize the canvas to full screen
function resize() {
const w = window.innerWidth;
const h = window.innerHeight;
canvas.width = w;
canvas.height = h;
ctx.width = w;
ctx.height = h;
game.size = [w, h];
}
// reset the player to the last checkpoint (or start)
function die() {
game.player.x = game.player.savex;
game.player.y = game.player.savey;
game.player.velx = 0;
game.player.vely = 0;
}
function draw() {
if (!game.cache.dirty) return;
requestAnimationFrame(draw); // to continuously animate
const offx = game.camera[0] - game.size[0] / 2;
const offy = game.camera[1] - game.size[1] / 2;
const c = game.color;
const point = (x, y) => [x - offx, y - offy];
const color = (which) => (ctx.fillStyle = game.color[which]);
const rect = (x, y, w, h) => ctx.fillRect(...point(x, y), w, h);
// draw background
color("background");
ctx.fillRect(0, 0, game.size[0], game.size[1]);
color("dots");
for (let i = 0; i < 30; i++) {
for (let j = 0; j < 40; j++) {
const spacing = 60;
const depth = 0.5;
ctx.beginPath();
ctx.arc(
i * spacing - (offx % (spacing / depth)) * depth,
j * spacing - (offy % (spacing / depth)) * depth,
5,
0,
2 * Math.PI
);
ctx.fill();
}
}
// draw checkpoint animation (if there is one)
if (game.anim[2] < 1) {
color("shadow");
ctx.globalAlpha = 1 - game.anim[2];
ctx.beginPath();
ctx.arc(
...point(game.anim[0], game.anim[1]),
game.anim[2] * 100 + 25,
0,
2 * Math.PI
);
ctx.fill();
ctx.globalAlpha = 1;
}
// draw platforms
for (let part of game.parts) {
color("shadow");
for (let i = 6; i > 0; i--) {
rect(part[0] + i, part[1] + i, part[2], part[3]);
}
color(part[4] || "platforms");
rect(part[0], part[1], part[2], part[3]);
}
// draw player
color("player");
rect(game.player.x, game.player.y, game.player.size, game.player.size);
game.cache.dirty = true;
}
function update() {
const p = game.player;
const c = game.camera;
// handle input
const i = game.input;
const speed = 2;
if (i.up && p.canJump) p.vely = -14;
if (i.down) p.vely += 0.8;
if (i.left) p.velx -= speed;
if (i.right) p.velx += speed;
// update x position
for (let i = 0; i < Math.abs(p.velx) - 1; i++) {
p.x += p.velx < 0 ? -1 : 1;
const c = collision();
if (c) {
p.x -= p.velx < 0 ? -1 : 1;
p.velx = 0;
}
}
// reset jump if they're falling or already jumping (there's a small grace period though)
if (Math.abs(p.vely) > 3) p.canJump = false;
// update y position
const collided = move("y", p.vely, p.vely < 0 ? -1 : 1);
if (collided) {
if (p.vely >= 0) {
// if they fell onto a platform then let them jump
p.canJump = true;
// if they hit a checkpoint
if (collided[4] === "checkpoint" || collided[4] === "final") {
// unset the other checkpoints
for (let part of game.parts.filter((i) => i[4] === "active")) {
part[4] = "checkpoint";
}
const x = collided[0] + collided[2] / 2;
const y = collided[1] + collided[3] / 2;
// play the checkpoint animation
game.anim = [x, y, 0];
game.player.savex = x - game.player.size / 2;
game.player.savey = y - collided[3] / 2 - game.player.size;
// they won!
if (collided[4] === "final") {
alert("ayo you win");
// reset the inputs, `alert()` does weird things
input.up = false;
input.down = false;
input.left = false;
input.right = false;
}
// don't spam animation; change platform color
collided[4] = collided[4] === "final" ? "win" : "active";
}
}
p.vely = 0;
}
// they fell out of the world
if (p.y > 1000) die();
// update velocity
p.velx *= 0.8;
p.vely = Math.min(30, p.vely + 0.8);
// update camera
const camx = (c[0] * 9 + p.x) / 10;
const camy = (c[1] * 9 + p.y) / 10;
if (c[0] !== camx || c[1] !== camy) game.cache.dirty = true;
c[0] = camx;
c[1] = camy;
if (game.anim[2] < 1) game.anim[2] += 0.04;
// move, and return the platform the player collided with if any
function move(key, amt, speed) {
for (let i = 0; i < Math.abs(amt) - 1; i++) {
p[key] += speed;
const c = collision();
if (c) {
p[key] -= speed;
return c;
}
}
return null;
}
// check if there was a collision
function collision() {
const s = game.player.size;
for (let part of game.parts) {
const inside =
p.x + s > part[0] &&
p.y + s > part[1] &&
p.x < part[0] + part[2] &&
p.y < part[1] + part[3];
if (inside) return part;
}
return false;
}
}
// handle input
function input(e) {
const i = game.input;
const down = e.type === "keydown";
switch (e.code) {
case "ArrowUp":
case "KeyW":
return (i.up = down);
case "ArrowDown":
case "KeyS":
return (i.down = down);
case "ArrowLeft":
case "KeyA":
return (i.left = down);
case "ArrowRight":
case "KeyD":
return (i.right = down);
case "KeyR":
return die();
}
}
// run the game!
resize();
draw();
setInterval(update, 1000 / 60);
window.addEventListener("resize", resize);
window.addEventListener("keydown", input);
window.addEventListener("keyup", input);