-
Notifications
You must be signed in to change notification settings - Fork 122
Open
Description
Error code
ERRW:0.8:TTH0.8:CD0.55:AS
Were you logged in?
Yes
Your username (if logged in)
Huevos_es
Your HTML
<canvas id="game" width="900" height="550"></canvas>
<style>
body {
background: #0d0d0d;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
font-family: Arial, sans-serif;
}
canvas {
background: #1a1a1a;
border: 4px solid #444;
border-radius: 12px;
box-shadow: 0 0 25px #000;
cursor: crosshair;
}
</style>
<script>
window.onload = function () {
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");
const SCREEN_W = canvas.width;
const SCREEN_H = canvas.height;
// 🌍 MUNDO GRANDE
const WORLD_W = 3000;
const WORLD_H = 3000;
// 🎥 CÁMARA
let cameraX = 0;
let cameraY = 0;
// ⏳ TIEMPO
let timeLeft = 60;
let lastTime = 0;
let gameOver = false;
let win = false;
// 🎮 INPUT
const keys = {};
window.addEventListener("keydown", e => keys[e.key] = true);
window.addEventListener("keyup", e => keys[e.key] = false);
let mouseX = 0;
let mouseY = 0;
canvas.addEventListener("mousemove", e => {
mouseX = e.offsetX;
mouseY = e.offsetY;
});
// 🔫 SISTEMA DE DISPARO
let bullets = [];
let canShoot = true;
const SHOOT_DELAY = 200; // ms
canvas.addEventListener("mousedown", () => {
if (!canShoot) return;
shoot();
canShoot = false;
setTimeout(() => canShoot = true, SHOOT_DELAY);
});
// 🧱 PAREDES
const walls = [
{ x: 400, y: 400, w: 600, h: 40 },
{ x: 400, y: 900, w: 40, h: 600 },
{ x: 1200, y: 400, w: 40, h: 600 },
{ x: 400, y: 1400, w: 600, h: 40 },
{ x: 1500, y: 800, w: 300, h: 40 },
{ x: 1500, y: 800, w: 40, h: 300 },
{ x: 1760, y: 800, w: 40, h: 300 },
{ x: 2200, y: 1200, w: 500, h: 40 },
{ x: 2200, y: 1200, w: 40, h: 400 },
{ x: 2660, y: 1200, w: 40, h: 400 }
];
// 🌲 DECORACIÓN DEL MAPA
const trees = [];
const rocks = [];
const houses = [];
for (let i = 0; i < 80; i++) {
trees.push({ x: Math.random() * WORLD_W, y: Math.random() * WORLD_H, r: 25 });
}
for (let i = 0; i < 40; i++) {
rocks.push({ x: Math.random() * WORLD_W, y: Math.random() * WORLD_H, r: 18 });
}
for (let i = 0; i < 10; i++) {
houses.push({ x: Math.random() * WORLD_W, y: Math.random() * WORLD_H, w: 120, h: 120 });
}
// -------------------------
// ENTIDADES
// -------------------------
class Entity {
constructor(x, y, radius, color, speed) {
this.x = x;
this.y = y;
this.radius = radius;
this.color = color;
this.speed = speed;
}
draw() {
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x - cameraX, this.y - cameraY, this.radius, 0, Math.PI * 2);
ctx.fill();
}
}
class Player extends Entity {
constructor(x, y) {
super(x, y, 16, "#4db8ff", 250);
}
update(dt) {
let dx = 0, dy = 0;
if (keys["w"]) dy -= 1;
if (keys["s"]) dy += 1;
if (keys["a"]) dx -= 1;
if (keys["d"]) dx += 1;
const len = Math.hypot(dx, dy) || 1;
dx /= len;
dy /= len;
let newX = this.x + dx * this.speed * dt;
let newY = this.y + dy * this.speed * dt;
if (!collidesWithWalls(newX, this.y, this.radius)) this.x = newX;
if (!collidesWithWalls(this.x, newY, this.radius)) this.y = newY;
this.x = Math.max(this.radius, Math.min(WORLD_W - this.radius, this.x));
this.y = Math.max(this.radius, Math.min(WORLD_H - this.radius, this.y));
}
}
class Zombie extends Entity {
constructor(x, y) {
super(x, y, 18, "#7aff7a", 60);
this.hp = 3;
}
update(dt, target) {
const dx = target.x - this.x;
const dy = target.y - this.y;
const dist = Math.hypot(dx, dy) || 1;
let newX = this.x + (dx / dist) * this.speed * dt;
let newY = this.y + (dy / dist) * this.speed * dt;
if (!collidesWithWalls(newX, this.y, this.radius)) this.x = newX;
if (!collidesWithWalls(this.x, newY, this.radius)) this.y = newY;
}
}
const player = new Player(WORLD_W / 2, WORLD_H / 2);
const zombies = [];
function spawnZombies(n) {
for (let i = 0; i < n; i++) {
zombies.push(new Zombie(Math.random() * WORLD_W, Math.random() * WORLD_H));
}
}
spawnZombies(25);
// -------------------------
// COLISIONES
// -------------------------
function collidesWithWalls(x, y, r) {
return walls.some(w =>
x + r > w.x &&
x - r < w.x + w.w &&
y + r > w.y &&
y - r < w.y + w.h
);
}
function checkCollision(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.hypot(dx, dy) < a.radius + b.radius;
}
// -------------------------
// DISPARAR
// -------------------------
function shoot() {
const angle = Math.atan2(mouseY - SCREEN_H / 2, mouseX - SCREEN_W / 2);
bullets.push({
x: player.x,
y: player.y,
dx: Math.cos(angle) * 600,
dy: Math.sin(angle) * 600,
radius: 4
});
}
// -------------------------
// CÁMARA
// -------------------------
function updateCamera() {
cameraX = player.x - SCREEN_W / 2;
cameraY = player.y - SCREEN_H / 2;
cameraX = Math.max(0, Math.min(WORLD_W - SCREEN_W, cameraX));
cameraY = Math.max(0, Math.min(WORLD_H - SCREEN_H, cameraY));
}
// -------------------------
// BUCLE PRINCIPAL
// -------------------------
function loop(timestamp) {
if (!lastTime) lastTime = timestamp;
const dt = (timestamp - lastTime) / 1000;
lastTime = timestamp;
if (!gameOver) {
timeLeft -= dt;
if (timeLeft <= 0) {
timeLeft = 0;
gameOver = true;
win = true;
}
update(dt);
}
draw();
requestAnimationFrame(loop);
}
function update(dt) {
player.update(dt);
zombies.forEach(z => z.update(dt, player));
bullets.forEach(b => {
b.x += b.dx * dt;
b.y += b.dy * dt;
});
bullets = bullets.filter(b =>
b.x > 0 && b.x < WORLD_W && b.y > 0 && b.y < WORLD_H
);
bullets.forEach(b => {
zombies.forEach(z => {
const dx = z.x - b.x;
const dy = z.y - b.y;
if (Math.hypot(dx, dy) < z.radius + b.radius) {
z.hp--;
b.dead = true;
}
});
});
bullets = bullets.filter(b => !b.dead);
for (let i = zombies.length - 1; i >= 0; i--) {
if (zombies[i].hp <= 0) zombies.splice(i, 1);
}
updateCamera();
}
// -------------------------
// DIBUJO
// -------------------------
function draw() {
ctx.clearRect(0, 0, SCREEN_W, SCREEN_H);
// Suelo cuadriculado
for (let x = 0; x < WORLD_W; x += 80) {
for (let y = 0; y < WORLD_H; y += 80) {
ctx.fillStyle = (x / 80 + y / 80) % 2 === 0 ? "#2a2a2a" : "#242424";
ctx.fillRect(x - cameraX, y - cameraY, 80, 80);
}
}
// Paredes
ctx.fillStyle = "#555";
walls.forEach(w => {
ctx.fillRect(w.x - cameraX, w.y - cameraY, w.w, w.h);
});
// Árboles
trees.forEach(t => {
ctx.fillStyle = "#0f0";
ctx.beginPath();
ctx.arc(t.x - cameraX, t.y - cameraY, t.r, 0, Math.PI * 2);
ctx.fill();
});
// Rocas
rocks.forEach(r => {
ctx.fillStyle = "#888";
ctx.beginPath();
ctx.arc(r.x - cameraX, r.y - cameraY, r.r, 0, Math.PI * 2);
ctx.fill();
});
// Casas
houses.forEach(h => {
ctx.fillStyle = "#663300";
ctx.fillRect(h.x - cameraX, h.y - cameraY, h.w, h.h);
ctx.fillStyle = "#442200";
ctx.fillRect(h.x - cameraX, h.y - cameraY, h.w, 20);
});
// Jugador y zombis
player.draw();
zombies.forEach(z => z.draw());
// Balas
ctx.fillStyle = "#ff0";
bullets.forEach(b => {
ctx.beginPath();
ctx.arc(b.x - cameraX, b.y - cameraY, b.radius, 0, Math.PI * 2);
ctx.fill();
});
// Mira del arma
ctx.strokeStyle = "#fff";
ctx.beginPath();
ctx.moveTo(SCREEN_W / 2, SCREEN_H / 2);
ctx.lineTo(mouseX, mouseY);
ctx.stroke();
// UI
ctx.fillStyle = "#fff";
ctx.font = "20px Arial";
ctx.fillText(`Tiempo: ${timeLeft.toFixed(1)}s`, 10, 25);
if (gameOver) {
ctx.fillStyle = "rgba(0,0,0,0.7)";
ctx.fillRect(0, 0, SCREEN_W, SCREEN_H);
ctx.fillStyle = "#fff";
ctx.font = "36px Arial";
ctx.textAlign = "center";
ctx.fillText(win ? "¡Has sobrevivido!" : "Has sido infectado", SCREEN_W / 2, SCREEN_H / 2);
}
}
requestAnimationFrame(loop);
}; // FIN window.onload
</script>Your JavaScript
'-'Your CSS
'-'Metadata
Metadata
Assignees
Labels
No labels