treballant en les naus de title

This commit is contained in:
2025-12-16 22:14:55 +01:00
parent 75a4a1b3b9
commit bc5982b286
12 changed files with 946 additions and 19 deletions

View File

@@ -358,6 +358,60 @@ constexpr int MOLINILLO_SCORE = 200; // Molinillo (agressiu, 50 px/s)
} // namespace Enemies
// Title scene ship animations (naus 3D flotants a l'escena de títol)
namespace Title {
namespace Ships {
// Posicions clock (coordenades polars des del centre 320, 240)
// En coordenades de pantalla: 0° = dreta, 90° = baix, 180° = esquerra, 270° = dalt
constexpr float CLOCK_8_ANGLE = 150.0f * Math::PI / 180.0f; // 8 o'clock = bottom-left
constexpr float CLOCK_4_ANGLE = 30.0f * Math::PI / 180.0f; // 4 o'clock = bottom-right
constexpr float CLOCK_RADIUS = 150.0f; // Distància des del centre
// P1 (8 o'clock, bottom-left)
// 150° → cos(150°)=-0.866, sin(150°)=0.5 → X = 320 - 130 = 190, Y = 240 + 75 = 315
constexpr float P1_TARGET_X = 190.0f;
constexpr float P1_TARGET_Y = 315.0f;
// P2 (4 o'clock, bottom-right)
// 30° → cos(30°)=0.866, sin(30°)=0.5 → X = 320 + 130 = 450, Y = 240 + 75 = 315
constexpr float P2_TARGET_X = 450.0f;
constexpr float P2_TARGET_Y = 315.0f;
// Escala base de les naus (ajusta aquí per fer-les més grans o petites)
constexpr float SHIP_BASE_SCALE = 2.5f; // Multiplicador global (1.0 = mida original)
// Escales d'animació (perspectiva ja incorporada a les formes .shp)
constexpr float ENTRY_SCALE_START = 1.5f * SHIP_BASE_SCALE; // Més gran per veure millor
constexpr float FLOATING_SCALE = 1.0f * SHIP_BASE_SCALE; // Mida normal (més grans)
// Animacions
constexpr float ENTRY_DURATION = 2.0f; // Entrada
constexpr float ENTRY_OFFSET = 340.0f; // Offset fora de pantalla (considera radi màxim 30px * escala 3.75 + marge)
constexpr float EXIT_DURATION = 1.0f; // Sortida (configurable)
// Flotació (oscil·lació reduïda i diferenciada per nau)
constexpr float FLOAT_AMPLITUDE_X = 4.0f; // Era 6.0f
constexpr float FLOAT_AMPLITUDE_Y = 2.5f; // Era 4.0f
// Freqüències base
constexpr float FLOAT_FREQUENCY_X_BASE = 0.5f;
constexpr float FLOAT_FREQUENCY_Y_BASE = 0.7f;
constexpr float FLOAT_PHASE_OFFSET = 1.57f; // π/2 (90°)
// Delays d'entrada
constexpr float P1_ENTRY_DELAY = 0.0f; // P1 entra immediatament
constexpr float P2_ENTRY_DELAY = 0.5f; // P2 entra 0.5s després
// Multiplicadors de freqüència per a cada nau (variació sutil ±12%)
constexpr float P1_FREQUENCY_MULTIPLIER = 0.88f; // 12% més lenta
constexpr float P2_FREQUENCY_MULTIPLIER = 1.12f; // 12% més ràpida
// Punt de fuga
constexpr float VANISHING_POINT_X = Game::WIDTH / 2.0f; // 320.0f
constexpr float VANISHING_POINT_Y = Game::HEIGHT / 2.0f; // 240.0f
} // namespace Ships
} // namespace Title
// Floating score numbers (números flotants de puntuació)
namespace FloatingScore {
constexpr float LIFETIME = 2.0f; // Duració màxima (segons)

View File

@@ -10,17 +10,55 @@
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) {
float z = 0.0f; // Tots els punts 2D comencen a Z=0
// Pitch (rotació 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ó eix Y): guiñada esquerra/dreta
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ó 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)
// Naus volen cap al punt de fuga (320, 240) a "infinit" (Z → +∞)
// Z més gran = més lluny = més petit a pantalla
constexpr float perspective_factor = 500.0f;
float scale_factor = perspective_factor / (perspective_factor + z2);
return {x3 * scale_factor, y3 * scale_factor};
}
// 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) {
static Punt transform_point(const Punt& point, const Punt& shape_centre, const Punt& 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 escala al punt centrat
// 2. Aplicar rotació 3D (si es proporciona)
if (rotation_3d && rotation_3d->has_rotation()) {
Punt rotated_3d = apply_3d_rotation(centered_x, centered_y, *rotation_3d);
centered_x = rotated_3d.x;
centered_y = rotated_3d.y;
}
// 3. Aplicar escala al punt (després de rotació 3D)
float scaled_x = centered_x * escala;
float scaled_y = centered_y * escala;
// 3. Aplicar rotació
// 4. Aplicar rotació 2D (Z-axis, tradicional)
// IMPORTANT: En el sistema original, angle=0 apunta AMUNT (no dreta)
// Per això usem (angle - PI/2) per compensar
// Però aquí angle ja ve en el sistema correcte del joc
@@ -30,7 +68,7 @@ static Punt transform_point(const Punt& point, const Punt& shape_centre, const P
float rotated_x = scaled_x * cos_a - scaled_y * sin_a;
float rotated_y = scaled_x * sin_a + scaled_y * cos_a;
// 4. Aplicar trasllació a posició mundial
// 5. Aplicar trasllació a posició mundial
return {rotated_x + posicio.x, rotated_y + posicio.y};
}
@@ -41,7 +79,8 @@ void render_shape(SDL_Renderer* renderer,
float escala,
bool dibuixar,
float progress,
float brightness) {
float brightness,
const Rotation3D* rotation_3d) {
// Verificar que la forma és vàlida
if (!shape || !shape->es_valida()) {
return;
@@ -60,16 +99,16 @@ void render_shape(SDL_Renderer* renderer,
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);
Punt p2 = transform_point(primitive.points[i + 1], shape_centre, posicio, angle, escala);
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);
linea(renderer, static_cast<int>(p1.x), static_cast<int>(p1.y), static_cast<int>(p2.x), static_cast<int>(p2.y), dibuixar, brightness);
}
} else { // PrimitiveType::LINE
// LINE: exactament 2 punts
if (primitive.points.size() >= 2) {
Punt p1 = transform_point(primitive.points[0], shape_centre, posicio, angle, escala);
Punt p2 = transform_point(primitive.points[1], shape_centre, posicio, angle, escala);
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);
linea(renderer, static_cast<int>(p1.x), static_cast<int>(p1.y), static_cast<int>(p2.x), static_cast<int>(p2.y), dibuixar, brightness);
}

View File

@@ -12,6 +12,20 @@
namespace Rendering {
// Estructura per rotacions 3D (pitch, yaw, roll)
struct Rotation3D {
float pitch; // Rotació eix X (cabeceo arriba/baix)
float yaw; // Rotació eix Y (guiñada esquerra/dreta)
float roll; // Rotació 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) {}
bool has_rotation() const {
return pitch != 0.0f || yaw != 0.0f || roll != 0.0f;
}
};
// Renderitzar forma amb transformacions
// - renderer: SDL renderer
// - shape: forma vectorial a dibuixar
@@ -28,6 +42,7 @@ void render_shape(SDL_Renderer* renderer,
float escala = 1.0f,
bool dibuixar = true,
float progress = 1.0f,
float brightness = 1.0f);
float brightness = 1.0f,
const Rotation3D* rotation_3d = nullptr);
} // namespace Rendering