refactor(defaults): centralitza constants de bullet, ship, enemy, hud i notifier
This commit is contained in:
@@ -16,7 +16,9 @@
|
||||
#include "core/defaults/entities.hpp"
|
||||
#include "core/defaults/floating_score.hpp"
|
||||
#include "core/defaults/game.hpp"
|
||||
#include "core/defaults/hud.hpp"
|
||||
#include "core/defaults/math.hpp"
|
||||
#include "core/defaults/notifier.hpp"
|
||||
#include "core/defaults/palette.hpp"
|
||||
#include "core/defaults/physics.hpp"
|
||||
#include "core/defaults/rendering.hpp"
|
||||
|
||||
@@ -7,19 +7,30 @@
|
||||
|
||||
namespace Defaults::Enemies {
|
||||
|
||||
// Cuerpo físico común (valores por defecto del constructor)
|
||||
namespace Body {
|
||||
constexpr float DEFAULT_MASS = 5.0F; // Más liviano que la nave (10.0)
|
||||
constexpr float RESTITUTION = 1.0F; // Rebote elástico perfecto contra paredes
|
||||
constexpr float LINEAR_DAMPING = 0.0F; // Sin fricción: mantienen velocidad
|
||||
constexpr float ANGULAR_DAMPING = 0.0F;
|
||||
} // namespace Body
|
||||
|
||||
// Pentagon (esquivador - zigzag evasion)
|
||||
namespace Pentagon {
|
||||
constexpr float VELOCITAT = 35.0F; // px/s (slightly slower)
|
||||
constexpr float CANVI_ANGLE_PROB = 0.20F; // 20% per wall hit (frequent zigzag)
|
||||
constexpr float CANVI_ANGLE_MAX = 1.0F; // Max random angle change (rad)
|
||||
constexpr float DROTACIO_MIN = 0.75F; // Min visual rotation (rad/s) [+50%]
|
||||
constexpr float DROTACIO_MAX = 3.75F; // Max visual rotation (rad/s) [+50%]
|
||||
constexpr float VELOCITAT = 35.0F; // px/s (slightly slower)
|
||||
constexpr float MASS = 5.0F; // Masa estándar
|
||||
constexpr float CANVI_ANGLE_PROB = 0.20F; // 20% per wall hit (frequent zigzag)
|
||||
constexpr float CANVI_ANGLE_MAX = 1.0F; // Max random angle change (rad)
|
||||
constexpr float ZIGZAG_PROB_PER_SECOND = 0.8F; // Probabilidad de zigzag por segundo
|
||||
constexpr float DROTACIO_MIN = 0.75F; // Min visual rotation (rad/s) [+50%]
|
||||
constexpr float DROTACIO_MAX = 3.75F; // Max visual rotation (rad/s) [+50%]
|
||||
constexpr const char* SHAPE_FILE = "enemy_pentagon.shp";
|
||||
} // namespace Pentagon
|
||||
|
||||
// Cuadrado (perseguidor - tracks player)
|
||||
namespace Cuadrado {
|
||||
constexpr float VELOCITAT = 40.0F; // px/s (medium speed)
|
||||
constexpr float MASS = 8.0F; // Más pesado, "tanque"
|
||||
constexpr float TRACKING_STRENGTH = 0.5F; // Interpolation toward player (0.0-1.0)
|
||||
constexpr float TRACKING_INTERVAL = 1.0F; // Seconds between angle updates
|
||||
constexpr float DROTACIO_MIN = 0.3F; // Slow rotation [+50%]
|
||||
@@ -30,6 +41,7 @@ namespace Defaults::Enemies {
|
||||
// Molinillo (agressiu - fast straight lines, proximity spin-up)
|
||||
namespace Molinillo {
|
||||
constexpr float VELOCITAT = 50.0F; // px/s (fastest)
|
||||
constexpr float MASS = 4.0F; // Más liviano, ágil
|
||||
constexpr float CANVI_ANGLE_PROB = 0.05F; // 5% per wall hit (rare direction change)
|
||||
constexpr float CANVI_ANGLE_MAX = 0.3F; // Small angle adjustments
|
||||
constexpr float DROTACIO_MIN = 3.0F; // Base rotation (rad/s) [+50%]
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace Defaults::Game {
|
||||
constexpr bool FRIENDLY_FIRE_ENABLED = true; // Activar friendly fire
|
||||
constexpr float COLLISION_BULLET_PLAYER_AMPLIFIER = 1.0F; // Hitbox exacto (100%)
|
||||
constexpr float BULLET_GRACE_PERIOD = 0.2F; // Inmunidad post-disparo (s)
|
||||
constexpr float BULLET_SPEED = 140.0F; // Velocidad escalar (px/s). Pascal: 7 px/frame × 20 FPS
|
||||
|
||||
// Transición LEVEL_START (mensajes aleatorios PRE-level)
|
||||
constexpr float LEVEL_START_DURATION = 3.0F; // Duración total
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// hud.hpp - Configuració visual del HUD (marcador, etc.)
|
||||
// © 2026 JailDesigner
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Defaults::Hud {
|
||||
|
||||
// Marcador (scoreboard inferior). Usado por GameScene::drawScoreboard()
|
||||
// y por la animación de entrada en init_hud_animator.
|
||||
constexpr float SCOREBOARD_TEXT_SCALE = 0.85F;
|
||||
constexpr float SCOREBOARD_TEXT_SPACING = 0.0F;
|
||||
|
||||
} // namespace Defaults::Hud
|
||||
@@ -0,0 +1,31 @@
|
||||
// notifier.hpp - Configuració del cuadre de notificacions toast (System::Notifier)
|
||||
// © 2026 JailDesigner
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
namespace Defaults::Notifier {
|
||||
|
||||
// Geometria del cuadre en coordenades lògiques (1280×720).
|
||||
constexpr float CANVAS_WIDTH = 1280.0F;
|
||||
constexpr float MARGIN_TOP = 40.0F;
|
||||
constexpr float PADDING_H = 16.0F;
|
||||
constexpr float PADDING_V = 10.0F;
|
||||
constexpr float BORDER_THICKNESS = 2.0F;
|
||||
constexpr float TEXT_SCALE = 0.55F;
|
||||
constexpr float TEXT_SPACING = 2.0F;
|
||||
constexpr float BORDER_BRIGHTNESS = 1.0F;
|
||||
|
||||
// Cinemàtica del slide.
|
||||
constexpr float SLIDE_DURATION_S = 0.30F;
|
||||
|
||||
// Presets per als atajos semàntics.
|
||||
constexpr SDL_Color COLOR_INFO{.r = 80, .g = 230, .b = 255, .a = 255};
|
||||
constexpr SDL_Color COLOR_WARN{.r = 255, .g = 180, .b = 40, .a = 255};
|
||||
constexpr SDL_Color COLOR_EXIT{.r = 255, .g = 80, .b = 80, .a = 255};
|
||||
constexpr float DURATION_INFO = 2.0F;
|
||||
constexpr float DURATION_WARN = 3.0F;
|
||||
constexpr float DURATION_EXIT = 3.0F;
|
||||
|
||||
} // namespace Defaults::Notifier
|
||||
@@ -13,4 +13,15 @@ namespace Defaults::Ship {
|
||||
constexpr float BLINK_INVISIBLE_TIME = 0.1F; // Tiempo invisible (segundos)
|
||||
// Frecuencia total: 0.2s/ciclo = 5 Hz (~15 parpadeos en 3s)
|
||||
|
||||
// Cuerpo físico
|
||||
constexpr float MASS = 10.0F; // Masa de referencia para choques
|
||||
constexpr float RESTITUTION = 0.6F; // Rebote moderado contra paredes
|
||||
constexpr float LINEAR_DAMPING = 1.5F; // Fricción exponencial (s⁻¹)
|
||||
constexpr float ANGULAR_DAMPING = 0.0F; // Rotación 100% por input (no inercial)
|
||||
|
||||
// Empuje visual: escala proporcional a la velocidad (0..200 px/s → 1.0..1.5)
|
||||
// Mantiene la sensación del Pascal original.
|
||||
constexpr float VISUAL_PUSH_DIVISOR = 33.33F; // SPEED / DIVISOR = empuje visual
|
||||
constexpr float VISUAL_SCALE_DIVISOR = 12.0F; // SCALE = 1 + (PUSH / DIVISOR)
|
||||
|
||||
} // namespace Defaults::Ship
|
||||
|
||||
@@ -2,24 +2,15 @@
|
||||
|
||||
#include "core/system/notifier.hpp"
|
||||
|
||||
#include "core/defaults.hpp"
|
||||
#include "core/rendering/gpu/gpu_frame_renderer.hpp"
|
||||
#include "core/utils/easing.hpp"
|
||||
|
||||
namespace System {
|
||||
|
||||
namespace {
|
||||
// Geometria del cuadre en coordenades lògiques (1280×720).
|
||||
constexpr float CANVAS_WIDTH = 1280.0F;
|
||||
constexpr float MARGIN_TOP = 40.0F;
|
||||
constexpr float PADDING_H = 16.0F;
|
||||
constexpr float PADDING_V = 10.0F;
|
||||
constexpr float BORDER_THICKNESS = 2.0F;
|
||||
constexpr float TEXT_SCALE = 0.55F;
|
||||
constexpr float TEXT_SPACING = 2.0F;
|
||||
constexpr float BORDER_BRIGHTNESS = 1.0F;
|
||||
|
||||
// Cinemàtica del slide.
|
||||
constexpr float SLIDE_DURATION_S = 0.30F;
|
||||
// Alias d'àmbit local per accedir compactament als defaults del notifier.
|
||||
namespace Cfg = Defaults::Notifier;
|
||||
|
||||
// Conversió color SDL → float [0,1].
|
||||
constexpr auto toUnit(Uint8 v) -> float {
|
||||
@@ -47,14 +38,6 @@ namespace System {
|
||||
.b = toUnit(c.b) * DARKEN,
|
||||
.a = BG_ALPHA};
|
||||
}
|
||||
|
||||
// Presets per als atajos semàntics.
|
||||
constexpr SDL_Color COLOR_INFO{.r = 80, .g = 230, .b = 255, .a = 255};
|
||||
constexpr SDL_Color COLOR_WARN{.r = 255, .g = 180, .b = 40, .a = 255};
|
||||
constexpr SDL_Color COLOR_EXIT{.r = 255, .g = 80, .b = 80, .a = 255};
|
||||
constexpr float DURATION_INFO = 2.0F;
|
||||
constexpr float DURATION_WARN = 3.0F;
|
||||
constexpr float DURATION_EXIT = 3.0F;
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<Notifier> Notifier::instance;
|
||||
@@ -79,15 +62,15 @@ namespace System {
|
||||
hold_remaining_s_ = duration_s;
|
||||
current_is_exit_ = false;
|
||||
|
||||
const float TEXT_W = Graphics::VectorText::getTextWidth(text, TEXT_SCALE, TEXT_SPACING);
|
||||
const float TEXT_H = Graphics::VectorText::getTextHeight(TEXT_SCALE);
|
||||
const float TEXT_W = Graphics::VectorText::getTextWidth(text, Cfg::TEXT_SCALE, Cfg::TEXT_SPACING);
|
||||
const float TEXT_H = Graphics::VectorText::getTextHeight(Cfg::TEXT_SCALE);
|
||||
|
||||
box_w_ = TEXT_W + (PADDING_H * 2.0F);
|
||||
box_h_ = TEXT_H + (PADDING_V * 2.0F);
|
||||
text_x_ = (CANVAS_WIDTH - TEXT_W) * 0.5F;
|
||||
box_w_ = TEXT_W + (Cfg::PADDING_H * 2.0F);
|
||||
box_h_ = TEXT_H + (Cfg::PADDING_V * 2.0F);
|
||||
text_x_ = (Cfg::CANVAS_WIDTH - TEXT_W) * 0.5F;
|
||||
|
||||
y_on_ = MARGIN_TOP;
|
||||
y_off_ = -(box_h_ + BORDER_THICKNESS);
|
||||
y_on_ = Cfg::MARGIN_TOP;
|
||||
y_off_ = -(box_h_ + Cfg::BORDER_THICKNESS);
|
||||
|
||||
// Si ja es veu, reseteja el slide-in des de la posició actual perquè
|
||||
// la transició sembli continua. Si està amagat, arrenc des de fora.
|
||||
@@ -96,13 +79,13 @@ namespace System {
|
||||
}
|
||||
status_ = Status::ENTERING;
|
||||
slide_elapsed_s_ = 0.0F;
|
||||
text_scale_ = TEXT_SCALE;
|
||||
text_scale_ = Cfg::TEXT_SCALE;
|
||||
}
|
||||
|
||||
void Notifier::notifyInfo(const std::string& text) { notify(text, COLOR_INFO, DURATION_INFO); }
|
||||
void Notifier::notifyWarn(const std::string& text) { notify(text, COLOR_WARN, DURATION_WARN); }
|
||||
void Notifier::notifyInfo(const std::string& text) { notify(text, Cfg::COLOR_INFO, Cfg::DURATION_INFO); }
|
||||
void Notifier::notifyWarn(const std::string& text) { notify(text, Cfg::COLOR_WARN, Cfg::DURATION_WARN); }
|
||||
void Notifier::notifyExit(const std::string& text) {
|
||||
notify(text, COLOR_EXIT, DURATION_EXIT);
|
||||
notify(text, Cfg::COLOR_EXIT, Cfg::DURATION_EXIT);
|
||||
current_is_exit_ = true; // notify() ho ha posat a false; restaurem.
|
||||
}
|
||||
|
||||
@@ -110,12 +93,12 @@ namespace System {
|
||||
switch (status_) {
|
||||
case Status::ENTERING: {
|
||||
slide_elapsed_s_ += delta_time;
|
||||
if (slide_elapsed_s_ >= SLIDE_DURATION_S) {
|
||||
if (slide_elapsed_s_ >= Cfg::SLIDE_DURATION_S) {
|
||||
y_current_ = y_on_;
|
||||
status_ = Status::HOLDING;
|
||||
slide_elapsed_s_ = 0.0F;
|
||||
} else {
|
||||
const float T = slide_elapsed_s_ / SLIDE_DURATION_S;
|
||||
const float T = slide_elapsed_s_ / Cfg::SLIDE_DURATION_S;
|
||||
const float K = Utils::Easing::outCubic(T);
|
||||
y_current_ = y_off_ + ((y_on_ - y_off_) * K);
|
||||
}
|
||||
@@ -131,11 +114,11 @@ namespace System {
|
||||
}
|
||||
case Status::EXITING: {
|
||||
slide_elapsed_s_ += delta_time;
|
||||
if (slide_elapsed_s_ >= SLIDE_DURATION_S) {
|
||||
if (slide_elapsed_s_ >= Cfg::SLIDE_DURATION_S) {
|
||||
y_current_ = y_off_;
|
||||
status_ = Status::HIDDEN;
|
||||
} else {
|
||||
const float T = slide_elapsed_s_ / SLIDE_DURATION_S;
|
||||
const float T = slide_elapsed_s_ / Cfg::SLIDE_DURATION_S;
|
||||
const float K = Utils::Easing::inCubic(T);
|
||||
y_current_ = y_on_ + ((y_off_ - y_on_) * K);
|
||||
}
|
||||
@@ -152,7 +135,7 @@ namespace System {
|
||||
return;
|
||||
}
|
||||
|
||||
const float BOX_X = (CANVAS_WIDTH - box_w_) * 0.5F;
|
||||
const float BOX_X = (Cfg::CANVAS_WIDTH - box_w_) * 0.5F;
|
||||
const float BOX_Y = y_current_;
|
||||
const UnitRGBA TC = textColorFloat(current_color_);
|
||||
const UnitRGBA BG = bgColorFloat(current_color_);
|
||||
@@ -167,19 +150,19 @@ namespace System {
|
||||
const float Y1 = BOX_Y;
|
||||
const float X2 = BOX_X + box_w_;
|
||||
const float Y2 = BOX_Y + box_h_;
|
||||
gpu->pushLine(X1, Y1, X2, Y1, BORDER_THICKNESS, TC.r, TC.g, TC.b, TC.a); // top
|
||||
gpu->pushLine(X1, Y2, X2, Y2, BORDER_THICKNESS, TC.r, TC.g, TC.b, TC.a); // bottom
|
||||
gpu->pushLine(X1, Y1, X1, Y2, BORDER_THICKNESS, TC.r, TC.g, TC.b, TC.a); // left
|
||||
gpu->pushLine(X2, Y1, X2, Y2, BORDER_THICKNESS, TC.r, TC.g, TC.b, TC.a); // right
|
||||
gpu->pushLine(X1, Y1, X2, Y1, Cfg::BORDER_THICKNESS, TC.r, TC.g, TC.b, TC.a); // top
|
||||
gpu->pushLine(X1, Y2, X2, Y2, Cfg::BORDER_THICKNESS, TC.r, TC.g, TC.b, TC.a); // bottom
|
||||
gpu->pushLine(X1, Y1, X1, Y2, Cfg::BORDER_THICKNESS, TC.r, TC.g, TC.b, TC.a); // left
|
||||
gpu->pushLine(X2, Y1, X2, Y2, Cfg::BORDER_THICKNESS, TC.r, TC.g, TC.b, TC.a); // right
|
||||
|
||||
// 3. Text centrat dins la caixa, amb color explícit (l'alpha != 0
|
||||
// li diu al renderShape que no agafe l'oscil·lador global de color).
|
||||
const float TEXT_Y = BOX_Y + PADDING_V;
|
||||
const float TEXT_Y = BOX_Y + Cfg::PADDING_V;
|
||||
text_.render(current_text_,
|
||||
Vec2{.x = text_x_, .y = TEXT_Y},
|
||||
text_scale_,
|
||||
TEXT_SPACING,
|
||||
BORDER_BRIGHTNESS,
|
||||
Cfg::TEXT_SPACING,
|
||||
Cfg::BORDER_BRIGHTNESS,
|
||||
current_color_);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,6 @@
|
||||
#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
|
||||
@@ -80,7 +74,7 @@ void Bullet::disparar(const Vec2& position, float angle, uint8_t owner_id) {
|
||||
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_.velocity = Vec2{.x = DIR_X * Defaults::Game::BULLET_SPEED, .y = DIR_Y * Defaults::Game::BULLET_SPEED};
|
||||
body_.angular_velocity = 0.0F;
|
||||
body_.clearAccumulators();
|
||||
|
||||
|
||||
@@ -41,16 +41,16 @@ namespace {
|
||||
Enemy::Enemy(Rendering::Renderer* renderer)
|
||||
: Entity(renderer),
|
||||
|
||||
tracking_strength_(0.5F) {
|
||||
tracking_strength_(Defaults::Enemies::Cuadrado::TRACKING_STRENGTH) {
|
||||
brightness_ = Defaults::Brightness::ENEMIC;
|
||||
|
||||
// Configuración del cuerpo físico — defaults para enemy genérico.
|
||||
// init() ajusta velocidad y masa según el tipo (Pentagon/Quadrat/Molinillo).
|
||||
body_.setMass(5.0F); // Más liviano que la nave (10.0)
|
||||
body_.radius = 0.0F; // 0 hasta spawn (no colisiona inactivo)
|
||||
body_.restitution = 1.0F; // Rebote elástico perfecto contra paredes
|
||||
body_.linear_damping = 0.0F; // Sin fricción: mantienen velocidad
|
||||
body_.angular_damping = 0.0F; // Idem
|
||||
body_.setMass(Defaults::Enemies::Body::DEFAULT_MASS);
|
||||
body_.radius = 0.0F; // 0 hasta spawn (no colisiona inactivo)
|
||||
body_.restitution = Defaults::Enemies::Body::RESTITUTION;
|
||||
body_.linear_damping = Defaults::Enemies::Body::LINEAR_DAMPING;
|
||||
body_.angular_damping = Defaults::Enemies::Body::ANGULAR_DAMPING;
|
||||
}
|
||||
|
||||
void Enemy::init(EnemyType type, const Vec2* ship_pos) {
|
||||
@@ -60,7 +60,7 @@ void Enemy::init(EnemyType type, const Vec2* ship_pos) {
|
||||
float base_speed = 0.0F;
|
||||
float drotacio_min = 0.0F;
|
||||
float drotacio_max = 0.0F;
|
||||
float type_mass = 5.0F;
|
||||
float type_mass = Defaults::Enemies::Body::DEFAULT_MASS;
|
||||
|
||||
switch (type_) {
|
||||
case EnemyType::PENTAGON:
|
||||
@@ -68,7 +68,7 @@ void Enemy::init(EnemyType type, const Vec2* ship_pos) {
|
||||
base_speed = Defaults::Enemies::Pentagon::VELOCITAT;
|
||||
drotacio_min = Defaults::Enemies::Pentagon::DROTACIO_MIN;
|
||||
drotacio_max = Defaults::Enemies::Pentagon::DROTACIO_MAX;
|
||||
type_mass = 5.0F;
|
||||
type_mass = Defaults::Enemies::Pentagon::MASS;
|
||||
break;
|
||||
|
||||
case EnemyType::QUADRAT:
|
||||
@@ -76,7 +76,7 @@ void Enemy::init(EnemyType type, const Vec2* ship_pos) {
|
||||
base_speed = Defaults::Enemies::Cuadrado::VELOCITAT;
|
||||
drotacio_min = Defaults::Enemies::Cuadrado::DROTACIO_MIN;
|
||||
drotacio_max = Defaults::Enemies::Cuadrado::DROTACIO_MAX;
|
||||
type_mass = 8.0F; // Más pesado, "tanque"
|
||||
type_mass = Defaults::Enemies::Cuadrado::MASS;
|
||||
tracking_timer_ = 0.0F;
|
||||
break;
|
||||
|
||||
@@ -85,7 +85,7 @@ void Enemy::init(EnemyType type, const Vec2* ship_pos) {
|
||||
base_speed = Defaults::Enemies::Molinillo::VELOCITAT;
|
||||
drotacio_min = Defaults::Enemies::Molinillo::DROTACIO_MIN;
|
||||
drotacio_max = Defaults::Enemies::Molinillo::DROTACIO_MAX;
|
||||
type_mass = 4.0F; // Más liviano, ágil
|
||||
type_mass = Defaults::Enemies::Molinillo::MASS;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -268,9 +268,8 @@ void Enemy::behaviorPentagon(float delta_time) {
|
||||
|
||||
// Probabilidad de zigzag por segundo (calibrada para sensación equivalente
|
||||
// a la versión vieja que disparaba en cada toque de pared).
|
||||
constexpr float ZIGZAG_PROB_PER_SECOND = 0.8F;
|
||||
const float RAND_VAL = static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX);
|
||||
if (RAND_VAL < ZIGZAG_PROB_PER_SECOND * delta_time) {
|
||||
if (RAND_VAL < Defaults::Enemies::Pentagon::ZIGZAG_PROB_PER_SECOND * delta_time) {
|
||||
const float CURRENT_ANGLE = velocityToAngle(body_.velocity);
|
||||
const float DELTA = (static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX)) *
|
||||
Defaults::Enemies::Pentagon::CANVI_ANGLE_MAX;
|
||||
|
||||
@@ -25,11 +25,11 @@ Ship::Ship(Rendering::Renderer* renderer, const char* shape_file)
|
||||
brightness_ = Defaults::Brightness::NAU;
|
||||
|
||||
// Configuración del cuerpo físico
|
||||
body_.setMass(10.0F); // Masa de referencia para choques
|
||||
body_.radius = Defaults::Entities::SHIP_RADIUS; // Radio de colisión
|
||||
body_.restitution = 0.6F; // Rebote moderado contra paredes
|
||||
body_.linear_damping = 1.5F; // Fricción exponencial (s⁻¹)
|
||||
body_.angular_damping = 0.0F; // La rotación es 100% por input, no inercial
|
||||
body_.setMass(Defaults::Ship::MASS);
|
||||
body_.radius = Defaults::Entities::SHIP_RADIUS;
|
||||
body_.restitution = Defaults::Ship::RESTITUTION;
|
||||
body_.linear_damping = Defaults::Ship::LINEAR_DAMPING;
|
||||
body_.angular_damping = Defaults::Ship::ANGULAR_DAMPING;
|
||||
|
||||
// Cargar shape compartida desde archivo
|
||||
shape_ = Graphics::ShapeLoader::load(shape_file);
|
||||
@@ -154,8 +154,8 @@ void Ship::draw() const {
|
||||
// Efecto visual de empuje: escala proporcional a la velocidad.
|
||||
// 0..200 px/s → escala 1.0..1.5 (manteniendo la sensación del Pascal original).
|
||||
const float SPEED = getSpeed();
|
||||
const float VISUAL_PUSH = SPEED / 33.33F;
|
||||
const float SCALE = 1.0F + (VISUAL_PUSH / 12.0F);
|
||||
const float VISUAL_PUSH = SPEED / Defaults::Ship::VISUAL_PUSH_DIVISOR;
|
||||
const float SCALE = 1.0F + (VISUAL_PUSH / Defaults::Ship::VISUAL_SCALE_DIVISOR);
|
||||
|
||||
Rendering::renderShape(renderer_, shape_, center_, angle_, SCALE, 1.0F, brightness_, Defaults::Palette::SHIP);
|
||||
}
|
||||
|
||||
@@ -674,8 +674,8 @@ void GameScene::drawScoreboard() {
|
||||
std::string text = buildScoreboard();
|
||||
|
||||
// Parámetros de renderització
|
||||
const float SCALE = 0.85F;
|
||||
const float SPACING = 0.0F;
|
||||
const float SCALE = Defaults::Hud::SCOREBOARD_TEXT_SCALE;
|
||||
const float SPACING = Defaults::Hud::SCOREBOARD_TEXT_SPACING;
|
||||
|
||||
// Calcular centro de la zona del marcador
|
||||
const SDL_FRect& scoreboard_zone = Defaults::Zones::SCOREBOARD;
|
||||
|
||||
@@ -13,87 +13,88 @@
|
||||
|
||||
namespace Systems::InitHud {
|
||||
|
||||
auto computeRangeProgress(float global_progress,
|
||||
float ratio_init,
|
||||
float ratio_end) -> float {
|
||||
if (ratio_init >= ratio_end) {
|
||||
return (global_progress >= ratio_end) ? 1.0F : 0.0F;
|
||||
}
|
||||
if (global_progress < ratio_init) {
|
||||
return 0.0F;
|
||||
}
|
||||
if (global_progress > ratio_end) {
|
||||
return 1.0F;
|
||||
}
|
||||
return (global_progress - ratio_init) / (ratio_end - ratio_init);
|
||||
}
|
||||
|
||||
auto computeShipPosition(float progress, const Vec2& final_position) -> Vec2 {
|
||||
const float EASED = Easing::easeOutQuad(progress);
|
||||
const SDL_FRect& zone = Defaults::Zones::PLAYAREA;
|
||||
// Y inicial: 50 px bajo la zona de juego.
|
||||
const float Y_INI = zone.y + zone.h + 50.0F;
|
||||
const float Y_ANIM = Y_INI + ((final_position.y - Y_INI) * EASED);
|
||||
return Vec2{.x = final_position.x, .y = Y_ANIM};
|
||||
}
|
||||
|
||||
void drawBordersAnimated(Rendering::Renderer* renderer, float progress) {
|
||||
const SDL_FRect& zone = Defaults::Zones::PLAYAREA;
|
||||
const float EASED = Easing::easeOutQuad(progress);
|
||||
|
||||
const int X1 = static_cast<int>(zone.x);
|
||||
const int Y1 = static_cast<int>(zone.y);
|
||||
const int X2 = static_cast<int>(zone.x + zone.w);
|
||||
const int Y2 = static_cast<int>(zone.y + zone.h);
|
||||
const int CX = (X1 + X2) / 2;
|
||||
|
||||
constexpr float PHASE_1_END = 0.33F;
|
||||
constexpr float PHASE_2_END = 0.66F;
|
||||
|
||||
// Fase 1: línea superior crece desde el centro hacia los lados.
|
||||
if (EASED > 0.0F) {
|
||||
const float P = std::min(EASED / PHASE_1_END, 1.0F);
|
||||
const int X_LEFT = static_cast<int>(CX - ((CX - X1) * P));
|
||||
const int X_RIGHT = static_cast<int>(CX + ((X2 - CX) * P));
|
||||
Rendering::linea(renderer, CX, Y1, X_LEFT, Y1);
|
||||
Rendering::linea(renderer, CX, Y1, X_RIGHT, Y1);
|
||||
auto computeRangeProgress(float global_progress,
|
||||
float ratio_init,
|
||||
float ratio_end) -> float {
|
||||
if (ratio_init >= ratio_end) {
|
||||
return (global_progress >= ratio_end) ? 1.0F : 0.0F;
|
||||
}
|
||||
if (global_progress < ratio_init) {
|
||||
return 0.0F;
|
||||
}
|
||||
if (global_progress > ratio_end) {
|
||||
return 1.0F;
|
||||
}
|
||||
return (global_progress - ratio_init) / (ratio_end - ratio_init);
|
||||
}
|
||||
|
||||
// Fase 2: laterales bajan.
|
||||
if (EASED > PHASE_1_END) {
|
||||
const float P = std::min((EASED - PHASE_1_END) / (PHASE_2_END - PHASE_1_END), 1.0F);
|
||||
const int Y_BOTTOM = static_cast<int>(Y1 + ((Y2 - Y1) * P));
|
||||
Rendering::linea(renderer, X1, Y1, X1, Y_BOTTOM);
|
||||
Rendering::linea(renderer, X2, Y1, X2, Y_BOTTOM);
|
||||
auto computeShipPosition(float progress, const Vec2& final_position) -> Vec2 {
|
||||
const float EASED = Easing::easeOutQuad(progress);
|
||||
const SDL_FRect& zone = Defaults::Zones::PLAYAREA;
|
||||
// Y inicial: 50 px bajo la zona de juego.
|
||||
const float Y_INI = zone.y + zone.h + 50.0F;
|
||||
const float Y_ANIM = Y_INI + ((final_position.y - Y_INI) * EASED);
|
||||
return Vec2{.x = final_position.x, .y = Y_ANIM};
|
||||
}
|
||||
|
||||
// Fase 3: línea inferior crece desde los lados hacia el centro.
|
||||
if (EASED > PHASE_2_END) {
|
||||
const float P = (EASED - PHASE_2_END) / (1.0F - PHASE_2_END);
|
||||
const int X_LEFT = static_cast<int>(X1 + ((CX - X1) * P));
|
||||
const int X_RIGHT = static_cast<int>(X2 - ((X2 - CX) * P));
|
||||
Rendering::linea(renderer, X1, Y2, X_LEFT, Y2);
|
||||
Rendering::linea(renderer, X2, Y2, X_RIGHT, Y2);
|
||||
void drawBordersAnimated(Rendering::Renderer* renderer, float progress) {
|
||||
const SDL_FRect& zone = Defaults::Zones::PLAYAREA;
|
||||
const float EASED = Easing::easeOutQuad(progress);
|
||||
|
||||
const int X1 = static_cast<int>(zone.x);
|
||||
const int Y1 = static_cast<int>(zone.y);
|
||||
const int X2 = static_cast<int>(zone.x + zone.w);
|
||||
const int Y2 = static_cast<int>(zone.y + zone.h);
|
||||
const int CX = (X1 + X2) / 2;
|
||||
|
||||
constexpr float PHASE_1_END = 0.33F;
|
||||
constexpr float PHASE_2_END = 0.66F;
|
||||
|
||||
// Fase 1: línea superior crece desde el centro hacia los lados.
|
||||
if (EASED > 0.0F) {
|
||||
const float P = std::min(EASED / PHASE_1_END, 1.0F);
|
||||
const int X_LEFT = static_cast<int>(CX - ((CX - X1) * P));
|
||||
const int X_RIGHT = static_cast<int>(CX + ((X2 - CX) * P));
|
||||
Rendering::linea(renderer, CX, Y1, X_LEFT, Y1);
|
||||
Rendering::linea(renderer, CX, Y1, X_RIGHT, Y1);
|
||||
}
|
||||
|
||||
// Fase 2: laterales bajan.
|
||||
if (EASED > PHASE_1_END) {
|
||||
const float P = std::min((EASED - PHASE_1_END) / (PHASE_2_END - PHASE_1_END), 1.0F);
|
||||
const int Y_BOTTOM = static_cast<int>(Y1 + ((Y2 - Y1) * P));
|
||||
Rendering::linea(renderer, X1, Y1, X1, Y_BOTTOM);
|
||||
Rendering::linea(renderer, X2, Y1, X2, Y_BOTTOM);
|
||||
}
|
||||
|
||||
// Fase 3: línea inferior crece desde los lados hacia el centro.
|
||||
if (EASED > PHASE_2_END) {
|
||||
const float P = (EASED - PHASE_2_END) / (1.0F - PHASE_2_END);
|
||||
const int X_LEFT = static_cast<int>(X1 + ((CX - X1) * P));
|
||||
const int X_RIGHT = static_cast<int>(X2 - ((X2 - CX) * P));
|
||||
Rendering::linea(renderer, X1, Y2, X_LEFT, Y2);
|
||||
Rendering::linea(renderer, X2, Y2, X_RIGHT, Y2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawScoreboardAnimated(const Graphics::VectorText& text,
|
||||
const std::string& scoreboard_text,
|
||||
float progress) {
|
||||
const float EASED = Easing::easeOutQuad(progress);
|
||||
void drawScoreboardAnimated(const Graphics::VectorText& text,
|
||||
const std::string& scoreboard_text,
|
||||
float progress) {
|
||||
const float EASED = Easing::easeOutQuad(progress);
|
||||
|
||||
constexpr float SCALE = 0.85F;
|
||||
constexpr float SPACING = 0.0F;
|
||||
const SDL_FRect& scoreboard_zone = Defaults::Zones::SCOREBOARD;
|
||||
const float CENTRE_X = scoreboard_zone.w / 2.0F;
|
||||
const float Y_FINAL = scoreboard_zone.y + (scoreboard_zone.h / 2.0F);
|
||||
// Posición inicial: fuera de la pantalla por debajo.
|
||||
const auto Y_INI = static_cast<float>(Defaults::Game::HEIGHT);
|
||||
const float Y_ANIM = Y_INI + ((Y_FINAL - Y_INI) * EASED);
|
||||
constexpr float SCALE = Defaults::Hud::SCOREBOARD_TEXT_SCALE;
|
||||
constexpr float SPACING = Defaults::Hud::SCOREBOARD_TEXT_SPACING;
|
||||
const SDL_FRect& scoreboard_zone = Defaults::Zones::SCOREBOARD;
|
||||
const float CENTRE_X = scoreboard_zone.w / 2.0F;
|
||||
const float Y_FINAL = scoreboard_zone.y + (scoreboard_zone.h / 2.0F);
|
||||
// Posición inicial: fuera de la pantalla por debajo.
|
||||
const auto Y_INI = static_cast<float>(Defaults::Game::HEIGHT);
|
||||
const float Y_ANIM = Y_INI + ((Y_FINAL - Y_INI) * EASED);
|
||||
|
||||
text.renderCentered(scoreboard_text,
|
||||
Vec2{.x = CENTRE_X, .y = Y_ANIM},
|
||||
SCALE, SPACING);
|
||||
}
|
||||
text.renderCentered(scoreboard_text,
|
||||
Vec2{.x = CENTRE_X, .y = Y_ANIM},
|
||||
SCALE,
|
||||
SPACING);
|
||||
}
|
||||
|
||||
} // namespace Systems::InitHud
|
||||
|
||||
Reference in New Issue
Block a user