Pistola
Explicación del Código con Funcionalidad de Balas
Voy a explicar cómo agregar la funcionalidad de balas al código existente, paso por paso:
Partes añadidas/modificadas:
Clase Bala: Esta nueva clase representa las balas que disparará el protagonista.
constructor(x, y): Inicializa la posición de la bala y su velocidad.
dibuja(): Dibuja la bala como un rectángulo rojo.
mueve(): Actualiza la posición de la bala según su velocidad.
Array de balas: let balas = []; almacena todas las balas activas.
Modificación en principal(): Ahora también procesa y dibuja todas las balas.
Event listener para disparar: Se añade document.addEventListener('keydown', function(tecla) {...} para detectar cuando se presiona la barra espaciadora y crear una nueva bala.
Lógica de movimiento de balas: Cada bala se mueve y se elimina cuando sale del canvas.
Clase Bala: Esta nueva clase representa las balas que disparará el protagonista.
constructor(x, y): Inicializa la posición de la bala y su velocidad.dibuja(): Dibuja la bala como un rectángulo rojo.mueve(): Actualiza la posición de la bala según su velocidad.
Array de balas: let balas = []; almacena todas las balas activas.
Modificación en principal(): Ahora también procesa y dibuja todas las balas.
Event listener para disparar: Se añade document.addEventListener('keydown', function(tecla) {...} para detectar cuando se presiona la barra espaciadora y crear una nueva bala.
Lógica de movimiento de balas: Cada bala se mueve y se elimina cuando sale del canvas.
Código completo:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Protagonista Simple</title>
</head>
<body onload="inicializa()">
<canvas id="canvas" width="500" height="300" style="border:2px solid #000"></canvas>
<script>
let canvas, ctx;
let FPS = 50;
// Imagen del protagonista
let imgMega = new Image();
imgMega.src = 'img/mega.jpeg';
// Inicialización
function inicializa() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
// Event listener para disparar con la barra espaciadora
document.addEventListener('keydown', function(tecla) {
if(tecla.code == 'Space') {
// Crea una nueva bala en la posición del protagonista
balas.push(new Bala(prota.x + 50, prota.y + 20));
}
});
setInterval(principal, 1000 / FPS);
}
// Clase Protagonista
class Protagonista {
constructor(x, y) {
this.x = x;
this.y = y;
}
dibuja() {
// Dibuja un rectángulo temporal si la imagen no está cargada
if (!imgMega.complete || !imgMega.naturalWidth) {
ctx.fillStyle = "blue";
ctx.fillRect(this.x, this.y, 50, 50);
} else {
ctx.drawImage(imgMega, this.x, this.y, 50, 50);
}
}
}
// Clase Bala
class Bala {
constructor(x, y) {
this.x = x;
this.y = y;
this.velocidad = 5;
}
dibuja() {
ctx.fillStyle = "#ff0000";
ctx.fillRect(this.x, this.y, 10, 5);
}
mueve() {
this.x += this.velocidad;
}
}
// Instancia del protagonista y array de balas
let prota = new Protagonista(200, 200);
let balas = [];
// Borra el canvas
function borraCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
// Función principal
function principal() {
borraCanvas();
// Dibuja y mueve al protagonista
prota.dibuja();
// Procesa todas las balas
for(let i = 0; i < balas.length; i++) {
balas[i].dibuja();
balas[i].mueve();
// Elimina balas que salieron del canvas
if(balas[i].x > canvas.width) {
balas.splice(i, 1);
i--; // Ajusta el índice después de eliminar
}
}
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Protagonista Simple</title>
</head>
<body onload="inicializa()">
<canvas id="canvas" width="500" height="300" style="border:2px solid #000"></canvas>
<script>
let canvas, ctx;
let FPS = 50;
// Imagen del protagonista
let imgMega = new Image();
imgMega.src = 'img/mega.jpeg';
// Inicialización
function inicializa() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
// Event listener para disparar con la barra espaciadora
document.addEventListener('keydown', function(tecla) {
if(tecla.code == 'Space') {
// Crea una nueva bala en la posición del protagonista
balas.push(new Bala(prota.x + 50, prota.y + 20));
}
});
setInterval(principal, 1000 / FPS);
}
// Clase Protagonista
class Protagonista {
constructor(x, y) {
this.x = x;
this.y = y;
}
dibuja() {
// Dibuja un rectángulo temporal si la imagen no está cargada
if (!imgMega.complete || !imgMega.naturalWidth) {
ctx.fillStyle = "blue";
ctx.fillRect(this.x, this.y, 50, 50);
} else {
ctx.drawImage(imgMega, this.x, this.y, 50, 50);
}
}
}
// Clase Bala
class Bala {
constructor(x, y) {
this.x = x;
this.y = y;
this.velocidad = 5;
}
dibuja() {
ctx.fillStyle = "#ff0000";
ctx.fillRect(this.x, this.y, 10, 5);
}
mueve() {
this.x += this.velocidad;
}
}
// Instancia del protagonista y array de balas
let prota = new Protagonista(200, 200);
let balas = [];
// Borra el canvas
function borraCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
// Función principal
function principal() {
borraCanvas();
// Dibuja y mueve al protagonista
prota.dibuja();
// Procesa todas las balas
for(let i = 0; i < balas.length; i++) {
balas[i].dibuja();
balas[i].mueve();
// Elimina balas que salieron del canvas
if(balas[i].x > canvas.width) {
balas.splice(i, 1);
i--; // Ajusta el índice después de eliminar
}
}
}
</script>
</body>
</html>Funcionamiento completo:
El juego se inicia cargando al protagonista (un rectángulo azul o una imagen si está disponible).
Cuando el usuario presiona la barra espaciadora, se crea una nueva bala en la posición del protagonista.
Cada bala se mueve hacia la derecha a una velocidad constante.
Las balas se dibujan como pequeños rectángulos rojos.
Cuando una bala sale del área del canvas, se elimina del array para optimizar el rendimiento.
El bucle principal (principal()) se ejecuta 50 veces por segundo (FPS = 50), actualizando la posición de todas las balas y redibujando la escena.
El juego se inicia cargando al protagonista (un rectángulo azul o una imagen si está disponible).
Cuando el usuario presiona la barra espaciadora, se crea una nueva bala en la posición del protagonista.
Cada bala se mueve hacia la derecha a una velocidad constante.
Las balas se dibujan como pequeños rectángulos rojos.
Cuando una bala sale del área del canvas, se elimina del array para optimizar el rendimiento.
El bucle principal (principal()) se ejecuta 50 veces por segundo (FPS = 50), actualizando la posición de todas las balas y redibujando la escena.
Este código proporciona una base simple para un sistema de disparos que puede expandirse fácilmente añadiendo colisiones, diferentes tipos de balas, o efectos visuales más avanzados.
Pistola - Disparos con la Barra Espaciadora"
En este post, vamos a analizar cómo funciona el disparo de balas usando la tecla de espacio (barra espaciadora) en un pequeño juego HTML5 con JavaScript.
🔫 Código Explicado Paso a Paso
1. Estructura HTML Básica
El juego se ejecuta dentro de un <canvas> (lienzo) donde dibujamos al protagonista, enemigos y balas.
<canvas id="canvas" width="500" height="300" style="border:2px solid #000"></canvas>2. Clases Principales
🔹 Protagonista
Controla al personaje principal con las teclas de dirección.
class Protagonista {
constructor(x, y) {
this.x = x;
this.y = y;
this.velocidad = 3;
}
// ... (métodos de movimiento)
}🔹 Enemigos (Personaje)
Son objetivos que pueden ser eliminados con balas.
class Personaje {
constructor(x, y) {
this.x = x;
this.y = y;
this.vivo = true; // Indica si el enemigo sigue activo
}
}🔹 Balas
Se generan al presionar Espacio y avanzan hacia la derecha.
class Bala {
constructor(x, y) {
this.x = x;
this.y = y;
this.velocidad = 5;
}
mueve() {
this.x += this.velocidad; // Movimiento horizontal
}
}3. Disparar con la Barra Espaciadora
El evento keydown detecta cuando se presiona una tecla. Si es Espacio (keyCode 32), crea una nueva bala:
document.addEventListener('keydown', function (tecla) {
if (tecla.keyCode == 32) { // Espacio
balas.push(new Bala(prota.x + 50, prota.y + 20)); // Nueva bala
}
});prota.x + 50: Posición X inicial de la bala (al frente del personaje).prota.y + 20: Posición Y centrada respecto al personaje.
4. Movimiento y Colisiones
Las balas se mueven con
bala.mueve().Se eliminan si salen del canvas.
Colisiones: Si una bala toca un enemigo, este desaparece.
function detectaColisiones() {
balas.forEach((bala, balaIndex) => {
enemigos.forEach((enemigo, enemigoIndex) => {
if (enemigo.vivo && bala.x < enemigo.x + 50 /* ... */) {
enemigo.vivo = false; // Elimina enemigo
balas.splice(balaIndex, 1); // Elimina bala
}
});
});
}5. Bucle Principal
Ejecuta todo 50 veces por segundo (FPS):
function principal() {
borraCanvas(); // Limpia pantalla
prota.dibuja(); // Dibuja protagonista
// Dibuja enemigos y balas...
detectaColisiones(); // Verifica impactos
}🎯 Conclusión
Espacio (keyCode 32) crea balas.
Cada bala se almacena en el array
balasy se mueve automáticamente.Si golpea a un enemigo, ambos desaparecen.
¡Ahora puedes modificar el código para añadir más enemigos, diferentes armas o efectos visuales! 🚀
Sistema de Colisiones entre Balas y Enemigos
Voy a explicar cómo implementar la detección de colisiones entre balas y enemigos, y luego proporcionaré el código completo.
Explicación de las nuevas funcionalidades:
Clase Enemigo:
Similar al protagonista pero con diferente color (rojo)
Tiene propiedad
vivopara controlar su estado
Array de enemigos:
let enemigos = [];almacena todos los enemigos activosEn el ejemplo, creo 3 enemigos de prueba
Función detectaColisiones():
Compara cada bala con cada enemigo vivo
Usa detección de colisión AABB (Axis-Aligned Bounding Box)
Si hay colisión:
Marca el enemigo como no vivo
Elimina la bala
Modificaciones en principal():
Ahora también dibuja los enemigos vivos
Llama a detectaColisiones() cada frame
Código completo:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Juego con Colisiones</title>
</head>
<body onload="inicializa()">
<canvas id="canvas" width="500" height="300" style="border:2px solid #000"></canvas>
<script>
let canvas, ctx;
let FPS = 50;
// Imagen del protagonista
let imgMega = new Image();
imgMega.src = 'img/mega.jpeg';
// Inicialización
function inicializa() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
// Event listener para disparar con la barra espaciadora
document.addEventListener('keydown', function(tecla) {
if(tecla.code == 'Space') {
// Crea una nueva bala en la posición del protagonista
balas.push(new Bala(prota.x + 50, prota.y + 20));
}
});
// Crear algunos enemigos de prueba
enemigos.push(new Enemigo(300, 100));
enemigos.push(new Enemigo(400, 150));
enemigos.push(new Enemigo(350, 200));
setInterval(principal, 1000 / FPS);
}
// Clase Protagonista
class Protagonista {
constructor(x, y) {
this.x = x;
this.y = y;
}
dibuja() {
// Dibuja un rectángulo temporal si la imagen no está cargada
if (!imgMega.complete || !imgMega.naturalWidth) {
ctx.fillStyle = "blue";
ctx.fillRect(this.x, this.y, 50, 50);
} else {
ctx.drawImage(imgMega, this.x, this.y, 50, 50);
}
}
}
// Clase Bala
class Bala {
constructor(x, y) {
this.x = x;
this.y = y;
this.velocidad = 5;
}
dibuja() {
ctx.fillStyle = "#ff0000";
ctx.fillRect(this.x, this.y, 10, 5);
}
mueve() {
this.x += this.velocidad;
}
}
// Clase Enemigo
class Enemigo {
constructor(x, y) {
this.x = x;
this.y = y;
this.vivo = true;
}
dibuja() {
if (this.vivo) {
ctx.fillStyle = "red";
ctx.fillRect(this.x, this.y, 50, 50);
}
}
}
// Instancias y arrays
let prota = new Protagonista(200, 200);
let balas = [];
let enemigos = [];
// Borra el canvas
function borraCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
// Detecta colisiones entre balas y enemigos
function detectaColisiones() {
balas.forEach((bala, balaIndex) => {
enemigos.forEach((enemigo, enemigoIndex) => {
if (enemigo.vivo &&
bala.x < enemigo.x + 50 && // Lado derecho del enemigo
bala.x + 10 > enemigo.x && // Lado izquierdo del enemigo
bala.y < enemigo.y + 50 && // Parte inferior del enemigo
bala.y + 5 > enemigo.y) { // Parte superior del enemigo
enemigo.vivo = false; // Marca el enemigo como eliminado
balas.splice(balaIndex, 1); // Elimina la bala
}
});
});
}
// Función principal
function principal() {
borraCanvas();
// Dibuja y mueve al protagonista
prota.dibuja();
// Dibuja enemigos vivos
enemigos.forEach(enemigo => enemigo.dibuja());
// Procesa todas las balas
for(let i = 0; i < balas.length; i++) {
balas[i].dibuja();
balas[i].mueve();
// Elimina balas que salieron del canvas
if(balas[i].x > canvas.width) {
balas.splice(i, 1);
i--; // Ajusta el índice después de eliminar
}
}
// Detecta colisiones
detectaColisiones();
}
</script>
</body>
</html>Explicación de la detección de colisiones:
La función detectaColisiones() usa el algoritmo AABB (Axis-Aligned Bounding Box) que verifica si los rectángulos que representan los objetos se superponen:
Para cada bala y cada enemigo vivo, verifica:
¿El lado izquierdo de la bala está a la izquierda del lado derecho del enemigo?
¿El lado derecho de la bala está a la derecha del lado izquierdo del enemigo?
¿La parte superior de la bala está por encima de la parte inferior del enemigo?
¿La parte inferior de la bala está por debajo de la parte superior del enemigo?
Si todas estas condiciones son verdaderas, hay colisión:
El enemigo se marca como no vivo (
vivo = false)La bala se elimina del array
En el bucle principal, los enemigos con
vivo = falseno se dibujan
Este sistema proporciona una base sólida para un juego simple que puedes expandir añadiendo más tipos de enemigos, efectos de explosión, puntuación, o sonidos cuando ocurren colisiones.
Comentarios
Publicar un comentario