CreaPersonajes — explicación parte por parte (detallada)

 

CreaPersonajes — explicación parte por parte (detallada)

Genial — buen punto de partida. Abajo te explico cada bloque del código que enviaste, señalo errores comunes y te doy una versión corregida y mejorada para que la puedas usar de base. Luego podemos añadir las funcionalidades que quieras (movimiento, animaciones, colisiones, selección de personajes, etc.).


1) Estructura HTML básica

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body onload="inicializa()">
  <canvas id="canvas" width="500" height="300" style="border:2px solid #000000"></canvas>
  <script> ... </script>
</body>
</html>
  • <!DOCTYPE html>: indica HTML5.

  • <meta charset="UTF-8"> y <meta name="viewport"...>: hacen que los caracteres y el escalado en móviles funcionen correctamente.

  • <canvas id="canvas" width="500" height="300">: crea el lienzo donde se va a dibujar. Importante: los atributos width/height (HTML) definen el tamaño en pixeles del contexto de dibujo; el style solo afecta su visualización en la página (CSS). Si cambias las propiedades del canvas por CSS sin ajustar los atributos, la escala de dibujo puede quedar rara.

  • body onload="inicializa()": llama a la función inicializa() cuando la página termina de cargar.


2) Variables globales y consola

var canvas;
var ctx;
var FPS = 50;
console.log("FPS",FPS);
console.log("hola");
  • canvas y ctx (contexto 2D) se declaran globales para ser accesibles desde cualquier función.

  • FPS = 50 pretende indicar fotogramas por segundo.

  • console.log son útiles para depurar, pero si los dejas en el bucle de dibujo van a spamear la consola y ralentizar un poco. Mejor eliminarlos o usarlos sólo en desarrollo.


3) Constructor personaje

var personaje = function (x, y) {
  this.x = x;
  this.y = y;

  this.dibuja = function () {
    ctx.fillStyle = "#fff000";
    ctx.fillRect(this.x, this.y, 50, 50);
  };
};
  • Es una función constructora clásica (pre-ES6). Cuando haces new personaje(10,50) crea un objeto con las propiedades x, y y el método dibuja.

  • dibuja() usa ctx.fillRect(x, y, ancho, alto) para pintar un rectángulo de 50x50 con color #fff000.

  • Observación: dibuja() depende de la variable global ctx. Es funcional, pero es más robusto pasar ctx como parámetro o usar clases ES6.


4) Inicialización y el bug del setInterval

function inicializa() {
  canvas = document.getElementById("canvas");
  ctx = canvas.getContext("2d");

  setInterval(function () {
    principal();
  }, 1000) / FPS;
}
  • getElementById y getContext("2d") son correctos: obtenemos el lienzo y el contexto para dibujar.

  • Error importante: setInterval(function(){...}, 1000) / FPS; — aquí tu intención era dividir el tiempo entre FPS, pero la división se aplica al valor retornado por setInterval (un id numérico) y está en un lugar donde no tiene efecto. El setInterval ya se ejecuta con 1000 ms y no con 1000 / FPS.

  • Lo correcto sería:

    setInterval(principal, 1000 / FPS);
    

    y calcular 1000 / FPS (en tu caso 1000 / 50 = 20 ms). (Cálculo: 1000 ÷ 50 = (1000 ÷ 10) ÷ 5 = 100 ÷ 5 = 20 ms.)

  • Mejor aún: usar requestAnimationFrame para animaciones fluidas o un bucle con control de FPS si necesitas velocidad fija.


5) Instancias de personajes

var per1 = new personaje(10, 50);
var per2 = new personaje(10, 120);
var per3 = new personaje(10, 230);
  • Crea tres objetos personaje con posiciones x,y distintas. Esto está bien.

  • Nota: las instancias se crean antes de inicializar ctx, pero eso no importa porque dibuja() se ejecuta después que ctx ya exista (si inicializas correctamente la animación tras inicializa()).


6) Limpiar el canvas — borraCanvas

