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 atributoswidth/height(HTML) definen el tamaño en pixeles del contexto de dibujo; elstylesolo 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óninicializa()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");
-
canvasyctx(contexto 2D) se declaran globales para ser accesibles desde cualquier función. -
FPS = 50pretende indicar fotogramas por segundo. -
console.logson ú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 propiedadesx,yy el métododibuja. -
dibuja()usactx.fillRect(x, y, ancho, alto)para pintar un rectángulo de50x50con color#fff000. -
Observación:
dibuja()depende de la variable globalctx. Es funcional, pero es más robusto pasarctxcomo 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;
}
-
getElementByIdygetContext("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 entreFPS, pero la división se aplica al valor retornado porsetInterval(un id numérico) y está en un lugar donde no tiene efecto. ElsetIntervalya se ejecuta con1000ms y no con1000 / FPS. -
Lo correcto sería:
setInterval(principal, 1000 / FPS);y calcular
1000 / FPS(en tu caso1000 / 50 = 20 ms). (Cálculo: 1000 ÷ 50 = (1000 ÷ 10) ÷ 5 = 100 ÷ 5 = 20 ms.) -
Mejor aún: usar
requestAnimationFramepara 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
personajecon posicionesx,ydistintas. Esto está bien. -
Nota: las instancias se crean antes de inicializar
ctx, pero eso no importa porquedibuja()se ejecuta después quectxya exista (si inicializas correctamente la animación trasinicializa()).
6) Limpiar el canvas — borraCanvas
function borraCanvas() {
canvas.width = 500;
canvas.height = 400;
}
-
canvas.width = ...ycanvas.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 = 400aunque en el HTML lo pusisteheight="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
-
Bug en
setInterval: usarsetInterval(principal, 1000 / FPS);o cambiar arequestAnimationFramepara animación más suave. -
Uso de
canvas.width/heightpara limpiar: preferirctx.clearRect(...)para evitar reasignar el tamaño cada frame. -
Inconsistencia de alturas: HTML declara
height="300"peroborraCanvas()poneheight = 400. Decide un tamaño único. -
Eliminar console.logs en el bucle para no saturar la consola ni impactar rendimiento.
-
Modernizar sintaxis: usar
let/constyclass Personaje { ... }para código más legible. -
Encapsular
ctx: pasarctxa métodos o mantener contexto dentro de un objeto, para evitar dependencias globales. -
Control de FPS con
requestAnimationFramesi 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
Publicar un comentario