Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>8K (7K) Roguelike (ignore 800mb browser)</title>
- <style>
- html, body {
- margin: 0;
- padding: 0;
- height: 100%;
- width: 100%;
- overflow: hidden;
- }
- body {
- background: #000;
- }
- canvas {
- display: block;
- position: fixed;
- top: 0;
- left: 0;
- width: 100vw;
- height: 100vh;
- }
- #hud {
- position: fixed;
- top: 8px;
- left: 8px;
- color: #fff;
- font: 20px monospace;
- z-index: 10;
- }
- </style>
- </head>
- <body>
- <div id="hud"></div>
- <canvas id="c"></canvas>
- <script>
- const W = 48, H = 32, TS = 24, GOLD_COUNT = 10, ENEMY_COUNT = 5;
- const canvas = /** @type HTMLCanvasElement */ document.getElementById("c");
- const ctx = canvas.getContext("2d");
- const hud = document.getElementById("hud");
- function resize() {
- canvas.width = W * TS;
- canvas.height = H * TS;
- }
- resize();
- let map = [];
- for (let y = 0; y < H; y++) {
- map[y] = [];
- for (let x = 0; x < W; x++)
- map[y][x] = Math.random() < 0.45 ? 1 : 0;
- }
- for (let k = 0; k < 4; k++) {
- let m2 = [];
- for (let y = 0; y < H; y++) {
- m2[y] = [];
- for (let x = 0; x < W; x++) {
- let cnt = 0;
- for (let dy = -1; dy <= 1; dy++)
- for (let dx = -1; dx <= 1; dx++)
- if (map[y + dy]?.[x + dx]) cnt++;
- m2[y][x] = cnt >= 5 ? 1 : 0;
- }
- }
- map = m2;
- }
- function randomFloor(exclude = []) {
- let x, y;
- do {
- x = 1 + Math.floor(Math.random() * (W - 2));
- y = 1 + Math.floor(Math.random() * (H - 2));
- } while (map[y][x] !== 0 || exclude.some(e => e.x === x && e.y === y));
- return { x, y };
- }
- let { x: px, y: py } = randomFloor();
- let hp = 10;
- let exit;
- do {
- exit = randomFloor([{ x: px, y: py }]);
- } while (Math.abs(exit.x - px) + Math.abs(exit.y - py) < W / 2);
- let golds = [];
- for (let i = 0; i < GOLD_COUNT; i++) {
- golds.push(randomFloor([{ x: px, y: py }, exit, ...golds]));
- }
- let enemies = [];
- for (let i = 0; i < ENEMY_COUNT; i++) {
- enemies.push(randomFloor([{ x: px, y: py }, exit, ...golds, ...enemies]));
- }
- const AudioContext = window.AudioContext;
- const audioCtx = new AudioContext();
- let drumGain, drumInterval, baseTempo = 1200, fastTempo = 300;
- let isFast = false;
- let drumHigh = false;
- function startSoundtrack() {
- drumGain = audioCtx.createGain();
- drumGain.gain.value = 1;
- drumGain.connect(audioCtx.destination);
- scheduleDrum(baseTempo);
- }
- function playDrum() {
- drumHigh = !drumHigh;
- let osc = audioCtx.createOscillator();
- osc.type = "triangle";
- let startFreq = drumHigh ? 260 : 180;
- osc.frequency.setValueAtTime(startFreq, audioCtx.currentTime);
- osc.frequency.exponentialRampToValueAtTime(60, audioCtx.currentTime + 0.3);
- let gain = audioCtx.createGain();
- gain.gain.setValueAtTime(1, audioCtx.currentTime);
- gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + 0.3);
- osc.connect(gain).connect(audioCtx.destination);
- osc.start();
- osc.stop(audioCtx.currentTime + 0.3);
- }
- function scheduleDrum(tempo) {
- if (drumInterval) clearInterval(drumInterval);
- drumInterval = setInterval(playDrum, tempo);
- }
- window.addEventListener("keydown", function once() {
- if (audioCtx.state === "suspended") audioCtx.resume();
- startSoundtrack();
- window.removeEventListener("keydown", once);
- });
- function updateSoundtrack() {
- let adjacent = enemies.some(en => isAdjacent({ x: px, y: py }, en));
- if (adjacent && !isFast) {
- isFast = true;
- scheduleDrum(fastTempo);
- } else if (!adjacent && isFast) {
- isFast = false;
- scheduleDrum(baseTempo);
- }
- }
- function draw() {
- ctx.clearRect(0, 0, canvas.width, canvas.height);
- for (let y = 0; y < H; y++)
- for (let x = 0; x < W; x++) {
- ctx.fillStyle = map[y][x] ? "#444" : "#111";
- ctx.fillRect(x * TS, y * TS, TS, TS);
- }
- for (const g of golds) {
- ctx.fillStyle = "#ff0";
- ctx.fillRect(g.x * TS + 6, g.y * TS + 6, TS - 12, TS - 12);
- }
- ctx.fillStyle = "#0f0";
- ctx.fillRect(exit.x * TS + 6, exit.y * TS + 6, TS - 12, TS - 12);
- for (const e of enemies) {
- ctx.fillStyle = "#f00";
- ctx.fillRect(e.x * TS + 6, e.y * TS + 6, TS - 12, TS - 12);
- }
- ctx.fillStyle = "#fff";
- ctx.fillRect(px * TS + 4, py * TS + 4, TS - 8, TS - 8);
- hud.textContent = `HP: ${hp} Gold: ${GOLD_COUNT - golds.length}`;
- }
- draw();
- function moveEnemies() {
- for (const e of enemies) {
- let dx = px - e.x, dy = py - e.y;
- let nx = e.x, ny = e.y;
- if (Math.abs(dx) > Math.abs(dy)) nx += Math.sign(dx);
- else if (dy !== 0) ny += Math.sign(dy);
- if (map[ny]?.[nx] === 0 && !enemies.some(en => en.x === nx && en.y === ny) && !(nx === px && ny === py))
- e.x = nx, e.y = ny;
- }
- }
- function isAdjacent(a, b) {
- return (Math.abs(a.x - b.x) + Math.abs(a.y - b.y)) === 1;
- }
- window.addEventListener("keydown", e => {
- if (hp <= 0) return;
- let dx = 0, dy = 0;
- if (e.key === "ArrowUp") dy = -1;
- if (e.key === "ArrowDown") dy = 1;
- if (e.key === "ArrowLeft") dx = -1;
- if (e.key === "ArrowRight") dx = 1;
- if (dx === 0 && dy === 0) return;
- let nx = px + dx, ny = py + dy;
- if (map[ny]?.[nx] === 0) {
- let idx = enemies.findIndex(en => en.x === nx && en.y === ny);
- if (idx !== -1) {
- enemies.splice(idx, 1);
- } else {
- px = nx;
- py = ny;
- golds = golds.filter(g => !(g.x === px && g.y === py));
- if (px === exit.x && py === exit.y && golds.length === 0) {
- hud.textContent = "You win!";
- return;
- }
- }
- let dmg = enemies.filter(en => isAdjacent({ x: px, y: py }, en)).length;
- if (dmg > 0) hp -= dmg;
- if (hp <= 0) {
- hud.textContent = "Game Over";
- draw();
- return;
- }
- moveEnemies();
- draw();
- updateSoundtrack();
- }
- });
- </script>
- </body>
- </html>
Advertisement
Add Comment
Please, Sign In to add comment