Skip to content

🤖 Cannot save fiddle #2336

@mariosandaza-blip

Description

@mariosandaza-blip

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

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions