264 lines
10 KiB
C++
264 lines
10 KiB
C++
#pragma once
|
|
|
|
#include <SDL3/SDL.h> // Para Uint8, SDL_FRect, SDL_FPoint, SDL_Renderer
|
|
|
|
#include <algorithm> // Para max, min
|
|
#include <array> // Para array
|
|
#include <cctype> // Para isxdigit
|
|
#include <cstdint> // Para int32_t
|
|
#include <cstdlib> // Para abs, size_t
|
|
#include <stdexcept> // Para invalid_argument
|
|
#include <string> // Para string, basic_string, stoi
|
|
#include <vector> // Para vector
|
|
|
|
// --- Constantes ---
|
|
constexpr int BLOCK = 8;
|
|
constexpr int TOTAL_DEMO_DATA = 2000;
|
|
constexpr size_t COLOR_CYCLE_SIZE = 6; // Mitad del ciclo espejado
|
|
|
|
// --- Estructuras y tipos ---
|
|
struct Overrides {
|
|
std::string param_file; // Fichero de parametros a utilizar
|
|
bool clear_hi_score_table{false}; // Reinicia la tabla de records
|
|
|
|
Overrides() = default;
|
|
};
|
|
extern Overrides overrides;
|
|
|
|
// Estructura para definir un circulo
|
|
struct Circle {
|
|
int x, y, r;
|
|
Circle() : x(0), y(0), r(0) {}
|
|
Circle(int x_coord, int y_coord, int radius)
|
|
: x(x_coord), y(y_coord), r(radius) {}
|
|
};
|
|
|
|
// Estructura para definir un color RGBA
|
|
struct Color {
|
|
private:
|
|
static constexpr Uint8 MAX_COLOR_VALUE = 255;
|
|
static constexpr Uint8 MIN_COLOR_VALUE = 0;
|
|
static constexpr Uint8 DEFAULT_ALPHA = 255;
|
|
static constexpr int DEFAULT_LIGHTEN_AMOUNT = 50;
|
|
static constexpr int DEFAULT_DARKEN_AMOUNT = 50;
|
|
static constexpr int DEFAULT_APPROACH_STEP = 1;
|
|
static constexpr size_t HEX_RGB_LENGTH = 6;
|
|
static constexpr size_t HEX_RGBA_LENGTH = 8;
|
|
static constexpr int HEX_BASE = 16;
|
|
static constexpr size_t HEX_COMPONENT_LENGTH = 2;
|
|
|
|
public:
|
|
Uint8 r, g, b, a;
|
|
|
|
constexpr Color() : r(MIN_COLOR_VALUE), g(MIN_COLOR_VALUE), b(MIN_COLOR_VALUE), a(DEFAULT_ALPHA) {}
|
|
|
|
explicit constexpr Color(Uint8 red, Uint8 green, Uint8 blue, Uint8 alpha = DEFAULT_ALPHA)
|
|
: r(red), g(green), b(blue), a(alpha) {}
|
|
|
|
[[nodiscard]] constexpr auto INVERSE() const -> Color {
|
|
return Color(MAX_COLOR_VALUE - r, MAX_COLOR_VALUE - g, MAX_COLOR_VALUE - b, a);
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto LIGHTEN(int amount = DEFAULT_LIGHTEN_AMOUNT) const -> Color {
|
|
return Color(
|
|
std::min(static_cast<int>(MAX_COLOR_VALUE), r + amount),
|
|
std::min(static_cast<int>(MAX_COLOR_VALUE), g + amount),
|
|
std::min(static_cast<int>(MAX_COLOR_VALUE), b + amount),
|
|
a);
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto DARKEN(int amount = DEFAULT_DARKEN_AMOUNT) const -> Color {
|
|
return Color(
|
|
std::max(static_cast<int>(MIN_COLOR_VALUE), r - amount),
|
|
std::max(static_cast<int>(MIN_COLOR_VALUE), g - amount),
|
|
std::max(static_cast<int>(MIN_COLOR_VALUE), b - amount),
|
|
a);
|
|
}
|
|
|
|
// Método estático para crear Color desde string hexadecimal
|
|
static auto fromHex(const std::string &hex_str) -> Color {
|
|
std::string hex = hex_str;
|
|
|
|
// Quitar '#' si existe
|
|
if (!hex.empty() && hex[0] == '#') {
|
|
hex = hex.substr(1);
|
|
}
|
|
|
|
// Verificar longitud válida (6 para RGB o 8 para RGBA)
|
|
if (hex.length() != HEX_RGB_LENGTH && hex.length() != HEX_RGBA_LENGTH) {
|
|
throw std::invalid_argument("String hexadecimal debe tener 6 o 8 caracteres");
|
|
}
|
|
|
|
// Verificar que todos los caracteres sean hexadecimales válidos
|
|
for (char c : hex) {
|
|
if (std::isxdigit(c) == 0) {
|
|
throw std::invalid_argument("String contiene caracteres no hexadecimales");
|
|
}
|
|
}
|
|
|
|
// Convertir cada par de caracteres a valores RGB(A)
|
|
Uint8 r = static_cast<Uint8>(std::stoi(hex.substr(0, HEX_COMPONENT_LENGTH), nullptr, HEX_BASE));
|
|
Uint8 g = static_cast<Uint8>(std::stoi(hex.substr(HEX_COMPONENT_LENGTH, HEX_COMPONENT_LENGTH), nullptr, HEX_BASE));
|
|
Uint8 b = static_cast<Uint8>(std::stoi(hex.substr(HEX_COMPONENT_LENGTH * 2, HEX_COMPONENT_LENGTH), nullptr, HEX_BASE));
|
|
Uint8 a = DEFAULT_ALPHA; // Alpha por defecto
|
|
|
|
// Si tiene 8 caracteres, extraer el alpha
|
|
if (hex.length() == HEX_RGBA_LENGTH) {
|
|
a = static_cast<Uint8>(std::stoi(hex.substr(HEX_COMPONENT_LENGTH * 3, HEX_COMPONENT_LENGTH), nullptr, HEX_BASE));
|
|
}
|
|
|
|
return Color(r, g, b, a);
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto IS_EQUAL_TO(const Color &other) const -> bool {
|
|
return r == other.r && g == other.g && b == other.b && a == other.a;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto APPROACH_TO(const Color &target, int step = DEFAULT_APPROACH_STEP) const -> Color {
|
|
auto approach_component = [step](Uint8 current, Uint8 target_val) -> Uint8 {
|
|
if (std::abs(current - target_val) <= step) {
|
|
return target_val;
|
|
}
|
|
return (current < target_val) ? current + step : current - step;
|
|
};
|
|
|
|
Uint8 new_r = approach_component(r, target.r);
|
|
Uint8 new_g = approach_component(g, target.g);
|
|
Uint8 new_b = approach_component(b, target.b);
|
|
Uint8 new_a = approach_component(a, target.a);
|
|
|
|
return Color(new_r, new_g, new_b, new_a);
|
|
}
|
|
};
|
|
|
|
// Estructura para definir un color HSV
|
|
struct HSV {
|
|
float h, s, v;
|
|
};
|
|
|
|
// Estructura para definir el ciclo de color
|
|
enum class ColorCycleStyle {
|
|
SUBTLE_PULSE, // Variación leve en brillo (por defecto)
|
|
HUE_WAVE, // Variación suave en tono (sin verde)
|
|
VIBRANT, // Cambios agresivos en tono y brillo
|
|
DARKEN_GLOW, // Oscurece hacia el centro y regresa
|
|
LIGHT_FLASH // Ilumina hacia el centro y regresa
|
|
};
|
|
|
|
// Posiciones de las notificaciones
|
|
enum class NotifyPosition {
|
|
TOP,
|
|
BOTTOM,
|
|
LEFT,
|
|
MIDDLE,
|
|
RIGHT,
|
|
};
|
|
|
|
// Estructura para datos de la demo
|
|
struct DemoKeys {
|
|
Uint8 left;
|
|
Uint8 right;
|
|
Uint8 no_input;
|
|
Uint8 fire;
|
|
Uint8 fire_left;
|
|
Uint8 fire_right;
|
|
|
|
explicit DemoKeys(Uint8 l = 0, Uint8 r = 0, Uint8 ni = 0, Uint8 f = 0, Uint8 fl = 0, Uint8 fr = 0)
|
|
: left(l), right(r), no_input(ni), fire(f), fire_left(fl), fire_right(fr) {}
|
|
};
|
|
|
|
using DemoData = std::vector<DemoKeys>;
|
|
|
|
struct Demo {
|
|
bool enabled; // Indica si está activo el modo demo
|
|
bool recording; // Indica si está activado el modo para grabar la demo
|
|
int counter; // Contador para el modo demo
|
|
DemoKeys keys; // Variable con las pulsaciones de teclas del modo demo
|
|
std::vector<DemoData> data; // Vector con diferentes sets de datos con los movimientos para la demo
|
|
|
|
Demo() : enabled(false), recording(false), counter(0) {}
|
|
Demo(bool e, bool r, int c, const DemoKeys &k, const std::vector<DemoData> &d)
|
|
: enabled(e), recording(r), counter(c), keys(k), data(d) {}
|
|
};
|
|
|
|
// Posiciones dentro de un rectangulo
|
|
struct Zone {
|
|
SDL_FRect rect; // Rectangulo que define la zona
|
|
float center_x; // Anclaje al 50% del eje X
|
|
float first_quarter_x; // Anclaje al 25% del eje X
|
|
float third_quarter_x; // Anclaje al 75% del eje X
|
|
float center_y; // Anclaje al 50% del eje Y
|
|
float first_quarter_y; // Anclaje al 25% del eje Y
|
|
float third_quarter_y; // Anclaje al 75% del eje Y
|
|
};
|
|
|
|
// --- Alias ---
|
|
using ColorCycle = std::array<Color, 2 * COLOR_CYCLE_SIZE>;
|
|
|
|
// --- Funciones utilitarias ---
|
|
|
|
// Colores
|
|
constexpr Color NO_TEXT_COLOR = Color(0XFF, 0XFF, 0XFF);
|
|
constexpr Color SHADOW_TEXT_COLOR = Color(0X43, 0X43, 0X4F);
|
|
constexpr Color TITLE_SHADOW_TEXT_COLOR = Color(0x14, 0x87, 0xc4);
|
|
|
|
constexpr Color FLASH_COLOR = Color(0XFF, 0XFF, 0XFF);
|
|
|
|
constexpr Color BLUE_SKY_COLOR = Color(0X02, 0X88, 0XD1);
|
|
constexpr Color PINK_SKY_COLOR = Color(0XFF, 0X6B, 0X97);
|
|
constexpr Color GREEN_SKY_COLOR = Color(0X00, 0X79, 0X6B);
|
|
|
|
// Colores y gráficos
|
|
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color;
|
|
constexpr auto rgbToHsv(Color color) -> HSV;
|
|
constexpr auto hsvToRgb(HSV hsv) -> Color;
|
|
auto generateMirroredCycle(Color base, ColorCycleStyle style = ColorCycleStyle::SUBTLE_PULSE) -> ColorCycle;
|
|
|
|
// Colisiones y geometría
|
|
auto distanceSquared(int x1, int y1, int x2, int y2) -> double;
|
|
auto checkCollision(const Circle &a, const Circle &b) -> bool;
|
|
auto checkCollision(const Circle &a, const SDL_FRect &b) -> bool;
|
|
auto checkCollision(const SDL_FRect &a, const SDL_FRect &b) -> bool;
|
|
auto checkCollision(const SDL_FPoint &p, const SDL_FRect &r) -> bool;
|
|
|
|
// Conversión y manipulación de cadenas
|
|
auto stringToBool(const std::string &str) -> bool;
|
|
auto boolToString(bool value) -> std::string;
|
|
auto boolToOnOff(bool value) -> std::string;
|
|
auto toLower(const std::string &str) -> std::string;
|
|
auto trim(const std::string &str) -> std::string;
|
|
|
|
// Dibujo
|
|
void drawCircle(SDL_Renderer *renderer, int32_t center_x, int32_t center_y, int32_t radius);
|
|
|
|
// Manipulación de color
|
|
auto lightenColor(const Color &color, int amount) -> Color;
|
|
auto darkenColor(const Color &color, int amount) -> Color;
|
|
|
|
// Funciones de suavizado (easing)
|
|
auto easeOutQuint(double time) -> double;
|
|
auto easeInQuint(double time) -> double;
|
|
auto easeInOutQuint(double time) -> double;
|
|
auto easeInQuad(double time) -> double;
|
|
auto easeOutQuad(double time) -> double;
|
|
auto easeInOutSine(double time) -> double;
|
|
auto easeInOut(double time) -> double;
|
|
auto easeInOutExpo(double time) -> double;
|
|
auto easeOutBounce(double time) -> double;
|
|
auto easeOutElastic(double time) -> double;
|
|
auto easeInElastic(double time) -> double;
|
|
|
|
// Utilidades varias
|
|
auto stringInVector(const std::vector<std::string> &vec, const std::string &str) -> bool; // Comprueba si un vector contiene una cadena
|
|
void printWithDots(const std::string &text1, const std::string &text2, const std::string &text3); // Imprime una línea con puntos
|
|
|
|
// Demo
|
|
auto loadDemoDataFromFile(const std::string &file_path) -> DemoData;
|
|
|
|
#ifdef RECORDING
|
|
bool saveDemoFile(const std::string &file_path, const DemoData &dd);
|
|
#endif
|
|
|
|
// Ficheros y rutas
|
|
auto getFileName(const std::string &path) -> std::string; // Obtiene el nombre de un fichero a partir de una ruta
|
|
auto getPath(const std::string &full_path) -> std::string; // Obtiene la ruta eliminando el nombre del fichero
|