refactor: eliminar Rotation3D i el seu camí de codi (codi mort)

L'struct Rotation3D, la funció apply3dRotation i el paràmetre opcional
rotation_3d de renderShape mai s'activaven en cap caller:
- Ship, Enemy i Bullet passaven explícitament nullptr.
- Title scene, logo scene, starfield, vector_text i ship_animator
  usaven el default nullptr (set els 7 callers).

CLAUDE.md descriu un sistema 3D del title screen que ja no està viu —
el comentari en ship_animator.cpp aclareix que la perspectiva s'ha
bakeat dins de la shape, així que la rotació dinàmica era residu
històric.

Esborrats: struct Rotation3D + ctors + hasRotation(), apply3dRotation(),
la branca rotation_3d a transformPoint() i el seu paràmetre, el
paràmetre rotation_3d de renderShape, i els arguments nullptr als
3 callers d'entitats.

Hallazgo #16 de CODE_REVIEW.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-20 16:50:03 +02:00
parent 682c27c07c
commit 707fd29b97
5 changed files with 117 additions and 183 deletions
+10 -54
View File
@@ -9,65 +9,24 @@
namespace Rendering { namespace Rendering {
// Helper: aplicar rotación 3D a un point 2D (assumeix Z=0)
static auto apply3dRotation(float x, float y, const Rotation3D& rot) -> Vec2 {
float z = 0.0F; // Todos los points 2D comencen a Z=0
// Pitch (rotación eix X): cabeceo arriba/baix
float cos_pitch = std::cos(rot.pitch);
float sin_pitch = std::sin(rot.pitch);
float y1 = (y * cos_pitch) - (z * sin_pitch);
float z1 = (y * sin_pitch) + (z * cos_pitch);
// Yaw (rotación eix Y): guiñada izquierda/derecha
float cos_yaw = std::cos(rot.yaw);
float sin_yaw = std::sin(rot.yaw);
float x2 = (x * cos_yaw) + (z1 * sin_yaw);
float z2 = (-x * sin_yaw) + (z1 * cos_yaw);
// Roll (rotación eix Z): alabeo lateral
float cos_roll = std::cos(rot.roll);
float sin_roll = std::sin(rot.roll);
float x3 = (x2 * cos_roll) - (y1 * sin_roll);
float y3 = (x2 * sin_roll) + (y1 * cos_roll);
// Proyecció perspectiva (Z-divide simple)
// Naves quieren hacia el point de fuga (320, 240) a "infinit" (Z → +∞)
// Z més grande = més lluny = més pequeño a pantalla
constexpr float PERSPECTIVE_FACTOR = 500.0F;
float scale_factor = PERSPECTIVE_FACTOR / (PERSPECTIVE_FACTOR + z2);
return {.x = x3 * scale_factor, .y = y3 * scale_factor};
}
// Helper: transformar un point con rotación, scale i traslación // Helper: transformar un point con rotación, scale i traslación
static auto transformPoint(const Vec2& point, const Vec2& shape_centre, const Vec2& position, float angle, float scale, const Rotation3D* rotation_3d) -> Vec2 { static auto transformPoint(const Vec2& point, const Vec2& shape_centre, const Vec2& position, float angle, float scale) -> Vec2 {
// 1. Centrar el point respecte al centro de la shape // 1. Centrar el point respecte al centro de la shape
float centered_x = point.x - shape_centre.x; float centered_x = point.x - shape_centre.x;
float centered_y = point.y - shape_centre.y; float centered_y = point.y - shape_centre.y;
// 2. Aplicar rotación 3D (si es proporciona) // 2. Aplicar scale al point
if ((rotation_3d != nullptr) && rotation_3d->hasRotation()) {
Vec2 rotated_3d = apply3dRotation(centered_x, centered_y, *rotation_3d);
centered_x = rotated_3d.x;
centered_y = rotated_3d.y;
}
// 3. Aplicar scale al point (después de rotación 3D)
float scaled_x = centered_x * scale; float scaled_x = centered_x * scale;
float scaled_y = centered_y * scale; float scaled_y = centered_y * scale;
// 4. Aplicar rotación 2D (Z-axis, tradicional) // 3. Aplicar rotación 2D (Z-axis)
// IMPORTANT: En el sistema original, angle=0 apunta AMUNT (no derecha)
// Per això usem (angle - PI/2) per compensar
// Pero aquí angle ya ve en el sistema correcte del juego
float cos_a = std::cos(angle); float cos_a = std::cos(angle);
float sin_a = std::sin(angle); float sin_a = std::sin(angle);
float rotated_x = (scaled_x * cos_a) - (scaled_y * sin_a); float rotated_x = (scaled_x * cos_a) - (scaled_y * sin_a);
float rotated_y = (scaled_x * sin_a) + (scaled_y * cos_a); float rotated_y = (scaled_x * sin_a) + (scaled_y * cos_a);
// 5. Aplicar traslación a posición mundial // 4. Aplicar traslación a posición mundial
return {.x = rotated_x + position.x, .y = rotated_y + position.y}; return {.x = rotated_x + position.x, .y = rotated_y + position.y};
} }
@@ -78,7 +37,6 @@ void renderShape(Rendering::Renderer* renderer,
float scale, float scale,
float progress, float progress,
float brightness, float brightness,
const Rotation3D* rotation_3d,
SDL_Color color) { SDL_Color color) {
if (!shape || !shape->isValid()) { if (!shape || !shape->isValid()) {
return; return;
@@ -93,16 +51,14 @@ void renderShape(Rendering::Renderer* renderer,
if (primitive.type == Graphics::PrimitiveType::POLYLINE) { if (primitive.type == Graphics::PrimitiveType::POLYLINE) {
// POLYLINE: conectar puntos consecutivos. // POLYLINE: conectar puntos consecutivos.
for (size_t i = 0; i < primitive.points.size() - 1; i++) { for (size_t i = 0; i < primitive.points.size() - 1; i++) {
const Vec2 P1 = transformPoint(primitive.points[i], shape_centre, position, angle, scale, rotation_3d); const Vec2 P1 = transformPoint(primitive.points[i], shape_centre, position, angle, scale);
const Vec2 P2 = transformPoint(primitive.points[i + 1], shape_centre, position, angle, scale, rotation_3d); const Vec2 P2 = transformPoint(primitive.points[i + 1], shape_centre, position, angle, scale);
linea(renderer, static_cast<int>(P1.x), static_cast<int>(P1.y), linea(renderer, static_cast<int>(P1.x), static_cast<int>(P1.y), static_cast<int>(P2.x), static_cast<int>(P2.y), brightness, 0.0F, color);
static_cast<int>(P2.x), static_cast<int>(P2.y), brightness, 0.0F, color);
} }
} else if (primitive.points.size() >= 2) { // LINE } else if (primitive.points.size() >= 2) { // LINE
const Vec2 P1 = transformPoint(primitive.points[0], shape_centre, position, angle, scale, rotation_3d); const Vec2 P1 = transformPoint(primitive.points[0], shape_centre, position, angle, scale);
const Vec2 P2 = transformPoint(primitive.points[1], shape_centre, position, angle, scale, rotation_3d); const Vec2 P2 = transformPoint(primitive.points[1], shape_centre, position, angle, scale);
linea(renderer, static_cast<int>(P1.x), static_cast<int>(P1.y), linea(renderer, static_cast<int>(P1.x), static_cast<int>(P1.y), static_cast<int>(P2.x), static_cast<int>(P2.y), brightness, 0.0F, color);
static_cast<int>(P2.x), static_cast<int>(P2.y), brightness, 0.0F, color);
} }
} }
} }
+1 -23
View File
@@ -3,37 +3,16 @@
#pragma once #pragma once
#include "core/rendering/render_context.hpp"
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <memory> #include <memory>
#include "core/graphics/shape.hpp" #include "core/graphics/shape.hpp"
#include "core/rendering/render_context.hpp"
#include "core/types.hpp" #include "core/types.hpp"
namespace Rendering { namespace Rendering {
// Estructura per rotacions 3D (pitch, yaw, roll)
struct Rotation3D {
float pitch; // Rotación eix X (cabeceo arriba/baix)
float yaw; // Rotación eix Y (guiñada izquierda/derecha)
float roll; // Rotación eix Z (alabeo lateral)
Rotation3D()
: pitch(0.0F),
yaw(0.0F),
roll(0.0F) {}
Rotation3D(float p, float y, float r)
: pitch(p),
yaw(y),
roll(r) {}
[[nodiscard]] auto hasRotation() const -> bool {
return pitch != 0.0F || yaw != 0.0F || roll != 0.0F;
}
};
// Renderizar shape con transformacions // Renderizar shape con transformacions
// - renderer: SDL renderer // - renderer: SDL renderer
// - shape: shape vectorial a draw // - shape: shape vectorial a draw
@@ -49,7 +28,6 @@ void renderShape(Rendering::Renderer* renderer,
float scale = 1.0F, float scale = 1.0F,
float progress = 1.0F, float progress = 1.0F,
float brightness = 1.0F, float brightness = 1.0F,
const Rotation3D* rotation_3d = nullptr,
SDL_Color color = {0, 0, 0, 0}); // alpha==0 → usa global oscilador SDL_Color color = {0, 0, 0, 0}); // alpha==0 → usa global oscilador
} // namespace Rendering } // namespace Rendering
+2 -4
View File
@@ -23,8 +23,7 @@ constexpr float BULLET_SPEED = 140.0F;
} // namespace } // namespace
Bullet::Bullet(Rendering::Renderer* renderer) Bullet::Bullet(Rendering::Renderer* renderer)
: Entity(renderer) : Entity(renderer) {
{
// Brightness específico para balas // Brightness específico para balas
brightness_ = Defaults::Brightness::BALA; brightness_ = Defaults::Brightness::BALA;
@@ -134,7 +133,6 @@ void Bullet::desactivar() {
void Bullet::draw() const { void Bullet::draw() const {
if (is_active_ && shape_) { if (is_active_ && shape_) {
// Les bales roten segons l'angle de trayectòria (estático tras disparo) // Les bales roten segons l'angle de trayectòria (estático tras disparo)
Rendering::renderShape(renderer_, shape_, center_, angle_, 1.0F, 1.0F, brightness_, Rendering::renderShape(renderer_, shape_, center_, angle_, 1.0F, 1.0F, brightness_, Defaults::Palette::BULLET);
/*rotation_3d=*/nullptr, Defaults::Palette::BULLET);
} }
} }
+11 -7
View File
@@ -41,8 +41,7 @@ auto velocityToAngle(const Vec2& velocity) -> float {
Enemy::Enemy(Rendering::Renderer* renderer) Enemy::Enemy(Rendering::Renderer* renderer)
: Entity(renderer), : Entity(renderer),
tracking_strength_(0.5F) tracking_strength_(0.5F) {
{
brightness_ = Defaults::Brightness::ENEMIC; brightness_ = Defaults::Brightness::ENEMIC;
// Configuración del cuerpo físico — defaults para enemy genérico. // Configuración del cuerpo físico — defaults para enemy genérico.
@@ -225,12 +224,17 @@ void Enemy::draw() const {
const float SCALE = computeCurrentScale(); const float SCALE = computeCurrentScale();
SDL_Color color{}; SDL_Color color{};
switch (type_) { switch (type_) {
case EnemyType::PENTAGON: color = Defaults::Palette::PENTAGON; break; case EnemyType::PENTAGON:
case EnemyType::QUADRAT: color = Defaults::Palette::QUADRAT; break; color = Defaults::Palette::PENTAGON;
case EnemyType::MOLINILLO: color = Defaults::Palette::MOLINILLO; break; break;
case EnemyType::QUADRAT:
color = Defaults::Palette::QUADRAT;
break;
case EnemyType::MOLINILLO:
color = Defaults::Palette::MOLINILLO;
break;
} }
Rendering::renderShape(renderer_, shape_, center_, rotacio_, SCALE, 1.0F, brightness_, Rendering::renderShape(renderer_, shape_, center_, rotacio_, SCALE, 1.0F, brightness_, color);
/*rotation_3d=*/nullptr, color);
} }
void Enemy::destruir() { void Enemy::destruir() {
+2 -4
View File
@@ -20,8 +20,7 @@
#include "game/constants.hpp" #include "game/constants.hpp"
Ship::Ship(Rendering::Renderer* renderer, const char* shape_file) Ship::Ship(Rendering::Renderer* renderer, const char* shape_file)
: Entity(renderer) : Entity(renderer) {
{
// Brightness específico para naves // Brightness específico para naves
brightness_ = Defaults::Brightness::NAU; brightness_ = Defaults::Brightness::NAU;
@@ -158,6 +157,5 @@ void Ship::draw() const {
const float VISUAL_PUSH = SPEED / 33.33F; const float VISUAL_PUSH = SPEED / 33.33F;
const float SCALE = 1.0F + (VISUAL_PUSH / 12.0F); const float SCALE = 1.0F + (VISUAL_PUSH / 12.0F);
Rendering::renderShape(renderer_, shape_, center_, angle_, SCALE, 1.0F, brightness_, Rendering::renderShape(renderer_, shape_, center_, angle_, SCALE, 1.0F, brightness_, Defaults::Palette::SHIP);
/*rotation_3d=*/nullptr, Defaults::Palette::SHIP);
} }