Files
orni-attack/source/game/entities/bullet.cpp
T
JailDesigner bbbb8d47ae Lint: rename públicos al inglés + refactor cognitive-complexity + unused-includes
Identifier-naming: rename de métodos públicos y cross-file al inglés
(camelBack), traducción de campos y locales en el proceso (TitleShip,
StageManager, SpawnController, ShipAnimator, helpers de PlayArea, etc.).

Refactor por cognitive-complexity (>25): GameScene::draw (59→3) con 9
helpers de estado, PhysicsWorld::resolveBodyCollisions (35→5) extrayendo
resolveBodyPair, Options::load{Window,Physics,Audio}ConfigFromYaml
(32/49/57→5/2/3) con templates readField, TitleScene::update (68→4) con
5 sub-pasos por estado + handleSkipInput/handleStartInput +
triggerExitForJoinedPlayers, DebrisManager::explode (39→3) con
extractSegments/spawnDebris/applyAngularVelocity/applyVisualRotation.

use-anyofallof: bucles → std::ranges::any_of/all_of en Input,
ShipAnimator y SpawnController.

readability-static-accessed-through-instance: Director::run y
VectorText::getTextWidth/Height invocados por clase.

readability-convert-member-functions-to-static: ResourcePack::decryptData.

unused-includes: eliminación de <utility>, <cstdint>, <vector>,
<iostream>, defaults.hpp y otros no usados directamente en headers y
unidades de traducción. Restablecido core/defaults.hpp en title_scene.cpp
(falsa "unused" del header).

Bug fix: eliminado isActive() duplicado en Bullet (redeclaración tras
rename de esta_activa→isActive que chocaba con el override de Entity).

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

141 lines
4.4 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)
{
// 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
is_active_ = 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
is_active_ = 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 (!is_active_) {
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::getSafePlayAreaBounds(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() {
is_active_ = 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 (is_active_ && shape_) {
// Les bales roten segons l'angle de trayectòria (estático tras disparo)
Rendering::renderShape(renderer_, shape_, center_, angle_, 1.0F, 1.0F, brightness_,
/*rotation_3d=*/nullptr, Defaults::Palette::BULLET);
}
}