Geometry Dash Style
by CrystalGlider19610 lines13.0 KB
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Geometry Dash Style</title>
<style>
* { box-sizing: border-box; }
body {
margin: 0;
background: #090b18;
overflow: hidden;
font-family: Arial, sans-serif;
user-select: none;
}
canvas {
display: block;
width: 100vw;
height: 100vh;
}
#ui {
position: fixed;
top: 18px;
left: 50%;
transform: translateX(-50%);
color: white;
font-weight: bold;
text-align: center;
pointer-events: none;
text-shadow: 0 2px 5px #000;
}
#title {
font-size: 26px;
letter-spacing: 3px;
}
#hint {
font-size: 14px;
opacity: .7;
margin-top: 6px;
}
#dead {
display: none;
position: fixed;
inset: 0;
align-items: center;
justify-content: center;
flex-direction: column;
background: rgba(0,0,0,.55);
color: white;
text-align: center;
}
#dead h1 {
font-size: 64px;
margin: 0 0 10px;
color: #ff3d71;
}
#dead p {
font-size: 20px;
}
</style>
</head>
<body>
<canvas id="game"></canvas>
<div id="ui">
<div id="title">GEOMETRY RUN</div>
<div id="hint">SPACE / CLICK TO JUMP</div>
</div>
<div id="dead">
<h1>CRASHED!</h1>
<p>Press SPACE or R to try again</p>
</div>
<script>
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");
let W, H;
function resize() {
W = canvas.width = innerWidth * devicePixelRatio;
H = canvas.height = innerHeight * devicePixelRatio;
canvas.style.width = innerWidth + "px";
canvas.style.height = innerHeight + "px";
}
resize();
addEventListener("resize", resize);
const dpr = () => devicePixelRatio;
let player;
let obstacles;
let particles;
let camera;
let speed;
let gameOver;
let won;
let distance;
const groundHeight = 100;
function reset() {
player = {
x: 180,
y: 0,
size: 42,
vy: 0,
rotation: 0,
grounded: false
};
obstacles = [];
particles = [];
camera = 0;
speed = 8;
gameOver = false;
won = false;
distance = 0;
document.getElementById("dead").style.display = "none";
generateLevel();
}
function generateLevel() {
obstacles = [];
// Ground spikes and platforms
const pattern = [
["spike", 650],
["spike", 850],
["spike", 1050],
["double", 1300],
["spike", 1600],
["block", 1850],
["spike", 2200],
["double", 2450],
["triple", 2800],
["block", 3300],
["spike", 3650],
["double", 3900],
["spike", 4250],
["triple", 4500],
["block", 5000],
["double", 5350],
["spike", 5750],
["triple", 6000],
["block", 6500],
["double", 7000],
["spike", 7500],
["triple", 7800],
["block", 8300],
["double", 8750],
["spike", 9200],
["triple", 9500],
["spike", 10000]
];
for (const [type, x] of pattern) {
if (type === "spike") {
obstacles.push({
type: "spike",
x,
y: 0,
w: 48,
h: 48
});
}
if (type === "double") {
obstacles.push({
type: "spike",
x,
y: 0,
w: 48,
h: 48
});
obstacles.push({
type: "spike",
x: x + 45,
y: 0,
w: 48,
h: 48
});
}
if (type === "triple") {
for (let i = 0; i < 3; i++) {
obstacles.push({
type: "spike",
x: x + i * 45,
y: 0,
w: 48,
h: 48
});
}
}
if (type === "block") {
obstacles.push({
type: "block",
x,
y: 0,
w: 60,
h: 80
});
}
}
}
function jump() {
if (gameOver) {
reset();
return;
}
if (player.grounded) {
player.vy = -17;
player.grounded = false;
for (let i = 0; i < 8; i++) {
particles.push({
x: player.x + player.size / 2,
y: player.y + player.size,
vx: (Math.random() - .5) * 5,
vy: Math.random() * 3,
life: 25
});
}
}
}
addEventListener("keydown", e => {
if (e.code === "Space") {
e.preventDefault();
jump();
}
if (e.key.toLowerCase() === "r") {
reset();
}
});
addEventListener("mousedown", jump);
addEventListener("touchstart", e => {
e.preventDefault();
jump();
}, { passive: false });
function collide(a, b) {
return (
a.x < b.x + b.w &&
a.x + a.size > b.x &&
a.y < b.y + b.h &&
a.y + a.size > b.y
);
}
function die() {
if (gameOver) return;
gameOver = true;
for (let i = 0; i < 35; i++) {
particles.push({
x: player.x + player.size / 2,
y: player.y + player.size / 2,
vx: (Math.random() - .5) * 12,
vy: (Math.random() - .5) * 12,
life: 50
});
}
document.getElementById("dead").style.display = "flex";
}
function update() {
if (gameOver) {
updateParticles();
return;
}
distance += speed;
camera += speed;
// Slight difficulty increase
speed = 8 + Math.min(distance / 3500, 3);
player.vy += .85;
player.y += player.vy;
const groundY = innerHeight - groundHeight;
if (player.y + player.size >= groundY) {
player.y = groundY - player.size;
player.vy = 0;
player.grounded = true;
} else {
player.grounded = false;
}
if (!player.grounded) {
player.rotation += .13;
} else {
player.rotation = Math.round(player.rotation / (Math.PI / 2))
* (Math.PI / 2);
}
for (const o of obstacles) {
const ox = o.x - camera + player.x;
if (o.type === "spike") {
// More accurate triangle collision
const box = {
x: ox + 8,
y: groundY - o.h + 10,
w: o.w - 16,
h: o.h - 10
};
if (collide(player, box)) {
die();
}
}
if (o.type === "block") {
const box = {
x: ox,
y: groundY - o.h,
w: o.w,
h: o.h
};
if (collide(player, box)) {
// Allow landing on top
if (
player.vy >= 0 &&
player.y + player.size - player.vy <= box.y + 10
) {
player.y = box.y - player.size;
player.vy = 0;
player.grounded = true;
} else {
die();
}
}
}
}
if (distance > 10500) {
won = true;
gameOver = true;
document.getElementById("dead").innerHTML =
"<h1 style='color:#5dffce'>LEVEL COMPLETE!</h1>" +
"<p>Press SPACE to play again</p>";
document.getElementById("dead").style.display = "flex";
}
updateParticles();
}
function updateParticles() {
for (const p of particles) {
p.x += p.vx;
p.y += p.vy;
p.vy += .25;
p.life--;
}
particles = particles.filter(p => p.life > 0);
}
function drawBackground() {
// Gradient
const gradient = ctx.createLinearGradient(0, 0, 0, H);
gradient.addColorStop(0, "#151a46");
gradient.addColorStop(1, "#080914");
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, W, H);
// Grid
ctx.strokeStyle = "rgba(100,150,255,.08)";
ctx.lineWidth = 2 * dpr();
const grid = 80 * dpr();
for (let x = -camera % grid; x < W; x += grid) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, H);
ctx.stroke();
}
for (let y = 0; y < H; y += grid) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(W, y);
ctx.stroke();
}
}
function drawGround() {
const y = H - groundHeight * dpr();
ctx.fillStyle = "#171b35";
ctx.fillRect(0, y, W, groundHeight * dpr());
ctx.fillStyle = "#36e8ff";
ctx.fillRect(0, y, W, 5 * dpr());
// Ground decoration
ctx.strokeStyle = "rgba(54,232,255,.18)";
ctx.lineWidth = 2 * dpr();
const spacing = 55 * dpr();
for (let x = -camera % spacing; x < W; x += spacing) {
ctx.beginPath();
ctx.moveTo(x, y + 5 * dpr());
ctx.lineTo(x + 25 * dpr(), y + 35 * dpr());
ctx.stroke();
}
}
function drawObstacle(o) {
const x = (o.x - camera + player.x) * dpr();
const groundY = H - groundHeight * dpr();
if (x < -100 || x > W + 100) return;
if (o.type === "spike") {
ctx.beginPath();
ctx.moveTo(x, groundY);
ctx.lineTo(x + o.w * dpr() / 2, groundY - o.h * dpr());
ctx.lineTo(x + o.w * dpr(), groundY);
ctx.closePath();
ctx.fillStyle = "#ff3d71";
ctx.fill();
ctx.strokeStyle = "#fff";
ctx.lineWidth = 2 * dpr();
ctx.stroke();
}
if (o.type === "block") {
ctx.fillStyle = "#7b4dff";
ctx.fillRect(
x,
groundY - o.h * dpr(),
o.w * dpr(),
o.h * dpr()
);
ctx.strokeStyle = "#d5c9ff";
ctx.lineWidth = 3 * dpr();
ctx.strokeRect(
x,
groundY - o.h * dpr(),
o.w * dpr(),
o.h * dpr()
);
// Inner pattern
ctx.strokeStyle = "rgba(255,255,255,.2)";
ctx.lineWidth = 2 * dpr();
for (let i = 0; i < o.w; i += 20) {
ctx.beginPath();
ctx.moveTo(x + i * dpr(), groundY);
ctx.lineTo(x + (i + 30) * dpr(),
groundY - o.h * dpr());
ctx.stroke();
}
}
}
function drawPlayer() {
const x = player.x * dpr();
const y = player.y * dpr();
const s = player.size * dpr();
ctx.save();
ctx.translate(x + s / 2, y + s / 2);
ctx.rotate(player.rotation);
// Glow
ctx.shadowBlur = 20 * dpr();
ctx.shadowColor = "#fff43d";
ctx.fillStyle = "#ffe83d";
ctx.fillRect(-s / 2, -s / 2, s, s);
ctx.shadowBlur = 0;
// Face
ctx.fillStyle = "#11152a";
ctx.fillRect(
-s * .25,
-s * .18,
s * .13,
s * .13
);
ctx.fillRect(
s * .12,
-s * .18,
s * .13,
s * .13
);
ctx.fillRect(
-s * .18,
s * .13,
s * .36,
s * .08
);
ctx.strokeStyle = "white";
ctx.lineWidth = 3 * dpr();
ctx.strokeRect(-s / 2, -s / 2, s, s);
ctx.restore();
}
function drawParticles() {
for (const p of particles) {
ctx.globalAlpha = p.life / 50;
ctx.fillStyle = "#ffe83d";
ctx.fillRect(
p.x * dpr(),
p.y * dpr(),
7 * dpr(),
7 * dpr()
);
}
ctx.globalAlpha = 1;
}
function drawProgress() {
const progress = Math.min(distance / 10500, 1);
ctx.fillStyle = "rgba(255,255,255,.15)";
ctx.fillRect(
20 * dpr(),
80 * dpr(),
(innerWidth - 40) * dpr(),
7 * dpr()
);
ctx.fillStyle = "#36e8ff";
ctx.fillRect(
20 * dpr(),
80 * dpr(),
(innerWidth - 40) * dpr() * progress,
7 * dpr()
);
ctx.fillStyle = "white";
ctx.font = `${14 * dpr()}px Arial`;
ctx.textAlign = "right";
ctx.fillText(
Math.floor(progress * 100) + "%",
(innerWidth - 20) * dpr(),
75 * dpr()
);
}
function draw() {
ctx.clearRect(0, 0, W, H);
drawBackground();
drawGround();
for (const o of obstacles) {
drawObstacle(o);
}
drawPlayer();
drawParticles();
drawProgress();
}
function loop() {
update();
draw();
requestAnimationFrame(loop);
}
reset();
loop();
</script>
</body>
</html>
```
Game Source: Geometry Dash Style
Creator: CrystalGlider19
Libraries: none
Complexity: complex (610 lines, 13.0 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: geometry-dash-style-crystalglider19" to link back to the original. Then publish at arcadelab.ai/publish.