Fase 1a: Punt -> Vec2 amb operadors moderns

Primera sub-fase del naming sweep. Punt era un struct sense
operacions, conservat per compatibilitat amb el Pascal original.
Substituit per Vec2, un aggregate amb operadors aritmetics, dot,
length, normalized i length_squared (camelBack: lengthSquared)
seguint les regles del .clang-tidy del projecte.

Canvis:
- core/types.hpp reescrit: nou struct Vec2 amb +=,-=,*=,/=,
  unary -, ==, dot, length, lengthSquared, normalized
- Operadors fora de la classe: +, -, *, / (amb float per ambdues
  bandes), - unari, ==
- Vec2 segueix sent aggregate (sense constructors definits):
  els 'designated initializers' del codi existent funcionen igual:
  Vec2{.x = ..., .y = ...}
- Sed global sobre 35 fitxers: tots els 'Punt' -> 'Vec2'

Net: 35 fitxers tocats, +180 / -114. Compila i enllaça.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-19 11:33:27 +02:00
parent 6cf990bc1d
commit cd38101f99
35 changed files with 180 additions and 114 deletions
+1 -1
View File
@@ -464,7 +464,7 @@ constexpr float FLOATING_SCALE = 1.0F * SHIP_BASE_SCALE; // Flotant: escala
// Fórmula: (radi màxim de la nau * escala d'entrada) + marge
constexpr float ENTRY_OFFSET = (SHIP_MAX_RADIUS * ENTRY_SCALE_START) + ENTRY_OFFSET_MARGIN;
// Punt de fuga (centre per a l'animació de sortida)
// Vec2 de fuga (centre per a l'animació de sortida)
constexpr float VANISHING_POINT_X = CENTER_X; // 320.0f
constexpr float VANISHING_POINT_Y = CENTER_Y; // 240.0f
+2 -2
View File
@@ -27,7 +27,7 @@ class Entitat {
[[nodiscard]] virtual bool es_collidable() const { return false; }
// Getters comuns (inline, sense overhead)
[[nodiscard]] const Punt& get_centre() const { return centre_; }
[[nodiscard]] const Vec2& get_centre() const { return centre_; }
[[nodiscard]] float get_angle() const { return angle_; }
[[nodiscard]] float get_brightness() const { return brightness_; }
[[nodiscard]] const std::shared_ptr<Graphics::Shape>& get_forma() const { return forma_; }
@@ -36,7 +36,7 @@ class Entitat {
// Estat comú (accés directe, sense overhead)
SDL_Renderer* renderer_;
std::shared_ptr<Graphics::Shape> forma_;
Punt centre_;
Vec2 centre_;
float angle_{0.0F};
float brightness_{1.0F};
+2 -2
View File
@@ -134,8 +134,8 @@ void Shape::parse_center(const std::string& value) {
}
// Helper: parse points "x1,y1 x2,y2 x3,y3"
std::vector<Punt> Shape::parse_points(const std::string& str) const {
std::vector<Punt> points;
std::vector<Vec2> Shape::parse_points(const std::string& str) const {
std::vector<Vec2> points;
std::istringstream iss(trim(str));
std::string pair;
+4 -4
View File
@@ -19,7 +19,7 @@ enum class PrimitiveType {
// Primitiva individual (polyline o line)
struct ShapePrimitive {
PrimitiveType type;
std::vector<Punt> points; // 2+ punts per polyline, exactament 2 per line
std::vector<Vec2> points; // 2+ punts per polyline, exactament 2 per line
};
// Classe Shape - representa una forma vectorial carregada des de .shp
@@ -39,7 +39,7 @@ class Shape {
[[nodiscard]] const std::vector<ShapePrimitive>& get_primitives() const {
return primitives_;
}
[[nodiscard]] const Punt& get_centre() const { return centre_; }
[[nodiscard]] const Vec2& get_centre() const { return centre_; }
[[nodiscard]] float get_escala_defecte() const { return escala_defecte_; }
[[nodiscard]] bool es_valida() const { return !primitives_.empty(); }
@@ -49,7 +49,7 @@ class Shape {
private:
std::vector<ShapePrimitive> primitives_;
Punt centre_; // Centre/origen de la forma
Vec2 centre_; // Centre/origen de la forma
float escala_defecte_; // Escala per defecte (normalment 1.0)
std::string nom_; // Nom de la forma (per depuració)
@@ -58,7 +58,7 @@ class Shape {
[[nodiscard]] bool starts_with(const std::string& str, const std::string& prefix) const;
[[nodiscard]] std::string extract_value(const std::string& line) const;
void parse_center(const std::string& value);
[[nodiscard]] std::vector<Punt> parse_points(const std::string& str) const;
[[nodiscard]] std::vector<Vec2> parse_points(const std::string& str) const;
};
} // namespace Graphics
+1 -1
View File
@@ -15,7 +15,7 @@ namespace Graphics {
// Constructor
Starfield::Starfield(SDL_Renderer* renderer,
const Punt& punt_fuga,
const Vec2& punt_fuga,
const SDL_FRect& area,
int densitat)
: renderer_(renderer),
+4 -4
View File
@@ -30,7 +30,7 @@ class Starfield {
// - area: rectangle on actuen les estrelles (SDL_FRect)
// - densitat: nombre total d'estrelles (es divideix entre capes)
Starfield(SDL_Renderer* renderer,
const Punt& punt_fuga,
const Vec2& punt_fuga,
const SDL_FRect& area,
int densitat = 150);
@@ -41,13 +41,13 @@ class Starfield {
void dibuixar();
// Setters per ajustar paràmetres en temps real
void set_punt_fuga(const Punt& punt) { punt_fuga_ = punt; }
void set_punt_fuga(const Vec2& punt) { punt_fuga_ = punt; }
void set_brightness(float multiplier);
private:
// Estructura interna per cada estrella
struct Estrella {
Punt posicio; // Posició actual
Vec2 posicio; // Posició actual
float angle; // Angle de moviment (radians)
float distancia_centre; // Distància normalitzada del centre (0.0-1.0)
int capa; // Índex de capa (0=lluny, 1=mitjà, 2=prop)
@@ -72,7 +72,7 @@ class Starfield {
SDL_Renderer* renderer_;
// Configuració
Punt punt_fuga_; // Punt d'origen de les estrelles
Vec2 punt_fuga_; // Vec2 d'origen de les estrelles
SDL_FRect area_; // Àrea activa
float radi_max_; // Distància màxima del centre al límit de pantalla
int densitat_; // Nombre total d'estrelles
+4 -4
View File
@@ -182,7 +182,7 @@ bool VectorText::is_supported(char c) const {
return chars_.contains(c);
}
void VectorText::render(const std::string& text, const Punt& posicio, float escala, float spacing, float brightness) const {
void VectorText::render(const std::string& text, const Vec2& posicio, float escala, float spacing, float brightness) const {
if (renderer_ == nullptr) {
return;
}
@@ -223,7 +223,7 @@ void VectorText::render(const std::string& text, const Punt& posicio, float esca
// Renderizar carácter
// Ajustar X e Y para que posicio represente esquina superior izquierda
// (render_shape espera el centro, así que sumamos la mitad de ancho y altura)
Punt char_pos = {.x = current_x + (char_width_scaled / 2.0F), .y = posicio.y + (char_height_scaled / 2.0F)};
Vec2 char_pos = {.x = current_x + (char_width_scaled / 2.0F), .y = posicio.y + (char_height_scaled / 2.0F)};
Rendering::render_shape(renderer_, it->second, char_pos, 0.0F, escala, 1.0F, brightness);
// Avanzar posición
@@ -237,14 +237,14 @@ void VectorText::render(const std::string& text, const Punt& posicio, float esca
}
}
void VectorText::render_centered(const std::string& text, const Punt& centre_punt, float escala, float spacing, float brightness) const {
void VectorText::render_centered(const std::string& text, const Vec2& centre_punt, float escala, float spacing, float brightness) const {
// Calcular dimensions del text
float text_width = get_text_width(text, escala, spacing);
float text_height = get_text_height(escala);
// Calcular posició de l'esquina superior esquerra
// restant la meitat de les dimensions del punt central
Punt posicio_esquerra = {
Vec2 posicio_esquerra = {
.x = centre_punt.x - (text_width / 2.0F),
.y = centre_punt.y - (text_height / 2.0F)};
+2 -2
View File
@@ -25,7 +25,7 @@ class VectorText {
// - escala: factor de escala (1.0 = 20×40 px por carácter)
// - spacing: espacio entre caracteres en píxeles (a escala 1.0)
// - brightness: factor de brillantor (0.0-1.0, default 1.0 = màxima brillantor)
void render(const std::string& text, const Punt& posicio, float escala = 1.0F, float spacing = 2.0F, float brightness = 1.0F) const;
void render(const std::string& text, const Vec2& posicio, float escala = 1.0F, float spacing = 2.0F, float brightness = 1.0F) const;
// Renderizar string centrado en un punto
// - text: cadena a renderizar
@@ -33,7 +33,7 @@ class VectorText {
// - escala: factor de escala (1.0 = 20×40 px por carácter)
// - spacing: espacio entre caracteres en píxeles (a escala 1.0)
// - brightness: factor de brillantor (0.0-1.0, default 1.0 = màxima brillantor)
void render_centered(const std::string& text, const Punt& centre_punt, float escala = 1.0F, float spacing = 2.0F, float brightness = 1.0F) const;
void render_centered(const std::string& text, const Vec2& centre_punt, float escala = 1.0F, float spacing = 2.0F, float brightness = 1.0F) const;
// Calcular ancho total de un string (útil para centrado)
[[nodiscard]] float get_text_width(const std::string& text, float escala = 1.0F, float spacing = 2.0F) const;
+2 -2
View File
@@ -20,8 +20,8 @@ inline bool check_collision(const Entities::Entitat& a, const Entities::Entitat&
float suma_radis_sq = suma_radis * suma_radis;
// Comprovació distància al quadrat (sense sqrt)
const Punt& pos_a = a.get_centre();
const Punt& pos_b = b.get_centre();
const Vec2& pos_a = a.get_centre();
const Vec2& pos_b = b.get_centre();
float dx = pos_a.x - pos_b.x;
float dy = pos_a.y - pos_b.y;
float dist_sq = (dx * dx) + (dy * dy);
+9 -9
View File
@@ -11,7 +11,7 @@
namespace Rendering {
// Helper: aplicar rotació 3D a un punt 2D (assumeix Z=0)
static Punt apply_3d_rotation(float x, float y, const Rotation3D& rot) {
static Vec2 apply_3d_rotation(float x, float y, const Rotation3D& rot) {
float z = 0.0F; // Tots els punts 2D comencen a Z=0
// Pitch (rotació eix X): cabeceo arriba/baix
@@ -42,14 +42,14 @@ static Punt apply_3d_rotation(float x, float y, const Rotation3D& rot) {
}
// Helper: transformar un punt amb rotació, escala i trasllació
static Punt transform_point(const Punt& point, const Punt& shape_centre, const Punt& posicio, float angle, float escala, const Rotation3D* rotation_3d) {
static Vec2 transform_point(const Vec2& point, const Vec2& shape_centre, const Vec2& posicio, float angle, float escala, const Rotation3D* rotation_3d) {
// 1. Centrar el punt respecte al centre de la forma
float centered_x = point.x - shape_centre.x;
float centered_y = point.y - shape_centre.y;
// 2. Aplicar rotació 3D (si es proporciona)
if ((rotation_3d != nullptr) && rotation_3d->has_rotation()) {
Punt rotated_3d = apply_3d_rotation(centered_x, centered_y, *rotation_3d);
Vec2 rotated_3d = apply_3d_rotation(centered_x, centered_y, *rotation_3d);
centered_x = rotated_3d.x;
centered_y = rotated_3d.y;
}
@@ -74,7 +74,7 @@ static Punt transform_point(const Punt& point, const Punt& shape_centre, const P
void render_shape(SDL_Renderer* renderer,
const std::shared_ptr<Graphics::Shape>& shape,
const Punt& posicio,
const Vec2& posicio,
float angle,
float escala,
float progress,
@@ -91,15 +91,15 @@ void render_shape(SDL_Renderer* renderer,
}
// Obtenir el centre de la forma per a transformacions
const Punt& shape_centre = shape->get_centre();
const Vec2& shape_centre = shape->get_centre();
// Iterar sobre totes les primitives
for (const auto& primitive : shape->get_primitives()) {
if (primitive.type == Graphics::PrimitiveType::POLYLINE) {
// POLYLINE: connectar punts consecutius
for (size_t i = 0; i < primitive.points.size() - 1; i++) {
Punt p1 = transform_point(primitive.points[i], shape_centre, posicio, angle, escala, rotation_3d);
Punt p2 = transform_point(primitive.points[i + 1], shape_centre, posicio, angle, escala, rotation_3d);
Vec2 p1 = transform_point(primitive.points[i], shape_centre, posicio, angle, escala, rotation_3d);
Vec2 p2 = transform_point(primitive.points[i + 1], shape_centre, posicio, angle, escala, rotation_3d);
linea(renderer, static_cast<int>(p1.x), static_cast<int>(p1.y),
static_cast<int>(p2.x), static_cast<int>(p2.y), brightness);
@@ -107,8 +107,8 @@ void render_shape(SDL_Renderer* renderer,
} else { // PrimitiveType::LINE
// LINE: exactament 2 punts
if (primitive.points.size() >= 2) {
Punt p1 = transform_point(primitive.points[0], shape_centre, posicio, angle, escala, rotation_3d);
Punt p2 = transform_point(primitive.points[1], shape_centre, posicio, angle, escala, rotation_3d);
Vec2 p1 = transform_point(primitive.points[0], shape_centre, posicio, angle, escala, rotation_3d);
Vec2 p2 = transform_point(primitive.points[1], shape_centre, posicio, angle, escala, rotation_3d);
linea(renderer, static_cast<int>(p1.x), static_cast<int>(p1.y),
static_cast<int>(p2.x), static_cast<int>(p2.y), brightness);
+1 -1
View File
@@ -42,7 +42,7 @@ struct Rotation3D {
// - brightness: factor de brillantor (0.0-1.0, default 1.0 = màxima brillantor)
void render_shape(SDL_Renderer* renderer,
const std::shared_ptr<Graphics::Shape>& shape,
const Punt& posicio,
const Vec2& posicio,
float angle,
float escala = 1.0F,
float progress = 1.0F,
+69 -3
View File
@@ -1,6 +1,72 @@
// types.hpp - Tipos básicos compartidos
// © 2025 Orni Attack
#pragma once
// Punt cartesià - ÚNICA estructura de coordenades del joc
struct Punt {
float x, y;
#include <cmath>
// Vector 2D cartesiano - única estructura de coordenadas del juego.
// Aggregate (sin constructores definidos) para soportar designated initializers:
// Vec2{.x = 1.0F, .y = 2.0F}
// y aggregate initialization clásica:
// Vec2{1.0F, 2.0F}
struct Vec2 {
float x{0.0F};
float y{0.0F};
constexpr auto operator+=(const Vec2& o) -> Vec2& {
x += o.x;
y += o.y;
return *this;
}
constexpr auto operator-=(const Vec2& o) -> Vec2& {
x -= o.x;
y -= o.y;
return *this;
}
constexpr auto operator*=(float s) -> Vec2& {
x *= s;
y *= s;
return *this;
}
constexpr auto operator/=(float s) -> Vec2& {
x /= s;
y /= s;
return *this;
}
[[nodiscard]] auto lengthSquared() const -> float { return (x * x) + (y * y); }
[[nodiscard]] auto length() const -> float { return std::sqrt(lengthSquared()); }
[[nodiscard]] auto dot(const Vec2& o) const -> float { return (x * o.x) + (y * o.y); }
// Devuelve el vector normalizado; si la magnitud es 0 devuelve {0,0}.
[[nodiscard]] auto normalized() const -> Vec2 {
const float L = length();
return L > 0.0F ? Vec2{.x = x / L, .y = y / L} : Vec2{};
}
};
constexpr auto operator+(Vec2 a, const Vec2& b) -> Vec2 {
a += b;
return a;
}
constexpr auto operator-(Vec2 a, const Vec2& b) -> Vec2 {
a -= b;
return a;
}
constexpr auto operator*(Vec2 v, float s) -> Vec2 {
v *= s;
return v;
}
constexpr auto operator*(float s, Vec2 v) -> Vec2 {
v *= s;
return v;
}
constexpr auto operator/(Vec2 v, float s) -> Vec2 {
v /= s;
return v;
}
constexpr auto operator-(const Vec2& v) -> Vec2 { return {.x = -v.x, .y = -v.y}; }
constexpr auto operator==(const Vec2& a, const Vec2& b) -> bool {
return a.x == b.x && a.y == b.y;
}
+3 -3
View File
@@ -10,11 +10,11 @@ namespace Effects {
// Representa un fragment d'una forma destruïda (nau, enemic, bala)
struct Debris {
// Geometria del segment (2 punts en coordenades mundials)
Punt p1; // Punt inicial del segment
Punt p2; // Punt final del segment
Vec2 p1; // Vec2 inicial del segment
Vec2 p2; // Vec2 final del segment
// Física
Punt velocitat; // Velocitat en px/s (components x, y)
Vec2 velocitat; // Velocitat en px/s (components x, y)
float acceleracio; // Acceleració negativa (fricció) en px/s²
// Rotació
+12 -12
View File
@@ -16,7 +16,7 @@ namespace Effects {
// Helper: transformar punt amb rotació, escala i trasllació
// (Copiat de shape_renderer.cpp:12-34)
static Punt transform_point(const Punt& point, const Punt& shape_centre, const Punt& posicio, float angle, float escala) {
static Vec2 transform_point(const Vec2& point, const Vec2& shape_centre, const Vec2& posicio, float angle, float escala) {
// 1. Centrar el punt respecte al centre de la forma
float centered_x = point.x - shape_centre.x;
float centered_y = point.y - shape_centre.y;
@@ -45,12 +45,12 @@ DebrisManager::DebrisManager(SDL_Renderer* renderer)
}
void DebrisManager::explotar(const std::shared_ptr<Graphics::Shape>& shape,
const Punt& centre,
const Vec2& centre,
float angle,
float escala,
float velocitat_base,
float brightness,
const Punt& velocitat_objecte,
const Vec2& velocitat_objecte,
float velocitat_angular,
float factor_herencia_visual,
const std::string& sound) {
@@ -62,12 +62,12 @@ void DebrisManager::explotar(const std::shared_ptr<Graphics::Shape>& shape,
Audio::get()->playSound(sound, Audio::Group::GAME);
// Obtenir centre de la forma per a transformacions
const Punt& shape_centre = shape->get_centre();
const Vec2& shape_centre = shape->get_centre();
// Iterar sobre totes les primitives de la forma
for (const auto& primitive : shape->get_primitives()) {
// Processar cada segment de línia
std::vector<std::pair<Punt, Punt>> segments;
std::vector<std::pair<Vec2, Vec2>> segments;
if (primitive.type == Graphics::PrimitiveType::POLYLINE) {
// Polyline: extreure segments consecutius
@@ -84,9 +84,9 @@ void DebrisManager::explotar(const std::shared_ptr<Graphics::Shape>& shape,
// Crear debris per a cada segment
for (const auto& [local_p1, local_p2] : segments) {
// 1. Transformar punts locals → coordenades mundials
Punt world_p1 =
Vec2 world_p1 =
transform_point(local_p1, shape_centre, centre, angle, escala);
Punt world_p2 =
Vec2 world_p2 =
transform_point(local_p2, shape_centre, centre, angle, escala);
// 2. Trobar slot lliure
@@ -101,7 +101,7 @@ void DebrisManager::explotar(const std::shared_ptr<Graphics::Shape>& shape,
debris->p2 = world_p2;
// 4. Calcular direcció d'explosió (radial, des del centre cap a fora)
Punt direccio = calcular_direccio_explosio(world_p1, world_p2, centre);
Vec2 direccio = calcular_direccio_explosio(world_p1, world_p2, centre);
// 5. Velocitat inicial (base ± variació aleatòria + velocitat heretada)
float speed =
@@ -271,7 +271,7 @@ void DebrisManager::actualitzar(float delta_time) {
}
// 3. Calcular centre del segment
Punt centre = {.x = (debris.p1.x + debris.p2.x) / 2.0F,
Vec2 centre = {.x = (debris.p1.x + debris.p2.x) / 2.0F,
.y = (debris.p1.y + debris.p2.y) / 2.0F};
// 4. Actualitzar posició del centre
@@ -327,9 +327,9 @@ Debris* DebrisManager::trobar_slot_lliure() {
return nullptr; // Pool ple
}
Punt DebrisManager::calcular_direccio_explosio(const Punt& p1,
const Punt& p2,
const Punt& centre_objecte) const {
Vec2 DebrisManager::calcular_direccio_explosio(const Vec2& p1,
const Vec2& p2,
const Vec2& centre_objecte) const {
// 1. Calcular centre del segment
float centro_seg_x = (p1.x + p2.x) / 2.0F;
float centro_seg_y = (p1.y + p2.y) / 2.0F;
+3 -3
View File
@@ -31,12 +31,12 @@ class DebrisManager {
// - velocitat_angular: velocitat angular heretada (rad/s, per defecte 0)
// - factor_herencia_visual: factor de herència rotació visual (0.0-1.0, per defecte 0.0)
void explotar(const std::shared_ptr<Graphics::Shape>& shape,
const Punt& centre,
const Vec2& centre,
float angle,
float escala,
float velocitat_base,
float brightness = 1.0F,
const Punt& velocitat_objecte = {.x = 0.0F, .y = 0.0F},
const Vec2& velocitat_objecte = {.x = 0.0F, .y = 0.0F},
float velocitat_angular = 0.0F,
float factor_herencia_visual = 0.0F,
const std::string& sound = Defaults::Sound::EXPLOSION);
@@ -67,7 +67,7 @@ class DebrisManager {
Debris* trobar_slot_lliure();
// Calcular direcció d'explosió (radial, des del centre cap al segment)
[[nodiscard]] Punt calcular_direccio_explosio(const Punt& p1, const Punt& p2, const Punt& centre_objecte) const;
[[nodiscard]] Vec2 calcular_direccio_explosio(const Vec2& p1, const Vec2& p2, const Vec2& centre_objecte) const;
};
} // namespace Effects
@@ -15,7 +15,7 @@ GestorPuntuacioFlotant::GestorPuntuacioFlotant(SDL_Renderer* renderer)
}
}
void GestorPuntuacioFlotant::crear(int punts, const Punt& posicio) {
void GestorPuntuacioFlotant::crear(int punts, const Vec2& posicio) {
// 1. Trobar slot lliure
PuntuacioFlotant* pf = trobar_slot_lliure();
if (pf == nullptr) {
@@ -23,7 +23,7 @@ class GestorPuntuacioFlotant {
// Crear número flotant
// - punts: valor numèric (100, 150, 200)
// - posicio: on apareix (normalment centre d'enemic destruït)
void crear(int punts, const Punt& posicio);
void crear(int punts, const Vec2& posicio);
// Actualitzar tots els números actius
void actualitzar(float delta_time);
+2 -2
View File
@@ -16,10 +16,10 @@ struct PuntuacioFlotant {
std::string text;
// Posició actual (coordenades mundials)
Punt posicio;
Vec2 posicio;
// Animació de moviment
Punt velocitat; // px/s (normalment cap amunt: {0.0f, -30.0f})
Vec2 velocitat; // px/s (normalment cap amunt: {0.0f, -30.0f})
// Animació de fade
float temps_vida; // Temps transcorregut (segons)
+1 -1
View File
@@ -43,7 +43,7 @@ void Bala::inicialitzar() {
grace_timer_ = 0.0F;
}
void Bala::disparar(const Punt& posicio, float angle, uint8_t owner_id) {
void Bala::disparar(const Vec2& posicio, float angle, uint8_t owner_id) {
// Activar bala i posicionar-la a la nau
// Basat en joc_asteroides.cpp línies 188-200
+1 -1
View File
@@ -18,7 +18,7 @@ class Bala : public Entities::Entitat {
Bala(SDL_Renderer* renderer);
void inicialitzar() override;
void disparar(const Punt& posicio, float angle, uint8_t owner_id);
void disparar(const Vec2& posicio, float angle, uint8_t owner_id);
void actualitzar(float delta_time) override;
void dibuixar() const override;
+2 -2
View File
@@ -34,7 +34,7 @@ Enemic::Enemic(SDL_Renderer* renderer)
// Constructor no carrega forma per permetre tipus diferents
}
void Enemic::inicialitzar(TipusEnemic tipus, const Punt* ship_pos) {
void Enemic::inicialitzar(TipusEnemic tipus, const Vec2* ship_pos) {
// Guardar tipus
tipus_ = tipus;
@@ -523,7 +523,7 @@ void Enemic::set_tracking_strength(float strength) {
}
// [NEW] Safe spawn helper - checks if position is away from ship
bool Enemic::intent_spawn_safe(const Punt& ship_pos, float& out_x, float& out_y) {
bool Enemic::intent_spawn_safe(const Vec2& ship_pos, float& out_x, float& out_y) {
// Generate random position within safe bounds
float min_x;
float max_x;
+5 -5
View File
@@ -43,7 +43,7 @@ class Enemic : public Entities::Entitat {
Enemic(SDL_Renderer* renderer);
void inicialitzar() override { inicialitzar(TipusEnemic::PENTAGON, nullptr); }
void inicialitzar(TipusEnemic tipus, const Punt* ship_pos = nullptr);
void inicialitzar(TipusEnemic tipus, const Vec2* ship_pos = nullptr);
void actualitzar(float delta_time) override;
void dibuixar() const override;
@@ -61,14 +61,14 @@ class Enemic : public Entities::Entitat {
// Getters (API pública sense canvis)
void destruir() { esta_ = false; }
[[nodiscard]] float get_drotacio() const { return drotacio_; }
[[nodiscard]] Punt get_velocitat_vector() const {
[[nodiscard]] Vec2 get_velocitat_vector() const {
return {
.x = velocitat_ * std::cos(angle_ - (Constants::PI / 2.0F)),
.y = velocitat_ * std::sin(angle_ - (Constants::PI / 2.0F))};
}
// Set ship position reference for tracking behavior
void set_ship_position(const Punt* ship_pos) { ship_position_ = ship_pos; }
void set_ship_position(const Vec2* ship_pos) { ship_position_ = ship_pos; }
// [NEW] Getters for stage system (base stats)
[[nodiscard]] float get_base_velocity() const;
@@ -102,7 +102,7 @@ class Enemic : public Entities::Entitat {
// [NEW] Behavior state (type-specific)
float tracking_timer_; // For Quadrat: time since last angle update
const Punt* ship_position_; // Pointer to ship position (for tracking)
const Vec2* ship_position_; // Pointer to ship position (for tracking)
float tracking_strength_; // For Quadrat: tracking intensity (0.0-1.5), default 0.5
// [NEW] Invulnerability state
@@ -119,5 +119,5 @@ class Enemic : public Entities::Entitat {
void comportament_quadrat(float delta_time);
void comportament_molinillo(float delta_time);
[[nodiscard]] float calcular_escala_actual() const; // Returns scale with palpitation applied
bool intent_spawn_safe(const Punt& ship_pos, float& out_x, float& out_y);
bool intent_spawn_safe(const Vec2& ship_pos, float& out_x, float& out_y);
};
+1 -1
View File
@@ -36,7 +36,7 @@ Nau::Nau(SDL_Renderer* renderer, const char* shape_file)
}
}
void Nau::inicialitzar(const Punt* spawn_point, bool activar_invulnerabilitat) {
void Nau::inicialitzar(const Vec2* spawn_point, bool activar_invulnerabilitat) {
// Inicialització de la nau (triangle)
// Basat en el codi Pascal original: lines 380-384
// Copiat de joc_asteroides.cpp línies 30-44
+3 -3
View File
@@ -20,7 +20,7 @@ class Nau : public Entities::Entitat {
Nau(SDL_Renderer* renderer, const char* shape_file = "ship.shp");
void inicialitzar() override { inicialitzar(nullptr, false); }
void inicialitzar(const Punt* spawn_point, bool activar_invulnerabilitat = false);
void inicialitzar(const Vec2* spawn_point, bool activar_invulnerabilitat = false);
void processar_input(float delta_time, uint8_t player_id);
void actualitzar(float delta_time) override;
void dibuixar() const override;
@@ -40,14 +40,14 @@ class Nau : public Entities::Entitat {
[[nodiscard]] bool esta_viva() const { return !esta_tocada_; }
[[nodiscard]] bool esta_tocada() const { return esta_tocada_; }
[[nodiscard]] bool es_invulnerable() const { return invulnerable_timer_ > 0.0F; }
[[nodiscard]] Punt get_velocitat_vector() const {
[[nodiscard]] Vec2 get_velocitat_vector() const {
return {
.x = velocitat_ * std::cos(angle_ - (Constants::PI / 2.0F)),
.y = velocitat_ * std::sin(angle_ - (Constants::PI / 2.0F))};
}
// Setters
void set_centre(const Punt& nou_centre) { centre_ = nou_centre; }
void set_centre(const Vec2& nou_centre) { centre_ = nou_centre; }
// Col·lisions (Fase 10)
void marcar_tocada() { esta_tocada_ = true; }
+18 -18
View File
@@ -176,7 +176,7 @@ void EscenaJoc::inicialitzar() {
if (jugador_actiu) {
// Jugador actiu: inicialitzar normalment
Punt spawn_pos = obtenir_punt_spawn(i);
Vec2 spawn_pos = obtenir_punt_spawn(i);
naus_[i].inicialitzar(&spawn_pos, false); // No invulnerability at start
std::cout << "[EscenaJoc] Jugador " << (i + 1) << " inicialitzat\n";
} else {
@@ -326,7 +326,7 @@ void EscenaJoc::actualitzar(float delta_time) {
if (vides_per_jugador_[i] > 0) {
// Respawn ship en spawn position con invulnerabilidad
Punt spawn_pos = obtenir_punt_spawn(i);
Vec2 spawn_pos = obtenir_punt_spawn(i);
naus_[i].inicialitzar(&spawn_pos, true);
itocado_per_jugador_[i] = 0.0F;
} else {
@@ -397,12 +397,12 @@ void EscenaJoc::actualitzar(float delta_time) {
// [MODIFICAT] Animar AMBAS naus con sus progress respectivos
if (config_partida_.jugador1_actiu && ship1_progress < 1.0F) {
Punt pos_p1 = calcular_posicio_nau_init_hud(ship1_progress, 0);
Vec2 pos_p1 = calcular_posicio_nau_init_hud(ship1_progress, 0);
naus_[0].set_centre(pos_p1);
}
if (config_partida_.jugador2_actiu && ship2_progress < 1.0F) {
Punt pos_p2 = calcular_posicio_nau_init_hud(ship2_progress, 1);
Vec2 pos_p2 = calcular_posicio_nau_init_hud(ship2_progress, 1);
naus_[1].set_centre(pos_p2);
}
@@ -708,11 +708,11 @@ void EscenaJoc::tocado(uint8_t player_id) {
naus_[player_id].marcar_tocada();
// Create ship explosion
const Punt& ship_pos = naus_[player_id].get_centre();
const Vec2& ship_pos = naus_[player_id].get_centre();
float ship_angle = naus_[player_id].get_angle();
Punt vel_nau = naus_[player_id].get_velocitat_vector();
Vec2 vel_nau = naus_[player_id].get_velocitat_vector();
// Reduir a 80% la velocitat heretada per la nau (més realista)
Punt vel_nau_80 = {.x = vel_nau.x * 0.8F, .y = vel_nau.y * 0.8F};
Vec2 vel_nau_80 = {.x = vel_nau.x * 0.8F, .y = vel_nau.y * 0.8F};
debris_manager_.explotar(
naus_[player_id].get_forma(), // Ship shape (3 lines)
@@ -855,7 +855,7 @@ void EscenaJoc::dibuixar_marcador_animat(float progress) {
text_.render_centered(text, {.x = centre_x, .y = centre_y_animada}, escala, spacing);
}
Punt EscenaJoc::calcular_posicio_nau_init_hud(float progress, uint8_t player_id) const {
Vec2 EscenaJoc::calcular_posicio_nau_init_hud(float progress, uint8_t player_id) const {
// Animació de la nau pujant des de baix amb easing
// [MODIFICAT] Ambas naves usan ease_out_quad (desfase temporal via INIT/END)
@@ -865,7 +865,7 @@ Punt EscenaJoc::calcular_posicio_nau_init_hud(float progress, uint8_t player_id)
const SDL_FRect& zona = Defaults::Zones::PLAYAREA;
// Calcular posició final segons jugador (reutilitza obtenir_punt_spawn)
Punt spawn_final = obtenir_punt_spawn(player_id);
Vec2 spawn_final = obtenir_punt_spawn(player_id);
float x_final = spawn_final.x;
float y_final = spawn_final.y;
@@ -957,7 +957,7 @@ void EscenaJoc::detectar_col·lisions_bales_enemics() {
if (Physics::check_collision(bala, enemic, AMPLIFIER)) {
// *** COL·LISIÓ DETECTADA ***
const Punt& pos_enemic = enemic.get_centre();
const Vec2& pos_enemic = enemic.get_centre();
// 1. Calculate score for enemy type
int punts = 0;
@@ -984,7 +984,7 @@ void EscenaJoc::detectar_col·lisions_bales_enemics() {
enemic.destruir();
// 2. Crear explosió de fragments
Punt vel_enemic = enemic.get_velocitat_vector();
Vec2 vel_enemic = enemic.get_velocitat_vector();
debris_manager_.explotar(
enemic.get_forma(), // Forma vectorial del pentàgon
pos_enemic, // Posició central
@@ -1174,7 +1174,7 @@ void EscenaJoc::dibuixar_missatge_stage(const std::string& missatge) {
float y = play_area.y + (play_area.h * Defaults::Game::STAGE_MESSAGE_Y_RATIO) - (text_height / 2.0F);
// Render only the partial message (typewriter effect)
Punt pos = {.x = x, .y = y};
Vec2 pos = {.x = x, .y = y};
text_.render(partial_message, pos, escala, spacing);
}
@@ -1182,7 +1182,7 @@ void EscenaJoc::dibuixar_missatge_stage(const std::string& missatge) {
// Helper methods for 2-player support
// ========================================
Punt EscenaJoc::obtenir_punt_spawn(uint8_t player_id) const {
Vec2 EscenaJoc::obtenir_punt_spawn(uint8_t player_id) const {
const SDL_FRect& zona = Defaults::Zones::PLAYAREA;
float x_ratio;
@@ -1211,7 +1211,7 @@ void EscenaJoc::disparar_bala(uint8_t player_id) {
}
// Calcular posición en la punta de la nave
const Punt& ship_centre = naus_[player_id].get_centre();
const Vec2& ship_centre = naus_[player_id].get_centre();
float ship_angle = naus_[player_id].get_angle();
constexpr float LOCAL_TIP_X = 0.0F;
@@ -1220,7 +1220,7 @@ void EscenaJoc::disparar_bala(uint8_t player_id) {
float sin_a = std::sin(ship_angle);
float tip_x = (LOCAL_TIP_X * cos_a) - (LOCAL_TIP_Y * sin_a) + ship_centre.x;
float tip_y = (LOCAL_TIP_X * sin_a) + (LOCAL_TIP_Y * cos_a) + ship_centre.y;
Punt posicio_dispar = {.x = tip_x, .y = tip_y};
Vec2 posicio_dispar = {.x = tip_x, .y = tip_y};
// Buscar primera bala inactiva en el pool del jugador
int start_idx = player_id * 3; // P1=[0,1,2], P2=[3,4,5]
@@ -1295,7 +1295,7 @@ void EscenaJoc::processar_input_continue() {
}
// Spawn with invulnerability
Punt spawn_pos = obtenir_punt_spawn(player_to_revive);
Vec2 spawn_pos = obtenir_punt_spawn(player_to_revive);
naus_[player_to_revive].inicialitzar(&spawn_pos, true);
// Check if other player wants to continue too
@@ -1305,7 +1305,7 @@ void EscenaJoc::processar_input_continue() {
vides_per_jugador_[other_player] = Defaults::Game::STARTING_LIVES;
itocado_per_jugador_[other_player] = 0.0F;
config_partida_.jugador2_actiu = true;
Punt spawn_pos2 = obtenir_punt_spawn(other_player);
Vec2 spawn_pos2 = obtenir_punt_spawn(other_player);
naus_[other_player].inicialitzar(&spawn_pos2, true);
}
@@ -1391,7 +1391,7 @@ void EscenaJoc::unir_jugador(uint8_t player_id) {
itocado_per_jugador_[player_id] = 0.0F;
// Spawn with invulnerability
Punt spawn_pos = obtenir_punt_spawn(player_id);
Vec2 spawn_pos = obtenir_punt_spawn(player_id);
naus_[player_id].inicialitzar(&spawn_pos, true);
// No visual message, just spawn (per user requirement)
+3 -3
View File
@@ -64,7 +64,7 @@ class EscenaJoc {
float continue_tick_timer_; // Timer for countdown tick (1.0s)
int continues_usados_; // Continues used this game (0-3 max)
float game_over_timer_; // Final GAME OVER timer before title screen
Punt punt_mort_; // Death position (for respawn)
Vec2 punt_mort_; // Death position (for respawn)
std::array<int, 2> puntuacio_per_jugador_; // [0]=P1, [1]=P2
// Text vectorial
@@ -85,7 +85,7 @@ class EscenaJoc {
void dibuixar_marges() const; // Dibuixar vores de la zona de joc
void dibuixar_marcador(); // Dibuixar marcador de puntuació
void disparar_bala(uint8_t player_id); // Shoot bullet from player
[[nodiscard]] Punt obtenir_punt_spawn(uint8_t player_id) const; // Get spawn position for player
[[nodiscard]] Vec2 obtenir_punt_spawn(uint8_t player_id) const; // Get spawn position for player
// [NEW] Continue & Join system
void unir_jugador(uint8_t player_id); // Join inactive player mid-game
@@ -100,7 +100,7 @@ class EscenaJoc {
// [NEW] Funcions d'animació per INIT_HUD
void dibuixar_marges_animat(float progress) const; // Rectangle amb creixement uniforme
void dibuixar_marcador_animat(float progress); // Marcador que puja des de baix
[[nodiscard]] Punt calcular_posicio_nau_init_hud(float progress, uint8_t player_id) const; // Posició animada de la nau
[[nodiscard]] Vec2 calcular_posicio_nau_init_hud(float progress, uint8_t player_id) const; // Posició animada de la nau
// [NEW] Función helper del sistema de animación INIT_HUD
[[nodiscard]] float calcular_progress_rango(float global_progress, float ratio_init, float ratio_end) const;
+2 -2
View File
@@ -347,7 +347,7 @@ void EscenaLogo::dibuixar() {
? std::min(temps_estat_actual_ / DURACIO_ZOOM, 1.0F)
: 1.0F; // POST: mantenir al 100%
const Punt ORIGEN_ZOOM = {.x = ORIGEN_ZOOM_X, .y = ORIGEN_ZOOM_Y};
const Vec2 ORIGEN_ZOOM = {.x = ORIGEN_ZOOM_X, .y = ORIGEN_ZOOM_Y};
for (size_t i = 0; i < lletres_.size(); i++) {
const auto& lletra = lletres_[i];
@@ -362,7 +362,7 @@ void EscenaLogo::dibuixar() {
continue;
}
Punt pos_actual;
Vec2 pos_actual;
pos_actual.x =
ORIGEN_ZOOM.x + ((lletra.posicio.x - ORIGEN_ZOOM.x) * letra_progress);
pos_actual.y =
+3 -3
View File
@@ -51,7 +51,7 @@ class EscenaLogo {
// Estructura per a cada lletra del logo
struct LetraLogo {
std::shared_ptr<Graphics::Shape> forma;
Punt posicio; // Posició final en pantalla
Vec2 posicio; // Posició final en pantalla
float ancho; // Ancho del bounding box
float offset_centre; // Distància de min_x a shape_centre.x
};
@@ -74,8 +74,8 @@ class EscenaLogo {
// Constants d'animació seqüencial
static constexpr float THRESHOLD_LETRA = 0.6F; // Umbral per activar següent lletra (0.0-1.0)
static constexpr float ORIGEN_ZOOM_X = Defaults::Game::WIDTH * 0.5F; // Punt inicial X del zoom
static constexpr float ORIGEN_ZOOM_Y = Defaults::Game::HEIGHT * 0.4F; // Punt inicial Y del zoom
static constexpr float ORIGEN_ZOOM_X = Defaults::Game::WIDTH * 0.5F; // Vec2 inicial X del zoom
static constexpr float ORIGEN_ZOOM_Y = Defaults::Game::HEIGHT * 0.4F; // Vec2 inicial Y del zoom
// Mètodes privats
void inicialitzar_lletres();
+3 -3
View File
@@ -51,7 +51,7 @@ EscenaTitol::EscenaTitol(SDLManager& sdl, ContextEscenes& context)
}
// Crear starfield de fons
Punt centre_pantalla{
Vec2 centre_pantalla{
.x = Defaults::Game::WIDTH / 2.0F,
.y = Defaults::Game::HEIGHT / 2.0F};
@@ -583,7 +583,7 @@ void EscenaTitol::dibuixar() {
// Ombra "ORNI"
for (size_t i = 0; i < lletres_orni_.size(); ++i) {
Punt pos_shadow;
Vec2 pos_shadow;
pos_shadow.x = posicions_originals_orni_[i].x + static_cast<int>(std::round(shadow_offset_x));
pos_shadow.y = posicions_originals_orni_[i].y + static_cast<int>(std::round(shadow_offset_y));
@@ -600,7 +600,7 @@ void EscenaTitol::dibuixar() {
// Ombra "ATTACK!"
for (size_t i = 0; i < lletres_attack_.size(); ++i) {
Punt pos_shadow;
Vec2 pos_shadow;
pos_shadow.x = posicions_originals_attack_[i].x + static_cast<int>(std::round(shadow_offset_x));
pos_shadow.y = posicions_originals_attack_[i].y + static_cast<int>(std::round(shadow_offset_y));
+3 -3
View File
@@ -44,7 +44,7 @@ class EscenaTitol {
// Estructura per emmagatzemar informació de cada lletra del títol
struct LetraLogo {
std::shared_ptr<Graphics::Shape> forma; // Forma vectorial de la lletra
Punt posicio; // Posició en pantalla
Vec2 posicio; // Posició en pantalla
float ancho; // Amplada escalada
float altura; // Altura escalada
float offset_centre; // Offset del centre per posicionament
@@ -66,8 +66,8 @@ class EscenaTitol {
// Estat d'animació del logo
float temps_animacio_; // Temps acumulat per animació orbital
std::vector<Punt> posicions_originals_orni_; // Posicions originals de "ORNI"
std::vector<Punt> posicions_originals_attack_; // Posicions originals de "ATTACK!"
std::vector<Vec2> posicions_originals_orni_; // Posicions originals de "ORNI"
std::vector<Vec2> posicions_originals_attack_; // Posicions originals de "ATTACK!"
// Estat d'arrencada de l'animació
float temps_estat_main_; // Temps acumulat en estat MAIN
@@ -149,7 +149,7 @@ TipusEnemic SpawnController::seleccionar_tipus_aleatori() const {
return TipusEnemic::MOLINILLO;
}
void SpawnController::spawn_enemic(Enemic& enemic, TipusEnemic tipus, const Punt* ship_pos) {
void SpawnController::spawn_enemic(Enemic& enemic, TipusEnemic tipus, const Vec2* ship_pos) {
// Initialize enemy (with safe spawn if ship_pos provided)
enemic.inicialitzar(tipus, ship_pos);
@@ -39,7 +39,7 @@ class SpawnController {
[[nodiscard]] uint8_t get_enemics_spawnejats() const;
// [NEW] Set ship position reference for safe spawn
void set_ship_position(const Punt* ship_pos) { ship_position_ = ship_pos; }
void set_ship_position(const Vec2* ship_pos) { ship_position_ = ship_pos; }
private:
const ConfigStage* config_; // Non-owning pointer to current stage config
@@ -50,9 +50,9 @@ class SpawnController {
// Spawn generation
void generar_spawn_events();
[[nodiscard]] TipusEnemic seleccionar_tipus_aleatori() const;
void spawn_enemic(Enemic& enemic, TipusEnemic tipus, const Punt* ship_pos = nullptr);
void spawn_enemic(Enemic& enemic, TipusEnemic tipus, const Vec2* ship_pos = nullptr);
void aplicar_multiplicadors(Enemic& enemic) const;
const Punt* ship_position_; // [NEW] Non-owning pointer to ship position
const Vec2* ship_position_; // [NEW] Non-owning pointer to ship position
};
} // namespace StageSystem
+3 -3
View File
@@ -232,8 +232,8 @@ void ShipAnimator::actualitzar_exiting(NauTitol& nau, float delta_time) {
// Aplicar easing (ease_in_quad per acceleració cap al punt de fuga)
float eased_progress = Easing::ease_in_quad(progress);
// Punt de fuga (centre del starfield)
constexpr Punt punt_fuga{.x = VANISHING_POINT_X, .y = VANISHING_POINT_Y};
// Vec2 de fuga (centre del starfield)
constexpr Vec2 punt_fuga{.x = VANISHING_POINT_X, .y = VANISHING_POINT_Y};
// Lerp posició cap al punt de fuga (preservar posició inicial actual)
// Nota: posicio_inicial conté la posició on estava quan es va activar EXITING
@@ -320,7 +320,7 @@ void ShipAnimator::configurar_nau_p2(NauTitol& nau) {
nau.visible = true;
}
Punt ShipAnimator::calcular_posicio_fora_pantalla(float angle_rellotge) const {
Vec2 ShipAnimator::calcular_posicio_fora_pantalla(float angle_rellotge) const {
using namespace Defaults::Title::Ships;
// Convertir angle del rellotge a radians (per exemple: 240° per clock 8)
+4 -4
View File
@@ -30,9 +30,9 @@ struct NauTitol {
float temps_estat; // Temps acumulat en l'estat actual
// Posicions
Punt posicio_inicial; // Posició d'inici (fora de pantalla per ENTERING)
Punt posicio_objectiu; // Posició objectiu (rellotge 8 o 4)
Punt posicio_actual; // Posició interpolada actual
Vec2 posicio_inicial; // Posició d'inici (fora de pantalla per ENTERING)
Vec2 posicio_objectiu; // Posició objectiu (rellotge 8 o 4)
Vec2 posicio_actual; // Posició interpolada actual
// Escales (simulació eix Z)
float escala_inicial; // Escala d'inici (més gran = més a prop)
@@ -91,7 +91,7 @@ class ShipAnimator {
// Configuració
void configurar_nau_p1(NauTitol& nau);
void configurar_nau_p2(NauTitol& nau);
[[nodiscard]] Punt calcular_posicio_fora_pantalla(float angle_rellotge) const;
[[nodiscard]] Vec2 calcular_posicio_fora_pantalla(float angle_rellotge) const;
};
} // namespace Title
+1 -1
View File
@@ -1,4 +1,4 @@
// main.cpp - Punt d'entrada del joc Asteroides
// main.cpp - Vec2 d'entrada del joc Asteroides
// © 1999 Visente i Sergi (versió Pascal)
// © 2025 Port a C++20 amb SDL3