Ir al contenido
Descargar

3. Disparos

  1. En Recursos, clic derecho en la carpeta objects › Novo objeto… (nuevo objeto). Ponle el nombre Bullet.

  2. En el Inspetor (Inspector), elige el sprite tiro.

  3. En el panel Camadas (capas; a la izquierda, debajo de Recursos), haz clic en + Camada › Instâncias. Haz doble clic en el nombre y llámala Tiros. Arrastra esa capa debajo de Instancias: la capa de arriba queda delante, así que los disparos van a aparecer detrás de la nave. Después haz clic de nuevo en Instancias, para que vuelva a ser la capa activa. Mira Capas.

Esta vez no coloques el Bullet en la room: los disparos los va a crear el código, en el momento en que la nave dispare.

Abre el Bullet.hpp, borra los ejemplos y escribe:

objects/Bullet.hpp
#pragma once
#include <brasa/brasa.hpp>
// El disparo de la nave: sube hasta salir de la pantalla.
class Bullet : public brasa::Entity {
public:
BRASA_VARS(Bullet)
void onSpawn() override;
void onUpdate() override;
};

Después el Bullet.cpp:

objects/Bullet.cpp
#include "Bullet.hpp"
using namespace brasa;
// onSpawn corre una vez, cuando nace el disparo. vspeed negativo = sube en la pantalla.
// El motor mueve el disparo solo en cada step, sin necesitar código en el onUpdate.
void Bullet::onSpawn() { vspeed = -5.0f; }
void Bullet::onUpdate() {
// ¿Salió por arriba? Lo destruimos para no acumular disparos invisibles.
if (y < -8.0f) destroy();
}
BRASA_ENTITY(Bullet);
  • vspeed es la velocidad vertical, en píxeles por paso. Brasa suma vspeed a la y sola en cada paso. En la pantalla, la y crece hacia abajo, así que -5 hace subir el disparo.
  • Cuando el disparo pasa la parte de arriba de la pantalla (y < -8), destroy() quita esa instancia del juego. Sin eso, los disparos seguirían existiendo para siempre, fuera de la pantalla.

El proyecto ya tiene las acciones de dirección. Falta una para el disparo:

  1. Abre Projeto › Configurações do projeto… (Proyecto › Configuración del proyecto) y ve a Ações de entrada (acciones de entrada).

  2. Haz clic en + Ação (agregar acción) y ponle el nombre atirar (disparar).

  3. En su fila, haz clic en el +, elige Apertar a tecla… (pulsar la tecla) y pulsa la barra espaciadora.

  4. Si quieres disparar también con el mando, haz clic en el + otra vez y elige Botão do controle › Pad:A (botón del mando).

  5. Haz clic en Salvar (guardar).

Sin una pausa, la nave soltaría 60 disparos por segundo. Crea una variable más para controlar eso: en el Inspetor del Player, + Variável › inteiro (entero), con el nombre intervaloTiro (intervalo de disparo) y el valor 10. Son 10 pasos entre un disparo y otro.

En el Player.hpp, agrega la parte private, con una variable que dice si la nave puede disparar. El archivo queda así:

objects/Player.hpp
#pragma once
#include <brasa/brasa.hpp>
// La nave. velocidade e intervaloTiro son variables del objeto: cámbialas en el Inspector, sin tocar el código.
class Player : public brasa::Entity {
public:
BRASA_VARS(Player)
void onSpawn() override;
void onUpdate() override;
private:
bool canShoot_ = true; // pasa a false durante intervaloTiro steps después de cada disparo
};

canShoot_ pertenece a la nave. Empieza en true (puede disparar) y va a pasar a false por un instante después de cada disparo. El private: dice que solo el propio Player la toca.

En el Player.cpp, agrega el bloque del disparo al final del onUpdate. El archivo entero queda así:

objects/Player.cpp
#include "Player.hpp"
#include <algorithm>
using namespace brasa;
void Player::onSpawn() {
animSpeed = 0.2f; // la llama del motor alterna entre los 2 frames
}
void Player::onUpdate() {
// Las acciones están en la configuración del proyecto (teclado y mando).
// axis devuelve de -1 a 1: -1 = la primera acción, 1 = la segunda.
float dx = axis("esquerda", "direita");
float dy = axis("cima", "baixo");
if (dx != 0.0f && dy != 0.0f) { // en diagonal, avanza a la misma velocidad
dx *= 0.7071f;
dy *= 0.7071f;
}
// clamp mantiene la nave dentro de la pantalla (la nave mide 16 px, así que el margen es 8).
const float maxX = static_cast<float>(roomWidth()) - 8.0f;
const float maxY = static_cast<float>(roomHeight()) - 8.0f;
x = std::clamp(x + dx * velocidade, 8.0f, maxX);
y = std::clamp(y + dy * velocidade, 8.0f, maxY);
// held(acción) es verdadero mientras la tecla o el botón están pulsados.
if (held("atirar") && canShoot_) {
spawn<Bullet>(x, y - 8.0f, "Tiros"); // el disparo nace en la capa Tiros, detrás de la nave
canShoot_ = false;
after(intervaloTiro, [this] { canShoot_ = true; }); // solo dispara de nuevo dentro de algunos steps
}
}
BRASA_ENTITY(Player);

El bloque nuevo, línea por línea:

  • held("atirar") && canShoot_: la acción atirar está mantenida y puede disparar.
  • spawn<Bullet>(x, y - 8.0f, "Tiros") crea un disparo en la posición de la nave, un poco más arriba (8 píxeles), en la capa Tiros.
  • canShoot_ = false bloquea nuevos disparos.
  • after(intervaloTiro, ...) programa algo para dentro de intervaloTiro pasos (10 pasos, un sexto de segundo). Cuando llegue el momento, canShoot_ vuelve a ser true.

Fíjate en que el Player.cpp usa el Bullet sin ningún #include más: en Brasa, todo objeto ve a todos los demás.

Pulsa Play. Mantén la barra espaciadora: la nave dispara una ráfaga de disparos que suben por la pantalla.

Prueba a cambiar el intervaloTiro en el Inspector a 3 o a 30 y mira la diferencia.

  • Los objetos se pueden crear desde el código con spawn<Objeto>(x, y, "Camada"). Mira Disparar.
  • hspeed y vspeed mueven el objeto solos en cada paso.
  • destroy() quita la instancia del juego.
  • Creas tus propias acciones en la configuración del proyecto y preguntas por ellas con held.
  • after(pasos, ...) ejecuta algo más tarde. Mira Esperar y repetir.

Siguiente parte: 4. Enemigos →