Pixel Collector
by MegaNinja77218 lines5.7 KB
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Pixel Collector</title>
<style>
body {
background: #15152b;
color: white;
font-family: monospace;
text-align: center;
margin: 0;
padding: 20px 10px;
}
h1 { color: #ffe66d; }
canvas {
width: min(100%, 480px);
image-rendering: pixelated;
border: 4px solid #7777ff;
background: #263b50;
}
button {
background: #ffe66d;
color: #20203b;
border: 0;
padding: 12px 20px;
margin: 8px;
font: bold 16px monospace;
cursor: pointer;
}
p { color: #c9d0ff; }
</style>
</head>
<body>
<h1>★ PIXEL COLLECTOR ★</h1>
<p>Collect the gold coins! Avoid the red monsters!</p>
<p>Score: <span id="score">0</span>
| Time: <span id="time">30</span></p>
<canvas id="game" width="320" height="320"></canvas>
<div>
<button onclick="startGame()">START / RESTART</button>
</div>
<p>Move with WASD or arrow keys.</p>
<script>
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");
ctx.imageSmoothingEnabled = false;
let player, coin, enemies, score, timeLeft;
let running = false;
let keys = {};
let lastTime = 0;
let timer = 0;
let animation;
function randomPos() {
return {
x: Math.floor(Math.random() * 19) * 16 + 8,
y: Math.floor(Math.random() * 19) * 16 + 8
};
}
function startGame() {
cancelAnimationFrame(animation);
player = { x: 160, y: 160, size: 12, speed: 2.5 };
coin = randomPos();
enemies = [
{ x: 40, y: 40, dx: 1.3, dy: 1.1 },
{ x: 280, y: 260, dx: -1.1, dy: 1.4 }
];
score = 0;
timeLeft = 30;
timer = 0;
lastTime = 0;
running = true;
document.getElementById("score").textContent = score;
document.getElementById("time").textContent = timeLeft;
animation = requestAnimationFrame(loop);
}
document.addEventListener("keydown", e => {
keys[e.key.toLowerCase()] = true;
if (["arrowup","arrowdown","arrowleft","arrowright"," "].includes(e.key.toLowerCase()))
e.preventDefault();
});
document.addEventListener("keyup", e => keys[e.key.toLowerCase()] = false);
function rectHit(a, b, sizeA, sizeB) {
return Math.abs(a.x - b.x) < (sizeA + sizeB) / 2 &&
Math.abs(a.y - b.y) < (sizeA + sizeB) / 2;
}
function drawPixel(x, y, color, size = 12) {
ctx.fillStyle = color;
ctx.fillRect(Math.round(x - size/2), Math.round(y - size/2), size, size);
}
function draw() {
ctx.fillStyle = "#263b50";
ctx.fillRect(0, 0, 320, 320);
// Pixel grass pattern
for (let y = 8; y < 320; y += 32) {
for (let x = 8; x < 320; x += 32) {
ctx.fillStyle = "#2c4356";
ctx.fillRect(x, y, 3, 3);
}
}
// Coins
drawPixel(coin.x, coin.y, "#ffca28", 12);
drawPixel(coin.x, coin.y, "#fff18a", 5);
// Monsters
enemies.forEach(e => {
drawPixel(e.x, e.y, "#ff496c", 16);
drawPixel(e.x - 4, e.y - 2, "white", 4);
drawPixel(e.x + 4, e.y - 2, "white", 4);
drawPixel(e.x - 4, e.y - 2, "#222244", 2);
drawPixel(e.x + 4, e.y - 2, "#222244", 2);
});
// Player
drawPixel(player.x, player.y, "#69e8ff", 14);
drawPixel(player.x - 3, player.y - 2, "white", 3);
drawPixel(player.x + 3, player.y - 2, "white", 3);
drawPixel(player.x - 3, player.y - 2, "#20203b", 1);
drawPixel(player.x + 3, player.y - 2, "#20203b", 1);
}
function endGame(message) {
running = false;
draw();
ctx.fillStyle = "rgba(10,10,30,0.85)";
ctx.fillRect(20, 105, 280, 105);
ctx.textAlign = "center";
ctx.fillStyle = "#ffe66d";
ctx.font = "bold 22px monospace";
ctx.fillText(message, 160, 145);
ctx.fillStyle = "white";
ctx.font = "14px monospace";
ctx.fillText("Final score: " + score, 160, 175);
ctx.fillText("Press START to play again", 160, 195);
}
function loop(timestamp) {
if (!running) return;
if (!lastTime) lastTime = timestamp;
const dt = Math.min((timestamp - lastTime) / 16.67, 2);
lastTime = timestamp;
timer += timestamp ? dt * 16.67 : 0;
if (timer >= 1000) {
const seconds = Math.floor(timer / 1000);
timeLeft -= seconds;
timer -= seconds * 1000;
document.getElementById("time").textContent = Math.max(0, timeLeft);
}
if (keys["arrowleft"] || keys["a"]) player.x -= player.speed * dt;
if (keys["arrowright"] || keys["d"]) player.x += player.speed * dt;
if (keys["arrowup"] || keys["w"]) player.y -= player.speed * dt;
if (keys["arrowdown"] || keys["s"]) player.y += player.speed * dt;
player.x = Math.max(8, Math.min(312, player.x));
player.y = Math.max(8, Math.min(312, player.y));
if (rectHit(player, coin, 14, 12)) {
score += 1;
document.getElementById("score").textContent = score;
coin = randomPos();
}
for (const e of enemies) {
e.x += e.dx * dt;
e.y += e.dy * dt;
if (e.x < 8 || e.x > 312) e.dx *= -1;
if (e.y < 8 || e.y > 312) e.dy *= -1;
if (rectHit(player, e, 12, 14)) {
draw();
endGame("OUCH! GAME OVER");
return;
}
}
draw();
if (timeLeft <= 0) {
endGame("TIME'S UP!");
return;
}
animation = requestAnimationFrame(loop);
}
// Draw a welcome screen
ctx.fillStyle = "#263b50";
ctx.fillRect(0, 0, 320, 320);
ctx.fillStyle = "#69e8ff";
ctx.fillRect(145, 140, 30, 30);
ctx.fillStyle = "#ffe66d";
ctx.fillRect(80, 90, 14, 14);
ctx.fillStyle = "#ff496c";
ctx.fillRect(230, 210, 18, 18);
ctx.fillStyle = "white";
ctx.textAlign = "center";
ctx.font = "bold 20px monospace";
ctx.fillText("READY PLAYER 1", 160, 55);
ctx.font = "13px monospace";
ctx.fillText("Press START to begin!", 160, 260);
</script>
</body>
</html>
Game Source: Pixel Collector
Creator: MegaNinja77
Libraries: none
Complexity: complex (218 lines, 5.7 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: pixel-collector-meganinja77" to link back to the original. Then publish at arcadelab.ai/publish.