Files
orni-attack/source/game/entities/bullet.cpp
T
JailDesigner b746578bc8 Cabeceras: unificar copyright a "© 2026 JailDesigner" en todo source/
Sustituye en bloque las cabeceras de los archivos por una sola línea de
copyright. Cero rastro de "Visente", "Sergi" o "1999" en el árbol del
proyecto. Se eliminan también las variantes "© 2025 Port a C++20", "© 2025
Port a C++20 con SDL3" y "© 2025 Orni Attack" (con todas sus colas
descriptivas como "Arquitectura de entidades" o "Sistema de física"), que
en este punto eran ruido histórico.

Aplicado con un par de sed (find -type f, excluyendo source/external y
source/legacy):

  1. \|^// © 1999 Visente i Sergi (versión Pascal)$|d
  2. s|^// © 2025 (Port a C++20.*|Orni Attack.*)$|// © 2026 JailDesigner|

Verificado: la única variante de cabecera tras el sweep es
"// © 2026 JailDesigner".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 09:51:46 +02:00

143 lines
4.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// bullet.cpp - Implementación de projectils de la ship
// © 2026 JailDesigner
#include "game/entities/bullet.hpp"
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <iostream>
#include "core/audio/audio.hpp"
#include "core/defaults.hpp"
#include "core/entities/entity.hpp"
#include "core/graphics/shape_loader.hpp"
#include "core/rendering/shape_renderer.hpp"
#include "core/types.hpp"
#include "game/constants.hpp"
namespace {
// Velocidad escalar de las balas (px/s). Conserva el feel del Pascal original
// (7 px/frame × 20 FPS = 140 px/s).
constexpr float BULLET_SPEED = 140.0F;
} // namespace
Bullet::Bullet(Rendering::Renderer* renderer)
: Entity(renderer),
esta_(false),
owner_id_(0),
grace_timer_(0.0F) {
// Brightness específico para balas
brightness_ = Defaults::Brightness::BALA;
// Configuración del cuerpo físico.
// Las balas son cinemáticas: no colisionan con otros bodies ni paredes.
// El gameplay (GameScene) gestiona los hits con check_collision y la
// salida del PLAYAREA. Por eso radius=0 en el world (no participa en
// resolveBodyCollisions ni resolveBoundsCollisions).
body_.setMass(0.5F); // Ligera (no afecta a nadie, pero por consistencia)
body_.radius = 0.0F; // Sin colisión física (cinemática pura)
body_.restitution = 0.0F; // Irrelevante (no rebota)
body_.linear_damping = 0.0F; // Sin fricción (movimiento rectilíneo uniforme)
body_.angular_damping = 0.0F;
// Cargar shape compartida desde archivo
shape_ = Graphics::ShapeLoader::load("bullet.shp");
if (!shape_ || !shape_->isValid()) {
std::cerr << "[Bullet] Error: no s'ha pogut load bullet.shp" << '\n';
}
}
void Bullet::init() {
// Inicialment inactiva
esta_ = false;
center_ = {.x = 0.0F, .y = 0.0F};
angle_ = 0.0F;
grace_timer_ = 0.0F;
// Reset del cuerpo físico
body_.position = Vec2{};
body_.velocity = Vec2{};
body_.angle = 0.0F;
body_.angular_velocity = 0.0F;
body_.clearAccumulators();
}
void Bullet::disparar(const Vec2& position, float angle, uint8_t owner_id) {
// Activar bullet
esta_ = true;
// Almacenar propietario (0=P1, 1=P2)
owner_id_ = owner_id;
// Activar grace period (prevents instant self-collision)
grace_timer_ = Defaults::Game::BULLET_GRACE_PERIOD;
// Posición y orientación iniciales = ship
center_ = position;
angle_ = angle;
// Sincronizar el body físico: posición + velocidad cartesiana
// angle - PI/2 porque angle=0 apunta hacia arriba (eje Y negativo SDL)
body_.position = position;
body_.angle = angle;
const float DIR_X = std::cos(angle - (Constants::PI / 2.0F));
const float DIR_Y = std::sin(angle - (Constants::PI / 2.0F));
body_.velocity = Vec2{.x = DIR_X * BULLET_SPEED, .y = DIR_Y * BULLET_SPEED};
body_.angular_velocity = 0.0F;
body_.clearAccumulators();
// Reproducir sonido de disparo láser
Audio::get()->playSound(Defaults::Sound::LASER, Audio::Group::GAME);
}
void Bullet::update(float delta_time) {
if (!esta_) {
return;
}
// Decrementar grace timer
if (grace_timer_ > 0.0F) {
grace_timer_ -= delta_time;
grace_timer_ = std::max(grace_timer_, 0.0F);
}
// El movimiento real lo hace PhysicsWorld::update() (integración).
// Aquí solo lógica de estado: detectar salida del PLAYAREA y desactivar.
float min_x;
float max_x;
float min_y;
float max_y;
Constants::obtenir_limits_zona_segurs(Defaults::Entities::BULLET_RADIUS,
min_x,
max_x,
min_y,
max_y);
if (body_.position.x < min_x || body_.position.x > max_x ||
body_.position.y < min_y || body_.position.y > max_y) {
desactivar();
}
}
void Bullet::postUpdate(float /*delta_time*/) {
// Sincronizar mirror desde body_ tras la integración del world.
center_ = body_.position;
// angle_ no cambia (las balas no rotan visualmente).
}
void Bullet::desactivar() {
esta_ = false;
// Detener el cuerpo físico para que no acumule deriva mientras inactiva.
body_.velocity = Vec2{};
body_.angular_velocity = 0.0F;
}
void Bullet::draw() const {
if (esta_ && shape_) {
// Les bales roten segons l'angle de trayectòria (estático tras disparo)
Rendering::render_shape(renderer_, shape_, center_, angle_, 1.0F, 1.0F, brightness_,
/*rotation_3d=*/nullptr, Defaults::Palette::BULLET);
}
}