function borraCanvas() {
  canvas.width = 500;
  canvas.height = 400;
}
  • canvas.width = ... y canvas.height = ... reinicializan el canvas (lo limpian) y además cambian su resolución interna. Esto funciona como método de limpieza, pero tiene efectos secundarios:

    • Estás forzando height = 400 aunque en el HTML lo pusiste height="300". Entonces hay inconsistencia (y cada frame reasignas el tamaño).

    • Cambiar las dimensiones en cada frame reinicia el contexto (y hace que pierdas configuraciones como transformaciones, estilos guardados, etc.). Es preferible usar:

      ctx.clearRect(0, 0, canvas.width, canvas.height);
      

      Esto solo borra el contenido sin tocar la resolución.


7) Función principal (bucle)

function principal() {
  borraCanvas();
  per1.dibuja();
  per2.dibuja();
  per3.dibuja();

  console.log("funcion");
}
  • Llama a borraCanvas() para limpiar y luego dibuja los personajes.

  • console.log("funcion") va a ejecutarse cada fotograma; quítalo o ponlo protegido por una condición de depuración.


8) Resumen de errores / mejoras recomendadas

  1. Bug en setInterval: usar setInterval(principal, 1000 / FPS); o cambiar a requestAnimationFrame para animación más suave.

  2. Uso de canvas.width/height para limpiar: preferir ctx.clearRect(...) para evitar reasignar el tamaño cada frame.

  3. Inconsistencia de alturas: HTML declara height="300" pero borraCanvas() pone height = 400. Decide un tamaño único.

  4. Eliminar console.logs en el bucle para no saturar la consola ni impactar rendimiento.

  5. Modernizar sintaxis: usar let/const y class Personaje { ... } para código más legible.

  6. Encapsular ctx: pasar ctx a métodos o mantener contexto dentro de un objeto, para evitar dependencias globales.

  7. Control de FPS con requestAnimationFrame si buscas suavidad y mejor integración con el navegador.


9) Código corregido y mejorado (sencillo y claro)

Aquí tienes una versión corregida usando requestAnimationFrame (bucle optimizado), ctx.clearRect para limpiar, y class ES6. Si quieres mantener un FPS fijo de 50 puedo añadir la lógica de timing, pero esto es más fluido por defecto:

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <title>CreaPersonajes - Demo</title>
</head>
<body onload="inicializa()">
  <canvas id="canvas" width="500" height="300" style="border:2px solid #000000"></canvas>

  <script>
    let canvas, ctx;
    const FPS = 50; // puedes usarlo si quieres controlar manualmente el frame rate

    class Personaje {
      constructor(x, y, w = 50, h = 50, color = "#fff000") {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.color = color;
      }

      dibuja(context) {
        context.fillStyle = this.color;
        context.fillRect(this.x, this.y, this.w, this.h);
      }
    }

    // Instancias
    const per1 = new Personaje(10, 50);
    const per2 = new Personaje(10, 120);
    const per3 = new Personaje(10, 190);

    function inicializa() {
      canvas = document.getElementById("canvas");
      ctx = canvas.getContext("2d");

      // Iniciar bucle de animación:
      requestAnimationFrame(loop);
    }

    function borraCanvas() {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
    }

    function principal() {
      borraCanvas();
      per1.dibuja(ctx);
      per2.dibuja(ctx);
      per3.dibuja(ctx);
    }

    function loop(timestamp) {
      // Si quisieras forzar 50 FPS, podrías usar timestamp y un delta; 
      // por simplicidad aquí dibujamos cada frame disponible:
      principal();
      requestAnimationFrame(loop);
    }
  </script>
</body>
</html>

Si prefieres fijar 50 FPS en lugar de dibujar a máximo framerate, dime y te doy la versión con control de tiempo (usa timestamp y compara con lastTime para actualizar cada 20 ms — 1000/50 = 20 ms).


10) ¿Qué más podemos agregar después?

Dime cuáles de estas funcionalidades quieres que agregue y lo hacemos:

  • mover personajes con teclado o clic.

  • animar sprites en vez de rectángulos.

  • detectar colisiones entre personajes.

  • agregar UI para crear/editar personajes en tiempo real.

  • guardar la configuración de personajes (localStorage).

  • controlar FPS exactamente a 50.


¿Quieres que implemente ahora la versión con control de FPS (50 FPS) o prefieres que añadamos movimiento por teclado primero?

Comentarios

Entradas más populares de este blog

codigo

5. 04.funciones parte1