pasaeta loca de clang-format (despres m'arrepentiré pero bueno)

This commit is contained in:
JailDesigner committed 2025-07-18 20:01:13 +02:00
1 parent 734c220fb0
commit dabba41179
112 files changed
+22361 -26474

No files matched your search

+11
View File
@@ -0,0 +1,11 @@
BasedOnStyle: Google
IndentWidth: 4
ColumnLimit: 0 # Sin límite de longitud de línea
BreakBeforeBraces: Attach # Llaves en la misma línea
AllowShortIfStatementsOnASingleLine: true
AllowShortBlocksOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AlignOperands: false
AlignAfterOpenBracket: DontAlign
BinPackArguments: false
BinPackParameters: false
+40
View File
@@ -0,0 +1,40 @@
Checks: >
readability-identifier-naming,
readability-*,
modernize-*,
clang-analyzer-*
WarningsAsErrors: '*'
HeaderFilterRegex: '.*'
FormatStyle: file
CheckOptions:
# Variables locales en snake_case
- { key: readability-identifier-naming.VariableCase, value: lower_case }
# Miembros privados en snake_case con sufijo _
- { key: readability-identifier-naming.PrivateMemberCase, value: lower_case }
- { key: readability-identifier-naming.PrivateMemberSuffix, value: _ }
# Namespaces en CamelCase
- { key: readability-identifier-naming.NamespaceCase, value: CamelCase }
# Constantes y constexpr en UPPER_CASE
- { key: readability-identifier-naming.GlobalConstantCase, value: UPPER_CASE }
- { key: readability-identifier-naming.ConstexprVariableCase, value: UPPER_CASE }
- { key: readability-identifier-naming.LocalConstantCase, value: UPPER_CASE }
# Clases, structs y enums en CamelCase
- { key: readability-identifier-naming.ClassCase, value: CamelCase }
- { key: readability-identifier-naming.StructCase, value: CamelCase }
- { key: readability-identifier-naming.EnumCase, value: CamelCase }
# Valores de enums en UPPER_CASE
- { key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE }
# Métodos en camelBack
- { key: readability-identifier-naming.MethodCase, value: camelBack }
# Funciones en camelBack
- { key: readability-identifier-naming.FunctionCase, value: camelBack }
+181 -221
View File
@@ -1,280 +1,240 @@
#include "animated_sprite.h" #include "animated_sprite.h"
#include <SDL3/SDL.h> // Para SDL_LogWarn, SDL_LogCategory, SDL_LogError #include <SDL3/SDL.h> // Para SDL_LogWarn, SDL_LogCategory, SDL_LogError
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <algorithm> // Para min
#include <fstream> // Para basic_istream, basic_ifstream, basic_ios, ifst...
#include <sstream> // Para basic_stringstream
#include <stdexcept> // Para runtime_error
#include <utility> // Para pair
#include "texture.h" // Para Texture #include <algorithm> // Para min
#include "utils.h" // Para printWithDots #include <fstream> // Para basic_istream, basic_ifstream, basic_ios, ifst...
#include <sstream> // Para basic_stringstream
#include <stdexcept> // Para runtime_error
#include <utility> // Para pair
#include "texture.h" // Para Texture
#include "utils.h" // Para printWithDots
// Carga las animaciones en un vector(Animations) desde un fichero // Carga las animaciones en un vector(Animations) desde un fichero
AnimationsFileBuffer loadAnimationsFromFile(const std::string &file_path) AnimationsFileBuffer loadAnimationsFromFile(const std::string &file_path) {
{ std::ifstream file(file_path);
std::ifstream file(file_path); if (!file) {
if (!file) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str());
{ throw std::runtime_error("Fichero no encontrado: " + file_path);
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str()); }
throw std::runtime_error("Fichero no encontrado: " + file_path);
}
printWithDots("Animation : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]"); printWithDots("Animation : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]");
std::vector<std::string> buffer; std::vector<std::string> buffer;
std::string line; std::string line;
while (std::getline(file, line)) while (std::getline(file, line)) {
{ if (!line.empty())
if (!line.empty()) buffer.push_back(line);
buffer.push_back(line); }
}
return buffer; return buffer;
} }
// Constructor // Constructor
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const std::string &file_path) AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const std::string &file_path)
: MovingSprite(texture) : MovingSprite(texture) {
{ // Carga las animaciones
// Carga las animaciones if (!file_path.empty()) {
if (!file_path.empty()) AnimationsFileBuffer v = loadAnimationsFromFile(file_path);
{ loadFromAnimationsFileBuffer(v);
AnimationsFileBuffer v = loadAnimationsFromFile(file_path); }
loadFromAnimationsFileBuffer(v);
}
} }
// Constructor // Constructor
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer &animations) AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer &animations)
: MovingSprite(texture) : MovingSprite(texture) {
{ if (!animations.empty()) {
if (!animations.empty()) loadFromAnimationsFileBuffer(animations);
{ }
loadFromAnimationsFileBuffer(animations);
}
} }
// Obtiene el índice de la animación a partir del nombre // Obtiene el índice de la animación a partir del nombre
int AnimatedSprite::getIndex(const std::string &name) int AnimatedSprite::getIndex(const std::string &name) {
{ auto it = animation_indices_.find(name);
auto it = animation_indices_.find(name); if (it != animation_indices_.end()) {
if (it != animation_indices_.end()) // Si se encuentra la animación en el mapa, devuelve su índice
{ return it->second;
// Si se encuentra la animación en el mapa, devuelve su índice }
return it->second;
}
// Si no se encuentra, muestra una advertencia y devuelve -1 // Si no se encuentra, muestra una advertencia y devuelve -1
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "** Warning: could not find \"%s\" animation", name.c_str()); SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "** Warning: could not find \"%s\" animation", name.c_str());
return -1; return -1;
} }
// Calcula el frame correspondiente a la animación // Calcula el frame correspondiente a la animación
void AnimatedSprite::animate() void AnimatedSprite::animate() {
{ if (animations_[current_animation_].speed == 0) {
if (animations_[current_animation_].speed == 0) return;
{ }
return;
}
// Calcula el frame actual a partir del contador // Calcula el frame actual a partir del contador
animations_[current_animation_].current_frame = animations_[current_animation_].counter / animations_[current_animation_].speed; animations_[current_animation_].current_frame = animations_[current_animation_].counter / animations_[current_animation_].speed;
// Si alcanza el final de la animación, reinicia el contador de la animación // Si alcanza el final de la animación, reinicia el contador de la animación
// en función de la variable loop y coloca el nuevo frame // en función de la variable loop y coloca el nuevo frame
if (animations_[current_animation_].current_frame >= animations_[current_animation_].frames.size()) if (animations_[current_animation_].current_frame >= animations_[current_animation_].frames.size()) {
{ if (animations_[current_animation_].loop == -1) { // Si no hay loop, deja el último frame
if (animations_[current_animation_].loop == -1) animations_[current_animation_].current_frame = animations_[current_animation_].frames.size();
{ // Si no hay loop, deja el último frame animations_[current_animation_].completed = true;
animations_[current_animation_].current_frame = animations_[current_animation_].frames.size(); } else { // Si hay loop, vuelve al frame indicado
animations_[current_animation_].completed = true; animations_[current_animation_].counter = 0;
} animations_[current_animation_].current_frame = animations_[current_animation_].loop;
else }
{ // Si hay loop, vuelve al frame indicado }
animations_[current_animation_].counter = 0; // En caso contrario
animations_[current_animation_].current_frame = animations_[current_animation_].loop; else {
} // Escoge el frame correspondiente de la animación
} setSpriteClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]);
// En caso contrario
else
{
// Escoge el frame correspondiente de la animación
setSpriteClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]);
// Incrementa el contador de la animacion // Incrementa el contador de la animacion
animations_[current_animation_].counter++; animations_[current_animation_].counter++;
} }
} }
// Comprueba si ha terminado la animación // Comprueba si ha terminado la animación
bool AnimatedSprite::animationIsCompleted() bool AnimatedSprite::animationIsCompleted() {
{ return animations_[current_animation_].completed;
return animations_[current_animation_].completed;
} }
// Establece la animacion actual // Establece la animacion actual
void AnimatedSprite::setCurrentAnimation(const std::string &name, bool reset) void AnimatedSprite::setCurrentAnimation(const std::string &name, bool reset) {
{ const auto NEW_ANIMATION = getIndex(name);
const auto NEW_ANIMATION = getIndex(name); if (current_animation_ != NEW_ANIMATION) {
if (current_animation_ != NEW_ANIMATION) const auto OLD_ANIMATION = current_animation_;
{ current_animation_ = NEW_ANIMATION;
const auto OLD_ANIMATION = current_animation_; if (reset) {
current_animation_ = NEW_ANIMATION; animations_[current_animation_].current_frame = 0;
if (reset) animations_[current_animation_].counter = 0;
{ animations_[current_animation_].completed = false;
animations_[current_animation_].current_frame = 0; } else {
animations_[current_animation_].counter = 0; animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size());
animations_[current_animation_].completed = false; animations_[current_animation_].counter = animations_[OLD_ANIMATION].counter;
} animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed;
else }
{ }
animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size());
animations_[current_animation_].counter = animations_[OLD_ANIMATION].counter;
animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed;
}
}
} }
// Establece la animacion actual // Establece la animacion actual
void AnimatedSprite::setCurrentAnimation(int index, bool reset) void AnimatedSprite::setCurrentAnimation(int index, bool reset) {
{ const auto NEW_ANIMATION = index;
const auto NEW_ANIMATION = index; if (current_animation_ != NEW_ANIMATION) {
if (current_animation_ != NEW_ANIMATION) const auto OLD_ANIMATION = current_animation_;
{ current_animation_ = NEW_ANIMATION;
const auto OLD_ANIMATION = current_animation_; if (reset) {
current_animation_ = NEW_ANIMATION; animations_[current_animation_].current_frame = 0;
if (reset) animations_[current_animation_].counter = 0;
{ animations_[current_animation_].completed = false;
animations_[current_animation_].current_frame = 0; } else {
animations_[current_animation_].counter = 0; animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size());
animations_[current_animation_].completed = false; animations_[current_animation_].counter = animations_[OLD_ANIMATION].counter;
} animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed;
else }
{ }
animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size());
animations_[current_animation_].counter = animations_[OLD_ANIMATION].counter;
animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed;
}
}
} }
// Actualiza las variables del objeto // Actualiza las variables del objeto
void AnimatedSprite::update() void AnimatedSprite::update() {
{ animate();
animate(); MovingSprite::update();
MovingSprite::update();
} }
// Reinicia la animación // Reinicia la animación
void AnimatedSprite::resetAnimation() void AnimatedSprite::resetAnimation() {
{ animations_[current_animation_].current_frame = 0;
animations_[current_animation_].current_frame = 0; animations_[current_animation_].counter = 0;
animations_[current_animation_].counter = 0; animations_[current_animation_].completed = false;
animations_[current_animation_].completed = false;
} }
// Carga la animación desde un vector de cadenas // Carga la animación desde un vector de cadenas
void AnimatedSprite::loadFromAnimationsFileBuffer(const AnimationsFileBuffer &source) void AnimatedSprite::loadFromAnimationsFileBuffer(const AnimationsFileBuffer &source) {
{ float frame_width = 1;
float frame_width = 1; float frame_height = 1;
float frame_height = 1; int frames_per_row = 1;
int frames_per_row = 1; int max_tiles = 1;
int max_tiles = 1;
size_t index = 0; size_t index = 0;
while (index < source.size()) while (index < source.size()) {
{ std::string line = source.at(index);
std::string line = source.at(index);
// Parsea el fichero para buscar variables y valores // Parsea el fichero para buscar variables y valores
if (line != "[animation]") if (line != "[animation]") {
{ // Encuentra la posición del carácter '='
// Encuentra la posición del carácter '=' size_t pos = line.find("=");
size_t pos = line.find("=");
// Procesa las dos subcadenas // Procesa las dos subcadenas
if (pos != std::string::npos) if (pos != std::string::npos) {
{ std::string key = line.substr(0, pos);
std::string key = line.substr(0, pos); int value = std::stoi(line.substr(pos + 1));
int value = std::stoi(line.substr(pos + 1)); if (key == "frame_width")
if (key == "frame_width") frame_width = value;
frame_width = value; else if (key == "frame_height")
else if (key == "frame_height") frame_height = value;
frame_height = value; else
else SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: unknown parameter %s", key.c_str());
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: unknown parameter %s", key.c_str());
frames_per_row = texture_->getWidth() / frame_width; frames_per_row = texture_->getWidth() / frame_width;
const int w = texture_->getWidth() / frame_width; const int w = texture_->getWidth() / frame_width;
const int h = texture_->getHeight() / frame_height; const int h = texture_->getHeight() / frame_height;
max_tiles = w * h; max_tiles = w * h;
} }
} }
// Si la línea contiene el texto [animation] se realiza el proceso de carga de una animación // Si la línea contiene el texto [animation] se realiza el proceso de carga de una animación
if (line == "[animation]") if (line == "[animation]") {
{ Animation animation;
Animation animation; do {
do index++;
{ line = source.at(index);
index++; size_t pos = line.find("=");
line = source.at(index);
size_t pos = line.find("=");
if (pos != std::string::npos) if (pos != std::string::npos) {
{ std::string key = line.substr(0, pos);
std::string key = line.substr(0, pos); std::string value = line.substr(pos + 1);
std::string value = line.substr(pos + 1);
if (key == "name") if (key == "name")
animation.name = value; animation.name = value;
else if (key == "speed") else if (key == "speed")
animation.speed = std::stoi(value); animation.speed = std::stoi(value);
else if (key == "loop") else if (key == "loop")
animation.loop = std::stoi(value); animation.loop = std::stoi(value);
else if (key == "frames") else if (key == "frames") {
{ // Se introducen los valores separados por comas en un vector
// Se introducen los valores separados por comas en un vector std::stringstream ss(value);
std::stringstream ss(value); std::string tmp;
std::string tmp; SDL_FRect rect = {0, 0, frame_width, frame_height};
SDL_FRect rect = {0, 0, frame_width, frame_height}; while (getline(ss, tmp, ',')) {
while (getline(ss, tmp, ',')) // Comprueba que el tile no sea mayor que el máximo índice permitido
{ const int num_tile = std::stoi(tmp);
// Comprueba que el tile no sea mayor que el máximo índice permitido if (num_tile <= max_tiles) {
const int num_tile = std::stoi(tmp); rect.x = (num_tile % frames_per_row) * frame_width;
if (num_tile <= max_tiles) rect.y = (num_tile / frames_per_row) * frame_height;
{ animation.frames.emplace_back(rect);
rect.x = (num_tile % frames_per_row) * frame_width; }
rect.y = (num_tile / frames_per_row) * frame_height; }
animation.frames.emplace_back(rect); } else
} SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: unknown parameter %s", key.c_str());
} }
} } while (line != "[/animation]");
else
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: unknown parameter %s", key.c_str());
}
} while (line != "[/animation]");
// Añade la animación al vector de animaciones // Añade la animación al vector de animaciones
animations_.emplace_back(animation); animations_.emplace_back(animation);
// Rellena el mapa con el nombre y el nuevo índice // Rellena el mapa con el nombre y el nuevo índice
animation_indices_[animation.name] = animations_.size() - 1; animation_indices_[animation.name] = animations_.size() - 1;
} }
// Una vez procesada la línea, aumenta el índice para pasar a la siguiente // Una vez procesada la línea, aumenta el índice para pasar a la siguiente
index++; index++;
} }
// Pone un valor por defecto // Pone un valor por defecto
setWidth(frame_width); setWidth(frame_width);
setHeight(frame_height); setHeight(frame_height);
} }
// Establece la velocidad de la animación // Establece la velocidad de la animación
void AnimatedSprite::setAnimationSpeed(size_t value) void AnimatedSprite::setAnimationSpeed(size_t value) {
{ animations_[current_animation_].speed = value;
animations_[current_animation_].speed = value;
} }
+31 -32
View File
@@ -1,27 +1,27 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_FRect #include <SDL3/SDL.h> // Para SDL_FRect
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <memory> // Para shared_ptr
#include <string> // Para basic_string, string, hash
#include <unordered_map> // Para unordered_map
#include <vector> // Para vector
#include "moving_sprite.h" // Para MovingSprite #include <memory> // Para shared_ptr
#include <string> // Para basic_string, string, hash
#include <unordered_map> // Para unordered_map
#include <vector> // Para vector
#include "moving_sprite.h" // Para MovingSprite
// Declaración adelantada // Declaración adelantada
class Texture; class Texture;
// Estructura de Animación // Estructura de Animación
struct Animation struct Animation {
{ std::string name; // Nombre de la animación
std::string name; // Nombre de la animación std::vector<SDL_FRect> frames; // Frames que componen la animación
std::vector<SDL_FRect> frames; // Frames que componen la animación int speed; // Velocidad de reproducción
int speed; // Velocidad de reproducción int loop; // Frame de vuelta al terminar (-1 para no repetir)
int loop; // Frame de vuelta al terminar (-1 para no repetir) bool completed; // Indica si la animación ha finalizado
bool completed; // Indica si la animación ha finalizado size_t current_frame; // Frame actual en reproducción
size_t current_frame; // Frame actual en reproducción int counter; // Contador para la animación
int counter; // Contador para la animación
Animation() : name(std::string()), speed(5), loop(0), completed(false), current_frame(0), counter(0) {} Animation() : name(std::string()), speed(5), loop(0), completed(false), current_frame(0), counter(0) {}
}; };
@@ -33,9 +33,8 @@ using AnimationsFileBuffer = std::vector<std::string>;
AnimationsFileBuffer loadAnimationsFromFile(const std::string &file_path); AnimationsFileBuffer loadAnimationsFromFile(const std::string &file_path);
// Clase AnimatedSprite: Sprite animado que hereda de MovingSprite // Clase AnimatedSprite: Sprite animado que hereda de MovingSprite
class AnimatedSprite : public MovingSprite class AnimatedSprite : public MovingSprite {
{ public:
public:
// --- Constructores y destructor --- // --- Constructores y destructor ---
AnimatedSprite(std::shared_ptr<Texture> texture, const std::string &file_path); AnimatedSprite(std::shared_ptr<Texture> texture, const std::string &file_path);
AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer &animations); AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer &animations);
@@ -43,28 +42,28 @@ public:
virtual ~AnimatedSprite() override = default; virtual ~AnimatedSprite() override = default;
// --- Métodos principales --- // --- Métodos principales ---
void update() override; // Actualiza la animación void update() override; // Actualiza la animación
// --- Control de animaciones --- // --- Control de animaciones ---
void setCurrentAnimation(const std::string &name = "default", bool reset = true); // Establece la animación por nombre void setCurrentAnimation(const std::string &name = "default", bool reset = true); // Establece la animación por nombre
void setCurrentAnimation(int index = 0, bool reset = true); // Establece la animación por índice void setCurrentAnimation(int index = 0, bool reset = true); // Establece la animación por índice
void resetAnimation(); // Reinicia la animación actual void resetAnimation(); // Reinicia la animación actual
void setAnimationSpeed(size_t value); // Establece la velocidad de la animación void setAnimationSpeed(size_t value); // Establece la velocidad de la animación
size_t getAnimationSpeed() const { return animations_[current_animation_].speed; } // Obtiene la velocidad de la animación actual size_t getAnimationSpeed() const { return animations_[current_animation_].speed; } // Obtiene la velocidad de la animación actual
// --- Consultas --- // --- Consultas ---
bool animationIsCompleted(); // Comprueba si la animación ha terminado bool animationIsCompleted(); // Comprueba si la animación ha terminado
int getIndex(const std::string &name); // Obtiene el índice de una animación por nombre int getIndex(const std::string &name); // Obtiene el índice de una animación por nombre
protected: protected:
// --- Datos de animación --- // --- Datos de animación ---
std::vector<Animation> animations_; // Vector de animaciones disponibles std::vector<Animation> animations_; // Vector de animaciones disponibles
int current_animation_ = 0; // Índice de la animación activa int current_animation_ = 0; // Índice de la animación activa
// --- Mapa para búsqueda rápida de animaciones por nombre --- // --- Mapa para búsqueda rápida de animaciones por nombre ---
std::unordered_map<std::string, int> animation_indices_; std::unordered_map<std::string, int> animation_indices_;
// --- Métodos internos --- // --- Métodos internos ---
void animate(); // Calcula el frame actual de la animación void animate(); // Calcula el frame actual de la animación
void loadFromAnimationsFileBuffer(const AnimationsFileBuffer &source); // Carga animaciones desde un buffer void loadFromAnimationsFileBuffer(const AnimationsFileBuffer &source); // Carga animaciones desde un buffer
}; };
+46 -69
View File
@@ -1,11 +1,12 @@
#include "asset.h" #include "asset.h"
#include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory, SDL_LogError #include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory, SDL_LogError
#include <algorithm> // Para find_if, max #include <algorithm> // Para find_if, max
#include <fstream> // Para basic_ifstream, ifstream #include <fstream> // Para basic_ifstream, ifstream
#include <string> // Para allocator, string, char_traits, operator+ #include <string> // Para allocator, string, char_traits, operator+
#include "utils.h" // Para getFileName #include "utils.h" // Para getFileName
// Singleton // Singleton
Asset *Asset::instance_ = nullptr; Asset *Asset::instance_ = nullptr;
@@ -20,62 +21,48 @@ void Asset::destroy() { delete Asset::instance_; }
Asset *Asset::get() { return Asset::instance_; } Asset *Asset::get() { return Asset::instance_; }
// Añade un elemento a la lista // Añade un elemento a la lista
void Asset::add(const std::string &file, AssetType type, bool required, bool absolute) void Asset::add(const std::string &file, AssetType type, bool required, bool absolute) {
{
file_list_.emplace_back(absolute ? file : executable_path_ + file, type, required); file_list_.emplace_back(absolute ? file : executable_path_ + file, type, required);
longest_name_ = std::max(longest_name_, static_cast<int>(file_list_.back().file.size())); longest_name_ = std::max(longest_name_, static_cast<int>(file_list_.back().file.size()));
} }
// Devuelve la ruta completa a un fichero a partir de una cadena // Devuelve la ruta completa a un fichero a partir de una cadena
std::string Asset::get(const std::string &text) const std::string Asset::get(const std::string &text) const {
{ auto it = std::find_if(file_list_.begin(), file_list_.end(), [&text](const auto &f) {
auto it = std::find_if(file_list_.begin(), file_list_.end(), return getFileName(f.file) == text;
[&text](const auto &f) });
{
return getFileName(f.file) == text;
});
if (it != file_list_.end()) if (it != file_list_.end()) {
{
return it->file; return it->file;
} } else {
else
{
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found", text.c_str()); SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found", text.c_str());
return ""; return "";
} }
} }
// Comprueba que existen todos los elementos // Comprueba que existen todos los elementos
bool Asset::check() const bool Asset::check() const {
{
bool success = true; bool success = true;
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n** CHECKING FILES"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n** CHECKING FILES");
// Comprueba la lista de ficheros clasificándolos por tipo // Comprueba la lista de ficheros clasificándolos por tipo
for (int type = 0; type < static_cast<int>(AssetType::COUNT); ++type) for (int type = 0; type < static_cast<int>(AssetType::COUNT); ++type) {
{
// Comprueba si hay ficheros de ese tipo // Comprueba si hay ficheros de ese tipo
bool any = false; bool any = false;
for (const auto &f : file_list_) for (const auto &f : file_list_) {
{ if (f.required && f.type == static_cast<AssetType>(type)) {
if (f.required && f.type == static_cast<AssetType>(type))
{
any = true; any = true;
} }
} }
// Si hay ficheros de ese tipo, comprueba si existen // Si hay ficheros de ese tipo, comprueba si existen
if (any) if (any) {
{
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> %s FILES", getTypeName(static_cast<AssetType>(type)).c_str()); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> %s FILES", getTypeName(static_cast<AssetType>(type)).c_str());
for (const auto &f : file_list_) for (const auto &f : file_list_) {
{ if (f.required && f.type == static_cast<AssetType>(type)) {
if (f.required && f.type == static_cast<AssetType>(type))
{
success &= checkFile(f.file); success &= checkFile(f.file);
} }
} }
@@ -85,12 +72,9 @@ bool Asset::check() const
} }
// Resultado // Resultado
if (success) if (success) {
{
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n** CHECKING FILES COMPLETED.\n"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n** CHECKING FILES COMPLETED.\n");
} } else {
else
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "\n** CHECKING FILES FAILED.\n"); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "\n** CHECKING FILES FAILED.\n");
} }
@@ -98,14 +82,12 @@ bool Asset::check() const
} }
// Comprueba que existe un fichero // Comprueba que existe un fichero
bool Asset::checkFile(const std::string &path) const bool Asset::checkFile(const std::string &path) const {
{
std::ifstream file(path); std::ifstream file(path);
bool success = file.good(); bool success = file.good();
file.close(); file.close();
if (!success) if (!success) {
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Checking file: %s [ ERROR ]", getFileName(path).c_str()); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Checking file: %s [ ERROR ]", getFileName(path).c_str());
} }
@@ -113,42 +95,37 @@ bool Asset::checkFile(const std::string &path) const
} }
// Devuelve el nombre del tipo de recurso // Devuelve el nombre del tipo de recurso
std::string Asset::getTypeName(AssetType type) const std::string Asset::getTypeName(AssetType type) const {
{ switch (type) {
switch (type) case AssetType::BITMAP:
{ return "BITMAP";
case AssetType::BITMAP: case AssetType::MUSIC:
return "BITMAP"; return "MUSIC";
case AssetType::MUSIC: case AssetType::SOUND:
return "MUSIC"; return "SOUND";
case AssetType::SOUND: case AssetType::FONT:
return "SOUND"; return "FONT";
case AssetType::FONT: case AssetType::LANG:
return "FONT"; return "LANG";
case AssetType::LANG: case AssetType::DATA:
return "LANG"; return "DATA";
case AssetType::DATA: case AssetType::DEMODATA:
return "DATA"; return "DEMODATA";
case AssetType::DEMODATA: case AssetType::ANIMATION:
return "DEMODATA"; return "ANIMATION";
case AssetType::ANIMATION: case AssetType::PALETTE:
return "ANIMATION"; return "PALETTE";
case AssetType::PALETTE: default:
return "PALETTE"; return "ERROR";
default:
return "ERROR";
} }
} }
// Devuelve la lista de recursos de un tipo // Devuelve la lista de recursos de un tipo
std::vector<std::string> Asset::getListByType(AssetType type) const std::vector<std::string> Asset::getListByType(AssetType type) const {
{
std::vector<std::string> list; std::vector<std::string> list;
for (auto f : file_list_) for (auto f : file_list_) {
{ if (f.type == type) {
if (f.type == type)
{
list.push_back(f.file); list.push_back(f.file);
} }
} }
+48 -51
View File
@@ -1,66 +1,63 @@
#pragma once #pragma once
#include <string> // Para string, basic_string #include <string> // Para string, basic_string
#include <vector> // Para vector #include <vector> // Para vector
// Tipos de recursos gestionados por Asset // Tipos de recursos gestionados por Asset
enum class AssetType : int enum class AssetType : int {
{ BITMAP,
BITMAP, MUSIC,
MUSIC, SOUND,
SOUND, FONT,
FONT, LANG,
LANG, DATA,
DATA, DEMODATA,
DEMODATA, ANIMATION,
ANIMATION, PALETTE,
PALETTE, COUNT,
COUNT,
}; };
// Clase Asset: gestor de recursos (singleton) // Clase Asset: gestor de recursos (singleton)
class Asset class Asset {
{ public:
public: // --- Métodos de singleton ---
// --- Métodos de singleton --- static void init(const std::string &executable_path); // Inicializa el objeto Asset
static void init(const std::string &executable_path); // Inicializa el objeto Asset static void destroy(); // Libera el objeto Asset
static void destroy(); // Libera el objeto Asset static Asset *get(); // Obtiene el puntero al objeto Asset
static Asset *get(); // Obtiene el puntero al objeto Asset
// --- Métodos para la gestión de recursos --- // --- Métodos para la gestión de recursos ---
void add(const std::string &file, AssetType type, bool required = true, bool absolute = false); // Añade un recurso a la lista void add(const std::string &file, AssetType type, bool required = true, bool absolute = false); // Añade un recurso a la lista
std::string get(const std::string &text) const; // Obtiene la ruta completa de un recurso a partir de su nombre std::string get(const std::string &text) const; // Obtiene la ruta completa de un recurso a partir de su nombre
bool check() const; // Verifica la existencia de todos los recursos requeridos bool check() const; // Verifica la existencia de todos los recursos requeridos
std::vector<std::string> getListByType(AssetType type) const; // Devuelve una lista de archivos de un tipo concreto std::vector<std::string> getListByType(AssetType type) const; // Devuelve una lista de archivos de un tipo concreto
private: private:
// --- Estructura interna para almacenar información de cada recurso --- // --- Estructura interna para almacenar información de cada recurso ---
struct AssetItem struct AssetItem {
{ std::string file; // Ruta del fichero desde la raíz del directorio
std::string file; // Ruta del fichero desde la raíz del directorio AssetType type; // Tipo de recurso
AssetType type; // Tipo de recurso bool required; // Indica si el fichero es obligatorio
bool required; // Indica si el fichero es obligatorio
AssetItem(const std::string &filePath, AssetType assetType, bool isRequired) AssetItem(const std::string &filePath, AssetType assetType, bool isRequired)
: file(filePath), type(assetType), required(isRequired) {} : file(filePath), type(assetType), required(isRequired) {}
}; };
// --- Variables internas --- // --- Variables internas ---
int longest_name_ = 0; // Longitud del nombre más largo int longest_name_ = 0; // Longitud del nombre más largo
std::vector<AssetItem> file_list_; // Lista con todas las rutas de recursos std::vector<AssetItem> file_list_; // Lista con todas las rutas de recursos
std::string executable_path_; // Ruta del ejecutable std::string executable_path_; // Ruta del ejecutable
// --- Métodos internos --- // --- Métodos internos ---
bool checkFile(const std::string &path) const; // Verifica si un archivo existe bool checkFile(const std::string &path) const; // Verifica si un archivo existe
std::string getTypeName(AssetType type) const; // Devuelve el nombre textual del tipo de recurso std::string getTypeName(AssetType type) const; // Devuelve el nombre textual del tipo de recurso
// --- Patrón Singleton --- // --- Patrón Singleton ---
explicit Asset(const std::string &executable_path) explicit Asset(const std::string &executable_path)
: executable_path_(executable_path) {} : executable_path_(executable_path) {}
~Asset() = default; ~Asset() = default;
Asset(const Asset &) = delete; Asset(const Asset &) = delete;
Asset &operator=(const Asset &) = delete; Asset &operator=(const Asset &) = delete;
// --- Singleton --- // --- Singleton ---
static Asset *instance_; static Asset *instance_;
}; };
+26 -47
View File
@@ -1,11 +1,12 @@
#include "audio.h" #include "audio.h"
#include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory, SDL_G... #include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory, SDL_G...
#include <algorithm> // Para clamp #include <algorithm> // Para clamp
#include "external/jail_audio.h" // Para JA_FadeOutMusic, JA_Init, JA_PauseM... #include "external/jail_audio.h" // Para JA_FadeOutMusic, JA_Init, JA_PauseM...
#include "options.h" // Para AudioOptions, audio, MusicOptions #include "options.h" // Para AudioOptions, audio, MusicOptions
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
// Singleton // Singleton
Audio *Audio::instance_ = nullptr; Audio *Audio::instance_ = nullptr;
@@ -26,70 +27,56 @@ Audio::Audio() { initSDLAudio(); }
Audio::~Audio() { JA_Quit(); } Audio::~Audio() { JA_Quit(); }
// Reproduce la música // Reproduce la música
void Audio::playMusic(const std::string &name, const int loop) void Audio::playMusic(const std::string &name, const int loop) {
{
music_.name = name; music_.name = name;
music_.loop = loop; music_.loop = loop;
if (music_enabled_ && music_.state != MusicState::PLAYING) if (music_enabled_ && music_.state != MusicState::PLAYING) {
{
JA_PlayMusic(Resource::get()->getMusic(name), loop); JA_PlayMusic(Resource::get()->getMusic(name), loop);
music_.state = MusicState::PLAYING; music_.state = MusicState::PLAYING;
} }
} }
// Pausa la música // Pausa la música
void Audio::pauseMusic() void Audio::pauseMusic() {
{ if (music_enabled_ && music_.state == MusicState::PLAYING) {
if (music_enabled_ && music_.state == MusicState::PLAYING)
{
JA_PauseMusic(); JA_PauseMusic();
music_.state = MusicState::PAUSED; music_.state = MusicState::PAUSED;
} }
} }
// Detiene la música // Detiene la música
void Audio::stopMusic() void Audio::stopMusic() {
{ if (music_enabled_) {
if (music_enabled_)
{
JA_StopMusic(); JA_StopMusic();
music_.state = MusicState::STOPPED; music_.state = MusicState::STOPPED;
} }
} }
// Reproduce un sonido // Reproduce un sonido
void Audio::playSound(const std::string &name, Group group) void Audio::playSound(const std::string &name, Group group) {
{ if (sound_enabled_) {
if (sound_enabled_)
{
JA_PlaySound(Resource::get()->getSound(name), 0, static_cast<int>(group)); JA_PlaySound(Resource::get()->getSound(name), 0, static_cast<int>(group));
} }
} }
// Detiene todos los sonidos // Detiene todos los sonidos
void Audio::stopAllSounds() void Audio::stopAllSounds() {
{ if (sound_enabled_) {
if (sound_enabled_)
{
JA_StopChannel(-1); JA_StopChannel(-1);
} }
} }
// Realiza un fundido de salida de la música // Realiza un fundido de salida de la música
void Audio::fadeOutMusic(int milliseconds) void Audio::fadeOutMusic(int milliseconds) {
{ if (music_enabled_) {
if (music_enabled_)
{
JA_FadeOutMusic(milliseconds); JA_FadeOutMusic(milliseconds);
} }
} }
// Establece el volumen de los sonidos // Establece el volumen de los sonidos
void Audio::setSoundVolume(int sound_volume, Group group) void Audio::setSoundVolume(int sound_volume, Group group) {
{ if (sound_enabled_) {
if (sound_enabled_)
{
sound_volume = std::clamp(sound_volume, 0, 100); sound_volume = std::clamp(sound_volume, 0, 100);
const float CONVERTED_VOLUME = (sound_volume / 100.0f) * (Options::audio.volume / 100.0f); const float CONVERTED_VOLUME = (sound_volume / 100.0f) * (Options::audio.volume / 100.0f);
JA_SetSoundVolume(CONVERTED_VOLUME, static_cast<int>(group)); JA_SetSoundVolume(CONVERTED_VOLUME, static_cast<int>(group));
@@ -97,10 +84,8 @@ void Audio::setSoundVolume(int sound_volume, Group group)
} }
// Establece el volumen de la música // Establece el volumen de la música
void Audio::setMusicVolume(int music_volume) void Audio::setMusicVolume(int music_volume) {
{ if (music_enabled_) {
if (music_enabled_)
{
music_volume = std::clamp(music_volume, 0, 100); music_volume = std::clamp(music_volume, 0, 100);
const float CONVERTED_VOLUME = (music_volume / 100.0f) * (Options::audio.volume / 100.0f); const float CONVERTED_VOLUME = (music_volume / 100.0f) * (Options::audio.volume / 100.0f);
JA_SetMusicVolume(CONVERTED_VOLUME); JA_SetMusicVolume(CONVERTED_VOLUME);
@@ -108,14 +93,12 @@ void Audio::setMusicVolume(int music_volume)
} }
// Aplica la configuración // Aplica la configuración
void Audio::applySettings() void Audio::applySettings() {
{
enable(Options::audio.enabled); enable(Options::audio.enabled);
} }
// Establecer estado general // Establecer estado general
void Audio::enable(bool value) void Audio::enable(bool value) {
{
enabled_ = value; enabled_ = value;
setSoundVolume(enabled_ ? Options::audio.sound.volume : 0); setSoundVolume(enabled_ ? Options::audio.sound.volume : 0);
@@ -123,14 +106,10 @@ void Audio::enable(bool value)
} }
// Inicializa SDL Audio // Inicializa SDL Audio
void Audio::initSDLAudio() void Audio::initSDLAudio() {
{ if (!SDL_Init(SDL_INIT_AUDIO)) {
if (!SDL_Init(SDL_INIT_AUDIO))
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_AUDIO could not initialize! SDL Error: %s", SDL_GetError()); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_AUDIO could not initialize! SDL Error: %s", SDL_GetError());
} } else {
else
{
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "\n** SDL_AUDIO: INITIALIZING\n"); SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "\n** SDL_AUDIO: INITIALIZING\n");
JA_Init(48000, SDL_AUDIO_S16LE, 2); JA_Init(48000, SDL_AUDIO_S16LE, 2);
+38 -42
View File
@@ -3,65 +3,61 @@
#include <string> #include <string>
// Clase Audio: gestor de audio (singleton) // Clase Audio: gestor de audio (singleton)
class Audio class Audio {
{ public:
public: enum class Group : int {
enum class Group : int
{
ALL = -1, ALL = -1,
GAME = 0, GAME = 0,
INTERFACE = 1 INTERFACE = 1
}; };
// --- Métodos de singleton --- // --- Métodos de singleton ---
static void init(); // Inicializa el objeto Audio static void init(); // Inicializa el objeto Audio
static void destroy(); // Libera el objeto Audio static void destroy(); // Libera el objeto Audio
static Audio *get(); // Obtiene el puntero al objeto Audio static Audio *get(); // Obtiene el puntero al objeto Audio
// --- Control de Música --- // --- Control de Música ---
void playMusic(const std::string &name, int loop = -1); // Reproducir música en bucle void playMusic(const std::string &name, int loop = -1); // Reproducir música en bucle
void pauseMusic(); // Pausar reproducción de música void pauseMusic(); // Pausar reproducción de música
void stopMusic(); // Detener completamente la música void stopMusic(); // Detener completamente la música
void fadeOutMusic(int milliseconds); // Fundido de salida de la música void fadeOutMusic(int milliseconds); // Fundido de salida de la música
// --- Control de Sonidos --- // --- Control de Sonidos ---
void playSound(const std::string &name, Group group = Group::GAME); // Reproducir sonido puntual void playSound(const std::string &name, Group group = Group::GAME); // Reproducir sonido puntual
void stopAllSounds(); // Detener todos los sonidos void stopAllSounds(); // Detener todos los sonidos
// --- Configuración General --- // --- Configuración General ---
void enable(bool value); // Establecer estado general void enable(bool value); // Establecer estado general
void toggleEnabled() { enabled_ = !enabled_; } // Alternar estado general void toggleEnabled() { enabled_ = !enabled_; } // Alternar estado general
void applySettings(); // Aplica la configuración void applySettings(); // Aplica la configuración
// --- Configuración de Sonidos --- // --- Configuración de Sonidos ---
void enableSound() { sound_enabled_ = true; } // Habilitar sonidos void enableSound() { sound_enabled_ = true; } // Habilitar sonidos
void disableSound() { sound_enabled_ = false; } // Deshabilitar sonidos void disableSound() { sound_enabled_ = false; } // Deshabilitar sonidos
void enableSound(bool value) { sound_enabled_ = value; } // Establecer estado de sonidos void enableSound(bool value) { sound_enabled_ = value; } // Establecer estado de sonidos
void toggleSound() { sound_enabled_ = !sound_enabled_; } // Alternar estado de sonidos void toggleSound() { sound_enabled_ = !sound_enabled_; } // Alternar estado de sonidos
// --- Configuración de Música --- // --- Configuración de Música ---
void enableMusic() { music_enabled_ = true; } // Habilitar música void enableMusic() { music_enabled_ = true; } // Habilitar música
void disableMusic() { music_enabled_ = false; } // Deshabilitar música void disableMusic() { music_enabled_ = false; } // Deshabilitar música
void enableMusic(bool value) { music_enabled_ = value; } // Establecer estado de música void enableMusic(bool value) { music_enabled_ = value; } // Establecer estado de música
void toggleMusic() { music_enabled_ = !music_enabled_; } // Alternar estado de música void toggleMusic() { music_enabled_ = !music_enabled_; } // Alternar estado de música
// --- Control de Volumen --- // --- Control de Volumen ---
void setSoundVolume(int volume, Group group = Group::ALL); // Ajustar volumen de efectos void setSoundVolume(int volume, Group group = Group::ALL); // Ajustar volumen de efectos
void setMusicVolume(int volume); // Ajustar volumen de música void setMusicVolume(int volume); // Ajustar volumen de música
private: private:
enum class MusicState enum class MusicState {
{
PLAYING, PLAYING,
PAUSED, PAUSED,
STOPPED, STOPPED,
}; };
struct Music struct Music {
{ MusicState state; // Estado actual de la música (reproduciendo, detenido, en pausa)
MusicState state; // Estado actual de la música (reproduciendo, detenido, en pausa) std::string name; // Última pista de música reproducida
std::string name; // Última pista de música reproducida bool loop; // Indica si la última pista de música se debe reproducir en bucle
bool loop; // Indica si la última pista de música se debe reproducir en bucle
// Constructor para inicializar la música con valores predeterminados // Constructor para inicializar la música con valores predeterminados
Music() : state(MusicState::STOPPED), name(""), loop(false) {} Music() : state(MusicState::STOPPED), name(""), loop(false) {}
@@ -74,18 +70,18 @@ private:
Music music_; Music music_;
// --- Variables de Estado --- // --- Variables de Estado ---
bool enabled_ = true; // Estado general del audio bool enabled_ = true; // Estado general del audio
bool sound_enabled_ = true; // Estado de los efectos de sonido bool sound_enabled_ = true; // Estado de los efectos de sonido
bool music_enabled_ = true; // Estado de la música bool music_enabled_ = true; // Estado de la música
// --- Inicializa SDL Audio --- // --- Inicializa SDL Audio ---
void initSDLAudio(); void initSDLAudio();
// --- Patrón Singleton --- // --- Patrón Singleton ---
Audio(); // Constructor privado Audio(); // Constructor privado
~Audio(); // Destructor privado ~Audio(); // Destructor privado
Audio(const Audio &) = delete; // Evitar copia Audio(const Audio &) = delete; // Evitar copia
Audio &operator=(const Audio &) = delete; // Evitar asignación Audio &operator=(const Audio &) = delete; // Evitar asignación
// --- Singleton --- // --- Singleton ---
static Audio *instance_; static Audio *instance_;
+37 -66
View File
@@ -1,17 +1,18 @@
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
#include "background.h" #include "background.h"
#include <SDL3/SDL.h> // Para SDL_SetRenderTarget, SDL_FRect, SDL_Creat... #include <SDL3/SDL.h> // Para SDL_SetRenderTarget, SDL_FRect, SDL_Creat...
#include <algorithm> // Para clamp, max #include <algorithm> // Para clamp, max
#include <cmath> // Para cos, sin, M_PI #include <cmath> // Para cos, sin, M_PI
#include <string> // Para basic_string #include <string> // Para basic_string
#include "moving_sprite.h" // Para MovingSprite #include "moving_sprite.h" // Para MovingSprite
#include "param.h" // Para Param, ParamBackground, param #include "param.h" // Para Param, ParamBackground, param
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
// Constructor // Constructor
Background::Background() Background::Background()
@@ -47,8 +48,7 @@ Background::Background()
const float TOP_CLOUDS_TEXTURE_HEIGHT = top_clouds_texture_->getHeight() / 4; const float TOP_CLOUDS_TEXTURE_HEIGHT = top_clouds_texture_->getHeight() / 4;
const float BOTTOM_CLOUDS_TEXTURE_HEIGHT = bottom_clouds_texture_->getHeight() / 4; const float BOTTOM_CLOUDS_TEXTURE_HEIGHT = bottom_clouds_texture_->getHeight() / 4;
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i) {
{
top_clouds_rect_[i] = {0, i * TOP_CLOUDS_TEXTURE_HEIGHT, static_cast<float>(top_clouds_texture_->getWidth()), TOP_CLOUDS_TEXTURE_HEIGHT}; top_clouds_rect_[i] = {0, i * TOP_CLOUDS_TEXTURE_HEIGHT, static_cast<float>(top_clouds_texture_->getWidth()), TOP_CLOUDS_TEXTURE_HEIGHT};
bottom_clouds_rect_[i] = {0, i * BOTTOM_CLOUDS_TEXTURE_HEIGHT, static_cast<float>(bottom_clouds_texture_->getWidth()), BOTTOM_CLOUDS_TEXTURE_HEIGHT}; bottom_clouds_rect_[i] = {0, i * BOTTOM_CLOUDS_TEXTURE_HEIGHT, static_cast<float>(bottom_clouds_texture_->getWidth()), BOTTOM_CLOUDS_TEXTURE_HEIGHT};
} }
@@ -107,15 +107,13 @@ Background::Background()
} }
// Destructor // Destructor
Background::~Background() Background::~Background() {
{
SDL_DestroyTexture(canvas_); SDL_DestroyTexture(canvas_);
SDL_DestroyTexture(color_texture_); SDL_DestroyTexture(color_texture_);
} }
// Actualiza la lógica del objeto // Actualiza la lógica del objeto
void Background::update() void Background::update() {
{
// Actualiza el valor de alpha_ // Actualiza el valor de alpha_
updateAlphaColorTexture(); updateAlphaColorTexture();
@@ -140,8 +138,7 @@ void Background::update()
} }
// Dibuja el gradiente de fondo // Dibuja el gradiente de fondo
void Background::renderGradient() void Background::renderGradient() {
{
// Dibuja el gradiente de detras // Dibuja el gradiente de detras
gradients_texture_->setAlpha(255); gradients_texture_->setAlpha(255);
gradient_sprite_->setSpriteClip(gradient_rect_[(gradient_number_ + 1) % 4]); gradient_sprite_->setSpriteClip(gradient_rect_[(gradient_number_ + 1) % 4]);
@@ -154,8 +151,7 @@ void Background::renderGradient()
} }
// Dibuja las nubes de arriba // Dibuja las nubes de arriba
void Background::renderTopClouds() void Background::renderTopClouds() {
{
// Dibuja el primer conjunto de nubes, las de detras // Dibuja el primer conjunto de nubes, las de detras
top_clouds_texture_->setAlpha(255); top_clouds_texture_->setAlpha(255);
top_clouds_sprite_a_->setSpriteClip(top_clouds_rect_[(gradient_number_ + 1) % 4]); top_clouds_sprite_a_->setSpriteClip(top_clouds_rect_[(gradient_number_ + 1) % 4]);
@@ -172,8 +168,7 @@ void Background::renderTopClouds()
} }
// Dibuja las nubes de abajo // Dibuja las nubes de abajo
void Background::renderBottomClouds() void Background::renderBottomClouds() {
{
// Dibuja el primer conjunto de nubes, las de detras // Dibuja el primer conjunto de nubes, las de detras
bottom_clouds_texture_->setAlpha(255); bottom_clouds_texture_->setAlpha(255);
bottom_clouds_sprite_a_->setSpriteClip(bottom_clouds_rect_[(gradient_number_ + 1) % 4]); bottom_clouds_sprite_a_->setSpriteClip(bottom_clouds_rect_[(gradient_number_ + 1) % 4]);
@@ -190,8 +185,7 @@ void Background::renderBottomClouds()
} }
// Compone todos los elementos del fondo en la textura // Compone todos los elementos del fondo en la textura
void Background::fillCanvas() void Background::fillCanvas() {
{
// Cambia el destino del renderizador // Cambia el destino del renderizador
auto temp = SDL_GetRenderTarget(renderer_); auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, canvas_); SDL_SetRenderTarget(renderer_, canvas_);
@@ -220,8 +214,7 @@ void Background::fillCanvas()
} }
// Dibuja el objeto // Dibuja el objeto
void Background::render() void Background::render() {
{
// Fondo // Fondo
SDL_RenderTexture(renderer_, canvas_, &src_rect_, &dst_rect_); SDL_RenderTexture(renderer_, canvas_, &src_rect_, &dst_rect_);
@@ -230,26 +223,22 @@ void Background::render()
} }
// Ajusta el valor de la variable // Ajusta el valor de la variable
void Background::setCloudsSpeed(float value) void Background::setCloudsSpeed(float value) {
{
clouds_speed_ = value; clouds_speed_ = value;
} }
// Ajusta el valor de la variable // Ajusta el valor de la variable
void Background::setGradientNumber(int value) void Background::setGradientNumber(int value) {
{
gradient_number_ = value % 4; gradient_number_ = value % 4;
} }
// Ajusta el valor de la variable // Ajusta el valor de la variable
void Background::setTransition(float value) void Background::setTransition(float value) {
{
transition_ = std::clamp(value, 0.0f, 1.0f); transition_ = std::clamp(value, 0.0f, 1.0f);
} }
// Establece la posición del objeto // Establece la posición del objeto
void Background::setPos(SDL_FRect pos) void Background::setPos(SDL_FRect pos) {
{
dst_rect_ = pos; dst_rect_ = pos;
// Si cambian las medidas del destino, hay que cambiar las del origen para evitar deformar la imagen // Si cambian las medidas del destino, hay que cambiar las del origen para evitar deformar la imagen
@@ -260,8 +249,7 @@ void Background::setPos(SDL_FRect pos)
} }
// Establece el color_ de atenuación // Establece el color_ de atenuación
void Background::setColor(Color color) void Background::setColor(Color color) {
{
attenuate_color_ = color; attenuate_color_ = color;
// Colorea la textura // Colorea la textura
@@ -275,8 +263,7 @@ void Background::setColor(Color color)
} }
// Establece la transparencia de la atenuación // Establece la transparencia de la atenuación
void Background::setAlpha(int alpha) void Background::setAlpha(int alpha) {
{
// Evita que se asignen valores fuera de rango // Evita que se asignen valores fuera de rango
alpha_ = std::clamp(alpha, 0, 255); alpha_ = std::clamp(alpha, 0, 255);
@@ -286,22 +273,17 @@ void Background::setAlpha(int alpha)
} }
// Actualiza el valor de alpha_ // Actualiza el valor de alpha_
void Background::updateAlphaColorTexture() void Background::updateAlphaColorTexture() {
{ if (alpha_color_text_ == alpha_color_text_temp_) {
if (alpha_color_text_ == alpha_color_text_temp_)
{
return; return;
} } else {
else
{
alpha_color_text_ > alpha_color_text_temp_ ? ++alpha_color_text_temp_ : --alpha_color_text_temp_; alpha_color_text_ > alpha_color_text_temp_ ? ++alpha_color_text_temp_ : --alpha_color_text_temp_;
SDL_SetTextureAlphaMod(color_texture_, alpha_color_text_temp_); SDL_SetTextureAlphaMod(color_texture_, alpha_color_text_temp_);
} }
} }
// Actualiza las nubes // Actualiza las nubes
void Background::updateClouds() void Background::updateClouds() {
{
// Aplica la velocidad calculada a las nubes // Aplica la velocidad calculada a las nubes
top_clouds_sprite_a_->setVelX(clouds_speed_); top_clouds_sprite_a_->setVelX(clouds_speed_);
top_clouds_sprite_b_->setVelX(clouds_speed_); top_clouds_sprite_b_->setVelX(clouds_speed_);
@@ -315,37 +297,31 @@ void Background::updateClouds()
bottom_clouds_sprite_b_->update(); bottom_clouds_sprite_b_->update();
// Calcula el offset de las nubes // Calcula el offset de las nubes
if (top_clouds_sprite_a_->getPosX() < -top_clouds_sprite_a_->getWidth()) if (top_clouds_sprite_a_->getPosX() < -top_clouds_sprite_a_->getWidth()) {
{
top_clouds_sprite_a_->setPosX(top_clouds_sprite_a_->getWidth()); top_clouds_sprite_a_->setPosX(top_clouds_sprite_a_->getWidth());
} }
if (top_clouds_sprite_b_->getPosX() < -top_clouds_sprite_b_->getWidth()) if (top_clouds_sprite_b_->getPosX() < -top_clouds_sprite_b_->getWidth()) {
{
top_clouds_sprite_b_->setPosX(top_clouds_sprite_b_->getWidth()); top_clouds_sprite_b_->setPosX(top_clouds_sprite_b_->getWidth());
} }
if (bottom_clouds_sprite_a_->getPosX() < -bottom_clouds_sprite_a_->getWidth()) if (bottom_clouds_sprite_a_->getPosX() < -bottom_clouds_sprite_a_->getWidth()) {
{
bottom_clouds_sprite_a_->setPosX(bottom_clouds_sprite_a_->getWidth()); bottom_clouds_sprite_a_->setPosX(bottom_clouds_sprite_a_->getWidth());
} }
if (bottom_clouds_sprite_b_->getPosX() < -bottom_clouds_sprite_b_->getWidth()) if (bottom_clouds_sprite_b_->getPosX() < -bottom_clouds_sprite_b_->getWidth()) {
{
bottom_clouds_sprite_b_->setPosX(bottom_clouds_sprite_b_->getWidth()); bottom_clouds_sprite_b_->setPosX(bottom_clouds_sprite_b_->getWidth());
} }
} }
// Precalcula el vector con el recorrido del sol // Precalcula el vector con el recorrido del sol
void Background::createSunPath() void Background::createSunPath() {
{
constexpr float CENTER_X = 170; constexpr float CENTER_X = 170;
const float center_y = base_ - 80; const float center_y = base_ - 80;
constexpr float RADIUS = 120; constexpr float RADIUS = 120;
// Generar puntos de la curva desde 90 a 180 grados // Generar puntos de la curva desde 90 a 180 grados
for (double theta = M_PI / 2; theta <= M_PI; theta += 0.01) for (double theta = M_PI / 2; theta <= M_PI; theta += 0.01) {
{
float x = CENTER_X + (RADIUS * cos(theta)); float x = CENTER_X + (RADIUS * cos(theta));
float y = center_y - (RADIUS * sin(theta)); float y = center_y - (RADIUS * sin(theta));
sun_path_.push_back({x, y}); sun_path_.push_back({x, y});
@@ -354,22 +330,19 @@ void Background::createSunPath()
// Agregar puntos en línea recta después de la curva // Agregar puntos en línea recta después de la curva
constexpr int EXTRA_PIXELS = 40; constexpr int EXTRA_PIXELS = 40;
SDL_FPoint last_point = sun_path_.back(); SDL_FPoint last_point = sun_path_.back();
for (int i = 1; i <= EXTRA_PIXELS; ++i) for (int i = 1; i <= EXTRA_PIXELS; ++i) {
{
sun_path_.push_back({last_point.x, last_point.y + i}); sun_path_.push_back({last_point.x, last_point.y + i});
} }
} }
// Precalcula el vector con el recorrido de la luna // Precalcula el vector con el recorrido de la luna
void Background::createMoonPath() void Background::createMoonPath() {
{
constexpr float CENTER_X = 100; constexpr float CENTER_X = 100;
const float center_y = base_ - 50; const float center_y = base_ - 50;
constexpr float RADIUS = 140; constexpr float RADIUS = 140;
// Generar puntos de la curva desde 0 a 90 grados // Generar puntos de la curva desde 0 a 90 grados
for (double theta = 0; theta <= M_PI / 2; theta += 0.01) for (double theta = 0; theta <= M_PI / 2; theta += 0.01) {
{
float x = CENTER_X + (RADIUS * cos(theta)); float x = CENTER_X + (RADIUS * cos(theta));
float y = center_y - (RADIUS * sin(theta)); float y = center_y - (RADIUS * sin(theta));
moon_path_.push_back({x, y}); moon_path_.push_back({x, y});
@@ -377,15 +350,13 @@ void Background::createMoonPath()
} }
// Establece la posición del sol // Establece la posición del sol
void Background::setSunProgression(float progress) void Background::setSunProgression(float progress) {
{
progress = std::clamp(progress, 0.0f, 1.0f); progress = std::clamp(progress, 0.0f, 1.0f);
sun_index_ = static_cast<size_t>(progress * (sun_path_.size() - 1)); sun_index_ = static_cast<size_t>(progress * (sun_path_.size() - 1));
} }
// Establece la posición de la luna // Establece la posición de la luna
void Background::setMoonProgression(float progress) void Background::setMoonProgression(float progress) {
{
progress = std::clamp(progress, 0.0f, 1.0f); progress = std::clamp(progress, 0.0f, 1.0f);
moon_index_ = static_cast<size_t>(progress * (moon_path_.size() - 1)); moon_index_ = static_cast<size_t>(progress * (moon_path_.size() - 1));
} }
+79 -79
View File
@@ -1,11 +1,12 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_FRect, SDL_FPoint, SDL_Texture, SDL_Renderer #include <SDL3/SDL.h> // Para SDL_FRect, SDL_FPoint, SDL_Texture, SDL_Renderer
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <memory> // Para unique_ptr, shared_ptr
#include <vector> // Para vector
#include "utils.h" // Para Color #include <memory> // Para unique_ptr, shared_ptr
#include <vector> // Para vector
#include "utils.h" // Para Color
class MovingSprite; class MovingSprite;
class Sprite; class Sprite;
@@ -25,89 +26,88 @@ class Texture;
- setAlpha(int alpha) -> Ajusta la transparencia de la capa de atenuación - setAlpha(int alpha) -> Ajusta la transparencia de la capa de atenuación
*/ */
class Background class Background {
{ public:
public: // Constructor y Destructor
// Constructor y Destructor Background();
Background(); ~Background();
~Background();
// Actualización y renderizado // Actualización y renderizado
void update(); // Actualiza la lógica del objeto void update(); // Actualiza la lógica del objeto
void render(); // Dibuja el objeto void render(); // Dibuja el objeto
// Configuración de posición // Configuración de posición
void setPos(SDL_FRect pos); // Establece la posición del objeto void setPos(SDL_FRect pos); // Establece la posición del objeto
// Configuración de animaciones y efectos // Configuración de animaciones y efectos
void setCloudsSpeed(float value); // Ajusta la velocidad de desplazamiento de las nubes void setCloudsSpeed(float value); // Ajusta la velocidad de desplazamiento de las nubes
void setGradientNumber(int value); // Establece el degradado de fondo a usar void setGradientNumber(int value); // Establece el degradado de fondo a usar
void setTransition(float value); // Ajusta la transición entre texturas de fondo void setTransition(float value); // Ajusta la transición entre texturas de fondo
// Configuración de efectos visuales // Configuración de efectos visuales
void setColor(Color color); // Establece el color de atenuación void setColor(Color color); // Establece el color de atenuación
void setAlpha(int alpha); // Ajusta la transparencia del fondo void setAlpha(int alpha); // Ajusta la transparencia del fondo
// Configuración del sol y la luna // Configuración del sol y la luna
void setSunProgression(float progress); // Establece la posición del sol void setSunProgression(float progress); // Establece la posición del sol
void setMoonProgression(float progress); // Establece la posición de la luna void setMoonProgression(float progress); // Establece la posición de la luna
private: private:
// Objetos y punteros // Objetos y punteros
SDL_Renderer *renderer_; // Renderizador de la ventana SDL_Renderer *renderer_; // Renderizador de la ventana
// Texturas // Texturas
std::shared_ptr<Texture> buildings_texture_; std::shared_ptr<Texture> buildings_texture_;
std::shared_ptr<Texture> top_clouds_texture_; std::shared_ptr<Texture> top_clouds_texture_;
std::shared_ptr<Texture> bottom_clouds_texture_; std::shared_ptr<Texture> bottom_clouds_texture_;
std::shared_ptr<Texture> grass_texture_; std::shared_ptr<Texture> grass_texture_;
std::shared_ptr<Texture> gradients_texture_; std::shared_ptr<Texture> gradients_texture_;
std::shared_ptr<Texture> sun_texture_; std::shared_ptr<Texture> sun_texture_;
std::shared_ptr<Texture> moon_texture_; std::shared_ptr<Texture> moon_texture_;
// Sprites // Sprites
std::unique_ptr<MovingSprite> top_clouds_sprite_a_; std::unique_ptr<MovingSprite> top_clouds_sprite_a_;
std::unique_ptr<MovingSprite> top_clouds_sprite_b_; std::unique_ptr<MovingSprite> top_clouds_sprite_b_;
std::unique_ptr<MovingSprite> bottom_clouds_sprite_a_; std::unique_ptr<MovingSprite> bottom_clouds_sprite_a_;
std::unique_ptr<MovingSprite> bottom_clouds_sprite_b_; std::unique_ptr<MovingSprite> bottom_clouds_sprite_b_;
std::unique_ptr<Sprite> buildings_sprite_; std::unique_ptr<Sprite> buildings_sprite_;
std::unique_ptr<Sprite> gradient_sprite_; std::unique_ptr<Sprite> gradient_sprite_;
std::unique_ptr<Sprite> grass_sprite_; std::unique_ptr<Sprite> grass_sprite_;
std::unique_ptr<Sprite> sun_sprite_; std::unique_ptr<Sprite> sun_sprite_;
std::unique_ptr<Sprite> moon_sprite_; std::unique_ptr<Sprite> moon_sprite_;
// Buffers de renderizado // Buffers de renderizado
SDL_Texture *canvas_; // Textura para componer el fondo SDL_Texture *canvas_; // Textura para componer el fondo
SDL_Texture *color_texture_; // Textura para atenuar el fondo SDL_Texture *color_texture_; // Textura para atenuar el fondo
// Variables de control // Variables de control
SDL_FRect gradient_rect_[4]; SDL_FRect gradient_rect_[4];
SDL_FRect top_clouds_rect_[4]; SDL_FRect top_clouds_rect_[4];
SDL_FRect bottom_clouds_rect_[4]; SDL_FRect bottom_clouds_rect_[4];
int gradient_number_ = 0; int gradient_number_ = 0;
int alpha_ = 0; int alpha_ = 0;
float clouds_speed_ = 0; float clouds_speed_ = 0;
float transition_ = 0; float transition_ = 0;
int counter_ = 0; int counter_ = 0;
SDL_FRect rect_; SDL_FRect rect_;
SDL_FRect src_rect_; SDL_FRect src_rect_;
SDL_FRect dst_rect_; SDL_FRect dst_rect_;
int base_; int base_;
Color attenuate_color_; Color attenuate_color_;
int alpha_color_text_; int alpha_color_text_;
int alpha_color_text_temp_; int alpha_color_text_temp_;
std::vector<SDL_FPoint> sun_path_; std::vector<SDL_FPoint> sun_path_;
std::vector<SDL_FPoint> moon_path_; std::vector<SDL_FPoint> moon_path_;
size_t sun_index_ = 0; size_t sun_index_ = 0;
size_t moon_index_ = 0; size_t moon_index_ = 0;
// Métodos internos // Métodos internos
void renderGradient(); // Dibuja el gradiente de fondo void renderGradient(); // Dibuja el gradiente de fondo
void renderTopClouds(); // Dibuja las nubes superiores void renderTopClouds(); // Dibuja las nubes superiores
void renderBottomClouds(); // Dibuja las nubes inferiores void renderBottomClouds(); // Dibuja las nubes inferiores
void fillCanvas(); // Compone todos los elementos en la textura void fillCanvas(); // Compone todos los elementos en la textura
void updateAlphaColorTexture(); // Actualiza el alpha de la textura de atenuación void updateAlphaColorTexture(); // Actualiza el alpha de la textura de atenuación
void updateClouds(); // Actualiza el movimiento de las nubes void updateClouds(); // Actualiza el movimiento de las nubes
void createSunPath(); // Precalcula el recorrido del sol void createSunPath(); // Precalcula el recorrido del sol
void createMoonPath(); // Precalcula el recorrido de la luna void createMoonPath(); // Precalcula el recorrido de la luna
}; };
+290 -344
View File
@@ -1,440 +1,386 @@
#include "balloon.h" #include "balloon.h"
#include <algorithm> // Para clamp #include <algorithm> // Para clamp
#include <array> // Para array #include <array> // Para array
#include <cmath> // Para fabs #include <cmath> // Para fabs
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
#include "audio.h" // Para Audio #include "audio.h" // Para Audio
#include "param.h" // Para Param, ParamBalloon, param #include "param.h" // Para Param, ParamBalloon, param
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
// Constructor // Constructor
Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel_x, float speed, Uint16 creation_timer, SDL_FRect play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation) Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel_x, float speed, Uint16 creation_timer, SDL_FRect play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation)
: sprite_(std::make_unique<AnimatedSprite>(texture, animation)), : sprite_(std::make_unique<AnimatedSprite>(texture, animation)),
x_(x), x_(x),
y_(y), y_(y),
vx_(vel_x), vx_(vel_x),
being_created_(creation_timer > 0), being_created_(creation_timer > 0),
invulnerable_(creation_timer > 0), invulnerable_(creation_timer > 0),
stopped_(creation_timer > 0), stopped_(creation_timer > 0),
creation_counter_(creation_timer), creation_counter_(creation_timer),
creation_counter_ini_(creation_timer), creation_counter_ini_(creation_timer),
type_(type), type_(type),
size_(size), size_(size),
speed_(speed), speed_(speed),
play_area_(play_area) play_area_(play_area) {
{ switch (type_) {
switch (type_) case BalloonType::BALLOON: {
{ vy_ = 0;
case BalloonType::BALLOON: max_vy_ = 3.0f;
{
vy_ = 0;
max_vy_ = 3.0f;
const int index = static_cast<int>(size_); const int index = static_cast<int>(size_);
gravity_ = param.balloon.settings.at(index).grav; gravity_ = param.balloon.settings.at(index).grav;
default_vy_ = param.balloon.settings.at(index).vel; default_vy_ = param.balloon.settings.at(index).vel;
h_ = w_ = BALLOON_SIZE[index]; h_ = w_ = BALLOON_SIZE[index];
power_ = BALLOON_POWER[index]; power_ = BALLOON_POWER[index];
menace_ = BALLOON_MENACE[index]; menace_ = BALLOON_MENACE[index];
score_ = BALLOON_SCORE[index]; score_ = BALLOON_SCORE[index];
bouncing_sound_ = BALLOON_BOUNCING_SOUND[index]; bouncing_sound_ = BALLOON_BOUNCING_SOUND[index];
popping_sound_ = BALLOON_POPPING_SOUND[index]; popping_sound_ = BALLOON_POPPING_SOUND[index];
break; break;
} }
case BalloonType::FLOATER: case BalloonType::FLOATER: {
{ default_vy_ = max_vy_ = vy_ = fabs(vx_ * 2.0f);
default_vy_ = max_vy_ = vy_ = fabs(vx_ * 2.0f); gravity_ = 0.00f;
gravity_ = 0.00f;
const int index = static_cast<int>(size_); const int index = static_cast<int>(size_);
h_ = w_ = BALLOON_SIZE[index]; h_ = w_ = BALLOON_SIZE[index];
power_ = BALLOON_POWER[index]; power_ = BALLOON_POWER[index];
menace_ = BALLOON_MENACE[index]; menace_ = BALLOON_MENACE[index];
score_ = BALLOON_SCORE[index]; score_ = BALLOON_SCORE[index];
bouncing_sound_ = BALLOON_BOUNCING_SOUND[index]; bouncing_sound_ = BALLOON_BOUNCING_SOUND[index];
popping_sound_ = BALLOON_POPPING_SOUND[index]; popping_sound_ = BALLOON_POPPING_SOUND[index];
break; break;
} }
case BalloonType::POWERBALL: case BalloonType::POWERBALL: {
{ constexpr int index = 3;
constexpr int index = 3; h_ = w_ = BALLOON_SIZE[4];
h_ = w_ = BALLOON_SIZE[4]; bouncing_sound_ = BALLOON_BOUNCING_SOUND[3];
bouncing_sound_ = BALLOON_BOUNCING_SOUND[3]; popping_sound_ = "power_ball_explosion.wav";
popping_sound_ = "power_ball_explosion.wav"; power_ = score_ = menace_ = 0;
power_ = score_ = menace_ = 0;
vy_ = 0; vy_ = 0;
max_vy_ = 3.0f; max_vy_ = 3.0f;
gravity_ = param.balloon.settings.at(index).grav; gravity_ = param.balloon.settings.at(index).grav;
default_vy_ = param.balloon.settings.at(index).vel; default_vy_ = param.balloon.settings.at(index).vel;
sprite_->setRotate(creation_timer <= 0); sprite_->setRotate(creation_timer <= 0);
sprite_->setRotateAmount(vx_ > 0.0f ? 2.0 : -2.0); sprite_->setRotateAmount(vx_ > 0.0f ? 2.0 : -2.0);
break; break;
} }
default: default:
break; break;
} }
// Configura el sprite // Configura el sprite
sprite_->setWidth(w_); sprite_->setWidth(w_);
sprite_->setHeight(h_); sprite_->setHeight(h_);
shiftSprite(); shiftSprite();
// Alinea el circulo de colisión con el objeto // Alinea el circulo de colisión con el objeto
collider_.r = w_ / 2; collider_.r = w_ / 2;
shiftColliders(); shiftColliders();
// Establece la animación a usar // Establece la animación a usar
setAnimation(); setAnimation();
} }
// Centra el globo en la posición X // Centra el globo en la posición X
void Balloon::alignTo(int x) void Balloon::alignTo(int x) {
{ x_ = static_cast<float>(x - (w_ / 2));
x_ = static_cast<float>(x - (w_ / 2)); const int min_x = play_area_.x;
const int min_x = play_area_.x; const int max_x = play_area_.w - w_;
const int max_x = play_area_.w - w_; x_ = std::clamp(x_, static_cast<float>(min_x), static_cast<float>(max_x));
x_ = std::clamp(x_, static_cast<float>(min_x), static_cast<float>(max_x));
} }
// Pinta el globo en la pantalla // Pinta el globo en la pantalla
void Balloon::render() void Balloon::render() {
{ if (type_ == BalloonType::POWERBALL) {
if (type_ == BalloonType::POWERBALL) // Renderiza el fondo azul
{ {
// Renderiza el fondo azul auto sp = std::make_unique<Sprite>(sprite_->getTexture(), sprite_->getPosition());
{ sp->setSpriteClip(0, 0, BALLOON_SIZE[4], BALLOON_SIZE[4]);
auto sp = std::make_unique<Sprite>(sprite_->getTexture(), sprite_->getPosition()); sp->render();
sp->setSpriteClip(0, 0, BALLOON_SIZE[4], BALLOON_SIZE[4]); }
sp->render();
}
// Renderiza la estrella // Renderiza la estrella
if (!invulnerable_) if (!invulnerable_) {
{ SDL_FPoint p = {24.0f, 24.0f};
SDL_FPoint p = {24.0f, 24.0f}; sprite_->setRotatingCenter(p);
sprite_->setRotatingCenter(p); sprite_->render();
sprite_->render(); }
}
// Añade la máscara del borde y los reflejos // Añade la máscara del borde y los reflejos
{ {
auto sp = std::make_unique<Sprite>(sprite_->getTexture(), sprite_->getPosition()); auto sp = std::make_unique<Sprite>(sprite_->getTexture(), sprite_->getPosition());
sp->setSpriteClip(BALLOON_SIZE[4] * 2, 0, BALLOON_SIZE[4], BALLOON_SIZE[4]); sp->setSpriteClip(BALLOON_SIZE[4] * 2, 0, BALLOON_SIZE[4], BALLOON_SIZE[4]);
sp->render(); sp->render();
} }
} } else {
else // Renderizado para el resto de globos
{ if (isBeingCreated()) {
// Renderizado para el resto de globos // Renderizado con transparencia
if (isBeingCreated()) sprite_->getTexture()->setAlpha(255 - (int)((float)creation_counter_ * (255.0f / (float)creation_counter_ini_)));
{ sprite_->render();
// Renderizado con transparencia sprite_->getTexture()->setAlpha(255);
sprite_->getTexture()->setAlpha(255 - (int)((float)creation_counter_ * (255.0f / (float)creation_counter_ini_))); } else {
sprite_->render(); // Renderizado normal
sprite_->getTexture()->setAlpha(255); sprite_->render();
} }
else }
{
// Renderizado normal
sprite_->render();
}
}
} }
// Actualiza la posición y estados del globo // Actualiza la posición y estados del globo
void Balloon::move() void Balloon::move() {
{ // Comprueba si se puede mover
// Comprueba si se puede mover if (!isStopped()) {
if (!isStopped()) // Mueve el globo en horizontal
{ x_ += vx_ * speed_;
// Mueve el globo en horizontal
x_ += vx_ * speed_;
// Colisión en las partes laterales de la zona de juego // Colisión en las partes laterales de la zona de juego
const int clip = 2; const int clip = 2;
const float min_x = play_area_.x - clip; const float min_x = play_area_.x - clip;
const float max_x = play_area_.x + play_area_.w - w_ + clip; const float max_x = play_area_.x + play_area_.w - w_ + clip;
if (x_ < min_x || x_ > max_x) if (x_ < min_x || x_ > max_x) {
{ if (bouncing_sound_enabled_)
if (bouncing_sound_enabled_) playSound(bouncing_sound_);
playSound(bouncing_sound_); x_ = std::clamp(x_, min_x, max_x);
x_ = std::clamp(x_, min_x, max_x); vx_ = -vx_;
vx_ = -vx_; // Activa el efecto de rebote o invierte la rotación
// Activa el efecto de rebote o invierte la rotación if (type_ == BalloonType::POWERBALL) {
if (type_ == BalloonType::POWERBALL) sprite_->switchRotate();
{ } else {
sprite_->switchRotate(); enableBounce();
} }
else }
{
enableBounce();
}
}
// Mueve el globo en vertical // Mueve el globo en vertical
y_ += vy_ * speed_; y_ += vy_ * speed_;
// Colisión en la parte superior solo si el globo va de subida // Colisión en la parte superior solo si el globo va de subida
if (vy_ < 0) if (vy_ < 0) {
{ const int min_y = play_area_.y;
const int min_y = play_area_.y; if (y_ < min_y) {
if (y_ < min_y) if (bouncing_sound_enabled_)
{ playSound(bouncing_sound_);
if (bouncing_sound_enabled_) y_ = min_y;
playSound(bouncing_sound_); vy_ = -vy_;
y_ = min_y; enableBounce();
vy_ = -vy_; }
enableBounce(); }
}
}
// Colisión en la parte inferior de la zona de juego // Colisión en la parte inferior de la zona de juego
const int max_y = play_area_.y + play_area_.h - h_; const int max_y = play_area_.y + play_area_.h - h_;
if (y_ > max_y) if (y_ > max_y) {
{ if (bouncing_sound_enabled_)
if (bouncing_sound_enabled_) playSound(bouncing_sound_);
playSound(bouncing_sound_); y_ = max_y;
y_ = max_y; vy_ = -default_vy_;
vy_ = -default_vy_; if (type_ != BalloonType::POWERBALL) {
if (type_ != BalloonType::POWERBALL) enableBounce();
{ } else {
enableBounce(); setInvulnerable(false);
} }
else }
{
setInvulnerable(false);
}
}
/* /*
Para aplicar la gravedad, el diseño original la aplicaba en cada iteración del bucle Para aplicar la gravedad, el diseño original la aplicaba en cada iteración del bucle
Al añadir el modificador de velocidad se reduce la distancia que recorre el objeto y por Al añadir el modificador de velocidad se reduce la distancia que recorre el objeto y por
tanto recibe mas gravedad. Para solucionarlo se va a aplicar la gravedad cuando se haya tanto recibe mas gravedad. Para solucionarlo se va a aplicar la gravedad cuando se haya
recorrido una distancia igual a la velocidad en Y, que era el cálculo inicial recorrido una distancia igual a la velocidad en Y, que era el cálculo inicial
*/ */
// Incrementa la variable que calcula la distancia acumulada en Y // Incrementa la variable que calcula la distancia acumulada en Y
travel_y_ += speed_; travel_y_ += speed_;
// Si la distancia acumulada en Y es igual a la velocidad, se aplica la gravedad // Si la distancia acumulada en Y es igual a la velocidad, se aplica la gravedad
if (travel_y_ >= 1.0f) if (travel_y_ >= 1.0f) {
{ // Quita el excedente
// Quita el excedente travel_y_ -= 1.0f;
travel_y_ -= 1.0f;
// Aplica la gravedad al objeto sin pasarse de una velocidad máxima // Aplica la gravedad al objeto sin pasarse de una velocidad máxima
vy_ += gravity_; vy_ += gravity_;
} }
} }
} }
// Actualiza al globo a su posicion, animación y controla los contadores // Actualiza al globo a su posicion, animación y controla los contadores
void Balloon::update() void Balloon::update() {
{ move();
move(); updateState();
updateState(); updateBounce();
updateBounce(); shiftSprite();
shiftSprite(); shiftColliders();
shiftColliders(); sprite_->update();
sprite_->update(); ++counter_;
++counter_;
} }
// Actualiza los estados del globo // Actualiza los estados del globo
void Balloon::updateState() void Balloon::updateState() {
{ // Si se está creando
// Si se está creando if (isBeingCreated()) {
if (isBeingCreated()) // Actualiza el valor de las variables
{ stop();
// Actualiza el valor de las variables setInvulnerable(true);
stop();
setInvulnerable(true);
if (creation_counter_ > 0) if (creation_counter_ > 0) {
{ // Desplaza lentamente el globo hacia abajo y hacia un lado
// Desplaza lentamente el globo hacia abajo y hacia un lado if (creation_counter_ % 10 == 0) {
if (creation_counter_ % 10 == 0) y_++;
{ x_ += vx_;
y_++;
x_ += vx_;
// Comprueba no se salga por los laterales // Comprueba no se salga por los laterales
const int min_x = play_area_.x; const int min_x = play_area_.x;
const int max_x = play_area_.w - w_; const int max_x = play_area_.w - w_;
if (x_ < min_x || x_ > max_x) if (x_ < min_x || x_ > max_x) {
{ // Corrige y cambia el sentido de la velocidad
// Corrige y cambia el sentido de la velocidad x_ -= vx_;
x_ -= vx_; vx_ = -vx_;
vx_ = -vx_; }
} }
} --creation_counter_;
--creation_counter_; }
}
else else {
{ // El contador ha llegado a cero
// El contador ha llegado a cero being_created_ = false;
being_created_ = false; start();
start(); setInvulnerable(false);
setInvulnerable(false); setAnimation();
setAnimation(); }
} }
}
} }
// Establece la animación correspondiente al estado // Establece la animación correspondiente al estado
void Balloon::setAnimation() void Balloon::setAnimation() {
{ std::string creating_animation;
std::string creating_animation; std::string normal_animation;
std::string normal_animation;
switch (type_) switch (type_) {
{ case BalloonType::POWERBALL:
case BalloonType::POWERBALL: creating_animation = "powerball";
creating_animation = "powerball"; normal_animation = "powerball";
normal_animation = "powerball"; break;
break; case BalloonType::FLOATER:
case BalloonType::FLOATER: creating_animation = param.balloon.color.at(2);
creating_animation = param.balloon.color.at(2); normal_animation = param.balloon.color.at(3);
normal_animation = param.balloon.color.at(3); break;
break; default:
default: creating_animation = param.balloon.color.at(0);
creating_animation = param.balloon.color.at(0); normal_animation = param.balloon.color.at(1);
normal_animation = param.balloon.color.at(1); break;
break; }
}
// Establece el frame de animación // Establece el frame de animación
if (use_reversed_colors_) if (use_reversed_colors_)
sprite_->setCurrentAnimation(creating_animation); sprite_->setCurrentAnimation(creating_animation);
else else
sprite_->setCurrentAnimation(isBeingCreated() ? creating_animation : normal_animation); sprite_->setCurrentAnimation(isBeingCreated() ? creating_animation : normal_animation);
} }
// Detiene el globo // Detiene el globo
void Balloon::stop() void Balloon::stop() {
{ stopped_ = true;
stopped_ = true; if (isPowerBall()) {
if (isPowerBall()) sprite_->setRotate(!stopped_);
{ }
sprite_->setRotate(!stopped_);
}
} }
// Pone el globo en movimiento // Pone el globo en movimiento
void Balloon::start() void Balloon::start() {
{ stopped_ = false;
stopped_ = false; if (isPowerBall()) {
if (isPowerBall()) sprite_->setRotate(!stopped_);
{ }
sprite_->setRotate(!stopped_);
}
} }
// Alinea el circulo de colisión con la posición del objeto globo // Alinea el circulo de colisión con la posición del objeto globo
void Balloon::shiftColliders() void Balloon::shiftColliders() {
{ collider_.x = static_cast<int>(x_) + collider_.r;
collider_.x = static_cast<int>(x_) + collider_.r; collider_.y = static_cast<int>(y_) + collider_.r;
collider_.y = static_cast<int>(y_) + collider_.r;
} }
// Alinea el sprite con la posición del objeto globo // Alinea el sprite con la posición del objeto globo
void Balloon::shiftSprite() void Balloon::shiftSprite() {
{ sprite_->setPosX(x_);
sprite_->setPosX(x_); sprite_->setPosY(y_);
sprite_->setPosY(y_);
} }
// Establece el nivel de zoom del sprite // Establece el nivel de zoom del sprite
void Balloon::zoomSprite() void Balloon::zoomSprite() {
{ sprite_->setZoomW(bouncing_.zoomW);
sprite_->setZoomW(bouncing_.zoomW); sprite_->setZoomH(bouncing_.zoomH);
sprite_->setZoomH(bouncing_.zoomH);
} }
// Activa el efecto // Activa el efecto
void Balloon::enableBounce() void Balloon::enableBounce() {
{ bouncing_.enabled = true;
bouncing_.enabled = true; bouncing_.reset();
bouncing_.reset(); zoomSprite();
zoomSprite();
} }
// Detiene el efecto // Detiene el efecto
void Balloon::disableBounce() void Balloon::disableBounce() {
{ bouncing_.enabled = false;
bouncing_.enabled = false; bouncing_.reset();
bouncing_.reset(); zoomSprite();
zoomSprite();
} }
// Aplica el efecto // Aplica el efecto
void Balloon::updateBounce() void Balloon::updateBounce() {
{ if (bouncing_.enabled) {
if (bouncing_.enabled) const int index = bouncing_.counter / bouncing_.speed;
{ bouncing_.zoomW = bouncing_.w[index];
const int index = bouncing_.counter / bouncing_.speed; bouncing_.zoomH = bouncing_.h[index];
bouncing_.zoomW = bouncing_.w[index];
bouncing_.zoomH = bouncing_.h[index];
zoomSprite(); zoomSprite();
if (++bouncing_.counter / bouncing_.speed >= MAX_BOUNCE) if (++bouncing_.counter / bouncing_.speed >= MAX_BOUNCE) {
{ disableBounce();
disableBounce(); }
} }
}
} }
// Pone el color alternativo en el globo // Pone el color alternativo en el globo
void Balloon::useReverseColor() void Balloon::useReverseColor() {
{ if (!isBeingCreated()) {
if (!isBeingCreated()) use_reversed_colors_ = true;
{ setAnimation();
use_reversed_colors_ = true; }
setAnimation();
}
} }
// Pone el color normal en el globo // Pone el color normal en el globo
void Balloon::useNormalColor() void Balloon::useNormalColor() {
{ use_reversed_colors_ = false;
use_reversed_colors_ = false; setAnimation();
setAnimation();
} }
// Reproduce sonido // Reproduce sonido
void Balloon::playSound(const std::string &name) void Balloon::playSound(const std::string &name) {
{ if (!sound_enabled_)
if (!sound_enabled_) return;
return;
static auto audio = Audio::get(); static auto audio = Audio::get();
audio->playSound(name); audio->playSound(name);
} }
// Explota el globo // Explota el globo
void Balloon::pop(bool should_sound) void Balloon::pop(bool should_sound) {
{ if (should_sound) {
if (should_sound) if (poping_sound_enabled_)
{ playSound(popping_sound_);
if (poping_sound_enabled_) }
playSound(popping_sound_);
}
enabled_ = false; enabled_ = false;
} }
+133 -137
View File
@@ -1,17 +1,18 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para Uint8, Uint16, SDL_FRect, Uint32 #include <SDL3/SDL.h> // Para Uint8, Uint16, SDL_FRect, Uint32
#include <memory> // Para shared_ptr, unique_ptr
#include <string> // Para basic_string, string
#include <vector> // Para vector
#include "animated_sprite.h" // Para AnimatedSprite #include <memory> // Para shared_ptr, unique_ptr
#include "utils.h" // Para Circle #include <string> // Para basic_string, string
#include <vector> // Para vector
#include "animated_sprite.h" // Para AnimatedSprite
#include "utils.h" // Para Circle
class Texture; class Texture;
// --- Constantes relacionadas con globos --- // --- Constantes relacionadas con globos ---
constexpr int MAX_BOUNCE = 10; // Cantidad de elementos del vector de deformación constexpr int MAX_BOUNCE = 10; // Cantidad de elementos del vector de deformación
constexpr int BALLOON_SCORE[] = {50, 100, 200, 400}; constexpr int BALLOON_SCORE[] = {50, 100, 200, 400};
constexpr int BALLOON_POWER[] = {1, 3, 7, 15}; constexpr int BALLOON_POWER[] = {1, 3, 7, 15};
@@ -20,19 +21,17 @@ constexpr int BALLOON_SIZE[] = {10, 16, 26, 48, 49};
const std::string BALLOON_BOUNCING_SOUND[] = {"bubble1.wav", "bubble2.wav", "bubble3.wav", "bubble4.wav"}; const std::string BALLOON_BOUNCING_SOUND[] = {"bubble1.wav", "bubble2.wav", "bubble3.wav", "bubble4.wav"};
const std::string BALLOON_POPPING_SOUND[] = {"balloon1.wav", "balloon2.wav", "balloon3.wav", "balloon4.wav"}; const std::string BALLOON_POPPING_SOUND[] = {"balloon1.wav", "balloon2.wav", "balloon3.wav", "balloon4.wav"};
enum class BalloonSize : Uint8 enum class BalloonSize : Uint8 {
{ SIZE1 = 0,
SIZE1 = 0, SIZE2 = 1,
SIZE2 = 1, SIZE3 = 2,
SIZE3 = 2, SIZE4 = 3,
SIZE4 = 3,
}; };
enum class BalloonType : Uint8 enum class BalloonType : Uint8 {
{ BALLOON = 0,
BALLOON = 0, FLOATER = 1,
FLOATER = 1, POWERBALL = 2,
POWERBALL = 2,
}; };
constexpr float BALLOON_VELX_POSITIVE = 0.7f; constexpr float BALLOON_VELX_POSITIVE = 0.7f;
@@ -48,133 +47,130 @@ constexpr int POWERBALL_SCREENPOWER_MINIMUM = 10;
constexpr int POWERBALL_COUNTER = 8; constexpr int POWERBALL_COUNTER = 8;
// --- Clase Balloon --- // --- Clase Balloon ---
class Balloon class Balloon {
{ public:
public: // --- Constructores y destructor ---
// --- Constructores y destructor --- Balloon(
Balloon( float x,
float x, float y,
float y, BalloonType type,
BalloonType type, BalloonSize size,
BalloonSize size, float vel_x,
float vel_x, float speed,
float speed, Uint16 creation_timer,
Uint16 creation_timer, SDL_FRect play_area,
SDL_FRect play_area, std::shared_ptr<Texture> texture,
std::shared_ptr<Texture> texture, const std::vector<std::string> &animation);
const std::vector<std::string> &animation); ~Balloon() = default;
~Balloon() = default;
// --- Métodos principales --- // --- Métodos principales ---
void alignTo(int x); // Centra el globo en la posición X void alignTo(int x); // Centra el globo en la posición X
void render(); // Pinta el globo en la pantalla void render(); // Pinta el globo en la pantalla
void move(); // Actualiza la posición y estados del globo void move(); // Actualiza la posición y estados del globo
void update(); // Actualiza el globo (posición, animación, contadores) void update(); // Actualiza el globo (posición, animación, contadores)
void stop(); // Detiene el globo void stop(); // Detiene el globo
void start(); // Pone el globo en movimiento void start(); // Pone el globo en movimiento
void pop(bool should_sound = false); // Explota el globo void pop(bool should_sound = false); // Explota el globo
// --- Métodos de color --- // --- Métodos de color ---
void useReverseColor(); // Pone el color alternativo en el globo void useReverseColor(); // Pone el color alternativo en el globo
void useNormalColor(); // Pone el color normal en el globo void useNormalColor(); // Pone el color normal en el globo
// --- Getters --- // --- Getters ---
float getPosX() const { return x_; } float getPosX() const { return x_; }
float getPosY() const { return y_; } float getPosY() const { return y_; }
int getWidth() const { return w_; } int getWidth() const { return w_; }
int getHeight() const { return h_; } int getHeight() const { return h_; }
BalloonSize getSize() const { return size_; } BalloonSize getSize() const { return size_; }
BalloonType getType() const { return type_; } BalloonType getType() const { return type_; }
Uint16 getScore() const { return score_; } Uint16 getScore() const { return score_; }
Circle &getCollider() { return collider_; } Circle &getCollider() { return collider_; }
Uint8 getMenace() const { return isEnabled() ? menace_ : 0; } Uint8 getMenace() const { return isEnabled() ? menace_ : 0; }
Uint8 getPower() const { return power_; } Uint8 getPower() const { return power_; }
bool isStopped() const { return stopped_; } bool isStopped() const { return stopped_; }
bool isPowerBall() const { return type_ == BalloonType::POWERBALL; } bool isPowerBall() const { return type_ == BalloonType::POWERBALL; }
bool isInvulnerable() const { return invulnerable_; } bool isInvulnerable() const { return invulnerable_; }
bool isBeingCreated() const { return being_created_; } bool isBeingCreated() const { return being_created_; }
bool isEnabled() const { return enabled_; } bool isEnabled() const { return enabled_; }
bool isUsingReversedColor() { return use_reversed_colors_; } bool isUsingReversedColor() { return use_reversed_colors_; }
bool canBePopped() const { return !isBeingCreated(); } bool canBePopped() const { return !isBeingCreated(); }
// --- Setters --- // --- Setters ---
void setVelY(float vel_y) { vy_ = vel_y; } void setVelY(float vel_y) { vy_ = vel_y; }
void setSpeed(float speed) { speed_ = speed; } void setSpeed(float speed) { speed_ = speed; }
void setInvulnerable(bool value) { invulnerable_ = value; } void setInvulnerable(bool value) { invulnerable_ = value; }
void setBouncingSound(bool value) { bouncing_sound_enabled_ = value; } void setBouncingSound(bool value) { bouncing_sound_enabled_ = value; }
void setPoppingSound(bool value) { poping_sound_enabled_ = value; } void setPoppingSound(bool value) { poping_sound_enabled_ = value; }
void setSound(bool value) { sound_enabled_ = value; } void setSound(bool value) { sound_enabled_ = value; }
private: private:
// --- Estructura para el efecto de rebote --- // --- Estructura para el efecto de rebote ---
struct Bouncing struct Bouncing {
{ bool enabled = false; // Si el efecto está activo
bool enabled = false; // Si el efecto está activo Uint8 counter = 0; // Contador para el efecto
Uint8 counter = 0; // Contador para el efecto Uint8 speed = 2; // Velocidad del efecto
Uint8 speed = 2; // Velocidad del efecto float zoomW = 1.0f; // Zoom en anchura
float zoomW = 1.0f; // Zoom en anchura float zoomH = 1.0f; // Zoom en altura
float zoomH = 1.0f; // Zoom en altura float despX = 0.0f; // Desplazamiento X antes de pintar
float despX = 0.0f; // Desplazamiento X antes de pintar float despY = 0.0f; // Desplazamiento Y antes de pintar
float despY = 0.0f; // Desplazamiento Y antes de pintar
float w[MAX_BOUNCE] = {1.10f, 1.05f, 1.00f, 0.95f, 0.90f, 0.95f, 1.00f, 1.02f, 1.05f, 1.02f}; // Zoom ancho float w[MAX_BOUNCE] = {1.10f, 1.05f, 1.00f, 0.95f, 0.90f, 0.95f, 1.00f, 1.02f, 1.05f, 1.02f}; // Zoom ancho
float h[MAX_BOUNCE] = {0.90f, 0.95f, 1.00f, 1.05f, 1.10f, 1.05f, 1.00f, 0.98f, 0.95f, 0.98f}; // Zoom alto float h[MAX_BOUNCE] = {0.90f, 0.95f, 1.00f, 1.05f, 1.10f, 1.05f, 1.00f, 0.98f, 0.95f, 0.98f}; // Zoom alto
Bouncing() = default; Bouncing() = default;
void reset() void reset() {
{ counter = 0;
counter = 0; zoomW = 1.0f;
zoomW = 1.0f; zoomH = 1.0f;
zoomH = 1.0f; despX = 0.0f;
despX = 0.0f; despY = 0.0f;
despY = 0.0f; }
} } bouncing_;
} bouncing_;
// --- Objetos y punteros --- // --- Objetos y punteros ---
std::unique_ptr<AnimatedSprite> sprite_; // Sprite del objeto globo std::unique_ptr<AnimatedSprite> sprite_; // Sprite del objeto globo
// --- Variables de estado y físicas --- // --- Variables de estado y físicas ---
float x_; // Posición X float x_; // Posición X
float y_; // Posición Y float y_; // Posición Y
float w_; // Ancho float w_; // Ancho
float h_; // Alto float h_; // Alto
float vx_; // Velocidad X float vx_; // Velocidad X
float vy_; // Velocidad Y float vy_; // Velocidad Y
float gravity_; // Aceleración en Y float gravity_; // Aceleración en Y
float default_vy_; // Velocidad inicial al rebotar float default_vy_; // Velocidad inicial al rebotar
float max_vy_; // Máxima velocidad en Y float max_vy_; // Máxima velocidad en Y
bool being_created_; // Si el globo se está creando bool being_created_; // Si el globo se está creando
bool enabled_ = true; // Si el globo está activo bool enabled_ = true; // Si el globo está activo
bool invulnerable_; // Si el globo es invulnerable bool invulnerable_; // Si el globo es invulnerable
bool stopped_; // Si el globo está parado bool stopped_; // Si el globo está parado
bool use_reversed_colors_ = false; // Si se usa el color alternativo bool use_reversed_colors_ = false; // Si se usa el color alternativo
Circle collider_; // Círculo de colisión Circle collider_; // Círculo de colisión
Uint16 creation_counter_; // Temporizador de creación Uint16 creation_counter_; // Temporizador de creación
Uint16 creation_counter_ini_; // Valor inicial del temporizador de creación Uint16 creation_counter_ini_; // Valor inicial del temporizador de creación
Uint16 score_; // Puntos al destruir el globo Uint16 score_; // Puntos al destruir el globo
BalloonType type_; // Tipo de globo BalloonType type_; // Tipo de globo
BalloonSize size_; // Tamaño de globo BalloonSize size_; // Tamaño de globo
Uint8 menace_; // Amenaza que genera el globo Uint8 menace_; // Amenaza que genera el globo
Uint32 counter_ = 0; // Contador interno Uint32 counter_ = 0; // Contador interno
float travel_y_ = 1.0f; // Distancia a recorrer en Y antes de aplicar gravedad float travel_y_ = 1.0f; // Distancia a recorrer en Y antes de aplicar gravedad
float speed_; // Velocidad del globo float speed_; // Velocidad del globo
Uint8 power_; // Poder que alberga el globo Uint8 power_; // Poder que alberga el globo
SDL_FRect play_area_; // Zona de movimiento del globo SDL_FRect play_area_; // Zona de movimiento del globo
std::string bouncing_sound_; // Archivo de sonido al rebotar std::string bouncing_sound_; // Archivo de sonido al rebotar
std::string popping_sound_; // Archivo de sonido al explotar std::string popping_sound_; // Archivo de sonido al explotar
bool bouncing_sound_enabled_ = false; // Si debe sonar el globo al rebotar bool bouncing_sound_enabled_ = false; // Si debe sonar el globo al rebotar
bool poping_sound_enabled_ = true; // Si debe sonar el globo al explotar bool poping_sound_enabled_ = true; // Si debe sonar el globo al explotar
bool sound_enabled_ = true; // Indica si los globos deben hacer algun sonido bool sound_enabled_ = true; // Indica si los globos deben hacer algun sonido
// --- Métodos internos --- // --- Métodos internos ---
void shiftColliders(); // Alinea el círculo de colisión void shiftColliders(); // Alinea el círculo de colisión
void shiftSprite(); // Alinea el sprite void shiftSprite(); // Alinea el sprite
void zoomSprite(); // Establece el nivel de zoom del sprite void zoomSprite(); // Establece el nivel de zoom del sprite
void enableBounce(); // Activa el efecto de rebote void enableBounce(); // Activa el efecto de rebote
void disableBounce(); // Detiene el efecto de rebote void disableBounce(); // Detiene el efecto de rebote
void updateBounce(); // Aplica el efecto de rebote void updateBounce(); // Aplica el efecto de rebote
void updateState(); // Actualiza los estados del globo void updateState(); // Actualiza los estados del globo
void setAnimation(); // Establece la animación correspondiente void setAnimation(); // Establece la animación correspondiente
void playSound(const std::string &name); // Reproduce sonido void playSound(const std::string &name); // Reproduce sonido
}; };
+324 -404
View File
@@ -1,457 +1,377 @@
#include "balloon_formations.h" #include "balloon_formations.h"
#include "balloon.h" // Para BALLOON_VELX_NEGATIVE, BALLOON_VELX_POSITIVE #include "balloon.h" // Para BALLOON_VELX_NEGATIVE, BALLOON_VELX_POSITIVE
#include "param.h" // Para param #include "param.h" // Para param
#include "utils.h" // Para ParamGame, Param, Zone, BLOCK #include "utils.h" // Para ParamGame, Param, Zone, BLOCK
void BalloonFormations::initBalloonFormations() void BalloonFormations::initBalloonFormations() {
{ constexpr int y4 = -BLOCK;
constexpr int y4 = -BLOCK; const int x4_0 = param.game.play_area.rect.x;
const int x4_0 = param.game.play_area.rect.x; const int x4_100 = param.game.play_area.rect.w - BALLOON_SIZE[3];
const int x4_100 = param.game.play_area.rect.w - BALLOON_SIZE[3];
constexpr int y3 = -BLOCK; constexpr int y3 = -BLOCK;
const int x3_0 = param.game.play_area.rect.x; const int x3_0 = param.game.play_area.rect.x;
const int x3_100 = param.game.play_area.rect.w - BALLOON_SIZE[2]; const int x3_100 = param.game.play_area.rect.w - BALLOON_SIZE[2];
constexpr int y2 = -BLOCK; constexpr int y2 = -BLOCK;
const int x2_0 = param.game.play_area.rect.x; const int x2_0 = param.game.play_area.rect.x;
const int x2_100 = param.game.play_area.rect.w - BALLOON_SIZE[1]; const int x2_100 = param.game.play_area.rect.w - BALLOON_SIZE[1];
constexpr int y1 = -BLOCK; constexpr int y1 = -BLOCK;
const int x1_0 = param.game.play_area.rect.x; const int x1_0 = param.game.play_area.rect.x;
const int x1_50 = param.game.play_area.center_x - (BALLOON_SIZE[0] / 2); const int x1_50 = param.game.play_area.center_x - (BALLOON_SIZE[0] / 2);
const int x1_100 = param.game.play_area.rect.w - BALLOON_SIZE[0]; const int x1_100 = param.game.play_area.rect.w - BALLOON_SIZE[0];
balloon_formation_.reserve(NUMBER_OF_BALLOON_FORMATIONS); balloon_formation_.reserve(NUMBER_OF_BALLOON_FORMATIONS);
constexpr int CREATION_TIME = 300; constexpr int CREATION_TIME = 300;
// #00 - Dos enemigos BALLOON4 uno a cada extremo // #00 - Dos enemigos BALLOON4 uno a cada extremo
{ {
std::vector<BalloonFormationParams> init_params = { std::vector<BalloonFormationParams> init_params = {
BalloonFormationParams(x4_0, y4, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME), BalloonFormationParams(x4_0, y4, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME),
BalloonFormationParams(x4_100, y4, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME)}; BalloonFormationParams(x4_100, y4, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME)};
balloon_formation_.emplace_back(2, init_params); balloon_formation_.emplace_back(2, init_params);
} }
// #01 - Dos enemigos BALLOON4 uno a cada cuarto. Ambos van hacia el centro // #01 - Dos enemigos BALLOON4 uno a cada cuarto. Ambos van hacia el centro
{ {
std::vector<BalloonFormationParams> init_params = { std::vector<BalloonFormationParams> init_params = {
BalloonFormationParams(param.game.play_area.first_quarter_x - (BALLOON_SIZE[3] / 2), y4, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME), BalloonFormationParams(param.game.play_area.first_quarter_x - (BALLOON_SIZE[3] / 2), y4, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME),
BalloonFormationParams(param.game.play_area.third_quarter_x - (BALLOON_SIZE[3] / 2), y4, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME)}; BalloonFormationParams(param.game.play_area.third_quarter_x - (BALLOON_SIZE[3] / 2), y4, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME)};
balloon_formation_.emplace_back(2, init_params); balloon_formation_.emplace_back(2, init_params);
} }
// #02 - Cuatro enemigos BALLOON2 uno detrás del otro. A la izquierda y hacia el centro // #02 - Cuatro enemigos BALLOON2 uno detrás del otro. A la izquierda y hacia el centro
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i) {
{ init_params.emplace_back(x2_0 + (i * (BALLOON_SIZE[1] + 1)), y2, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE2, CREATION_TIME - (10 * i));
init_params.emplace_back(x2_0 + (i * (BALLOON_SIZE[1] + 1)), y2, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE2, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(4, init_params);
balloon_formation_.emplace_back(4, init_params); }
}
// #03 - Cuatro enemigos BALLOON2 uno detrás del otro. A la derecha y hacia el centro // #03 - Cuatro enemigos BALLOON2 uno detrás del otro. A la derecha y hacia el centro
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i) {
{ init_params.emplace_back(x2_100 - (i * (BALLOON_SIZE[1] + 1)), y2, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE2, CREATION_TIME - (10 * i));
init_params.emplace_back(x2_100 - (i * (BALLOON_SIZE[1] + 1)), y2, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE2, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(4, init_params);
balloon_formation_.emplace_back(4, init_params); }
}
// #04 - Tres enemigos BALLOON3. 0, 25, 50. Hacia la derecha // #04 - Tres enemigos BALLOON3. 0, 25, 50. Hacia la derecha
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i) {
{ init_params.emplace_back(x3_0 + (i * (BALLOON_SIZE[2] * 2)), y3, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i));
init_params.emplace_back(x3_0 + (i * (BALLOON_SIZE[2] * 2)), y3, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(3, init_params);
balloon_formation_.emplace_back(3, init_params); }
}
// #05 - Tres enemigos BALLOON3. 50, 75, 100. Hacia la izquierda // #05 - Tres enemigos BALLOON3. 50, 75, 100. Hacia la izquierda
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i) {
{ init_params.emplace_back(x3_100 - (i * (BALLOON_SIZE[2] * 2)), y3, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i));
init_params.emplace_back(x3_100 - (i * (BALLOON_SIZE[2] * 2)), y3, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(3, init_params);
balloon_formation_.emplace_back(3, init_params); }
}
// #06 - Tres enemigos BALLOON3. 0, 0, 0. Hacia la derecha // #06 - Tres enemigos BALLOON3. 0, 0, 0. Hacia la derecha
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i) {
{ init_params.emplace_back(x3_0 + (i * (BALLOON_SIZE[2] + 1)), y3, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i));
init_params.emplace_back(x3_0 + (i * (BALLOON_SIZE[2] + 1)), y3, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(3, init_params);
balloon_formation_.emplace_back(3, init_params); }
}
// #07 - Tres enemigos BALLOON3. 100, 100, 100. Hacia la izquierda // #07 - Tres enemigos BALLOON3. 100, 100, 100. Hacia la izquierda
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i) {
{ init_params.emplace_back(x3_100 - (i * (BALLOON_SIZE[2] + 1)), y3, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i));
init_params.emplace_back(x3_100 - (i * (BALLOON_SIZE[2] + 1)), y3, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(3, init_params);
balloon_formation_.emplace_back(3, init_params); }
}
// #08 - Seis enemigos BALLOON1. 0, 0, 0, 0, 0, 0. Hacia la derecha // #08 - Seis enemigos BALLOON1. 0, 0, 0, 0, 0, 0. Hacia la derecha
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 6; ++i) for (int i = 0; i < 6; ++i) {
{ init_params.emplace_back(x1_0 + (i * (BALLOON_SIZE[0] + 1)), y1, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME - (10 * i));
init_params.emplace_back(x1_0 + (i * (BALLOON_SIZE[0] + 1)), y1, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(6, init_params);
balloon_formation_.emplace_back(6, init_params); }
}
// #09 - Seis enemigos BALLOON1. 100, 100, 100, 100, 100, 100. Hacia la izquierda // #09 - Seis enemigos BALLOON1. 100, 100, 100, 100, 100, 100. Hacia la izquierda
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 6; ++i) for (int i = 0; i < 6; ++i) {
{ init_params.emplace_back(x1_100 - (i * (BALLOON_SIZE[0] + 1)), y1, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME - (10 * i));
init_params.emplace_back(x1_100 - (i * (BALLOON_SIZE[0] + 1)), y1, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(6, init_params);
balloon_formation_.emplace_back(6, init_params); }
}
// #10 - Tres enemigos BALLOON4 seguidos desde la izquierda. Hacia la derecha // #10 - Tres enemigos BALLOON4 seguidos desde la izquierda. Hacia la derecha
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i) {
{ init_params.emplace_back(x4_0 + (i * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME - (15 * i));
init_params.emplace_back(x4_0 + (i * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME - (15 * i)); }
} balloon_formation_.emplace_back(3, init_params);
balloon_formation_.emplace_back(3, init_params); }
}
// #11 - Tres enemigos BALLOON4 seguidos desde la derecha. Hacia la izquierda // #11 - Tres enemigos BALLOON4 seguidos desde la derecha. Hacia la izquierda
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i) {
{ init_params.emplace_back(x4_100 - (i * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME - (15 * i));
init_params.emplace_back(x4_100 - (i * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME - (15 * i)); }
} balloon_formation_.emplace_back(3, init_params);
balloon_formation_.emplace_back(3, init_params); }
}
// #12 - Seis enemigos BALLOON2 uno detrás del otro. A la izquierda y hacia el centro // #12 - Seis enemigos BALLOON2 uno detrás del otro. A la izquierda y hacia el centro
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 6; ++i) for (int i = 0; i < 6; ++i) {
{ init_params.emplace_back(x2_0 + (i * (BALLOON_SIZE[1] + 1)), y2, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE2, CREATION_TIME - (10 * i));
init_params.emplace_back(x2_0 + (i * (BALLOON_SIZE[1] + 1)), y2, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE2, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(6, init_params);
balloon_formation_.emplace_back(6, init_params); }
}
// #13 - Seis enemigos BALLOON2 uno detrás del otro. A la derecha y hacia el centro // #13 - Seis enemigos BALLOON2 uno detrás del otro. A la derecha y hacia el centro
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 6; ++i) for (int i = 0; i < 6; ++i) {
{ init_params.emplace_back(x2_100 - (i * (BALLOON_SIZE[1] + 1)), y2, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE2, CREATION_TIME - (10 * i));
init_params.emplace_back(x2_100 - (i * (BALLOON_SIZE[1] + 1)), y2, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE2, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(6, init_params);
balloon_formation_.emplace_back(6, init_params); }
}
// #14 - Cinco enemigos BALLOON3. Hacia la derecha. Separados // #14 - Cinco enemigos BALLOON3. Hacia la derecha. Separados
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 5; ++i) for (int i = 0; i < 5; ++i) {
{ init_params.emplace_back(x3_0 + (i * (BALLOON_SIZE[2] * 2)), y3, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i));
init_params.emplace_back(x3_0 + (i * (BALLOON_SIZE[2] * 2)), y3, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(5, init_params);
balloon_formation_.emplace_back(5, init_params); }
}
// #15 - Cinco enemigos BALLOON3. Hacia la izquierda. Separados // #15 - Cinco enemigos BALLOON3. Hacia la izquierda. Separados
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 5; ++i) for (int i = 0; i < 5; ++i) {
{ init_params.emplace_back(x3_100 - (i * (BALLOON_SIZE[2] * 2)), y3, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i));
init_params.emplace_back(x3_100 - (i * (BALLOON_SIZE[2] * 2)), y3, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(5, init_params);
balloon_formation_.emplace_back(5, init_params); }
}
// #16 - Cinco enemigos BALLOON3. Hacia la derecha. Juntos // #16 - Cinco enemigos BALLOON3. Hacia la derecha. Juntos
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 5; ++i) for (int i = 0; i < 5; ++i) {
{ init_params.emplace_back(x3_0 + (i * (BALLOON_SIZE[2] + 1)), y3, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i));
init_params.emplace_back(x3_0 + (i * (BALLOON_SIZE[2] + 1)), y3, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(5, init_params);
balloon_formation_.emplace_back(5, init_params); }
}
// #17 - Cinco enemigos BALLOON3. Hacia la izquierda. Juntos // #17 - Cinco enemigos BALLOON3. Hacia la izquierda. Juntos
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 5; ++i) for (int i = 0; i < 5; ++i) {
{ init_params.emplace_back(x3_100 - (i * (BALLOON_SIZE[2] + 1)), y3, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i));
init_params.emplace_back(x3_100 - (i * (BALLOON_SIZE[2] + 1)), y3, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(5, init_params);
balloon_formation_.emplace_back(5, init_params); }
}
// #18 - Doce enemigos BALLOON1. Hacia la derecha. Juntos // #18 - Doce enemigos BALLOON1. Hacia la derecha. Juntos
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 12; ++i) for (int i = 0; i < 12; ++i) {
{ init_params.emplace_back(x1_0 + (i * (BALLOON_SIZE[0] + 1)), y1, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME - (10 * i));
init_params.emplace_back(x1_0 + (i * (BALLOON_SIZE[0] + 1)), y1, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(12, init_params);
balloon_formation_.emplace_back(12, init_params); }
}
// #19 - Doce enemigos BALLOON1. Hacia la izquierda. Juntos // #19 - Doce enemigos BALLOON1. Hacia la izquierda. Juntos
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
for (int i = 0; i < 12; ++i) for (int i = 0; i < 12; ++i) {
{ init_params.emplace_back(x1_100 - (i * (BALLOON_SIZE[0] + 1)), y1, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME - (10 * i));
init_params.emplace_back(x1_100 - (i * (BALLOON_SIZE[0] + 1)), y1, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME - (10 * i)); }
} balloon_formation_.emplace_back(12, init_params);
balloon_formation_.emplace_back(12, init_params); }
}
// #20 - Dos enemigos BALLOON4 seguidos desde la izquierda/derecha. Simétricos // #20 - Dos enemigos BALLOON4 seguidos desde la izquierda/derecha. Simétricos
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
const int half = 4 / 2; const int half = 4 / 2;
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i) {
{ if (i < half) {
if (i < half) init_params.emplace_back(x4_0 + (i * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME + (0 * i));
{ } else {
init_params.emplace_back(x4_0 + (i * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME + (0 * i)); init_params.emplace_back(x4_100 - ((i - half) * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME + (0 * i));
} }
else }
{ balloon_formation_.emplace_back(4, init_params);
init_params.emplace_back(x4_100 - ((i - half) * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME + (0 * i)); }
}
}
balloon_formation_.emplace_back(4, init_params);
}
// #20 - Dos enemigos BALLOON4 seguidos desde la izquierda/derecha. Simétricos // #20 - Dos enemigos BALLOON4 seguidos desde la izquierda/derecha. Simétricos
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
const int half = 4 / 2; const int half = 4 / 2;
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i) {
{ if (i < half) {
if (i < half) init_params.emplace_back(x4_0 + (i * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME + (0 * i));
{ } else {
init_params.emplace_back(x4_0 + (i * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME + (0 * i)); init_params.emplace_back(x4_100 - ((i - half) * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME + (0 * i));
} }
else }
{ balloon_formation_.emplace_back(4, init_params);
init_params.emplace_back(x4_100 - ((i - half) * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME + (0 * i)); }
}
}
balloon_formation_.emplace_back(4, init_params);
}
// #21 - Diez enemigos BALLOON2 uno detrás del otro. Izquierda/derecha. Simétricos // #21 - Diez enemigos BALLOON2 uno detrás del otro. Izquierda/derecha. Simétricos
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
const int half = 10 / 2; const int half = 10 / 2;
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i) {
{ if (i < half) {
if (i < half) init_params.emplace_back(x2_0 + (i * (BALLOON_SIZE[1] + 1)), y2, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE2, CREATION_TIME - (3 * i));
{ } else {
init_params.emplace_back(x2_0 + (i * (BALLOON_SIZE[1] + 1)), y2, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE2, CREATION_TIME - (3 * i)); init_params.emplace_back(x2_100 - ((i - half) * (BALLOON_SIZE[1] + 1)), y2, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE2, CREATION_TIME - (3 * (i - half)));
} }
else }
{ balloon_formation_.emplace_back(10, init_params);
init_params.emplace_back(x2_100 - ((i - half) * (BALLOON_SIZE[1] + 1)), y2, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE2, CREATION_TIME - (3 * (i - half))); }
}
}
balloon_formation_.emplace_back(10, init_params);
}
// #22 - Diez enemigos BALLOON3. Hacia la derecha/izquierda. Separados. Simétricos // #22 - Diez enemigos BALLOON3. Hacia la derecha/izquierda. Separados. Simétricos
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
const int half = 10 / 2; const int half = 10 / 2;
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i) {
{ if (i < half) {
if (i < half) init_params.emplace_back(x3_0 + (i * (BALLOON_SIZE[2] * 2)), y3, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i));
{ } else {
init_params.emplace_back(x3_0 + (i * (BALLOON_SIZE[2] * 2)), y3, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i)); init_params.emplace_back(x3_100 - ((i - half) * (BALLOON_SIZE[2] * 2)), y3, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * (i - half)));
} }
else }
{ balloon_formation_.emplace_back(10, init_params);
init_params.emplace_back(x3_100 - ((i - half) * (BALLOON_SIZE[2] * 2)), y3, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * (i - half))); }
}
}
balloon_formation_.emplace_back(10, init_params);
}
// #23 - Diez enemigos BALLOON3. Hacia la derecha. Juntos. Simétricos // #23 - Diez enemigos BALLOON3. Hacia la derecha. Juntos. Simétricos
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
const int half = 10 / 2; const int half = 10 / 2;
for (int i = 0; i < 10; ++i) for (int i = 0; i < 10; ++i) {
{ if (i < half) {
if (i < half) init_params.emplace_back(x3_0 + (i * (BALLOON_SIZE[2] + 1)), y3, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i));
{ } else {
init_params.emplace_back(x3_0 + (i * (BALLOON_SIZE[2] + 1)), y3, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i)); init_params.emplace_back(x3_100 - ((i - half) * (BALLOON_SIZE[2] + 1)), y3, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * (i - half)));
} }
else }
{ balloon_formation_.emplace_back(10, init_params);
init_params.emplace_back(x3_100 - ((i - half) * (BALLOON_SIZE[2] + 1)), y3, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * (i - half))); }
}
}
balloon_formation_.emplace_back(10, init_params);
}
// #24 - Treinta enemigos BALLOON1. Del centro hacia los extremos. Juntos. Simétricos // #24 - Treinta enemigos BALLOON1. Del centro hacia los extremos. Juntos. Simétricos
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
const int half = 30 / 2; const int half = 30 / 2;
for (int i = 0; i < 30; ++i) for (int i = 0; i < 30; ++i) {
{ if (i < half) {
if (i < half) init_params.emplace_back(x1_50, y1, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME + (5 * i));
{ } else {
init_params.emplace_back(x1_50, y1, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME + (5 * i)); init_params.emplace_back(x1_50, y1, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME + (5 * (i - half)));
} }
else }
{ balloon_formation_.emplace_back(30, init_params);
init_params.emplace_back(x1_50, y1, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME + (5 * (i - half))); }
}
}
balloon_formation_.emplace_back(30, init_params);
}
// #25 - Treinta enemigos BALLOON1. Del centro hacia adentro. Juntos. Simétricos // #25 - Treinta enemigos BALLOON1. Del centro hacia adentro. Juntos. Simétricos
{ {
std::vector<BalloonFormationParams> init_params; std::vector<BalloonFormationParams> init_params;
const int half = 30 / 2; const int half = 30 / 2;
for (int i = 0; i < 30; ++i) for (int i = 0; i < 30; ++i) {
{ if (i < half) {
if (i < half) init_params.emplace_back(x1_50 + 20, y1, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME - (5 * i));
{ } else {
init_params.emplace_back(x1_50 + 20, y1, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME - (5 * i)); init_params.emplace_back(x1_50 - 20, y1, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME - (5 * (i - half)));
} }
else }
{ balloon_formation_.emplace_back(30, init_params);
init_params.emplace_back(x1_50 - 20, y1, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME - (5 * (i - half))); }
}
}
balloon_formation_.emplace_back(30, init_params);
}
// Reservar espacio para el vector // Reservar espacio para el vector
balloon_formation_.resize(100); balloon_formation_.resize(100);
// Crea las mismas formaciones pero con hexágonos a partir de la posición 50 del vector // Crea las mismas formaciones pero con hexágonos a partir de la posición 50 del vector
for (int k = 0; k < 50; k++) for (int k = 0; k < 50; k++) {
{ std::vector<BalloonFormationParams> init_params;
std::vector<BalloonFormationParams> init_params; for (int i = 0; i < balloon_formation_.at(k).number_of_balloons; i++) {
for (int i = 0; i < balloon_formation_.at(k).number_of_balloons; i++) init_params.emplace_back(
{ balloon_formation_.at(k).init.at(i).x,
init_params.emplace_back( balloon_formation_.at(k).init.at(i).y,
balloon_formation_.at(k).init.at(i).x, balloon_formation_.at(k).init.at(i).vel_x,
balloon_formation_.at(k).init.at(i).y, BalloonType::FLOATER,
balloon_formation_.at(k).init.at(i).vel_x, balloon_formation_.at(k).init.at(i).size,
BalloonType::FLOATER, balloon_formation_.at(k).init.at(i).creation_counter);
balloon_formation_.at(k).init.at(i).size, }
balloon_formation_.at(k).init.at(i).creation_counter); balloon_formation_.at(k + 50) = BalloonFormationUnit(balloon_formation_.at(k).number_of_balloons, init_params);
} }
balloon_formation_.at(k + 50) = BalloonFormationUnit(balloon_formation_.at(k).number_of_balloons, init_params);
}
// TEST // TEST
std::vector<BalloonFormationParams> test_params = { std::vector<BalloonFormationParams> test_params = {
{10, y1, 0, BalloonType::FLOATER, BalloonSize::SIZE1, 200}, {10, y1, 0, BalloonType::FLOATER, BalloonSize::SIZE1, 200},
{50, y1, 0, BalloonType::FLOATER, BalloonSize::SIZE2, 200}, {50, y1, 0, BalloonType::FLOATER, BalloonSize::SIZE2, 200},
{90, y1, 0, BalloonType::FLOATER, BalloonSize::SIZE3, 200}, {90, y1, 0, BalloonType::FLOATER, BalloonSize::SIZE3, 200},
{140, y1, 0, BalloonType::FLOATER, BalloonSize::SIZE4, 200}}; {140, y1, 0, BalloonType::FLOATER, BalloonSize::SIZE4, 200}};
balloon_formation_.at(99) = BalloonFormationUnit(4, test_params); balloon_formation_.at(99) = BalloonFormationUnit(4, test_params);
} }
// Inicializa los conjuntos de formaciones // Inicializa los conjuntos de formaciones
void BalloonFormations::initBalloonFormationPools() void BalloonFormations::initBalloonFormationPools() {
{ // Reserva espacio para cada pool de formaciones
// Reserva espacio para cada pool de formaciones balloon_formation_pool_.resize(NUMBER_OF_SETS_PER_POOL);
balloon_formation_pool_.resize(NUMBER_OF_SETS_PER_POOL);
// Set #0 // Set #0
balloon_formation_pool_.at(0) = { balloon_formation_pool_.at(0) = {
&balloon_formation_.at(0), &balloon_formation_.at(1), &balloon_formation_.at(2), &balloon_formation_.at(0), &balloon_formation_.at(1), &balloon_formation_.at(2), &balloon_formation_.at(3), &balloon_formation_.at(4), &balloon_formation_.at(5), &balloon_formation_.at(6), &balloon_formation_.at(7), &balloon_formation_.at(8), &balloon_formation_.at(9)};
&balloon_formation_.at(3), &balloon_formation_.at(4), &balloon_formation_.at(5),
&balloon_formation_.at(6), &balloon_formation_.at(7), &balloon_formation_.at(8),
&balloon_formation_.at(9)};
// Set #1 // Set #1
balloon_formation_pool_.at(1) = { balloon_formation_pool_.at(1) = {
&balloon_formation_.at(10), &balloon_formation_.at(11), &balloon_formation_.at(12), &balloon_formation_.at(10), &balloon_formation_.at(11), &balloon_formation_.at(12), &balloon_formation_.at(13), &balloon_formation_.at(14), &balloon_formation_.at(15), &balloon_formation_.at(16), &balloon_formation_.at(17), &balloon_formation_.at(18), &balloon_formation_.at(19)};
&balloon_formation_.at(13), &balloon_formation_.at(14), &balloon_formation_.at(15),
&balloon_formation_.at(16), &balloon_formation_.at(17), &balloon_formation_.at(18),
&balloon_formation_.at(19)};
// Set #2 // Set #2
balloon_formation_pool_.at(2) = { balloon_formation_pool_.at(2) = {
&balloon_formation_.at(0), &balloon_formation_.at(1), &balloon_formation_.at(2), &balloon_formation_.at(0), &balloon_formation_.at(1), &balloon_formation_.at(2), &balloon_formation_.at(3), &balloon_formation_.at(4), &balloon_formation_.at(55), &balloon_formation_.at(56), &balloon_formation_.at(57), &balloon_formation_.at(58), &balloon_formation_.at(59)};
&balloon_formation_.at(3), &balloon_formation_.at(4), &balloon_formation_.at(55),
&balloon_formation_.at(56), &balloon_formation_.at(57), &balloon_formation_.at(58),
&balloon_formation_.at(59)};
// Set #3 // Set #3
balloon_formation_pool_.at(3) = { balloon_formation_pool_.at(3) = {
&balloon_formation_.at(50), &balloon_formation_.at(51), &balloon_formation_.at(52), &balloon_formation_.at(50), &balloon_formation_.at(51), &balloon_formation_.at(52), &balloon_formation_.at(53), &balloon_formation_.at(54), &balloon_formation_.at(5), &balloon_formation_.at(6), &balloon_formation_.at(7), &balloon_formation_.at(8), &balloon_formation_.at(9)};
&balloon_formation_.at(53), &balloon_formation_.at(54), &balloon_formation_.at(5),
&balloon_formation_.at(6), &balloon_formation_.at(7), &balloon_formation_.at(8),
&balloon_formation_.at(9)};
// Set #4 // Set #4
balloon_formation_pool_.at(4) = { balloon_formation_pool_.at(4) = {
&balloon_formation_.at(60), &balloon_formation_.at(61), &balloon_formation_.at(62), &balloon_formation_.at(60), &balloon_formation_.at(61), &balloon_formation_.at(62), &balloon_formation_.at(63), &balloon_formation_.at(64), &balloon_formation_.at(65), &balloon_formation_.at(66), &balloon_formation_.at(67), &balloon_formation_.at(68), &balloon_formation_.at(69)};
&balloon_formation_.at(63), &balloon_formation_.at(64), &balloon_formation_.at(65),
&balloon_formation_.at(66), &balloon_formation_.at(67), &balloon_formation_.at(68),
&balloon_formation_.at(69)};
// Set #5 // Set #5
balloon_formation_pool_.at(5) = { balloon_formation_pool_.at(5) = {
&balloon_formation_.at(10), &balloon_formation_.at(61), &balloon_formation_.at(12), &balloon_formation_.at(10), &balloon_formation_.at(61), &balloon_formation_.at(12), &balloon_formation_.at(63), &balloon_formation_.at(14), &balloon_formation_.at(65), &balloon_formation_.at(16), &balloon_formation_.at(67), &balloon_formation_.at(18), &balloon_formation_.at(69)};
&balloon_formation_.at(63), &balloon_formation_.at(14), &balloon_formation_.at(65),
&balloon_formation_.at(16), &balloon_formation_.at(67), &balloon_formation_.at(18),
&balloon_formation_.at(69)};
// Set #6 // Set #6
balloon_formation_pool_.at(6) = { balloon_formation_pool_.at(6) = {
&balloon_formation_.at(60), &balloon_formation_.at(11), &balloon_formation_.at(62), &balloon_formation_.at(60), &balloon_formation_.at(11), &balloon_formation_.at(62), &balloon_formation_.at(13), &balloon_formation_.at(64), &balloon_formation_.at(15), &balloon_formation_.at(66), &balloon_formation_.at(17), &balloon_formation_.at(68), &balloon_formation_.at(19)};
&balloon_formation_.at(13), &balloon_formation_.at(64), &balloon_formation_.at(15),
&balloon_formation_.at(66), &balloon_formation_.at(17), &balloon_formation_.at(68),
&balloon_formation_.at(19)};
// Set #7 // Set #7
balloon_formation_pool_.at(7) = { balloon_formation_pool_.at(7) = {
&balloon_formation_.at(20), &balloon_formation_.at(21), &balloon_formation_.at(22), &balloon_formation_.at(20), &balloon_formation_.at(21), &balloon_formation_.at(22), &balloon_formation_.at(23), &balloon_formation_.at(24), &balloon_formation_.at(65), &balloon_formation_.at(66), &balloon_formation_.at(67), &balloon_formation_.at(68), &balloon_formation_.at(69)};
&balloon_formation_.at(23), &balloon_formation_.at(24), &balloon_formation_.at(65),
&balloon_formation_.at(66), &balloon_formation_.at(67), &balloon_formation_.at(68),
&balloon_formation_.at(69)};
// Set #8 // Set #8
balloon_formation_pool_.at(8) = { balloon_formation_pool_.at(8) = {
&balloon_formation_.at(70), &balloon_formation_.at(71), &balloon_formation_.at(72), &balloon_formation_.at(70), &balloon_formation_.at(71), &balloon_formation_.at(72), &balloon_formation_.at(73), &balloon_formation_.at(74), &balloon_formation_.at(15), &balloon_formation_.at(16), &balloon_formation_.at(17), &balloon_formation_.at(18), &balloon_formation_.at(19)};
&balloon_formation_.at(73), &balloon_formation_.at(74), &balloon_formation_.at(15),
&balloon_formation_.at(16), &balloon_formation_.at(17), &balloon_formation_.at(18),
&balloon_formation_.at(19)};
// Set #9 // Set #9
balloon_formation_pool_.at(9) = { balloon_formation_pool_.at(9) = {
&balloon_formation_.at(20), &balloon_formation_.at(21), &balloon_formation_.at(22), &balloon_formation_.at(20), &balloon_formation_.at(21), &balloon_formation_.at(22), &balloon_formation_.at(23), &balloon_formation_.at(24), &balloon_formation_.at(70), &balloon_formation_.at(71), &balloon_formation_.at(72), &balloon_formation_.at(73), &balloon_formation_.at(74)};
&balloon_formation_.at(23), &balloon_formation_.at(24), &balloon_formation_.at(70),
&balloon_formation_.at(71), &balloon_formation_.at(72), &balloon_formation_.at(73),
&balloon_formation_.at(74)};
} }
+17 -21
View File
@@ -2,7 +2,7 @@
#include <vector> #include <vector>
#include "balloon.h" // Para BALLOON_VELX_NEGATIVE, BALLOON_VELX_POSITIVE #include "balloon.h" // Para BALLOON_VELX_NEGATIVE, BALLOON_VELX_POSITIVE
// --- Constantes de configuración --- // --- Constantes de configuración ---
constexpr int NUMBER_OF_BALLOON_FORMATIONS = 100; constexpr int NUMBER_OF_BALLOON_FORMATIONS = 100;
@@ -11,14 +11,13 @@ constexpr int NUMBER_OF_SETS_PER_POOL = 10;
constexpr int NUMBER_OF_STAGES = 10; constexpr int NUMBER_OF_STAGES = 10;
// --- Estructuras de datos --- // --- Estructuras de datos ---
struct BalloonFormationParams struct BalloonFormationParams {
{ int x = 0; // Posición en el eje X donde crear el globo
int x = 0; // Posición en el eje X donde crear el globo int y = 0; // Posición en el eje Y donde crear el globo
int y = 0; // Posición en el eje Y donde crear el globo float vel_x = 0.0f; // Velocidad inicial en el eje X
float vel_x = 0.0f; // Velocidad inicial en el eje X BalloonType type = BalloonType::BALLOON; // Tipo de globo
BalloonType type = BalloonType::BALLOON; // Tipo de globo BalloonSize size = BalloonSize::SIZE1; // Tamaño de globo
BalloonSize size = BalloonSize::SIZE1; // Tamaño de globo int creation_counter = 0; // Temporizador para la creación del globo
int creation_counter = 0; // Temporizador para la creación del globo
// Constructor por defecto // Constructor por defecto
BalloonFormationParams() = default; BalloonFormationParams() = default;
@@ -28,10 +27,9 @@ struct BalloonFormationParams
: x(x_val), y(y_val), vel_x(vel_x_val), type(type_val), size(size_val), creation_counter(creation_counter_val) {} : x(x_val), y(y_val), vel_x(vel_x_val), type(type_val), size(size_val), creation_counter(creation_counter_val) {}
}; };
struct BalloonFormationUnit struct BalloonFormationUnit {
{ int number_of_balloons; // Cantidad de globos que forman la formación
int number_of_balloons; // Cantidad de globos que forman la formación std::vector<BalloonFormationParams> init; // Vector con todas las inicializaciones de los globos de la formación
std::vector<BalloonFormationParams> init; // Vector con todas las inicializaciones de los globos de la formación
// Constructor con parámetros // Constructor con parámetros
BalloonFormationUnit(int num_balloons, const std::vector<BalloonFormationParams> &init_params) BalloonFormationUnit(int num_balloons, const std::vector<BalloonFormationParams> &init_params)
@@ -44,12 +42,10 @@ struct BalloonFormationUnit
using BalloonFormationPool = std::vector<const BalloonFormationUnit *>; using BalloonFormationPool = std::vector<const BalloonFormationUnit *>;
// --- Clase BalloonFormations --- // --- Clase BalloonFormations ---
class BalloonFormations class BalloonFormations {
{ public:
public:
// --- Constructor y destructor --- // --- Constructor y destructor ---
BalloonFormations() BalloonFormations() {
{
initBalloonFormations(); initBalloonFormations();
initBalloonFormationPools(); initBalloonFormationPools();
} }
@@ -60,10 +56,10 @@ public:
const BalloonFormationUnit &getSet(int pool, int set) { return *balloon_formation_pool_.at(pool).at(set); } const BalloonFormationUnit &getSet(int pool, int set) { return *balloon_formation_pool_.at(pool).at(set); }
const BalloonFormationUnit &getSet(int set) const { return balloon_formation_.at(set); } const BalloonFormationUnit &getSet(int set) const { return balloon_formation_.at(set); }
private: private:
// --- Datos --- // --- Datos ---
std::vector<BalloonFormationUnit> balloon_formation_; // Vector con todas las formaciones enemigas std::vector<BalloonFormationUnit> balloon_formation_; // Vector con todas las formaciones enemigas
std::vector<BalloonFormationPool> balloon_formation_pool_; // Conjuntos de formaciones enemigas std::vector<BalloonFormationPool> balloon_formation_pool_; // Conjuntos de formaciones enemigas
// --- Métodos internos de inicialización --- // --- Métodos internos de inicialización ---
void initBalloonFormations(); void initBalloonFormations();
+87 -148
View File
@@ -1,17 +1,18 @@
#include "balloon_manager.h" #include "balloon_manager.h"
#include <stdlib.h> // Para rand #include <stdlib.h> // Para rand
#include <algorithm> // Para remove_if
#include <numeric> // Para accumulate
#include "balloon.h" // Para Balloon, BALLOON_SCORE, BALLOON_VELX... #include <algorithm> // Para remove_if
#include "balloon_formations.h" // Para BalloonFormationParams, BalloonForma... #include <numeric> // Para accumulate
#include "explosions.h" // Para Explosions
#include "param.h" // Para Param, ParamGame, param #include "balloon.h" // Para Balloon, BALLOON_SCORE, BALLOON_VELX...
#include "resource.h" // Para Resource #include "balloon_formations.h" // Para BalloonFormationParams, BalloonForma...
#include "screen.h" // Para Screen #include "explosions.h" // Para Explosions
#include "stage.h" // Para addPower #include "param.h" // Para Param, ParamGame, param
#include "utils.h" // Para Zone, Color, flash_color #include "resource.h" // Para Resource
#include "screen.h" // Para Screen
#include "stage.h" // Para addPower
#include "utils.h" // Para Zone, Color, flash_color
// Constructor // Constructor
BalloonManager::BalloonManager() BalloonManager::BalloonManager()
@@ -19,8 +20,7 @@ BalloonManager::BalloonManager()
balloon_formations_(std::make_unique<BalloonFormations>()) { init(); } balloon_formations_(std::make_unique<BalloonFormations>()) { init(); }
// Inicializa // Inicializa
void BalloonManager::init() void BalloonManager::init() {
{
// Texturas - Globos // Texturas - Globos
balloon_textures_.emplace_back(Resource::get()->getTexture("balloon1.png")); balloon_textures_.emplace_back(Resource::get()->getTexture("balloon1.png"));
balloon_textures_.emplace_back(Resource::get()->getTexture("balloon2.png")); balloon_textures_.emplace_back(Resource::get()->getTexture("balloon2.png"));
@@ -55,10 +55,8 @@ void BalloonManager::init()
} }
// Actualiza // Actualiza
void BalloonManager::update() void BalloonManager::update() {
{ for (auto balloon : balloons_) {
for (auto balloon : balloons_)
{
balloon->update(); balloon->update();
} }
updateBalloonDeployCounter(); updateBalloonDeployCounter();
@@ -66,32 +64,25 @@ void BalloonManager::update()
} }
// Renderiza los objetos // Renderiza los objetos
void BalloonManager::render() void BalloonManager::render() {
{ for (auto &balloon : balloons_) {
for (auto &balloon : balloons_)
{
balloon->render(); balloon->render();
} }
explosions_->render(); explosions_->render();
} }
// Crea una formación de enemigos // Crea una formación de enemigos
void BalloonManager::deployBalloonFormation(int stage) void BalloonManager::deployBalloonFormation(int stage) {
{
// Solo despliega una formación enemiga si ha pasado cierto tiempo desde la última // Solo despliega una formación enemiga si ha pasado cierto tiempo desde la última
if (balloon_deploy_counter_ == 0) if (balloon_deploy_counter_ == 0) {
{
// En este punto se decide entre crear una powerball o una formación enemiga // En este punto se decide entre crear una powerball o una formación enemiga
if ((rand() % 100 < 15) && (canPowerBallBeCreated())) if ((rand() % 100 < 15) && (canPowerBallBeCreated())) {
{
// Crea una powerball // Crea una powerball
createPowerBall(); createPowerBall();
// Da un poco de margen para que se creen mas enemigos // Da un poco de margen para que se creen mas enemigos
balloon_deploy_counter_ = 10; balloon_deploy_counter_ = 10;
} } else {
else
{
// Decrementa el contador de despliegues enemigos de la PowerBall // Decrementa el contador de despliegues enemigos de la PowerBall
power_ball_counter_ = (power_ball_counter_ > 0) ? (power_ball_counter_ - 1) : 0; power_ball_counter_ = (power_ball_counter_ > 0) ? (power_ball_counter_ - 1) : 0;
@@ -99,8 +90,7 @@ void BalloonManager::deployBalloonFormation(int stage)
auto formation = rand() % 10; auto formation = rand() % 10;
// Evita repetir la ultima formación enemiga desplegada // Evita repetir la ultima formación enemiga desplegada
if (formation == last_balloon_deploy_) if (formation == last_balloon_deploy_) {
{
++formation %= 10; ++formation %= 10;
} }
@@ -108,8 +98,7 @@ void BalloonManager::deployBalloonFormation(int stage)
const auto set = balloon_formations_->getSet(stage, formation); const auto set = balloon_formations_->getSet(stage, formation);
const auto num_enemies = set.number_of_balloons; const auto num_enemies = set.number_of_balloons;
for (int i = 0; i < num_enemies; ++i) for (int i = 0; i < num_enemies; ++i) {
{
auto p = set.init[i]; auto p = set.init[i];
createBalloon( createBalloon(
p.x, p.x,
@@ -127,42 +116,34 @@ void BalloonManager::deployBalloonFormation(int stage)
} }
// Crea una formación de enemigos específica // Crea una formación de enemigos específica
void BalloonManager::deploySet(int set_number) void BalloonManager::deploySet(int set_number) {
{
const auto set = balloon_formations_->getSet(set_number); const auto set = balloon_formations_->getSet(set_number);
const auto num_enemies = set.number_of_balloons; const auto num_enemies = set.number_of_balloons;
for (int i = 0; i < num_enemies; ++i) for (int i = 0; i < num_enemies; ++i) {
{
auto p = set.init[i]; auto p = set.init[i];
createBalloon(p.x, p.y, p.type, p.size, p.vel_x, balloon_speed_, p.creation_counter); createBalloon(p.x, p.y, p.type, p.size, p.vel_x, balloon_speed_, p.creation_counter);
} }
} }
// Crea una formación de enemigos específica // Crea una formación de enemigos específica
void BalloonManager::deploySet(int set_number, int y) void BalloonManager::deploySet(int set_number, int y) {
{
const auto set = balloon_formations_->getSet(set_number); const auto set = balloon_formations_->getSet(set_number);
const auto num_enemies = set.number_of_balloons; const auto num_enemies = set.number_of_balloons;
for (int i = 0; i < num_enemies; ++i) for (int i = 0; i < num_enemies; ++i) {
{
auto p = set.init[i]; auto p = set.init[i];
createBalloon(p.x, y, p.type, p.size, p.vel_x, balloon_speed_, p.creation_counter); createBalloon(p.x, y, p.type, p.size, p.vel_x, balloon_speed_, p.creation_counter);
} }
} }
// Vacia del vector de globos los globos que ya no sirven // Vacia del vector de globos los globos que ya no sirven
void BalloonManager::freeBalloons() void BalloonManager::freeBalloons() {
{ auto it = std::remove_if(balloons_.begin(), balloons_.end(), [](const auto &balloon) { return !balloon->isEnabled(); });
auto it = std::remove_if(balloons_.begin(), balloons_.end(), [](const auto &balloon)
{ return !balloon->isEnabled(); });
balloons_.erase(it, balloons_.end()); balloons_.erase(it, balloons_.end());
} }
// Actualiza la variable enemyDeployCounter // Actualiza la variable enemyDeployCounter
void BalloonManager::updateBalloonDeployCounter() void BalloonManager::updateBalloonDeployCounter() {
{ if (balloon_deploy_counter_ > 0) {
if (balloon_deploy_counter_ > 0)
{
--balloon_deploy_counter_; --balloon_deploy_counter_;
} }
} }
@@ -171,17 +152,13 @@ void BalloonManager::updateBalloonDeployCounter()
bool BalloonManager::canPowerBallBeCreated() { return (!power_ball_enabled_) && (calculateScreenPower() > POWERBALL_SCREENPOWER_MINIMUM) && (power_ball_counter_ == 0); } bool BalloonManager::canPowerBallBeCreated() { return (!power_ball_enabled_) && (calculateScreenPower() > POWERBALL_SCREENPOWER_MINIMUM) && (power_ball_counter_ == 0); }
// Calcula el poder actual de los globos en pantalla // Calcula el poder actual de los globos en pantalla
int BalloonManager::calculateScreenPower() int BalloonManager::calculateScreenPower() {
{ return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon) { return sum + (balloon->isEnabled() ? balloon->getPower() : 0); });
return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon)
{ return sum + (balloon->isEnabled() ? balloon->getPower() : 0); });
} }
// Crea un globo nuevo en el vector de globos // Crea un globo nuevo en el vector de globos
std::shared_ptr<Balloon> BalloonManager::createBalloon(float x, int y, BalloonType type, BalloonSize size, float velx, float speed, int creation_timer) std::shared_ptr<Balloon> BalloonManager::createBalloon(float x, int y, BalloonType type, BalloonSize size, float velx, float speed, int creation_timer) {
{ if (can_deploy_balloons_) {
if (can_deploy_balloons_)
{
const int INDEX = static_cast<int>(size); const int INDEX = static_cast<int>(size);
balloons_.emplace_back(std::make_shared<Balloon>(x, y, type, size, velx, speed, creation_timer, play_area_, balloon_textures_.at(INDEX), balloon_animations_.at(INDEX))); balloons_.emplace_back(std::make_shared<Balloon>(x, y, type, size, velx, speed, creation_timer, play_area_, balloon_textures_.at(INDEX), balloon_animations_.at(INDEX)));
balloons_.back()->setSound(sound_enabled_); balloons_.back()->setSound(sound_enabled_);
@@ -194,10 +171,8 @@ std::shared_ptr<Balloon> BalloonManager::createBalloon(float x, int y, BalloonTy
} }
// Crea un globo a partir de otro globo // Crea un globo a partir de otro globo
void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction) void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction) {
{ if (can_deploy_balloons_) {
if (can_deploy_balloons_)
{
// Calcula parametros // Calcula parametros
const float VX = direction == "LEFT" ? BALLOON_VELX_NEGATIVE : BALLOON_VELX_POSITIVE; const float VX = direction == "LEFT" ? BALLOON_VELX_NEGATIVE : BALLOON_VELX_POSITIVE;
const auto SIZE = static_cast<BalloonSize>(static_cast<int>(balloon->getSize()) - 1); const auto SIZE = static_cast<BalloonSize>(static_cast<int>(balloon->getSize()) - 1);
@@ -214,22 +189,18 @@ void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon> &balloon,
b->setVelY(b->getType() == BalloonType::BALLOON ? -2.50f : BALLOON_VELX_NEGATIVE * 2.0f); b->setVelY(b->getType() == BalloonType::BALLOON ? -2.50f : BALLOON_VELX_NEGATIVE * 2.0f);
// Herencia de estados // Herencia de estados
if (balloon->isStopped()) if (balloon->isStopped()) {
{
b->stop(); b->stop();
} }
if (balloon->isUsingReversedColor()) if (balloon->isUsingReversedColor()) {
{
b->useReverseColor(); b->useReverseColor();
} }
} }
} }
// Crea una PowerBall // Crea una PowerBall
void BalloonManager::createPowerBall() void BalloonManager::createPowerBall() {
{ if (can_deploy_balloons_) {
if (can_deploy_balloons_)
{
constexpr int VALUES = 6; constexpr int VALUES = 6;
constexpr float POS_Y = -BALLOON_SIZE[4]; constexpr float POS_Y = -BALLOON_SIZE[4];
constexpr int CREATION_TIME = 0; constexpr int CREATION_TIME = 0;
@@ -251,33 +222,26 @@ void BalloonManager::createPowerBall()
} }
// Establece la velocidad de los globos // Establece la velocidad de los globos
void BalloonManager::setBalloonSpeed(float speed) void BalloonManager::setBalloonSpeed(float speed) {
{
balloon_speed_ = speed; balloon_speed_ = speed;
for (auto &balloon : balloons_) for (auto &balloon : balloons_) {
{
balloon->setSpeed(speed); balloon->setSpeed(speed);
} }
} }
// Explosiona un globo. Lo destruye y crea otros dos si es el caso // Explosiona un globo. Lo destruye y crea otros dos si es el caso
int BalloonManager::popBalloon(std::shared_ptr<Balloon> balloon) int BalloonManager::popBalloon(std::shared_ptr<Balloon> balloon) {
{
Stage::addPower(1); Stage::addPower(1);
int score = 0; int score = 0;
if (balloon->getType() == BalloonType::POWERBALL) if (balloon->getType() == BalloonType::POWERBALL) {
{
balloon->pop(true); balloon->pop(true);
score = destroyAllBalloons(); score = destroyAllBalloons();
power_ball_enabled_ = false; power_ball_enabled_ = false;
balloon_deploy_counter_ = 20; balloon_deploy_counter_ = 20;
} } else {
else
{
score = balloon->getScore(); score = balloon->getScore();
if (balloon->getSize() != BalloonSize::SIZE1) if (balloon->getSize() != BalloonSize::SIZE1) {
{
createChildBalloon(balloon, "LEFT"); createChildBalloon(balloon, "LEFT");
createChildBalloon(balloon, "RIGHT"); createChildBalloon(balloon, "RIGHT");
} }
@@ -291,28 +255,26 @@ int BalloonManager::popBalloon(std::shared_ptr<Balloon> balloon)
} }
// Explosiona un globo. Lo destruye = no crea otros globos // Explosiona un globo. Lo destruye = no crea otros globos
int BalloonManager::destroyBalloon(std::shared_ptr<Balloon> &balloon) int BalloonManager::destroyBalloon(std::shared_ptr<Balloon> &balloon) {
{
int score = 0; int score = 0;
// Calcula la puntuación y el poder que generaria el globo en caso de romperlo a él y a sus hijos // Calcula la puntuación y el poder que generaria el globo en caso de romperlo a él y a sus hijos
switch (balloon->getSize()) switch (balloon->getSize()) {
{ case BalloonSize::SIZE4:
case BalloonSize::SIZE4: score = BALLOON_SCORE[3] + (2 * BALLOON_SCORE[2]) + (4 * BALLOON_SCORE[1]) + (8 * BALLOON_SCORE[0]);
score = BALLOON_SCORE[3] + (2 * BALLOON_SCORE[2]) + (4 * BALLOON_SCORE[1]) + (8 * BALLOON_SCORE[0]); break;
break; case BalloonSize::SIZE3:
case BalloonSize::SIZE3: score = BALLOON_SCORE[2] + (2 * BALLOON_SCORE[1]) + (4 * BALLOON_SCORE[0]);
score = BALLOON_SCORE[2] + (2 * BALLOON_SCORE[1]) + (4 * BALLOON_SCORE[0]); break;
break; case BalloonSize::SIZE2:
case BalloonSize::SIZE2: score = BALLOON_SCORE[1] + (2 * BALLOON_SCORE[0]);
score = BALLOON_SCORE[1] + (2 * BALLOON_SCORE[0]); break;
break; case BalloonSize::SIZE1:
case BalloonSize::SIZE1: score = BALLOON_SCORE[0];
score = BALLOON_SCORE[0]; break;
break; default:
default: score = 0;
score = 0; break;
break;
} }
// Aumenta el poder de la fase // Aumenta el poder de la fase
@@ -326,11 +288,9 @@ int BalloonManager::destroyBalloon(std::shared_ptr<Balloon> &balloon)
} }
// Destruye todos los globos // Destruye todos los globos
int BalloonManager::destroyAllBalloons() int BalloonManager::destroyAllBalloons() {
{
int score = 0; int score = 0;
for (auto &balloon : balloons_) for (auto &balloon : balloons_) {
{
score += destroyBalloon(balloon); score += destroyBalloon(balloon);
} }
@@ -342,59 +302,46 @@ int BalloonManager::destroyAllBalloons()
} }
// Detiene todos los globos // Detiene todos los globos
void BalloonManager::stopAllBalloons() void BalloonManager::stopAllBalloons() {
{ for (auto &balloon : balloons_) {
for (auto &balloon : balloons_)
{
balloon->stop(); balloon->stop();
} }
} }
// Pone en marcha todos los globos // Pone en marcha todos los globos
void BalloonManager::startAllBalloons() void BalloonManager::startAllBalloons() {
{ for (auto &balloon : balloons_) {
for (auto &balloon : balloons_) if (!balloon->isBeingCreated()) {
{
if (!balloon->isBeingCreated())
{
balloon->start(); balloon->start();
} }
} }
} }
// Cambia el color de todos los globos // Cambia el color de todos los globos
void BalloonManager::reverseColorsToAllBalloons() void BalloonManager::reverseColorsToAllBalloons() {
{ for (auto &balloon : balloons_) {
for (auto &balloon : balloons_) if (balloon->isStopped()) {
{
if (balloon->isStopped())
{
balloon->useReverseColor(); balloon->useReverseColor();
} }
} }
} }
// Cambia el color de todos los globos // Cambia el color de todos los globos
void BalloonManager::normalColorsToAllBalloons() void BalloonManager::normalColorsToAllBalloons() {
{ for (auto &balloon : balloons_) {
for (auto &balloon : balloons_)
{
balloon->useNormalColor(); balloon->useNormalColor();
} }
} }
// Crea dos globos gordos // Crea dos globos gordos
void BalloonManager::createTwoBigBalloons() void BalloonManager::createTwoBigBalloons() {
{
deploySet(1); deploySet(1);
} }
// Crea una disposición de globos aleatoria // Crea una disposición de globos aleatoria
void BalloonManager::createRandomBalloons() void BalloonManager::createRandomBalloons() {
{
const int num_balloons = 2 + rand() % 4; const int num_balloons = 2 + rand() % 4;
for (int i = 0; i < num_balloons; ++i) for (int i = 0; i < num_balloons; ++i) {
{
const float x = param.game.game_area.rect.x + (rand() % static_cast<int>(param.game.game_area.rect.w)) - BALLOON_SIZE[3]; const float x = param.game.game_area.rect.x + (rand() % static_cast<int>(param.game.game_area.rect.w)) - BALLOON_SIZE[3];
const int y = param.game.game_area.rect.y + (rand() % 50); const int y = param.game.game_area.rect.y + (rand() % 50);
const BalloonSize size = static_cast<BalloonSize>(rand() % 4); const BalloonSize size = static_cast<BalloonSize>(rand() % 4);
@@ -405,37 +352,29 @@ void BalloonManager::createRandomBalloons()
} }
// Obtiene el nivel de ameza actual generado por los globos // Obtiene el nivel de ameza actual generado por los globos
int BalloonManager::getMenace() int BalloonManager::getMenace() {
{ return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon) { return sum + (balloon->isEnabled() ? balloon->getMenace() : 0); });
return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon)
{ return sum + (balloon->isEnabled() ? balloon->getMenace() : 0); });
} }
// Establece el sonido de los globos // Establece el sonido de los globos
void BalloonManager::setSounds(bool value) void BalloonManager::setSounds(bool value) {
{
sound_enabled_ = value; sound_enabled_ = value;
for (auto &balloon : balloons_) for (auto &balloon : balloons_) {
{
balloon->setSound(value); balloon->setSound(value);
} }
} }
// Activa o desactiva los sonidos de rebote los globos // Activa o desactiva los sonidos de rebote los globos
void BalloonManager::setBouncingSounds(bool value) void BalloonManager::setBouncingSounds(bool value) {
{
bouncing_sound_enabled_ = value; bouncing_sound_enabled_ = value;
for (auto &balloon : balloons_) for (auto &balloon : balloons_) {
{
balloon->setBouncingSound(value); balloon->setBouncingSound(value);
} }
} }
// Activa o desactiva los sonidos de los globos al explotar // Activa o desactiva los sonidos de los globos al explotar
void BalloonManager::setPoppingSounds(bool value) void BalloonManager::setPoppingSounds(bool value) {
{
poping_sound_enabled_ = value; poping_sound_enabled_ = value;
for (auto &balloon : balloons_) for (auto &balloon : balloons_) {
{
balloon->setPoppingSound(value); balloon->setPoppingSound(value);
} }
} }
+54 -54
View File
@@ -1,92 +1,92 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_FRect #include <SDL3/SDL.h> // Para SDL_FRect
#include <memory> // Para shared_ptr, unique_ptr
#include <string> // Para string
#include <vector> // Para vector
#include "balloon.h" // Para BALLOON_SPEED, Balloon #include <memory> // Para shared_ptr, unique_ptr
#include "balloon_formations.h" // Para BalloonFormations #include <string> // Para string
#include "explosions.h" // Para Explosions #include <vector> // Para vector
#include "param.h" // Para Param, ParamGame, param
#include "utils.h" // Para Zone #include "balloon.h" // Para BALLOON_SPEED, Balloon
#include "balloon_formations.h" // Para BalloonFormations
#include "explosions.h" // Para Explosions
#include "param.h" // Para Param, ParamGame, param
#include "utils.h" // Para Zone
class Texture; class Texture;
using Balloons = std::vector<std::shared_ptr<Balloon>>; using Balloons = std::vector<std::shared_ptr<Balloon>>;
// Clase BalloonManager // Clase BalloonManager
class BalloonManager class BalloonManager {
{ public:
public:
// Constructor y Destructor // Constructor y Destructor
BalloonManager(); BalloonManager();
~BalloonManager() = default; ~BalloonManager() = default;
// Actualización y Renderizado // Actualización y Renderizado
void update(); // Actualiza el estado de los globos void update(); // Actualiza el estado de los globos
void render(); // Renderiza los globos en pantalla void render(); // Renderiza los globos en pantalla
// Gestión de globos // Gestión de globos
void freeBalloons(); // Libera globos que ya no sirven void freeBalloons(); // Libera globos que ya no sirven
// Creación de formaciones enemigas // Creación de formaciones enemigas
void deployBalloonFormation(int stage); // Crea una formación de enemigos aleatoria void deployBalloonFormation(int stage); // Crea una formación de enemigos aleatoria
void deploySet(int set); // Crea una formación específica void deploySet(int set); // Crea una formación específica
void deploySet(int set, int y); // Crea una formación específica con coordenadas void deploySet(int set, int y); // Crea una formación específica con coordenadas
// Creación de globos // Creación de globos
std::shared_ptr<Balloon> createBalloon(float x, int y, BalloonType type, BalloonSize size, float velx, float speed, int creation_timer); // Crea un nuevo globo std::shared_ptr<Balloon> createBalloon(float x, int y, BalloonType type, BalloonSize size, float velx, float speed, int creation_timer); // Crea un nuevo globo
void createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction); // Crea un globo a partir de otro void createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction); // Crea un globo a partir de otro
void createPowerBall(); // Crea una PowerBall void createPowerBall(); // Crea una PowerBall
void createTwoBigBalloons(); // Crea dos globos grandes void createTwoBigBalloons(); // Crea dos globos grandes
void createRandomBalloons(); // Crea una disposición aleatoria de globos void createRandomBalloons(); // Crea una disposición aleatoria de globos
// Control de velocidad y despliegue // Control de velocidad y despliegue
void setBalloonSpeed(float speed); // Ajusta la velocidad de los globos void setBalloonSpeed(float speed); // Ajusta la velocidad de los globos
void setDefaultBalloonSpeed(float speed) { default_balloon_speed_ = speed; }; // Establece la velocidad base void setDefaultBalloonSpeed(float speed) { default_balloon_speed_ = speed; }; // Establece la velocidad base
void resetBalloonSpeed() { setBalloonSpeed(default_balloon_speed_); }; // Restablece la velocidad de los globos void resetBalloonSpeed() { setBalloonSpeed(default_balloon_speed_); }; // Restablece la velocidad de los globos
void updateBalloonDeployCounter(); // Actualiza el contador de despliegue void updateBalloonDeployCounter(); // Actualiza el contador de despliegue
bool canPowerBallBeCreated(); // Indica si se puede crear una PowerBall bool canPowerBallBeCreated(); // Indica si se puede crear una PowerBall
int calculateScreenPower(); // Calcula el poder de los globos en pantalla int calculateScreenPower(); // Calcula el poder de los globos en pantalla
// Manipulación de globos existentes // Manipulación de globos existentes
int popBalloon(std::shared_ptr<Balloon> balloon); // Explosiona un globo, creando otros si aplica int popBalloon(std::shared_ptr<Balloon> balloon); // Explosiona un globo, creando otros si aplica
int destroyBalloon(std::shared_ptr<Balloon> &balloon); // Explosiona un globo sin crear otros int destroyBalloon(std::shared_ptr<Balloon> &balloon); // Explosiona un globo sin crear otros
int destroyAllBalloons(); // Destruye todos los globos int destroyAllBalloons(); // Destruye todos los globos
void stopAllBalloons(); // Detiene el movimiento de los globos void stopAllBalloons(); // Detiene el movimiento de los globos
void startAllBalloons(); // Reactiva el movimiento de los globos void startAllBalloons(); // Reactiva el movimiento de los globos
// Cambios de apariencia // Cambios de apariencia
void reverseColorsToAllBalloons(); // Invierte los colores de los globos void reverseColorsToAllBalloons(); // Invierte los colores de los globos
void normalColorsToAllBalloons(); // Restaura los colores originales void normalColorsToAllBalloons(); // Restaura los colores originales
// Configuración de sonido // Configuración de sonido
void setSounds(bool value); // Activa o desactiva los sonidos de los globos void setSounds(bool value); // Activa o desactiva los sonidos de los globos
void setBouncingSounds(bool value); // Activa o desactiva los sonidos de rebote los globos void setBouncingSounds(bool value); // Activa o desactiva los sonidos de rebote los globos
void setPoppingSounds(bool value); // Activa o desactiva los sonidos de los globos al explotar void setPoppingSounds(bool value); // Activa o desactiva los sonidos de los globos al explotar
// Configuración de juego // Configuración de juego
void setPlayArea(SDL_FRect play_area) { play_area_ = play_area; }; // Define el área de juego void setPlayArea(SDL_FRect play_area) { play_area_ = play_area; }; // Define el área de juego
void setCreationTimeEnabled(bool value) { creation_time_enabled_ = value; }; // Activa o desactiva el tiempo de creación de globos void setCreationTimeEnabled(bool value) { creation_time_enabled_ = value; }; // Activa o desactiva el tiempo de creación de globos
void enableBalloonDeployment(bool value) { can_deploy_balloons_ = value; }; // Activa o desactiva la generación de globos void enableBalloonDeployment(bool value) { can_deploy_balloons_ = value; }; // Activa o desactiva la generación de globos
// Obtención de información // Obtención de información
int getMenace(); // Obtiene el nivel de amenaza generado por los globos int getMenace(); // Obtiene el nivel de amenaza generado por los globos
float getBalloonSpeed() const { return balloon_speed_; } float getBalloonSpeed() const { return balloon_speed_; }
Balloons &getBalloons() { return balloons_; } Balloons &getBalloons() { return balloons_; }
int getNumBalloons() const { return balloons_.size(); } int getNumBalloons() const { return balloons_.size(); }
private: private:
Balloons balloons_; // Vector con los globos activos Balloons balloons_; // Vector con los globos activos
std::unique_ptr<Explosions> explosions_; // Objeto para gestionar explosiones std::unique_ptr<Explosions> explosions_; // Objeto para gestionar explosiones
std::unique_ptr<BalloonFormations> balloon_formations_; // Objeto para manejar formaciones enemigas std::unique_ptr<BalloonFormations> balloon_formations_; // Objeto para manejar formaciones enemigas
std::vector<std::shared_ptr<Texture>> balloon_textures_; // Texturas de los globos std::vector<std::shared_ptr<Texture>> balloon_textures_; // Texturas de los globos
std::vector<std::shared_ptr<Texture>> explosions_textures_; // Texturas de explosiones std::vector<std::shared_ptr<Texture>> explosions_textures_; // Texturas de explosiones
std::vector<std::vector<std::string>> balloon_animations_; // Animaciones de los globos std::vector<std::vector<std::string>> balloon_animations_; // Animaciones de los globos
std::vector<std::vector<std::string>> explosions_animations_; // Animaciones de las explosiones std::vector<std::vector<std::string>> explosions_animations_; // Animaciones de las explosiones
// Variables de control de globos // Variables de control de globos
float balloon_speed_ = BALLOON_SPEED[0]; float balloon_speed_ = BALLOON_SPEED[0];
@@ -98,9 +98,9 @@ private:
SDL_FRect play_area_ = param.game.play_area.rect; SDL_FRect play_area_ = param.game.play_area.rect;
bool creation_time_enabled_ = true; bool creation_time_enabled_ = true;
bool can_deploy_balloons_ = true; bool can_deploy_balloons_ = true;
bool bouncing_sound_enabled_ = false; // Si debe sonar el globo al rebotar bool bouncing_sound_enabled_ = false; // Si debe sonar el globo al rebotar
bool poping_sound_enabled_ = true; // Si debe sonar el globo al explotar bool poping_sound_enabled_ = true; // Si debe sonar el globo al explotar
bool sound_enabled_ = true; // Indica si los globos deben hacer algun sonido bool sound_enabled_ = true; // Indica si los globos deben hacer algun sonido
// Metodos privados // Metodos privados
void init(); void init();
+31 -44
View File
@@ -1,10 +1,10 @@
#include "bullet.h" #include "bullet.h"
#include <memory> // Para allocator, unique_ptr, make_unique #include <memory> // Para allocator, unique_ptr, make_unique
#include <string> // Para char_traits, basic_string, operator+, string #include <string> // Para char_traits, basic_string, operator+, string
#include "param.h" // Para Param, ParamGame, param #include "param.h" // Para Param, ParamGame, param
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
// Constructor // Constructor
Bullet::Bullet(float x, float y, BulletType bullet_type, bool powered, int owner) Bullet::Bullet(float x, float y, BulletType bullet_type, bool powered, int owner)
@@ -12,29 +12,27 @@ Bullet::Bullet(float x, float y, BulletType bullet_type, bool powered, int owner
pos_x_(x), pos_x_(x),
pos_y_(y), pos_y_(y),
bullet_type_(bullet_type), bullet_type_(bullet_type),
owner_(owner) owner_(owner) {
{ vel_x_ = (bullet_type_ == BulletType::LEFT) ? VEL_X_LEFT_
vel_x_ = (bullet_type_ == BulletType::LEFT) ? VEL_X_LEFT_ : (bullet_type_ == BulletType::RIGHT) ? VEL_X_RIGHT_
: (bullet_type_ == BulletType::RIGHT) ? VEL_X_RIGHT_ : 0;
: 0;
std::string powered_type = powered ? "powered_" : "normal_"; std::string powered_type = powered ? "powered_" : "normal_";
switch (bullet_type) switch (bullet_type) {
{ case BulletType::UP:
case BulletType::UP: sprite_->setCurrentAnimation(powered_type + "up");
sprite_->setCurrentAnimation(powered_type + "up"); break;
break;
case BulletType::LEFT: case BulletType::LEFT:
sprite_->setCurrentAnimation(powered_type + "left"); sprite_->setCurrentAnimation(powered_type + "left");
break; break;
case BulletType::RIGHT: case BulletType::RIGHT:
sprite_->setCurrentAnimation(powered_type + "right"); sprite_->setCurrentAnimation(powered_type + "right");
break; break;
default: default:
break; break;
} }
collider_.r = WIDTH / 2; collider_.r = WIDTH / 2;
@@ -42,32 +40,27 @@ Bullet::Bullet(float x, float y, BulletType bullet_type, bool powered, int owner
} }
// Implementación de render (llama al render del sprite_) // Implementación de render (llama al render del sprite_)
void Bullet::render() void Bullet::render() {
{
if (bullet_type_ != BulletType::NONE) if (bullet_type_ != BulletType::NONE)
sprite_->render(); sprite_->render();
} }
// Actualiza el estado del objeto // Actualiza el estado del objeto
BulletMoveStatus Bullet::update() BulletMoveStatus Bullet::update() {
{
sprite_->update(); sprite_->update();
return move(); return move();
} }
// Implementación del movimiento usando BulletMoveStatus // Implementación del movimiento usando BulletMoveStatus
BulletMoveStatus Bullet::move() BulletMoveStatus Bullet::move() {
{
pos_x_ += vel_x_; pos_x_ += vel_x_;
if (pos_x_ < param.game.play_area.rect.x - WIDTH || pos_x_ > param.game.play_area.rect.w) if (pos_x_ < param.game.play_area.rect.x - WIDTH || pos_x_ > param.game.play_area.rect.w) {
{
disable(); disable();
return BulletMoveStatus::OUT; return BulletMoveStatus::OUT;
} }
pos_y_ += VEL_Y_; pos_y_ += VEL_Y_;
if (pos_y_ < param.game.play_area.rect.y - HEIGHT) if (pos_y_ < param.game.play_area.rect.y - HEIGHT) {
{
disable(); disable();
return BulletMoveStatus::OUT; return BulletMoveStatus::OUT;
} }
@@ -78,34 +71,28 @@ BulletMoveStatus Bullet::move()
return BulletMoveStatus::OK; return BulletMoveStatus::OK;
} }
bool Bullet::isEnabled() const bool Bullet::isEnabled() const {
{
return bullet_type_ != BulletType::NONE; return bullet_type_ != BulletType::NONE;
} }
void Bullet::disable() void Bullet::disable() {
{
bullet_type_ = BulletType::NONE; bullet_type_ = BulletType::NONE;
} }
int Bullet::getOwner() const int Bullet::getOwner() const {
{
return owner_; return owner_;
} }
Circle &Bullet::getCollider() Circle &Bullet::getCollider() {
{
return collider_; return collider_;
} }
void Bullet::shiftColliders() void Bullet::shiftColliders() {
{
collider_.x = pos_x_ + collider_.r; collider_.x = pos_x_ + collider_.r;
collider_.y = pos_y_ + collider_.r; collider_.y = pos_y_ + collider_.r;
} }
void Bullet::shiftSprite() void Bullet::shiftSprite() {
{
sprite_->setX(pos_x_); sprite_->setX(pos_x_);
sprite_->setY(pos_y_); sprite_->setY(pos_y_);
} }
+47 -49
View File
@@ -1,70 +1,68 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para Uint8 #include <SDL3/SDL.h> // Para Uint8
#include <memory> // Para unique_ptr
#include "animated_sprite.h" // Para AnimatedSprite #include <memory> // Para unique_ptr
#include "utils.h" // Para Circle
#include "animated_sprite.h" // Para AnimatedSprite
#include "utils.h" // Para Circle
// Tipos de balas // Tipos de balas
enum class BulletType : Uint8 enum class BulletType : Uint8 {
{ UP,
UP, LEFT,
LEFT, RIGHT,
RIGHT, NONE
NONE
}; };
// Resultado del movimiento de la bala // Resultado del movimiento de la bala
enum class BulletMoveStatus : Uint8 enum class BulletMoveStatus : Uint8 {
{ OK = 0,
OK = 0, OUT = 1
OUT = 1
}; };
// Clase Bullet // Clase Bullet
class Bullet class Bullet {
{ public:
public: // Constantes
// Constantes static constexpr float WIDTH = 12.0f;
static constexpr float WIDTH = 12.0f; static constexpr float HEIGHT = 12.0f;
static constexpr float HEIGHT = 12.0f;
// Constructor y Destructor // Constructor y Destructor
Bullet(float x, float y, BulletType bullet_type, bool powered, int owner); Bullet(float x, float y, BulletType bullet_type, bool powered, int owner);
~Bullet() = default; ~Bullet() = default;
// Métodos principales // Métodos principales
void render(); // Dibuja la bala en pantalla void render(); // Dibuja la bala en pantalla
BulletMoveStatus update(); // Actualiza el estado del objeto BulletMoveStatus update(); // Actualiza el estado del objeto
// Estado de la bala // Estado de la bala
bool isEnabled() const; // Comprueba si está activa bool isEnabled() const; // Comprueba si está activa
void disable(); // Desactiva la bala void disable(); // Desactiva la bala
// Getters // Getters
int getOwner() const; // Devuelve el identificador del dueño int getOwner() const; // Devuelve el identificador del dueño
Circle &getCollider(); // Devuelve el círculo de colisión Circle &getCollider(); // Devuelve el círculo de colisión
private: private:
// Constantes // Constantes
static constexpr float VEL_Y_ = -3.0f; static constexpr float VEL_Y_ = -3.0f;
static constexpr float VEL_X_LEFT_ = -2.0f; static constexpr float VEL_X_LEFT_ = -2.0f;
static constexpr float VEL_X_RIGHT_ = 2.0f; static constexpr float VEL_X_RIGHT_ = 2.0f;
// Propiedades // Propiedades
std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos
float pos_x_; // Posición en el eje X float pos_x_; // Posición en el eje X
float pos_y_; // Posición en el eje Y float pos_y_; // Posición en el eje Y
float vel_x_; // Velocidad en el eje X float vel_x_; // Velocidad en el eje X
BulletType bullet_type_; // Tipo de bala BulletType bullet_type_; // Tipo de bala
int owner_; // Identificador del dueño int owner_; // Identificador del dueño
Circle collider_; // Círculo de colisión Circle collider_; // Círculo de colisión
// Métodos internos // Métodos internos
void shiftColliders(); // Ajusta el círculo de colisión void shiftColliders(); // Ajusta el círculo de colisión
void shiftSprite(); // Ajusta el sprite void shiftSprite(); // Ajusta el sprite
BulletMoveStatus move(); // Mueve la bala y devuelve su estado BulletMoveStatus move(); // Mueve la bala y devuelve su estado
}; };
+39 -65
View File
@@ -1,34 +1,30 @@
#include "define_buttons.h" #include "define_buttons.h"
#include "input.h" // Para Input, InputAction #include "input.h" // Para Input, InputAction
#include "lang.h" // Para getText #include "lang.h" // Para getText
#include "options.h" // Para OptionsController, Options, options #include "options.h" // Para OptionsController, Options, options
#include "param.h" // Para Param, param, ParamGame, ParamTitle #include "param.h" // Para Param, param, ParamGame, ParamTitle
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
#include "text.h" // Para Text #include "text.h" // Para Text
// Constructor // Constructor
DefineButtons::DefineButtons() DefineButtons::DefineButtons()
: input_(Input::get()), : input_(Input::get()),
text_(Resource::get()->getText("8bithud")) text_(Resource::get()->getText("8bithud")) {
{
// Inicializa variables // Inicializa variables
x_ = param.game.width / 2; x_ = param.game.width / 2;
y_ = param.title.press_start_position; y_ = param.title.press_start_position;
clearButtons(); clearButtons();
for (int i = 0; i < input_->getNumControllers(); ++i) for (int i = 0; i < input_->getNumControllers(); ++i) {
{
controller_names_.emplace_back(input_->getControllerName(i)); controller_names_.emplace_back(input_->getControllerName(i));
} }
} }
// Dibuja el objeto en pantalla // Dibuja el objeto en pantalla
void DefineButtons::render() void DefineButtons::render() {
{ if (enabled_) {
if (enabled_)
{
text_->writeCentered(x_, y_ - 10, Lang::getText("[DEFINE_BUTTONS] PLAYER") + std::to_string(Options::controllers.at(index_controller_).player_id)); text_->writeCentered(x_, y_ - 10, Lang::getText("[DEFINE_BUTTONS] PLAYER") + std::to_string(Options::controllers.at(index_controller_).player_id));
text_->writeCentered(x_, y_, controller_names_.at(index_controller_)); text_->writeCentered(x_, y_, controller_names_.at(index_controller_));
text_->writeCentered(x_, y_ + 10, buttons_.at(index_button_).label); text_->writeCentered(x_, y_ + 10, buttons_.at(index_button_).label);
@@ -36,27 +32,22 @@ void DefineButtons::render()
} }
// Comprueba el botón que se ha pulsado // Comprueba el botón que se ha pulsado
void DefineButtons::doControllerButtonDown(const SDL_GamepadButtonEvent &event) void DefineButtons::doControllerButtonDown(const SDL_GamepadButtonEvent &event) {
{
// Solo pilla botones del mando que toca // Solo pilla botones del mando que toca
if (input_->getJoyIndex(event.which) != static_cast<int>(index_controller_)) if (input_->getJoyIndex(event.which) != static_cast<int>(index_controller_)) {
{
return; return;
} }
const auto button = static_cast<SDL_GamepadButton>(event.button); const auto button = static_cast<SDL_GamepadButton>(event.button);
if (checkButtonNotInUse(button)) if (checkButtonNotInUse(button)) {
{
buttons_.at(index_button_).button = button; buttons_.at(index_button_).button = button;
incIndexButton(); incIndexButton();
} }
} }
// Asigna los botones definidos al input_ // Asigna los botones definidos al input_
void DefineButtons::bindButtons() void DefineButtons::bindButtons() {
{ for (const auto &button : buttons_) {
for (const auto &button : buttons_)
{
input_->bindGameControllerButton(index_controller_, button.input, button.button); input_->bindGameControllerButton(index_controller_, button.input, button.button);
} }
@@ -66,29 +57,24 @@ void DefineButtons::bindButtons()
} }
// Comprueba los eventos // Comprueba los eventos
void DefineButtons::checkEvents(const SDL_Event &event) void DefineButtons::checkEvents(const SDL_Event &event) {
{ if (enabled_) {
if (enabled_) switch (event.type) {
{ case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
switch (event.type) doControllerButtonDown(event.gbutton);
{ break;
case SDL_EVENT_GAMEPAD_BUTTON_DOWN: case SDL_EVENT_GAMEPAD_BUTTON_UP:
doControllerButtonDown(event.gbutton); checkEnd();
break; break;
case SDL_EVENT_GAMEPAD_BUTTON_UP: default:
checkEnd(); break;
break;
default:
break;
} }
} }
} }
// Habilita el objeto // Habilita el objeto
bool DefineButtons::enable(int index) bool DefineButtons::enable(int index) {
{ if (index < input_->getNumControllers()) {
if (index < input_->getNumControllers())
{
enabled_ = true; enabled_ = true;
finished_ = false; finished_ = false;
index_controller_ = index; index_controller_ = index;
@@ -104,37 +90,28 @@ bool DefineButtons::enable(int index)
bool DefineButtons::isEnabled() const { return enabled_; } bool DefineButtons::isEnabled() const { return enabled_; }
// Incrementa el indice de los botones // Incrementa el indice de los botones
void DefineButtons::incIndexButton() void DefineButtons::incIndexButton() {
{ if (index_button_ < buttons_.size() - 1) {
if (index_button_ < buttons_.size() - 1)
{
++index_button_; ++index_button_;
} } else {
else
{
finished_ = true; finished_ = true;
} }
} }
// Guarda los cambios en las opciones // Guarda los cambios en las opciones
void DefineButtons::saveBindingsToOptions() void DefineButtons::saveBindingsToOptions() {
{
// Modifica las opciones para colocar los valores asignados // Modifica las opciones para colocar los valores asignados
auto &controller = Options::controllers.at(index_controller_); auto &controller = Options::controllers.at(index_controller_);
controller.name = input_->getControllerName(index_controller_); controller.name = input_->getControllerName(index_controller_);
for (size_t j = 0; j < controller.inputs.size(); ++j) for (size_t j = 0; j < controller.inputs.size(); ++j) {
{
controller.buttons.at(j) = input_->getControllerBinding(index_controller_, controller.inputs.at(j)); controller.buttons.at(j) = input_->getControllerBinding(index_controller_, controller.inputs.at(j));
} }
} }
// Comprueba que un botón no esté ya asignado // Comprueba que un botón no esté ya asignado
bool DefineButtons::checkButtonNotInUse(SDL_GamepadButton button) bool DefineButtons::checkButtonNotInUse(SDL_GamepadButton button) {
{ for (const auto &b : buttons_) {
for (const auto &b : buttons_) if (b.button == button) {
{
if (b.button == button)
{
return false; return false;
} }
} }
@@ -142,8 +119,7 @@ bool DefineButtons::checkButtonNotInUse(SDL_GamepadButton button)
} }
// Limpia la asignación de botones // Limpia la asignación de botones
void DefineButtons::clearButtons() void DefineButtons::clearButtons() {
{
buttons_.clear(); buttons_.clear();
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_LEFT"), InputAction::FIRE_LEFT, SDL_GAMEPAD_BUTTON_INVALID); buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_LEFT"), InputAction::FIRE_LEFT, SDL_GAMEPAD_BUTTON_INVALID);
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_UP"), InputAction::FIRE_CENTER, SDL_GAMEPAD_BUTTON_INVALID); buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_UP"), InputAction::FIRE_CENTER, SDL_GAMEPAD_BUTTON_INVALID);
@@ -153,11 +129,9 @@ void DefineButtons::clearButtons()
} }
// Comprueba si ha finalizado // Comprueba si ha finalizado
void DefineButtons::checkEnd() void DefineButtons::checkEnd() {
{
// Comprueba si ha finalizado // Comprueba si ha finalizado
if (finished_) if (finished_) {
{
// Asigna los botones definidos al input_ // Asigna los botones definidos al input_
bindButtons(); bindButtons();
+32 -33
View File
@@ -1,10 +1,11 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_GamepadButton, SDL_Event, SDL_GamepadButtonEvent #include <SDL3/SDL.h> // Para SDL_GamepadButton, SDL_Event, SDL_GamepadButtonEvent
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <memory> // Para shared_ptr
#include <string> // Para basic_string, string #include <memory> // Para shared_ptr
#include <vector> // Para vector #include <string> // Para basic_string, string
#include <vector> // Para vector
// Declaraciones adelantadas // Declaraciones adelantadas
class Input; class Input;
@@ -12,48 +13,46 @@ class Text;
enum class InputAction : int; enum class InputAction : int;
// Estructura para definir botones // Estructura para definir botones
struct DefineButtonsButton struct DefineButtonsButton {
{ std::string label; // Texto en pantalla
std::string label; // Texto en pantalla InputAction input; // Acción asociada
InputAction input; // Acción asociada SDL_GamepadButton button; // Botón del mando
SDL_GamepadButton button; // Botón del mando
DefineButtonsButton(const std::string &lbl, InputAction inp, SDL_GamepadButton btn) DefineButtonsButton(const std::string &lbl, InputAction inp, SDL_GamepadButton btn)
: label(lbl), input(inp), button(btn) {} : label(lbl), input(inp), button(btn) {}
}; };
// Clase DefineButtons // Clase DefineButtons
class DefineButtons class DefineButtons {
{ public:
public:
DefineButtons(); DefineButtons();
~DefineButtons() = default; ~DefineButtons() = default;
void render(); // Dibuja el objeto en pantalla void render(); // Dibuja el objeto en pantalla
void checkEvents(const SDL_Event &event); // Procesa los eventos void checkEvents(const SDL_Event &event); // Procesa los eventos
bool enable(int index_controller); // Habilita la redefinición de botones bool enable(int index_controller); // Habilita la redefinición de botones
bool isEnabled() const; // Comprueba si está habilitado bool isEnabled() const; // Comprueba si está habilitado
private: private:
// Objetos // Objetos
Input *input_ = nullptr; // Gestión de entrada Input *input_ = nullptr; // Gestión de entrada
std::shared_ptr<Text> text_; // Renderizado de texto std::shared_ptr<Text> text_; // Renderizado de texto
// Variables // Variables
bool enabled_ = false; // Indica si está activo bool enabled_ = false; // Indica si está activo
int x_ = 0, y_ = 0; // Coordenadas de texto int x_ = 0, y_ = 0; // Coordenadas de texto
std::vector<DefineButtonsButton> buttons_; // Definiciones de botones std::vector<DefineButtonsButton> buttons_; // Definiciones de botones
size_t index_controller_ = 0; // Índice del controlador asignado size_t index_controller_ = 0; // Índice del controlador asignado
size_t index_button_ = 0; // Índice del botón en proceso size_t index_button_ = 0; // Índice del botón en proceso
std::vector<std::string> controller_names_; // Nombres de los mandos std::vector<std::string> controller_names_; // Nombres de los mandos
bool finished_ = false; bool finished_ = false;
// Métodos internos // Métodos internos
void incIndexButton(); // Incrementa el índice de botones void incIndexButton(); // Incrementa el índice de botones
void doControllerButtonDown(const SDL_GamepadButtonEvent &event); // Procesa pulsaciones void doControllerButtonDown(const SDL_GamepadButtonEvent &event); // Procesa pulsaciones
void bindButtons(); // Asigna botones al sistema de entrada void bindButtons(); // Asigna botones al sistema de entrada
void saveBindingsToOptions(); // Guarda configuraciones void saveBindingsToOptions(); // Guarda configuraciones
bool checkButtonNotInUse(SDL_GamepadButton button); // Verifica uso de botones bool checkButtonNotInUse(SDL_GamepadButton button); // Verifica uso de botones
void clearButtons(); // Limpia asignaciones actuales void clearButtons(); // Limpia asignaciones actuales
void checkEnd(); // Comprueba si ha finalizado void checkEnd(); // Comprueba si ha finalizado
}; };
+500 -546
View File
File diff suppressed because it is too large. Load diff
+39 -41
View File
@@ -1,55 +1,53 @@
#pragma once #pragma once
#include <string> // Para manejar cadenas de texto #include <string> // Para manejar cadenas de texto
namespace Lang namespace Lang {
{ enum class Code : int;
enum class Code : int;
} }
class Director class Director {
{ public:
public: // --- Constructor y destructor ---
// --- Constructor y destructor --- Director(int argc, const char *argv[]);
Director(int argc, const char *argv[]); ~Director();
~Director();
// --- Bucle principal --- // --- Bucle principal ---
int run(); int run();
private: private:
// --- Variables internas --- // --- Variables internas ---
std::string executable_path_; // Ruta del ejecutable std::string executable_path_; // Ruta del ejecutable
std::string system_folder_; // Carpeta del sistema para almacenar datos std::string system_folder_; // Carpeta del sistema para almacenar datos
// --- Inicialización y cierre del sistema --- // --- Inicialización y cierre del sistema ---
void init(); // Inicializa la aplicación void init(); // Inicializa la aplicación
void close(); // Cierra y libera recursos void close(); // Cierra y libera recursos
// --- Configuración inicial --- // --- Configuración inicial ---
void loadParams(); // Carga los parámetros del programa void loadParams(); // Carga los parámetros del programa
void loadScoreFile(); // Carga el fichero de puntuaciones void loadScoreFile(); // Carga el fichero de puntuaciones
void createSystemFolder(const std::string &folder); // Crea la carpeta del sistema void createSystemFolder(const std::string &folder); // Crea la carpeta del sistema
// --- Gestión de entrada y archivos --- // --- Gestión de entrada y archivos ---
void bindInputs(); // Asigna botones y teclas al sistema de entrada void bindInputs(); // Asigna botones y teclas al sistema de entrada
void setFileList(); // Crea el índice de archivos disponibles void setFileList(); // Crea el índice de archivos disponibles
void checkProgramArguments(int argc, const char *argv[]); // Verifica los parámetros del programa void checkProgramArguments(int argc, const char *argv[]); // Verifica los parámetros del programa
// --- Secciones del programa --- // --- Secciones del programa ---
void runLogo(); // Ejecuta la pantalla con el logo void runLogo(); // Ejecuta la pantalla con el logo
void runIntro(); // Ejecuta la introducción del juego void runIntro(); // Ejecuta la introducción del juego
void runTitle(); // Ejecuta la pantalla de título void runTitle(); // Ejecuta la pantalla de título
void runGame(); // Inicia el juego void runGame(); // Inicia el juego
void runInstructions(); // Muestra las instrucciones void runInstructions(); // Muestra las instrucciones
void runCredits(); // Muestra los créditos del juego void runCredits(); // Muestra los créditos del juego
void runHiScoreTable(); // Muestra la tabla de puntuaciones void runHiScoreTable(); // Muestra la tabla de puntuaciones
void runDemoGame(); // Ejecuta el modo demo void runDemoGame(); // Ejecuta el modo demo
void reset(); // Reinicia objetos y vuelve a la sección inicial void reset(); // Reinicia objetos y vuelve a la sección inicial
// --- Gestión de archivos de idioma --- // --- Gestión de archivos de idioma ---
std::string getLangFile(Lang::Code code); // Obtiene un fichero de idioma según el código std::string getLangFile(Lang::Code code); // Obtiene un fichero de idioma según el código
// --- Apagado del sistema --- // --- Apagado del sistema ---
void shutdownSystem(bool should_shutdown); // Apaga el sistema void shutdownSystem(bool should_shutdown); // Apaga el sistema
}; };
+39 -73
View File
@@ -1,10 +1,11 @@
#include "enter_name.h" #include "enter_name.h"
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <stdlib.h> // Para rand #include <stdlib.h> // Para rand
#include <string_view> // Para basic_string_view, string_view
#include "utils.h" // Para trim #include <string_view> // Para basic_string_view, string_view
#include "utils.h" // Para trim
// Constructor // Constructor
EnterName::EnterName() EnterName::EnterName()
@@ -12,18 +13,15 @@ EnterName::EnterName()
character_index_{0} {} character_index_{0} {}
// Inicializa el objeto // Inicializa el objeto
void EnterName::init(const std::string &name) void EnterName::init(const std::string &name) {
{
// No se pasa ningún nombre // No se pasa ningún nombre
if (name.empty()) if (name.empty()) {
{
name_ = "A"; name_ = "A";
position_ = 0; position_ = 0;
position_overflow_ = false; position_overflow_ = false;
} }
// Se pasa un nombre // Se pasa un nombre
else else {
{
name_ = name; name_ = name;
position_ = name_.length(); position_ = name_.length();
position_overflow_ = position_ >= NAME_SIZE ? true : false; position_overflow_ = position_ >= NAME_SIZE ? true : false;
@@ -34,28 +32,22 @@ void EnterName::init(const std::string &name)
} }
// Incrementa la posición // Incrementa la posición
void EnterName::incPosition() void EnterName::incPosition() {
{ if (position_overflow_) {
if (position_overflow_)
{
// Si ya estamos en overflow, no incrementamos más. // Si ya estamos en overflow, no incrementamos más.
return; return;
} }
++position_; ++position_;
if (position_ >= NAME_SIZE) if (position_ >= NAME_SIZE) {
{ position_ = NAME_SIZE; // Mantenemos en el índice máximo válido.
position_ = NAME_SIZE; // Mantenemos en el índice máximo válido. position_overflow_ = true; // Activamos el flag de overflow.
position_overflow_ = true; // Activamos el flag de overflow. } else if (position_ > 0) // No es necesario verificar position_ < MAX_NAME_LENGHT
}
else if (position_ > 0) // No es necesario verificar position_ < MAX_NAME_LENGHT
{ {
// Copiamos el índice del carácter anterior si es posible. // Copiamos el índice del carácter anterior si es posible.
character_index_[position_] = character_index_[position_ - 1]; character_index_[position_] = character_index_[position_ - 1];
} } else {
else
{
// Si position_ es 0, inicializamos el carácter actual. // Si position_ es 0, inicializamos el carácter actual.
character_index_[position_] = 0; character_index_[position_] = 0;
} }
@@ -64,36 +56,27 @@ void EnterName::incPosition()
} }
// Decrementa la posición // Decrementa la posición
void EnterName::decPosition() void EnterName::decPosition() {
{ if (position_overflow_) {
if (position_overflow_)
{
// Si estaba en overflow, lo desactivamos y mantenemos position_ en el máximo. // Si estaba en overflow, lo desactivamos y mantenemos position_ en el máximo.
position_overflow_ = false; position_overflow_ = false;
position_ = NAME_SIZE - 1; position_ = NAME_SIZE - 1;
} } else {
else if (position_ > 0) {
{
if (position_ > 0)
{
--position_; --position_;
// Limpiamos el carácter siguiente si el índice es válido. // Limpiamos el carácter siguiente si el índice es válido.
if (position_ + 1 < NAME_SIZE) if (position_ + 1 < NAME_SIZE) {
{
character_index_[position_ + 1] = 0; character_index_[position_ + 1] = 0;
} }
} } else {
else
{
// Si position_ es 0, aseguramos que no vaya a ser negativo y limpiamos el carácter actual. // Si position_ es 0, aseguramos que no vaya a ser negativo y limpiamos el carácter actual.
position_ = 0; position_ = 0;
// character_index_[position_] = 0; // character_index_[position_] = 0;
} }
// Si position_ es menor que NAME_LENGHT, aseguramos que el overflow esté desactivado. // Si position_ es menor que NAME_LENGHT, aseguramos que el overflow esté desactivado.
if (position_ < NAME_SIZE) if (position_ < NAME_SIZE) {
{
position_overflow_ = false; position_overflow_ = false;
} }
} }
@@ -102,71 +85,57 @@ void EnterName::decPosition()
} }
// Incrementa el índice // Incrementa el índice
void EnterName::incIndex() void EnterName::incIndex() {
{ if (position_overflow_) {
if (position_overflow_)
{
return; return;
} }
++character_index_[position_]; ++character_index_[position_];
if (character_index_[position_] >= static_cast<int>(character_list_.size())) if (character_index_[position_] >= static_cast<int>(character_list_.size())) {
{
character_index_[position_] = 0; character_index_[position_] = 0;
} }
updateNameFromCharacterIndex(); updateNameFromCharacterIndex();
} }
// Decrementa el índice // Decrementa el índice
void EnterName::decIndex() void EnterName::decIndex() {
{ if (position_overflow_) {
if (position_overflow_)
{
return; return;
} }
--character_index_[position_]; --character_index_[position_];
if (character_index_[position_] < 0) if (character_index_[position_] < 0) {
{
character_index_[position_] = character_list_.size() - 1; character_index_[position_] = character_list_.size() - 1;
} }
updateNameFromCharacterIndex(); updateNameFromCharacterIndex();
} }
// Actualiza el nombre a partir de la lista de índices // Actualiza el nombre a partir de la lista de índices
void EnterName::updateNameFromCharacterIndex() void EnterName::updateNameFromCharacterIndex() {
{
name_.clear(); name_.clear();
for (size_t i = 0; i < NAME_SIZE; ++i) for (size_t i = 0; i < NAME_SIZE; ++i) {
{
name_.push_back(character_list_[character_index_[i]]); name_.push_back(character_list_[character_index_[i]]);
} }
name_ = trim(name_); name_ = trim(name_);
} }
// Actualiza la variable // Actualiza la variable
void EnterName::initCharacterIndex(const std::string &name) void EnterName::initCharacterIndex(const std::string &name) {
{
// Rellena de espacios // Rellena de espacios
for (size_t i = 0; i < NAME_SIZE; ++i) for (size_t i = 0; i < NAME_SIZE; ++i) {
{
character_index_[i] = 0; character_index_[i] = 0;
} }
// Coloca los índices en función de los caracteres que forman el nombre // Coloca los índices en función de los caracteres que forman el nombre
for (size_t i = 0; i < name.substr(0, NAME_SIZE).size(); ++i) for (size_t i = 0; i < name.substr(0, NAME_SIZE).size(); ++i) {
{
character_index_[i] = findIndex(name.at(i)); character_index_[i] = findIndex(name.at(i));
} }
} }
// Encuentra el indice de un caracter en "character_list_" // Encuentra el indice de un caracter en "character_list_"
int EnterName::findIndex(char character) const int EnterName::findIndex(char character) const {
{ for (size_t i = 0; i < character_list_.size(); ++i) {
for (size_t i = 0; i < character_list_.size(); ++i) if (character == character_list_.at(i)) {
{
if (character == character_list_.at(i))
{
return i; return i;
} }
} }
@@ -174,18 +143,15 @@ int EnterName::findIndex(char character) const
} }
// Devuelve un nombre al azar // Devuelve un nombre al azar
std::string EnterName::getRandomName() std::string EnterName::getRandomName() {
{
static constexpr std::array<std::string_view, 8> NAMES = { static constexpr std::array<std::string_view, 8> NAMES = {
"BAL1", "TABE", "DOC", "MON", "SAM1", "JORDI", "JDES", "PEPE"}; "BAL1", "TABE", "DOC", "MON", "SAM1", "JORDI", "JDES", "PEPE"};
return std::string(NAMES[rand() % NAMES.size()]); return std::string(NAMES[rand() % NAMES.size()]);
} }
// Obtiene el nombre final introducido // Obtiene el nombre final introducido
std::string EnterName::getFinalName() std::string EnterName::getFinalName() {
{
auto name = trim(name_.substr(0, position_)); auto name = trim(name_.substr(0, position_));
if (name.empty()) if (name.empty()) {
{
name = getRandomName(); name = getRandomName();
} }
name_ = name; name_ = name;
+26 -26
View File
@@ -1,43 +1,43 @@
#pragma once #pragma once
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <array> // Para array
#include <string> // Para string, basic_string
#include "utils.h" // Para trim #include <array> // Para array
#include <string> // Para string, basic_string
#include "utils.h" // Para trim
// Tamaño máximo del nombre // Tamaño máximo del nombre
constexpr size_t NAME_SIZE = 5; constexpr size_t NAME_SIZE = 5;
// Clase EnterName // Clase EnterName
class EnterName class EnterName {
{ public:
public:
EnterName(); EnterName();
~EnterName() = default; ~EnterName() = default;
void init(const std::string &name = ""); // Inicializa con un nombre opcional void init(const std::string &name = ""); // Inicializa con un nombre opcional
void incPosition(); // Incrementa la posición del carácter actual void incPosition(); // Incrementa la posición del carácter actual
void decPosition(); // Decrementa la posición del carácter actual void decPosition(); // Decrementa la posición del carácter actual
void incIndex(); // Incrementa el índice del carácter en la lista void incIndex(); // Incrementa el índice del carácter en la lista
void decIndex(); // Decrementa el índice del carácter en la lista void decIndex(); // Decrementa el índice del carácter en la lista
std::string getFinalName(); // Obtiene el nombre final introducido std::string getFinalName(); // Obtiene el nombre final introducido
std::string getCurrentName() const { return trim(name_); } // Obtiene el nombre actual en proceso std::string getCurrentName() const { return trim(name_); } // Obtiene el nombre actual en proceso
int getPosition() const { return position_; } // Posición actual del carácter editado int getPosition() const { return position_; } // Posición actual del carácter editado
bool getPositionOverflow() const { return position_overflow_; } // Indica si la posición excede el límite bool getPositionOverflow() const { return position_overflow_; } // Indica si la posición excede el límite
private: private:
std::string character_list_; // Lista de caracteres permitidos std::string character_list_; // Lista de caracteres permitidos
std::string name_; // Nombre en proceso std::string name_; // Nombre en proceso
size_t position_ = 0; // Índice del carácter que se edita size_t position_ = 0; // Índice del carácter que se edita
bool position_overflow_ = false; // Flag para exceder límite bool position_overflow_ = false; // Flag para exceder límite
std::array<int, NAME_SIZE> character_index_; // Índices a "character_list_" std::array<int, NAME_SIZE> character_index_; // Índices a "character_list_"
void updateNameFromCharacterIndex(); // Actualiza "name_" según "character_index_" void updateNameFromCharacterIndex(); // Actualiza "name_" según "character_index_"
void initCharacterIndex(const std::string &name); // Inicializa índices desde el nombre void initCharacterIndex(const std::string &name); // Inicializa índices desde el nombre
int findIndex(char character) const; // Busca el índice de un carácter en "character_list_" int findIndex(char character) const; // Busca el índice de un carácter en "character_list_"
static std::string getRandomName(); // Devuelve un nombre al azar static std::string getRandomName(); // Devuelve un nombre al azar
}; };
+15 -28
View File
@@ -1,14 +1,12 @@
#include "explosions.h" #include "explosions.h"
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
class Texture; // lines 4-4 class Texture; // lines 4-4
// Actualiza la lógica de la clase // Actualiza la lógica de la clase
void Explosions::update() void Explosions::update() {
{ for (auto &explosion : explosions_) {
for (auto &explosion : explosions_)
{
explosion->update(); explosion->update();
} }
@@ -17,37 +15,29 @@ void Explosions::update()
} }
// Dibuja el objeto en pantalla // Dibuja el objeto en pantalla
void Explosions::render() void Explosions::render() {
{ for (auto &explosion : explosions_) {
for (auto &explosion : explosions_)
{
explosion->render(); explosion->render();
} }
} }
// Añade texturas al objeto // Añade texturas al objeto
void Explosions::addTexture(int size, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation) void Explosions::addTexture(int size, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation) {
{
textures_.emplace_back(ExplosionTexture(size, texture, animation)); textures_.emplace_back(ExplosionTexture(size, texture, animation));
} }
// Añade una explosión // Añade una explosión
void Explosions::add(int x, int y, int size) void Explosions::add(int x, int y, int size) {
{
const auto INDEX = getIndexBySize(size); const auto INDEX = getIndexBySize(size);
explosions_.emplace_back(std::make_unique<AnimatedSprite>(textures_[INDEX].texture, textures_[INDEX].animation)); explosions_.emplace_back(std::make_unique<AnimatedSprite>(textures_[INDEX].texture, textures_[INDEX].animation));
explosions_.back()->setPos(x, y); explosions_.back()->setPos(x, y);
} }
// Vacia el vector de elementos finalizados // Vacia el vector de elementos finalizados
void Explosions::freeExplosions() void Explosions::freeExplosions() {
{ if (explosions_.empty() == false) {
if (explosions_.empty() == false) for (int i = explosions_.size() - 1; i >= 0; --i) {
{ if (explosions_[i]->animationIsCompleted()) {
for (int i = explosions_.size() - 1; i >= 0; --i)
{
if (explosions_[i]->animationIsCompleted())
{
explosions_.erase(explosions_.begin() + i); explosions_.erase(explosions_.begin() + i);
} }
} }
@@ -55,12 +45,9 @@ void Explosions::freeExplosions()
} }
// Busca una textura a partir del tamaño // Busca una textura a partir del tamaño
int Explosions::getIndexBySize(int size) int Explosions::getIndexBySize(int size) {
{ for (int i = 0; i < (int)textures_.size(); ++i) {
for (int i = 0; i < (int)textures_.size(); ++i) if (size == textures_[i].size) {
{
if (size == textures_[i].size)
{
return i; return i;
} }
} }
+11 -13
View File
@@ -1,28 +1,26 @@
#pragma once #pragma once
#include <memory> // Para unique_ptr, shared_ptr #include <memory> // Para unique_ptr, shared_ptr
#include <string> // Para string #include <string> // Para string
#include <vector> // Para vector #include <vector> // Para vector
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
class Texture; class Texture;
// Estructura para almacenar la información de una textura de explosión // Estructura para almacenar la información de una textura de explosión
struct ExplosionTexture struct ExplosionTexture {
{ int size; // Tamaño de la explosión
int size; // Tamaño de la explosión std::shared_ptr<Texture> texture; // Textura para la explosión
std::shared_ptr<Texture> texture; // Textura para la explosión std::vector<std::string> animation; // Animación para la textura
std::vector<std::string> animation; // Animación para la textura
ExplosionTexture(int sz, std::shared_ptr<Texture> tex, const std::vector<std::string> &anim) ExplosionTexture(int sz, std::shared_ptr<Texture> tex, const std::vector<std::string> &anim)
: size(sz), texture(tex), animation(anim) {} : size(sz), texture(tex), animation(anim) {}
}; };
// Clase Explosions // Clase Explosions
class Explosions class Explosions {
{ public:
public:
// Constructor y destructor // Constructor y destructor
Explosions() = default; Explosions() = default;
~Explosions() = default; ~Explosions() = default;
@@ -39,7 +37,7 @@ public:
// Añade una explosión // Añade una explosión
void add(int x, int y, int size); void add(int x, int y, int size);
private: private:
// Vector con las texturas a utilizar // Vector con las texturas a utilizar
std::vector<ExplosionTexture> textures_; std::vector<ExplosionTexture> textures_;
+199 -243
View File
@@ -1,249 +1,214 @@
#include "gif.h" #include "gif.h"
#include <SDL3/SDL.h> // Para SDL_LogError, SDL_LogCategory, SDL_LogInfo #include <SDL3/SDL.h> // Para SDL_LogError, SDL_LogCategory, SDL_LogInfo
#include <cstring> // Para memcpy, size_t #include <cstring> // Para memcpy, size_t
#include <stdexcept> // Para runtime_error #include <stdexcept> // Para runtime_error
#include <string> // Para char_traits, operator==, basic_string, string #include <string> // Para char_traits, operator==, basic_string, string
namespace GIF namespace GIF {
{ inline void readBytes(const uint8_t *&buffer, void *dst, size_t size) {
inline void readBytes(const uint8_t *&buffer, void *dst, size_t size) std::memcpy(dst, buffer, size);
{ buffer += size;
std::memcpy(dst, buffer, size); }
buffer += size;
void Gif::decompress(int code_length, const uint8_t *input, int input_length, uint8_t *out) {
if (code_length < 2 || code_length > 12) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid LZW code length: %d", code_length);
throw std::runtime_error("Invalid LZW code length");
} }
void Gif::decompress(int code_length, const uint8_t *input, int input_length, uint8_t *out) int i, bit;
{ int prev = -1;
if (code_length < 2 || code_length > 12) std::vector<DictionaryEntry> dictionary;
{ int dictionary_ind;
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid LZW code length: %d", code_length); unsigned int mask = 0x01;
throw std::runtime_error("Invalid LZW code length"); int reset_code_length = code_length;
int clear_code = 1 << code_length;
int stop_code = clear_code + 1;
int match_len = 0;
dictionary.resize(1 << (code_length + 1));
for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) {
dictionary[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind);
dictionary[dictionary_ind].prev = -1;
dictionary[dictionary_ind].len = 1;
}
dictionary_ind += 2;
while (input_length > 0) {
int code = 0;
for (i = 0; i < (code_length + 1); i++) {
if (input_length <= 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unexpected end of input in decompress");
throw std::runtime_error("Unexpected end of input in decompress");
}
bit = ((*input & mask) != 0) ? 1 : 0;
mask <<= 1;
if (mask == 0x100) {
mask = 0x01;
input++;
input_length--;
}
code |= (bit << i);
} }
int i, bit; if (code == clear_code) {
int prev = -1; code_length = reset_code_length;
std::vector<DictionaryEntry> dictionary; dictionary.resize(1 << (code_length + 1));
int dictionary_ind; for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) {
unsigned int mask = 0x01; dictionary[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind);
int reset_code_length = code_length; dictionary[dictionary_ind].prev = -1;
int clear_code = 1 << code_length; dictionary[dictionary_ind].len = 1;
int stop_code = clear_code + 1; }
int match_len = 0; dictionary_ind += 2;
prev = -1;
dictionary.resize(1 << (code_length + 1)); continue;
for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) } else if (code == stop_code) {
{ break;
dictionary[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind);
dictionary[dictionary_ind].prev = -1;
dictionary[dictionary_ind].len = 1;
} }
dictionary_ind += 2;
while (input_length > 0) if (prev > -1 && code_length < 12) {
{ if (code > dictionary_ind) {
int code = 0; SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "LZW error: code (%d) exceeds dictionary_ind (%d)", code, dictionary_ind);
for (i = 0; i < (code_length + 1); i++) throw std::runtime_error("LZW error: code exceeds dictionary_ind.");
{
if (input_length <= 0)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unexpected end of input in decompress");
throw std::runtime_error("Unexpected end of input in decompress");
}
bit = ((*input & mask) != 0) ? 1 : 0;
mask <<= 1;
if (mask == 0x100)
{
mask = 0x01;
input++;
input_length--;
}
code |= (bit << i);
} }
if (code == clear_code) int ptr;
{ if (code == dictionary_ind) {
code_length = reset_code_length; ptr = prev;
while (dictionary[ptr].prev != -1)
ptr = dictionary[ptr].prev;
dictionary[dictionary_ind].byte = dictionary[ptr].byte;
} else {
ptr = code;
while (dictionary[ptr].prev != -1)
ptr = dictionary[ptr].prev;
dictionary[dictionary_ind].byte = dictionary[ptr].byte;
}
dictionary[dictionary_ind].prev = prev;
dictionary[dictionary_ind].len = dictionary[prev].len + 1;
dictionary_ind++;
if ((dictionary_ind == (1 << (code_length + 1))) && (code_length < 11)) {
code_length++;
dictionary.resize(1 << (code_length + 1)); dictionary.resize(1 << (code_length + 1));
for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++)
{
dictionary[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind);
dictionary[dictionary_ind].prev = -1;
dictionary[dictionary_ind].len = 1;
}
dictionary_ind += 2;
prev = -1;
continue;
} }
else if (code == stop_code)
{
break;
}
if (prev > -1 && code_length < 12)
{
if (code > dictionary_ind)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "LZW error: code (%d) exceeds dictionary_ind (%d)", code, dictionary_ind);
throw std::runtime_error("LZW error: code exceeds dictionary_ind.");
}
int ptr;
if (code == dictionary_ind)
{
ptr = prev;
while (dictionary[ptr].prev != -1)
ptr = dictionary[ptr].prev;
dictionary[dictionary_ind].byte = dictionary[ptr].byte;
}
else
{
ptr = code;
while (dictionary[ptr].prev != -1)
ptr = dictionary[ptr].prev;
dictionary[dictionary_ind].byte = dictionary[ptr].byte;
}
dictionary[dictionary_ind].prev = prev;
dictionary[dictionary_ind].len = dictionary[prev].len + 1;
dictionary_ind++;
if ((dictionary_ind == (1 << (code_length + 1))) && (code_length < 11))
{
code_length++;
dictionary.resize(1 << (code_length + 1));
}
}
prev = code;
if (code < 0 || static_cast<size_t>(code) >= dictionary.size())
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid LZW code %d, dictionary size %lu", code, static_cast<unsigned long>(dictionary.size()));
throw std::runtime_error("LZW error: invalid code encountered");
}
int curCode = code;
match_len = dictionary[curCode].len;
while (curCode != -1)
{
out[dictionary[curCode].len - 1] = dictionary[curCode].byte;
if (dictionary[curCode].prev == curCode)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Internal error; self-reference detected.");
throw std::runtime_error("Internal error in decompress: self-reference");
}
curCode = dictionary[curCode].prev;
}
out += match_len;
} }
}
std::vector<uint8_t> Gif::readSubBlocks(const uint8_t *&buffer) prev = code;
{
std::vector<uint8_t> data; if (code < 0 || static_cast<size_t>(code) >= dictionary.size()) {
uint8_t block_size = *buffer; SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid LZW code %d, dictionary size %lu", code, static_cast<unsigned long>(dictionary.size()));
throw std::runtime_error("LZW error: invalid code encountered");
}
int curCode = code;
match_len = dictionary[curCode].len;
while (curCode != -1) {
out[dictionary[curCode].len - 1] = dictionary[curCode].byte;
if (dictionary[curCode].prev == curCode) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Internal error; self-reference detected.");
throw std::runtime_error("Internal error in decompress: self-reference");
}
curCode = dictionary[curCode].prev;
}
out += match_len;
}
}
std::vector<uint8_t> Gif::readSubBlocks(const uint8_t *&buffer) {
std::vector<uint8_t> data;
uint8_t block_size = *buffer;
buffer++;
while (block_size != 0) {
data.insert(data.end(), buffer, buffer + block_size);
buffer += block_size;
block_size = *buffer;
buffer++; buffer++;
while (block_size != 0) }
{ return data;
data.insert(data.end(), buffer, buffer + block_size); }
buffer += block_size;
block_size = *buffer; std::vector<uint8_t> Gif::processImageDescriptor(const uint8_t *&buffer, const std::vector<RGB> &gct, int resolution_bits) {
buffer++; ImageDescriptor image_descriptor;
readBytes(buffer, &image_descriptor, sizeof(ImageDescriptor));
uint8_t lzw_code_size;
readBytes(buffer, &lzw_code_size, sizeof(uint8_t));
std::vector<uint8_t> compressed_data = readSubBlocks(buffer);
int uncompressed_data_length = image_descriptor.image_width * image_descriptor.image_height;
std::vector<uint8_t> uncompressed_data(uncompressed_data_length);
decompress(lzw_code_size, compressed_data.data(), static_cast<int>(compressed_data.size()), uncompressed_data.data());
return uncompressed_data;
}
std::vector<uint32_t> Gif::loadPalette(const uint8_t *buffer) {
uint8_t header[6];
std::memcpy(header, buffer, 6);
buffer += 6;
ScreenDescriptor screen_descriptor;
std::memcpy(&screen_descriptor, buffer, sizeof(ScreenDescriptor));
buffer += sizeof(ScreenDescriptor);
std::vector<uint32_t> global_color_table;
if (screen_descriptor.fields & 0x80) {
int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1));
global_color_table.resize(global_color_table_size);
for (int i = 0; i < global_color_table_size; ++i) {
uint8_t r = buffer[0];
uint8_t g = buffer[1];
uint8_t b = buffer[2];
global_color_table[i] = (r << 16) | (g << 8) | b;
buffer += 3;
} }
return data; }
return global_color_table;
}
std::vector<uint8_t> Gif::processGifStream(const uint8_t *buffer, uint16_t &w, uint16_t &h) {
uint8_t header[6];
std::memcpy(header, buffer, 6);
buffer += 6;
std::string headerStr(reinterpret_cast<char *>(header), 6);
if (headerStr != "GIF87a" && headerStr != "GIF89a") {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Formato de archivo GIF inválido: %s", headerStr.c_str());
throw std::runtime_error("Formato de archivo GIF inválido.");
} }
std::vector<uint8_t> Gif::processImageDescriptor(const uint8_t *&buffer, const std::vector<RGB> &gct, int resolution_bits) SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "Procesando GIF con cabecera: %s", headerStr.c_str());
{
ImageDescriptor image_descriptor;
readBytes(buffer, &image_descriptor, sizeof(ImageDescriptor));
uint8_t lzw_code_size; ScreenDescriptor screen_descriptor;
readBytes(buffer, &lzw_code_size, sizeof(uint8_t)); readBytes(buffer, &screen_descriptor, sizeof(ScreenDescriptor));
std::vector<uint8_t> compressed_data = readSubBlocks(buffer); w = screen_descriptor.width;
int uncompressed_data_length = image_descriptor.image_width * image_descriptor.image_height; h = screen_descriptor.height;
std::vector<uint8_t> uncompressed_data(uncompressed_data_length);
decompress(lzw_code_size, compressed_data.data(), static_cast<int>(compressed_data.size()), uncompressed_data.data()); SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "Resolución del GIF: %dx%d", w, h);
return uncompressed_data;
int color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1;
std::vector<RGB> global_color_table;
if (screen_descriptor.fields & 0x80) {
int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1));
global_color_table.resize(global_color_table_size);
std::memcpy(global_color_table.data(), buffer, 3 * global_color_table_size);
buffer += 3 * global_color_table_size;
} }
std::vector<uint32_t> Gif::loadPalette(const uint8_t *buffer) uint8_t block_type = *buffer++;
{ while (block_type != TRAILER) {
uint8_t header[6]; if (block_type == EXTENSION_INTRODUCER) {
std::memcpy(header, buffer, 6); uint8_t extension_label = *buffer++;
buffer += 6; switch (extension_label) {
case GRAPHIC_CONTROL: {
ScreenDescriptor screen_descriptor;
std::memcpy(&screen_descriptor, buffer, sizeof(ScreenDescriptor));
buffer += sizeof(ScreenDescriptor);
std::vector<uint32_t> global_color_table;
if (screen_descriptor.fields & 0x80)
{
int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1));
global_color_table.resize(global_color_table_size);
for (int i = 0; i < global_color_table_size; ++i)
{
uint8_t r = buffer[0];
uint8_t g = buffer[1];
uint8_t b = buffer[2];
global_color_table[i] = (r << 16) | (g << 8) | b;
buffer += 3;
}
}
return global_color_table;
}
std::vector<uint8_t> Gif::processGifStream(const uint8_t *buffer, uint16_t &w, uint16_t &h)
{
uint8_t header[6];
std::memcpy(header, buffer, 6);
buffer += 6;
std::string headerStr(reinterpret_cast<char *>(header), 6);
if (headerStr != "GIF87a" && headerStr != "GIF89a")
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Formato de archivo GIF inválido: %s", headerStr.c_str());
throw std::runtime_error("Formato de archivo GIF inválido.");
}
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "Procesando GIF con cabecera: %s", headerStr.c_str());
ScreenDescriptor screen_descriptor;
readBytes(buffer, &screen_descriptor, sizeof(ScreenDescriptor));
w = screen_descriptor.width;
h = screen_descriptor.height;
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "Resolución del GIF: %dx%d", w, h);
int color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1;
std::vector<RGB> global_color_table;
if (screen_descriptor.fields & 0x80)
{
int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1));
global_color_table.resize(global_color_table_size);
std::memcpy(global_color_table.data(), buffer, 3 * global_color_table_size);
buffer += 3 * global_color_table_size;
}
uint8_t block_type = *buffer++;
while (block_type != TRAILER)
{
if (block_type == EXTENSION_INTRODUCER)
{
uint8_t extension_label = *buffer++;
switch (extension_label)
{
case GRAPHIC_CONTROL:
{
uint8_t blockSize = *buffer++; uint8_t blockSize = *buffer++;
buffer += blockSize; buffer += blockSize;
uint8_t subBlockSize = *buffer++; uint8_t subBlockSize = *buffer++;
while (subBlockSize != 0) while (subBlockSize != 0) {
{
buffer += subBlockSize; buffer += subBlockSize;
subBlockSize = *buffer++; subBlockSize = *buffer++;
} }
@@ -251,51 +216,42 @@ namespace GIF
} }
case APPLICATION_EXTENSION: case APPLICATION_EXTENSION:
case COMMENT_EXTENSION: case COMMENT_EXTENSION:
case PLAINTEXT_EXTENSION: case PLAINTEXT_EXTENSION: {
{
uint8_t blockSize = *buffer++; uint8_t blockSize = *buffer++;
buffer += blockSize; buffer += blockSize;
uint8_t subBlockSize = *buffer++; uint8_t subBlockSize = *buffer++;
while (subBlockSize != 0) while (subBlockSize != 0) {
{
buffer += subBlockSize; buffer += subBlockSize;
subBlockSize = *buffer++; subBlockSize = *buffer++;
} }
break; break;
} }
default: default: {
{
uint8_t blockSize = *buffer++; uint8_t blockSize = *buffer++;
buffer += blockSize; buffer += blockSize;
uint8_t subBlockSize = *buffer++; uint8_t subBlockSize = *buffer++;
while (subBlockSize != 0) while (subBlockSize != 0) {
{
buffer += subBlockSize; buffer += subBlockSize;
subBlockSize = *buffer++; subBlockSize = *buffer++;
} }
break; break;
} }
}
} }
else if (block_type == IMAGE_DESCRIPTOR) } else if (block_type == IMAGE_DESCRIPTOR) {
{ return processImageDescriptor(buffer, global_color_table, color_resolution_bits);
return processImageDescriptor(buffer, global_color_table, color_resolution_bits); } else {
} SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Unrecognized block type: 0x%X", block_type);
else return std::vector<uint8_t>{};
{
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Unrecognized block type: 0x%X", block_type);
return std::vector<uint8_t>{};
}
block_type = *buffer++;
} }
block_type = *buffer++;
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "GIF procesado correctamente.");
return std::vector<uint8_t>{};
} }
std::vector<uint8_t> Gif::loadGif(const uint8_t *buffer, uint16_t &w, uint16_t &h) SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "GIF procesado correctamente.");
{ return std::vector<uint8_t>{};
return processGifStream(buffer, w, h); }
}
} // namespace GIF std::vector<uint8_t> Gif::loadGif(const uint8_t *buffer, uint16_t &w, uint16_t &h) {
return processGifStream(buffer, w, h);
}
} // namespace GIF
+71 -81
View File
@@ -1,102 +1,92 @@
#pragma once #pragma once
#include <cstdint> // Para uint8_t, uint16_t, uint32_t #include <cstdint> // Para uint8_t, uint16_t, uint32_t
#include <vector> // Para vector #include <vector> // Para vector
namespace GIF namespace GIF {
{
// Constantes definidas con constexpr, en lugar de macros // Constantes definidas con constexpr, en lugar de macros
constexpr uint8_t EXTENSION_INTRODUCER = 0x21; constexpr uint8_t EXTENSION_INTRODUCER = 0x21;
constexpr uint8_t IMAGE_DESCRIPTOR = 0x2C; constexpr uint8_t IMAGE_DESCRIPTOR = 0x2C;
constexpr uint8_t TRAILER = 0x3B; constexpr uint8_t TRAILER = 0x3B;
constexpr uint8_t GRAPHIC_CONTROL = 0xF9; constexpr uint8_t GRAPHIC_CONTROL = 0xF9;
constexpr uint8_t APPLICATION_EXTENSION = 0xFF; constexpr uint8_t APPLICATION_EXTENSION = 0xFF;
constexpr uint8_t COMMENT_EXTENSION = 0xFE; constexpr uint8_t COMMENT_EXTENSION = 0xFE;
constexpr uint8_t PLAINTEXT_EXTENSION = 0x01; constexpr uint8_t PLAINTEXT_EXTENSION = 0x01;
#pragma pack(push, 1) #pragma pack(push, 1)
struct ScreenDescriptor struct ScreenDescriptor {
{ uint16_t width;
uint16_t width; uint16_t height;
uint16_t height; uint8_t fields;
uint8_t fields; uint8_t background_color_index;
uint8_t background_color_index; uint8_t pixel_aspect_ratio;
uint8_t pixel_aspect_ratio; };
};
struct RGB struct RGB {
{ uint8_t r, g, b;
uint8_t r, g, b; };
};
struct ImageDescriptor struct ImageDescriptor {
{ uint16_t image_left_position;
uint16_t image_left_position; uint16_t image_top_position;
uint16_t image_top_position; uint16_t image_width;
uint16_t image_width; uint16_t image_height;
uint16_t image_height; uint8_t fields;
uint8_t fields; };
};
#pragma pack(pop) #pragma pack(pop)
struct DictionaryEntry struct DictionaryEntry {
{ uint8_t byte;
uint8_t byte; int prev;
int prev; int len;
int len; };
};
struct Extension struct Extension {
{ uint8_t extension_code;
uint8_t extension_code; uint8_t block_size;
uint8_t block_size; };
};
struct GraphicControlExtension struct GraphicControlExtension {
{ uint8_t fields;
uint8_t fields; uint16_t delay_time;
uint16_t delay_time; uint8_t transparent_color_index;
uint8_t transparent_color_index; };
};
struct ApplicationExtension struct ApplicationExtension {
{ uint8_t application_id[8];
uint8_t application_id[8]; uint8_t version[3];
uint8_t version[3]; };
};
struct PlaintextExtension struct PlaintextExtension {
{ uint16_t left, top, width, height;
uint16_t left, top, width, height; uint8_t cell_width, cell_height;
uint8_t cell_width, cell_height; uint8_t foreground_color, background_color;
uint8_t foreground_color, background_color; };
};
class Gif class Gif {
{ public:
public: // Descompone (uncompress) el bloque comprimido usando LZW.
// Descompone (uncompress) el bloque comprimido usando LZW. // Este método puede lanzar std::runtime_error en caso de error.
// Este método puede lanzar std::runtime_error en caso de error. void decompress(int code_length, const uint8_t *input, int input_length, uint8_t *out);
void decompress(int code_length, const uint8_t *input, int input_length, uint8_t *out);
// Carga la paleta (global color table) a partir de un buffer, // Carga la paleta (global color table) a partir de un buffer,
// retornándola en un vector de uint32_t (cada color se compone de R, G, B). // retornándola en un vector de uint32_t (cada color se compone de R, G, B).
std::vector<uint32_t> loadPalette(const uint8_t *buffer); std::vector<uint32_t> loadPalette(const uint8_t *buffer);
// Carga el stream GIF; devuelve un vector con los datos de imagen sin comprimir y // Carga el stream GIF; devuelve un vector con los datos de imagen sin comprimir y
// asigna el ancho y alto mediante referencias. // asigna el ancho y alto mediante referencias.
std::vector<uint8_t> loadGif(const uint8_t *buffer, uint16_t &w, uint16_t &h); std::vector<uint8_t> loadGif(const uint8_t *buffer, uint16_t &w, uint16_t &h);
private: private:
// Lee los sub-bloques de datos y los acumula en un std::vector<uint8_t>. // Lee los sub-bloques de datos y los acumula en un std::vector<uint8_t>.
std::vector<uint8_t> readSubBlocks(const uint8_t *&buffer); std::vector<uint8_t> readSubBlocks(const uint8_t *&buffer);
// Procesa el Image Descriptor y retorna el vector de datos sin comprimir. // Procesa el Image Descriptor y retorna el vector de datos sin comprimir.
std::vector<uint8_t> processImageDescriptor(const uint8_t *&buffer, const std::vector<RGB> &gct, int resolution_bits); std::vector<uint8_t> processImageDescriptor(const uint8_t *&buffer, const std::vector<RGB> &gct, int resolution_bits);
// Procesa el stream completo del GIF y devuelve los datos sin comprimir. // Procesa el stream completo del GIF y devuelve los datos sin comprimir.
std::vector<uint8_t> processGifStream(const uint8_t *buffer, uint16_t &w, uint16_t &h); std::vector<uint8_t> processGifStream(const uint8_t *buffer, uint16_t &w, uint16_t &h);
}; };
} // namespace GIF } // namespace GIF
+66 -132
View File
@@ -1,26 +1,24 @@
#ifndef JA_USESDLMIXER #ifndef JA_USESDLMIXER
#include "jail_audio.h" #include "jail_audio.h"
#include <SDL3/SDL.h> // Para SDL_AudioFormat, SDL_BindAudioStream, SDL_Se... #include <SDL3/SDL.h> // Para SDL_AudioFormat, SDL_BindAudioStream, SDL_Se...
#include <stdint.h> // Para uint32_t, uint8_t #include <stdint.h> // Para uint32_t, uint8_t
#include <stdio.h> // Para NULL, fseek, printf, fclose, fopen, fread #include <stdio.h> // Para NULL, fseek, printf, fclose, fopen, fread
#include <stdlib.h> // Para free, malloc #include <stdlib.h> // Para free, malloc
#include <string.h> // Para strcpy, strlen #include <string.h> // Para strcpy, strlen
#include "stb_vorbis.h" // Para stb_vorbis_decode_memory #include "stb_vorbis.h" // Para stb_vorbis_decode_memory
#define JA_MAX_SIMULTANEOUS_CHANNELS 20 #define JA_MAX_SIMULTANEOUS_CHANNELS 20
#define JA_MAX_GROUPS 2 #define JA_MAX_GROUPS 2
struct JA_Sound_t struct JA_Sound_t {
{
SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000}; SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000};
Uint32 length{0}; Uint32 length{0};
Uint8 *buffer{NULL}; Uint8 *buffer{NULL};
}; };
struct JA_Channel_t struct JA_Channel_t {
{
JA_Sound_t *sound{nullptr}; JA_Sound_t *sound{nullptr};
int pos{0}; int pos{0};
int times{0}; int times{0};
@@ -29,8 +27,7 @@ struct JA_Channel_t
JA_Channel_state state{JA_CHANNEL_FREE}; JA_Channel_state state{JA_CHANNEL_FREE};
}; };
struct JA_Music_t struct JA_Music_t {
{
SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000}; SDL_AudioSpec spec{SDL_AUDIO_S16, 2, 48000};
Uint32 length{0}; Uint32 length{0};
Uint8 *buffer{nullptr}; Uint8 *buffer{nullptr};
@@ -58,59 +55,43 @@ int fade_start_time;
int fade_duration; int fade_duration;
int fade_initial_volume; int fade_initial_volume;
Uint32 JA_UpdateCallback(void *userdata, SDL_TimerID timerID, Uint32 interval) Uint32 JA_UpdateCallback(void *userdata, SDL_TimerID timerID, Uint32 interval) {
{ if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING) {
if (JA_musicEnabled && current_music && current_music->state == JA_MUSIC_PLAYING) if (fading) {
{
if (fading)
{
int time = SDL_GetTicks(); int time = SDL_GetTicks();
if (time > (fade_start_time + fade_duration)) if (time > (fade_start_time + fade_duration)) {
{
fading = false; fading = false;
JA_StopMusic(); JA_StopMusic();
return 30; return 30;
} } else {
else
{
const int time_passed = time - fade_start_time; const int time_passed = time - fade_start_time;
const float percent = (float)time_passed / (float)fade_duration; const float percent = (float)time_passed / (float)fade_duration;
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume * (1.0 - percent)); SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume * (1.0 - percent));
} }
} }
if (current_music->times != 0) if (current_music->times != 0) {
{ if ((Uint32)SDL_GetAudioStreamAvailable(current_music->stream) < (current_music->length / 2)) {
if ((Uint32)SDL_GetAudioStreamAvailable(current_music->stream) < (current_music->length / 2))
{
SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length); SDL_PutAudioStreamData(current_music->stream, current_music->buffer, current_music->length);
} }
if (current_music->times > 0) if (current_music->times > 0)
current_music->times--; current_music->times--;
} } else {
else
{
if (SDL_GetAudioStreamAvailable(current_music->stream) == 0) if (SDL_GetAudioStreamAvailable(current_music->stream) == 0)
JA_StopMusic(); JA_StopMusic();
} }
} }
if (JA_soundEnabled) if (JA_soundEnabled) {
{
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i) for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; ++i)
if (channels[i].state == JA_CHANNEL_PLAYING) if (channels[i].state == JA_CHANNEL_PLAYING) {
{ if (channels[i].times != 0) {
if (channels[i].times != 0) if ((Uint32)SDL_GetAudioStreamAvailable(channels[i].stream) < (channels[i].sound->length / 2)) {
{
if ((Uint32)SDL_GetAudioStreamAvailable(channels[i].stream) < (channels[i].sound->length / 2))
{
SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer, channels[i].sound->length); SDL_PutAudioStreamData(channels[i].stream, channels[i].sound->buffer, channels[i].sound->length);
if (channels[i].times > 0) if (channels[i].times > 0)
channels[i].times--; channels[i].times--;
} }
} } else {
else
{
if (SDL_GetAudioStreamAvailable(channels[i].stream) == 0) if (SDL_GetAudioStreamAvailable(channels[i].stream) == 0)
JA_StopChannel(i); JA_StopChannel(i);
} }
@@ -120,8 +101,7 @@ Uint32 JA_UpdateCallback(void *userdata, SDL_TimerID timerID, Uint32 interval)
return 30; return 30;
} }
void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channels) void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channels) {
{
#ifdef DEBUG #ifdef DEBUG
SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG); SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
#endif #endif
@@ -140,8 +120,7 @@ void JA_Init(const int freq, const SDL_AudioFormat format, const int num_channel
JA_timerID = SDL_AddTimer(30, JA_UpdateCallback, nullptr); JA_timerID = SDL_AddTimer(30, JA_UpdateCallback, nullptr);
} }
void JA_Quit() void JA_Quit() {
{
if (JA_timerID) if (JA_timerID)
SDL_RemoveTimer(JA_timerID); SDL_RemoveTimer(JA_timerID);
@@ -150,8 +129,7 @@ void JA_Quit()
sdlAudioDevice = 0; sdlAudioDevice = 0;
} }
JA_Music_t *JA_LoadMusic(Uint8 *buffer, Uint32 length) JA_Music_t *JA_LoadMusic(Uint8 *buffer, Uint32 length) {
{
JA_Music_t *music = new JA_Music_t(); JA_Music_t *music = new JA_Music_t();
int chan, samplerate; int chan, samplerate;
@@ -170,8 +148,7 @@ JA_Music_t *JA_LoadMusic(Uint8 *buffer, Uint32 length)
return music; return music;
} }
JA_Music_t *JA_LoadMusic(const char *filename) JA_Music_t *JA_LoadMusic(const char *filename) {
{
// [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid. // [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid.
FILE *f = fopen(filename, "rb"); FILE *f = fopen(filename, "rb");
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
@@ -191,8 +168,7 @@ JA_Music_t *JA_LoadMusic(const char *filename)
return music; return music;
} }
void JA_PlayMusic(JA_Music_t *music, const int loop) void JA_PlayMusic(JA_Music_t *music, const int loop) {
{
if (!JA_musicEnabled) if (!JA_musicEnabled)
return; return;
@@ -212,15 +188,13 @@ void JA_PlayMusic(JA_Music_t *music, const int loop)
// SDL_ResumeAudioStreamDevice(current_music->stream); // SDL_ResumeAudioStreamDevice(current_music->stream);
} }
char *JA_GetMusicFilename(JA_Music_t *music) char *JA_GetMusicFilename(JA_Music_t *music) {
{
if (!music) if (!music)
music = current_music; music = current_music;
return music->filename; return music->filename;
} }
void JA_PauseMusic() void JA_PauseMusic() {
{
if (!JA_musicEnabled) if (!JA_musicEnabled)
return; return;
if (!current_music || current_music->state == JA_MUSIC_INVALID) if (!current_music || current_music->state == JA_MUSIC_INVALID)
@@ -231,8 +205,7 @@ void JA_PauseMusic()
SDL_UnbindAudioStream(current_music->stream); SDL_UnbindAudioStream(current_music->stream);
} }
void JA_ResumeMusic() void JA_ResumeMusic() {
{
if (!JA_musicEnabled) if (!JA_musicEnabled)
return; return;
if (!current_music || current_music->state == JA_MUSIC_INVALID) if (!current_music || current_music->state == JA_MUSIC_INVALID)
@@ -243,8 +216,7 @@ void JA_ResumeMusic()
SDL_BindAudioStream(sdlAudioDevice, current_music->stream); SDL_BindAudioStream(sdlAudioDevice, current_music->stream);
} }
void JA_StopMusic() void JA_StopMusic() {
{
if (!JA_musicEnabled) if (!JA_musicEnabled)
return; return;
if (!current_music || current_music->state == JA_MUSIC_INVALID) if (!current_music || current_music->state == JA_MUSIC_INVALID)
@@ -259,8 +231,7 @@ void JA_StopMusic()
current_music->filename = nullptr; current_music->filename = nullptr;
} }
void JA_FadeOutMusic(const int milliseconds) void JA_FadeOutMusic(const int milliseconds) {
{
if (!JA_musicEnabled) if (!JA_musicEnabled)
return; return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) if (current_music == NULL || current_music->state == JA_MUSIC_INVALID)
@@ -272,8 +243,7 @@ void JA_FadeOutMusic(const int milliseconds)
fade_initial_volume = JA_musicVolume; fade_initial_volume = JA_musicVolume;
} }
JA_Music_state JA_GetMusicState() JA_Music_state JA_GetMusicState() {
{
if (!JA_musicEnabled) if (!JA_musicEnabled)
return JA_MUSIC_DISABLED; return JA_MUSIC_DISABLED;
if (!current_music) if (!current_music)
@@ -282,8 +252,7 @@ JA_Music_state JA_GetMusicState()
return current_music->state; return current_music->state;
} }
void JA_DeleteMusic(JA_Music_t *music) void JA_DeleteMusic(JA_Music_t *music) {
{
if (current_music == music) if (current_music == music)
current_music = nullptr; current_music = nullptr;
SDL_free(music->buffer); SDL_free(music->buffer);
@@ -292,68 +261,59 @@ void JA_DeleteMusic(JA_Music_t *music)
delete music; delete music;
} }
float JA_SetMusicVolume(float volume) float JA_SetMusicVolume(float volume) {
{
JA_musicVolume = SDL_clamp(volume, 0.0f, 1.0f); JA_musicVolume = SDL_clamp(volume, 0.0f, 1.0f);
if (current_music) if (current_music)
SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume); SDL_SetAudioStreamGain(current_music->stream, JA_musicVolume);
return JA_musicVolume; return JA_musicVolume;
} }
void JA_SetMusicPosition(float value) void JA_SetMusicPosition(float value) {
{
if (!current_music) if (!current_music)
return; return;
current_music->pos = value * current_music->spec.freq; current_music->pos = value * current_music->spec.freq;
} }
float JA_GetMusicPosition() float JA_GetMusicPosition() {
{
if (!current_music) if (!current_music)
return 0; return 0;
return float(current_music->pos) / float(current_music->spec.freq); return float(current_music->pos) / float(current_music->spec.freq);
} }
void JA_EnableMusic(const bool value) void JA_EnableMusic(const bool value) {
{
if (!value && current_music && (current_music->state == JA_MUSIC_PLAYING)) if (!value && current_music && (current_music->state == JA_MUSIC_PLAYING))
JA_StopMusic(); JA_StopMusic();
JA_musicEnabled = value; JA_musicEnabled = value;
} }
JA_Sound_t *JA_NewSound(Uint8 *buffer, Uint32 length) JA_Sound_t *JA_NewSound(Uint8 *buffer, Uint32 length) {
{
JA_Sound_t *sound = new JA_Sound_t(); JA_Sound_t *sound = new JA_Sound_t();
sound->buffer = buffer; sound->buffer = buffer;
sound->length = length; sound->length = length;
return sound; return sound;
} }
JA_Sound_t *JA_LoadSound(uint8_t *buffer, uint32_t size) JA_Sound_t *JA_LoadSound(uint8_t *buffer, uint32_t size) {
{
JA_Sound_t *sound = new JA_Sound_t(); JA_Sound_t *sound = new JA_Sound_t();
SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), 1, &sound->spec, &sound->buffer, &sound->length); SDL_LoadWAV_IO(SDL_IOFromMem(buffer, size), 1, &sound->spec, &sound->buffer, &sound->length);
return sound; return sound;
} }
JA_Sound_t *JA_LoadSound(const char *filename) JA_Sound_t *JA_LoadSound(const char *filename) {
{
JA_Sound_t *sound = new JA_Sound_t(); JA_Sound_t *sound = new JA_Sound_t();
SDL_LoadWAV(filename, &sound->spec, &sound->buffer, &sound->length); SDL_LoadWAV(filename, &sound->spec, &sound->buffer, &sound->length);
return sound; return sound;
} }
int JA_PlaySound(JA_Sound_t *sound, const int loop, const int group) int JA_PlaySound(JA_Sound_t *sound, const int loop, const int group) {
{
if (!JA_soundEnabled) if (!JA_soundEnabled)
return -1; return -1;
int channel = 0; int channel = 0;
while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) {
{
channel++; channel++;
} }
if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) if (channel == JA_MAX_SIMULTANEOUS_CHANNELS)
@@ -372,8 +332,7 @@ int JA_PlaySound(JA_Sound_t *sound, const int loop, const int group)
return channel; return channel;
} }
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop, const int group) int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop, const int group) {
{
if (!JA_soundEnabled) if (!JA_soundEnabled)
return -1; return -1;
@@ -393,10 +352,8 @@ int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop,
return channel; return channel;
} }
void JA_DeleteSound(JA_Sound_t *sound) void JA_DeleteSound(JA_Sound_t *sound) {
{ for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{
if (channels[i].sound == sound) if (channels[i].sound == sound)
JA_StopChannel(i); JA_StopChannel(i);
} }
@@ -404,25 +361,19 @@ void JA_DeleteSound(JA_Sound_t *sound)
delete sound; delete sound;
} }
void JA_PauseChannel(const int channel) void JA_PauseChannel(const int channel) {
{
if (!JA_soundEnabled) if (!JA_soundEnabled)
return; return;
if (channel == -1) if (channel == -1) {
{
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
if (channels[i].state == JA_CHANNEL_PLAYING) if (channels[i].state == JA_CHANNEL_PLAYING) {
{
channels[i].state = JA_CHANNEL_PAUSED; channels[i].state = JA_CHANNEL_PAUSED;
// SDL_PauseAudioStreamDevice(channels[i].stream); // SDL_PauseAudioStreamDevice(channels[i].stream);
SDL_UnbindAudioStream(channels[i].stream); SDL_UnbindAudioStream(channels[i].stream);
} }
} } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) if (channels[channel].state == JA_CHANNEL_PLAYING) {
{
if (channels[channel].state == JA_CHANNEL_PLAYING)
{
channels[channel].state = JA_CHANNEL_PAUSED; channels[channel].state = JA_CHANNEL_PAUSED;
// SDL_PauseAudioStreamDevice(channels[channel].stream); // SDL_PauseAudioStreamDevice(channels[channel].stream);
SDL_UnbindAudioStream(channels[channel].stream); SDL_UnbindAudioStream(channels[channel].stream);
@@ -430,25 +381,19 @@ void JA_PauseChannel(const int channel)
} }
} }
void JA_ResumeChannel(const int channel) void JA_ResumeChannel(const int channel) {
{
if (!JA_soundEnabled) if (!JA_soundEnabled)
return; return;
if (channel == -1) if (channel == -1) {
{
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
if (channels[i].state == JA_CHANNEL_PAUSED) if (channels[i].state == JA_CHANNEL_PAUSED) {
{
channels[i].state = JA_CHANNEL_PLAYING; channels[i].state = JA_CHANNEL_PLAYING;
// SDL_ResumeAudioStreamDevice(channels[i].stream); // SDL_ResumeAudioStreamDevice(channels[i].stream);
SDL_BindAudioStream(sdlAudioDevice, channels[i].stream); SDL_BindAudioStream(sdlAudioDevice, channels[i].stream);
} }
} } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) if (channels[channel].state == JA_CHANNEL_PAUSED) {
{
if (channels[channel].state == JA_CHANNEL_PAUSED)
{
channels[channel].state = JA_CHANNEL_PLAYING; channels[channel].state = JA_CHANNEL_PLAYING;
// SDL_ResumeAudioStreamDevice(channels[channel].stream); // SDL_ResumeAudioStreamDevice(channels[channel].stream);
SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream); SDL_BindAudioStream(sdlAudioDevice, channels[channel].stream);
@@ -456,15 +401,12 @@ void JA_ResumeChannel(const int channel)
} }
} }
void JA_StopChannel(const int channel) void JA_StopChannel(const int channel) {
{
if (!JA_soundEnabled) if (!JA_soundEnabled)
return; return;
if (channel == -1) if (channel == -1) {
{ for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{
if (channels[i].state != JA_CHANNEL_FREE) if (channels[i].state != JA_CHANNEL_FREE)
SDL_DestroyAudioStream(channels[i].stream); SDL_DestroyAudioStream(channels[i].stream);
channels[i].stream = nullptr; channels[i].stream = nullptr;
@@ -472,9 +414,7 @@ void JA_StopChannel(const int channel)
channels[i].pos = 0; channels[i].pos = 0;
channels[i].sound = NULL; channels[i].sound = NULL;
} }
} } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
{
if (channels[channel].state != JA_CHANNEL_FREE) if (channels[channel].state != JA_CHANNEL_FREE)
SDL_DestroyAudioStream(channels[channel].stream); SDL_DestroyAudioStream(channels[channel].stream);
channels[channel].stream = nullptr; channels[channel].stream = nullptr;
@@ -484,8 +424,7 @@ void JA_StopChannel(const int channel)
} }
} }
JA_Channel_state JA_GetChannelState(const int channel) JA_Channel_state JA_GetChannelState(const int channel) {
{
if (!JA_soundEnabled) if (!JA_soundEnabled)
return JA_SOUND_DISABLED; return JA_SOUND_DISABLED;
@@ -495,11 +434,9 @@ JA_Channel_state JA_GetChannelState(const int channel)
return channels[channel].state; return channels[channel].state;
} }
float JA_SetSoundVolume(float volume, const int group) float JA_SetSoundVolume(float volume, const int group) {
{
const float v = SDL_clamp(volume, 0.0f, 1.0f); const float v = SDL_clamp(volume, 0.0f, 1.0f);
for (int i = 0; i < JA_MAX_GROUPS; ++i) for (int i = 0; i < JA_MAX_GROUPS; ++i) {
{
if (group == -1 || group == i) if (group == -1 || group == i)
JA_soundVolume[i] = v; JA_soundVolume[i] = v;
} }
@@ -512,18 +449,15 @@ float JA_SetSoundVolume(float volume, const int group)
return v; return v;
} }
void JA_EnableSound(const bool value) void JA_EnableSound(const bool value) {
{ for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{
if (channels[i].state == JA_CHANNEL_PLAYING) if (channels[i].state == JA_CHANNEL_PLAYING)
JA_StopChannel(i); JA_StopChannel(i);
} }
JA_soundEnabled = value; JA_soundEnabled = value;
} }
float JA_SetVolume(float volume) float JA_SetVolume(float volume) {
{
JA_SetSoundVolume(JA_SetMusicVolume(volume) / 2.0f); JA_SetSoundVolume(JA_SetMusicVolume(volume) / 2.0f);
return JA_musicVolume; return JA_musicVolume;
+2 -4
View File
@@ -1,16 +1,14 @@
#pragma once #pragma once
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
enum JA_Channel_state enum JA_Channel_state {
{
JA_CHANNEL_INVALID, JA_CHANNEL_INVALID,
JA_CHANNEL_FREE, JA_CHANNEL_FREE,
JA_CHANNEL_PLAYING, JA_CHANNEL_PLAYING,
JA_CHANNEL_PAUSED, JA_CHANNEL_PAUSED,
JA_SOUND_DISABLED JA_SOUND_DISABLED
}; };
enum JA_Music_state enum JA_Music_state {
{
JA_MUSIC_INVALID, JA_MUSIC_INVALID,
JA_MUSIC_PLAYING, JA_MUSIC_PLAYING,
JA_MUSIC_PAUSED, JA_MUSIC_PAUSED,
+355 -400
View File
@@ -1,461 +1,416 @@
#include "jail_shader.h" #include "jail_shader.h"
#include <SDL3/SDL.h> // Para SDL_GL_GetProcAddress, SDL_LogError #include <SDL3/SDL.h> // Para SDL_GL_GetProcAddress, SDL_LogError
#include <stdint.h> // Para uintptr_t #include <stdint.h> // Para uintptr_t
#include <cstring> // Para strncmp #include <cstring> // Para strncmp
#include <stdexcept> // Para runtime_error #include <stdexcept> // Para runtime_error
#include <vector> // Para vector #include <vector> // Para vector
#ifdef __APPLE__ #ifdef __APPLE__
#include <OpenGL/OpenGL.h> // Para OpenGL en macOS #include <OpenGL/OpenGL.h> // Para OpenGL en macOS
#include "CoreFoundation/CoreFoundation.h" // Para Core Foundation en macOS #include "CoreFoundation/CoreFoundation.h" // Para Core Foundation en macOS
#if ESSENTIAL_GL_PRACTICES_SUPPORT_GL3 #if ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
#include <OpenGL/gl3.h> // Para OpenGL 3 en macOS #include <OpenGL/gl3.h> // Para OpenGL 3 en macOS
#else // NO ESSENTIAL_GL_PRACTICES_SUPPORT_GL3 #else // NO ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
#include <OpenGL/gl.h> // Para OpenGL (compatibilidad) en macOS #include <OpenGL/gl.h> // Para OpenGL (compatibilidad) en macOS
#endif // ESSENTIAL_GL_PRACTICES_SUPPORT_GL3 #endif // ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
#else // SI NO ES __APPLE__ #else // SI NO ES __APPLE__
#include <SDL3/SDL_opengl.h> // Para GLuint, GLint, glTexCoord2f, glVertex2f #include <SDL3/SDL_opengl.h> // Para GLuint, GLint, glTexCoord2f, glVertex2f
#endif // __APPLE__ #endif // __APPLE__
namespace shader namespace shader {
{ // Constantes
// Constantes const GLuint INVALID_SHADER_ID = 0;
const GLuint INVALID_SHADER_ID = 0; const GLuint INVALID_PROGRAM_ID = 0;
const GLuint INVALID_PROGRAM_ID = 0; const GLuint DEFAULT_TEXTURE_ID = 1;
const GLuint DEFAULT_TEXTURE_ID = 1;
// Variables globales // Variables globales
SDL_Window *win = nullptr; SDL_Window *win = nullptr;
SDL_Renderer *renderer = nullptr; SDL_Renderer *renderer = nullptr;
GLuint programId = 0; GLuint programId = 0;
SDL_Texture *backBuffer = nullptr; SDL_Texture *backBuffer = nullptr;
SDL_Point win_size = {320 * 4, 256 * 4}; SDL_Point win_size = {320 * 4, 256 * 4};
SDL_FPoint tex_size = {320, 256}; SDL_FPoint tex_size = {320, 256};
bool usingOpenGL = false; bool usingOpenGL = false;
#ifndef __APPLE__ #ifndef __APPLE__
// Declaración de funciones de extensión de OpenGL (evitando GLEW) // Declaración de funciones de extensión de OpenGL (evitando GLEW)
PFNGLCREATESHADERPROC glCreateShader; PFNGLCREATESHADERPROC glCreateShader;
PFNGLSHADERSOURCEPROC glShaderSource; PFNGLSHADERSOURCEPROC glShaderSource;
PFNGLCOMPILESHADERPROC glCompileShader; PFNGLCOMPILESHADERPROC glCompileShader;
PFNGLGETSHADERIVPROC glGetShaderiv; PFNGLGETSHADERIVPROC glGetShaderiv;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
PFNGLDELETESHADERPROC glDeleteShader; PFNGLDELETESHADERPROC glDeleteShader;
PFNGLATTACHSHADERPROC glAttachShader; PFNGLATTACHSHADERPROC glAttachShader;
PFNGLCREATEPROGRAMPROC glCreateProgram; PFNGLCREATEPROGRAMPROC glCreateProgram;
PFNGLLINKPROGRAMPROC glLinkProgram; PFNGLLINKPROGRAMPROC glLinkProgram;
PFNGLVALIDATEPROGRAMPROC glValidateProgram; PFNGLVALIDATEPROGRAMPROC glValidateProgram;
PFNGLGETPROGRAMIVPROC glGetProgramiv; PFNGLGETPROGRAMIVPROC glGetProgramiv;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
PFNGLUSEPROGRAMPROC glUseProgram; PFNGLUSEPROGRAMPROC glUseProgram;
PFNGLDELETEPROGRAMPROC glDeleteProgram; PFNGLDELETEPROGRAMPROC glDeleteProgram;
bool initGLExtensions() bool initGLExtensions() {
{ glCreateShader = (PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader");
glCreateShader = (PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader"); glShaderSource = (PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource");
glShaderSource = (PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource"); glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader");
glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader"); glGetShaderiv = (PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv");
glGetShaderiv = (PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv"); glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog");
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog"); glDeleteShader = (PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader");
glDeleteShader = (PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader"); glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader");
glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader"); glCreateProgram = (PFNGLCREATEPROGRAMPROC)SDL_GL_GetProcAddress("glCreateProgram");
glCreateProgram = (PFNGLCREATEPROGRAMPROC)SDL_GL_GetProcAddress("glCreateProgram"); glLinkProgram = (PFNGLLINKPROGRAMPROC)SDL_GL_GetProcAddress("glLinkProgram");
glLinkProgram = (PFNGLLINKPROGRAMPROC)SDL_GL_GetProcAddress("glLinkProgram"); glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)SDL_GL_GetProcAddress("glValidateProgram");
glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)SDL_GL_GetProcAddress("glValidateProgram"); glGetProgramiv = (PFNGLGETPROGRAMIVPROC)SDL_GL_GetProcAddress("glGetProgramiv");
glGetProgramiv = (PFNGLGETPROGRAMIVPROC)SDL_GL_GetProcAddress("glGetProgramiv"); glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)SDL_GL_GetProcAddress("glGetProgramInfoLog");
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)SDL_GL_GetProcAddress("glGetProgramInfoLog"); glUseProgram = (PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram");
glUseProgram = (PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram"); glDeleteProgram = (PFNGLDELETEPROGRAMPROC)SDL_GL_GetProcAddress("glDeleteProgram");
glDeleteProgram = (PFNGLDELETEPROGRAMPROC)SDL_GL_GetProcAddress("glDeleteProgram");
return glCreateShader && glShaderSource && glCompileShader && glGetShaderiv && return glCreateShader && glShaderSource && glCompileShader && glGetShaderiv &&
glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram && glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram &&
glLinkProgram && glValidateProgram && glGetProgramiv && glGetProgramInfoLog && glLinkProgram && glValidateProgram && glGetProgramiv && glGetProgramInfoLog &&
glUseProgram && glDeleteProgram; glUseProgram && glDeleteProgram;
} }
#endif #endif
// Función para verificar errores de OpenGL // Función para verificar errores de OpenGL
void checkGLError(const char *operation) void checkGLError(const char *operation) {
{ GLenum error = glGetError();
GLenum error = glGetError(); if (error != GL_NO_ERROR) {
if (error != GL_NO_ERROR) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
{ "Error OpenGL en %s: 0x%x",
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, operation,
"Error OpenGL en %s: 0x%x", operation, error); error);
} }
}
// Función para compilar un shader a partir de un std::string
GLuint compileShader(const std::string &source, GLuint shader_type) {
if (source.empty()) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR FATAL: El código fuente del shader está vacío.");
throw std::runtime_error("ERROR FATAL: El código fuente del shader está vacío.");
} }
// Función para compilar un shader a partir de un std::string // Crear identificador del shader
GLuint compileShader(const std::string &source, GLuint shader_type) GLuint shader_id = glCreateShader(shader_type);
{ if (shader_id == INVALID_SHADER_ID) {
if (source.empty()) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al crear el shader.");
{ checkGLError("glCreateShader");
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR FATAL: El código fuente del shader está vacío."); return INVALID_SHADER_ID;
throw std::runtime_error("ERROR FATAL: El código fuente del shader está vacío."); }
// Agregar una directiva según el tipo de shader
std::string directive = (shader_type == GL_VERTEX_SHADER)
? "#define VERTEX\n"
: "#define FRAGMENT\n";
const char *sources[2] = {directive.c_str(), source.c_str()};
// Especificar el código fuente del shader
glShaderSource(shader_id, 2, sources, nullptr);
checkGLError("glShaderSource");
// Compilar el shader
glCompileShader(shader_id);
checkGLError("glCompileShader");
// Verificar si la compilación fue exitosa
GLint compiled_ok = GL_FALSE;
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &compiled_ok);
if (compiled_ok != GL_TRUE) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error en la compilación del shader (%d)!", shader_id);
GLint log_length;
glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0) {
std::vector<GLchar> log(log_length);
glGetShaderInfoLog(shader_id, log_length, &log_length, log.data());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Registro de compilación del shader: %s", log.data());
} }
glDeleteShader(shader_id);
return INVALID_SHADER_ID;
}
return shader_id;
}
// Crear identificador del shader // Función para compilar un programa de shaders (vertex y fragment) a partir de std::string
GLuint shader_id = glCreateShader(shader_type); GLuint compileProgram(const std::string &vertex_shader_source, const std::string &fragment_shader_source) {
if (shader_id == INVALID_SHADER_ID) GLuint program_id = glCreateProgram();
{ if (program_id == INVALID_PROGRAM_ID) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al crear el shader."); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al crear el programa de shaders.");
checkGLError("glCreateShader"); checkGLError("glCreateProgram");
return INVALID_SHADER_ID; return INVALID_PROGRAM_ID;
} }
// Agregar una directiva según el tipo de shader // Si el fragment shader está vacío, reutilizamos el código del vertex shader
std::string directive = (shader_type == GL_VERTEX_SHADER) GLuint vertex_shader_id = compileShader(vertex_shader_source, GL_VERTEX_SHADER);
? "#define VERTEX\n" GLuint fragment_shader_id = compileShader(fragment_shader_source.empty() ? vertex_shader_source : fragment_shader_source, GL_FRAGMENT_SHADER);
: "#define FRAGMENT\n";
const char *sources[2] = {directive.c_str(), source.c_str()}; if (vertex_shader_id != INVALID_SHADER_ID && fragment_shader_id != INVALID_SHADER_ID) {
// Asociar los shaders al programa
glAttachShader(program_id, vertex_shader_id);
checkGLError("glAttachShader vertex");
glAttachShader(program_id, fragment_shader_id);
checkGLError("glAttachShader fragment");
// Especificar el código fuente del shader glLinkProgram(program_id);
glShaderSource(shader_id, 2, sources, nullptr); checkGLError("glLinkProgram");
checkGLError("glShaderSource");
// Compilar el shader // Verificar el estado del enlace
glCompileShader(shader_id); GLint isLinked = GL_FALSE;
checkGLError("glCompileShader"); glGetProgramiv(program_id, GL_LINK_STATUS, &isLinked);
if (isLinked == GL_FALSE) {
// Verificar si la compilación fue exitosa SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al enlazar el programa de shaders.");
GLint compiled_ok = GL_FALSE;
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &compiled_ok);
if (compiled_ok != GL_TRUE)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error en la compilación del shader (%d)!", shader_id);
GLint log_length; GLint log_length;
glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &log_length); glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0) if (log_length > 0) {
{ std::vector<char> log(log_length);
std::vector<GLchar> log(log_length); glGetProgramInfoLog(program_id, log_length, &log_length, log.data());
glGetShaderInfoLog(shader_id, log_length, &log_length, log.data()); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Registro de enlace del programa: %s", log.data());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Registro de compilación del shader: %s", log.data());
} }
glDeleteShader(shader_id);
return INVALID_SHADER_ID;
}
return shader_id;
}
// Función para compilar un programa de shaders (vertex y fragment) a partir de std::string
GLuint compileProgram(const std::string &vertex_shader_source, const std::string &fragment_shader_source)
{
GLuint program_id = glCreateProgram();
if (program_id == INVALID_PROGRAM_ID)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al crear el programa de shaders.");
checkGLError("glCreateProgram");
return INVALID_PROGRAM_ID;
}
// Si el fragment shader está vacío, reutilizamos el código del vertex shader
GLuint vertex_shader_id = compileShader(vertex_shader_source, GL_VERTEX_SHADER);
GLuint fragment_shader_id = compileShader(fragment_shader_source.empty() ? vertex_shader_source : fragment_shader_source, GL_FRAGMENT_SHADER);
if (vertex_shader_id != INVALID_SHADER_ID && fragment_shader_id != INVALID_SHADER_ID)
{
// Asociar los shaders al programa
glAttachShader(program_id, vertex_shader_id);
checkGLError("glAttachShader vertex");
glAttachShader(program_id, fragment_shader_id);
checkGLError("glAttachShader fragment");
glLinkProgram(program_id);
checkGLError("glLinkProgram");
// Verificar el estado del enlace
GLint isLinked = GL_FALSE;
glGetProgramiv(program_id, GL_LINK_STATUS, &isLinked);
if (isLinked == GL_FALSE)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al enlazar el programa de shaders.");
GLint log_length;
glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0)
{
std::vector<char> log(log_length);
glGetProgramInfoLog(program_id, log_length, &log_length, log.data());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Registro de enlace del programa: %s", log.data());
}
glDeleteProgram(program_id);
program_id = INVALID_PROGRAM_ID;
}
else
{
glValidateProgram(program_id);
checkGLError("glValidateProgram");
// Log de información del programa (solo si hay información)
GLint log_length;
glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 1) // > 1 porque algunos drivers devuelven 1 para cadena vacía
{
std::vector<char> log(log_length);
glGetProgramInfoLog(program_id, log_length, &log_length, log.data());
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Registro de información del programa:\n%s", log.data());
}
}
}
else
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudieron compilar los shaders.");
glDeleteProgram(program_id); glDeleteProgram(program_id);
program_id = INVALID_PROGRAM_ID; program_id = INVALID_PROGRAM_ID;
} } else {
glValidateProgram(program_id);
checkGLError("glValidateProgram");
// Limpiar los shaders (ya no son necesarios después del enlace) // Log de información del programa (solo si hay información)
if (vertex_shader_id != INVALID_SHADER_ID) GLint log_length;
{ glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &log_length);
glDeleteShader(vertex_shader_id); if (log_length > 1) // > 1 porque algunos drivers devuelven 1 para cadena vacía
{
std::vector<char> log(log_length);
glGetProgramInfoLog(program_id, log_length, &log_length, log.data());
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Registro de información del programa:\n%s", log.data());
}
} }
if (fragment_shader_id != INVALID_SHADER_ID) } else {
{ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudieron compilar los shaders.");
glDeleteShader(fragment_shader_id); glDeleteProgram(program_id);
} program_id = INVALID_PROGRAM_ID;
return program_id;
} }
// Función para obtener el ID de textura OpenGL desde SDL3 // Limpiar los shaders (ya no son necesarios después del enlace)
GLuint getTextureID(SDL_Texture *texture) if (vertex_shader_id != INVALID_SHADER_ID) {
{ glDeleteShader(vertex_shader_id);
if (!texture) }
return DEFAULT_TEXTURE_ID; if (fragment_shader_id != INVALID_SHADER_ID) {
glDeleteShader(fragment_shader_id);
// Intentar obtener el ID de textura OpenGL desde las propiedades de SDL3
SDL_PropertiesID props = SDL_GetTextureProperties(texture);
GLuint textureId = 0;
// Intentar diferentes nombres de propiedades según la versión de SDL3
textureId = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "SDL.texture.opengl.texture", nullptr);
// Si la primera no funciona, intentar con el nombre alternativo
if (textureId == 0)
{
textureId = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "texture.opengl.texture", nullptr);
}
// Si aún no funciona, intentar obtener como número
if (textureId == 0)
{
textureId = (GLuint)SDL_GetNumberProperty(props, "SDL.texture.opengl.texture", DEFAULT_TEXTURE_ID);
}
// Si ninguna funciona, usar el método manual de bindeo de textura
if (textureId == 0)
{
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"No se pudo obtener el ID de textura OpenGL, usando ID por defecto (%d)", DEFAULT_TEXTURE_ID);
textureId = DEFAULT_TEXTURE_ID;
}
return textureId;
} }
bool init(SDL_Window *window, SDL_Texture *back_buffer_texture, const std::string &vertex_shader, const std::string &fragment_shader) return program_id;
{ }
shader::win = window;
shader::renderer = SDL_GetRenderer(window);
shader::backBuffer = back_buffer_texture;
if (!shader::renderer) // Función para obtener el ID de textura OpenGL desde SDL3
{ GLuint getTextureID(SDL_Texture *texture) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo obtener el renderer de la ventana."); if (!texture)
return false; return DEFAULT_TEXTURE_ID;
}
SDL_GetWindowSize(window, &win_size.x, &win_size.y); // Intentar obtener el ID de textura OpenGL desde las propiedades de SDL3
SDL_GetTextureSize(back_buffer_texture, &tex_size.x, &tex_size.y); SDL_PropertiesID props = SDL_GetTextureProperties(texture);
GLuint textureId = 0;
const auto render_name = SDL_GetRendererName(renderer); // Intentar diferentes nombres de propiedades según la versión de SDL3
if (!render_name) textureId = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "SDL.texture.opengl.texture", nullptr);
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo obtener el nombre del renderer.");
return false;
}
// Verificar que el renderer sea OpenGL // Si la primera no funciona, intentar con el nombre alternativo
if (!strncmp(render_name, "opengl", 6)) if (textureId == 0) {
{ textureId = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "texture.opengl.texture", nullptr);
}
// Si aún no funciona, intentar obtener como número
if (textureId == 0) {
textureId = (GLuint)SDL_GetNumberProperty(props, "SDL.texture.opengl.texture", DEFAULT_TEXTURE_ID);
}
// Si ninguna funciona, usar el método manual de bindeo de textura
if (textureId == 0) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"No se pudo obtener el ID de textura OpenGL, usando ID por defecto (%d)",
DEFAULT_TEXTURE_ID);
textureId = DEFAULT_TEXTURE_ID;
}
return textureId;
}
bool init(SDL_Window *window, SDL_Texture *back_buffer_texture, const std::string &vertex_shader, const std::string &fragment_shader) {
shader::win = window;
shader::renderer = SDL_GetRenderer(window);
shader::backBuffer = back_buffer_texture;
if (!shader::renderer) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo obtener el renderer de la ventana.");
return false;
}
SDL_GetWindowSize(window, &win_size.x, &win_size.y);
SDL_GetTextureSize(back_buffer_texture, &tex_size.x, &tex_size.y);
const auto render_name = SDL_GetRendererName(renderer);
if (!render_name) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo obtener el nombre del renderer.");
return false;
}
// Verificar que el renderer sea OpenGL
if (!strncmp(render_name, "opengl", 6)) {
#ifndef __APPLE__ #ifndef __APPLE__
if (!initGLExtensions()) if (!initGLExtensions()) {
{ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR: No se han podido inicializar las extensiones de OpenGL.");
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR: No se han podido inicializar las extensiones de OpenGL.");
usingOpenGL = false;
return false;
}
#endif
// Compilar el programa de shaders utilizando std::string
programId = compileProgram(vertex_shader, fragment_shader);
if (programId == INVALID_PROGRAM_ID)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR: No se pudo compilar el programa de shaders.");
usingOpenGL = false;
return false;
}
}
else
{
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "ADVERTENCIA: El driver del renderer no es OpenGL (%s).", render_name);
usingOpenGL = false; usingOpenGL = false;
return false; return false;
} }
#endif
usingOpenGL = true; // Compilar el programa de shaders utilizando std::string
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Shader system initialized successfully."); programId = compileProgram(vertex_shader, fragment_shader);
return true; if (programId == INVALID_PROGRAM_ID) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR: No se pudo compilar el programa de shaders.");
usingOpenGL = false;
return false;
}
} else {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "ADVERTENCIA: El driver del renderer no es OpenGL (%s).", render_name);
usingOpenGL = false;
return false;
} }
void render() usingOpenGL = true;
{ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Shader system initialized successfully.");
// Establece el color de fondo return true;
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); }
SDL_SetRenderTarget(renderer, nullptr);
SDL_RenderClear(renderer);
if (usingOpenGL && programId != INVALID_PROGRAM_ID) void render() {
{ // Establece el color de fondo
// Guardar estados de OpenGL SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
GLint oldProgramId; SDL_SetRenderTarget(renderer, nullptr);
glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgramId); SDL_RenderClear(renderer);
GLint oldViewport[4]; if (usingOpenGL && programId != INVALID_PROGRAM_ID) {
glGetIntegerv(GL_VIEWPORT, oldViewport); // Guardar estados de OpenGL
GLint oldProgramId;
glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgramId);
GLboolean wasTextureEnabled = glIsEnabled(GL_TEXTURE_2D); GLint oldViewport[4];
GLint oldTextureId; glGetIntegerv(GL_VIEWPORT, oldViewport);
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTextureId);
// Obtener y bindear la textura GLboolean wasTextureEnabled = glIsEnabled(GL_TEXTURE_2D);
GLuint textureId = getTextureID(backBuffer); GLint oldTextureId;
glEnable(GL_TEXTURE_2D); glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTextureId);
glBindTexture(GL_TEXTURE_2D, textureId);
checkGLError("glBindTexture");
// Usar nuestro programa de shaders // Obtener y bindear la textura
glUseProgram(programId); GLuint textureId = getTextureID(backBuffer);
checkGLError("glUseProgram"); glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureId);
checkGLError("glBindTexture");
// Recupera el tamaño lógico configurado con SDL_RenderSetLogicalSize // Usar nuestro programa de shaders
int logicalW, logicalH; glUseProgram(programId);
SDL_RendererLogicalPresentation mode; checkGLError("glUseProgram");
SDL_GetRenderLogicalPresentation(renderer, &logicalW, &logicalH, &mode);
if (logicalW == 0 || logicalH == 0) // Recupera el tamaño lógico configurado con SDL_RenderSetLogicalSize
{ int logicalW, logicalH;
logicalW = win_size.x; SDL_RendererLogicalPresentation mode;
logicalH = win_size.y; SDL_GetRenderLogicalPresentation(renderer, &logicalW, &logicalH, &mode);
if (logicalW == 0 || logicalH == 0) {
logicalW = win_size.x;
logicalH = win_size.y;
}
// Cálculo del viewport
int viewportX = 0, viewportY = 0, viewportW = win_size.x, viewportH = win_size.y;
const bool USE_INTEGER_SCALE = mode == SDL_LOGICAL_PRESENTATION_INTEGER_SCALE;
if (USE_INTEGER_SCALE) {
// Calcula el factor de escalado entero máximo que se puede aplicar
int scaleX = win_size.x / logicalW;
int scaleY = win_size.y / logicalH;
int scale = (scaleX < scaleY ? scaleX : scaleY);
if (scale < 1) {
scale = 1;
} }
viewportW = logicalW * scale;
// Cálculo del viewport viewportH = logicalH * scale;
int viewportX = 0, viewportY = 0, viewportW = win_size.x, viewportH = win_size.y; viewportX = (win_size.x - viewportW) / 2;
const bool USE_INTEGER_SCALE = mode == SDL_LOGICAL_PRESENTATION_INTEGER_SCALE; viewportY = (win_size.y - viewportH) / 2;
if (USE_INTEGER_SCALE) } else {
{ // Letterboxing: preserva la relación de aspecto usando una escala flotante
// Calcula el factor de escalado entero máximo que se puede aplicar float windowAspect = static_cast<float>(win_size.x) / win_size.y;
int scaleX = win_size.x / logicalW; float logicalAspect = static_cast<float>(logicalW) / logicalH;
int scaleY = win_size.y / logicalH; if (windowAspect > logicalAspect) {
int scale = (scaleX < scaleY ? scaleX : scaleY); viewportW = static_cast<int>(logicalAspect * win_size.y);
if (scale < 1)
{
scale = 1;
}
viewportW = logicalW * scale;
viewportH = logicalH * scale;
viewportX = (win_size.x - viewportW) / 2; viewportX = (win_size.x - viewportW) / 2;
} else {
viewportH = static_cast<int>(win_size.x / logicalAspect);
viewportY = (win_size.y - viewportH) / 2; viewportY = (win_size.y - viewportH) / 2;
} }
else
{
// Letterboxing: preserva la relación de aspecto usando una escala flotante
float windowAspect = static_cast<float>(win_size.x) / win_size.y;
float logicalAspect = static_cast<float>(logicalW) / logicalH;
if (windowAspect > logicalAspect)
{
viewportW = static_cast<int>(logicalAspect * win_size.y);
viewportX = (win_size.x - viewportW) / 2;
}
else
{
viewportH = static_cast<int>(win_size.x / logicalAspect);
viewportY = (win_size.y - viewportH) / 2;
}
}
glViewport(viewportX, viewportY, viewportW, viewportH);
checkGLError("glViewport");
// Configurar la proyección ortográfica usando el espacio lógico
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Queremos que el origen esté en la esquina superior izquierda del espacio lógico.
glOrtho(0, static_cast<GLdouble>(logicalW), static_cast<GLdouble>(logicalH), 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Dibuja el quad con las coordenadas ajustadas.
// Se asignan las coordenadas de textura "normales" para que no quede espejado horizontalmente,
// y se mantiene el flip vertical para que la imagen no aparezca volteada.
glBegin(GL_TRIANGLE_STRIP);
// Vértice superior izquierdo
glTexCoord2f(0.0f, 1.0f);
glVertex2f(0.0f, 0.0f);
// Vértice superior derecho
glTexCoord2f(1.0f, 1.0f);
glVertex2f(static_cast<GLfloat>(logicalW), 0.0f);
// Vértice inferior izquierdo
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0.0f, static_cast<GLfloat>(logicalH));
// Vértice inferior derecho
glTexCoord2f(1.0f, 0.0f);
glVertex2f(static_cast<GLfloat>(logicalW), static_cast<GLfloat>(logicalH));
glEnd();
checkGLError("render quad");
SDL_GL_SwapWindow(win);
// Restaurar estados de OpenGL
glUseProgram(oldProgramId);
glBindTexture(GL_TEXTURE_2D, oldTextureId);
if (!wasTextureEnabled)
{
glDisable(GL_TEXTURE_2D);
}
glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
} }
else glViewport(viewportX, viewportY, viewportW, viewportH);
{ checkGLError("glViewport");
// Fallback a renderizado normal de SDL
SDL_RenderTexture(renderer, backBuffer, nullptr, nullptr); // Configurar la proyección ortográfica usando el espacio lógico
SDL_RenderPresent(renderer); glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Queremos que el origen esté en la esquina superior izquierda del espacio lógico.
glOrtho(0, static_cast<GLdouble>(logicalW), static_cast<GLdouble>(logicalH), 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Dibuja el quad con las coordenadas ajustadas.
// Se asignan las coordenadas de textura "normales" para que no quede espejado horizontalmente,
// y se mantiene el flip vertical para que la imagen no aparezca volteada.
glBegin(GL_TRIANGLE_STRIP);
// Vértice superior izquierdo
glTexCoord2f(0.0f, 1.0f);
glVertex2f(0.0f, 0.0f);
// Vértice superior derecho
glTexCoord2f(1.0f, 1.0f);
glVertex2f(static_cast<GLfloat>(logicalW), 0.0f);
// Vértice inferior izquierdo
glTexCoord2f(0.0f, 0.0f);
glVertex2f(0.0f, static_cast<GLfloat>(logicalH));
// Vértice inferior derecho
glTexCoord2f(1.0f, 0.0f);
glVertex2f(static_cast<GLfloat>(logicalW), static_cast<GLfloat>(logicalH));
glEnd();
checkGLError("render quad");
SDL_GL_SwapWindow(win);
// Restaurar estados de OpenGL
glUseProgram(oldProgramId);
glBindTexture(GL_TEXTURE_2D, oldTextureId);
if (!wasTextureEnabled) {
glDisable(GL_TEXTURE_2D);
} }
glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
} else {
// Fallback a renderizado normal de SDL
SDL_RenderTexture(renderer, backBuffer, nullptr, nullptr);
SDL_RenderPresent(renderer);
}
}
void cleanup() {
if (programId != INVALID_PROGRAM_ID) {
glDeleteProgram(programId);
programId = INVALID_PROGRAM_ID;
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Programa de shaders liberado.");
} }
void cleanup() // Reinicializar variables
{ win = nullptr;
if (programId != INVALID_PROGRAM_ID) renderer = nullptr;
{ backBuffer = nullptr;
glDeleteProgram(programId); usingOpenGL = false;
programId = INVALID_PROGRAM_ID; }
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Programa de shaders liberado.");
}
// Reinicializar variables bool isUsingOpenGL() {
win = nullptr; return usingOpenGL;
renderer = nullptr; }
backBuffer = nullptr;
usingOpenGL = false;
}
bool isUsingOpenGL() GLuint getProgramId() {
{ return programId;
return usingOpenGL; }
} } // namespace shader
GLuint getProgramId()
{
return programId;
}
}
+7 -7
View File
@@ -1,10 +1,10 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_Texture, SDL_Window #include <SDL3/SDL.h> // Para SDL_Texture, SDL_Window
#include <string> // Para basic_string, string
namespace shader #include <string> // Para basic_string, string
{
bool init(SDL_Window *ventana, SDL_Texture *texturaBackBuffer, const std::string &vertexShader, const std::string &fragmentShader = ""); namespace shader {
void render(); bool init(SDL_Window *ventana, SDL_Texture *texturaBackBuffer, const std::string &vertexShader, const std::string &fragmentShader = "");
} void render();
} // namespace shader
+5915 -6851
View File
File diff suppressed because it is too large. Load diff
+4088 -4709
View File
File diff suppressed because it is too large. Load diff
+243 -292
View File
@@ -1,374 +1,325 @@
#include "fade.h" #include "fade.h"
#include <SDL3/SDL.h> // Para SDL_SetRenderTarget, SDL_FRect, SDL_GetRenderT... #include <SDL3/SDL.h> // Para SDL_SetRenderTarget, SDL_FRect, SDL_GetRenderT...
#include <stdlib.h> // Para rand, size_t #include <stdlib.h> // Para rand, size_t
#include <algorithm> // Para min, max #include <algorithm> // Para min, max
#include "param.h" // Para Param, param, ParamGame, ParamFade #include "param.h" // Para Param, param, ParamGame, ParamFade
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "utils.h" // Para Color #include "utils.h" // Para Color
// Constructor // Constructor
Fade::Fade() Fade::Fade()
: renderer_(Screen::get()->getRenderer()) : renderer_(Screen::get()->getRenderer()) {
{ // Crea la textura donde dibujar el fade
// Crea la textura donde dibujar el fade backbuffer_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);
backbuffer_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height); SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
// Inicializa las variables // Inicializa las variables
init(); init();
} }
// Destructor // Destructor
Fade::~Fade() Fade::~Fade() {
{ SDL_DestroyTexture(backbuffer_);
SDL_DestroyTexture(backbuffer_);
} }
// Inicializa las variables // Inicializa las variables
void Fade::init() void Fade::init() {
{ type_ = FadeType::CENTER;
type_ = FadeType::CENTER; mode_ = FadeMode::OUT;
mode_ = FadeMode::OUT; counter_ = 0;
counter_ = 0; r_ = 0;
r_ = 0; g_ = 0;
g_ = 0; b_ = 0;
b_ = 0; a_ = 0;
a_ = 0; post_duration_ = 0;
post_duration_ = 0; post_counter_ = 0;
post_counter_ = 0; pre_duration_ = 0;
pre_duration_ = 0; pre_counter_ = 0;
pre_counter_ = 0; num_squares_width_ = param.fade.num_squares_width;
num_squares_width_ = param.fade.num_squares_width; num_squares_height_ = param.fade.num_squares_height;
num_squares_height_ = param.fade.num_squares_height; fade_random_squares_delay_ = param.fade.random_squares_delay;
fade_random_squares_delay_ = param.fade.random_squares_delay; fade_random_squares_mult_ = param.fade.random_squares_mult;
fade_random_squares_mult_ = param.fade.random_squares_mult;
} }
// Resetea algunas variables para volver a hacer el fade sin perder ciertos parametros // Resetea algunas variables para volver a hacer el fade sin perder ciertos parametros
void Fade::reset() void Fade::reset() {
{ state_ = FadeState::NOT_ENABLED;
state_ = FadeState::NOT_ENABLED; counter_ = 0;
counter_ = 0;
} }
// Pinta una transición en pantalla // Pinta una transición en pantalla
void Fade::render() void Fade::render() {
{ if (state_ != FadeState::NOT_ENABLED) {
if (state_ != FadeState::NOT_ENABLED) SDL_RenderTexture(renderer_, backbuffer_, nullptr, nullptr);
{ }
SDL_RenderTexture(renderer_, backbuffer_, nullptr, nullptr);
}
} }
// Actualiza las variables internas // Actualiza las variables internas
void Fade::update() void Fade::update() {
{ if (state_ == FadeState::PRE) {
if (state_ == FadeState::PRE) // Actualiza el contador
{ if (pre_counter_ == pre_duration_) {
// Actualiza el contador state_ = FadeState::FADING;
if (pre_counter_ == pre_duration_) } else {
{ pre_counter_++;
state_ = FadeState::FADING; }
} }
else
{
pre_counter_++;
}
}
if (state_ == FadeState::FADING) if (state_ == FadeState::FADING) {
{ switch (type_) {
switch (type_) case FadeType::FULLSCREEN: {
{ // Modifica la transparencia
case FadeType::FULLSCREEN: a_ = mode_ == FadeMode::OUT ? std::min(counter_ * 4, 255) : 255 - std::min(counter_ * 4, 255);
{
// Modifica la transparencia
a_ = mode_ == FadeMode::OUT ? std::min(counter_ * 4, 255) : 255 - std::min(counter_ * 4, 255);
SDL_SetTextureAlphaMod(backbuffer_, a_); SDL_SetTextureAlphaMod(backbuffer_, a_);
// Comprueba si ha terminado // Comprueba si ha terminado
if (counter_ >= 255 / 4) if (counter_ >= 255 / 4) {
{ state_ = FadeState::POST;
state_ = FadeState::POST; }
}
break; break;
} }
case FadeType::CENTER: case FadeType::CENTER: {
{ // Dibuja sobre el backbuffer_
// Dibuja sobre el backbuffer_ auto temp = SDL_GetRenderTarget(renderer_);
auto temp = SDL_GetRenderTarget(renderer_); SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_); SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
for (int i = 0; i < counter_; i++) for (int i = 0; i < counter_; i++) {
{ rect1_.h = rect2_.h = i * 4;
rect1_.h = rect2_.h = i * 4; rect2_.y = param.game.height - (i * 4);
rect2_.y = param.game.height - (i * 4);
SDL_RenderFillRect(renderer_, &rect1_); SDL_RenderFillRect(renderer_, &rect1_);
SDL_RenderFillRect(renderer_, &rect2_); SDL_RenderFillRect(renderer_, &rect2_);
value_ = calculateValue(0, counter_, i); value_ = calculateValue(0, counter_, i);
} }
// Deja el renderizador como estaba // Deja el renderizador como estaba
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
// Comprueba si ha terminado // Comprueba si ha terminado
if ((counter_ * 4) > param.game.height) if ((counter_ * 4) > param.game.height) {
{ state_ = FadeState::POST;
state_ = FadeState::POST; a_ = 255;
a_ = 255; }
} break;
break; }
}
case FadeType::RANDOM_SQUARE: case FadeType::RANDOM_SQUARE: {
{ if (counter_ % fade_random_squares_delay_ == 0) {
if (counter_ % fade_random_squares_delay_ == 0) // Cambia el renderizador al backbuffer_ y modifica sus opciones
{ auto temp = SDL_GetRenderTarget(renderer_);
// Cambia el renderizador al backbuffer_ y modifica sus opciones SDL_SetRenderTarget(renderer_, backbuffer_);
auto temp = SDL_GetRenderTarget(renderer_); SDL_BlendMode blend_mode;
SDL_SetRenderTarget(renderer_, backbuffer_); SDL_GetRenderDrawBlendMode(renderer_, &blend_mode);
SDL_BlendMode blend_mode; SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE);
SDL_GetRenderDrawBlendMode(renderer_, &blend_mode); SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
// Dibuja el cuadrado correspondiente // Dibuja el cuadrado correspondiente
const int INDEX = std::min(counter_ / fade_random_squares_delay_, (num_squares_width_ * num_squares_height_) - 1); const int INDEX = std::min(counter_ / fade_random_squares_delay_, (num_squares_width_ * num_squares_height_) - 1);
for (int i = 0; i < fade_random_squares_mult_; ++i) for (int i = 0; i < fade_random_squares_mult_; ++i) {
{ const int INDEX2 = std::min(INDEX * fade_random_squares_mult_ + i, (int)square_.size() - 1);
const int INDEX2 = std::min(INDEX * fade_random_squares_mult_ + i, (int)square_.size() - 1); SDL_RenderFillRect(renderer_, &square_[INDEX2]);
SDL_RenderFillRect(renderer_, &square_[INDEX2]); }
}
// Deja el renderizador como estaba // Deja el renderizador como estaba
SDL_SetRenderDrawBlendMode(renderer_, blend_mode); SDL_SetRenderDrawBlendMode(renderer_, blend_mode);
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
} }
value_ = calculateValue(0, static_cast<int>(num_squares_width_ * num_squares_height_), static_cast<int>(counter_ * fade_random_squares_mult_ / fade_random_squares_delay_)); value_ = calculateValue(0, static_cast<int>(num_squares_width_ * num_squares_height_), static_cast<int>(counter_ * fade_random_squares_mult_ / fade_random_squares_delay_));
// Comprueba si ha terminado // Comprueba si ha terminado
if (counter_ * fade_random_squares_mult_ / fade_random_squares_delay_ >= num_squares_width_ * num_squares_height_) if (counter_ * fade_random_squares_mult_ / fade_random_squares_delay_ >= num_squares_width_ * num_squares_height_) {
{ state_ = FadeState::POST;
state_ = FadeState::POST; }
}
break; break;
} }
case FadeType::VENETIAN: case FadeType::VENETIAN: {
{ // Counter debe ir de 0 a 150 <-- comprobar si esto es aún cierto
// Counter debe ir de 0 a 150 <-- comprobar si esto es aún cierto if (square_.back().h < param.fade.venetian_size) {
if (square_.back().h < param.fade.venetian_size) // Dibuja sobre el backbuffer_
{ auto temp = SDL_GetRenderTarget(renderer_);
// Dibuja sobre el backbuffer_ SDL_SetRenderTarget(renderer_, backbuffer_);
auto temp = SDL_GetRenderTarget(renderer_); SDL_BlendMode blend_mode;
SDL_SetRenderTarget(renderer_, backbuffer_); SDL_GetRenderDrawBlendMode(renderer_, &blend_mode);
SDL_BlendMode blend_mode; SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE);
SDL_GetRenderDrawBlendMode(renderer_, &blend_mode); SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
// Dibuja el cuadrado correspondiente // Dibuja el cuadrado correspondiente
for (const auto rect : square_) for (const auto rect : square_) {
{ SDL_RenderFillRect(renderer_, &rect);
SDL_RenderFillRect(renderer_, &rect); }
}
// Deja el renderizador como estaba // Deja el renderizador como estaba
SDL_SetRenderDrawBlendMode(renderer_, blend_mode); SDL_SetRenderDrawBlendMode(renderer_, blend_mode);
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
// Modifica el tamaño de los rectangulos // Modifica el tamaño de los rectangulos
const auto h = counter_ / 2; const auto h = counter_ / 2;
for (size_t i = 0; i < square_.size(); ++i) for (size_t i = 0; i < square_.size(); ++i) {
{ // A partir del segundo rectangulo se pinta en función del anterior
// A partir del segundo rectangulo se pinta en función del anterior square_.at(i).h = i == 0 ? h : std::max(static_cast<int>(square_.at(i - 1).h) - 2, 0);
square_.at(i).h = i == 0 ? h : std::max(static_cast<int>(square_.at(i - 1).h) - 2, 0); }
}
int completed = 0; int completed = 0;
for (const auto &square : square_) for (const auto &square : square_) {
{ if (square.h >= param.fade.venetian_size) {
if (square.h >= param.fade.venetian_size) ++completed;
{ }
++completed; }
} value_ = calculateValue(0, square_.size() - 1, completed);
} } else {
value_ = calculateValue(0, square_.size() - 1, completed); state_ = FadeState::POST;
} }
else
{
state_ = FadeState::POST;
}
break; break;
} }
default: default:
break; break;
} }
counter_++; counter_++;
} }
if (state_ == FadeState::POST) if (state_ == FadeState::POST) {
{ // Actualiza el contador
// Actualiza el contador if (post_counter_ == post_duration_) {
if (post_counter_ == post_duration_) state_ = FadeState::FINISHED;
{ } else {
state_ = FadeState::FINISHED; post_counter_++;
} }
else
{
post_counter_++;
}
// Deja el backbuffer_ todo del mismo color // Deja el backbuffer_ todo del mismo color
cleanBackbuffer(r_, g_, b_, a_); cleanBackbuffer(r_, g_, b_, a_);
} }
} }
// Activa el fade // Activa el fade
void Fade::activate() void Fade::activate() {
{ // Si ya está habilitado, no hay que volverlo a activar
// Si ya está habilitado, no hay que volverlo a activar if (state_ != FadeState::NOT_ENABLED) {
if (state_ != FadeState::NOT_ENABLED) return;
{ }
return;
}
state_ = FadeState::PRE; state_ = FadeState::PRE;
counter_ = 0; counter_ = 0;
post_counter_ = 0; post_counter_ = 0;
pre_counter_ = 0; pre_counter_ = 0;
switch (type_) switch (type_) {
{ case FadeType::FULLSCREEN: {
case FadeType::FULLSCREEN: // Pinta el backbuffer_ de color sólido
{ cleanBackbuffer(r_, g_, b_, 255);
// Pinta el backbuffer_ de color sólido break;
cleanBackbuffer(r_, g_, b_, 255); }
break;
}
case FadeType::CENTER: case FadeType::CENTER: {
{ rect1_ = {0, 0, static_cast<float>(param.game.width), 0};
rect1_ = {0, 0, static_cast<float>(param.game.width), 0}; rect2_ = {0, 0, static_cast<float>(param.game.width), 0};
rect2_ = {0, 0, static_cast<float>(param.game.width), 0}; a_ = 64;
a_ = 64; break;
break; }
}
case FadeType::RANDOM_SQUARE: case FadeType::RANDOM_SQUARE: {
{ rect1_ = {0, 0, static_cast<float>(param.game.width / num_squares_width_), static_cast<float>(param.game.height / num_squares_height_)};
rect1_ = {0, 0, static_cast<float>(param.game.width / num_squares_width_), static_cast<float>(param.game.height / num_squares_height_)}; square_.clear();
square_.clear();
// Añade los cuadrados al vector // Añade los cuadrados al vector
for (int i = 0; i < num_squares_width_ * num_squares_height_; ++i) for (int i = 0; i < num_squares_width_ * num_squares_height_; ++i) {
{ rect1_.x = (i % num_squares_width_) * rect1_.w;
rect1_.x = (i % num_squares_width_) * rect1_.w; rect1_.y = (i / num_squares_width_) * rect1_.h;
rect1_.y = (i / num_squares_width_) * rect1_.h; square_.push_back(rect1_);
square_.push_back(rect1_); }
}
// Desordena el vector de cuadrados // Desordena el vector de cuadrados
auto num = num_squares_width_ * num_squares_height_; auto num = num_squares_width_ * num_squares_height_;
while (num > 1) while (num > 1) {
{ auto num_arreu = rand() % num;
auto num_arreu = rand() % num; SDL_FRect temp = square_[num_arreu];
SDL_FRect temp = square_[num_arreu]; square_[num_arreu] = square_[num - 1];
square_[num_arreu] = square_[num - 1]; square_[num - 1] = temp;
square_[num - 1] = temp; num--;
num--; }
}
// Limpia la textura // Limpia la textura
a_ = mode_ == FadeMode::OUT ? 0 : 255; a_ = mode_ == FadeMode::OUT ? 0 : 255;
cleanBackbuffer(r_, g_, b_, a_); cleanBackbuffer(r_, g_, b_, a_);
// Deja el color listo para usar // Deja el color listo para usar
a_ = mode_ == FadeMode::OUT ? 255 : 0; a_ = mode_ == FadeMode::OUT ? 255 : 0;
break; break;
} }
case FadeType::VENETIAN: case FadeType::VENETIAN: {
{ // Limpia la textura
// Limpia la textura a_ = mode_ == FadeMode::OUT ? 0 : 255;
a_ = mode_ == FadeMode::OUT ? 0 : 255; cleanBackbuffer(r_, g_, b_, a_);
cleanBackbuffer(r_, g_, b_, a_);
// Deja el color listo para usar // Deja el color listo para usar
a_ = mode_ == FadeMode::OUT ? 255 : 0; a_ = mode_ == FadeMode::OUT ? 255 : 0;
// Añade los cuadrados al vector // Añade los cuadrados al vector
square_.clear(); square_.clear();
rect1_ = {0, 0, static_cast<float>(param.game.width), 0}; rect1_ = {0, 0, static_cast<float>(param.game.width), 0};
const int MAX = param.game.height / param.fade.venetian_size; const int MAX = param.game.height / param.fade.venetian_size;
for (int i = 0; i < MAX; ++i) for (int i = 0; i < MAX; ++i) {
{ rect1_.y = i * param.fade.venetian_size;
rect1_.y = i * param.fade.venetian_size; square_.push_back(rect1_);
square_.push_back(rect1_); }
}
break; break;
} }
} }
} }
// Establece el color del fade // Establece el color del fade
void Fade::setColor(Uint8 r, Uint8 g, Uint8 b) void Fade::setColor(Uint8 r, Uint8 g, Uint8 b) {
{ r_ = r;
r_ = r; g_ = g;
g_ = g; b_ = b;
b_ = b;
} }
// Establece el color del fade // Establece el color del fade
void Fade::setColor(Color color) void Fade::setColor(Color color) {
{ r_ = color.r;
r_ = color.r; g_ = color.g;
g_ = color.g; b_ = color.b;
b_ = color.b;
} }
// Limpia el backbuffer // Limpia el backbuffer
void Fade::cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a) void Fade::cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
{ // Dibujamos sobre el backbuffer_
// Dibujamos sobre el backbuffer_ auto temp = SDL_GetRenderTarget(renderer_);
auto temp = SDL_GetRenderTarget(renderer_); SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_SetRenderTarget(renderer_, backbuffer_);
// Pintamos la textura con el color del fade // Pintamos la textura con el color del fade
SDL_SetRenderDrawColor(renderer_, r, g, b, a); SDL_SetRenderDrawColor(renderer_, r, g, b, a);
SDL_RenderClear(renderer_); SDL_RenderClear(renderer_);
// Vuelve a dejar el renderizador como estaba // Vuelve a dejar el renderizador como estaba
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
} }
// Calcula el valor del estado del fade // Calcula el valor del estado del fade
int Fade::calculateValue(int min, int max, int current) int Fade::calculateValue(int min, int max, int current) {
{ if (current < min) {
if (current < min) return 0;
{ }
return 0;
}
if (current > max) if (current > max) {
{ return 100;
return 100; }
}
return static_cast<int>(100.0 * (current - min) / (max - min)); return static_cast<int>(100.0 * (current - min) / (max - min));
} }
+65 -68
View File
@@ -1,93 +1,90 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para Uint8, SDL_FRect, SDL_Renderer, SDL_Texture, Uint16 #include <SDL3/SDL.h> // Para Uint8, SDL_FRect, SDL_Renderer, SDL_Texture, Uint16
#include <vector> // Para vector
#include <vector> // Para vector
struct Color; struct Color;
// Tipos de fundido // Tipos de fundido
enum class FadeType : Uint8 enum class FadeType : Uint8 {
{ FULLSCREEN = 0,
FULLSCREEN = 0, CENTER = 1,
CENTER = 1, RANDOM_SQUARE = 2,
RANDOM_SQUARE = 2, VENETIAN = 3,
VENETIAN = 3,
}; };
// Modos de fundido // Modos de fundido
enum class FadeMode : Uint8 enum class FadeMode : Uint8 {
{ IN = 0,
IN = 0, OUT = 1,
OUT = 1,
}; };
// Estados del objeto // Estados del objeto
enum class FadeState : Uint8 enum class FadeState : Uint8 {
{ NOT_ENABLED = 0,
NOT_ENABLED = 0, PRE = 1,
PRE = 1, FADING = 2,
FADING = 2, POST = 3,
POST = 3, FINISHED = 4,
FINISHED = 4,
}; };
class Fade class Fade {
{ public:
public: // --- Constructores y destructor ---
// --- Constructores y destructor --- Fade();
Fade(); ~Fade();
~Fade();
// --- Métodos principales --- // --- Métodos principales ---
void reset(); // Resetea variables para reutilizar el fade void reset(); // Resetea variables para reutilizar el fade
void render(); // Dibuja la transición en pantalla void render(); // Dibuja la transición en pantalla
void update(); // Actualiza el estado interno void update(); // Actualiza el estado interno
void activate(); // Activa el fade void activate(); // Activa el fade
// --- Configuración --- // --- Configuración ---
void setColor(Uint8 r, Uint8 g, Uint8 b); void setColor(Uint8 r, Uint8 g, Uint8 b);
void setColor(Color color); void setColor(Color color);
void setType(FadeType type) { type_ = type; } void setType(FadeType type) { type_ = type; }
void setMode(FadeMode mode) { mode_ = mode; } void setMode(FadeMode mode) { mode_ = mode; }
void setPostDuration(int value) { post_duration_ = value; } void setPostDuration(int value) { post_duration_ = value; }
void setPreDuration(int value) { pre_duration_ = value; } void setPreDuration(int value) { pre_duration_ = value; }
// --- Getters --- // --- Getters ---
int getValue() const { return value_; } int getValue() const { return value_; }
bool isEnabled() const { return state_ != FadeState::NOT_ENABLED; } bool isEnabled() const { return state_ != FadeState::NOT_ENABLED; }
bool hasEnded() const { return state_ == FadeState::FINISHED; } bool hasEnded() const { return state_ == FadeState::FINISHED; }
private: private:
// --- Objetos y punteros --- // --- Objetos y punteros ---
SDL_Renderer *renderer_; // Renderizador de la ventana SDL_Renderer *renderer_; // Renderizador de la ventana
SDL_Texture *backbuffer_; // Backbuffer para efectos SDL_Texture *backbuffer_; // Backbuffer para efectos
// --- Variables de estado --- // --- Variables de estado ---
FadeType type_; // Tipo de fade FadeType type_; // Tipo de fade
FadeMode mode_; // Modo de fade FadeMode mode_; // Modo de fade
FadeState state_ = FadeState::NOT_ENABLED; // Estado actual FadeState state_ = FadeState::NOT_ENABLED; // Estado actual
Uint16 counter_; // Contador interno Uint16 counter_; // Contador interno
// --- Parámetros de color y geometría --- // --- Parámetros de color y geometría ---
Uint8 r_, g_, b_, a_; // Color del fade Uint8 r_, g_, b_, a_; // Color del fade
SDL_FRect rect1_, rect2_; // Rectángulos para efectos SDL_FRect rect1_, rect2_; // Rectángulos para efectos
// --- Parámetros para RANDOM_SQUARE --- // --- Parámetros para RANDOM_SQUARE ---
int num_squares_width_; // Cuadrados en horizontal int num_squares_width_; // Cuadrados en horizontal
int num_squares_height_; // Cuadrados en vertical int num_squares_height_; // Cuadrados en vertical
std::vector<SDL_FRect> square_; // Vector de cuadrados std::vector<SDL_FRect> square_; // Vector de cuadrados
int fade_random_squares_delay_; // Delay entre cuadrados int fade_random_squares_delay_; // Delay entre cuadrados
int fade_random_squares_mult_; // Cuadrados por paso int fade_random_squares_mult_; // Cuadrados por paso
// --- Temporizadores --- // --- Temporizadores ---
int post_duration_ = 0, post_counter_ = 0; int post_duration_ = 0, post_counter_ = 0;
int pre_duration_ = 0, pre_counter_ = 0; int pre_duration_ = 0, pre_counter_ = 0;
// --- Valor de progreso --- // --- Valor de progreso ---
int value_ = 0; // Estado del fade (0-100) int value_ = 0; // Estado del fade (0-100)
// --- Métodos internos --- // --- Métodos internos ---
void init(); // Inicializa variables void init(); // Inicializa variables
void cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a); // Limpia el backbuffer void cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a); // Limpia el backbuffer
int calculateValue(int min, int max, int current); // Calcula el valor del fade int calculateValue(int min, int max, int current); // Calcula el valor del fade
}; };
+96 -124
View File
@@ -1,18 +1,19 @@
#include "game_logo.h" #include "game_logo.h"
#include <SDL3/SDL.h> // Para SDL_SetTextureScaleMode, SDL_FlipMode #include <SDL3/SDL.h> // Para SDL_SetTextureScaleMode, SDL_FlipMode
#include <algorithm> // Para max #include <algorithm> // Para max
#include <string> // Para basic_string #include <string> // Para basic_string
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
#include "audio.h" // Para Audio #include "audio.h" // Para Audio
#include "param.h" // Para Param, param, ParamGame, ParamTitle #include "param.h" // Para Param, param, ParamGame, ParamTitle
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "smart_sprite.h" // Para SmartSprite #include "smart_sprite.h" // Para SmartSprite
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "utils.h" // Para Color #include "utils.h" // Para Color
constexpr int ZOOM_FACTOR = 5; constexpr int ZOOM_FACTOR = 5;
constexpr int FLASH_DELAY = 3; constexpr int FLASH_DELAY = 3;
@@ -33,8 +34,7 @@ GameLogo::GameLogo(int x, int y)
y_(y) {} y_(y) {}
// Inicializa las variables // Inicializa las variables
void GameLogo::init() void GameLogo::init() {
{
const auto xp = x_ - coffee_texture_->getWidth() / 2; const auto xp = x_ - coffee_texture_->getWidth() / 2;
const auto desp = getInitialVerticalDesp(); const auto desp = getInitialVerticalDesp();
@@ -97,14 +97,12 @@ void GameLogo::init()
} }
// Pinta la clase en pantalla // Pinta la clase en pantalla
void GameLogo::render() void GameLogo::render() {
{
// Dibuja el logo // Dibuja el logo
coffee_sprite_->render(); coffee_sprite_->render();
crisis_sprite_->render(); crisis_sprite_->render();
if (arcade_edition_status_ != Status::DISABLED) if (arcade_edition_status_ != Status::DISABLED) {
{
arcade_edition_sprite_->render(); arcade_edition_sprite_->render();
} }
@@ -114,145 +112,119 @@ void GameLogo::render()
} }
// Actualiza la lógica de la clase // Actualiza la lógica de la clase
void GameLogo::update() void GameLogo::update() {
{ switch (coffee_crisis_status_) {
switch (coffee_crisis_status_) case Status::MOVING: {
{ coffee_sprite_->update();
case Status::MOVING: crisis_sprite_->update();
{
coffee_sprite_->update();
crisis_sprite_->update();
// Si los objetos han llegado a su destino, cambia el estado // Si los objetos han llegado a su destino, cambia el estado
if (coffee_sprite_->hasFinished() && crisis_sprite_->hasFinished()) if (coffee_sprite_->hasFinished() && crisis_sprite_->hasFinished()) {
{ coffee_crisis_status_ = Status::SHAKING;
coffee_crisis_status_ = Status::SHAKING;
// Reproduce el efecto sonoro // Reproduce el efecto sonoro
Audio::get()->playSound("title.wav"); Audio::get()->playSound("title.wav");
Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGHT, FLASH_DELAY); Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGHT, FLASH_DELAY);
Screen::get()->shake(); Screen::get()->shake();
}
break;
}
case Status::SHAKING:
{
// Agita "COFFEE CRISIS"
if (shake_.remaining > 0)
{
if (shake_.counter > 0)
{
shake_.counter--;
} }
else
{ break;
shake_.counter = shake_.delay; }
const auto desp = shake_.remaining % 2 == 0 ? shake_.desp * (-1) : shake_.desp;
coffee_sprite_->setPosX(shake_.origin + desp); case Status::SHAKING: {
crisis_sprite_->setPosX(shake_.origin + desp + 15); // Agita "COFFEE CRISIS"
shake_.remaining--; if (shake_.remaining > 0) {
if (shake_.counter > 0) {
shake_.counter--;
} else {
shake_.counter = shake_.delay;
const auto desp = shake_.remaining % 2 == 0 ? shake_.desp * (-1) : shake_.desp;
coffee_sprite_->setPosX(shake_.origin + desp);
crisis_sprite_->setPosX(shake_.origin + desp + 15);
shake_.remaining--;
}
} else {
coffee_sprite_->setPosX(shake_.origin);
crisis_sprite_->setPosX(shake_.origin + 15);
coffee_crisis_status_ = Status::FINISHED;
arcade_edition_status_ = Status::MOVING;
} }
}
else dust_right_sprite_->update();
{ dust_left_sprite_->update();
coffee_sprite_->setPosX(shake_.origin);
crisis_sprite_->setPosX(shake_.origin + 15); break;
coffee_crisis_status_ = Status::FINISHED;
arcade_edition_status_ = Status::MOVING;
} }
dust_right_sprite_->update(); case Status::FINISHED: {
dust_left_sprite_->update(); dust_right_sprite_->update();
dust_left_sprite_->update();
break; break;
}
default:
break;
} }
case Status::FINISHED: switch (arcade_edition_status_) {
{ case Status::MOVING: {
dust_right_sprite_->update(); zoom_ -= 0.1f * ZOOM_FACTOR;
dust_left_sprite_->update();
break;
}
default:
break;
}
switch (arcade_edition_status_)
{
case Status::MOVING:
{
zoom_ -= 0.1f * ZOOM_FACTOR;
arcade_edition_sprite_->setZoom(zoom_);
if (zoom_ <= 1.0f)
{
arcade_edition_status_ = Status::SHAKING;
zoom_ = 1.0f;
arcade_edition_sprite_->setZoom(zoom_); arcade_edition_sprite_->setZoom(zoom_);
shake_.init(1, 2, 8, arcade_edition_sprite_->getX()); if (zoom_ <= 1.0f) {
Audio::get()->playSound("title.wav"); arcade_edition_status_ = Status::SHAKING;
Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGHT, FLASH_DELAY); zoom_ = 1.0f;
Screen::get()->shake(); arcade_edition_sprite_->setZoom(zoom_);
} shake_.init(1, 2, 8, arcade_edition_sprite_->getX());
break; Audio::get()->playSound("title.wav");
} Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGHT, FLASH_DELAY);
Screen::get()->shake();
case Status::SHAKING:
{
// Agita "ARCADE EDITION"
if (shake_.remaining > 0)
{
if (shake_.counter > 0)
{
shake_.counter--;
}
else
{
shake_.counter = shake_.delay;
const auto desp = shake_.remaining % 2 == 0 ? shake_.desp * (-1) : shake_.desp;
arcade_edition_sprite_->setX(shake_.origin + desp);
shake_.remaining--;
} }
break;
} }
else
{
arcade_edition_sprite_->setX(shake_.origin);
arcade_edition_status_ = Status::FINISHED;
}
break;
}
default: case Status::SHAKING: {
break; // Agita "ARCADE EDITION"
if (shake_.remaining > 0) {
if (shake_.counter > 0) {
shake_.counter--;
} else {
shake_.counter = shake_.delay;
const auto desp = shake_.remaining % 2 == 0 ? shake_.desp * (-1) : shake_.desp;
arcade_edition_sprite_->setX(shake_.origin + desp);
shake_.remaining--;
}
} else {
arcade_edition_sprite_->setX(shake_.origin);
arcade_edition_status_ = Status::FINISHED;
}
break;
}
default:
break;
} }
if (coffee_crisis_status_ == Status::FINISHED && if (coffee_crisis_status_ == Status::FINISHED &&
arcade_edition_status_ == Status::FINISHED && arcade_edition_status_ == Status::FINISHED &&
post_finished_counter_ > 0) post_finished_counter_ > 0) {
{
--post_finished_counter_; --post_finished_counter_;
} }
} }
// Activa la clase // Activa la clase
void GameLogo::enable() void GameLogo::enable() {
{
init(); init();
coffee_crisis_status_ = Status::MOVING; coffee_crisis_status_ = Status::MOVING;
} }
// Indica si ha terminado la animación // Indica si ha terminado la animación
bool GameLogo::hasFinished() const bool GameLogo::hasFinished() const {
{
return post_finished_counter_ == 0; return post_finished_counter_ == 0;
} }
// Calcula el desplazamiento vertical inicial // Calcula el desplazamiento vertical inicial
int GameLogo::getInitialVerticalDesp() int GameLogo::getInitialVerticalDesp() {
{
const float OFFSET_UP = y_; const float OFFSET_UP = y_;
const float OFFSET_DOWN = param.game.height - y_; const float OFFSET_DOWN = param.game.height - y_;
+38 -42
View File
@@ -1,54 +1,50 @@
#pragma once #pragma once
#include <memory> // Para unique_ptr, shared_ptr #include <memory> // Para unique_ptr, shared_ptr
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
#include "smart_sprite.h" // Para SmartSprite #include "smart_sprite.h" // Para SmartSprite
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
class Texture; class Texture;
// Clase GameLogo // Clase GameLogo
class GameLogo class GameLogo {
{ public:
public:
// --- Constructores y destructor --- // --- Constructores y destructor ---
GameLogo(int x, int y); GameLogo(int x, int y);
~GameLogo() = default; ~GameLogo() = default;
// --- Métodos principales --- // --- Métodos principales ---
void render(); // Pinta la clase en pantalla void render(); // Pinta la clase en pantalla
void update(); // Actualiza la lógica de la clase void update(); // Actualiza la lógica de la clase
void enable(); // Activa la clase void enable(); // Activa la clase
// --- Getters --- // --- Getters ---
bool hasFinished() const; // Indica si ha terminado la animación bool hasFinished() const; // Indica si ha terminado la animación
private: private:
// --- Tipos internos --- // --- Tipos internos ---
enum class Status enum class Status {
{
DISABLED, DISABLED,
MOVING, MOVING,
SHAKING, SHAKING,
FINISHED, FINISHED,
}; };
struct Shake struct Shake {
{ int desp = 1; // Pixels de desplazamiento para agitar la pantalla en el eje x
int desp = 1; // Pixels de desplazamiento para agitar la pantalla en el eje x int delay = 2; // Retraso entre cada desplazamiento de la pantalla al agitarse
int delay = 2; // Retraso entre cada desplazamiento de la pantalla al agitarse int lenght = 8; // Cantidad de desplazamientos a realizar
int lenght = 8; // Cantidad de desplazamientos a realizar int remaining = lenght; // Cantidad de desplazamientos pendientes a realizar
int remaining = lenght; // Cantidad de desplazamientos pendientes a realizar int counter = delay; // Contador para el retraso
int counter = delay; // Contador para el retraso int origin = 0; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
int origin = 0; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
Shake() = default; Shake() = default;
Shake(int d, int de, int l, int o) Shake(int d, int de, int l, int o)
: desp(d), delay(de), lenght(l), remaining(l), counter(de), origin(o) {} : desp(d), delay(de), lenght(l), remaining(l), counter(de), origin(o) {}
void init(int d, int de, int l, int o) void init(int d, int de, int l, int o) {
{
desp = d; desp = d;
delay = de; delay = de;
lenght = l; lenght = l;
@@ -59,28 +55,28 @@ private:
}; };
// --- Objetos y punteros --- // --- Objetos y punteros ---
std::shared_ptr<Texture> dust_texture_; // Textura con los graficos del polvo std::shared_ptr<Texture> dust_texture_; // Textura con los graficos del polvo
std::shared_ptr<Texture> coffee_texture_; // Textura con los graficos de la palabra "COFFEE" std::shared_ptr<Texture> coffee_texture_; // Textura con los graficos de la palabra "COFFEE"
std::shared_ptr<Texture> crisis_texture_; // Textura con los graficos de la palabra "CRISIS" std::shared_ptr<Texture> crisis_texture_; // Textura con los graficos de la palabra "CRISIS"
std::shared_ptr<Texture> arcade_edition_texture_; // Textura con los graficos de "Arcade Edition" std::shared_ptr<Texture> arcade_edition_texture_; // Textura con los graficos de "Arcade Edition"
std::unique_ptr<AnimatedSprite> dust_left_sprite_; // Sprite del polvo (izquierda) std::unique_ptr<AnimatedSprite> dust_left_sprite_; // Sprite del polvo (izquierda)
std::unique_ptr<AnimatedSprite> dust_right_sprite_; // Sprite del polvo (derecha) std::unique_ptr<AnimatedSprite> dust_right_sprite_; // Sprite del polvo (derecha)
std::unique_ptr<SmartSprite> coffee_sprite_; // Sprite de "COFFEE" std::unique_ptr<SmartSprite> coffee_sprite_; // Sprite de "COFFEE"
std::unique_ptr<SmartSprite> crisis_sprite_; // Sprite de "CRISIS" std::unique_ptr<SmartSprite> crisis_sprite_; // Sprite de "CRISIS"
std::unique_ptr<Sprite> arcade_edition_sprite_; // Sprite de "Arcade Edition" std::unique_ptr<Sprite> arcade_edition_sprite_; // Sprite de "Arcade Edition"
// --- Variables de estado --- // --- Variables de estado ---
float x_; // Posición X del logo float x_; // Posición X del logo
float y_; // Posición Y del logo float y_; // Posición Y del logo
float zoom_ = 1.0f; // Zoom aplicado al texto "ARCADE EDITION" float zoom_ = 1.0f; // Zoom aplicado al texto "ARCADE EDITION"
int post_finished_counter_ = 1; // Contador final tras animaciones int post_finished_counter_ = 1; // Contador final tras animaciones
Status coffee_crisis_status_ = Status::DISABLED; // Estado de "COFFEE CRISIS" Status coffee_crisis_status_ = Status::DISABLED; // Estado de "COFFEE CRISIS"
Status arcade_edition_status_ = Status::DISABLED; // Estado de "ARCADE EDITION" Status arcade_edition_status_ = Status::DISABLED; // Estado de "ARCADE EDITION"
Shake shake_; // Efecto de agitación Shake shake_; // Efecto de agitación
// --- Métodos internos --- // --- Métodos internos ---
void init(); // Inicializa las variables void init(); // Inicializa las variables
int getInitialVerticalDesp(); // Calcula el desplazamiento vertical inicial int getInitialVerticalDesp(); // Calcula el desplazamiento vertical inicial
}; };
+11 -14
View File
@@ -1,19 +1,16 @@
#include "global_events.h" #include "global_events.h"
#include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory #include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory
#include "mouse.h" // Para handleEvent #include "mouse.h" // Para handleEvent
#include "screen.h" #include "screen.h"
#include "section.h" // Para Name, Options, name, options #include "section.h" // Para Name, Options, name, options
namespace GlobalEvents namespace GlobalEvents {
{ // Comprueba los eventos que se pueden producir en cualquier sección del juego
// Comprueba los eventos que se pueden producir en cualquier sección del juego void check(const SDL_Event &event) {
void check(const SDL_Event &event) switch (event.type) {
{ case SDL_EVENT_QUIT: // Evento de salida de la aplicación
switch (event.type)
{
case SDL_EVENT_QUIT: // Evento de salida de la aplicación
Section::name = Section::Name::QUIT; Section::name = Section::Name::QUIT;
Section::options = Section::Options::NONE; Section::options = Section::Options::NONE;
return; return;
@@ -29,8 +26,8 @@ namespace GlobalEvents
default: default:
break; break;
}
Mouse::handleEvent(event);
} }
}
Mouse::handleEvent(event);
}
} // namespace GlobalEvents
+4 -5
View File
@@ -2,8 +2,7 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
namespace GlobalEvents namespace GlobalEvents {
{ // Comprueba los eventos que se pueden producir en cualquier sección del juego
// Comprueba los eventos que se pueden producir en cualquier sección del juego void check(const SDL_Event &event);
void check(const SDL_Event &event); } // namespace GlobalEvents
}
+261 -327
View File
@@ -1,87 +1,72 @@
#include "global_inputs.h" #include "global_inputs.h"
#include <string> // Para basic_string, operator+, allocator, cha... #include <string> // Para basic_string, operator+, allocator, cha...
#include <vector> // Para vector #include <vector> // Para vector
#include "asset.h" // Para Asset #include "asset.h" // Para Asset
#include "audio.h" // Para Audio #include "audio.h" // Para Audio
#include "input.h" // Para Input, INPUT_DO_NOT_ALLOW_REPEAT, Input... #include "input.h" // Para Input, INPUT_DO_NOT_ALLOW_REPEAT, Input...
#include "lang.h" // Para getText, Code, getNextLangCode, loadFro... #include "lang.h" // Para getText, Code, getNextLangCode, loadFro...
#include "notifier.h" // Para Notifier #include "notifier.h" // Para Notifier
#include "options.h" // Para SettingsOptions, settings, VideoOptions #include "options.h" // Para SettingsOptions, settings, VideoOptions
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "section.h" // Para Name, name, Options, options, AttractMode #include "section.h" // Para Name, name, Options, options, AttractMode
#include "ui/service_menu.h" // Para ServiceMenu #include "ui/service_menu.h" // Para ServiceMenu
#include "utils.h" // Para boolToOnOff #include "utils.h" // Para boolToOnOff
namespace GlobalInputs namespace GlobalInputs {
{ // Termina
// Termina void quit() {
void quit() const std::string CODE = "QUIT";
{ if (Notifier::get()->checkCode(CODE)) {
const std::string CODE = "QUIT"; // Si la notificación de salir está activa, cambia de sección
if (Notifier::get()->checkCode(CODE)) Section::name = Section::Name::QUIT;
{ Section::options = Section::Options::NONE;
// Si la notificación de salir está activa, cambia de sección } else {
Section::name = Section::Name::QUIT; // Si la notificación de salir no está activa, muestra la notificación
Section::options = Section::Options::NONE; Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 01"), std::string()}, -1, CODE);
}
else
{
// Si la notificación de salir no está activa, muestra la notificación
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 01"), std::string()}, -1, CODE);
}
} }
}
// Reinicia // Reinicia
void reset() void reset() {
{ const std::string CODE = "RESET";
const std::string CODE = "RESET"; if (Notifier::get()->checkCode(CODE)) {
if (Notifier::get()->checkCode(CODE)) Section::name = Section::Name::RESET;
{ Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 15")});
Section::name = Section::Name::RESET; } else {
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 15")}); Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 03"), std::string()}, -1, CODE);
}
else
{
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 03"), std::string()}, -1, CODE);
}
} }
}
// Activa o desactiva el audio // Activa o desactiva el audio
void toggleAudio() void toggleAudio() {
{ Options::audio.enabled = !Options::audio.enabled;
Options::audio.enabled = !Options::audio.enabled; Audio::get()->enable(Options::audio.enabled);
Audio::get()->enable(Options::audio.enabled); Notifier::get()->show({"Audio " + boolToOnOff(Options::audio.enabled)});
Notifier::get()->show({"Audio " + boolToOnOff(Options::audio.enabled)}); }
}
// Cambia el modo de escalado entero // Cambia el modo de escalado entero
void toggleIntegerScale() void toggleIntegerScale() {
{ Screen::get()->toggleIntegerScale();
Screen::get()->toggleIntegerScale(); Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 12") + " " + boolToOnOff(Options::video.integer_scale)});
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 12") + " " + boolToOnOff(Options::video.integer_scale)}); }
}
// Activa / desactiva el vsync // Activa / desactiva el vsync
void toggleVSync() void toggleVSync() {
{ Screen::get()->toggleVSync();
Screen::get()->toggleVSync(); Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 14") + " " + boolToOnOff(Options::video.v_sync)});
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 14") + " " + boolToOnOff(Options::video.v_sync)}); }
}
// Activa o desactiva los shaders // Activa o desactiva los shaders
void toggleShaders() void toggleShaders() {
{ Screen::get()->toggleShaders();
Screen::get()->toggleShaders(); Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 13") + " " + boolToOnOff(Options::video.shaders)});
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 13") + " " + boolToOnOff(Options::video.shaders)}); }
}
// Obtiene una fichero a partir de un lang::Code // Obtiene una fichero a partir de un lang::Code
std::string getLangFile(Lang::Code code) std::string getLangFile(Lang::Code code) {
{ switch (code) {
switch (code)
{
case Lang::Code::VALENCIAN: case Lang::Code::VALENCIAN:
return Asset::get()->get("ba_BA.json"); return Asset::get()->get("ba_BA.json");
break; break;
@@ -91,14 +76,12 @@ namespace GlobalInputs
default: default:
return Asset::get()->get("en_UK.json"); return Asset::get()->get("en_UK.json");
break; break;
}
} }
}
// Obtiene una cadena a partir de un lang::Code // Obtiene una cadena a partir de un lang::Code
std::string getLangName(Lang::Code code) std::string getLangName(Lang::Code code) {
{ switch (code) {
switch (code)
{
case Lang::Code::VALENCIAN: case Lang::Code::VALENCIAN:
return " \"ba_BA\""; return " \"ba_BA\"";
break; break;
@@ -108,47 +91,39 @@ namespace GlobalInputs
default: default:
return " \"en_UK\""; return " \"en_UK\"";
break; break;
}
} }
}
// Cambia el idioma // Cambia el idioma
void changeLang() void changeLang() {
{ const std::string CODE = "LANG";
const std::string CODE = "LANG"; if (Notifier::get()->checkCode(CODE)) {
if (Notifier::get()->checkCode(CODE)) Options::settings.language = Lang::getNextLangCode(Options::settings.language);
{ Lang::loadFromFile(getLangFile(static_cast<Lang::Code>(Options::settings.language)));
Options::settings.language = Lang::getNextLangCode(Options::settings.language); Section::name = Section::Name::RESET;
Lang::loadFromFile(getLangFile(static_cast<Lang::Code>(Options::settings.language))); Section::options = Section::Options::RELOAD;
Section::name = Section::Name::RESET; Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 05") + getLangName(Options::settings.language)});
Section::options = Section::Options::RELOAD; } else {
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 05") + getLangName(Options::settings.language)}); const auto NEXT = Lang::getNextLangCode(Options::settings.language);
} Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 04") + getLangName(NEXT), std::string()}, -1, CODE);
else
{
const auto NEXT = Lang::getNextLangCode(Options::settings.language);
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 04") + getLangName(NEXT), std::string()}, -1, CODE);
}
} }
}
// Cambia el modo de disparo // Cambia el modo de disparo
void toggleFireMode() void toggleFireMode() {
{ Options::settings.autofire = !Options::settings.autofire;
Options::settings.autofire = !Options::settings.autofire; Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 08") + " " + boolToOnOff(Options::settings.autofire)});
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 08") + " " + boolToOnOff(Options::settings.autofire)}); }
}
// Salta una sección del juego // Salta una sección del juego
void skipSection() void skipSection() {
{ switch (Section::name) {
switch (Section::name)
{
case Section::Name::INTRO: case Section::Name::INTRO:
Audio::get()->stopMusic(); Audio::get()->stopMusic();
/* Continua en el case de abajo */ /* Continua en el case de abajo */
case Section::Name::LOGO: case Section::Name::LOGO:
case Section::Name::HI_SCORE_TABLE: case Section::Name::HI_SCORE_TABLE:
case Section::Name::INSTRUCTIONS: case Section::Name::INSTRUCTIONS: {
{
Section::name = Section::Name::TITLE; Section::name = Section::Name::TITLE;
Section::options = Section::Options::TITLE_1; Section::options = Section::Options::TITLE_1;
Section::attract_mode = Section::AttractMode::TITLE_TO_DEMO; Section::attract_mode = Section::AttractMode::TITLE_TO_DEMO;
@@ -156,284 +131,243 @@ namespace GlobalInputs
} }
default: default:
break; break;
}
}
// Activa el menu de servicio
void toggleServiceMenu() {
ServiceMenu::get()->toggle();
}
// Cambia el modo de pantalla completa
void toggleFullscreen() {
Screen::get()->toggleFullscreen();
const std::string MODE = Options::video.fullscreen ? Lang::getText("[NOTIFICATIONS] 11") : Lang::getText("[NOTIFICATIONS] 10");
Notifier::get()->show({MODE});
}
// Reduce el tamaño de la ventana
void decWindowSize() {
if (Screen::get()->decWindowSize()) {
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 09") + " x" + std::to_string(Options::window.size)});
}
}
// Aumenta el tamaño de la ventana
void incWindowSize() {
if (Screen::get()->incWindowSize()) {
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 09") + " x" + std::to_string(Options::window.size)});
}
}
// Comprueba el boton de servicio
bool checkServiceButton() {
// Teclado
if (Input::get()->checkInput(InputAction::SERVICE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
toggleServiceMenu();
return true;
}
// Mandos
{
for (int i = 0; i < Input::get()->getNumControllers(); ++i) {
if (Input::get()->checkInput(InputAction::SERVICE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i)) {
toggleServiceMenu();
return true;
}
} }
} }
return false;
}
// Activa el menu de servicio // Comprueba las entradas del menú de servicio
void toggleServiceMenu() bool checkServiceInputs() {
{ if (!ServiceMenu::get()->isEnabled())
ServiceMenu::get()->toggle(); return false;
}
// Cambia el modo de pantalla completa // Teclado
void toggleFullscreen()
{ {
Screen::get()->toggleFullscreen(); // Arriba
const std::string MODE = Options::video.fullscreen ? Lang::getText("[NOTIFICATIONS] 11") : Lang::getText("[NOTIFICATIONS] 10"); if (Input::get()->checkInput(InputAction::UP, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
Notifier::get()->show({MODE}); ServiceMenu::get()->setSelectorUp();
}
// Reduce el tamaño de la ventana
void decWindowSize()
{
if (Screen::get()->decWindowSize())
{
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 09") + " x" + std::to_string(Options::window.size)});
}
}
// Aumenta el tamaño de la ventana
void incWindowSize()
{
if (Screen::get()->incWindowSize())
{
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 09") + " x" + std::to_string(Options::window.size)});
}
}
// Comprueba el boton de servicio
bool checkServiceButton()
{
// Teclado
if (Input::get()->checkInput(InputAction::SERVICE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD))
{
toggleServiceMenu();
return true; return true;
} }
// Mandos // Abajo
{ if (Input::get()->checkInput(InputAction::DOWN, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
for (int i = 0; i < Input::get()->getNumControllers(); ++i) ServiceMenu::get()->setSelectorDown();
{ return true;
if (Input::get()->checkInput(InputAction::SERVICE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i)) }
{
toggleServiceMenu(); // Derecha
return true; if (Input::get()->checkInput(InputAction::RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
} ServiceMenu::get()->adjustOption(true);
} return true;
}
// Izquierda
if (Input::get()->checkInput(InputAction::LEFT, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
ServiceMenu::get()->adjustOption(false);
return true;
}
// Aceptar
if (Input::get()->checkInput(InputAction::SM_SELECT, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
ServiceMenu::get()->selectOption();
return true;
}
// Atras
if (Input::get()->checkInput(InputAction::SM_BACK, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
ServiceMenu::get()->moveBack();
return true;
} }
return false;
} }
// Comprueba las entradas del menú de servicio // Mandos
bool checkServiceInputs()
{ {
if (!ServiceMenu::get()->isEnabled()) for (int i = 0; i < Input::get()->getNumControllers(); ++i) {
return false;
// Teclado
{
// Arriba // Arriba
if (Input::get()->checkInput(InputAction::UP, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::UP, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i)) {
{
ServiceMenu::get()->setSelectorUp(); ServiceMenu::get()->setSelectorUp();
return true; return true;
} }
// Abajo // Abajo
if (Input::get()->checkInput(InputAction::DOWN, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::DOWN, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i)) {
{
ServiceMenu::get()->setSelectorDown(); ServiceMenu::get()->setSelectorDown();
return true; return true;
} }
// Derecha // Derecha
if (Input::get()->checkInput(InputAction::RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i)) {
{
ServiceMenu::get()->adjustOption(true); ServiceMenu::get()->adjustOption(true);
return true; return true;
} }
// Izquierda // Izquierda
if (Input::get()->checkInput(InputAction::LEFT, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::LEFT, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i)) {
{
ServiceMenu::get()->adjustOption(false); ServiceMenu::get()->adjustOption(false);
return true; return true;
} }
// Aceptar // Aceptar
if (Input::get()->checkInput(InputAction::SM_SELECT, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::SM_SELECT, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i)) {
{
ServiceMenu::get()->selectOption(); ServiceMenu::get()->selectOption();
return true; return true;
} }
// Atras // Atras
if (Input::get()->checkInput(InputAction::SM_BACK, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::SM_BACK, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i)) {
{
ServiceMenu::get()->moveBack(); ServiceMenu::get()->moveBack();
return true; return true;
} }
} }
// Mandos
{
for (int i = 0; i < Input::get()->getNumControllers(); ++i)
{
// Arriba
if (Input::get()->checkInput(InputAction::UP, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i))
{
ServiceMenu::get()->setSelectorUp();
return true;
}
// Abajo
if (Input::get()->checkInput(InputAction::DOWN, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i))
{
ServiceMenu::get()->setSelectorDown();
return true;
}
// Derecha
if (Input::get()->checkInput(InputAction::RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i))
{
ServiceMenu::get()->adjustOption(true);
return true;
}
// Izquierda
if (Input::get()->checkInput(InputAction::LEFT, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i))
{
ServiceMenu::get()->adjustOption(false);
return true;
}
// Aceptar
if (Input::get()->checkInput(InputAction::SM_SELECT, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i))
{
ServiceMenu::get()->selectOption();
return true;
}
// Atras
if (Input::get()->checkInput(InputAction::SM_BACK, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i))
{
ServiceMenu::get()->moveBack();
return true;
}
}
}
return false;
} }
return false;
}
// Comprueba las entradas fuera del menú de servicio // Comprueba las entradas fuera del menú de servicio
bool checkInputs() bool checkInputs() {
// Teclado
{ {
// Teclado // Comprueba el teclado para cambiar entre pantalla completa y ventana
{ if (Input::get()->checkInput(InputAction::WINDOW_FULLSCREEN, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
// Comprueba el teclado para cambiar entre pantalla completa y ventana Screen::get()->toggleFullscreen();
if (Input::get()->checkInput(InputAction::WINDOW_FULLSCREEN, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) const std::string MODE = Options::video.fullscreen ? Lang::getText("[NOTIFICATIONS] 11") : Lang::getText("[NOTIFICATIONS] 10");
{ Notifier::get()->show({MODE});
Screen::get()->toggleFullscreen(); return true;
const std::string MODE = Options::video.fullscreen ? Lang::getText("[NOTIFICATIONS] 11") : Lang::getText("[NOTIFICATIONS] 10"); }
Notifier::get()->show({MODE});
return true;
}
// Comprueba el teclado para decrementar el tamaño de la ventana // Comprueba el teclado para decrementar el tamaño de la ventana
if (Input::get()->checkInput(InputAction::WINDOW_DEC_SIZE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::WINDOW_DEC_SIZE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
{ if (Screen::get()->decWindowSize()) {
if (Screen::get()->decWindowSize()) Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 09") + " x" + std::to_string(Options::window.size)});
{
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 09") + " x" + std::to_string(Options::window.size)});
}
return true;
} }
return true;
}
// Comprueba el teclado para incrementar el tamaño de la ventana // Comprueba el teclado para incrementar el tamaño de la ventana
if (Input::get()->checkInput(InputAction::WINDOW_INC_SIZE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::WINDOW_INC_SIZE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
{ if (Screen::get()->incWindowSize()) {
if (Screen::get()->incWindowSize()) Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 09") + " x" + std::to_string(Options::window.size)});
{
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 09") + " x" + std::to_string(Options::window.size)});
}
return true;
} }
return true;
}
// Salir // Salir
if (Input::get()->checkInput(InputAction::EXIT, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::EXIT, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
{ quit();
quit(); return true;
return true; }
}
// Saltar sección // Saltar sección
if (Input::get()->checkAnyButton() && !ServiceMenu::get()->isEnabled()) if (Input::get()->checkAnyButton() && !ServiceMenu::get()->isEnabled()) {
{ skipSection();
skipSection(); return true;
return true; }
}
// Reset // Reset
if (Input::get()->checkInput(InputAction::RESET, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::RESET, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
{ reset();
reset(); return true;
return true; }
}
// Audio // Audio
if (Input::get()->checkInput(InputAction::TOGGLE_AUDIO, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::TOGGLE_AUDIO, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
{ toggleAudio();
toggleAudio(); return true;
return true; }
}
// Autofire // Autofire
if (Input::get()->checkInput(InputAction::TOGGLE_AUTO_FIRE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::TOGGLE_AUTO_FIRE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
{ toggleFireMode();
toggleFireMode(); return true;
return true; }
}
// Idioma // Idioma
if (Input::get()->checkInput(InputAction::CHANGE_LANG, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::CHANGE_LANG, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
{ changeLang();
changeLang(); return true;
return true; }
}
// Shaders // Shaders
if (Input::get()->checkInput(InputAction::TOGGLE_VIDEO_SHADERS, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::TOGGLE_VIDEO_SHADERS, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
{ toggleShaders();
toggleShaders(); return true;
return true; }
}
// Integer Scale // Integer Scale
if (Input::get()->checkInput(InputAction::TOGGLE_VIDEO_INTEGER_SCALE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::TOGGLE_VIDEO_INTEGER_SCALE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
{ toggleIntegerScale();
toggleIntegerScale(); return true;
return true; }
}
// VSync // VSync
if (Input::get()->checkInput(InputAction::TOGGLE_VIDEO_VSYNC, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::TOGGLE_VIDEO_VSYNC, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
{ toggleVSync();
toggleVSync(); return true;
return true; }
}
#ifdef DEBUG #ifdef DEBUG
// Debug info // Debug info
if (Input::get()->checkInput(InputAction::SHOW_INFO, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::SHOW_INFO, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
{ Screen::get()->toggleDebugInfo();
Screen::get()->toggleDebugInfo(); return true;
return true;
}
#endif
} }
return false; #endif
} }
return false;
}
// Comprueba los inputs que se pueden introducir en cualquier sección del juego // Comprueba los inputs que se pueden introducir en cualquier sección del juego
bool check() bool check() {
{ if (checkServiceButton())
if (checkServiceButton()) return true;
return true; if (checkServiceInputs())
if (checkServiceInputs()) return true;
return true; if (checkInputs())
if (checkInputs()) return true;
return true; return false;
return false; }
} } // namespace GlobalInputs
}
+4 -5
View File
@@ -1,7 +1,6 @@
#pragma once #pragma once
namespace GlobalInputs namespace GlobalInputs {
{ // Comprueba los inputs que se pueden introducir en cualquier sección del juego
// Comprueba los inputs que se pueden introducir en cualquier sección del juego bool check();
bool check(); } // namespace GlobalInputs
}
+274 -351
View File
@@ -1,11 +1,12 @@
#include "input.h" #include "input.h"
#include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory, SDL_GetGamepa... #include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory, SDL_GetGamepa...
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <algorithm> // Para find
#include <iterator> // Para distance #include <algorithm> // Para find
#include <unordered_map> // Para unordered_map, _Node_const_iterator, operat... #include <iterator> // Para distance
#include <utility> // Para pair #include <unordered_map> // Para unordered_map, _Node_const_iterator, operat...
#include <utility> // Para pair
// Singleton // Singleton
Input *Input::instance_ = nullptr; Input *Input::instance_ = nullptr;
@@ -21,232 +22,188 @@ Input *Input::get() { return Input::instance_; }
// Constructor // Constructor
Input::Input(const std::string &game_controller_db_path) Input::Input(const std::string &game_controller_db_path)
: game_controller_db_path_(game_controller_db_path) : game_controller_db_path_(game_controller_db_path) {
{ // Inicializa el subsistema SDL_INIT_GAMEPAD
// Inicializa el subsistema SDL_INIT_GAMEPAD initSDLGamePad();
initSDLGamePad();
// Inicializa los vectores // Inicializa los vectores
key_bindings_.resize(static_cast<int>(InputAction::SIZE), KeyBindings()); key_bindings_.resize(static_cast<int>(InputAction::SIZE), KeyBindings());
controller_bindings_.resize(num_gamepads_, std::vector<ControllerBindings>(static_cast<int>(InputAction::SIZE), ControllerBindings())); controller_bindings_.resize(num_gamepads_, std::vector<ControllerBindings>(static_cast<int>(InputAction::SIZE), ControllerBindings()));
// Listado de los inputs para jugar que utilizan botones, ni palancas ni crucetas // Listado de los inputs para jugar que utilizan botones, ni palancas ni crucetas
button_inputs_ = {InputAction::FIRE_LEFT, InputAction::FIRE_CENTER, InputAction::FIRE_RIGHT, InputAction::START}; button_inputs_ = {InputAction::FIRE_LEFT, InputAction::FIRE_CENTER, InputAction::FIRE_RIGHT, InputAction::START};
} }
// Asigna inputs a teclas // Asigna inputs a teclas
void Input::bindKey(InputAction input, SDL_Scancode code) void Input::bindKey(InputAction input, SDL_Scancode code) {
{ key_bindings_.at(static_cast<int>(input)).scancode = code;
key_bindings_.at(static_cast<int>(input)).scancode = code;
} }
// Asigna inputs a botones del mando // Asigna inputs a botones del mando
void Input::bindGameControllerButton(int controller_index, InputAction input, SDL_GamepadButton button) void Input::bindGameControllerButton(int controller_index, InputAction input, SDL_GamepadButton button) {
{ if (controller_index < num_gamepads_) {
if (controller_index < num_gamepads_) controller_bindings_.at(controller_index).at(static_cast<int>(input)).button = button;
{ }
controller_bindings_.at(controller_index).at(static_cast<int>(input)).button = button;
}
} }
// Asigna inputs a botones del mando // Asigna inputs a botones del mando
void Input::bindGameControllerButton(int controller_index, InputAction input_target, InputAction input_source) void Input::bindGameControllerButton(int controller_index, InputAction input_target, InputAction input_source) {
{ if (controller_index < num_gamepads_) {
if (controller_index < num_gamepads_) controller_bindings_.at(controller_index).at(static_cast<int>(input_target)).button = controller_bindings_.at(controller_index).at(static_cast<int>(input_source)).button;
{ }
controller_bindings_.at(controller_index).at(static_cast<int>(input_target)).button = controller_bindings_.at(controller_index).at(static_cast<int>(input_source)).button;
}
} }
// Comprueba si un input esta activo // Comprueba si un input esta activo
bool Input::checkInput(InputAction input, bool repeat, InputDevice device, int controller_index) bool Input::checkInput(InputAction input, bool repeat, InputDevice device, int controller_index) {
{ bool success_keyboard = false;
bool success_keyboard = false; bool success_controller = false;
bool success_controller = false; const int input_index = static_cast<int>(input);
const int input_index = static_cast<int>(input);
if (device == InputDevice::KEYBOARD || device == InputDevice::ANY) if (device == InputDevice::KEYBOARD || device == InputDevice::ANY) {
{ if (repeat) { // El usuario quiere saber si está pulsada (estado mantenido)
if (repeat) success_keyboard = key_bindings_[input_index].is_held;
{ // El usuario quiere saber si está pulsada (estado mantenido) } else { // El usuario quiere saber si ACABA de ser pulsada (evento de un solo fotograma)
success_keyboard = key_bindings_[input_index].is_held; success_keyboard = key_bindings_[input_index].just_pressed;
} }
else }
{ // El usuario quiere saber si ACABA de ser pulsada (evento de un solo fotograma)
success_keyboard = key_bindings_[input_index].just_pressed;
}
}
if (gameControllerFound() && controller_index >= 0 && controller_index < num_gamepads_) if (gameControllerFound() && controller_index >= 0 && controller_index < num_gamepads_) {
{ if ((device == InputDevice::CONTROLLER) || (device == InputDevice::ANY)) {
if ((device == InputDevice::CONTROLLER) || (device == InputDevice::ANY)) success_controller = checkAxisInput(input, controller_index, repeat);
{
success_controller = checkAxisInput(input, controller_index, repeat);
if (!success_controller) if (!success_controller) {
{ if (repeat) { // El usuario quiere saber si está pulsada (estado mantenido)
if (repeat) success_controller = controller_bindings_.at(controller_index).at(input_index).is_held;
{ // El usuario quiere saber si está pulsada (estado mantenido) } else { // El usuario quiere saber si ACABA de ser pulsada (evento de un solo fotograma)
success_controller = controller_bindings_.at(controller_index).at(input_index).is_held; success_controller = controller_bindings_.at(controller_index).at(input_index).just_pressed;
} }
else }
{ // El usuario quiere saber si ACABA de ser pulsada (evento de un solo fotograma) }
success_controller = controller_bindings_.at(controller_index).at(input_index).just_pressed; }
}
}
}
}
return (success_keyboard || success_controller); return (success_keyboard || success_controller);
} }
// Comprueba si hay almenos un input activo // Comprueba si hay almenos un input activo
bool Input::checkAnyInput(InputDevice device, int controller_index) bool Input::checkAnyInput(InputDevice device, int controller_index) {
{ // Obtenemos el número total de acciones posibles para iterar sobre ellas.
// Obtenemos el número total de acciones posibles para iterar sobre ellas. const int num_actions = static_cast<int>(InputAction::SIZE);
const int num_actions = static_cast<int>(InputAction::SIZE);
// --- Comprobación del Teclado --- // --- Comprobación del Teclado ---
if (device == InputDevice::KEYBOARD || device == InputDevice::ANY) if (device == InputDevice::KEYBOARD || device == InputDevice::ANY) {
{ for (int i = 0; i < num_actions; ++i) {
for (int i = 0; i < num_actions; ++i) // Simplemente leemos el estado pre-calculado por Input::update().
{ // Ya no se llama a SDL_GetKeyboardState ni se modifica el estado '.active'.
// Simplemente leemos el estado pre-calculado por Input::update(). if (key_bindings_.at(i).just_pressed) {
// Ya no se llama a SDL_GetKeyboardState ni se modifica el estado '.active'. return true; // Se encontró una acción recién pulsada.
if (key_bindings_.at(i).just_pressed) }
{ }
return true; // Se encontró una acción recién pulsada. }
}
}
}
// --- Comprobación del Mando --- // --- Comprobación del Mando ---
// Comprobamos si hay mandos y si el índice solicitado es válido. // Comprobamos si hay mandos y si el índice solicitado es válido.
if (gameControllerFound() && controller_index >= 0 && controller_index < num_gamepads_) if (gameControllerFound() && controller_index >= 0 && controller_index < num_gamepads_) {
{ if (device == InputDevice::CONTROLLER || device == InputDevice::ANY) {
if (device == InputDevice::CONTROLLER || device == InputDevice::ANY) // Bucle CORREGIDO: Iteramos sobre todas las acciones, no sobre el número de mandos.
{ for (int i = 0; i < num_actions; ++i) {
// Bucle CORREGIDO: Iteramos sobre todas las acciones, no sobre el número de mandos. // Leemos el estado pre-calculado para el mando y la acción específicos.
for (int i = 0; i < num_actions; ++i) if (controller_bindings_.at(controller_index).at(i).just_pressed) {
{ return true; // Se encontró una acción recién pulsada en el mando.
// Leemos el estado pre-calculado para el mando y la acción específicos. }
if (controller_bindings_.at(controller_index).at(i).just_pressed) }
{ }
return true; // Se encontró una acción recién pulsada en el mando. }
}
}
}
}
// Si llegamos hasta aquí, no se detectó ninguna nueva pulsación. // Si llegamos hasta aquí, no se detectó ninguna nueva pulsación.
return false; return false;
} }
// Comprueba si hay algún botón pulsado. Devuelve 0 en caso de no encontrar nada o el indice del dispositivo + 1. Se hace así para poder gastar el valor devuelto como un valor "booleano" // Comprueba si hay algún botón pulsado. Devuelve 0 en caso de no encontrar nada o el indice del dispositivo + 1. Se hace así para poder gastar el valor devuelto como un valor "booleano"
int Input::checkAnyButton(bool repeat) int Input::checkAnyButton(bool repeat) {
{ // Solo comprueba los botones definidos previamente
// Solo comprueba los botones definidos previamente for (auto bi : button_inputs_) {
for (auto bi : button_inputs_) // Comprueba el teclado
{ if (checkInput(bi, repeat, InputDevice::KEYBOARD)) {
// Comprueba el teclado return 1;
if (checkInput(bi, repeat, InputDevice::KEYBOARD)) }
{
return 1;
}
// Comprueba los mandos // Comprueba los mandos
for (int i = 0; i < num_gamepads_; ++i) for (int i = 0; i < num_gamepads_; ++i) {
{ if (checkInput(bi, repeat, InputDevice::CONTROLLER, i)) {
if (checkInput(bi, repeat, InputDevice::CONTROLLER, i)) return i + 1;
{ }
return i + 1; }
} }
}
}
return 0; return 0;
} }
// Busca si hay mandos conectados // Busca si hay mandos conectados
bool Input::discoverGameControllers() bool Input::discoverGameControllers() {
{ bool found = false;
bool found = false;
if (SDL_AddGamepadMappingsFromFile(game_controller_db_path_.c_str()) < 0) if (SDL_AddGamepadMappingsFromFile(game_controller_db_path_.c_str()) < 0) {
{ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: could not load %s file: %s", game_controller_db_path_.c_str(), SDL_GetError());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: could not load %s file: %s", game_controller_db_path_.c_str(), SDL_GetError()); }
}
// En SDL3, SDL_GetJoysticks devuelve un array de IDs, no un contador // En SDL3, SDL_GetJoysticks devuelve un array de IDs, no un contador
SDL_JoystickID *joystick_ids = SDL_GetJoysticks(&num_joysticks_); SDL_JoystickID *joystick_ids = SDL_GetJoysticks(&num_joysticks_);
num_gamepads_ = 0; num_gamepads_ = 0;
// Cuenta el número de mandos // Cuenta el número de mandos
joysticks_.clear(); joysticks_.clear();
for (int i = 0; i < num_joysticks_; ++i) for (int i = 0; i < num_joysticks_; ++i) {
{ // Usar el ID del joystick, no el índice
// Usar el ID del joystick, no el índice auto joy = SDL_OpenJoystick(joystick_ids[i]);
auto joy = SDL_OpenJoystick(joystick_ids[i]); joysticks_.push_back(joy);
joysticks_.push_back(joy);
// En SDL3, SDL_IsGamepad toma un SDL_JoystickID, no un índice // En SDL3, SDL_IsGamepad toma un SDL_JoystickID, no un índice
if (SDL_IsGamepad(joystick_ids[i])) if (SDL_IsGamepad(joystick_ids[i])) {
{ num_gamepads_++;
num_gamepads_++; }
} }
}
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, ">> LOOKING FOR GAME CONTROLLERS"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, ">> LOOKING FOR GAME CONTROLLERS");
if (num_joysticks_ != num_gamepads_) if (num_joysticks_ != num_gamepads_) {
{ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Joysticks found: %d", num_joysticks_);
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Joysticks found: %d", num_joysticks_); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Gamepads found : %d", num_gamepads_);
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Gamepads found : %d", num_gamepads_); } else {
} SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Gamepads found: %d", num_gamepads_);
else }
{
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Gamepads found: %d", num_gamepads_);
}
if (num_gamepads_ > 0) if (num_gamepads_ > 0) {
{ found = true;
found = true;
// Recorrer los joysticks y abrir solo los que son gamepads // Recorrer los joysticks y abrir solo los que son gamepads
for (int i = 0; i < num_joysticks_; i++) for (int i = 0; i < num_joysticks_; i++) {
{ if (SDL_IsGamepad(joystick_ids[i])) {
if (SDL_IsGamepad(joystick_ids[i])) // Abre el mando usando el ID del joystick
{ auto pad = SDL_OpenGamepad(joystick_ids[i]);
// Abre el mando usando el ID del joystick if (pad != nullptr) {
auto pad = SDL_OpenGamepad(joystick_ids[i]); connected_controllers_.push_back(pad);
if (pad != nullptr)
{
connected_controllers_.push_back(pad);
// Obtener el nombre usando el ID del joystick // Obtener el nombre usando el ID del joystick
const char *name_cstr = SDL_GetGamepadNameForID(joystick_ids[i]); const char *name_cstr = SDL_GetGamepadNameForID(joystick_ids[i]);
std::string name = name_cstr ? name_cstr : "Unknown Gamepad"; std::string name = name_cstr ? name_cstr : "Unknown Gamepad";
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "#%d: %s", i, name.c_str()); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "#%d: %s", i, name.c_str());
controller_names_.push_back(name); controller_names_.push_back(name);
} } else {
else SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open gamepad %d: %s", joystick_ids[i], SDL_GetError());
{ }
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open gamepad %d: %s", joystick_ids[i], SDL_GetError()); }
} }
}
}
SDL_SetGamepadEventsEnabled(true); SDL_SetGamepadEventsEnabled(true);
} }
// Liberar el array de IDs // Liberar el array de IDs
if (joystick_ids) if (joystick_ids) {
{ SDL_free(joystick_ids);
SDL_free(joystick_ids); }
}
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> FINISHED LOOKING FOR GAME CONTROLLERS"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> FINISHED LOOKING FOR GAME CONTROLLERS");
return found; return found;
} }
// Comprueba si hay algun mando conectado // Comprueba si hay algun mando conectado
@@ -259,202 +216,168 @@ std::string Input::getControllerName(int controller_index) const { return num_ga
int Input::getNumControllers() const { return num_gamepads_; } int Input::getNumControllers() const { return num_gamepads_; }
// Obtiene el indice del controlador a partir de un event.id // Obtiene el indice del controlador a partir de un event.id
int Input::getJoyIndex(SDL_JoystickID id) const int Input::getJoyIndex(SDL_JoystickID id) const {
{ for (int i = 0; i < num_joysticks_; ++i) {
for (int i = 0; i < num_joysticks_; ++i) if (SDL_GetJoystickID(joysticks_[i]) == id) {
{ return i;
if (SDL_GetJoystickID(joysticks_[i]) == id) }
{ }
return i; return -1;
}
}
return -1;
} }
// Muestra por consola los controles asignados // Muestra por consola los controles asignados
void Input::printBindings(InputDevice device, int controller_index) const void Input::printBindings(InputDevice device, int controller_index) const {
{ if (device == InputDevice::ANY || device == InputDevice::KEYBOARD) {
if (device == InputDevice::ANY || device == InputDevice::KEYBOARD) return;
{ }
return;
}
if (device == InputDevice::CONTROLLER) if (device == InputDevice::CONTROLLER) {
{ if (controller_index >= num_gamepads_) {
if (controller_index >= num_gamepads_) return;
{ }
return;
}
// Muestra el nombre del mando // Muestra el nombre del mando
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n%s", controller_names_.at(controller_index).c_str()); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n%s", controller_names_.at(controller_index).c_str());
// Muestra los botones asignados // Muestra los botones asignados
for (auto bi : button_inputs_) for (auto bi : button_inputs_) {
{ SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "%s : %d", to_string(bi).c_str(), controller_bindings_.at(controller_index).at(static_cast<int>(bi)).button);
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "%s : %d", to_string(bi).c_str(), controller_bindings_.at(controller_index).at(static_cast<int>(bi)).button); }
} }
}
} }
// Obtiene el SDL_GamepadButton asignado a un input // Obtiene el SDL_GamepadButton asignado a un input
SDL_GamepadButton Input::getControllerBinding(int controller_index, InputAction input) const SDL_GamepadButton Input::getControllerBinding(int controller_index, InputAction input) const {
{ return controller_bindings_[controller_index][static_cast<int>(input)].button;
return controller_bindings_[controller_index][static_cast<int>(input)].button;
} }
// Obtiene el indice a partir del nombre del mando // Obtiene el indice a partir del nombre del mando
int Input::getIndexByName(const std::string &name) const int Input::getIndexByName(const std::string &name) const {
{ auto it = std::find(controller_names_.begin(), controller_names_.end(), name);
auto it = std::find(controller_names_.begin(), controller_names_.end(), name); return it != controller_names_.end() ? std::distance(controller_names_.begin(), it) : -1;
return it != controller_names_.end() ? std::distance(controller_names_.begin(), it) : -1;
} }
// Convierte un InputAction a std::string // Convierte un InputAction a std::string
std::string Input::to_string(InputAction input) const std::string Input::to_string(InputAction input) const {
{ switch (input) {
switch (input) case InputAction::FIRE_LEFT:
{ return "input_fire_left";
case InputAction::FIRE_LEFT: case InputAction::FIRE_CENTER:
return "input_fire_left"; return "input_fire_center";
case InputAction::FIRE_CENTER: case InputAction::FIRE_RIGHT:
return "input_fire_center"; return "input_fire_right";
case InputAction::FIRE_RIGHT: case InputAction::START:
return "input_fire_right"; return "input_start";
case InputAction::START: case InputAction::SERVICE:
return "input_start"; return "input_service";
case InputAction::SERVICE: default:
return "input_service"; return "";
default: }
return "";
}
} }
// Convierte un std::string a InputAction // Convierte un std::string a InputAction
InputAction Input::to_inputs_e(const std::string &name) const InputAction Input::to_inputs_e(const std::string &name) const {
{ static const std::unordered_map<std::string, InputAction> inputMap = {
static const std::unordered_map<std::string, InputAction> inputMap = { {"input_fire_left", InputAction::FIRE_LEFT},
{"input_fire_left", InputAction::FIRE_LEFT}, {"input_fire_center", InputAction::FIRE_CENTER},
{"input_fire_center", InputAction::FIRE_CENTER}, {"input_fire_right", InputAction::FIRE_RIGHT},
{"input_fire_right", InputAction::FIRE_RIGHT}, {"input_start", InputAction::START},
{"input_start", InputAction::START}, {"input_service", InputAction::SERVICE}};
{"input_service", InputAction::SERVICE}};
auto it = inputMap.find(name); auto it = inputMap.find(name);
return it != inputMap.end() ? it->second : InputAction::NONE; return it != inputMap.end() ? it->second : InputAction::NONE;
} }
// Comprueba el eje del mando // Comprueba el eje del mando
bool Input::checkAxisInput(InputAction input, int controller_index, bool repeat) bool Input::checkAxisInput(InputAction input, int controller_index, bool repeat) {
{ // Umbral para considerar el eje como activo
// Umbral para considerar el eje como activo bool axis_active_now = false;
bool axis_active_now = false;
switch (input) switch (input) {
{ case InputAction::LEFT:
case InputAction::LEFT: axis_active_now = SDL_GetGamepadAxis(connected_controllers_[controller_index], SDL_GAMEPAD_AXIS_LEFTX) < -AXIS_THRESHOLD_;
axis_active_now = SDL_GetGamepadAxis(connected_controllers_[controller_index], SDL_GAMEPAD_AXIS_LEFTX) < -AXIS_THRESHOLD_; break;
break; case InputAction::RIGHT:
case InputAction::RIGHT: axis_active_now = SDL_GetGamepadAxis(connected_controllers_[controller_index], SDL_GAMEPAD_AXIS_LEFTX) > AXIS_THRESHOLD_;
axis_active_now = SDL_GetGamepadAxis(connected_controllers_[controller_index], SDL_GAMEPAD_AXIS_LEFTX) > AXIS_THRESHOLD_; break;
break; case InputAction::UP:
case InputAction::UP: axis_active_now = SDL_GetGamepadAxis(connected_controllers_[controller_index], SDL_GAMEPAD_AXIS_LEFTY) < -AXIS_THRESHOLD_;
axis_active_now = SDL_GetGamepadAxis(connected_controllers_[controller_index], SDL_GAMEPAD_AXIS_LEFTY) < -AXIS_THRESHOLD_; break;
break; case InputAction::DOWN:
case InputAction::DOWN: axis_active_now = SDL_GetGamepadAxis(connected_controllers_[controller_index], SDL_GAMEPAD_AXIS_LEFTY) > AXIS_THRESHOLD_;
axis_active_now = SDL_GetGamepadAxis(connected_controllers_[controller_index], SDL_GAMEPAD_AXIS_LEFTY) > AXIS_THRESHOLD_; break;
break; default:
default: return false;
return false; }
}
// Referencia al binding correspondiente // Referencia al binding correspondiente
auto &binding = controller_bindings_.at(controller_index).at(static_cast<int>(input)); auto &binding = controller_bindings_.at(controller_index).at(static_cast<int>(input));
if (repeat) if (repeat) {
{ // Si se permite repetir, simplemente devolvemos el estado actual
// Si se permite repetir, simplemente devolvemos el estado actual return axis_active_now;
return axis_active_now; } else {
} // Si no se permite repetir, aplicamos la lógica de transición
else if (axis_active_now && !binding.axis_active) {
{ // Transición de inactivo a activo
// Si no se permite repetir, aplicamos la lógica de transición binding.axis_active = true;
if (axis_active_now && !binding.axis_active) return true;
{ } else if (!axis_active_now && binding.axis_active) {
// Transición de inactivo a activo // Transición de activo a inactivo
binding.axis_active = true; binding.axis_active = false;
return true; }
} // Mantener el estado actual
else if (!axis_active_now && binding.axis_active) return false;
{ }
// Transición de activo a inactivo
binding.axis_active = false;
}
// Mantener el estado actual
return false;
}
} }
void Input::initSDLGamePad() void Input::initSDLGamePad() {
{ if (SDL_WasInit(SDL_INIT_GAMEPAD) != 1) {
if (SDL_WasInit(SDL_INIT_GAMEPAD) != 1) if (!SDL_InitSubSystem(SDL_INIT_GAMEPAD)) {
{ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GAMEPAD could not initialize! SDL Error: %s", SDL_GetError());
if (!SDL_InitSubSystem(SDL_INIT_GAMEPAD)) } else {
{ SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "\n** SDL_GAMEPAD: INITIALIZING");
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GAMEPAD could not initialize! SDL Error: %s", SDL_GetError()); discoverGameControllers();
} SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "** SDL_GAMEPAD: INITIALIZATION COMPLETE\n");
else }
{ }
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "\n** SDL_GAMEPAD: INITIALIZING");
discoverGameControllers();
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "** SDL_GAMEPAD: INITIALIZATION COMPLETE\n");
}
}
} }
void Input::resetInputStates() void Input::resetInputStates() {
{ // Resetear todos los KeyBindings.active a false
// Resetear todos los KeyBindings.active a false for (auto &key : key_bindings_) {
for (auto &key : key_bindings_) key.is_held = false;
{ key.just_pressed = false;
key.is_held = false; }
key.just_pressed = false; // Resetear todos los ControllerBindings.active a false
} for (auto &controller_vec : controller_bindings_) {
// Resetear todos los ControllerBindings.active a false for (auto &binding : controller_vec) {
for (auto &controller_vec : controller_bindings_) binding.is_held = false;
{ binding.just_pressed = false;
for (auto &binding : controller_vec) }
{ }
binding.is_held = false;
binding.just_pressed = false;
}
}
} }
void Input::update() void Input::update() {
{ // --- TECLADO ---
// --- TECLADO --- const bool *key_states = SDL_GetKeyboardState(nullptr);
const bool *key_states = SDL_GetKeyboardState(nullptr);
for (size_t i = 0; i < key_bindings_.size(); ++i) for (size_t i = 0; i < key_bindings_.size(); ++i) {
{ bool key_is_down_now = key_states[key_bindings_[i].scancode];
bool key_is_down_now = key_states[key_bindings_[i].scancode];
// El estado .is_held del fotograma anterior nos sirve para saber si es un pulso nuevo // El estado .is_held del fotograma anterior nos sirve para saber si es un pulso nuevo
key_bindings_[i].just_pressed = key_is_down_now && !key_bindings_[i].is_held; key_bindings_[i].just_pressed = key_is_down_now && !key_bindings_[i].is_held;
key_bindings_[i].is_held = key_is_down_now; key_bindings_[i].is_held = key_is_down_now;
} }
// --- MANDOS --- // --- MANDOS ---
for (int c = 0; c < num_gamepads_; ++c) for (int c = 0; c < num_gamepads_; ++c) {
{ for (size_t i = 0; i < controller_bindings_[c].size(); ++i) {
for (size_t i = 0; i < controller_bindings_[c].size(); ++i) bool button_is_down_now = SDL_GetGamepadButton(connected_controllers_.at(c), controller_bindings_.at(c).at(i).button) != 0;
{
bool button_is_down_now = SDL_GetGamepadButton(connected_controllers_.at(c), controller_bindings_.at(c).at(i).button) != 0;
// El estado .is_held del fotograma anterior nos sirve para saber si es un pulso nuevo // El estado .is_held del fotograma anterior nos sirve para saber si es un pulso nuevo
controller_bindings_[c][i].just_pressed = button_is_down_now && !controller_bindings_[c][i].is_held; controller_bindings_[c][i].just_pressed = button_is_down_now && !controller_bindings_[c][i].is_held;
controller_bindings_[c][i].is_held = button_is_down_now; controller_bindings_[c][i].is_held = button_is_down_now;
} }
} }
} }
+112 -116
View File
@@ -1,154 +1,150 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_GamepadButton, Uint8, SDL_Gamepad, SDL_Joystick, SDL_JoystickID, SDL_Scancode, Sint16 #include <SDL3/SDL.h> // Para SDL_GamepadButton, Uint8, SDL_Gamepad, SDL_Joystick, SDL_JoystickID, SDL_Scancode, Sint16
#include <string> // Para basic_string, string
#include <vector> // Para vector #include <string> // Para basic_string, string
#include <vector> // Para vector
/* /*
connectedControllers es un vector donde están todos los mandos encontrados [0 .. n] connectedControllers es un vector donde están todos los mandos encontrados [0 .. n]
checkInput requiere de un índice para comprobar las pulsaciones de un controlador en concreto [0 .. n] checkInput requiere de un índice para comprobar las pulsaciones de un controlador en concreto [0 .. n]
device contiene el tipo de dispositivo a comprobar: device contiene el tipo de dispositivo a comprobar:
InputDeviceToUse::KEYBOARD solo mirará el teclado InputDeviceToUse::KEYBOARD solo mirará el teclado
InputDeviceToUse::CONTROLLER solo mirará el controlador especificado (Si no se especifica, el primero) InputDeviceToUse::CONTROLLER solo mirará el controlador especificado (Si no se especifica, el primero)
InputDeviceToUse::ANY mirará tanto el teclado como el PRIMER controlador InputDeviceToUse::ANY mirará tanto el teclado como el PRIMER controlador
*/ */
// Acciones de entrada posibles en el juego // Acciones de entrada posibles en el juego
enum class InputAction : int enum class InputAction : int {
{ // Inputs de movimiento
// Inputs de movimiento UP,
UP, DOWN,
DOWN, LEFT,
LEFT, RIGHT,
RIGHT,
// Inputs personalizados // Inputs personalizados
FIRE_LEFT, FIRE_LEFT,
FIRE_CENTER, FIRE_CENTER,
FIRE_RIGHT, FIRE_RIGHT,
START, START,
// Service Menu // Service Menu
SM_SELECT, SM_SELECT,
SM_BACK, SM_BACK,
// Inputs de control // Inputs de control
BACK, BACK,
EXIT, EXIT,
PAUSE, PAUSE,
SERVICE, SERVICE,
WINDOW_FULLSCREEN, WINDOW_FULLSCREEN,
WINDOW_INC_SIZE, WINDOW_INC_SIZE,
WINDOW_DEC_SIZE, WINDOW_DEC_SIZE,
TOGGLE_VIDEO_SHADERS, TOGGLE_VIDEO_SHADERS,
TOGGLE_VIDEO_INTEGER_SCALE, TOGGLE_VIDEO_INTEGER_SCALE,
TOGGLE_VIDEO_VSYNC, TOGGLE_VIDEO_VSYNC,
RESET, RESET,
TOGGLE_AUDIO, TOGGLE_AUDIO,
CHANGE_LANG, CHANGE_LANG,
SHOW_INFO, SHOW_INFO,
CONFIG, CONFIG,
SWAP_CONTROLLERS, SWAP_CONTROLLERS,
TOGGLE_AUTO_FIRE, TOGGLE_AUTO_FIRE,
// Input obligatorio // Input obligatorio
NONE, NONE,
SIZE, SIZE,
}; };
constexpr bool INPUT_ALLOW_REPEAT = true; constexpr bool INPUT_ALLOW_REPEAT = true;
constexpr bool INPUT_DO_NOT_ALLOW_REPEAT = false; constexpr bool INPUT_DO_NOT_ALLOW_REPEAT = false;
// Tipos de dispositivos de entrada // Tipos de dispositivos de entrada
enum class InputDevice : int enum class InputDevice : int {
{ KEYBOARD = 0,
KEYBOARD = 0, CONTROLLER = 1,
CONTROLLER = 1, ANY = 2,
ANY = 2,
}; };
// Clase Input: gestiona la entrada de teclado y mandos (singleton) // Clase Input: gestiona la entrada de teclado y mandos (singleton)
class Input class Input {
{ public:
public: // --- Métodos de singleton ---
// --- Métodos de singleton --- static void init(const std::string &game_controller_db_path); // Inicializa el singleton
static void init(const std::string &game_controller_db_path); // Inicializa el singleton static void destroy(); // Libera el singleton
static void destroy(); // Libera el singleton static Input *get(); // Obtiene la instancia
static Input *get(); // Obtiene la instancia
// --- Métodos de configuración de controles --- // --- Métodos de configuración de controles ---
void bindKey(InputAction input, SDL_Scancode code); // Asigna inputs a teclas void bindKey(InputAction input, SDL_Scancode code); // Asigna inputs a teclas
void bindGameControllerButton(int controller_index, InputAction input, SDL_GamepadButton button); // Asigna inputs a botones del mando void bindGameControllerButton(int controller_index, InputAction input, SDL_GamepadButton button); // Asigna inputs a botones del mando
void bindGameControllerButton(int controller_index, InputAction inputTarget, InputAction inputSource); // Asigna inputs a otros inputs del mando void bindGameControllerButton(int controller_index, InputAction inputTarget, InputAction inputSource); // Asigna inputs a otros inputs del mando
// --- Métodos de consulta de entrada --- // --- Métodos de consulta de entrada ---
void update(); // Comprueba fisicamente los botones y teclas que se han pulsado void update(); // Comprueba fisicamente los botones y teclas que se han pulsado
bool checkInput(InputAction input, bool repeat = true, InputDevice device = InputDevice::ANY, int controller_index = 0); // Comprueba si un input está activo bool checkInput(InputAction input, bool repeat = true, InputDevice device = InputDevice::ANY, int controller_index = 0); // Comprueba si un input está activo
bool checkAnyInput(InputDevice device = InputDevice::ANY, int controller_index = 0); // Comprueba si hay al menos un input activo bool checkAnyInput(InputDevice device = InputDevice::ANY, int controller_index = 0); // Comprueba si hay al menos un input activo
int checkAnyButton(bool repeat = INPUT_DO_NOT_ALLOW_REPEAT); // Comprueba si hay algún botón pulsado int checkAnyButton(bool repeat = INPUT_DO_NOT_ALLOW_REPEAT); // Comprueba si hay algún botón pulsado
// --- Métodos de gestión de mandos --- // --- Métodos de gestión de mandos ---
bool discoverGameControllers(); // Busca si hay mandos conectados bool discoverGameControllers(); // Busca si hay mandos conectados
bool gameControllerFound(); // Comprueba si hay algún mando conectado bool gameControllerFound(); // Comprueba si hay algún mando conectado
int getNumControllers() const; // Obtiene el número de mandos conectados int getNumControllers() const; // Obtiene el número de mandos conectados
std::string getControllerName(int controller_index) const; // Obtiene el nombre de un mando de juego std::string getControllerName(int controller_index) const; // Obtiene el nombre de un mando de juego
int getJoyIndex(SDL_JoystickID id) const; // Obtiene el índice del controlador a partir de un event.id int getJoyIndex(SDL_JoystickID id) const; // Obtiene el índice del controlador a partir de un event.id
// --- Métodos de consulta y utilidades --- // --- Métodos de consulta y utilidades ---
void printBindings(InputDevice device = InputDevice::KEYBOARD, int controller_index = 0) const; // Muestra por consola los controles asignados void printBindings(InputDevice device = InputDevice::KEYBOARD, int controller_index = 0) const; // Muestra por consola los controles asignados
SDL_GamepadButton getControllerBinding(int controller_index, InputAction input) const; // Obtiene el SDL_GamepadButton asignado a un input SDL_GamepadButton getControllerBinding(int controller_index, InputAction input) const; // Obtiene el SDL_GamepadButton asignado a un input
std::string to_string(InputAction input) const; // Convierte un InputAction a std::string std::string to_string(InputAction input) const; // Convierte un InputAction a std::string
InputAction to_inputs_e(const std::string &name) const; // Convierte un std::string a InputAction InputAction to_inputs_e(const std::string &name) const; // Convierte un std::string a InputAction
int getIndexByName(const std::string &name) const; // Obtiene el índice a partir del nombre del mando int getIndexByName(const std::string &name) const; // Obtiene el índice a partir del nombre del mando
// --- Métodos de reseteo de estado de entrada --- // --- Métodos de reseteo de estado de entrada ---
void resetInputStates(); // Pone todos los KeyBindings.active y ControllerBindings.active a false void resetInputStates(); // Pone todos los KeyBindings.active y ControllerBindings.active a false
private: private:
// --- Singleton --- // --- Singleton ---
static Input *instance_; static Input *instance_;
// --- Estructuras internas --- // --- Estructuras internas ---
struct KeyBindings struct KeyBindings {
{ Uint8 scancode; // Scancode asociado
Uint8 scancode; // Scancode asociado bool is_held; // Está pulsada ahora mismo
bool is_held; // Está pulsada ahora mismo bool just_pressed; // Se acaba de pulsar en este fotograma
bool just_pressed; // Se acaba de pulsar en este fotograma
KeyBindings(Uint8 scancode = 0, bool is_held = false, bool just_pressed = false) KeyBindings(Uint8 scancode = 0, bool is_held = false, bool just_pressed = false)
: scancode(scancode), is_held(is_held), just_pressed(just_pressed) {} : scancode(scancode), is_held(is_held), just_pressed(just_pressed) {}
}; };
struct ControllerBindings struct ControllerBindings {
{ SDL_GamepadButton button; // GameControllerButton asociado
SDL_GamepadButton button; // GameControllerButton asociado bool is_held; // Está pulsada ahora mismo
bool is_held; // Está pulsada ahora mismo bool just_pressed; // Se acaba de pulsar en este fotograma
bool just_pressed; // Se acaba de pulsar en este fotograma bool axis_active; // Estado del eje
bool axis_active; // Estado del eje
ControllerBindings(SDL_GamepadButton btn = SDL_GAMEPAD_BUTTON_INVALID, bool is_held = false, bool just_pressed = false, bool axis_act = false) ControllerBindings(SDL_GamepadButton btn = SDL_GAMEPAD_BUTTON_INVALID, bool is_held = false, bool just_pressed = false, bool axis_act = false)
: button(btn), is_held(is_held), just_pressed(just_pressed), axis_active(axis_act) {} : button(btn), is_held(is_held), just_pressed(just_pressed), axis_active(axis_act) {}
}; };
// --- Constantes --- // --- Constantes ---
static constexpr Sint16 AXIS_THRESHOLD_ = 30000; static constexpr Sint16 AXIS_THRESHOLD_ = 30000;
// --- Variables internas --- // --- Variables internas ---
std::vector<SDL_Gamepad *> connected_controllers_; // Vector con todos los mandos conectados std::vector<SDL_Gamepad *> connected_controllers_; // Vector con todos los mandos conectados
std::vector<SDL_Joystick *> joysticks_; // Vector con todos los joysticks conectados std::vector<SDL_Joystick *> joysticks_; // Vector con todos los joysticks conectados
std::vector<KeyBindings> key_bindings_; // Vector con las teclas asociadas a los inputs predefinidos std::vector<KeyBindings> key_bindings_; // Vector con las teclas asociadas a los inputs predefinidos
std::vector<std::vector<ControllerBindings>> controller_bindings_; // Vector con los botones asociados a los inputs predefinidos para cada mando std::vector<std::vector<ControllerBindings>> controller_bindings_; // Vector con los botones asociados a los inputs predefinidos para cada mando
std::vector<std::string> controller_names_; // Vector con los nombres de los mandos std::vector<std::string> controller_names_; // Vector con los nombres de los mandos
std::vector<InputAction> button_inputs_; // Inputs asignados al jugador y a botones, excluyendo direcciones std::vector<InputAction> button_inputs_; // Inputs asignados al jugador y a botones, excluyendo direcciones
int num_joysticks_ = 0; // Número de joysticks conectados int num_joysticks_ = 0; // Número de joysticks conectados
int num_gamepads_ = 0; // Número de mandos conectados int num_gamepads_ = 0; // Número de mandos conectados
std::string game_controller_db_path_; // Ruta al archivo gamecontrollerdb.txt std::string game_controller_db_path_; // Ruta al archivo gamecontrollerdb.txt
// --- Métodos internos --- // --- Métodos internos ---
void initSDLGamePad(); // Inicializa SDL para la gestión de mandos void initSDLGamePad(); // Inicializa SDL para la gestión de mandos
bool checkAxisInput(InputAction input, int controller_index, bool repeat); // Comprueba el eje del mando bool checkAxisInput(InputAction input, int controller_index, bool repeat); // Comprueba el eje del mando
// --- Constructor y destructor --- // --- Constructor y destructor ---
explicit Input(const std::string &game_controller_db_path); // Constructor privado explicit Input(const std::string &game_controller_db_path); // Constructor privado
~Input() = default; // Destructor privado ~Input() = default; // Destructor privado
}; };
+163 -204
View File
@@ -1,249 +1,208 @@
#include "item.h" #include "item.h"
#include <stdlib.h> // Para rand #include <stdlib.h> // Para rand
#include <algorithm> // Para clamp
#include "animated_sprite.h" // Para AnimatedSprite #include <algorithm> // Para clamp
#include "param.h" // Para Param, ParamGame, param
class Texture; // lines 6-6 #include "animated_sprite.h" // Para AnimatedSprite
#include "param.h" // Para Param, ParamGame, param
class Texture; // lines 6-6
Item::Item(ItemType type, float x, float y, SDL_FRect &play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation) Item::Item(ItemType type, float x, float y, SDL_FRect &play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation)
: sprite_(std::make_unique<AnimatedSprite>(texture, animation)), : sprite_(std::make_unique<AnimatedSprite>(texture, animation)),
type_(type), type_(type),
play_area_(play_area) play_area_(play_area) {
{ switch (type) {
switch (type) case ItemType::COFFEE_MACHINE: {
{ width_ = COFFEE_MACHINE_WIDTH;
case ItemType::COFFEE_MACHINE: height_ = COFFEE_MACHINE_HEIGHT;
{ pos_x_ = getCoffeeMachineSpawn(x, width_, play_area_.w);
width_ = COFFEE_MACHINE_WIDTH; pos_y_ = y;
height_ = COFFEE_MACHINE_HEIGHT; vel_x_ = ((rand() % 3) - 1) * 0.5f;
pos_x_ = getCoffeeMachineSpawn(x, width_, play_area_.w); vel_y_ = -0.1f;
pos_y_ = y; accel_y_ = 0.1f;
vel_x_ = ((rand() % 3) - 1) * 0.5f; collider_.r = 10;
vel_y_ = -0.1f; break;
accel_y_ = 0.1f; }
collider_.r = 10; default: {
break; width_ = param.game.item_size;
} height_ = param.game.item_size;
default: pos_x_ = x;
{ pos_y_ = y;
width_ = param.game.item_size; vel_x_ = -1.0f + ((rand() % 5) * 0.5f);
height_ = param.game.item_size; vel_y_ = -4.0f;
pos_x_ = x; accel_y_ = 0.2f;
pos_y_ = y; collider_.r = width_ / 2;
vel_x_ = -1.0f + ((rand() % 5) * 0.5f); break;
vel_y_ = -4.0f; }
accel_y_ = 0.2f; }
collider_.r = width_ / 2;
break;
}
}
// Actualiza el sprite // Actualiza el sprite
shiftSprite(); shiftSprite();
shiftColliders(); shiftColliders();
} }
void Item::alignTo(int x) void Item::alignTo(int x) {
{ const float min_x = param.game.play_area.rect.x + 1;
const float min_x = param.game.play_area.rect.x + 1; const float max_x = play_area_.w - width_ - 1;
const float max_x = play_area_.w - width_ - 1;
pos_x_ = x - (width_ / 2); pos_x_ = x - (width_ / 2);
// Ajusta para que no quede fuera de la zona de juego // Ajusta para que no quede fuera de la zona de juego
pos_x_ = std::clamp(pos_x_, min_x, max_x); pos_x_ = std::clamp(pos_x_, min_x, max_x);
// Actualiza el sprite // Actualiza el sprite
shiftSprite(); shiftSprite();
shiftColliders(); shiftColliders();
} }
void Item::render() void Item::render() {
{ if (enabled_) {
if (enabled_) if (time_to_live_ > 200) {
{ sprite_->render();
if (time_to_live_ > 200) } else if (time_to_live_ % 20 > 10) {
{ sprite_->render();
sprite_->render(); }
} }
else if (time_to_live_ % 20 > 10)
{
sprite_->render();
}
}
} }
void Item::move() void Item::move() {
{ floor_collision_ = false;
floor_collision_ = false;
// Calcula la nueva posición // Calcula la nueva posición
pos_x_ += vel_x_; pos_x_ += vel_x_;
pos_y_ += vel_y_; pos_y_ += vel_y_;
// Aplica las aceleraciones a la velocidad // Aplica las aceleraciones a la velocidad
vel_x_ += accel_x_; vel_x_ += accel_x_;
vel_y_ += accel_y_; vel_y_ += accel_y_;
// Comprueba los laterales de la zona de juego // Comprueba los laterales de la zona de juego
const float MIN_X = param.game.play_area.rect.x; const float MIN_X = param.game.play_area.rect.x;
const float MAX_X = play_area_.w - width_; const float MAX_X = play_area_.w - width_;
pos_x_ = std::clamp(pos_x_, MIN_X, MAX_X); pos_x_ = std::clamp(pos_x_, MIN_X, MAX_X);
// Si toca el borde lateral, invierte la velocidad horizontal // Si toca el borde lateral, invierte la velocidad horizontal
if (pos_x_ == MIN_X || pos_x_ == MAX_X) if (pos_x_ == MIN_X || pos_x_ == MAX_X) {
{ vel_x_ = -vel_x_;
vel_x_ = -vel_x_; }
}
// Si colisiona por arriba, rebota (excepto la máquina de café) // Si colisiona por arriba, rebota (excepto la máquina de café)
if ((pos_y_ < param.game.play_area.rect.y) && !(type_ == ItemType::COFFEE_MACHINE)) if ((pos_y_ < param.game.play_area.rect.y) && !(type_ == ItemType::COFFEE_MACHINE)) {
{ // Corrige
// Corrige pos_y_ = param.game.play_area.rect.y;
pos_y_ = param.game.play_area.rect.y;
// Invierte la velocidad // Invierte la velocidad
vel_y_ = -vel_y_; vel_y_ = -vel_y_;
} }
// Si colisiona con la parte inferior // Si colisiona con la parte inferior
if (pos_y_ > play_area_.h - height_) if (pos_y_ > play_area_.h - height_) {
{ // Corrige la posición
// Corrige la posición pos_y_ = play_area_.h - height_;
pos_y_ = play_area_.h - height_;
switch (type_) switch (type_) {
{ case ItemType::COFFEE_MACHINE:
case ItemType::COFFEE_MACHINE: // La máquina de café es mas pesada y tiene una fisica diferente, ademas hace ruido
// La máquina de café es mas pesada y tiene una fisica diferente, ademas hace ruido floor_collision_ = true;
floor_collision_ = true; if (vel_y_ < 1.0f) {
if (vel_y_ < 1.0f) // Si la velocidad vertical es baja, detiene el objeto
{ vel_y_ = vel_x_ = accel_x_ = accel_y_ = 0;
// Si la velocidad vertical es baja, detiene el objeto } else {
vel_y_ = vel_x_ = accel_x_ = accel_y_ = 0; // Si la velocidad vertical es alta, el objeto rebota y pierde velocidad
} vel_y_ *= -0.20f;
else vel_x_ *= 0.75f;
{ }
// Si la velocidad vertical es alta, el objeto rebota y pierde velocidad break;
vel_y_ *= -0.20f; default:
vel_x_ *= 0.75f; // Si no es una máquina de café
} if (vel_y_ < 1.0f) {
break; // Si la velocidad vertical es baja, detiene el objeto
default: vel_y_ = vel_x_ = accel_x_ = accel_y_ = 0;
// Si no es una máquina de café } else {
if (vel_y_ < 1.0f) // Si la velocidad vertical es alta, el objeto rebota y pierde velocidad
{ vel_y_ *= -0.5f;
// Si la velocidad vertical es baja, detiene el objeto vel_x_ *= 0.75f;
vel_y_ = vel_x_ = accel_x_ = accel_y_ = 0; }
} break;
else }
{ }
// Si la velocidad vertical es alta, el objeto rebota y pierde velocidad
vel_y_ *= -0.5f;
vel_x_ *= 0.75f;
}
break;
}
}
// Actualiza la posición del sprite // Actualiza la posición del sprite
shiftSprite(); shiftSprite();
shiftColliders(); shiftColliders();
} }
void Item::disable() { enabled_ = false; } void Item::disable() { enabled_ = false; }
void Item::update() void Item::update() {
{ move();
move(); sprite_->update();
sprite_->update(); updateTimeToLive();
updateTimeToLive();
} }
void Item::updateTimeToLive() void Item::updateTimeToLive() {
{ if (time_to_live_ > 0) {
if (time_to_live_ > 0) time_to_live_--;
{ } else {
time_to_live_--; disable();
} }
else
{
disable();
}
} }
void Item::shiftColliders() void Item::shiftColliders() {
{ collider_.x = static_cast<int>(pos_x_ + (width_ / 2));
collider_.x = static_cast<int>(pos_x_ + (width_ / 2)); collider_.y = static_cast<int>(pos_y_ + (height_ / 2));
collider_.y = static_cast<int>(pos_y_ + (height_ / 2));
} }
void Item::shiftSprite() void Item::shiftSprite() {
{ sprite_->setPosX(pos_x_);
sprite_->setPosX(pos_x_); sprite_->setPosY(pos_y_);
sprite_->setPosY(pos_y_);
} }
// Calcula la zona de aparición de la máquina de café // Calcula la zona de aparición de la máquina de café
int Item::getCoffeeMachineSpawn(int player_x, int item_width, int area_width, int margin) int Item::getCoffeeMachineSpawn(int player_x, int item_width, int area_width, int margin) {
{ // Distancia mínima del jugador (ajusta según necesites)
// Distancia mínima del jugador (ajusta según necesites) const int MIN_DISTANCE_FROM_PLAYER = area_width / 2;
const int MIN_DISTANCE_FROM_PLAYER = area_width / 2;
const int LEFT_BOUND = margin; const int LEFT_BOUND = margin;
const int RIGHT_BOUND = area_width - item_width - margin; const int RIGHT_BOUND = area_width - item_width - margin;
// Calcular zona de exclusión alrededor del jugador // Calcular zona de exclusión alrededor del jugador
int exclude_left = player_x - MIN_DISTANCE_FROM_PLAYER; int exclude_left = player_x - MIN_DISTANCE_FROM_PLAYER;
int exclude_right = player_x + MIN_DISTANCE_FROM_PLAYER; int exclude_right = player_x + MIN_DISTANCE_FROM_PLAYER;
// Verificar si hay espacio suficiente a la izquierda // Verificar si hay espacio suficiente a la izquierda
bool can_spawn_left = (exclude_left > LEFT_BOUND) && (exclude_left - LEFT_BOUND > item_width); bool can_spawn_left = (exclude_left > LEFT_BOUND) && (exclude_left - LEFT_BOUND > item_width);
// Verificar si hay espacio suficiente a la derecha // Verificar si hay espacio suficiente a la derecha
bool can_spawn_right = (exclude_right < RIGHT_BOUND) && (RIGHT_BOUND - exclude_right > item_width); bool can_spawn_right = (exclude_right < RIGHT_BOUND) && (RIGHT_BOUND - exclude_right > item_width);
if (can_spawn_left && can_spawn_right) if (can_spawn_left && can_spawn_right) {
{ // Ambos lados disponibles, elegir aleatoriamente
// Ambos lados disponibles, elegir aleatoriamente if (rand() % 2 == 0) {
if (rand() % 2 == 0) // Lado izquierdo
{ return rand() % (exclude_left - LEFT_BOUND) + LEFT_BOUND;
// Lado izquierdo } else {
return rand() % (exclude_left - LEFT_BOUND) + LEFT_BOUND; // Lado derecho
} return rand() % (RIGHT_BOUND - exclude_right) + exclude_right;
else }
{ } else if (can_spawn_left) {
// Lado derecho // Solo lado izquierdo disponible
return rand() % (RIGHT_BOUND - exclude_right) + exclude_right; return rand() % (exclude_left - LEFT_BOUND) + LEFT_BOUND;
} } else if (can_spawn_right) {
} // Solo lado derecho disponible
else if (can_spawn_left) return rand() % (RIGHT_BOUND - exclude_right) + exclude_right;
{ } else {
// Solo lado izquierdo disponible // No hay espacio suficiente lejos del jugador
return rand() % (exclude_left - LEFT_BOUND) + LEFT_BOUND; // Por ahora, intentar spawn en el extremo más lejano posible
} int distance_to_left = abs(player_x - LEFT_BOUND);
else if (can_spawn_right) int distance_to_right = abs(RIGHT_BOUND - player_x);
{
// Solo lado derecho disponible
return rand() % (RIGHT_BOUND - exclude_right) + exclude_right;
}
else
{
// No hay espacio suficiente lejos del jugador
// Por ahora, intentar spawn en el extremo más lejano posible
int distance_to_left = abs(player_x - LEFT_BOUND);
int distance_to_right = abs(RIGHT_BOUND - player_x);
if (distance_to_left > distance_to_right) if (distance_to_left > distance_to_right) {
{ return LEFT_BOUND;
return LEFT_BOUND; } else {
} return RIGHT_BOUND - item_width;
else }
{ }
return RIGHT_BOUND - item_width;
}
}
} }
+34 -35
View File
@@ -1,34 +1,33 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_FRect, Uint16 #include <SDL3/SDL.h> // Para SDL_FRect, Uint16
#include <memory> // Para shared_ptr, unique_ptr
#include <string> // Para string
#include <vector> // Para vector
#include "animated_sprite.h" // Para AnimatedSprite #include <memory> // Para shared_ptr, unique_ptr
#include "utils.h" // Para Circle #include <string> // Para string
#include <vector> // Para vector
#include "animated_sprite.h" // Para AnimatedSprite
#include "utils.h" // Para Circle
class Texture; class Texture;
// Tipos de objetos disponibles en el juego. // Tipos de objetos disponibles en el juego.
// Define los diferentes tipos de objetos que pueden existir en el juego. // Define los diferentes tipos de objetos que pueden existir en el juego.
enum class ItemType : int enum class ItemType : int {
{ DISK = 1, // Disco
DISK = 1, // Disco GAVINA = 2, // Gavina
GAVINA = 2, // Gavina PACMAR = 3, // Pacman
PACMAR = 3, // Pacman CLOCK = 4, // Reloj
CLOCK = 4, // Reloj COFFEE = 5, // Café
COFFEE = 5, // Café DEBIAN = 6, // Debian
DEBIAN = 6, // Debian COFFEE_MACHINE = 7, // Máquina de café
COFFEE_MACHINE = 7, // Máquina de café NONE = 8, // Ninguno
NONE = 8, // Ninguno
}; };
// Clase Item. // Clase Item.
// Representa un objeto en el juego, con sus propiedades y métodos para gestionar su comportamiento. // Representa un objeto en el juego, con sus propiedades y métodos para gestionar su comportamiento.
class Item class Item {
{ public:
public:
// Constantes // Constantes
static constexpr int COFFEE_MACHINE_WIDTH = 30; static constexpr int COFFEE_MACHINE_WIDTH = 30;
static constexpr int COFFEE_MACHINE_HEIGHT = 39; static constexpr int COFFEE_MACHINE_HEIGHT = 39;
@@ -64,25 +63,25 @@ public:
bool isOnFloor() const { return floor_collision_; } bool isOnFloor() const { return floor_collision_; }
Circle &getCollider() { return collider_; } Circle &getCollider() { return collider_; }
private: private:
// Objetos y punteros // Objetos y punteros
std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos del objeto std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos del objeto
// Variables de estado y físicas // Variables de estado y físicas
float pos_x_; // Posición X del objeto float pos_x_; // Posición X del objeto
float pos_y_; // Posición Y del objeto float pos_y_; // Posición Y del objeto
int width_; // Ancho del objeto int width_; // Ancho del objeto
int height_; // Alto del objeto int height_; // Alto del objeto
float vel_x_; // Velocidad en el eje X float vel_x_; // Velocidad en el eje X
float vel_y_; // Velocidad en el eje Y float vel_y_; // Velocidad en el eje Y
float accel_x_ = 0.0f; // Aceleración en el eje X float accel_x_ = 0.0f; // Aceleración en el eje X
float accel_y_; // Aceleración en el eje Y float accel_y_; // Aceleración en el eje Y
bool floor_collision_ = false; // Indica si el objeto colisiona con el suelo bool floor_collision_ = false; // Indica si el objeto colisiona con el suelo
ItemType type_; // Tipo de objeto ItemType type_; // Tipo de objeto
bool enabled_ = true; // Indica si el objeto está habilitado bool enabled_ = true; // Indica si el objeto está habilitado
Circle collider_; // Círculo de colisión del objeto Circle collider_; // Círculo de colisión del objeto
SDL_FRect play_area_; // Rectángulo con la zona de juego SDL_FRect play_area_; // Rectángulo con la zona de juego
Uint16 time_to_live_ = 600; // Tiempo que el objeto está presente Uint16 time_to_live_ = 600; // Tiempo que el objeto está presente
// Alinea el círculo de colisión con la posición del objeto. // Alinea el círculo de colisión con la posición del objeto.
// Actualiza las coordenadas X e Y del colisionador. // Actualiza las coordenadas X e Y del colisionador.
+102 -126
View File
@@ -1,123 +1,105 @@
#include "lang.h" #include "lang.h"
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <exception> // Para exception
#include <fstream> // Para basic_ifstream, basic_istream, ifstream
#include <unordered_map> // Para unordered_map, _Node_iterator, operator==
#include <utility> // Para pair
#include <vector> // Para vector
#include "asset.h" // Para Asset #include <exception> // Para exception
#include "external/json.hpp" // Para basic_json, iteration_proxy_value, oper... #include <fstream> // Para basic_ifstream, basic_istream, ifstream
#include "options.h" // Para Difficulty, DifficultyCode, SettingsOpt... #include <unordered_map> // Para unordered_map, _Node_iterator, operator==
#include <utility> // Para pair
#include <vector> // Para vector
#include "asset.h" // Para Asset
#include "external/json.hpp" // Para basic_json, iteration_proxy_value, oper...
#include "options.h" // Para Difficulty, DifficultyCode, SettingsOpt...
using json = nlohmann::json; using json = nlohmann::json;
namespace Lang namespace Lang {
{ std::unordered_map<std::string, std::string> texts;
std::unordered_map<std::string, std::string> texts;
// Vector con los idiomas soportados // Vector con los idiomas soportados
std::vector<Language> languages = { std::vector<Language> languages = {
{Code::SPANISH, "Castellano", "es_ES.json"}, {Code::SPANISH, "Castellano", "es_ES.json"},
{Code::VALENCIAN, "Balooncia", "ba_BA.json"}, {Code::VALENCIAN, "Balooncia", "ba_BA.json"},
{Code::ENGLISH, "Ingles", "en_UK.json"}}; {Code::ENGLISH, "Ingles", "en_UK.json"}};
// Inicializa los textos del juego en el idioma seleccionado // Inicializa los textos del juego en el idioma seleccionado
bool loadFromFile(const std::string &file_path) bool loadFromFile(const std::string &file_path) {
{ texts.clear();
texts.clear();
std::ifstream rfile(file_path); std::ifstream rfile(file_path);
if (!rfile.is_open()) if (!rfile.is_open())
return false; return false;
try try {
{ json j;
json j; rfile >> j;
rfile >> j;
for (auto &el : j.items()) for (auto &el : j.items()) {
{ texts[el.key()] = el.value();
texts[el.key()] = el.value();
}
} }
catch (const std::exception &e) } catch (const std::exception &e) {
{ // Puedes loguear el error si quieres
// Puedes loguear el error si quieres return false;
return false;
}
return true;
} }
// Obtiene el texto por clave return true;
std::string getText(const std::string &key) }
{
auto it = texts.find(key);
if (it != texts.end())
return it->second;
else
return "[missing text: " + key + "]";
}
// Obtiene el código del siguiente idioma disponible // Obtiene el texto por clave
Code getNextLangCode(Code lang) std::string getText(const std::string &key) {
{ auto it = texts.find(key);
for (size_t i = 0; i < languages.size(); ++i) if (it != texts.end())
{ return it->second;
if (languages[i].code == lang) else
{ return "[missing text: " + key + "]";
return languages[(i + 1) % languages.size()].code; }
}
// Obtiene el código del siguiente idioma disponible
Code getNextLangCode(Code lang) {
for (size_t i = 0; i < languages.size(); ++i) {
if (languages[i].code == lang) {
return languages[(i + 1) % languages.size()].code;
} }
// Si no se encuentra, devuelve el primero por defecto
return languages[0].code;
} }
// Si no se encuentra, devuelve el primero por defecto
return languages[0].code;
}
// Obtiene un idioma del vector de idiomas a partir de un código // Obtiene un idioma del vector de idiomas a partir de un código
Language getLanguage(Code code) Language getLanguage(Code code) {
{ for (const auto &lang : languages) {
for (const auto &lang : languages) if (lang.code == code)
{ return lang;
if (lang.code == code)
return lang;
}
// Si no se encuentra, devuelve el primero por defecto
return languages[0];
} }
// Si no se encuentra, devuelve el primero por defecto
return languages[0];
}
// Devuelve el código de un idioma a partir de un nombre // Devuelve el código de un idioma a partir de un nombre
Code getCodeFromName(const std::string &name) Code getCodeFromName(const std::string &name) {
{ for (const auto &lang : languages) {
for (const auto &lang : languages) if (lang.name == name)
{ return lang.code;
if (lang.name == name)
return lang.code;
}
// Si no se encuentra, devuelve el primero por defecto
return languages[0].code;
} }
// Si no se encuentra, devuelve el primero por defecto
return languages[0].code;
}
// Devuelve el nombre de un idioma a partir de un código // Devuelve el nombre de un idioma a partir de un código
std::string getNameFromCode(Code code) std::string getNameFromCode(Code code) {
{ for (const auto &lang : languages) {
for (const auto &lang : languages) if (lang.code == code)
{ return lang.name;
if (lang.code == code)
return lang.name;
}
// Si no se encuentra, devuelve el nombre del primer idioma por defecto
return languages[0].name;
} }
// Si no se encuentra, devuelve el nombre del primer idioma por defecto
return languages[0].name;
}
// Actualiza los nombres de los idiomas // Actualiza los nombres de los idiomas
void updateLanguageNames() void updateLanguageNames() {
{ for (auto &lang : languages) {
for (auto &lang : languages) switch (lang.code) {
{
switch (lang.code)
{
case Code::SPANISH: case Code::SPANISH:
lang.name = Lang::getText("[SERVICE_MENU] LANG_ES"); lang.name = Lang::getText("[SERVICE_MENU] LANG_ES");
break; break;
@@ -130,17 +112,14 @@ namespace Lang
default: default:
lang.name = "Unknown"; lang.name = "Unknown";
break; break;
}
} }
} }
}
// Actualiza los nombres de las dificultades // Actualiza los nombres de las dificultades
void updateDifficultyNames() void updateDifficultyNames() {
{ for (auto &difficulty : Options::difficulties) {
for (auto &difficulty : Options::difficulties) switch (difficulty.code) {
{
switch (difficulty.code)
{
case Options::DifficultyCode::EASY: case Options::DifficultyCode::EASY:
difficulty.name = Lang::getText("[SERVICE_MENU] EASY"); difficulty.name = Lang::getText("[SERVICE_MENU] EASY");
break; break;
@@ -153,28 +132,25 @@ namespace Lang
default: default:
difficulty.name = "Unknown"; difficulty.name = "Unknown";
break; break;
}
} }
} }
// Obtiene una fichero a partir de un lang::Code
std::string getLanguageFileName(Lang::Code code)
{
for (const auto &lang : languages)
{
if (lang.code == code)
return Asset::get()->get(lang.file_name);
}
// Si no se encuentra, devuelve el fichero del primer idioma por defecto
return Asset::get()->get(languages[0].file_name);
}
// Establece el idioma
void setLanguage(Code lang)
{
Options::settings.language = lang;
loadFromFile(Asset::get()->get(getLanguage(lang).file_name));
updateLanguageNames();
updateDifficultyNames();
}
} }
// Obtiene una fichero a partir de un lang::Code
std::string getLanguageFileName(Lang::Code code) {
for (const auto &lang : languages) {
if (lang.code == code)
return Asset::get()->get(lang.file_name);
}
// Si no se encuentra, devuelve el fichero del primer idioma por defecto
return Asset::get()->get(languages[0].file_name);
}
// Establece el idioma
void setLanguage(Code lang) {
Options::settings.language = lang;
loadFromFile(Asset::get()->get(getLanguage(lang).file_name));
updateLanguageNames();
updateDifficultyNames();
}
} // namespace Lang
+35 -38
View File
@@ -1,52 +1,49 @@
#pragma once #pragma once
#include <string> // Para string, basic_string #include <string> // Para string, basic_string
namespace Lang namespace Lang {
{ // --- Códigos de idioma soportados ---
// --- Códigos de idioma soportados --- enum class Code : int {
enum class Code : int SPANISH = 0,
{ VALENCIAN = 1,
SPANISH = 0, ENGLISH = 2
VALENCIAN = 1, };
ENGLISH = 2
};
// Estructura que representa un idioma // Estructura que representa un idioma
struct Language struct Language {
{ Code code; // Código que identifica al idioma
Code code; // Código que identifica al idioma std::string name; // Nombre que identifica el idioma
std::string name; // Nombre que identifica el idioma std::string file_name; // Nombre del fichero con los textos
std::string file_name; // Nombre del fichero con los textos
Language(Code c, const std::string &n, const std::string &fn) Language(Code c, const std::string &n, const std::string &fn)
: code(c), name(n), file_name(fn) {} : code(c), name(n), file_name(fn) {}
}; };
// Carga los textos desde el fichero JSON especificado // Carga los textos desde el fichero JSON especificado
bool loadFromFile(const std::string &file_path); bool loadFromFile(const std::string &file_path);
// Obtiene el texto por clave // Obtiene el texto por clave
std::string getText(const std::string &key); std::string getText(const std::string &key);
// Obtiene el código del siguiente idioma (circular) // Obtiene el código del siguiente idioma (circular)
Code getNextLangCode(Code current_lang); Code getNextLangCode(Code current_lang);
// Obtiene el idioma correspondiente al código proporcionado // Obtiene el idioma correspondiente al código proporcionado
Language getLanguage(Code code); Language getLanguage(Code code);
// Devuelve el código de un idioma a partir de un nombre // Devuelve el código de un idioma a partir de un nombre
Code getCodeFromName(const std::string &name); Code getCodeFromName(const std::string &name);
// Devuelve el nombre de un idioma a partir de un código // Devuelve el nombre de un idioma a partir de un código
std::string getNameFromCode(Code code); std::string getNameFromCode(Code code);
// Actualiza los nombres de los idiomas // Actualiza los nombres de los idiomas
void updateLanguageNames(); void updateLanguageNames();
// Obtiene el nombre del fichero de textos asociado a un código de idioma // Obtiene el nombre del fichero de textos asociado a un código de idioma
std::string getLanguageFileName(Code code); std::string getLanguageFileName(Code code);
// Establece el idioma actual // Establece el idioma actual
void setLanguage(Code lang); void setLanguage(Code lang);
} } // namespace Lang
+3 -4
View File
@@ -7,12 +7,11 @@ Actualizando a la versión "Arcade Edition" en 08/05/2024
*/ */
#include <memory> // Para make_unique, unique_ptr #include <memory> // Para make_unique, unique_ptr
#include "director.h" // Para Director #include "director.h" // Para Director
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{
// Crea el objeto Director // Crea el objeto Director
auto director = std::make_unique<Director>(argc, const_cast<const char **>(argv)); auto director = std::make_unique<Director>(argc, const_cast<const char **>(argv));
+23 -39
View File
@@ -1,14 +1,14 @@
#include "manage_hiscore_table.h" #include "manage_hiscore_table.h"
#include <SDL3/SDL.h> // Para SDL_ReadIO, SDL_WriteIO, SDL_CloseIO, SDL_GetE... #include <SDL3/SDL.h> // Para SDL_ReadIO, SDL_WriteIO, SDL_CloseIO, SDL_GetE...
#include <algorithm> // Para find_if, sort #include <algorithm> // Para find_if, sort
#include <iterator> // Para distance #include <iterator> // Para distance
#include "utils.h" // Para getFileName #include "utils.h" // Para getFileName
// Resetea la tabla a los valores por defecto // Resetea la tabla a los valores por defecto
void ManageHiScoreTable::clear() void ManageHiScoreTable::clear() {
{
// Limpia la tabla // Limpia la tabla
table_.clear(); table_.clear();
@@ -28,8 +28,7 @@ void ManageHiScoreTable::clear()
} }
// Añade un elemento a la tabla // Añade un elemento a la tabla
int ManageHiScoreTable::add(const HiScoreEntry &entry) int ManageHiScoreTable::add(const HiScoreEntry &entry) {
{
// Añade la entrada a la tabla // Añade la entrada a la tabla
table_.push_back(entry); table_.push_back(entry);
@@ -37,26 +36,22 @@ int ManageHiScoreTable::add(const HiScoreEntry &entry)
sort(); sort();
// Encontrar la posición del nuevo elemento // Encontrar la posición del nuevo elemento
auto it = std::find_if(table_.begin(), table_.end(), [&](const HiScoreEntry &e) auto it = std::find_if(table_.begin(), table_.end(), [&](const HiScoreEntry &e) { return e.name == entry.name &&
{ return e.name == entry.name && e.score == entry.score &&
e.score == entry.score && e.one_credit_complete == entry.one_credit_complete; });
e.one_credit_complete == entry.one_credit_complete; });
int position = -1; int position = -1;
if (it != table_.end()) if (it != table_.end()) {
{
position = std::distance(table_.begin(), it); position = std::distance(table_.begin(), it);
} }
// Deja solo las 10 primeras entradas // Deja solo las 10 primeras entradas
if (table_.size() > 10) if (table_.size() > 10) {
{
table_.resize(10); table_.resize(10);
// Si el nuevo elemento quedó fuera del top 10 // Si el nuevo elemento quedó fuera del top 10
if (position >= 10) if (position >= 10) {
{ position = -1; // No entró en el top 10
position = -1; // No entró en el top 10
} }
} }
@@ -65,8 +60,7 @@ int ManageHiScoreTable::add(const HiScoreEntry &entry)
} }
// Ordena la tabla // Ordena la tabla
void ManageHiScoreTable::sort() void ManageHiScoreTable::sort() {
{
struct struct
{ {
bool operator()(const HiScoreEntry &a, const HiScoreEntry &b) const { return a.score > b.score; } bool operator()(const HiScoreEntry &a, const HiScoreEntry &b) const { return a.score > b.score; }
@@ -76,23 +70,20 @@ void ManageHiScoreTable::sort()
} }
// Carga la tabla desde un fichero // Carga la tabla desde un fichero
bool ManageHiScoreTable::loadFromFile(const std::string &file_path) bool ManageHiScoreTable::loadFromFile(const std::string &file_path) {
{
clear(); clear();
auto success = true; auto success = true;
auto file = SDL_IOFromFile(file_path.c_str(), "rb"); auto file = SDL_IOFromFile(file_path.c_str(), "rb");
if (file) if (file) {
{ table_.clear(); // Limpia la tabla actual
table_.clear(); // Limpia la tabla actual
// Lee el número de entradas en la tabla // Lee el número de entradas en la tabla
int table_size = 0; int table_size = 0;
SDL_ReadIO(file, &table_size, sizeof(int)); SDL_ReadIO(file, &table_size, sizeof(int));
// Lee los datos de cada entrada // Lee los datos de cada entrada
for (int i = 0; i < table_size; ++i) for (int i = 0; i < table_size; ++i) {
{
HiScoreEntry entry; HiScoreEntry entry;
// Lee la puntuación // Lee la puntuación
@@ -104,7 +95,7 @@ bool ManageHiScoreTable::loadFromFile(const std::string &file_path)
std::vector<char> name_buffer(name_size + 1); std::vector<char> name_buffer(name_size + 1);
SDL_ReadIO(file, name_buffer.data(), name_size); SDL_ReadIO(file, name_buffer.data(), name_size);
name_buffer[name_size] = '\0'; // Asegurar el fin de la cadena name_buffer[name_size] = '\0'; // Asegurar el fin de la cadena
entry.name = std::string(name_buffer.data()); entry.name = std::string(name_buffer.data());
// Lee el valor de one_credit_complete // Lee el valor de one_credit_complete
@@ -118,9 +109,7 @@ bool ManageHiScoreTable::loadFromFile(const std::string &file_path)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\nReading file: %s", getFileName(file_path).c_str()); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\nReading file: %s", getFileName(file_path).c_str());
SDL_CloseIO(file); SDL_CloseIO(file);
} } else {
else
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Unable to load %s file! %s", getFileName(file_path).c_str(), SDL_GetError()); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Unable to load %s file! %s", getFileName(file_path).c_str(), SDL_GetError());
success = false; success = false;
} }
@@ -128,20 +117,17 @@ bool ManageHiScoreTable::loadFromFile(const std::string &file_path)
} }
// Guarda la tabla en un fichero // Guarda la tabla en un fichero
bool ManageHiScoreTable::saveToFile(const std::string &file_path) bool ManageHiScoreTable::saveToFile(const std::string &file_path) {
{
auto success = true; auto success = true;
auto file = SDL_IOFromFile(file_path.c_str(), "w+b"); auto file = SDL_IOFromFile(file_path.c_str(), "w+b");
if (file) if (file) {
{
// Guarda el número de entradas en la tabla // Guarda el número de entradas en la tabla
int table_size = static_cast<int>(table_.size()); int table_size = static_cast<int>(table_.size());
SDL_WriteIO(file, &table_size, sizeof(int)); SDL_WriteIO(file, &table_size, sizeof(int));
// Guarda los datos de cada entrada // Guarda los datos de cada entrada
for (int i = 0; i < table_size; ++i) for (int i = 0; i < table_size; ++i) {
{
const HiScoreEntry &entry = table_.at(i); const HiScoreEntry &entry = table_.at(i);
// Guarda la puntuación // Guarda la puntuación
@@ -159,9 +145,7 @@ bool ManageHiScoreTable::saveToFile(const std::string &file_path)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Writing file: %s", getFileName(file_path).c_str()); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Writing file: %s", getFileName(file_path).c_str());
SDL_CloseIO(file); SDL_CloseIO(file);
} } else {
else
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Unable to save %s file! %s", getFileName(file_path).c_str(), SDL_GetError()); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Unable to save %s file! %s", getFileName(file_path).c_str(), SDL_GetError());
success = false; success = false;
} }
+9 -11
View File
@@ -1,7 +1,7 @@
#pragma once #pragma once
#include <string> // Para std::string #include <string> // Para std::string
#include <vector> // Para std::vector #include <vector> // Para std::vector
/* /*
Esta clase sirve para añadir elementos HiScoreEntry a un vector (tabla), de manera Esta clase sirve para añadir elementos HiScoreEntry a un vector (tabla), de manera
@@ -12,11 +12,10 @@
*/ */
// --- Estructura para las entradas de la tabla de records --- // --- Estructura para las entradas de la tabla de records ---
struct HiScoreEntry struct HiScoreEntry {
{ std::string name; // Nombre
std::string name; // Nombre int score; // Puntuación
int score; // Puntuación bool one_credit_complete; // Indica si se ha conseguido 1CC
bool one_credit_complete; // Indica si se ha conseguido 1CC
// Constructor // Constructor
explicit HiScoreEntry(const std::string &n = "", int s = 0, bool occ = false) explicit HiScoreEntry(const std::string &n = "", int s = 0, bool occ = false)
@@ -24,9 +23,8 @@ struct HiScoreEntry
}; };
// --- Clase ManageHiScoreTable --- // --- Clase ManageHiScoreTable ---
class ManageHiScoreTable class ManageHiScoreTable {
{ public:
public:
// Constructor // Constructor
explicit ManageHiScoreTable(std::vector<HiScoreEntry> &table) explicit ManageHiScoreTable(std::vector<HiScoreEntry> &table)
: table_(table) {} : table_(table) {}
@@ -46,7 +44,7 @@ public:
// Guarda la tabla en un fichero // Guarda la tabla en un fichero
bool saveToFile(const std::string &file_path); bool saveToFile(const std::string &file_path);
private: private:
// Referencia a la tabla con los records // Referencia a la tabla con los records
std::vector<HiScoreEntry> &table_; std::vector<HiScoreEntry> &table_;
+20 -26
View File
@@ -1,33 +1,27 @@
#include "mouse.h" #include "mouse.h"
#include <SDL3/SDL.h> // Para SDL_GetTicks, Uint32, SDL_HideCursor, SDL_Show... #include <SDL3/SDL.h> // Para SDL_GetTicks, Uint32, SDL_HideCursor, SDL_Show...
namespace Mouse namespace Mouse {
{ Uint32 cursor_hide_time = 3000; // Tiempo en milisegundos para ocultar el cursor
Uint32 cursor_hide_time = 3000; // Tiempo en milisegundos para ocultar el cursor Uint32 last_mouse_move_time = 0; // Última vez que el ratón se movió
Uint32 last_mouse_move_time = 0; // Última vez que el ratón se movió bool cursor_visible = true; // Estado del cursor
bool cursor_visible = true; // Estado del cursor
void handleEvent(const SDL_Event &event) void handleEvent(const SDL_Event &event) {
{ if (event.type == SDL_EVENT_MOUSE_MOTION) {
if (event.type == SDL_EVENT_MOUSE_MOTION) last_mouse_move_time = SDL_GetTicks();
{ if (!cursor_visible) {
last_mouse_move_time = SDL_GetTicks(); SDL_ShowCursor();
if (!cursor_visible) cursor_visible = true;
{
SDL_ShowCursor();
cursor_visible = true;
}
}
}
void updateCursorVisibility()
{
Uint32 current_time = SDL_GetTicks();
if (cursor_visible && (current_time - last_mouse_move_time > cursor_hide_time))
{
SDL_HideCursor();
cursor_visible = false;
} }
} }
} }
void updateCursorVisibility() {
Uint32 current_time = SDL_GetTicks();
if (cursor_visible && (current_time - last_mouse_move_time > cursor_hide_time)) {
SDL_HideCursor();
cursor_visible = false;
}
}
} // namespace Mouse
+10 -11
View File
@@ -1,15 +1,14 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para Uint32, SDL_Event #include <SDL3/SDL.h> // Para Uint32, SDL_Event
namespace Mouse namespace Mouse {
{ // --- Variables de estado del cursor ---
// --- Variables de estado del cursor --- extern Uint32 cursor_hide_time; // Tiempo en milisegundos para ocultar el cursor tras inactividad
extern Uint32 cursor_hide_time; // Tiempo en milisegundos para ocultar el cursor tras inactividad extern Uint32 last_mouse_move_time; // Última vez (en ms) que el ratón se movió
extern Uint32 last_mouse_move_time; // Última vez (en ms) que el ratón se movió extern bool cursor_visible; // Indica si el cursor está visible
extern bool cursor_visible; // Indica si el cursor está visible
// --- Gestión de eventos y visibilidad --- // --- Gestión de eventos y visibilidad ---
void handleEvent(const SDL_Event &event); // Procesa eventos de ratón (movimiento, clic, etc.) void handleEvent(const SDL_Event &event); // Procesa eventos de ratón (movimiento, clic, etc.)
void updateCursorVisibility(); // Actualiza la visibilidad del cursor según la inactividad void updateCursorVisibility(); // Actualiza la visibilidad del cursor según la inactividad
} } // namespace Mouse
+70 -81
View File
@@ -1,130 +1,119 @@
#include "moving_sprite.h" #include "moving_sprite.h"
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
// Constructor // Constructor
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos, Rotate rotate, float zoom_w, float zoom_h, SDL_FlipMode flip) MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos, Rotate rotate, float zoom_w, float zoom_h, SDL_FlipMode flip)
: Sprite(texture, pos), : Sprite(texture, pos),
x_(pos.x), x_(pos.x),
y_(pos.y), y_(pos.y),
rotate_(rotate), rotate_(rotate),
zoom_w_(zoom_w), zoom_w_(zoom_w),
zoom_h_(zoom_h), zoom_h_(zoom_h),
flip_(flip) {} flip_(flip) {}
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos) MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos)
: Sprite(texture, pos), : Sprite(texture, pos),
x_(pos.x), x_(pos.x),
y_(pos.y), y_(pos.y),
rotate_(Rotate()), rotate_(Rotate()),
zoom_w_(1.0f), zoom_w_(1.0f),
zoom_h_(1.0f), zoom_h_(1.0f),
flip_(SDL_FLIP_NONE) {} flip_(SDL_FLIP_NONE) {}
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture) MovingSprite::MovingSprite(std::shared_ptr<Texture> texture)
: Sprite(texture), : Sprite(texture),
x_(0.0f), x_(0.0f),
y_(0.0f), y_(0.0f),
rotate_(Rotate()), rotate_(Rotate()),
zoom_w_(1.0f), zoom_w_(1.0f),
zoom_h_(1.0f), zoom_h_(1.0f),
flip_(SDL_FLIP_NONE) { Sprite::clear(); } flip_(SDL_FLIP_NONE) { Sprite::clear(); }
// Reinicia todas las variables // Reinicia todas las variables
void MovingSprite::clear() void MovingSprite::clear() {
{ x_ = 0.0f; // Posición en el eje X
x_ = 0.0f; // Posición en el eje X y_ = 0.0f; // Posición en el eje Y
y_ = 0.0f; // Posición en el eje Y
vx_ = 0.0f; // Velocidad en el eje X. Cantidad de pixeles a desplazarse vx_ = 0.0f; // Velocidad en el eje X. Cantidad de pixeles a desplazarse
vy_ = 0.0f; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse vy_ = 0.0f; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse
ax_ = 0.0f; // Aceleración en el eje X. Variación de la velocidad ax_ = 0.0f; // Aceleración en el eje X. Variación de la velocidad
ay_ = 0.0f; // Aceleración en el eje Y. Variación de la velocidad ay_ = 0.0f; // Aceleración en el eje Y. Variación de la velocidad
rotate_ = Rotate(); // Inicializa la estructura rotate_ = Rotate(); // Inicializa la estructura
zoom_w_ = 1.0f; // Zoom aplicado a la anchura zoom_w_ = 1.0f; // Zoom aplicado a la anchura
zoom_h_ = 1.0f; // Zoom aplicado a la altura zoom_h_ = 1.0f; // Zoom aplicado a la altura
flip_ = SDL_FLIP_NONE; // Establece como se ha de voltear el sprite flip_ = SDL_FLIP_NONE; // Establece como se ha de voltear el sprite
Sprite::clear(); Sprite::clear();
} }
// Mueve el sprite // Mueve el sprite
void MovingSprite::move() void MovingSprite::move() {
{ x_ += vx_;
x_ += vx_; y_ += vy_;
y_ += vy_;
vx_ += ax_; vx_ += ax_;
vy_ += ay_; vy_ += ay_;
pos_.x = static_cast<int>(x_); pos_.x = static_cast<int>(x_);
pos_.y = static_cast<int>(y_); pos_.y = static_cast<int>(y_);
} }
// Actualiza las variables internas del objeto // Actualiza las variables internas del objeto
void MovingSprite::update() void MovingSprite::update() {
{ move();
move(); rotate();
rotate();
} }
// Muestra el sprite por pantalla // Muestra el sprite por pantalla
void MovingSprite::render() { texture_->render(pos_.x, pos_.y, &sprite_clip_, zoom_w_, zoom_h_, rotate_.angle, &rotate_.center, flip_); } void MovingSprite::render() { texture_->render(pos_.x, pos_.y, &sprite_clip_, zoom_w_, zoom_h_, rotate_.angle, &rotate_.center, flip_); }
// Establece la rotacion // Establece la rotacion
void MovingSprite::rotate() void MovingSprite::rotate() {
{ if (rotate_.enabled) {
if (rotate_.enabled) ++rotate_.counter;
{ if (rotate_.counter % rotate_.speed == 0) {
++rotate_.counter; updateAngle();
if (rotate_.counter % rotate_.speed == 0) rotate_.counter = 0;
{ }
updateAngle(); }
rotate_.counter = 0;
}
}
} }
// Activa o desactiva el efecto de rotación // Activa o desactiva el efecto de rotación
void MovingSprite::setRotate(bool enable) void MovingSprite::setRotate(bool enable) {
{ rotate_.enabled = enable;
rotate_.enabled = enable; rotate_.counter = 0;
rotate_.counter = 0;
} }
// Establece la posición y_ el tamaño del objeto // Establece la posición y_ el tamaño del objeto
void MovingSprite::setPos(SDL_FRect rect) void MovingSprite::setPos(SDL_FRect rect) {
{ x_ = static_cast<float>(rect.x);
x_ = static_cast<float>(rect.x); y_ = static_cast<float>(rect.y);
y_ = static_cast<float>(rect.y);
pos_ = rect; pos_ = rect;
} }
// Establece el valor de las variables // Establece el valor de las variables
void MovingSprite::setPos(float x, float y) void MovingSprite::setPos(float x, float y) {
{ x_ = x;
x_ = x; y_ = y;
y_ = y;
pos_.x = static_cast<int>(x_); pos_.x = static_cast<int>(x_);
pos_.y = static_cast<int>(y_); pos_.y = static_cast<int>(y_);
} }
// Establece el valor de la variable // Establece el valor de la variable
void MovingSprite::setPosX(float value) void MovingSprite::setPosX(float value) {
{ x_ = value;
x_ = value; pos_.x = static_cast<int>(x_);
pos_.x = static_cast<int>(x_);
} }
// Establece el valor de la variable // Establece el valor de la variable
void MovingSprite::setPosY(float value) void MovingSprite::setPosY(float value) {
{ y_ = value;
y_ = value; pos_.y = static_cast<int>(y_);
pos_.y = static_cast<int>(y_);
} }
+35 -36
View File
@@ -1,26 +1,25 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_FlipMode, SDL_FPoint, SDL_FRect #include <SDL3/SDL.h> // Para SDL_FlipMode, SDL_FPoint, SDL_FRect
#include <algorithm> // Para max #include <algorithm> // Para max
#include <memory> // Para shared_ptr #include <memory> // Para shared_ptr
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
class Texture; class Texture;
// Clase MovingSprite. Añade movimiento y efectos de rotación, zoom y flip al sprite // Clase MovingSprite. Añade movimiento y efectos de rotación, zoom y flip al sprite
class MovingSprite : public Sprite class MovingSprite : public Sprite {
{ public:
public:
// --- Estructura para la rotación --- // --- Estructura para la rotación ---
struct Rotate struct Rotate {
{ bool enabled; // Indica si ha de rotar
bool enabled; // Indica si ha de rotar int counter; // Contador
int counter; // Contador int speed; // Velocidad de giro
int speed; // Velocidad de giro double angle; // Ángulo para dibujarlo
double angle; // Ángulo para dibujarlo float amount; // Cantidad de grados a girar en cada iteración
float amount; // Cantidad de grados a girar en cada iteración SDL_FPoint center; // Centro de rotación
SDL_FPoint center; // Centro de rotación
Rotate() : enabled(false), counter(0), speed(1), angle(0.0), amount(0.0f), center({0.0f, 0.0f}) {} Rotate() : enabled(false), counter(0), speed(1), angle(0.0), amount(0.0f), center({0.0f, 0.0f}) {}
}; };
@@ -32,9 +31,9 @@ public:
virtual ~MovingSprite() override = default; virtual ~MovingSprite() override = default;
// --- Métodos principales --- // --- Métodos principales ---
virtual void update(); // Actualiza las variables internas del objeto virtual void update(); // Actualiza las variables internas del objeto
void clear() override; // Reinicia todas las variables a cero void clear() override; // Reinicia todas las variables a cero
void render() override; // Muestra el sprite por pantalla void render() override; // Muestra el sprite por pantalla
// --- Getters de posición y movimiento --- // --- Getters de posición y movimiento ---
float getPosX() const { return x_; } float getPosX() const { return x_; }
@@ -56,10 +55,10 @@ public:
void setZoomH(float value) { zoom_h_ = value; } void setZoomH(float value) { zoom_h_ = value; }
void setAngle(double value) { rotate_.angle = value; } void setAngle(double value) { rotate_.angle = value; }
void setRotatingCenter(SDL_FPoint point) { rotate_.center = point; } void setRotatingCenter(SDL_FPoint point) { rotate_.center = point; }
void setRotate(bool enable); // Activa o desactiva el efecto de rotación void setRotate(bool enable); // Activa o desactiva el efecto de rotación
void setRotateSpeed(int value) { rotate_.speed = std::max(1, value); } void setRotateSpeed(int value) { rotate_.speed = std::max(1, value); }
void setRotateAmount(double value) { rotate_.amount = value; } void setRotateAmount(double value) { rotate_.amount = value; }
void switchRotate() { rotate_.amount *= -1; } // Cambia el sentido de la rotación void switchRotate() { rotate_.amount *= -1; } // Cambia el sentido de la rotación
// --- Flip --- // --- Flip ---
void setFlip(SDL_FlipMode flip) { flip_ = flip; } void setFlip(SDL_FlipMode flip) { flip_ = flip; }
@@ -67,30 +66,30 @@ public:
SDL_FlipMode getFlip() { return flip_; } SDL_FlipMode getFlip() { return flip_; }
// --- Posición y tamaño --- // --- Posición y tamaño ---
void setPos(SDL_FRect rect); // Establece la posición y el tamaño del objeto void setPos(SDL_FRect rect); // Establece la posición y el tamaño del objeto
void setPos(float x, float y); // Establece la posición del objeto void setPos(float x, float y); // Establece la posición del objeto
void setPosX(float value); // Establece la posición X void setPosX(float value); // Establece la posición X
void setPosY(float value); // Establece la posición Y void setPosY(float value); // Establece la posición Y
protected: protected:
// --- Variables de posición y movimiento --- // --- Variables de posición y movimiento ---
float x_ = 0.0f; // Posición en el eje X float x_ = 0.0f; // Posición en el eje X
float y_ = 0.0f; // Posición en el eje Y float y_ = 0.0f; // Posición en el eje Y
float vx_ = 0.0f; // Velocidad en el eje X. Cantidad de píxeles a desplazarse float vx_ = 0.0f; // Velocidad en el eje X. Cantidad de píxeles a desplazarse
float vy_ = 0.0f; // Velocidad en el eje Y. Cantidad de píxeles a desplazarse float vy_ = 0.0f; // Velocidad en el eje Y. Cantidad de píxeles a desplazarse
float ax_ = 0.0f; // Aceleración en el eje X. Variación de la velocidad float ax_ = 0.0f; // Aceleración en el eje X. Variación de la velocidad
float ay_ = 0.0f; // Aceleración en el eje Y. Variación de la velocidad float ay_ = 0.0f; // Aceleración en el eje Y. Variación de la velocidad
// --- Efectos visuales --- // --- Efectos visuales ---
Rotate rotate_; // Variables usadas para controlar la rotación del sprite Rotate rotate_; // Variables usadas para controlar la rotación del sprite
float zoom_w_; // Zoom aplicado a la anchura float zoom_w_; // Zoom aplicado a la anchura
float zoom_h_; // Zoom aplicado a la altura float zoom_h_; // Zoom aplicado a la altura
SDL_FlipMode flip_; // Indica cómo se voltea el sprite SDL_FlipMode flip_; // Indica cómo se voltea el sprite
// --- Métodos internos --- // --- Métodos internos ---
void updateAngle() { rotate_.angle += rotate_.amount; } // Incrementa el valor del ángulo void updateAngle() { rotate_.angle += rotate_.amount; } // Incrementa el valor del ángulo
void move(); // Mueve el sprite según velocidad y aceleración void move(); // Mueve el sprite según velocidad y aceleración
void rotate(); // Rota el sprite según los parámetros de rotación void rotate(); // Rota el sprite según los parámetros de rotación
}; };
+59 -98
View File
@@ -1,16 +1,17 @@
#include "notifier.h" #include "notifier.h"
#include <SDL3/SDL.h> // Para SDL_RenderFillRect, SDL_FRect, SDL_RenderClear #include <SDL3/SDL.h> // Para SDL_RenderFillRect, SDL_FRect, SDL_RenderClear
#include <algorithm> // Para remove_if #include <algorithm> // Para remove_if
#include <string> // Para basic_string, string #include <string> // Para basic_string, string
#include <vector> // Para vector #include <vector> // Para vector
#include "audio.h" // Para Audio #include "audio.h" // Para Audio
#include "param.h" // Para Param, param, ParamNotification, ParamGame #include "param.h" // Para Param, param, ParamNotification, ParamGame
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "text.h" // Para Text #include "text.h" // Para Text
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
// Singleton // Singleton
Notifier *Notifier::instance_ = nullptr; Notifier *Notifier::instance_ = nullptr;
@@ -35,24 +36,18 @@ Notifier::Notifier(std::string icon_file, std::shared_ptr<Text> text)
has_icons_(!icon_file.empty()) {} has_icons_(!icon_file.empty()) {}
// Dibuja las notificaciones por pantalla // Dibuja las notificaciones por pantalla
void Notifier::render() void Notifier::render() {
{ for (int i = (int)notifications_.size() - 1; i >= 0; --i) {
for (int i = (int)notifications_.size() - 1; i >= 0; --i)
{
notifications_[i].sprite->render(); notifications_[i].sprite->render();
} }
} }
// Actualiza el estado de las notificaiones // Actualiza el estado de las notificaiones
void Notifier::update() void Notifier::update() {
{ for (int i = 0; i < (int)notifications_.size(); ++i) {
for (int i = 0; i < (int)notifications_.size(); ++i)
{
// Si la notificación anterior está "saliendo", no hagas nada // Si la notificación anterior está "saliendo", no hagas nada
if (i > 0) if (i > 0) {
{ if (notifications_[i - 1].state == NotificationStatus::RISING) {
if (notifications_[i - 1].state == NotificationStatus::RISING)
{
break; break;
} }
} }
@@ -60,12 +55,9 @@ void Notifier::update()
notifications_[i].counter++; notifications_[i].counter++;
// Hace sonar la notificación en el primer frame // Hace sonar la notificación en el primer frame
if (notifications_[i].counter == 1) if (notifications_[i].counter == 1) {
{ if (param.notification.sound) {
if (param.notification.sound) if (notifications_[i].state == NotificationStatus::RISING) {
{
if (notifications_[i].state == NotificationStatus::RISING)
{
// Reproduce el sonido de la notificación // Reproduce el sonido de la notificación
Audio::get()->playSound("notify.wav", Audio::Group::INTERFACE); Audio::get()->playSound("notify.wav", Audio::Group::INTERFACE);
} }
@@ -73,55 +65,41 @@ void Notifier::update()
} }
// Comprueba los estados // Comprueba los estados
if (notifications_[i].state == NotificationStatus::RISING) if (notifications_[i].state == NotificationStatus::RISING) {
{
const float step = ((float)notifications_[i].counter / notifications_[i].travel_dist); const float step = ((float)notifications_[i].counter / notifications_[i].travel_dist);
const int alpha = 255 * step; const int alpha = 255 * step;
if (param.notification.pos_v == NotifyPosition::TOP) if (param.notification.pos_v == NotifyPosition::TOP) {
{
notifications_[i].rect.y++; notifications_[i].rect.y++;
} } else {
else
{
notifications_[i].rect.y--; notifications_[i].rect.y--;
} }
notifications_[i].texture->setAlpha(alpha); notifications_[i].texture->setAlpha(alpha);
if (notifications_[i].rect.y == notifications_[i].y) if (notifications_[i].rect.y == notifications_[i].y) {
{
notifications_[i].state = NotificationStatus::STAY; notifications_[i].state = NotificationStatus::STAY;
notifications_[i].texture->setAlpha(255); notifications_[i].texture->setAlpha(255);
notifications_[i].counter = 0; notifications_[i].counter = 0;
} }
} }
else if (notifications_[i].state == NotificationStatus::STAY) else if (notifications_[i].state == NotificationStatus::STAY) {
{ if (notifications_[i].counter == wait_time_) {
if (notifications_[i].counter == wait_time_)
{
notifications_[i].state = NotificationStatus::VANISHING; notifications_[i].state = NotificationStatus::VANISHING;
notifications_[i].counter = 0; notifications_[i].counter = 0;
} }
} } else if (notifications_[i].state == NotificationStatus::VANISHING) {
else if (notifications_[i].state == NotificationStatus::VANISHING)
{
const float step = (notifications_[i].counter / (float)notifications_[i].travel_dist); const float step = (notifications_[i].counter / (float)notifications_[i].travel_dist);
const int alpha = 255 * (1 - step); const int alpha = 255 * (1 - step);
if (param.notification.pos_v == NotifyPosition::TOP) if (param.notification.pos_v == NotifyPosition::TOP) {
{
notifications_[i].rect.y--; notifications_[i].rect.y--;
} } else {
else
{
notifications_[i].rect.y++; notifications_[i].rect.y++;
} }
notifications_[i].texture->setAlpha(alpha); notifications_[i].texture->setAlpha(alpha);
if (notifications_[i].rect.y == notifications_[i].y - notifications_[i].travel_dist) if (notifications_[i].rect.y == notifications_[i].y - notifications_[i].travel_dist) {
{
notifications_[i].state = NotificationStatus::FINISHED; notifications_[i].state = NotificationStatus::FINISHED;
} }
} }
@@ -133,40 +111,32 @@ void Notifier::update()
} }
// Elimina las notificaciones finalizadas // Elimina las notificaciones finalizadas
void Notifier::clearFinishedNotifications() void Notifier::clearFinishedNotifications() {
{ for (int i = (int)notifications_.size() - 1; i >= 0; --i) {
for (int i = (int)notifications_.size() - 1; i >= 0; --i) if (notifications_[i].state == NotificationStatus::FINISHED) {
{
if (notifications_[i].state == NotificationStatus::FINISHED)
{
notifications_.erase(notifications_.begin() + i); notifications_.erase(notifications_.begin() + i);
} }
} }
} }
void Notifier::show(std::vector<std::string> texts, int icon, const std::string &code) void Notifier::show(std::vector<std::string> texts, int icon, const std::string &code) {
{
// Si no hay texto, acaba // Si no hay texto, acaba
if (texts.empty()) if (texts.empty()) {
{
return; return;
} }
// Si las notificaciones no se apilan, elimina las anteriores // Si las notificaciones no se apilan, elimina las anteriores
if (!stack_) if (!stack_) {
{
clearAllNotifications(); clearAllNotifications();
} }
// Elimina las cadenas vacías // Elimina las cadenas vacías
texts.erase(std::remove_if(texts.begin(), texts.end(), [](const std::string &s) texts.erase(std::remove_if(texts.begin(), texts.end(), [](const std::string &s) { return s.empty(); }),
{ return s.empty(); }), texts.end());
texts.end());
// Encuentra la cadena más larga // Encuentra la cadena más larga
std::string longest; std::string longest;
for (const auto &text : texts) for (const auto &text : texts) {
{
if (text.length() > longest.length()) if (text.length() > longest.length())
longest = text; longest = text;
} }
@@ -183,23 +153,22 @@ void Notifier::show(std::vector<std::string> texts, int icon, const std::string
// Posición horizontal // Posición horizontal
float desp_h = 0; float desp_h = 0;
switch (param.notification.pos_h) switch (param.notification.pos_h) {
{ case NotifyPosition::LEFT:
case NotifyPosition::LEFT: desp_h = PADDING_OUT;
desp_h = PADDING_OUT; break;
break;
case NotifyPosition::MIDDLE: case NotifyPosition::MIDDLE:
desp_h = ((param.game.width / 2) - (WIDTH / 2)); desp_h = ((param.game.width / 2) - (WIDTH / 2));
break; break;
case NotifyPosition::RIGHT: case NotifyPosition::RIGHT:
desp_h = param.game.width - WIDTH - PADDING_OUT; desp_h = param.game.width - WIDTH - PADDING_OUT;
break; break;
default: default:
desp_h = 0; desp_h = 0;
break; break;
} }
// Posición vertical // Posición vertical
@@ -208,8 +177,8 @@ void Notifier::show(std::vector<std::string> texts, int icon, const std::string
// Offset // Offset
const auto TRAVEL_DIST = HEIGHT + PADDING_OUT; const auto TRAVEL_DIST = HEIGHT + PADDING_OUT;
auto OFFSET = notifications_.empty() auto OFFSET = notifications_.empty()
? DESP_V ? DESP_V
: notifications_.back().y + (param.notification.pos_v == NotifyPosition::TOP ? TRAVEL_DIST : -TRAVEL_DIST); : notifications_.back().y + (param.notification.pos_v == NotifyPosition::TOP ? TRAVEL_DIST : -TRAVEL_DIST);
// Crea la notificacion // Crea la notificacion
Notification n; Notification n;
@@ -234,8 +203,7 @@ void Notifier::show(std::vector<std::string> texts, int icon, const std::string
// Dibuja el fondo de la notificación // Dibuja el fondo de la notificación
SDL_SetRenderDrawColor(renderer_, bg_color_.r, bg_color_.g, bg_color_.b, 255); SDL_SetRenderDrawColor(renderer_, bg_color_.r, bg_color_.g, bg_color_.b, 255);
SDL_FRect rect; SDL_FRect rect;
if (SHAPE == NotificationShape::ROUNDED) if (SHAPE == NotificationShape::ROUNDED) {
{
rect = {4, 0, WIDTH - (4 * 2), HEIGHT}; rect = {4, 0, WIDTH - (4 * 2), HEIGHT};
SDL_RenderFillRect(renderer_, &rect); SDL_RenderFillRect(renderer_, &rect);
@@ -249,14 +217,12 @@ void Notifier::show(std::vector<std::string> texts, int icon, const std::string
SDL_RenderFillRect(renderer_, &rect); SDL_RenderFillRect(renderer_, &rect);
} }
else if (SHAPE == NotificationShape::SQUARED) else if (SHAPE == NotificationShape::SQUARED) {
{
SDL_RenderClear(renderer_); SDL_RenderClear(renderer_);
} }
// Dibuja el icono de la notificación // Dibuja el icono de la notificación
if (has_icons_ && icon >= 0 && texts.size() >= 2) if (has_icons_ && icon >= 0 && texts.size() >= 2) {
{
auto sp = std::make_unique<Sprite>(icon_texture_, (SDL_FRect){0, 0, ICON_SIZE, ICON_SIZE}); auto sp = std::make_unique<Sprite>(icon_texture_, (SDL_FRect){0, 0, ICON_SIZE, ICON_SIZE});
sp->setPosition({PADDING_IN_H, PADDING_IN_V, ICON_SIZE, ICON_SIZE}); sp->setPosition({PADDING_IN_H, PADDING_IN_V, ICON_SIZE, ICON_SIZE});
sp->setSpriteClip(SDL_FRect{ sp->setSpriteClip(SDL_FRect{
@@ -270,8 +236,7 @@ void Notifier::show(std::vector<std::string> texts, int icon, const std::string
// Escribe el texto de la notificación // Escribe el texto de la notificación
const Color color{255, 255, 255}; const Color color{255, 255, 255};
int iterator = 0; int iterator = 0;
for (const auto &text : texts) for (const auto &text : texts) {
{
text_->writeColored(PADDING_IN_H + ICON_SPACE, PADDING_IN_V + iterator * (text_->getCharacterSize() + 1), text, color); text_->writeColored(PADDING_IN_H + ICON_SPACE, PADDING_IN_V + iterator * (text_->getCharacterSize() + 1), text, color);
++iterator; ++iterator;
} }
@@ -290,10 +255,8 @@ void Notifier::show(std::vector<std::string> texts, int icon, const std::string
} }
// Finaliza y elimnina todas las notificaciones activas // Finaliza y elimnina todas las notificaciones activas
void Notifier::clearAllNotifications() void Notifier::clearAllNotifications() {
{ for (auto &notification : notifications_) {
for (auto &notification : notifications_)
{
notification.state = NotificationStatus::FINISHED; notification.state = NotificationStatus::FINISHED;
} }
@@ -301,11 +264,9 @@ void Notifier::clearAllNotifications()
} }
// Obtiene los códigos de las notificaciones // Obtiene los códigos de las notificaciones
std::vector<std::string> Notifier::getCodes() std::vector<std::string> Notifier::getCodes() {
{
std::vector<std::string> codes; std::vector<std::string> codes;
for (const auto &notification : notifications_) for (const auto &notification : notifications_) {
{
codes.emplace_back(notification.code); codes.emplace_back(notification.code);
} }
return codes; return codes;
+44 -48
View File
@@ -1,91 +1,87 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_FRect, SDL_Renderer #include <SDL3/SDL.h> // Para SDL_FRect, SDL_Renderer
#include <memory> // Para shared_ptr
#include <string> // Para basic_string, string
#include <vector> // Para vector
#include "utils.h" // Para stringInVector, Color #include <memory> // Para shared_ptr
#include <string> // Para basic_string, string
#include <vector> // Para vector
#include "utils.h" // Para stringInVector, Color
class Sprite; class Sprite;
class Text; class Text;
class Texture; class Texture;
// --- Clase Notifier: gestiona las notificaciones en pantalla (singleton) --- // --- Clase Notifier: gestiona las notificaciones en pantalla (singleton) ---
class Notifier class Notifier {
{ public:
public:
// --- Métodos de singleton --- // --- Métodos de singleton ---
static void init(const std::string &icon_file, std::shared_ptr<Text> text); // Inicializa el singleton static void init(const std::string &icon_file, std::shared_ptr<Text> text); // Inicializa el singleton
static void destroy(); // Libera el singleton static void destroy(); // Libera el singleton
static Notifier *get(); // Obtiene la instancia static Notifier *get(); // Obtiene la instancia
// --- Métodos principales --- // --- Métodos principales ---
void render(); // Dibuja las notificaciones por pantalla void render(); // Dibuja las notificaciones por pantalla
void update(); // Actualiza el estado de las notificaciones void update(); // Actualiza el estado de las notificaciones
// --- Gestión de notificaciones --- // --- Gestión de notificaciones ---
void show(std::vector<std::string> texts, int icon = -1, const std::string &code = std::string()); // Muestra una notificación de texto por pantalla void show(std::vector<std::string> texts, int icon = -1, const std::string &code = std::string()); // Muestra una notificación de texto por pantalla
bool isActive() const { return !notifications_.empty(); } // Indica si hay notificaciones activas bool isActive() const { return !notifications_.empty(); } // Indica si hay notificaciones activas
std::vector<std::string> getCodes(); // Obtiene los códigos de las notificaciones activas std::vector<std::string> getCodes(); // Obtiene los códigos de las notificaciones activas
bool checkCode(const std::string &code) { return stringInVector(getCodes(), code); } // Comprueba si hay alguna notificación con un código concreto bool checkCode(const std::string &code) { return stringInVector(getCodes(), code); } // Comprueba si hay alguna notificación con un código concreto
private: private:
// --- Singleton --- // --- Singleton ---
static Notifier *instance_; static Notifier *instance_;
// --- Tipos internos --- // --- Tipos internos ---
enum class NotificationStatus enum class NotificationStatus {
{
RISING, RISING,
STAY, STAY,
VANISHING, VANISHING,
FINISHED, FINISHED,
}; };
enum class NotificationShape enum class NotificationShape {
{
ROUNDED, ROUNDED,
SQUARED, SQUARED,
}; };
// --- Estructura Notification --- // --- Estructura Notification ---
struct Notification struct Notification {
{ std::shared_ptr<Texture> texture; // Textura de la notificación
std::shared_ptr<Texture> texture; // Textura de la notificación std::shared_ptr<Sprite> sprite; // Sprite asociado
std::shared_ptr<Sprite> sprite; // Sprite asociado std::vector<std::string> texts; // Textos a mostrar
std::vector<std::string> texts; // Textos a mostrar int counter; // Contador de tiempo
int counter; // Contador de tiempo NotificationStatus state; // Estado de la notificación
NotificationStatus state; // Estado de la notificación NotificationShape shape; // Forma de la notificación
NotificationShape shape; // Forma de la notificación SDL_FRect rect; // Rectángulo de la notificación
SDL_FRect rect; // Rectángulo de la notificación int y; // Posición vertical
int y; // Posición vertical int travel_dist; // Distancia a recorrer
int travel_dist; // Distancia a recorrer std::string code; // Código identificador de la notificación
std::string code; // Código identificador de la notificación
// Constructor // Constructor
explicit Notification() explicit Notification()
: texture(nullptr), sprite(nullptr), texts(), counter(0), state(NotificationStatus::RISING), : texture(nullptr), sprite(nullptr), texts(), counter(0), state(NotificationStatus::RISING), shape(NotificationShape::SQUARED), rect{0, 0, 0, 0}, y(0), travel_dist(0), code("") {}
shape(NotificationShape::SQUARED), rect{0, 0, 0, 0}, y(0), travel_dist(0), code("") {}
}; };
// --- Objetos y punteros --- // --- Objetos y punteros ---
SDL_Renderer *renderer_; // El renderizador de la ventana SDL_Renderer *renderer_; // El renderizador de la ventana
std::shared_ptr<Texture> icon_texture_; // Textura para los iconos de las notificaciones std::shared_ptr<Texture> icon_texture_; // Textura para los iconos de las notificaciones
std::shared_ptr<Text> text_; // Objeto para dibujar texto std::shared_ptr<Text> text_; // Objeto para dibujar texto
// --- Variables de estado --- // --- Variables de estado ---
Color bg_color_; // Color de fondo de las notificaciones Color bg_color_; // Color de fondo de las notificaciones
int wait_time_; // Tiempo que se ve la notificación int wait_time_; // Tiempo que se ve la notificación
std::vector<Notification> notifications_; // Lista de notificaciones activas std::vector<Notification> notifications_; // Lista de notificaciones activas
bool stack_; // Indica si las notificaciones se apilan bool stack_; // Indica si las notificaciones se apilan
bool has_icons_; // Indica si el notificador tiene textura para iconos bool has_icons_; // Indica si el notificador tiene textura para iconos
// --- Métodos internos --- // --- Métodos internos ---
void clearFinishedNotifications(); // Elimina las notificaciones finalizadas void clearFinishedNotifications(); // Elimina las notificaciones finalizadas
void clearAllNotifications(); // Finaliza y elimina todas las notificaciones activas void clearAllNotifications(); // Finaliza y elimina todas las notificaciones activas
// --- Constructor y destructor --- // --- Constructor y destructor ---
Notifier(std::string icon_file, std::shared_ptr<Text> text); // Constructor privado Notifier(std::string icon_file, std::shared_ptr<Text> text); // Constructor privado
~Notifier() = default; // Destructor privado ~Notifier() = default; // Destructor privado
}; };
+281 -376
View File
@@ -1,423 +1,328 @@
#include "options.h" #include "options.h"
#include <SDL3/SDL.h> // Para SDL_LogCategory, SDL_LogInfo, SDL_LogError #include <SDL3/SDL.h> // Para SDL_LogCategory, SDL_LogInfo, SDL_LogError
#include <algorithm> // Para clamp #include <algorithm> // Para clamp
#include <fstream> // Para basic_ostream, operator<<, basic_ostream::... #include <fstream> // Para basic_ostream, operator<<, basic_ostream::...
#include <utility> // Para swap #include <utility> // Para swap
#include <vector> // Para vector #include <vector> // Para vector
#include "asset.h" #include "asset.h"
#include "input.h" // Para InputDeviceToUse #include "input.h" // Para InputDeviceToUse
#include "lang.h" // Para Code #include "lang.h" // Para Code
#include "utils.h" // Para boolToString, stringToBool, getFileName #include "utils.h" // Para boolToString, stringToBool, getFileName
namespace Options namespace Options {
{ // --- Variables globales ---
// --- Variables globales --- WindowOptions window; // Opciones de la ventana
WindowOptions window; // Opciones de la ventana SettingsOptions settings; // Opciones del juego
SettingsOptions settings; // Opciones del juego VideoOptions video; // Opciones de vídeo
VideoOptions video; // Opciones de vídeo AudioOptions audio; // Opciones de audio
AudioOptions audio; // Opciones de audio std::vector<GamepadOptions> controllers; // Opciones de mando para cada jugador
std::vector<GamepadOptions> controllers; // Opciones de mando para cada jugador PendingChanges pending_changes; // Opciones que se aplican al cerrar
PendingChanges pending_changes; // Opciones que se aplican al cerrar
// Vector con las dificultades // Vector con las dificultades
std::vector<Difficulty> difficulties = { std::vector<Difficulty> difficulties = {
{DifficultyCode::EASY, "Easy"}, {DifficultyCode::EASY, "Easy"},
{DifficultyCode::NORMAL, "Normal"}, {DifficultyCode::NORMAL, "Normal"},
{DifficultyCode::HARD, "Hard"}}; {DifficultyCode::HARD, "Hard"}};
// Declaraciones // Declaraciones
bool set(const std::string &var, const std::string &value); bool set(const std::string &var, const std::string &value);
// Inicializa las opciones del programa // Inicializa las opciones del programa
void init() void init() {
{ // Settings
// Settings settings.config_file = Asset::get()->get("config.txt");
settings.config_file = Asset::get()->get("config.txt");
// Opciones de control // Opciones de control
controllers.clear(); controllers.clear();
controllers.resize(2); controllers.resize(2);
controllers.at(0).player_id = 1; controllers.at(0).player_id = 1;
controllers.at(1).player_id = 2; controllers.at(1).player_id = 2;
setKeyboardToPlayer(1); setKeyboardToPlayer(1);
// Opciones pendientes // Opciones pendientes
pending_changes.new_language = settings.language; pending_changes.new_language = settings.language;
pending_changes.new_difficulty = settings.difficulty; pending_changes.new_difficulty = settings.difficulty;
pending_changes.has_pending_changes = false; pending_changes.has_pending_changes = false;
} }
// Carga el fichero de configuración // Carga el fichero de configuración
bool loadFromFile() bool loadFromFile() {
{ // Inicializa las opciones del programa
// Inicializa las opciones del programa init();
init();
// Indicador de éxito en la carga // Indicador de éxito en la carga
bool success = true; bool success = true;
// Variables para manejar el fichero // Variables para manejar el fichero
std::ifstream file(settings.config_file); std::ifstream file(settings.config_file);
// Si el fichero se puede abrir // Si el fichero se puede abrir
if (file.good()) if (file.good()) {
{ // Procesa el fichero línea a línea
// Procesa el fichero línea a línea SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\nReading file: %s", getFileName(settings.config_file).c_str());
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\nReading file: %s", getFileName(settings.config_file).c_str()); std::string line;
std::string line; while (std::getline(file, line)) {
while (std::getline(file, line)) // Comprueba que la línea no sea un comentario
{ if (line.substr(0, 1) != "#") {
// Comprueba que la línea no sea un comentario // Encuentra la posición del carácter '='
if (line.substr(0, 1) != "#") int pos = line.find("=");
{ // Procesa las dos subcadenas
// Encuentra la posición del carácter '=' if (!set(line.substr(0, pos), line.substr(pos + 1, line.length()))) {
int pos = line.find("="); SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Unknown parameter: %s", line.substr(0, pos).c_str());
// Procesa las dos subcadenas success = false;
if (!set(line.substr(0, pos), line.substr(pos + 1, line.length()))) }
{ }
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Unknown parameter: %s", line.substr(0, pos).c_str()); }
success = false; file.close();
} }
} // El fichero no existe
} else {
file.close(); saveToFile(); // Crea el fichero con los valores por defecto
} }
// El fichero no existe
else
{
saveToFile(); // Crea el fichero con los valores por defecto
}
// Normaliza los valores // Normaliza los valores
if (settings.language != Lang::Code::ENGLISH && if (settings.language != Lang::Code::ENGLISH &&
settings.language != Lang::Code::VALENCIAN && settings.language != Lang::Code::VALENCIAN &&
settings.language != Lang::Code::SPANISH) settings.language != Lang::Code::SPANISH) {
{ settings.language = Lang::Code::ENGLISH;
settings.language = Lang::Code::ENGLISH; }
}
return success; return success;
} }
// Guarda el fichero de configuración // Guarda el fichero de configuración
bool saveToFile() bool saveToFile() {
{ std::ofstream file(settings.config_file);
std::ofstream file(settings.config_file);
if (!file.good()) if (!file.good()) {
{ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: %s can't be opened", getFileName(settings.config_file).c_str());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: %s can't be opened", getFileName(settings.config_file).c_str()); return false;
return false; }
}
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Writing file: %s", getFileName(settings.config_file).c_str()); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Writing file: %s", getFileName(settings.config_file).c_str());
applyPendingChanges(); applyPendingChanges();
// Opciones de video // Opciones de video
file << "## VIDEO\n"; file << "## VIDEO\n";
file << "## video.scale_mode [" << static_cast<int>(SDL_ScaleMode::SDL_SCALEMODE_NEAREST) << ": nearest, " << static_cast<int>(SDL_ScaleMode::SDL_SCALEMODE_LINEAR) << ": lineal]\n"; file << "## video.scale_mode [" << static_cast<int>(SDL_ScaleMode::SDL_SCALEMODE_NEAREST) << ": nearest, " << static_cast<int>(SDL_ScaleMode::SDL_SCALEMODE_LINEAR) << ": lineal]\n";
file << "\n"; file << "\n";
file << "window.zoom=" << window.size << "\n"; file << "window.zoom=" << window.size << "\n";
file << "video.fullscreen=" << boolToString(video.fullscreen) << "\n"; file << "video.fullscreen=" << boolToString(video.fullscreen) << "\n";
file << "video.scale_mode=" << static_cast<int>(video.scale_mode) << "\n"; file << "video.scale_mode=" << static_cast<int>(video.scale_mode) << "\n";
file << "video.v_sync=" << boolToString(video.v_sync) << "\n"; file << "video.v_sync=" << boolToString(video.v_sync) << "\n";
file << "video.integer_scale=" << boolToString(video.integer_scale) << "\n"; file << "video.integer_scale=" << boolToString(video.integer_scale) << "\n";
file << "video.shaders=" << boolToString(video.shaders) << "\n"; file << "video.shaders=" << boolToString(video.shaders) << "\n";
// Opciones de audio // Opciones de audio
file << "\n\n## AUDIO\n"; file << "\n\n## AUDIO\n";
file << "## volume [0 .. 100]\n"; file << "## volume [0 .. 100]\n";
file << "\n"; file << "\n";
file << "audio.enabled=" << boolToString(audio.enabled) << "\n"; file << "audio.enabled=" << boolToString(audio.enabled) << "\n";
file << "audio.volume=" << audio.volume << "\n"; file << "audio.volume=" << audio.volume << "\n";
file << "audio.music.enabled=" << boolToString(audio.music.enabled) << "\n"; file << "audio.music.enabled=" << boolToString(audio.music.enabled) << "\n";
file << "audio.music.volume=" << audio.music.volume << "\n"; file << "audio.music.volume=" << audio.music.volume << "\n";
file << "audio.sound.enabled=" << boolToString(audio.sound.enabled) << "\n"; file << "audio.sound.enabled=" << boolToString(audio.sound.enabled) << "\n";
file << "audio.sound.volume=" << audio.sound.volume << "\n"; file << "audio.sound.volume=" << audio.sound.volume << "\n";
// Opciones del juego // Opciones del juego
file << "\n\n## GAME\n"; file << "\n\n## GAME\n";
file << "## game.language [0: spanish, 1: valencian, 2: english]\n"; file << "## game.language [0: spanish, 1: valencian, 2: english]\n";
file << "## game.difficulty [" << static_cast<int>(DifficultyCode::EASY) << ": easy, " << static_cast<int>(DifficultyCode::NORMAL) << ": normal, " << static_cast<int>(DifficultyCode::HARD) << ": hard]\n"; file << "## game.difficulty [" << static_cast<int>(DifficultyCode::EASY) << ": easy, " << static_cast<int>(DifficultyCode::NORMAL) << ": normal, " << static_cast<int>(DifficultyCode::HARD) << ": hard]\n";
file << "\n"; file << "\n";
file << "game.language=" << static_cast<int>(settings.language) << "\n"; file << "game.language=" << static_cast<int>(settings.language) << "\n";
file << "game.difficulty=" << static_cast<int>(settings.difficulty) << "\n"; file << "game.difficulty=" << static_cast<int>(settings.difficulty) << "\n";
file << "game.autofire=" << boolToString(settings.autofire) << "\n"; file << "game.autofire=" << boolToString(settings.autofire) << "\n";
file << "game.shutdown_enabled=" << boolToString(settings.shutdown_enabled) << "\n"; file << "game.shutdown_enabled=" << boolToString(settings.shutdown_enabled) << "\n";
// Opciones de mandos // Opciones de mandos
file << "\n\n## CONTROLLERS\n"; file << "\n\n## CONTROLLERS\n";
int controller_index = 0; int controller_index = 0;
for (const auto &controller : controllers) for (const auto &controller : controllers) {
{ file << "\n";
file << "\n"; file << "controller." << controller_index << ".name=" << controller.name << "\n";
file << "controller." << controller_index << ".name=" << controller.name << "\n"; file << "controller." << controller_index << ".player=" << controller.player_id << "\n";
file << "controller." << controller_index << ".player=" << controller.player_id << "\n"; file << "controller." << controller_index << ".type=" << static_cast<int>(controller.type) << "\n";
file << "controller." << controller_index << ".type=" << static_cast<int>(controller.type) << "\n"; file << "controller." << controller_index << ".button.fire_left=" << controller.buttons.at(0) << "\n";
file << "controller." << controller_index << ".button.fire_left=" << controller.buttons.at(0) << "\n"; file << "controller." << controller_index << ".button.fire_center=" << controller.buttons.at(1) << "\n";
file << "controller." << controller_index << ".button.fire_center=" << controller.buttons.at(1) << "\n"; file << "controller." << controller_index << ".button.fire_right=" << controller.buttons.at(2) << "\n";
file << "controller." << controller_index << ".button.fire_right=" << controller.buttons.at(2) << "\n"; file << "controller." << controller_index << ".button.start=" << controller.buttons.at(3) << "\n";
file << "controller." << controller_index << ".button.start=" << controller.buttons.at(3) << "\n"; file << "controller." << controller_index << ".button.service=" << controller.buttons.at(4) << "\n";
file << "controller." << controller_index << ".button.service=" << controller.buttons.at(4) << "\n";
// Incrementa el índice // Incrementa el índice
++controller_index; ++controller_index;
} }
// Cierra el fichero // Cierra el fichero
file.close(); file.close();
return true; return true;
} }
// Asigna variables a partir de dos cadenas // Asigna variables a partir de dos cadenas
bool set(const std::string &var, const std::string &value) bool set(const std::string &var, const std::string &value) {
{ // Indicador de éxito en la asignación
// Indicador de éxito en la asignación auto success = true;
auto success = true;
// Opciones de video // Opciones de video
if (var == "video.fullscreen") if (var == "video.fullscreen") {
{ video.fullscreen = stringToBool(value);
video.fullscreen = stringToBool(value); } else if (var == "window.zoom") {
} window.size = std::stoi(value);
else if (var == "window.zoom") } else if (var == "video.scale_mode") {
{ video.scale_mode = static_cast<SDL_ScaleMode>(std::stoi(value));
window.size = std::stoi(value); } else if (var == "video.shaders") {
} video.shaders = stringToBool(value);
else if (var == "video.scale_mode") } else if (var == "video.integer_scale") {
{ video.integer_scale = stringToBool(value);
video.scale_mode = static_cast<SDL_ScaleMode>(std::stoi(value)); } else if (var == "video.v_sync") {
} video.v_sync = stringToBool(value);
else if (var == "video.shaders") }
{
video.shaders = stringToBool(value);
}
else if (var == "video.integer_scale")
{
video.integer_scale = stringToBool(value);
}
else if (var == "video.v_sync")
{
video.v_sync = stringToBool(value);
}
// Opciones de audio // Opciones de audio
else if (var == "audio.enabled") else if (var == "audio.enabled") {
{ audio.enabled = stringToBool(value);
audio.enabled = stringToBool(value); } else if (var == "audio.volume") {
} audio.volume = std::clamp(std::stoi(value), 0, 100);
else if (var == "audio.volume") } else if (var == "audio.music.enabled") {
{ audio.music.enabled = stringToBool(value);
audio.volume = std::clamp(std::stoi(value), 0, 100); } else if (var == "audio.music.volume") {
} audio.music.volume = std::clamp(std::stoi(value), 0, 100);
else if (var == "audio.music.enabled") } else if (var == "audio.sound.enabled") {
{ audio.sound.enabled = stringToBool(value);
audio.music.enabled = stringToBool(value); } else if (var == "audio.sound.volume") {
} audio.sound.volume = std::clamp(std::stoi(value), 0, 100);
else if (var == "audio.music.volume") }
{
audio.music.volume = std::clamp(std::stoi(value), 0, 100);
}
else if (var == "audio.sound.enabled")
{
audio.sound.enabled = stringToBool(value);
}
else if (var == "audio.sound.volume")
{
audio.sound.volume = std::clamp(std::stoi(value), 0, 100);
}
// Opciones de juego // Opciones de juego
else if (var == "game.language") else if (var == "game.language") {
{ settings.language = static_cast<Lang::Code>(std::stoi(value));
settings.language = static_cast<Lang::Code>(std::stoi(value)); pending_changes.new_language = settings.language;
pending_changes.new_language = settings.language; } else if (var == "game.difficulty") {
} settings.difficulty = static_cast<DifficultyCode>(std::stoi(value));
else if (var == "game.difficulty") pending_changes.new_difficulty = settings.difficulty;
{ } else if (var == "game.autofire") {
settings.difficulty = static_cast<DifficultyCode>(std::stoi(value)); settings.autofire = stringToBool(value);
pending_changes.new_difficulty = settings.difficulty; } else if (var == "game.shutdown_enabled") {
} settings.shutdown_enabled = stringToBool(value);
else if (var == "game.autofire") }
{
settings.autofire = stringToBool(value);
}
else if (var == "game.shutdown_enabled")
{
settings.shutdown_enabled = stringToBool(value);
}
// Opciones de mandos // Opciones de mandos
else if (var == "controller.0.name") else if (var == "controller.0.name") {
{ controllers.at(0).name = value;
controllers.at(0).name = value; } else if (var == "controller.0.player") {
} controllers.at(0).player_id = std::clamp(std::stoi(value), 1, 2);
else if (var == "controller.0.player") } else if (var == "controller.0.type") {
{ controllers.at(0).type = static_cast<InputDevice>(std::stoi(value));
controllers.at(0).player_id = std::clamp(std::stoi(value), 1, 2); } else if (var == "controller.0.button.fire_left") {
} controllers.at(0).buttons.at(0) = static_cast<SDL_GamepadButton>(std::stoi(value));
else if (var == "controller.0.type") } else if (var == "controller.0.button.fire_center") {
{ controllers.at(0).buttons.at(1) = static_cast<SDL_GamepadButton>(std::stoi(value));
controllers.at(0).type = static_cast<InputDevice>(std::stoi(value)); } else if (var == "controller.0.button.fire_right") {
} controllers.at(0).buttons.at(2) = static_cast<SDL_GamepadButton>(std::stoi(value));
else if (var == "controller.0.button.fire_left") } else if (var == "controller.0.button.start") {
{ controllers.at(0).buttons.at(3) = static_cast<SDL_GamepadButton>(std::stoi(value));
controllers.at(0).buttons.at(0) = static_cast<SDL_GamepadButton>(std::stoi(value)); } else if (var == "controller.0.button.service") {
} controllers.at(0).buttons.at(4) = static_cast<SDL_GamepadButton>(std::stoi(value));
else if (var == "controller.0.button.fire_center") } else if (var == "controller.1.name") {
{ controllers.at(1).name = value;
controllers.at(0).buttons.at(1) = static_cast<SDL_GamepadButton>(std::stoi(value)); } else if (var == "controller.1.player") {
} controllers.at(1).player_id = std::clamp(std::stoi(value), 1, 2);
else if (var == "controller.0.button.fire_right") } else if (var == "controller.1.type") {
{ controllers.at(1).type = static_cast<InputDevice>(std::stoi(value));
controllers.at(0).buttons.at(2) = static_cast<SDL_GamepadButton>(std::stoi(value)); } else if (var == "controller.1.button.fire_left") {
} controllers.at(1).buttons.at(0) = static_cast<SDL_GamepadButton>(std::stoi(value));
else if (var == "controller.0.button.start") } else if (var == "controller.1.button.fire_center") {
{ controllers.at(1).buttons.at(1) = static_cast<SDL_GamepadButton>(std::stoi(value));
controllers.at(0).buttons.at(3) = static_cast<SDL_GamepadButton>(std::stoi(value)); } else if (var == "controller.1.button.fire_right") {
} controllers.at(1).buttons.at(2) = static_cast<SDL_GamepadButton>(std::stoi(value));
else if (var == "controller.0.button.service") } else if (var == "controller.1.button.start") {
{ controllers.at(1).buttons.at(3) = static_cast<SDL_GamepadButton>(std::stoi(value));
controllers.at(0).buttons.at(4) = static_cast<SDL_GamepadButton>(std::stoi(value)); } else if (var == "controller.1.button.service") {
} controllers.at(1).buttons.at(4) = static_cast<SDL_GamepadButton>(std::stoi(value));
else if (var == "controller.1.name") }
{
controllers.at(1).name = value;
}
else if (var == "controller.1.player")
{
controllers.at(1).player_id = std::clamp(std::stoi(value), 1, 2);
}
else if (var == "controller.1.type")
{
controllers.at(1).type = static_cast<InputDevice>(std::stoi(value));
}
else if (var == "controller.1.button.fire_left")
{
controllers.at(1).buttons.at(0) = static_cast<SDL_GamepadButton>(std::stoi(value));
}
else if (var == "controller.1.button.fire_center")
{
controllers.at(1).buttons.at(1) = static_cast<SDL_GamepadButton>(std::stoi(value));
}
else if (var == "controller.1.button.fire_right")
{
controllers.at(1).buttons.at(2) = static_cast<SDL_GamepadButton>(std::stoi(value));
}
else if (var == "controller.1.button.start")
{
controllers.at(1).buttons.at(3) = static_cast<SDL_GamepadButton>(std::stoi(value));
}
else if (var == "controller.1.button.service")
{
controllers.at(1).buttons.at(4) = static_cast<SDL_GamepadButton>(std::stoi(value));
}
// Lineas vacias o que empiezan por comentario // Lineas vacias o que empiezan por comentario
else if (var.empty() || var.starts_with("#")) else if (var.empty() || var.starts_with("#")) {
{ } else {
} success = false;
else }
{
success = false;
}
return success; return success;
} }
// Asigna el teclado al jugador // Asigna el teclado al jugador
void setKeyboardToPlayer(int player_id) void setKeyboardToPlayer(int player_id) {
{ for (auto &controller : controllers) {
for (auto &controller : controllers) if (controller.player_id == player_id) {
{ controller.type = InputDevice::ANY;
if (controller.player_id == player_id) } else {
{ controller.type = InputDevice::CONTROLLER;
controller.type = InputDevice::ANY; }
} }
else }
{
controller.type = InputDevice::CONTROLLER;
}
}
}
// Intercambia el teclado de jugador // Intercambia el teclado de jugador
void swapKeyboard() void swapKeyboard() {
{ std::swap(controllers.at(0).type, controllers.at(1).type);
std::swap(controllers.at(0).type, controllers.at(1).type); }
}
// Intercambia los jugadores asignados a los dos primeros mandos // Intercambia los jugadores asignados a los dos primeros mandos
void swapControllers() void swapControllers() {
{ std::swap(controllers.at(0).player_id, controllers.at(1).player_id);
std::swap(controllers.at(0).player_id, controllers.at(1).player_id); std::swap(controllers.at(0).type, controllers.at(1).type);
std::swap(controllers.at(0).type, controllers.at(1).type); }
}
// Averigua quien está usando el teclado // Averigua quien está usando el teclado
int getPlayerWhoUsesKeyboard() int getPlayerWhoUsesKeyboard() {
{ for (const auto &controller : controllers) {
for (const auto &controller : controllers) if (controller.type == InputDevice::ANY) {
{ return controller.player_id;
if (controller.type == InputDevice::ANY) }
{ }
return controller.player_id; return 0;
} }
}
return 0;
}
// Aplica los cambios pendientes copiando los valores a sus variables // Aplica los cambios pendientes copiando los valores a sus variables
void applyPendingChanges() void applyPendingChanges() {
{ if (pending_changes.has_pending_changes) {
if (pending_changes.has_pending_changes) settings.language = pending_changes.new_language;
{ settings.difficulty = pending_changes.new_difficulty;
settings.language = pending_changes.new_language; pending_changes.has_pending_changes = false;
settings.difficulty = pending_changes.new_difficulty; }
pending_changes.has_pending_changes = false; }
}
}
void checkPendingChanges() void checkPendingChanges() {
{ if (settings.language != pending_changes.new_language ||
if (settings.language != pending_changes.new_language || settings.difficulty != pending_changes.new_difficulty) {
settings.difficulty != pending_changes.new_difficulty) pending_changes.has_pending_changes = true;
{ } else {
pending_changes.has_pending_changes = true; pending_changes.has_pending_changes = false;
} }
else }
{
pending_changes.has_pending_changes = false;
}
}
DifficultyCode getDifficultyCodeFromName(const std::string &name) DifficultyCode getDifficultyCodeFromName(const std::string &name) {
{ for (const auto &difficulty : difficulties) {
for (const auto &difficulty : difficulties) if (difficulty.name == name)
{ return difficulty.code;
if (difficulty.name == name) }
return difficulty.code; // Si no se encuentra, devuelve el primero por defecto
} return difficulties[0].code;
// Si no se encuentra, devuelve el primero por defecto }
return difficulties[0].code;
}
std::string getDifficultyNameFromCode(DifficultyCode code) std::string getDifficultyNameFromCode(DifficultyCode code) {
{ for (const auto &difficulty : difficulties) {
for (const auto &difficulty : difficulties) if (difficulty.code == code)
{ return difficulty.name;
if (difficulty.code == code) }
return difficulty.name; // Si no se encuentra, devuelve el nombre del primero por defecto
} return difficulties[0].name;
// Si no se encuentra, devuelve el nombre del primero por defecto }
return difficulties[0].name; } // namespace Options
}
} // namespace Options
+164 -175
View File
@@ -1,202 +1,191 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_GamepadButton, SDL_ScaleMode #include <SDL3/SDL.h> // Para SDL_GamepadButton, SDL_ScaleMode
#include <string> // Para string, basic_string
#include <vector> // Para vector
#include "input.h" // Para InputAction, InputDevice #include <string> // Para string, basic_string
#include "lang.h" // Para Code #include <vector> // Para vector
#include "manage_hiscore_table.h" // Para HiScoreEntry
#include "input.h" // Para InputAction, InputDevice
#include "lang.h" // Para Code
#include "manage_hiscore_table.h" // Para HiScoreEntry
static constexpr int INVALID_INDEX = -1; static constexpr int INVALID_INDEX = -1;
namespace Options namespace Options {
{ // --- Dificultad del juego ---
// --- Dificultad del juego --- enum class DifficultyCode {
enum class DifficultyCode EASY = 0,
{ NORMAL = 1,
EASY = 0, HARD = 2,
NORMAL = 1, };
HARD = 2,
};
// --- Estructura que representa un nivel de dificultad // --- Estructura que representa un nivel de dificultad
struct Difficulty struct Difficulty {
{ DifficultyCode code; // Código que identifica la dificultad
DifficultyCode code; // Código que identifica la dificultad std::string name; // Nombre que identifica la dificultad
std::string name; // Nombre que identifica la dificultad
Difficulty(DifficultyCode c, const std::string &n) Difficulty(DifficultyCode c, const std::string &n)
: code(c), name(n) {} : code(c), name(n) {}
}; };
// --- Opciones de ventana --- // --- Opciones de ventana ---
struct WindowOptions struct WindowOptions {
{ std::string caption; // Texto que aparece en la barra de título de la ventana
std::string caption; // Texto que aparece en la barra de título de la ventana int size; // Valor por el que se multiplica el tamaño de la ventana
int size; // Valor por el que se multiplica el tamaño de la ventana int max_size; // Tamaño máximo para que la ventana no sea mayor que la pantalla
int max_size; // Tamaño máximo para que la ventana no sea mayor que la pantalla
// Constructor por defecto con valores iniciales // Constructor por defecto con valores iniciales
WindowOptions() WindowOptions()
: caption("Coffee Crisis Arcade Edition"), : caption("Coffee Crisis Arcade Edition"),
size(2), size(2),
max_size(2) {} max_size(2) {}
}; };
// --- Opciones de vídeo --- // --- Opciones de vídeo ---
struct VideoOptions struct VideoOptions {
{ SDL_ScaleMode scale_mode; // Filtro usado para el escalado de la imagen
SDL_ScaleMode scale_mode; // Filtro usado para el escalado de la imagen bool fullscreen; // Indica si se usa pantalla completa
bool fullscreen; // Indica si se usa pantalla completa bool v_sync; // Indica si se usa vsync
bool v_sync; // Indica si se usa vsync bool integer_scale; // Indica si se usa escalado entero
bool integer_scale; // Indica si se usa escalado entero bool shaders; // Indica si se usan shaders para los filtros de vídeo
bool shaders; // Indica si se usan shaders para los filtros de vídeo std::string info; // Información sobre el modo de vídeo
std::string info; // Información sobre el modo de vídeo
// Constructor por defecto con valores iniciales // Constructor por defecto con valores iniciales
VideoOptions() VideoOptions()
: scale_mode(SDL_ScaleMode::SDL_SCALEMODE_NEAREST), : scale_mode(SDL_ScaleMode::SDL_SCALEMODE_NEAREST),
fullscreen(false), fullscreen(false),
v_sync(true), v_sync(true),
integer_scale(true), integer_scale(true),
shaders(false), shaders(false),
info() {} info() {}
}; };
// --- Opciones de música --- // --- Opciones de música ---
struct MusicOptions struct MusicOptions {
{ bool enabled; // Indica si la música suena o no
bool enabled; // Indica si la música suena o no int volume; // Volumen de la música
int volume; // Volumen de la música
// Constructor por defecto // Constructor por defecto
MusicOptions() MusicOptions()
: enabled(true), : enabled(true),
volume(100) {} volume(100) {}
}; };
// --- Opciones de sonido --- // --- Opciones de sonido ---
struct SoundOptions struct SoundOptions {
{ bool enabled; // Indica si los sonidos suenan o no
bool enabled; // Indica si los sonidos suenan o no int volume; // Volumen de los sonidos
int volume; // Volumen de los sonidos
// Constructor por defecto // Constructor por defecto
SoundOptions() SoundOptions()
: enabled(true), : enabled(true),
volume(100) {} volume(100) {}
}; };
// --- Opciones de audio --- // --- Opciones de audio ---
struct AudioOptions struct AudioOptions {
{ MusicOptions music; // Opciones para la música
MusicOptions music; // Opciones para la música SoundOptions sound; // Opciones para los efectos de sonido
SoundOptions sound; // Opciones para los efectos de sonido bool enabled; // Indica si el audio está activo o no
bool enabled; // Indica si el audio está activo o no int volume; // Volumen general del audio
int volume; // Volumen general del audio
// Constructor por defecto // Constructor por defecto
AudioOptions() AudioOptions()
: music(), : music(),
sound(), sound(),
enabled(true), enabled(true),
volume(100) {} volume(100) {}
}; };
// --- Opciones de configuración --- // --- Opciones de configuración ---
struct SettingsOptions struct SettingsOptions {
{ DifficultyCode difficulty; // Dificultad del juego
DifficultyCode difficulty; // Dificultad del juego Lang::Code language; // Idioma usado en el juego
Lang::Code language; // Idioma usado en el juego bool autofire; // Indicador de autofire
bool autofire; // Indicador de autofire bool shutdown_enabled; // Especifica si se puede apagar el sistema
bool shutdown_enabled; // Especifica si se puede apagar el sistema std::vector<HiScoreEntry> hi_score_table; // Tabla de mejores puntuaciones
std::vector<HiScoreEntry> hi_score_table; // Tabla de mejores puntuaciones std::vector<int> last_hi_score_entry; // Últimas posiciones de entrada en la tabla
std::vector<int> last_hi_score_entry; // Últimas posiciones de entrada en la tabla std::string config_file; // Ruta al fichero donde guardar la configuración y las opciones del juego
std::string config_file; // Ruta al fichero donde guardar la configuración y las opciones del juego
// Constructor por defecto con valores iniciales // Constructor por defecto con valores iniciales
SettingsOptions() SettingsOptions()
: difficulty(DifficultyCode::NORMAL), : difficulty(DifficultyCode::NORMAL),
language(Lang::Code::VALENCIAN), language(Lang::Code::VALENCIAN),
autofire(true), autofire(true),
shutdown_enabled(false), shutdown_enabled(false),
last_hi_score_entry({INVALID_INDEX, INVALID_INDEX}), last_hi_score_entry({INVALID_INDEX, INVALID_INDEX}),
config_file() {} config_file() {}
// Reinicia las últimas entradas de puntuación // Reinicia las últimas entradas de puntuación
void clearLastHiScoreEntries() void clearLastHiScoreEntries() {
{ last_hi_score_entry[0] = INVALID_INDEX;
last_hi_score_entry[0] = INVALID_INDEX; last_hi_score_entry[1] = INVALID_INDEX;
last_hi_score_entry[1] = INVALID_INDEX; }
} };
};
// --- Opciones de mando --- // --- Opciones de mando ---
struct GamepadOptions struct GamepadOptions {
{ int index; // Índice en el vector de mandos
int index; // Índice en el vector de mandos int player_id; // Jugador asociado al mando
int player_id; // Jugador asociado al mando InputDevice type; // Indica si se usará teclado, mando o ambos
InputDevice type; // Indica si se usará teclado, mando o ambos std::string name; // Nombre del dispositivo
std::string name; // Nombre del dispositivo bool plugged; // Indica si el mando está conectado
bool plugged; // Indica si el mando está conectado std::vector<InputAction> inputs; // Listado de acciones asignadas
std::vector<InputAction> inputs; // Listado de acciones asignadas std::vector<SDL_GamepadButton> buttons; // Listado de botones asignados a cada acción
std::vector<SDL_GamepadButton> buttons; // Listado de botones asignados a cada acción
// Constructor por defecto // Constructor por defecto
GamepadOptions() GamepadOptions()
: index(INVALID_INDEX), : index(INVALID_INDEX),
player_id(INVALID_INDEX), player_id(INVALID_INDEX),
type(InputDevice::CONTROLLER), type(InputDevice::CONTROLLER),
name(), name(),
plugged(false), plugged(false),
inputs{ inputs{
InputAction::FIRE_LEFT, InputAction::FIRE_LEFT,
InputAction::FIRE_CENTER, InputAction::FIRE_CENTER,
InputAction::FIRE_RIGHT, InputAction::FIRE_RIGHT,
InputAction::START, InputAction::START,
InputAction::SERVICE}, InputAction::SERVICE},
buttons{ buttons{
SDL_GAMEPAD_BUTTON_WEST, SDL_GAMEPAD_BUTTON_WEST,
SDL_GAMEPAD_BUTTON_NORTH, SDL_GAMEPAD_BUTTON_NORTH,
SDL_GAMEPAD_BUTTON_EAST, SDL_GAMEPAD_BUTTON_EAST,
SDL_GAMEPAD_BUTTON_START, SDL_GAMEPAD_BUTTON_START,
SDL_GAMEPAD_BUTTON_BACK} {} SDL_GAMEPAD_BUTTON_BACK} {}
}; };
// --- Opciones pendientes de aplicar --- // --- Opciones pendientes de aplicar ---
struct PendingChanges struct PendingChanges {
{ Lang::Code new_language; // Idioma en espera de aplicar
Lang::Code new_language; // Idioma en espera de aplicar DifficultyCode new_difficulty; // Dificultad en espera de aplicar
DifficultyCode new_difficulty; // Dificultad en espera de aplicar bool has_pending_changes; // Indica si hay cambios pendientes
bool has_pending_changes; // Indica si hay cambios pendientes
// Constructor por defecto con valores iniciales // Constructor por defecto con valores iniciales
PendingChanges() PendingChanges()
: new_language(Lang::Code::VALENCIAN), : new_language(Lang::Code::VALENCIAN),
new_difficulty(DifficultyCode::NORMAL), new_difficulty(DifficultyCode::NORMAL),
has_pending_changes(false) {} has_pending_changes(false) {}
}; };
// --- Variables globales --- // --- Variables globales ---
extern WindowOptions window; // Opciones de la ventana extern WindowOptions window; // Opciones de la ventana
extern SettingsOptions settings; // Opciones del juego extern SettingsOptions settings; // Opciones del juego
extern VideoOptions video; // Opciones de vídeo extern VideoOptions video; // Opciones de vídeo
extern AudioOptions audio; // Opciones de audio extern AudioOptions audio; // Opciones de audio
extern std::vector<GamepadOptions> controllers; // Opciones de mando para cada jugador extern std::vector<GamepadOptions> controllers; // Opciones de mando para cada jugador
extern PendingChanges pending_changes; // Opciones que se aplican al cerrar extern PendingChanges pending_changes; // Opciones que se aplican al cerrar
extern std::vector<Difficulty> difficulties; // Lista de los diferentes tipos de dificultad extern std::vector<Difficulty> difficulties; // Lista de los diferentes tipos de dificultad
// --- Funciones de configuración --- // --- Funciones de configuración ---
void init(); // Inicializa las opciones del programa void init(); // Inicializa las opciones del programa
bool loadFromFile(); // Carga el fichero de configuración bool loadFromFile(); // Carga el fichero de configuración
bool saveToFile(); // Guarda el fichero de configuración bool saveToFile(); // Guarda el fichero de configuración
void setKeyboardToPlayer(int player_id); // Asigna el teclado al jugador void setKeyboardToPlayer(int player_id); // Asigna el teclado al jugador
void swapKeyboard(); // Intercambia el teclado de jugador void swapKeyboard(); // Intercambia el teclado de jugador
void swapControllers(); // Intercambia los jugadores asignados a los dos primeros mandos void swapControllers(); // Intercambia los jugadores asignados a los dos primeros mandos
int getPlayerWhoUsesKeyboard(); // Averigua quién está usando el teclado int getPlayerWhoUsesKeyboard(); // Averigua quién está usando el teclado
void applyPendingChanges(); // Aplica los cambios pendientes copiando los valores a sus variables void applyPendingChanges(); // Aplica los cambios pendientes copiando los valores a sus variables
void checkPendingChanges(); // Verifica si hay cambios pendientes void checkPendingChanges(); // Verifica si hay cambios pendientes
DifficultyCode getDifficultyCodeFromName(const std::string &name); // Obtiene el código de dificultad a partir del nombre DifficultyCode getDifficultyCodeFromName(const std::string &name); // Obtiene el código de dificultad a partir del nombre
std::string getDifficultyNameFromCode(DifficultyCode code); // Obtiene el nombre de la dificultad a partir del código std::string getDifficultyNameFromCode(DifficultyCode code); // Obtiene el nombre de la dificultad a partir del código
} // namespace Options } // namespace Options
+398 -477
View File
@@ -1,12 +1,13 @@
#include "param.h" #include "param.h"
#include <SDL3/SDL.h> // Para SDL_LogCategory, SDL_LogError, SDL_LogInfo #include <SDL3/SDL.h> // Para SDL_LogCategory, SDL_LogError, SDL_LogInfo
#include <fstream> // Para basic_istream, basic_ifstream, ifstream
#include <sstream> // Para basic_istringstream
#include <stdexcept> // Para runtime_error
#include <string> // Para operator==, stoi, char_traits, string, ope...
#include "utils.h" // Para Zone, Color, NotifyPosition, getFileName #include <fstream> // Para basic_istream, basic_ifstream, ifstream
#include <sstream> // Para basic_istringstream
#include <stdexcept> // Para runtime_error
#include <string> // Para operator==, stoi, char_traits, string, ope...
#include "utils.h" // Para Zone, Color, NotifyPosition, getFileName
Param param; Param param;
@@ -17,500 +18,420 @@ void precalculateZones();
bool setParams(const std::string &var, const std::string &value); bool setParams(const std::string &var, const std::string &value);
// Establece valores por defecto a las variables // Establece valores por defecto a las variables
void initParam() void initParam() {
{ // GAME
// GAME param.game.width = 320;
param.game.width = 320; param.game.height = 256;
param.game.height = 256; param.game.item_size = 20;
param.game.item_size = 20; param.game.game_area.rect = {0, 0, param.game.width, param.game.height};
param.game.game_area.rect = {0, 0, param.game.width, param.game.height}; param.game.play_area.rect = {0, 0, param.game.width, 216};
param.game.play_area.rect = {0, 0, param.game.width, 216}; param.game.name_entry_idle_time = 10;
param.game.name_entry_idle_time = 10; param.game.name_entry_total_time = 60;
param.game.name_entry_total_time = 60; param.game.speed = 15;
param.game.speed = 15; param.game.hit_stop = true;
param.game.hit_stop = true; param.game.hit_stop_ms = 300;
param.game.hit_stop_ms = 300; precalculateZones();
precalculateZones();
// SCOREBOARD // SCOREBOARD
param.scoreboard.rect = {0, 216, param.game.width, 40}; param.scoreboard.rect = {0, 216, param.game.width, 40};
param.scoreboard.separator_autocolor = false; param.scoreboard.separator_autocolor = false;
param.scoreboard.separator_color = Color(); param.scoreboard.separator_color = Color();
param.scoreboard.easy_color = Color(); param.scoreboard.easy_color = Color();
param.scoreboard.normal_color = Color(); param.scoreboard.normal_color = Color();
param.scoreboard.hard_color = Color(); param.scoreboard.hard_color = Color();
param.scoreboard.text_autocolor = false; param.scoreboard.text_autocolor = false;
param.scoreboard.text_color1 = Color(); param.scoreboard.text_color1 = Color();
param.scoreboard.text_color2 = Color(); param.scoreboard.text_color2 = Color();
param.scoreboard.skip_countdown_value = 8; param.scoreboard.skip_countdown_value = 8;
// FADE // FADE
param.fade.num_squares_width = param.game.width / 2; param.fade.num_squares_width = param.game.width / 2;
param.fade.num_squares_height = param.game.height / 2; param.fade.num_squares_height = param.game.height / 2;
param.fade.random_squares_delay = 1; param.fade.random_squares_delay = 1;
param.fade.random_squares_mult = 500; param.fade.random_squares_mult = 500;
param.fade.post_duration = 80; param.fade.post_duration = 80;
param.fade.venetian_size = 16; param.fade.venetian_size = 16;
// TITLE // TITLE
param.title.press_start_position = 160; param.title.press_start_position = 160;
param.title.title_duration = 800; param.title.title_duration = 800;
param.title.arcade_edition_position = 123; param.title.arcade_edition_position = 123;
param.title.title_c_c_position = 11; param.title.title_c_c_position = 11;
param.title.bg_color = Color(255, 255, 255); param.title.bg_color = Color(255, 255, 255);
// BACKGROUND // BACKGROUND
param.background.attenuate_color = Color(255, 255, 255, 0); param.background.attenuate_color = Color(255, 255, 255, 0);
// BALLOONS // BALLOONS
param.balloon.settings.at(0) = ParamBalloon::Settings(0.09f, 2.60f); param.balloon.settings.at(0) = ParamBalloon::Settings(0.09f, 2.60f);
param.balloon.settings.at(1) = ParamBalloon::Settings(0.10f, 3.50f); param.balloon.settings.at(1) = ParamBalloon::Settings(0.10f, 3.50f);
param.balloon.settings.at(2) = ParamBalloon::Settings(0.10f, 4.50f); param.balloon.settings.at(2) = ParamBalloon::Settings(0.10f, 4.50f);
param.balloon.settings.at(3) = ParamBalloon::Settings(0.10f, 4.95f); param.balloon.settings.at(3) = ParamBalloon::Settings(0.10f, 4.95f);
param.balloon.color.at(0) = "blue"; param.balloon.color.at(0) = "blue";
param.balloon.color.at(1) = "orange"; param.balloon.color.at(1) = "orange";
param.balloon.color.at(2) = "red"; param.balloon.color.at(2) = "red";
param.balloon.color.at(3) = "green"; param.balloon.color.at(3) = "green";
param.balloon.bouncing_sound = false; param.balloon.bouncing_sound = false;
// NOTIFICATION // NOTIFICATION
param.notification.pos_v = NotifyPosition::TOP; param.notification.pos_v = NotifyPosition::TOP;
param.notification.pos_h = NotifyPosition::LEFT; param.notification.pos_h = NotifyPosition::LEFT;
param.notification.sound = false; param.notification.sound = false;
param.notification.color = Color(48, 48, 48); param.notification.color = Color(48, 48, 48);
// INTRO // INTRO
param.intro.bg_color = Color::fromHex("543149"); param.intro.bg_color = Color::fromHex("543149");
param.intro.card_color = Color::fromHex("CBDBFC"); param.intro.card_color = Color::fromHex("CBDBFC");
param.intro.shadow_color = Color::fromHex("00000080"); param.intro.shadow_color = Color::fromHex("00000080");
param.intro.text_distance_from_bottom = 48; param.intro.text_distance_from_bottom = 48;
} }
// Carga los parámetros desde un archivo // Carga los parámetros desde un archivo
void loadParamsFromFile(const std::string &file_path) void loadParamsFromFile(const std::string &file_path) {
{ // Inicializa los parámetros con valores por defecto
// Inicializa los parámetros con valores por defecto initParam();
initParam();
// Abre el archivo // Abre el archivo
std::ifstream file(file_path); std::ifstream file(file_path);
if (!file.is_open()) if (!file.is_open()) {
{ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo abrir el archivo %s", file_path.c_str());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo abrir el archivo %s", file_path.c_str()); throw std::runtime_error("No se pudo abrir el archivo: " + file_path);
throw std::runtime_error("No se pudo abrir el archivo: " + file_path); }
}
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\nReading file: %s", getFileName(file_path).c_str()); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\nReading file: %s", getFileName(file_path).c_str());
std::string line, param1, param2; std::string line, param1, param2;
while (std::getline(file, line)) while (std::getline(file, line)) {
{ // Elimina comentarios
// Elimina comentarios auto comment_pos = line.find('#');
auto comment_pos = line.find('#'); if (comment_pos != std::string::npos) {
if (comment_pos != std::string::npos) line.resize(comment_pos);
{ }
line.resize(comment_pos);
}
// Usa un stream para separar palabras // Usa un stream para separar palabras
std::istringstream iss(line); std::istringstream iss(line);
if (iss >> param1 >> param2) if (iss >> param1 >> param2) {
{ if (!setParams(param1, param2)) {
if (!setParams(param1, param2)) SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Parámetro desconocido: %s", param1.c_str());
{ }
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Parámetro desconocido: %s", param1.c_str()); }
} }
}
}
// Cierra el archivo // Cierra el archivo
file.close(); file.close();
// Realiza cálculos adicionales después de cargar los parámetros // Realiza cálculos adicionales después de cargar los parámetros
precalculateZones(); precalculateZones();
} }
// Asigna variables a partir de dos cadenas // Asigna variables a partir de dos cadenas
bool setParams(const std::string &var, const std::string &value) bool setParams(const std::string &var, const std::string &value) {
{ // Indicador de éxito en la asignación
// Indicador de éxito en la asignación auto success = true;
auto success = true;
// GAME
// GAME if (var == "game.width") {
if (var == "game.width") param.game.width = std::stoi(value);
{ }
param.game.width = std::stoi(value);
} else if (var == "game.height") {
param.game.height = std::stoi(value);
else if (var == "game.height") }
{
param.game.height = std::stoi(value); else if (var == "game.item_size") {
} param.game.item_size = std::stoi(value);
}
else if (var == "game.item_size")
{ else if (var == "game.play_area.rect.x") {
param.game.item_size = std::stoi(value); param.game.play_area.rect.x = std::stoi(value);
} }
else if (var == "game.play_area.rect.x") else if (var == "game.play_area.rect.y") {
{ param.game.play_area.rect.y = std::stoi(value);
param.game.play_area.rect.x = std::stoi(value); }
}
else if (var == "game.play_area.rect.w") {
else if (var == "game.play_area.rect.y") param.game.play_area.rect.w = std::stoi(value);
{ }
param.game.play_area.rect.y = std::stoi(value);
} else if (var == "game.play_area.rect.h") {
param.game.play_area.rect.h = std::stoi(value);
else if (var == "game.play_area.rect.w") }
{
param.game.play_area.rect.w = std::stoi(value); else if (var == "game.name_entry_idle_time") {
} param.game.name_entry_idle_time = std::stoi(value);
}
else if (var == "game.play_area.rect.h")
{ else if (var == "game.name_entry_total_time") {
param.game.play_area.rect.h = std::stoi(value); param.game.name_entry_total_time = std::stoi(value);
} }
else if (var == "game.name_entry_idle_time") else if (var == "game.hit_stop") {
{ param.game.hit_stop = stringToBool(value);
param.game.name_entry_idle_time = std::stoi(value); }
}
else if (var == "game.hit_stop_ms") {
else if (var == "game.name_entry_total_time") param.game.hit_stop_ms = std::stoi(value);
{ }
param.game.name_entry_total_time = std::stoi(value);
} // FADE
else if (var == "fade.color") {
else if (var == "game.hit_stop") param.fade.color = Color::fromHex(value);
{ }
param.game.hit_stop = stringToBool(value);
} else if (var == "fade.num_squares_width") {
param.fade.num_squares_width = std::stoi(value);
else if (var == "game.hit_stop_ms") }
{
param.game.hit_stop_ms = std::stoi(value); else if (var == "fade.num_squares_height") {
} param.fade.num_squares_height = std::stoi(value);
}
// FADE
else if (var == "fade.color") else if (var == "fade.random_squares_delay") {
{ param.fade.random_squares_delay = std::stoi(value);
param.fade.color = Color::fromHex(value); }
}
else if (var == "fade.random_squares_mult") {
else if (var == "fade.num_squares_width") param.fade.random_squares_mult = std::stoi(value);
{ }
param.fade.num_squares_width = std::stoi(value);
} else if (var == "fade.post_duration") {
param.fade.post_duration = std::stoi(value);
else if (var == "fade.num_squares_height") }
{
param.fade.num_squares_height = std::stoi(value); else if (var == "fade.venetian_size") {
} param.fade.venetian_size = std::stoi(value);
}
else if (var == "fade.random_squares_delay")
{ // SCOREBOARD
param.fade.random_squares_delay = std::stoi(value); else if (var == "scoreboard.rect.x") {
} param.scoreboard.rect.x = std::stoi(value);
}
else if (var == "fade.random_squares_mult")
{ else if (var == "scoreboard.rect.y") {
param.fade.random_squares_mult = std::stoi(value); param.scoreboard.rect.y = std::stoi(value);
} }
else if (var == "fade.post_duration") else if (var == "scoreboard.rect.w") {
{ param.scoreboard.rect.w = std::stoi(value);
param.fade.post_duration = std::stoi(value); }
}
else if (var == "scoreboard.rect.h") {
else if (var == "fade.venetian_size") param.scoreboard.rect.h = std::stoi(value);
{ }
param.fade.venetian_size = std::stoi(value);
} else if (var == "scoreboard.separator_autocolor") {
param.scoreboard.separator_autocolor = stringToBool(value);
// SCOREBOARD }
else if (var == "scoreboard.rect.x")
{ else if (var == "scoreboard.separator_color") {
param.scoreboard.rect.x = std::stoi(value); param.scoreboard.separator_color = Color::fromHex(value);
} }
else if (var == "scoreboard.rect.y") else if (var == "scoreboard.easy_color") {
{ param.scoreboard.easy_color = Color::fromHex(value);
param.scoreboard.rect.y = std::stoi(value); }
}
else if (var == "scoreboard.normal_color") {
else if (var == "scoreboard.rect.w") param.scoreboard.normal_color = Color::fromHex(value);
{ }
param.scoreboard.rect.w = std::stoi(value);
} else if (var == "scoreboard.hard_color") {
param.scoreboard.hard_color = Color::fromHex(value);
else if (var == "scoreboard.rect.h") }
{
param.scoreboard.rect.h = std::stoi(value); else if (var == "scoreboard.text_autocolor") {
} param.scoreboard.text_autocolor = stringToBool(value);
}
else if (var == "scoreboard.separator_autocolor")
{ else if (var == "scoreboard.text_color1") {
param.scoreboard.separator_autocolor = stringToBool(value); param.scoreboard.text_color1 = Color::fromHex(value);
} }
else if (var == "scoreboard.separator_color") else if (var == "scoreboard.text_color2") {
{ param.scoreboard.text_color2 = Color::fromHex(value);
param.scoreboard.separator_color = Color::fromHex(value); }
}
else if (var == "scoreboard.skip_countdown_value") {
else if (var == "scoreboard.easy_color") param.scoreboard.skip_countdown_value = std::stoi(value);
{ }
param.scoreboard.easy_color = Color::fromHex(value);
} // TITLE
else if (var == "title.press_start_position") {
else if (var == "scoreboard.normal_color") param.title.press_start_position = std::stoi(value);
{ }
param.scoreboard.normal_color = Color::fromHex(value);
} else if (var == "title.title_duration") {
param.title.title_duration = std::stoi(value);
else if (var == "scoreboard.hard_color") }
{
param.scoreboard.hard_color = Color::fromHex(value); else if (var == "title.arcade_edition_position") {
} param.title.arcade_edition_position = std::stoi(value);
}
else if (var == "scoreboard.text_autocolor")
{ else if (var == "title.title_c_c_position") {
param.scoreboard.text_autocolor = stringToBool(value); param.title.title_c_c_position = std::stoi(value);
} }
else if (var == "scoreboard.text_color1") else if (var == "title.bg_color") {
{ param.title.bg_color = Color::fromHex(value);
param.scoreboard.text_color1 = Color::fromHex(value); }
}
// BACKGROUND
else if (var == "scoreboard.text_color2") else if (var == "background.attenuate_color") {
{ param.background.attenuate_color = Color::fromHex(value);
param.scoreboard.text_color2 = Color::fromHex(value); }
}
// BALLOON
else if (var == "scoreboard.skip_countdown_value") else if (var == "balloon.settings[0].vel") {
{ param.balloon.settings.at(0).vel = std::stof(value);
param.scoreboard.skip_countdown_value = std::stoi(value); }
}
else if (var == "balloon.settings[0].grav") {
// TITLE param.balloon.settings.at(0).grav = std::stof(value);
else if (var == "title.press_start_position") }
{
param.title.press_start_position = std::stoi(value); else if (var == "balloon.settings[1].vel") {
} param.balloon.settings.at(1).vel = std::stof(value);
}
else if (var == "title.title_duration")
{ else if (var == "balloon.settings[1].grav") {
param.title.title_duration = std::stoi(value); param.balloon.settings.at(1).grav = std::stof(value);
} }
else if (var == "title.arcade_edition_position") else if (var == "balloon.settings[2].vel") {
{ param.balloon.settings.at(2).vel = std::stof(value);
param.title.arcade_edition_position = std::stoi(value); }
}
else if (var == "balloon.settings[2].grav") {
else if (var == "title.title_c_c_position") param.balloon.settings.at(2).grav = std::stof(value);
{ }
param.title.title_c_c_position = std::stoi(value);
} else if (var == "balloon.settings[3].vel") {
param.balloon.settings.at(3).vel = std::stof(value);
else if (var == "title.bg_color") }
{
param.title.bg_color = Color::fromHex(value); else if (var == "balloon.settings[3].grav") {
} param.balloon.settings.at(3).grav = std::stof(value);
}
// BACKGROUND
else if (var == "background.attenuate_color") else if (var == "balloon.color[0]") {
{ param.balloon.color.at(0) = value;
param.background.attenuate_color = Color::fromHex(value); }
}
else if (var == "balloon.color[1]") {
// BALLOON param.balloon.color.at(1) = value;
else if (var == "balloon.settings[0].vel") }
{
param.balloon.settings.at(0).vel = std::stof(value); else if (var == "balloon.color[2]") {
} param.balloon.color.at(2) = value;
}
else if (var == "balloon.settings[0].grav")
{ else if (var == "balloon.color[3]") {
param.balloon.settings.at(0).grav = std::stof(value); param.balloon.color.at(3) = value;
} }
else if (var == "balloon.settings[1].vel") else if (var == "balloon.bouncing_sound") {
{ param.balloon.bouncing_sound = stringToBool(value);
param.balloon.settings.at(1).vel = std::stof(value); }
}
// NOTIFICACIONES
else if (var == "balloon.settings[1].grav") else if (var == "notification.pos_h") {
{ if (value == "LEFT") {
param.balloon.settings.at(1).grav = std::stof(value); param.notification.pos_h = NotifyPosition::LEFT;
} } else if (value == "MIDDLE") {
param.notification.pos_h = NotifyPosition::MIDDLE;
else if (var == "balloon.settings[2].vel") } else {
{ param.notification.pos_h = NotifyPosition::RIGHT;
param.balloon.settings.at(2).vel = std::stof(value); }
} }
else if (var == "balloon.settings[2].grav") else if (var == "notification.pos_v") {
{ param.notification.pos_v = value == "TOP" ? NotifyPosition::TOP : NotifyPosition::BOTTOM;
param.balloon.settings.at(2).grav = std::stof(value); }
}
else if (var == "notification.sound") {
else if (var == "balloon.settings[3].vel") param.notification.sound = stringToBool(value);
{ }
param.balloon.settings.at(3).vel = std::stof(value);
} else if (var == "notification.color") {
param.notification.color = Color::fromHex(value);
else if (var == "balloon.settings[3].grav") }
{
param.balloon.settings.at(3).grav = std::stof(value); // SERVICE MENU
} else if (var == "service_menu.title_color") {
param.service_menu.title_color = Color::fromHex(value);
else if (var == "balloon.color[0]") }
{
param.balloon.color.at(0) = value; else if (var == "service_menu.text_color") {
} param.service_menu.text_color = Color::fromHex(value);
}
else if (var == "balloon.color[1]")
{ else if (var == "service_menu.selected_color") {
param.balloon.color.at(1) = value; param.service_menu.selected_color = Color::fromHex(value);
} }
else if (var == "balloon.color[2]") else if (var == "service_menu.bg_color") {
{ param.service_menu.bg_color = Color::fromHex(value);
param.balloon.color.at(2) = value; }
}
else if (var == "service_menu.drop_shadow") {
else if (var == "balloon.color[3]") param.service_menu.drop_shadow = stringToBool(value);
{ }
param.balloon.color.at(3) = value;
} // INTRO
else if (var == "intro.bg_color") {
else if (var == "balloon.bouncing_sound") param.intro.bg_color = Color::fromHex(value);
{ }
param.balloon.bouncing_sound = stringToBool(value);
} else if (var == "intro.card_color") {
param.intro.card_color = Color::fromHex(value);
// NOTIFICACIONES }
else if (var == "notification.pos_h")
{ else if (var == "intro.shadow_color") {
if (value == "LEFT") param.intro.shadow_color = Color::fromHex(value);
{ }
param.notification.pos_h = NotifyPosition::LEFT;
} else if (var == "intro.text_distance_from_bottom") {
else if (value == "MIDDLE") param.intro.text_distance_from_bottom = std::stoi(value);
{ }
param.notification.pos_h = NotifyPosition::MIDDLE;
} // DEBUG
else else if (var == "debug.color") {
{ param.debug.color = Color::fromHex(value);
param.notification.pos_h = NotifyPosition::RIGHT; }
}
} // RESOURCE
else if (var == "resource.color") {
else if (var == "notification.pos_v") param.resource.color = Color::fromHex(value);
{ }
param.notification.pos_v = value == "TOP" ? NotifyPosition::TOP : NotifyPosition::BOTTOM;
} // RESTO
else {
else if (var == "notification.sound") success = false;
{ }
param.notification.sound = stringToBool(value);
} return success;
else if (var == "notification.color")
{
param.notification.color = Color::fromHex(value);
}
// SERVICE MENU
else if (var == "service_menu.title_color")
{
param.service_menu.title_color = Color::fromHex(value);
}
else if (var == "service_menu.text_color")
{
param.service_menu.text_color = Color::fromHex(value);
}
else if (var == "service_menu.selected_color")
{
param.service_menu.selected_color = Color::fromHex(value);
}
else if (var == "service_menu.bg_color")
{
param.service_menu.bg_color = Color::fromHex(value);
}
else if (var == "service_menu.drop_shadow")
{
param.service_menu.drop_shadow = stringToBool(value);
}
// INTRO
else if (var == "intro.bg_color")
{
param.intro.bg_color = Color::fromHex(value);
}
else if (var == "intro.card_color")
{
param.intro.card_color = Color::fromHex(value);
}
else if (var == "intro.shadow_color")
{
param.intro.shadow_color = Color::fromHex(value);
}
else if (var == "intro.text_distance_from_bottom")
{
param.intro.text_distance_from_bottom = std::stoi(value);
}
// DEBUG
else if (var == "debug.color")
{
param.debug.color = Color::fromHex(value);
}
// RESOURCE
else if (var == "resource.color")
{
param.resource.color = Color::fromHex(value);
}
// RESTO
else
{
success = false;
}
return success;
} }
// Calcula variables a partir de otras variables // Calcula variables a partir de otras variables
void precalculateZones() void precalculateZones() {
{ // playArea
// playArea param.game.play_area.center_x = param.game.play_area.rect.w / 2;
param.game.play_area.center_x = param.game.play_area.rect.w / 2; param.game.play_area.first_quarter_x = param.game.play_area.rect.w / 4;
param.game.play_area.first_quarter_x = param.game.play_area.rect.w / 4; param.game.play_area.third_quarter_x = param.game.play_area.rect.w / 4 * 3;
param.game.play_area.third_quarter_x = param.game.play_area.rect.w / 4 * 3; param.game.play_area.center_y = param.game.play_area.rect.h / 2;
param.game.play_area.center_y = param.game.play_area.rect.h / 2; param.game.play_area.first_quarter_y = param.game.play_area.rect.h / 4;
param.game.play_area.first_quarter_y = param.game.play_area.rect.h / 4; param.game.play_area.third_quarter_y = param.game.play_area.rect.h / 4 * 3;
param.game.play_area.third_quarter_y = param.game.play_area.rect.h / 4 * 3;
// gameArea // gameArea
param.game.game_area.rect = {0, 0, param.game.width, param.game.height}; param.game.game_area.rect = {0, 0, param.game.width, param.game.height};
param.game.game_area.center_x = param.game.game_area.rect.w / 2; param.game.game_area.center_x = param.game.game_area.rect.w / 2;
param.game.game_area.first_quarter_x = param.game.game_area.rect.w / 4; param.game.game_area.first_quarter_x = param.game.game_area.rect.w / 4;
param.game.game_area.third_quarter_x = param.game.game_area.rect.w / 4 * 3; param.game.game_area.third_quarter_x = param.game.game_area.rect.w / 4 * 3;
param.game.game_area.center_y = param.game.game_area.rect.h / 2; param.game.game_area.center_y = param.game.game_area.rect.h / 2;
param.game.game_area.first_quarter_y = param.game.game_area.rect.h / 4; param.game.game_area.first_quarter_y = param.game.game_area.rect.h / 4;
param.game.game_area.third_quarter_y = param.game.game_area.rect.h / 4 * 3; param.game.game_area.third_quarter_y = param.game.game_area.rect.h / 4 * 3;
} }
+71 -84
View File
@@ -1,61 +1,56 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para Uint32, SDL_FRect #include <SDL3/SDL.h> // Para Uint32, SDL_FRect
#include <array> // Para array
#include <string> // Para basic_string, string
#include "utils.h" // Para Color, NotifyPosition (ptr only), Zone #include <array> // Para array
#include <string> // Para basic_string, string
#include "utils.h" // Para Color, NotifyPosition (ptr only), Zone
// --- Parámetros del juego --- // --- Parámetros del juego ---
struct ParamGame struct ParamGame {
{ float width; // Ancho de la resolución nativa del juego
float width; // Ancho de la resolución nativa del juego float height; // Alto de la resolución nativa del juego
float height; // Alto de la resolución nativa del juego float item_size; // Tamaño de los ítems del juego
float item_size; // Tamaño de los ítems del juego Zone play_area; // Rectángulo con la posición de la zona de juego
Zone play_area; // Rectángulo con la posición de la zona de juego Zone game_area; // Rectángulo con las dimensiones del juego
Zone game_area; // Rectángulo con las dimensiones del juego int name_entry_idle_time; // Segundos para introducir el nombre al finalizar la partida si no se pulsa nada
int name_entry_idle_time; // Segundos para introducir el nombre al finalizar la partida si no se pulsa nada int name_entry_total_time; // Segundos totales para introducir el nombre al finalizar la partida
int name_entry_total_time; // Segundos totales para introducir el nombre al finalizar la partida Uint32 speed; // Velocidad a la que transcurre el juego
Uint32 speed; // Velocidad a la que transcurre el juego bool hit_stop; // Indica si debe haber un paro cuando el jugador es golpeado por un globo
bool hit_stop; // Indica si debe haber un paro cuando el jugador es golpeado por un globo Uint32 hit_stop_ms; // Cantidad de milisegundos que dura el hit_stop
Uint32 hit_stop_ms; // Cantidad de milisegundos que dura el hit_stop
}; };
// --- Parámetros del fade --- // --- Parámetros del fade ---
struct ParamFade struct ParamFade {
{ Color color; // Color del fade
Color color; // Color del fade float num_squares_width; // Cantidad total de cuadraditos en horizontal para el FadeType::RANDOM_SQUARE
float num_squares_width; // Cantidad total de cuadraditos en horizontal para el FadeType::RANDOM_SQUARE float num_squares_height; // Cantidad total de cuadraditos en vertical para el FadeType::RANDOM_SQUARE
float num_squares_height; // Cantidad total de cuadraditos en vertical para el FadeType::RANDOM_SQUARE int random_squares_delay; // Duración entre cada pintado de cuadrados
int random_squares_delay; // Duración entre cada pintado de cuadrados int random_squares_mult; // Cantidad de cuadrados que se pintarán cada vez
int random_squares_mult; // Cantidad de cuadrados que se pintarán cada vez int post_duration; // Duración final del fade
int post_duration; // Duración final del fade float venetian_size; // Altura de los rectángulos para FadeType::VENETIAN
float venetian_size; // Altura de los rectángulos para FadeType::VENETIAN
}; };
// --- Parámetros de la pantalla de título --- // --- Parámetros de la pantalla de título ---
struct ParamTitle struct ParamTitle {
{ int press_start_position; // Posición del texto para empezar a jugar
int press_start_position; // Posición del texto para empezar a jugar int title_duration; // Tiempo de inactividad del título
int title_duration; // Tiempo de inactividad del título int arcade_edition_position; // Posición del bitmap "Arcade Edition"
int arcade_edition_position; // Posición del bitmap "Arcade Edition" int title_c_c_position; // Posición del bitmap "Coffee Crisis"
int title_c_c_position; // Posición del bitmap "Coffee Crisis" Color bg_color; // Color para los tiles de fondo
Color bg_color; // Color para los tiles de fondo
}; };
// --- Parámetros del fondo --- // --- Parámetros del fondo ---
struct ParamBackground struct ParamBackground {
{ Color attenuate_color; // Color para atenuar el fondo
Color attenuate_color; // Color para atenuar el fondo
}; };
// --- Parámetros de los globos --- // --- Parámetros de los globos ---
struct ParamBalloon struct ParamBalloon {
{ struct Settings {
struct Settings float grav; // Aceleración en el eje Y. Modifica la velocidad
{ float vel; // Velocidad inicial al rebotar contra el suelo
float grav; // Aceleración en el eje Y. Modifica la velocidad
float vel; // Velocidad inicial al rebotar contra el suelo
// Constructor // Constructor
explicit Settings(float grav_val = 0.0f, float vel_val = 0.0f) explicit Settings(float grav_val = 0.0f, float vel_val = 0.0f)
@@ -64,36 +59,33 @@ struct ParamBalloon
std::array<Settings, 4> settings; std::array<Settings, 4> settings;
std::array<std::string, 4> color; std::array<std::string, 4> color;
bool bouncing_sound; // Indica si los globos hacer sonido al rebotar bool bouncing_sound; // Indica si los globos hacer sonido al rebotar
}; };
// --- Parámetros de las notificaciones --- // --- Parámetros de las notificaciones ---
struct ParamNotification struct ParamNotification {
{ NotifyPosition pos_h; // Ubicación horizontal de las notificaciones en pantalla
NotifyPosition pos_h; // Ubicación horizontal de las notificaciones en pantalla NotifyPosition pos_v; // Ubicación vertical de las notificaciones en pantalla
NotifyPosition pos_v; // Ubicación vertical de las notificaciones en pantalla bool sound; // Indica si las notificaciones suenan
bool sound; // Indica si las notificaciones suenan Color color; // Color de las notificaciones
Color color; // Color de las notificaciones
}; };
// --- Parámetros del marcador --- // --- Parámetros del marcador ---
struct ParamScoreboard struct ParamScoreboard {
{ SDL_FRect rect; // Posición y tamaño del marcador
SDL_FRect rect; // Posición y tamaño del marcador bool separator_autocolor; // El separado establece su color de forma automatica
bool separator_autocolor; // El separado establece su color de forma automatica Color separator_color; // Color del separador si se pone de forma manual
Color separator_color; // Color del separador si se pone de forma manual Color easy_color; // Color del marcador segun la dificultad
Color easy_color; // Color del marcador segun la dificultad Color normal_color; // Color del marcador segun la dificultad
Color normal_color; // Color del marcador segun la dificultad Color hard_color; // Color del marcador segun la dificultad
Color hard_color; // Color del marcador segun la dificultad bool text_autocolor; // El texto establece su color de forma automatica
bool text_autocolor; // El texto establece su color de forma automatica Color text_color1; // Color del texto
Color text_color1; // Color del texto Color text_color2; // Color del texto
Color text_color2; // Color del texto int skip_countdown_value; // Valor a partir del cual se puede saltar la cuenta atras
int skip_countdown_value; // Valor a partir del cual se puede saltar la cuenta atras
}; };
// --- Parámetros del menú de servicio --- // --- Parámetros del menú de servicio ---
struct ParamServiceMenu struct ParamServiceMenu {
{
Color title_color; Color title_color;
Color text_color; Color text_color;
Color selected_color; Color selected_color;
@@ -102,8 +94,7 @@ struct ParamServiceMenu
}; };
// --- Parámetros de la intro --- // --- Parámetros de la intro ---
struct ParamIntro struct ParamIntro {
{
Color bg_color; Color bg_color;
Color card_color; Color card_color;
Color shadow_color; Color shadow_color;
@@ -111,40 +102,36 @@ struct ParamIntro
}; };
// --- Parámetros para Debug --- // --- Parámetros para Debug ---
struct ParamDebug struct ParamDebug {
{
Color color; Color color;
}; };
// --- Parámetros para Resource --- // --- Parámetros para Resource ---
struct ParamResource struct ParamResource {
{
Color color; Color color;
}; };
// --- Estructura principal para almacenar todos los parámetros del juego --- // --- Estructura principal para almacenar todos los parámetros del juego ---
struct Param struct Param {
{ ParamGame game; // Parámetros del juego
ParamGame game; // Parámetros del juego ParamFade fade; // Parámetros del fade
ParamFade fade; // Parámetros del fade ParamScoreboard scoreboard; // Rectángulo del marcador
ParamScoreboard scoreboard; // Rectángulo del marcador ParamTitle title; // Parámetros de la pantalla de título
ParamTitle title; // Parámetros de la pantalla de título ParamBackground background; // Parámetros del fondo
ParamBackground background; // Parámetros del fondo ParamBalloon balloon; // Parámetros de los globos
ParamBalloon balloon; // Parámetros de los globos ParamNotification notification; // Parámetros de las notificaciones
ParamNotification notification; // Parámetros de las notificaciones ParamServiceMenu service_menu; // Parámetros del menú de servicio
ParamServiceMenu service_menu; // Parámetros del menú de servicio ParamIntro intro; // Parámetros de la intro
ParamIntro intro; // Parámetros de la intro ParamDebug debug; // Parámetros para Debug
ParamDebug debug; // Parámetros para Debug ParamResource resource; // Parámetros para Resource
ParamResource resource; // Parámetros para Resource
// Constructor // Constructor
Param() Param()
: game(), fade(), scoreboard(), title(), background(), balloon(), : game(), fade(), scoreboard(), title(), background(), balloon(), notification(), service_menu(), intro(), debug(), resource() {}
notification(), service_menu(), intro(), debug(), resource() {}
}; };
// --- Variable global con los parámetros del juego --- // --- Variable global con los parámetros del juego ---
extern Param param; extern Param param;
// --- Funciones globales --- // --- Funciones globales ---
void loadParamsFromFile(const std::string &file_path); // Establece valores para los parámetros a partir de un fichero de texto void loadParamsFromFile(const std::string &file_path); // Establece valores para los parámetros a partir de un fichero de texto
+100 -126
View File
@@ -1,169 +1,143 @@
// IWYU pragma: no_include <bits/std_abs.h> // IWYU pragma: no_include <bits/std_abs.h>
#include "path_sprite.h" #include "path_sprite.h"
#include <cmath> // Para abs #include <cmath> // Para abs
#include <functional> // Para function #include <functional> // Para function
#include <utility> // Para move #include <utility> // Para move
// Devuelve un vector con los puntos que conforman la ruta // Devuelve un vector con los puntos que conforman la ruta
std::vector<SDL_FPoint> createPath(float start, float end, PathType type, float fixed_pos, int steps, const std::function<double(double)> &easingFunction) std::vector<SDL_FPoint> createPath(float start, float end, PathType type, float fixed_pos, int steps, const std::function<double(double)> &easingFunction) {
{ std::vector<SDL_FPoint> v;
std::vector<SDL_FPoint> v; v.reserve(steps);
v.reserve(steps);
for (int i = 0; i < steps; ++i) for (int i = 0; i < steps; ++i) {
{ double t = static_cast<double>(i) / (steps - 1);
double t = static_cast<double>(i) / (steps - 1); double value = start + (end - start) * easingFunction(t);
double value = start + (end - start) * easingFunction(t);
if ((start > 0 && end < 0) || (start < 0 && end > 0)) if ((start > 0 && end < 0) || (start < 0 && end > 0)) {
{ value = start + (end > 0 ? 1 : -1) * std::abs(end - start) * easingFunction(t);
value = start + (end > 0 ? 1 : -1) * std::abs(end - start) * easingFunction(t); }
}
switch (type) switch (type) {
{ case PathType::HORIZONTAL:
case PathType::HORIZONTAL: v.emplace_back(SDL_FPoint{static_cast<float>(value), fixed_pos});
v.emplace_back(SDL_FPoint{static_cast<float>(value), fixed_pos}); break;
break; case PathType::VERTICAL:
case PathType::VERTICAL: v.emplace_back(SDL_FPoint{fixed_pos, static_cast<float>(value)});
v.emplace_back(SDL_FPoint{fixed_pos, static_cast<float>(value)}); break;
break; default:
default: break;
break; }
} }
}
return v; return v;
} }
// Actualiza la posición y comprueba si ha llegado a su destino // Actualiza la posición y comprueba si ha llegado a su destino
void PathSprite::update() void PathSprite::update() {
{ if (enabled_ && !has_finished_) {
if (enabled_ && !has_finished_) moveThroughCurrentPath();
{ goToNextPathOrDie();
moveThroughCurrentPath(); }
goToNextPathOrDie();
}
} }
// Muestra el sprite por pantalla // Muestra el sprite por pantalla
void PathSprite::render() void PathSprite::render() {
{ if (enabled_) {
if (enabled_) Sprite::render();
{ }
Sprite::render();
}
} }
// Añade un recorrido // Añade un recorrido
void PathSprite::addPath(Path path, bool centered) void PathSprite::addPath(Path path, bool centered) {
{ PathCentered path_centered = PathCentered::NONE;
PathCentered path_centered = PathCentered::NONE; if (centered)
if (centered) path_centered = (path.spots.back().x == path.spots.front().x) ? PathCentered::ON_X : PathCentered::ON_Y;
path_centered = (path.spots.back().x == path.spots.front().x) ? PathCentered::ON_X : PathCentered::ON_Y;
switch (path_centered) switch (path_centered) {
{ case PathCentered::ON_X: {
case PathCentered::ON_X: const int x = path.spots.back().x - pos_.w / 2;
{ for (auto &spot : path.spots)
const int x = path.spots.back().x - pos_.w / 2; spot.x = x;
for (auto &spot : path.spots) paths_.emplace_back(path);
spot.x = x; break;
paths_.emplace_back(path); }
break; case PathCentered::ON_Y: {
} const int y = path.spots.back().y - pos_.h / 2;
case PathCentered::ON_Y: for (auto &spot : path.spots)
{ spot.y = y;
const int y = path.spots.back().y - pos_.h / 2; paths_.emplace_back(path);
for (auto &spot : path.spots) break;
spot.y = y; }
paths_.emplace_back(path); default:
break; paths_.emplace_back(path);
} break;
default: }
paths_.emplace_back(path);
break;
}
} }
// Añade un recorrido // Añade un recorrido
void PathSprite::addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easingFunction, int waiting_counter) void PathSprite::addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easingFunction, int waiting_counter) {
{ paths_.emplace_back(createPath(start, end, type, fixed_pos, steps, easingFunction), waiting_counter);
paths_.emplace_back(createPath(start, end, type, fixed_pos, steps, easingFunction), waiting_counter);
} }
// Añade un recorrido // Añade un recorrido
void PathSprite::addPath(std::vector<SDL_FPoint> spots, int waiting_counter) void PathSprite::addPath(std::vector<SDL_FPoint> spots, int waiting_counter) {
{ paths_.emplace_back(std::move(spots), waiting_counter);
paths_.emplace_back(std::move(spots), waiting_counter);
} }
// Habilita el objeto // Habilita el objeto
void PathSprite::enable() void PathSprite::enable() {
{ if (paths_.size() == 0 || enabled_) {
if (paths_.size() == 0 || enabled_) return;
{ }
return;
}
enabled_ = true; enabled_ = true;
// Establece la posición // Establece la posición
auto &path = paths_.at(current_path_); auto &path = paths_.at(current_path_);
const auto &P = path.spots.at(path.counter); const auto &P = path.spots.at(path.counter);
setPosition(P); setPosition(P);
} }
// Coloca el sprite en los diferentes puntos del recorrido // Coloca el sprite en los diferentes puntos del recorrido
void PathSprite::moveThroughCurrentPath() void PathSprite::moveThroughCurrentPath() {
{ auto &path = paths_.at(current_path_);
auto &path = paths_.at(current_path_);
// Establece la posición // Establece la posición
const auto &p = path.spots.at(path.counter); const auto &p = path.spots.at(path.counter);
setPosition(p); setPosition(p);
// Comprobar si ha terminado el recorrido // Comprobar si ha terminado el recorrido
if (!path.on_destination) if (!path.on_destination) {
{ ++path.counter;
++path.counter; if (path.counter >= static_cast<int>(path.spots.size())) {
if (path.counter >= static_cast<int>(path.spots.size())) path.on_destination = true;
{ path.counter = static_cast<int>(path.spots.size()) - 1;
path.on_destination = true; }
path.counter = static_cast<int>(path.spots.size()) - 1; }
}
}
// Comprobar si ha terminado la espera // Comprobar si ha terminado la espera
if (path.on_destination) if (path.on_destination) {
{ if (path.waiting_counter == 0) {
if (path.waiting_counter == 0) path.finished = true;
{ } else {
path.finished = true; --path.waiting_counter;
} }
else }
{
--path.waiting_counter;
}
}
} }
// Cambia de recorrido o finaliza // Cambia de recorrido o finaliza
void PathSprite::goToNextPathOrDie() void PathSprite::goToNextPathOrDie() {
{ // Comprueba si ha terminado el recorrdo actual
// Comprueba si ha terminado el recorrdo actual if (paths_.at(current_path_).finished) {
if (paths_.at(current_path_).finished) ++current_path_;
{ }
++current_path_;
}
// Comprueba si quedan mas recorridos // Comprueba si quedan mas recorridos
if (current_path_ >= static_cast<int>(paths_.size())) if (current_path_ >= static_cast<int>(paths_.size())) {
{ has_finished_ = true;
has_finished_ = true; current_path_ = 0;
current_path_ = 0; }
}
} }
// Indica si ha terminado todos los recorridos // Indica si ha terminado todos los recorridos
+49 -52
View File
@@ -1,79 +1,76 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_FPoint #include <SDL3/SDL.h> // Para SDL_FPoint
#include <functional> // Para std::function
#include <memory> // Para shared_ptr
#include <vector> // Para vector
#include "sprite.h" // Para Sprite #include <functional> // Para std::function
#include <memory> // Para shared_ptr
#include <vector> // Para vector
#include "sprite.h" // Para Sprite
class Texture; class Texture;
// --- Tipos de recorrido --- // --- Tipos de recorrido ---
enum class PathType enum class PathType {
{ VERTICAL,
VERTICAL, HORIZONTAL,
HORIZONTAL,
}; };
// --- Centrado del recorrido --- // --- Centrado del recorrido ---
enum class PathCentered enum class PathCentered {
{ ON_X,
ON_X, ON_Y,
ON_Y, NONE,
NONE,
}; };
// --- Estructura Path: define un recorrido para el sprite --- // --- Estructura Path: define un recorrido para el sprite ---
struct Path struct Path {
{ std::vector<SDL_FPoint> spots; // Puntos por los que se desplazará el sprite
std::vector<SDL_FPoint> spots; // Puntos por los que se desplazará el sprite int waiting_counter; // Tiempo de espera una vez en el destino
int waiting_counter; // Tiempo de espera una vez en el destino bool on_destination = false; // Indica si ha llegado al destino
bool on_destination = false; // Indica si ha llegado al destino bool finished = false; // Indica si ha terminado de esperarse
bool finished = false; // Indica si ha terminado de esperarse int counter = 0; // Contador interno
int counter = 0; // Contador interno
// Constructor // Constructor
Path(const std::vector<SDL_FPoint> &spots_init, int waiting_counter_init) Path(const std::vector<SDL_FPoint> &spots_init, int waiting_counter_init)
: spots(spots_init), waiting_counter(waiting_counter_init) {} : spots(spots_init), waiting_counter(waiting_counter_init) {}
}; };
// Devuelve un vector con los puntos que conforman la ruta // Devuelve un vector con los puntos que conforman la ruta
std::vector<SDL_FPoint> createPath(float start, float end, PathType type, float fixed_pos, int steps, const std::function<double(double)> &easingFunction); std::vector<SDL_FPoint> createPath(float start, float end, PathType type, float fixed_pos, int steps, const std::function<double(double)> &easingFunction);
// --- Clase PathSprite: Sprite que sigue uno o varios recorridos --- // --- Clase PathSprite: Sprite que sigue uno o varios recorridos ---
class PathSprite : public Sprite class PathSprite : public Sprite {
{ public:
public: // --- Constructor y destructor ---
// --- Constructor y destructor --- explicit PathSprite(std::shared_ptr<Texture> texture)
explicit PathSprite(std::shared_ptr<Texture> texture) : Sprite(texture) {}
: Sprite(texture) {} ~PathSprite() override = default;
~PathSprite() override = default;
// --- Métodos principales --- // --- Métodos principales ---
void update(); // Actualiza la posición del sprite según el recorrido void update(); // Actualiza la posición del sprite según el recorrido
void render() override; // Muestra el sprite por pantalla void render() override; // Muestra el sprite por pantalla
// --- Gestión de recorridos --- // --- Gestión de recorridos ---
void addPath(Path path, bool centered = false); // Añade un recorrido (Path) void addPath(Path path, bool centered = false); // Añade un recorrido (Path)
void addPath(std::vector<SDL_FPoint> spots, int waiting_counter = 0); // Añade un recorrido a partir de puntos void addPath(std::vector<SDL_FPoint> spots, int waiting_counter = 0); // Añade un recorrido a partir de puntos
void addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easingFunction, int waiting_counter = 0); // Añade un recorrido generado void addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easingFunction, int waiting_counter = 0); // Añade un recorrido generado
// --- Estado y control --- // --- Estado y control ---
void enable(); // Habilita el objeto void enable(); // Habilita el objeto
bool hasFinished(); // Indica si ha terminado todos los recorridos bool hasFinished(); // Indica si ha terminado todos los recorridos
// --- Getters --- // --- Getters ---
int getCurrentPath() const { return current_path_; } // Devuelve el índice del recorrido actual int getCurrentPath() const { return current_path_; } // Devuelve el índice del recorrido actual
private: private:
// --- Variables internas --- // --- Variables internas ---
bool enabled_ = false; // Indica si el objeto está habilitado bool enabled_ = false; // Indica si el objeto está habilitado
bool has_finished_ = false; // Indica si el objeto ha finalizado el recorrido bool has_finished_ = false; // Indica si el objeto ha finalizado el recorrido
int current_path_ = 0; // Recorrido que se está recorriendo actualmente int current_path_ = 0; // Recorrido que se está recorriendo actualmente
std::vector<Path> paths_; // Caminos a recorrer por el sprite std::vector<Path> paths_; // Caminos a recorrer por el sprite
// --- Métodos internos --- // --- Métodos internos ---
void moveThroughCurrentPath(); // Coloca el sprite en los diferentes puntos del recorrido void moveThroughCurrentPath(); // Coloca el sprite en los diferentes puntos del recorrido
void goToNextPathOrDie(); // Cambia de recorrido o finaliza void goToNextPathOrDie(); // Cambia de recorrido o finaliza
}; };
+672 -819
View File
File diff suppressed because it is too large. Load diff
+123 -124
View File
@@ -1,108 +1,107 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para Uint32, SDL_FRect #include <SDL3/SDL.h> // Para Uint32, SDL_FRect
#include <memory> // Para unique_ptr, shared_ptr
#include <string> // Para basic_string, string
#include <vector> // Para vector
#include "animated_sprite.h" // Para AnimatedSprite #include <memory> // Para unique_ptr, shared_ptr
#include "enter_name.h" // Para EnterName #include <string> // Para basic_string, string
#include "manage_hiscore_table.h" // Para HiScoreEntry #include <vector> // Para vector
#include "options.h" // Para SettingsOptions, settings
#include "utils.h" // Para Circle #include "animated_sprite.h" // Para AnimatedSprite
#include "enter_name.h" // Para EnterName
#include "manage_hiscore_table.h" // Para HiScoreEntry
#include "options.h" // Para SettingsOptions, settings
#include "utils.h" // Para Circle
class Texture; class Texture;
enum class InputAction : int; enum class InputAction : int;
enum class ScoreboardMode; enum class ScoreboardMode;
// --- Estados posibles del jugador --- // --- Estados posibles del jugador ---
enum class PlayerState enum class PlayerState {
{
// Estados de movimiento // Estados de movimiento
WALKING_LEFT, // Caminando hacia la izquierda WALKING_LEFT, // Caminando hacia la izquierda
WALKING_RIGHT, // Caminando hacia la derecha WALKING_RIGHT, // Caminando hacia la derecha
WALKING_STOP, // Parado, sin moverse WALKING_STOP, // Parado, sin moverse
// Estados de disparo // Estados de disparo
FIRING_UP, // Disparando hacia arriba FIRING_UP, // Disparando hacia arriba
FIRING_LEFT, // Disparando hacia la izquierda FIRING_LEFT, // Disparando hacia la izquierda
FIRING_RIGHT, // Disparando hacia la derecha FIRING_RIGHT, // Disparando hacia la derecha
FIRING_NONE, // No está disparando FIRING_NONE, // No está disparando
// Estados de retroceso tras disparar // Estados de retroceso tras disparar
RECOILING_UP, // Retroceso tras disparar hacia arriba RECOILING_UP, // Retroceso tras disparar hacia arriba
RECOILING_LEFT, // Retroceso tras disparar hacia la izquierda RECOILING_LEFT, // Retroceso tras disparar hacia la izquierda
RECOILING_RIGHT, // Retroceso tras disparar hacia la derecha RECOILING_RIGHT, // Retroceso tras disparar hacia la derecha
// Estados de enfriamiento tras disparar // Estados de enfriamiento tras disparar
COOLING_UP, // Enfriando tras disparar hacia arriba COOLING_UP, // Enfriando tras disparar hacia arriba
COOLING_LEFT, // Enfriando tras disparar hacia la izquierda COOLING_LEFT, // Enfriando tras disparar hacia la izquierda
COOLING_RIGHT, // Enfriando tras disparar hacia la derecha COOLING_RIGHT, // Enfriando tras disparar hacia la derecha
// Estados generales del jugador // Estados generales del jugador
PLAYING, // Está jugando activamente PLAYING, // Está jugando activamente
CONTINUE, // Cuenta atrás para continuar tras perder CONTINUE, // Cuenta atrás para continuar tras perder
CONTINUE_TIME_OUT, // Se ha terminado la cuenta atras para continuar y se retira al jugador de la zona de juego CONTINUE_TIME_OUT, // Se ha terminado la cuenta atras para continuar y se retira al jugador de la zona de juego
WAITING, // Esperando para entrar a jugar WAITING, // Esperando para entrar a jugar
ENTERING_NAME, // Introduciendo nombre para la tabla de puntuaciones ENTERING_NAME, // Introduciendo nombre para la tabla de puntuaciones
SHOWING_NAME, // Mostrando el nombre introducido SHOWING_NAME, // Mostrando el nombre introducido
ROLLING, // El jugador está muriendo (animación de muerte) ROLLING, // El jugador está muriendo (animación de muerte)
LYING_ON_THE_FLOOR_FOREVER, // El jugador está inconsciente para siempre en el suelo (demo) LYING_ON_THE_FLOOR_FOREVER, // El jugador está inconsciente para siempre en el suelo (demo)
GAME_OVER, // Fin de la partida, no puede jugar GAME_OVER, // Fin de la partida, no puede jugar
CELEBRATING, // Celebrando victoria (pose de victoria) CELEBRATING, // Celebrando victoria (pose de victoria)
ENTERING_NAME_GAME_COMPLETED, // Introduciendo nombre tras completar el juego ENTERING_NAME_GAME_COMPLETED, // Introduciendo nombre tras completar el juego
LEAVING_SCREEN, // Saliendo de la pantalla (animación) LEAVING_SCREEN, // Saliendo de la pantalla (animación)
ENTERING_SCREEN, // Entrando a la pantalla (animación) ENTERING_SCREEN, // Entrando a la pantalla (animación)
CREDITS, // Estado para mostrar los créditos del juego CREDITS, // Estado para mostrar los créditos del juego
TITLE_ANIMATION, // Animacion para el titulo TITLE_ANIMATION, // Animacion para el titulo
TITLE_HIDDEN, // Animacion para el titulo TITLE_HIDDEN, // Animacion para el titulo
RESPAWNING, // Tras continuar y volver al juego RESPAWNING, // Tras continuar y volver al juego
}; };
// --- Clase Player --- // --- Clase Player ---
class Player class Player {
{ public:
public:
// --- Constructor y destructor --- // --- Constructor y destructor ---
Player(int id, float x, int y, bool demo, SDL_FRect &play_area, std::vector<std::shared_ptr<Texture>> texture, const std::vector<std::vector<std::string>> &animations); Player(int id, float x, int y, bool demo, SDL_FRect &play_area, std::vector<std::shared_ptr<Texture>> texture, const std::vector<std::vector<std::string>> &animations);
~Player() = default; ~Player() = default;
// --- Inicialización y ciclo de vida --- // --- Inicialización y ciclo de vida ---
void init(); // Inicializa el jugador void init(); // Inicializa el jugador
void update(); // Actualiza estado, animación y contadores void update(); // Actualiza estado, animación y contadores
void render(); // Dibuja el jugador en pantalla void render(); // Dibuja el jugador en pantalla
// --- Entrada y control --- // --- Entrada y control ---
void setInput(InputAction input); // Procesa entrada general void setInput(InputAction input); // Procesa entrada general
void setInputPlaying(InputAction input); // Procesa entrada en modo jugando void setInputPlaying(InputAction input); // Procesa entrada en modo jugando
void setInputEnteringName(InputAction input); // Procesa entrada al introducir nombre void setInputEnteringName(InputAction input); // Procesa entrada al introducir nombre
// --- Movimiento y animación --- // --- Movimiento y animación ---
void move(); // Mueve el jugador void move(); // Mueve el jugador
void setAnimation(); // Establece la animación según el estado void setAnimation(); // Establece la animación según el estado
// --- Texturas y animaciones --- // --- Texturas y animaciones ---
void setPlayerTextures(const std::vector<std::shared_ptr<Texture>> &texture); // Cambia las texturas del jugador void setPlayerTextures(const std::vector<std::shared_ptr<Texture>> &texture); // Cambia las texturas del jugador
// --- Estados y contadores --- // --- Estados y contadores ---
void updateCooldown(); // Actualiza el cooldown de disparo void updateCooldown(); // Actualiza el cooldown de disparo
// --- Puntuación y marcador --- // --- Puntuación y marcador ---
void addScore(int score); // Añade puntos void addScore(int score); // Añade puntos
void incScoreMultiplier(); // Incrementa el multiplicador void incScoreMultiplier(); // Incrementa el multiplicador
void decScoreMultiplier(); // Decrementa el multiplicador void decScoreMultiplier(); // Decrementa el multiplicador
// --- Estados de juego --- // --- Estados de juego ---
void setPlayingState(PlayerState state); // Cambia el estado de juego void setPlayingState(PlayerState state); // Cambia el estado de juego
void setInvulnerable(bool value); // Establece el valor del estado de invulnerabilidad void setInvulnerable(bool value); // Establece el valor del estado de invulnerabilidad
void setPowerUp(); // Activa el modo PowerUp void setPowerUp(); // Activa el modo PowerUp
void updatePowerUp(); // Actualiza el valor de PowerUp void updatePowerUp(); // Actualiza el valor de PowerUp
void giveExtraHit(); // Concede un toque extra al jugador void giveExtraHit(); // Concede un toque extra al jugador
void removeExtraHit(); // Quita el toque extra al jugador void removeExtraHit(); // Quita el toque extra al jugador
void decContinueCounter(); // Decrementa el contador de continuar void decContinueCounter(); // Decrementa el contador de continuar
// --- Getters y comprobaciones de estado --- // --- Getters y comprobaciones de estado ---
int getRecordNamePos() const; // Obtiene la posición que se está editando del nombre del jugador para la tabla de mejores puntuaciones int getRecordNamePos() const; // Obtiene la posición que se está editando del nombre del jugador para la tabla de mejores puntuaciones
// Comprobación de playing_state // Comprobación de playing_state
bool isLyingOnTheFloorForever() const { return playing_state_ == PlayerState::LYING_ON_THE_FLOOR_FOREVER; } bool isLyingOnTheFloorForever() const { return playing_state_ == PlayerState::LYING_ON_THE_FLOOR_FOREVER; }
@@ -160,73 +159,73 @@ public:
void setWalkingState(PlayerState state) { walking_state_ = state; } void setWalkingState(PlayerState state) { walking_state_ = state; }
void addCredit() { ++credits_used_; } void addCredit() { ++credits_used_; }
private: private:
// --- Constantes --- // --- Constantes ---
static constexpr int POWERUP_COUNTER_ = 1500; // Duración del estado PowerUp static constexpr int POWERUP_COUNTER_ = 1500; // Duración del estado PowerUp
static constexpr int INVULNERABLE_COUNTER_ = 200; // Duración del estado invulnerable static constexpr int INVULNERABLE_COUNTER_ = 200; // Duración del estado invulnerable
static constexpr int WIDTH_ = 30; // Anchura static constexpr int WIDTH_ = 30; // Anchura
static constexpr int HEIGHT_ = 30; // Altura static constexpr int HEIGHT_ = 30; // Altura
static constexpr float BASE_SPEED_ = 1.5f; // Velocidad base del jugador static constexpr float BASE_SPEED_ = 1.5f; // Velocidad base del jugador
static constexpr int COOLING_DURATION_ = 50; static constexpr int COOLING_DURATION_ = 50;
static constexpr int COOLING_COMPLETE_ = 0; static constexpr int COOLING_COMPLETE_ = 0;
// --- Objetos y punteros --- // --- Objetos y punteros ---
std::unique_ptr<AnimatedSprite> player_sprite_; // Sprite para dibujar el jugador std::unique_ptr<AnimatedSprite> player_sprite_; // Sprite para dibujar el jugador
std::unique_ptr<AnimatedSprite> power_sprite_; // Sprite para dibujar el aura del jugador con el poder a tope std::unique_ptr<AnimatedSprite> power_sprite_; // Sprite para dibujar el aura del jugador con el poder a tope
std::unique_ptr<EnterName> enter_name_; // Clase utilizada para introducir el nombre std::unique_ptr<EnterName> enter_name_; // Clase utilizada para introducir el nombre
// --- Variables de estado --- // --- Variables de estado ---
int id_; // Número de identificación para el jugador. Player1 = 1, Player2 = 2 int id_; // Número de identificación para el jugador. Player1 = 1, Player2 = 2
SDL_FRect play_area_; // Rectángulo con la zona de juego SDL_FRect play_area_; // Rectángulo con la zona de juego
float pos_x_ = 0.0f; // Posición en el eje X float pos_x_ = 0.0f; // Posición en el eje X
int pos_y_ = 0; // Posición en el eje Y int pos_y_ = 0; // Posición en el eje Y
float default_pos_x_; // Posición inicial para el jugador float default_pos_x_; // Posición inicial para el jugador
int default_pos_y_; // Posición inicial para el jugador int default_pos_y_; // Posición inicial para el jugador
float vel_x_ = 0.0f; // Cantidad de píxeles a desplazarse en el eje X float vel_x_ = 0.0f; // Cantidad de píxeles a desplazarse en el eje X
int vel_y_ = 0.0f; // Cantidad de píxeles a desplazarse en el eje Y int vel_y_ = 0.0f; // Cantidad de píxeles a desplazarse en el eje Y
int cant_fire_counter_ = 0; // Contador durante el cual no puede disparar int cant_fire_counter_ = 0; // Contador durante el cual no puede disparar
int recoiling_state_counter_ = 0; // Contador para la animación del estado de retroceso int recoiling_state_counter_ = 0; // Contador para la animación del estado de retroceso
int recoiling_state_duration_ = 0; // Numero de frames que dura el estado de retroceso int recoiling_state_duration_ = 0; // Numero de frames que dura el estado de retroceso
int cooling_state_counter_ = 0; // Contador para la animación del estado cooling int cooling_state_counter_ = 0; // Contador para la animación del estado cooling
int score_ = 0; // Puntos del jugador int score_ = 0; // Puntos del jugador
float score_multiplier_ = 1.0f; // Multiplicador de puntos float score_multiplier_ = 1.0f; // Multiplicador de puntos
PlayerState walking_state_ = PlayerState::WALKING_STOP; // Estado del jugador al moverse PlayerState walking_state_ = PlayerState::WALKING_STOP; // Estado del jugador al moverse
PlayerState firing_state_ = PlayerState::FIRING_NONE; // Estado del jugador al disparar PlayerState firing_state_ = PlayerState::FIRING_NONE; // Estado del jugador al disparar
PlayerState playing_state_ = PlayerState::WAITING; // Estado del jugador en el juego PlayerState playing_state_ = PlayerState::WAITING; // Estado del jugador en el juego
bool invulnerable_ = true; // Indica si el jugador es invulnerable bool invulnerable_ = true; // Indica si el jugador es invulnerable
int invulnerable_counter_ = INVULNERABLE_COUNTER_; // Contador para la invulnerabilidad int invulnerable_counter_ = INVULNERABLE_COUNTER_; // Contador para la invulnerabilidad
bool extra_hit_ = false; // Indica si el jugador tiene un toque extra bool extra_hit_ = false; // Indica si el jugador tiene un toque extra
int coffees_ = 0; // Indica cuántos cafés lleva acumulados int coffees_ = 0; // Indica cuántos cafés lleva acumulados
bool power_up_ = false; // Indica si el jugador tiene activo el modo PowerUp bool power_up_ = false; // Indica si el jugador tiene activo el modo PowerUp
int power_up_counter_ = POWERUP_COUNTER_; // Temporizador para el modo PowerUp int power_up_counter_ = POWERUP_COUNTER_; // Temporizador para el modo PowerUp
int power_up_desp_x_ = 0; // Desplazamiento del sprite de PowerUp respecto al sprite del jugador int power_up_desp_x_ = 0; // Desplazamiento del sprite de PowerUp respecto al sprite del jugador
Circle collider_ = Circle(0, 0, 9); // Círculo de colisión del jugador Circle collider_ = Circle(0, 0, 9); // Círculo de colisión del jugador
int continue_counter_ = 10; // Contador para poder continuar int continue_counter_ = 10; // Contador para poder continuar
Uint32 continue_ticks_ = 0; // Variable para poder cambiar el contador de continue en función del tiempo Uint32 continue_ticks_ = 0; // Variable para poder cambiar el contador de continue en función del tiempo
int scoreboard_panel_ = 0; // Panel del marcador asociado al jugador int scoreboard_panel_ = 0; // Panel del marcador asociado al jugador
std::string name_; // Nombre del jugador std::string name_; // Nombre del jugador
int controller_index_ = 0; // Índice del array de mandos que utilizará para moverse int controller_index_ = 0; // Índice del array de mandos que utilizará para moverse
bool demo_ = false; // Para que el jugador sepa si está en el modo demostración bool demo_ = false; // Para que el jugador sepa si está en el modo demostración
int name_entry_idle_counter_ = 0; // Contador para poner nombre int name_entry_idle_counter_ = 0; // Contador para poner nombre
int name_entry_total_counter_ = 0; // Segundos totales que lleva acumulados poniendo nombre int name_entry_total_counter_ = 0; // Segundos totales que lleva acumulados poniendo nombre
Uint32 name_entry_ticks_ = 0; // Variable para poder cambiar el contador de poner nombre en función del tiempo Uint32 name_entry_ticks_ = 0; // Variable para poder cambiar el contador de poner nombre en función del tiempo
Uint32 showing_name_ticks_ = 0; // Tiempo en el que se entra al estado SHOWING_NAME Uint32 showing_name_ticks_ = 0; // Tiempo en el que se entra al estado SHOWING_NAME
int step_counter_ = 0; // Cuenta los pasos para los estados en los que camina automáticamente int step_counter_ = 0; // Cuenta los pasos para los estados en los que camina automáticamente
bool game_completed_ = false; // Indica si ha completado el juego bool game_completed_ = false; // Indica si ha completado el juego
int credits_used_ = 1; // Indica el número de veces que ha continuado int credits_used_ = 1; // Indica el número de veces que ha continuado
std::string last_enter_name_; // Último nombre introducido en la tabla de puntuaciones std::string last_enter_name_; // Último nombre introducido en la tabla de puntuaciones
// --- Métodos internos --- // --- Métodos internos ---
void shiftColliders(); // Actualiza el círculo de colisión a la posición del jugador void shiftColliders(); // Actualiza el círculo de colisión a la posición del jugador
void shiftSprite(); // Recoloca el sprite void shiftSprite(); // Recoloca el sprite
void updateInvulnerable(); // Monitoriza el estado de invulnerabilidad void updateInvulnerable(); // Monitoriza el estado de invulnerabilidad
void updateContinueCounter(); // Actualiza el contador de continue void updateContinueCounter(); // Actualiza el contador de continue
void updateEnterNameCounter(); // Actualiza el contador de entrar nombre void updateEnterNameCounter(); // Actualiza el contador de entrar nombre
void updateShowingName(); // Actualiza el estado SHOWING_NAME void updateShowingName(); // Actualiza el estado SHOWING_NAME
void decNameEntryCounter(); // Decrementa el contador de entrar nombre void decNameEntryCounter(); // Decrementa el contador de entrar nombre
void updateScoreboard(); // Actualiza el panel del marcador void updateScoreboard(); // Actualiza el panel del marcador
void setScoreboardMode(ScoreboardMode mode); // Cambia el modo del marcador void setScoreboardMode(ScoreboardMode mode); // Cambia el modo del marcador
void playSound(const std::string &name); // Hace sonar un sonido void playSound(const std::string &name); // Hace sonar un sonido
bool isRenderable() const { return !isWaiting() && !isGameOver() && !isTitleHidden(); } bool isRenderable() const { return !isWaiting() && !isGameOver() && !isTitleHidden(); }
void addScoreToScoreBoard(); // Añade una puntuación a la tabla de records void addScoreToScoreBoard(); // Añade una puntuación a la tabla de records
}; };
+86 -146
View File
@@ -1,20 +1,21 @@
#include "resource.h" #include "resource.h"
#include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory, SDL_L... #include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory, SDL_L...
#include <stdlib.h> // Para exit #include <stdlib.h> // Para exit
#include <algorithm> // Para find_if #include <algorithm> // Para find_if
#include <array> // Para array #include <array> // Para array
#include <stdexcept> // Para runtime_error #include <stdexcept> // Para runtime_error
#include "asset.h" // Para Asset, AssetType #include "asset.h" // Para Asset, AssetType
#include "external/jail_audio.h" // Para JA_DeleteMusic, JA_DeleteSound, JA_... #include "external/jail_audio.h" // Para JA_DeleteMusic, JA_DeleteSound, JA_...
#include "lang.h" // Para getText #include "lang.h" // Para getText
#include "param.h" // Para Param, param, ParamResource, ParamGame #include "param.h" // Para Param, param, ParamResource, ParamGame
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "text.h" // Para Text, loadTextFile, TextFile (ptr o... #include "text.h" // Para Text, loadTextFile, TextFile (ptr o...
struct JA_Music_t; // lines 11-11 struct JA_Music_t; // lines 11-11
struct JA_Sound_t; // lines 12-12 struct JA_Sound_t; // lines 12-12
// Singleton // Singleton
Resource *Resource::instance_ = nullptr; Resource *Resource::instance_ = nullptr;
@@ -35,8 +36,7 @@ Resource::Resource() : loading_text_(Screen::get()->getText()) { load(); }
Resource::~Resource() { clear(); } Resource::~Resource() { clear(); }
// Vacia todos los vectores de recursos // Vacia todos los vectores de recursos
void Resource::clear() void Resource::clear() {
{
clearSounds(); clearSounds();
clearMusics(); clearMusics();
textures_.clear(); textures_.clear();
@@ -47,8 +47,7 @@ void Resource::clear()
} }
// Carga todos los recursos del juego y muestra el progreso de carga // Carga todos los recursos del juego y muestra el progreso de carga
void Resource::load() void Resource::load() {
{
// Prepara la gestión del progreso de carga // Prepara la gestión del progreso de carga
calculateTotalResources(); calculateTotalResources();
initProgressBar(); initProgressBar();
@@ -59,15 +58,15 @@ void Resource::load()
screen->setVSync(false); screen->setVSync(false);
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n** LOADING RESOURCES"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n** LOADING RESOURCES");
loadSounds(); // Carga sonidos loadSounds(); // Carga sonidos
loadMusics(); // Carga músicas loadMusics(); // Carga músicas
loadTextures(); // Carga texturas loadTextures(); // Carga texturas
loadTextFiles(); // Carga ficheros de texto loadTextFiles(); // Carga ficheros de texto
loadAnimations(); // Carga animaciones loadAnimations(); // Carga animaciones
loadDemoData(); // Carga datos de demo loadDemoData(); // Carga datos de demo
addPalettes(); // Añade paletas a las texturas addPalettes(); // Añade paletas a las texturas
createText(); // Crea objetos de texto createText(); // Crea objetos de texto
createTextures(); // Crea texturas a partir de texto createTextures(); // Crea texturas a partir de texto
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n** RESOURCES LOADED"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n** RESOURCES LOADED");
// Restablece el sincronismo vertical a su valor original // Restablece el sincronismo vertical a su valor original
@@ -75,28 +74,23 @@ void Resource::load()
} }
// Recarga todos los recursos (limpia y vuelve a cargar) // Recarga todos los recursos (limpia y vuelve a cargar)
void Resource::reload() void Resource::reload() {
{
clear(); clear();
load(); load();
} }
// Recarga solo las texturas y paletas // Recarga solo las texturas y paletas
void Resource::reloadTextures() void Resource::reloadTextures() {
{
loadTextures(); loadTextures();
addPalettes(); addPalettes();
createTextures(); createTextures();
} }
// Obtiene el sonido a partir de un nombre. Lanza excepción si no existe. // Obtiene el sonido a partir de un nombre. Lanza excepción si no existe.
JA_Sound_t *Resource::getSound(const std::string &name) JA_Sound_t *Resource::getSound(const std::string &name) {
{ auto it = std::find_if(sounds_.begin(), sounds_.end(), [&name](const auto &s) { return s.name == name; });
auto it = std::find_if(sounds_.begin(), sounds_.end(), [&name](const auto &s)
{ return s.name == name; });
if (it != sounds_.end()) if (it != sounds_.end()) {
{
return it->sound; return it->sound;
} }
@@ -105,13 +99,10 @@ JA_Sound_t *Resource::getSound(const std::string &name)
} }
// Obtiene la música a partir de un nombre. Lanza excepción si no existe. // Obtiene la música a partir de un nombre. Lanza excepción si no existe.
JA_Music_t *Resource::getMusic(const std::string &name) JA_Music_t *Resource::getMusic(const std::string &name) {
{ auto it = std::find_if(musics_.begin(), musics_.end(), [&name](const auto &m) { return m.name == name; });
auto it = std::find_if(musics_.begin(), musics_.end(), [&name](const auto &m)
{ return m.name == name; });
if (it != musics_.end()) if (it != musics_.end()) {
{
return it->music; return it->music;
} }
@@ -120,13 +111,10 @@ JA_Music_t *Resource::getMusic(const std::string &name)
} }
// Obtiene la textura a partir de un nombre. Lanza excepción si no existe. // Obtiene la textura a partir de un nombre. Lanza excepción si no existe.
std::shared_ptr<Texture> Resource::getTexture(const std::string &name) std::shared_ptr<Texture> Resource::getTexture(const std::string &name) {
{ auto it = std::find_if(textures_.begin(), textures_.end(), [&name](const auto &t) { return t.name == name; });
auto it = std::find_if(textures_.begin(), textures_.end(), [&name](const auto &t)
{ return t.name == name; });
if (it != textures_.end()) if (it != textures_.end()) {
{
return it->texture; return it->texture;
} }
@@ -135,13 +123,10 @@ std::shared_ptr<Texture> Resource::getTexture(const std::string &name)
} }
// Obtiene el fichero de texto a partir de un nombre. Lanza excepción si no existe. // Obtiene el fichero de texto a partir de un nombre. Lanza excepción si no existe.
std::shared_ptr<TextFile> Resource::getTextFile(const std::string &name) std::shared_ptr<TextFile> Resource::getTextFile(const std::string &name) {
{ auto it = std::find_if(text_files_.begin(), text_files_.end(), [&name](const auto &t) { return t.name == name; });
auto it = std::find_if(text_files_.begin(), text_files_.end(), [&name](const auto &t)
{ return t.name == name; });
if (it != text_files_.end()) if (it != text_files_.end()) {
{
return it->text_file; return it->text_file;
} }
@@ -150,13 +135,10 @@ std::shared_ptr<TextFile> Resource::getTextFile(const std::string &name)
} }
// Obtiene el objeto de texto a partir de un nombre. Lanza excepción si no existe. // Obtiene el objeto de texto a partir de un nombre. Lanza excepción si no existe.
std::shared_ptr<Text> Resource::getText(const std::string &name) std::shared_ptr<Text> Resource::getText(const std::string &name) {
{ auto it = std::find_if(texts_.begin(), texts_.end(), [&name](const auto &t) { return t.name == name; });
auto it = std::find_if(texts_.begin(), texts_.end(), [&name](const auto &t)
{ return t.name == name; });
if (it != texts_.end()) if (it != texts_.end()) {
{
return it->text; return it->text;
} }
@@ -165,13 +147,10 @@ std::shared_ptr<Text> Resource::getText(const std::string &name)
} }
// Obtiene la animación a partir de un nombre. Lanza excepción si no existe. // Obtiene la animación a partir de un nombre. Lanza excepción si no existe.
AnimationsFileBuffer &Resource::getAnimation(const std::string &name) AnimationsFileBuffer &Resource::getAnimation(const std::string &name) {
{ auto it = std::find_if(animations_.begin(), animations_.end(), [&name](const auto &a) { return a.name == name; });
auto it = std::find_if(animations_.begin(), animations_.end(), [&name](const auto &a)
{ return a.name == name; });
if (it != animations_.end()) if (it != animations_.end()) {
{
return it->animation; return it->animation;
} }
@@ -180,20 +159,17 @@ AnimationsFileBuffer &Resource::getAnimation(const std::string &name)
} }
// Obtiene el fichero con los datos para el modo demostración a partir de un índice // Obtiene el fichero con los datos para el modo demostración a partir de un índice
DemoData &Resource::getDemoData(int index) DemoData &Resource::getDemoData(int index) {
{
return demos_.at(index); return demos_.at(index);
} }
// Carga los sonidos del juego // Carga los sonidos del juego
void Resource::loadSounds() void Resource::loadSounds() {
{
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> SOUND FILES"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> SOUND FILES");
auto list = Asset::get()->getListByType(AssetType::SOUND); auto list = Asset::get()->getListByType(AssetType::SOUND);
sounds_.clear(); sounds_.clear();
for (const auto &l : list) for (const auto &l : list) {
{
auto name = getFileName(l); auto name = getFileName(l);
updateLoadingProgress(name); updateLoadingProgress(name);
sounds_.emplace_back(Resource::ResourceSound(name, JA_LoadSound(l.c_str()))); sounds_.emplace_back(Resource::ResourceSound(name, JA_LoadSound(l.c_str())));
@@ -202,14 +178,12 @@ void Resource::loadSounds()
} }
// Carga las músicas del juego // Carga las músicas del juego
void Resource::loadMusics() void Resource::loadMusics() {
{
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> MUSIC FILES"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> MUSIC FILES");
auto list = Asset::get()->getListByType(AssetType::MUSIC); auto list = Asset::get()->getListByType(AssetType::MUSIC);
musics_.clear(); musics_.clear();
for (const auto &l : list) for (const auto &l : list) {
{
auto name = getFileName(l); auto name = getFileName(l);
updateLoadingProgress(name); updateLoadingProgress(name);
musics_.emplace_back(Resource::ResourceMusic(name, JA_LoadMusic(l.c_str()))); musics_.emplace_back(Resource::ResourceMusic(name, JA_LoadMusic(l.c_str())));
@@ -218,14 +192,12 @@ void Resource::loadMusics()
} }
// Carga las texturas del juego // Carga las texturas del juego
void Resource::loadTextures() void Resource::loadTextures() {
{
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> TEXTURES"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> TEXTURES");
auto list = Asset::get()->getListByType(AssetType::BITMAP); auto list = Asset::get()->getListByType(AssetType::BITMAP);
textures_.clear(); textures_.clear();
for (const auto &l : list) for (const auto &l : list) {
{
auto name = getFileName(l); auto name = getFileName(l);
updateLoadingProgress(name); updateLoadingProgress(name);
textures_.emplace_back(Resource::ResourceTexture(name, std::make_shared<Texture>(Screen::get()->getRenderer(), l))); textures_.emplace_back(Resource::ResourceTexture(name, std::make_shared<Texture>(Screen::get()->getRenderer(), l)));
@@ -233,14 +205,12 @@ void Resource::loadTextures()
} }
// Carga los ficheros de texto del juego // Carga los ficheros de texto del juego
void Resource::loadTextFiles() void Resource::loadTextFiles() {
{
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> TEXT FILES"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> TEXT FILES");
auto list = Asset::get()->getListByType(AssetType::FONT); auto list = Asset::get()->getListByType(AssetType::FONT);
text_files_.clear(); text_files_.clear();
for (const auto &l : list) for (const auto &l : list) {
{
auto name = getFileName(l); auto name = getFileName(l);
updateLoadingProgress(name); updateLoadingProgress(name);
text_files_.emplace_back(Resource::ResourceTextFile(name, loadTextFile(l))); text_files_.emplace_back(Resource::ResourceTextFile(name, loadTextFile(l)));
@@ -248,14 +218,12 @@ void Resource::loadTextFiles()
} }
// Carga las animaciones del juego // Carga las animaciones del juego
void Resource::loadAnimations() void Resource::loadAnimations() {
{
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> ANIMATIONS"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> ANIMATIONS");
auto list = Asset::get()->getListByType(AssetType::ANIMATION); auto list = Asset::get()->getListByType(AssetType::ANIMATION);
animations_.clear(); animations_.clear();
for (const auto &l : list) for (const auto &l : list) {
{
auto name = getFileName(l); auto name = getFileName(l);
updateLoadingProgress(name); updateLoadingProgress(name);
animations_.emplace_back(Resource::ResourceAnimation(name, loadAnimationsFromFile(l))); animations_.emplace_back(Resource::ResourceAnimation(name, loadAnimationsFromFile(l)));
@@ -263,22 +231,19 @@ void Resource::loadAnimations()
} }
// Carga los datos para el modo demostración // Carga los datos para el modo demostración
void Resource::loadDemoData() void Resource::loadDemoData() {
{
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> DEMO FILES"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> DEMO FILES");
constexpr std::array<const char *, 2> demo_files = {"demo1.bin", "demo2.bin"}; constexpr std::array<const char *, 2> demo_files = {"demo1.bin", "demo2.bin"};
for (const auto &file : demo_files) for (const auto &file : demo_files) {
{
updateLoadingProgress(file); updateLoadingProgress(file);
demos_.emplace_back(loadDemoDataFromFile(Asset::get()->get(file))); demos_.emplace_back(loadDemoDataFromFile(Asset::get()->get(file)));
} }
} }
// Añade paletas de colores a las texturas principales // Añade paletas de colores a las texturas principales
void Resource::addPalettes() void Resource::addPalettes() {
{
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> PALETTES"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> PALETTES");
// Paletas para el jugador 1 // Paletas para el jugador 1
@@ -293,10 +258,8 @@ void Resource::addPalettes()
} }
// Crea texturas a partir de textos para mostrar puntuaciones y mensajes // Crea texturas a partir de textos para mostrar puntuaciones y mensajes
void Resource::createTextures() void Resource::createTextures() {
{ struct NameAndText {
struct NameAndText
{
std::string name; std::string name;
std::string text; std::string text;
@@ -317,8 +280,7 @@ void Resource::createTextures()
{"game_text_1000000_points", Lang::getText("[GAME_TEXT] 8")}}; {"game_text_1000000_points", Lang::getText("[GAME_TEXT] 8")}};
auto text = getText("04b_25"); auto text = getText("04b_25");
for (const auto &s : strings) for (const auto &s : strings) {
{
textures_.emplace_back(Resource::ResourceTexture(s.name, text->writeToTexture(s.text, 1, -2))); textures_.emplace_back(Resource::ResourceTexture(s.name, text->writeToTexture(s.text, 1, -2)));
printWithDots("Texture : ", s.name, "[ DONE ]"); printWithDots("Texture : ", s.name, "[ DONE ]");
} }
@@ -332,18 +294,15 @@ void Resource::createTextures()
{"game_text_game_over", "Game Over"}}; {"game_text_game_over", "Game Over"}};
auto text2 = getText("04b_25_2x"); auto text2 = getText("04b_25_2x");
for (const auto &s : strings2X) for (const auto &s : strings2X) {
{
textures_.emplace_back(Resource::ResourceTexture(s.name, text2->writeToTexture(s.text, 1, -4))); textures_.emplace_back(Resource::ResourceTexture(s.name, text2->writeToTexture(s.text, 1, -4)));
printWithDots("Texture : ", s.name, "[ DONE ]"); printWithDots("Texture : ", s.name, "[ DONE ]");
} }
} }
// Crea los objetos de texto a partir de los archivos de textura y texto // Crea los objetos de texto a partir de los archivos de textura y texto
void Resource::createText() void Resource::createText() {
{ struct ResourceInfo {
struct ResourceInfo
{
std::string key; std::string key;
std::string textureFile; std::string textureFile;
std::string textFile; std::string textFile;
@@ -368,22 +327,16 @@ void Resource::createText()
{"smb2", "smb2.png", "smb2.txt"}, {"smb2", "smb2.png", "smb2.txt"},
{"smb2_grad", "smb2_grad.png", "smb2.txt"}}; {"smb2_grad", "smb2_grad.png", "smb2.txt"}};
for (const auto &resource : resources) for (const auto &resource : resources) {
{ texts_.emplace_back(Resource::ResourceText(resource.key, std::make_shared<Text>(getTexture(resource.textureFile), getTextFile(resource.textFile))));
texts_.emplace_back(Resource::ResourceText(resource.key, std::make_shared<Text>(
getTexture(resource.textureFile),
getTextFile(resource.textFile))));
printWithDots("Text : ", resource.key, "[ DONE ]"); printWithDots("Text : ", resource.key, "[ DONE ]");
} }
} }
// Vacía el vector de sonidos y libera la memoria asociada // Vacía el vector de sonidos y libera la memoria asociada
void Resource::clearSounds() void Resource::clearSounds() {
{ for (auto &sound : sounds_) {
for (auto &sound : sounds_) if (sound.sound) {
{
if (sound.sound)
{
JA_DeleteSound(sound.sound); JA_DeleteSound(sound.sound);
sound.sound = nullptr; sound.sound = nullptr;
} }
@@ -392,12 +345,9 @@ void Resource::clearSounds()
} }
// Vacía el vector de músicas y libera la memoria asociada // Vacía el vector de músicas y libera la memoria asociada
void Resource::clearMusics() void Resource::clearMusics() {
{ for (auto &music : musics_) {
for (auto &music : musics_) if (music.music) {
{
if (music.music)
{
JA_DeleteMusic(music.music); JA_DeleteMusic(music.music);
music.music = nullptr; music.music = nullptr;
} }
@@ -406,8 +356,7 @@ void Resource::clearMusics()
} }
// Calcula el número total de recursos a cargar y reinicia el contador de carga // Calcula el número total de recursos a cargar y reinicia el contador de carga
void Resource::calculateTotalResources() void Resource::calculateTotalResources() {
{
const std::array<AssetType, 6> ASSET_TYPES = { const std::array<AssetType, 6> ASSET_TYPES = {
AssetType::SOUND, AssetType::SOUND,
AssetType::MUSIC, AssetType::MUSIC,
@@ -417,8 +366,7 @@ void Resource::calculateTotalResources()
AssetType::DEMODATA}; AssetType::DEMODATA};
size_t total = 0; size_t total = 0;
for (const auto &asset_type : ASSET_TYPES) for (const auto &asset_type : ASSET_TYPES) {
{
auto list = Asset::get()->getListByType(asset_type); auto list = Asset::get()->getListByType(asset_type);
total += list.size(); total += list.size();
} }
@@ -427,8 +375,7 @@ void Resource::calculateTotalResources()
} }
// Muestra el progreso de carga en pantalla (barra y texto) // Muestra el progreso de carga en pantalla (barra y texto)
void Resource::renderProgress() void Resource::renderProgress() {
{
// Obtiene la pantalla y el renderer // Obtiene la pantalla y el renderer
auto screen = Screen::get(); auto screen = Screen::get();
auto renderer = screen->getRenderer(); auto renderer = screen->getRenderer();
@@ -462,29 +409,24 @@ void Resource::renderProgress()
} }
// Comprueba los eventos durante la carga (permite salir con ESC o cerrar ventana) // Comprueba los eventos durante la carga (permite salir con ESC o cerrar ventana)
void Resource::checkEvents() void Resource::checkEvents() {
{
SDL_Event event; SDL_Event event;
while (SDL_PollEvent(&event)) while (SDL_PollEvent(&event)) {
{ switch (event.type) {
switch (event.type) case SDL_EVENT_QUIT:
{
case SDL_EVENT_QUIT:
exit(0);
break;
case SDL_EVENT_KEY_DOWN:
if (event.key.key == SDLK_ESCAPE)
{
exit(0); exit(0);
} break;
break; case SDL_EVENT_KEY_DOWN:
if (event.key.key == SDLK_ESCAPE) {
exit(0);
}
break;
} }
} }
} }
// Actualiza el progreso de carga, muestra la barra y procesa eventos // Actualiza el progreso de carga, muestra la barra y procesa eventos
void Resource::updateLoadingProgress(std::string name) void Resource::updateLoadingProgress(std::string name) {
{
loading_resource_name_ = name; loading_resource_name_ = name;
loading_count_.increase(); loading_count_.increase();
updateProgressBar(); updateProgressBar();
@@ -493,8 +435,7 @@ void Resource::updateLoadingProgress(std::string name)
} }
// Inicializa los rectangulos que definen la barra de progreso // Inicializa los rectangulos que definen la barra de progreso
void Resource::initProgressBar() void Resource::initProgressBar() {
{
constexpr float X_PADDING = 20.0f; constexpr float X_PADDING = 20.0f;
constexpr float Y_PADDING = 20.0f; constexpr float Y_PADDING = 20.0f;
constexpr float BAR_HEIGHT = 10.0f; constexpr float BAR_HEIGHT = 10.0f;
@@ -508,7 +449,6 @@ void Resource::initProgressBar()
} }
// Actualiza la barra de estado // Actualiza la barra de estado
void Resource::updateProgressBar() void Resource::updateProgressBar() {
{
loading_full_rect_.w = loading_wired_rect_.w * loading_count_.getPercentage(); loading_full_rect_.w = loading_wired_rect_.w * loading_count_.getPercentage();
} }
+79 -87
View File
@@ -1,157 +1,149 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_FRect #include <SDL3/SDL.h> // Para SDL_FRect
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <memory> // Para shared_ptr
#include <string> // Para basic_string, string
#include <vector> // Para vector
#include "animated_sprite.h" // Para AnimationsFileBuffer #include <memory> // Para shared_ptr
#include "text.h" // Para Text, TextFile #include <string> // Para basic_string, string
#include "texture.h" // Para Texture #include <vector> // Para vector
#include "utils.h" // Para DemoData
#include "animated_sprite.h" // Para AnimationsFileBuffer
#include "text.h" // Para Text, TextFile
#include "texture.h" // Para Texture
#include "utils.h" // Para DemoData
struct JA_Music_t; struct JA_Music_t;
struct JA_Sound_t; struct JA_Sound_t;
// --- Clase Resource: gestiona todos los recursos del juego (singleton) --- // --- Clase Resource: gestiona todos los recursos del juego (singleton) ---
class Resource class Resource {
{ public:
public:
// --- Métodos de singleton --- // --- Métodos de singleton ---
static void init(); // Inicializa el objeto Resource static void init(); // Inicializa el objeto Resource
static void destroy(); // Libera el objeto Resource static void destroy(); // Libera el objeto Resource
static Resource *get(); // Obtiene el puntero al objeto Resource static Resource *get(); // Obtiene el puntero al objeto Resource
// --- Métodos de acceso a recursos --- // --- Métodos de acceso a recursos ---
JA_Sound_t *getSound(const std::string &name); // Obtiene el sonido por nombre JA_Sound_t *getSound(const std::string &name); // Obtiene el sonido por nombre
JA_Music_t *getMusic(const std::string &name); // Obtiene la música por nombre JA_Music_t *getMusic(const std::string &name); // Obtiene la música por nombre
std::shared_ptr<Texture> getTexture(const std::string &name); // Obtiene la textura por nombre std::shared_ptr<Texture> getTexture(const std::string &name); // Obtiene la textura por nombre
std::shared_ptr<TextFile> getTextFile(const std::string &name); // Obtiene el fichero de texto por nombre std::shared_ptr<TextFile> getTextFile(const std::string &name); // Obtiene el fichero de texto por nombre
std::shared_ptr<Text> getText(const std::string &name); // Obtiene el objeto de texto por nombre std::shared_ptr<Text> getText(const std::string &name); // Obtiene el objeto de texto por nombre
AnimationsFileBuffer &getAnimation(const std::string &name); // Obtiene la animación por nombre AnimationsFileBuffer &getAnimation(const std::string &name); // Obtiene la animación por nombre
DemoData &getDemoData(int index); // Obtiene los datos de demo por índice DemoData &getDemoData(int index); // Obtiene los datos de demo por índice
// --- Métodos de recarga de recursos --- // --- Métodos de recarga de recursos ---
void reload(); // Recarga todos los recursos void reload(); // Recarga todos los recursos
void reloadTextures(); // Recarga solo las texturas void reloadTextures(); // Recarga solo las texturas
private: private:
// --- Estructuras para recursos individuales --- // --- Estructuras para recursos individuales ---
struct ResourceSound struct ResourceSound {
{ std::string name; // Nombre del sonido
std::string name; // Nombre del sonido JA_Sound_t *sound; // Objeto con el sonido
JA_Sound_t *sound; // Objeto con el sonido
ResourceSound(const std::string &name, JA_Sound_t *sound) ResourceSound(const std::string &name, JA_Sound_t *sound)
: name(name), sound(sound) {} : name(name), sound(sound) {}
}; };
struct ResourceMusic struct ResourceMusic {
{ std::string name; // Nombre de la música
std::string name; // Nombre de la música JA_Music_t *music; // Objeto con la música
JA_Music_t *music; // Objeto con la música
ResourceMusic(const std::string &name, JA_Music_t *music) ResourceMusic(const std::string &name, JA_Music_t *music)
: name(name), music(music) {} : name(name), music(music) {}
}; };
struct ResourceTexture struct ResourceTexture {
{ std::string name; // Nombre de la textura
std::string name; // Nombre de la textura std::shared_ptr<Texture> texture; // Objeto con la textura
std::shared_ptr<Texture> texture; // Objeto con la textura
ResourceTexture(const std::string &name, std::shared_ptr<Texture> texture) ResourceTexture(const std::string &name, std::shared_ptr<Texture> texture)
: name(name), texture(texture) {} : name(name), texture(texture) {}
}; };
struct ResourceTextFile struct ResourceTextFile {
{ std::string name; // Nombre del fichero
std::string name; // Nombre del fichero std::shared_ptr<TextFile> text_file; // Objeto con los descriptores de la fuente de texto
std::shared_ptr<TextFile> text_file; // Objeto con los descriptores de la fuente de texto
ResourceTextFile(const std::string &name, std::shared_ptr<TextFile> text_file) ResourceTextFile(const std::string &name, std::shared_ptr<TextFile> text_file)
: name(name), text_file(text_file) {} : name(name), text_file(text_file) {}
}; };
struct ResourceText struct ResourceText {
{ std::string name; // Nombre del objeto
std::string name; // Nombre del objeto std::shared_ptr<Text> text; // Objeto de texto
std::shared_ptr<Text> text; // Objeto de texto
ResourceText(const std::string &name, std::shared_ptr<Text> text) ResourceText(const std::string &name, std::shared_ptr<Text> text)
: name(name), text(text) {} : name(name), text(text) {}
}; };
struct ResourceAnimation struct ResourceAnimation {
{ std::string name; // Nombre de la animación
std::string name; // Nombre de la animación AnimationsFileBuffer animation; // Objeto con las animaciones
AnimationsFileBuffer animation; // Objeto con las animaciones
ResourceAnimation(const std::string &name, const AnimationsFileBuffer &animation) ResourceAnimation(const std::string &name, const AnimationsFileBuffer &animation)
: name(name), animation(animation) {} : name(name), animation(animation) {}
}; };
// --- Estructura para el progreso de carga --- // --- Estructura para el progreso de carga ---
struct ResourceCount struct ResourceCount {
{ size_t total; // Número total de recursos
size_t total; // Número total de recursos size_t loaded; // Número de recursos cargados
size_t loaded; // Número de recursos cargados
ResourceCount() : total(0), loaded(0) {} ResourceCount() : total(0), loaded(0) {}
ResourceCount(size_t total) : total(total), loaded(0) {} ResourceCount(size_t total) : total(total), loaded(0) {}
void add(size_t amount) { loaded += amount; } void add(size_t amount) { loaded += amount; }
void increase() { loaded++; } void increase() { loaded++; }
float getPercentage() const float getPercentage() const {
{
return total > 0 ? static_cast<float>(loaded) / static_cast<float>(total) : 0.0f; return total > 0 ? static_cast<float>(loaded) / static_cast<float>(total) : 0.0f;
} }
}; };
// --- Instancia singleton --- // --- Instancia singleton ---
static Resource *instance_; // Instancia única de Resource static Resource *instance_; // Instancia única de Resource
// --- Vectores de recursos --- // --- Vectores de recursos ---
std::vector<ResourceSound> sounds_; // Vector con los sonidos std::vector<ResourceSound> sounds_; // Vector con los sonidos
std::vector<ResourceMusic> musics_; // Vector con las músicas std::vector<ResourceMusic> musics_; // Vector con las músicas
std::vector<ResourceTexture> textures_; // Vector con las texturas std::vector<ResourceTexture> textures_; // Vector con las texturas
std::vector<ResourceTextFile> text_files_; // Vector con los ficheros de texto std::vector<ResourceTextFile> text_files_; // Vector con los ficheros de texto
std::vector<ResourceText> texts_; // Vector con los objetos de texto std::vector<ResourceText> texts_; // Vector con los objetos de texto
std::vector<ResourceAnimation> animations_; // Vector con las animaciones std::vector<ResourceAnimation> animations_; // Vector con las animaciones
std::vector<DemoData> demos_; // Vector con los ficheros de datos para el modo demostración std::vector<DemoData> demos_; // Vector con los ficheros de datos para el modo demostración
// --- Progreso de carga --- // --- Progreso de carga ---
ResourceCount loading_count_; // Contador de recursos cargados ResourceCount loading_count_; // Contador de recursos cargados
std::shared_ptr<Text> loading_text_; // Texto para escribir en pantalla std::shared_ptr<Text> loading_text_; // Texto para escribir en pantalla
std::string loading_resource_name_; // Nombre del recurso que se está cargando std::string loading_resource_name_; // Nombre del recurso que se está cargando
SDL_FRect loading_wired_rect_; SDL_FRect loading_wired_rect_;
SDL_FRect loading_full_rect_; SDL_FRect loading_full_rect_;
// --- Métodos internos de carga y gestión --- // --- Métodos internos de carga y gestión ---
void loadSounds(); // Carga los sonidos void loadSounds(); // Carga los sonidos
void loadMusics(); // Carga las músicas void loadMusics(); // Carga las músicas
void loadTextures(); // Carga las texturas void loadTextures(); // Carga las texturas
void loadTextFiles(); // Carga los ficheros de texto void loadTextFiles(); // Carga los ficheros de texto
void loadAnimations(); // Carga las animaciones void loadAnimations(); // Carga las animaciones
void loadDemoData(); // Carga los datos para el modo demostración void loadDemoData(); // Carga los datos para el modo demostración
void addPalettes(); // Añade paletas a las texturas void addPalettes(); // Añade paletas a las texturas
void createTextures(); // Crea las texturas a partir de los datos cargados void createTextures(); // Crea las texturas a partir de los datos cargados
void createText(); // Crea los objetos de texto void createText(); // Crea los objetos de texto
void clear(); // Vacía todos los vectores de recursos void clear(); // Vacía todos los vectores de recursos
void load(); // Carga todos los recursos void load(); // Carga todos los recursos
void clearSounds(); // Vacía el vector de sonidos void clearSounds(); // Vacía el vector de sonidos
void clearMusics(); // Vacía el vector de músicas void clearMusics(); // Vacía el vector de músicas
// --- Métodos internos para gestionar el progreso --- // --- Métodos internos para gestionar el progreso ---
void calculateTotalResources(); // Calcula el número de recursos para cargar void calculateTotalResources(); // Calcula el número de recursos para cargar
void renderProgress(); // Muestra el progreso de carga void renderProgress(); // Muestra el progreso de carga
void checkEvents(); // Comprueba los eventos durante la carga void checkEvents(); // Comprueba los eventos durante la carga
void updateLoadingProgress(std::string name); // Actualiza el progreso de carga void updateLoadingProgress(std::string name); // Actualiza el progreso de carga
void initProgressBar(); // Inicializa los rectangulos que definen la barra de progreso void initProgressBar(); // Inicializa los rectangulos que definen la barra de progreso
void updateProgressBar(); // Actualiza la barra de estado void updateProgressBar(); // Actualiza la barra de estado
// --- Constructores y destructor privados (singleton) --- // --- Constructores y destructor privados (singleton) ---
Resource(); // Constructor privado Resource(); // Constructor privado
~Resource(); // Destructor privado ~Resource(); // Destructor privado
}; };
+303 -351
View File
@@ -1,460 +1,412 @@
#include "scoreboard.h" #include "scoreboard.h"
#include <SDL3/SDL.h> // Para SDL_DestroyTexture, SDL_SetRenderDrawColor #include <SDL3/SDL.h> // Para SDL_DestroyTexture, SDL_SetRenderDrawColor
#include <math.h> // Para roundf #include <math.h> // Para roundf
#include <iomanip> // Para operator<<, setfill, setw
#include <sstream> // Para basic_ostringstream, basic_ostream, basic_os...
#include "enter_name.h" // Para NAME_SIZE #include <iomanip> // Para operator<<, setfill, setw
#include "lang.h" // Para getText #include <sstream> // Para basic_ostringstream, basic_ostream, basic_os...
#include "param.h" // Para Param, ParamScoreboard, param
#include "resource.h" // Para Resource #include "enter_name.h" // Para NAME_SIZE
#include "screen.h" // Para Screen #include "lang.h" // Para getText
#include "sprite.h" // Para Sprite #include "param.h" // Para Param, ParamScoreboard, param
#include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR #include "resource.h" // Para Resource
#include "texture.h" // Para Texture #include "screen.h" // Para Screen
#include "sprite.h" // Para Sprite
#include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR
#include "texture.h" // Para Texture
// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado // [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado
Scoreboard *Scoreboard::scoreboard_ = nullptr; Scoreboard *Scoreboard::scoreboard_ = nullptr;
// [SINGLETON] Crearemos el objeto score_board con esta función estática // [SINGLETON] Crearemos el objeto score_board con esta función estática
void Scoreboard::init() void Scoreboard::init() {
{ Scoreboard::scoreboard_ = new Scoreboard();
Scoreboard::scoreboard_ = new Scoreboard();
} }
// [SINGLETON] Destruiremos el objeto score_board con esta función estática // [SINGLETON] Destruiremos el objeto score_board con esta función estática
void Scoreboard::destroy() void Scoreboard::destroy() {
{ delete Scoreboard::scoreboard_;
delete Scoreboard::scoreboard_;
} }
// [SINGLETON] Con este método obtenemos el objeto score_board y podemos trabajar con él // [SINGLETON] Con este método obtenemos el objeto score_board y podemos trabajar con él
Scoreboard *Scoreboard::get() Scoreboard *Scoreboard::get() {
{ return Scoreboard::scoreboard_;
return Scoreboard::scoreboard_;
} }
// Constructor // Constructor
Scoreboard::Scoreboard() Scoreboard::Scoreboard()
: renderer_(Screen::get()->getRenderer()), : renderer_(Screen::get()->getRenderer()),
game_power_meter_texture_(Resource::get()->getTexture("game_power_meter.png")), game_power_meter_texture_(Resource::get()->getTexture("game_power_meter.png")),
power_meter_sprite_(std::make_unique<Sprite>(game_power_meter_texture_)), power_meter_sprite_(std::make_unique<Sprite>(game_power_meter_texture_)),
text_scoreboard_(Resource::get()->getText("8bithud")) text_scoreboard_(Resource::get()->getText("8bithud")) {
{ // Inicializa variables
// Inicializa variables for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) {
for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) name_[i].clear();
{ record_name_[i].clear();
name_[i].clear(); selector_pos_[i] = 0;
record_name_[i].clear(); score_[i] = 0;
selector_pos_[i] = 0; mult_[i] = 0;
score_[i] = 0; continue_counter_[i] = 0;
mult_[i] = 0; }
continue_counter_[i] = 0;
}
panel_[SCOREBOARD_LEFT_PANEL].mode = ScoreboardMode::SCORE; panel_[SCOREBOARD_LEFT_PANEL].mode = ScoreboardMode::SCORE;
panel_[SCOREBOARD_RIGHT_PANEL].mode = ScoreboardMode::SCORE; panel_[SCOREBOARD_RIGHT_PANEL].mode = ScoreboardMode::SCORE;
panel_[SCOREBOARD_CENTER_PANEL].mode = ScoreboardMode::STAGE_INFO; panel_[SCOREBOARD_CENTER_PANEL].mode = ScoreboardMode::STAGE_INFO;
// Recalcula las anclas de los elementos // Recalcula las anclas de los elementos
recalculateAnchors(); recalculateAnchors();
power_meter_sprite_->setPosition(SDL_FRect{ power_meter_sprite_->setPosition(SDL_FRect{
static_cast<float>(slot4_2_.x - 20), static_cast<float>(slot4_2_.x - 20),
static_cast<float>(slot4_2_.y), static_cast<float>(slot4_2_.y),
40, 40,
7}); 7});
// Crea la textura de fondo // Crea la textura de fondo
background_ = nullptr; background_ = nullptr;
createBackgroundTexture(); createBackgroundTexture();
// Crea las texturas de los paneles // Crea las texturas de los paneles
createPanelTextures(); createPanelTextures();
// Rellena la textura de fondo // Rellena la textura de fondo
fillBackgroundTexture(); fillBackgroundTexture();
// Inicializa el vector de colores para el nombre // Inicializa el vector de colores para el nombre
iniNameColors(); iniNameColors();
} }
Scoreboard::~Scoreboard() Scoreboard::~Scoreboard() {
{ if (background_) {
if (background_) SDL_DestroyTexture(background_);
{ }
SDL_DestroyTexture(background_);
}
for (auto texture : panel_texture_) for (auto texture : panel_texture_) {
{ if (texture) {
if (texture) SDL_DestroyTexture(texture);
{ }
SDL_DestroyTexture(texture); }
}
}
} }
// Transforma un valor numérico en una cadena de 7 cifras // Transforma un valor numérico en una cadena de 7 cifras
std::string Scoreboard::updateScoreText(int num) std::string Scoreboard::updateScoreText(int num) {
{ std::ostringstream oss;
std::ostringstream oss; oss << std::setw(7) << std::setfill('0') << num;
oss << std::setw(7) << std::setfill('0') << num; return oss.str();
return oss.str();
} }
// Actualiza el contador // Actualiza el contador
void Scoreboard::updateTimeCounter() void Scoreboard::updateTimeCounter() {
{ constexpr int TICKS_SPEED = 100;
constexpr int TICKS_SPEED = 100;
if (SDL_GetTicks() - ticks_ > TICKS_SPEED) if (SDL_GetTicks() - ticks_ > TICKS_SPEED) {
{ ticks_ = SDL_GetTicks();
ticks_ = SDL_GetTicks(); ++time_counter_;
++time_counter_; }
}
} }
// Actualiza la lógica del marcador // Actualiza la lógica del marcador
void Scoreboard::update() void Scoreboard::update() {
{ fillBackgroundTexture();
fillBackgroundTexture(); updateTimeCounter();
updateTimeCounter(); ++loop_counter_;
++loop_counter_;
} }
// Pinta el marcador // Pinta el marcador
void Scoreboard::render() void Scoreboard::render() {
{ SDL_RenderTexture(renderer_, background_, nullptr, &rect_);
SDL_RenderTexture(renderer_, background_, nullptr, &rect_);
} }
// Establece el valor de la variable // Establece el valor de la variable
void Scoreboard::setColor(Color color) void Scoreboard::setColor(Color color) {
{ // Actualiza las variables de colores
// Actualiza las variables de colores color_ = color;
color_ = color; text_color1_ = param.scoreboard.text_autocolor ? color_.lighten(100) : param.scoreboard.text_color1;
text_color1_ = param.scoreboard.text_autocolor ? color_.lighten(100) : param.scoreboard.text_color1; text_color2_ = param.scoreboard.text_autocolor ? color_.lighten(150) : param.scoreboard.text_color2;
text_color2_ = param.scoreboard.text_autocolor ? color_.lighten(150) : param.scoreboard.text_color2;
// Aplica los colores // Aplica los colores
power_meter_sprite_->getTexture()->setColor(text_color2_); power_meter_sprite_->getTexture()->setColor(text_color2_);
fillBackgroundTexture(); fillBackgroundTexture();
iniNameColors(); iniNameColors();
} }
// Establece el valor de la variable // Establece el valor de la variable
void Scoreboard::setPos(SDL_FRect rect) void Scoreboard::setPos(SDL_FRect rect) {
{ rect_ = rect;
rect_ = rect;
recalculateAnchors(); // Recalcula las anclas de los elementos recalculateAnchors(); // Recalcula las anclas de los elementos
createBackgroundTexture(); // Crea la textura de fondo createBackgroundTexture(); // Crea la textura de fondo
createPanelTextures(); // Crea las texturas de los paneles createPanelTextures(); // Crea las texturas de los paneles
fillBackgroundTexture(); // Rellena la textura de fondo fillBackgroundTexture(); // Rellena la textura de fondo
} }
// Rellena los diferentes paneles del marcador // Rellena los diferentes paneles del marcador
void Scoreboard::fillPanelTextures() void Scoreboard::fillPanelTextures() {
{ // Guarda a donde apunta actualmente el renderizador
// Guarda a donde apunta actualmente el renderizador auto temp = SDL_GetRenderTarget(renderer_);
auto temp = SDL_GetRenderTarget(renderer_);
// Genera el contenido de cada panel_ // Genera el contenido de cada panel_
for (size_t i = 0; i < SCOREBOARD_MAX_PANELS; ++i) for (size_t i = 0; i < SCOREBOARD_MAX_PANELS; ++i) {
{ // Cambia el destino del renderizador
// Cambia el destino del renderizador SDL_SetRenderTarget(renderer_, panel_texture_[i]);
SDL_SetRenderTarget(renderer_, panel_texture_[i]);
// Dibuja el fondo de la textura // Dibuja el fondo de la textura
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0); SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
SDL_RenderClear(renderer_); SDL_RenderClear(renderer_);
switch (panel_[i].mode) switch (panel_[i].mode) {
{ case ScoreboardMode::SCORE: {
case ScoreboardMode::SCORE: // SCORE
{ text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_1_.x, slot4_1_.y, name_[i], 1, text_color1_);
// SCORE text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]), 1, text_color2_);
text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_1_.x, slot4_1_.y, name_[i], 1, text_color1_);
text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]), 1, text_color2_);
// MULT // MULT
text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 3"), 1, text_color1_); text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 3"), 1, text_color1_);
text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_4_.x, slot4_4_.y, "x" + std::to_string(mult_[i]).substr(0, 3), 1, text_color2_); text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_4_.x, slot4_4_.y, "x" + std::to_string(mult_[i]).substr(0, 3), 1, text_color2_);
break; break;
} }
case ScoreboardMode::DEMO: case ScoreboardMode::DEMO: {
{ // DEMO MODE
// DEMO MODE text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y + 4, Lang::getText("[SCOREBOARD] 6"), 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y + 4, Lang::getText("[SCOREBOARD] 6"), 1, text_color1_);
// PRESS START TO PLAY // PRESS START TO PLAY
if (time_counter_ % 10 < 8) if (time_counter_ % 10 < 8) {
{ text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y - 2, Lang::getText("[SCOREBOARD] 8"), 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y - 2, Lang::getText("[SCOREBOARD] 8"), 1, text_color1_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y - 2, Lang::getText("[SCOREBOARD] 9"), 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y - 2, Lang::getText("[SCOREBOARD] 9"), 1, text_color1_); }
} break;
break; }
}
case ScoreboardMode::WAITING: case ScoreboardMode::WAITING: {
{ // GAME OVER
// GAME OVER text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y + 4, Lang::getText("[SCOREBOARD] 7"), 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y + 4, Lang::getText("[SCOREBOARD] 7"), 1, text_color1_);
// PRESS START TO PLAY // PRESS START TO PLAY
if (time_counter_ % 10 < 8) if (time_counter_ % 10 < 8) {
{ text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y - 2, Lang::getText("[SCOREBOARD] 8"), 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y - 2, Lang::getText("[SCOREBOARD] 8"), 1, text_color1_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y - 2, Lang::getText("[SCOREBOARD] 9"), 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y - 2, Lang::getText("[SCOREBOARD] 9"), 1, text_color1_); }
} break;
break; }
}
case ScoreboardMode::GAME_OVER: case ScoreboardMode::GAME_OVER: {
{ // GAME OVER
// GAME OVER text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y + 4, Lang::getText("[SCOREBOARD] 7"), 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y + 4, Lang::getText("[SCOREBOARD] 7"), 1, text_color1_);
// PLEASE WAIT // PLEASE WAIT
if (time_counter_ % 10 < 8) if (time_counter_ % 10 < 8) {
{ text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y - 2, Lang::getText("[SCOREBOARD] 12"), 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y - 2, Lang::getText("[SCOREBOARD] 12"), 1, text_color1_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y - 2, Lang::getText("[SCOREBOARD] 13"), 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y - 2, Lang::getText("[SCOREBOARD] 13"), 1, text_color1_); }
} break;
break; }
}
case ScoreboardMode::STAGE_INFO: case ScoreboardMode::STAGE_INFO: {
{ // STAGE
// STAGE text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y, Lang::getText("[SCOREBOARD] 5") + std::to_string(stage_), 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y, Lang::getText("[SCOREBOARD] 5") + std::to_string(stage_), 1, text_color1_);
// POWERMETER // POWERMETER
power_meter_sprite_->setSpriteClip(0, 0, 40, 7); power_meter_sprite_->setSpriteClip(0, 0, 40, 7);
power_meter_sprite_->render(); power_meter_sprite_->render();
power_meter_sprite_->setSpriteClip(40, 0, int(power_ * 40.0f), 7); power_meter_sprite_->setSpriteClip(40, 0, int(power_ * 40.0f), 7);
power_meter_sprite_->render(); power_meter_sprite_->render();
// HI-SCORE // HI-SCORE
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 4"), 1, text_color1_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 4"), 1, text_color1_);
const std::string name = hi_score_name_ == "" ? "" : hi_score_name_ + " - "; const std::string name = hi_score_name_ == "" ? "" : hi_score_name_ + " - ";
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y, name + updateScoreText(hi_score_), 1, text_color2_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y, name + updateScoreText(hi_score_), 1, text_color2_);
break; break;
} }
case ScoreboardMode::CONTINUE: case ScoreboardMode::CONTINUE: {
{ // SCORE
// SCORE text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y, name_[i], 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y, name_[i], 1, text_color1_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]), 1, text_color2_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]), 1, text_color2_);
// CONTINUE // CONTINUE
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 10"), 1, text_color1_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 10"), 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y, std::to_string(continue_counter_[i]), 1, text_color2_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y, std::to_string(continue_counter_[i]), 1, text_color2_);
break; break;
} }
case ScoreboardMode::ENTER_NAME: case ScoreboardMode::ENTER_NAME: {
{ // SCORE
// SCORE text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y, name_[i], 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y, name_[i], 1, text_color1_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]), 1, text_color2_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]), 1, text_color2_);
// ENTER NAME // ENTER NAME
{ {
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 11"), 1, text_color1_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 11"), 1, text_color1_);
SDL_FRect rect = {enter_name_pos_.x, enter_name_pos_.y, 5.0f, 7.0f}; SDL_FRect rect = {enter_name_pos_.x, enter_name_pos_.y, 5.0f, 7.0f};
// Recorre todos los slots de letras del nombre // Recorre todos los slots de letras del nombre
for (size_t j = 0; j < NAME_SIZE; ++j) for (size_t j = 0; j < NAME_SIZE; ++j) {
{ // Selecciona el color
// Selecciona el color const Color color = j < selector_pos_[i] ? text_color2_ : text_color1_;
const Color color = j < selector_pos_[i] ? text_color2_ : text_color1_;
if (j != selector_pos_[i] || time_counter_ % 3 == 0) if (j != selector_pos_[i] || time_counter_ % 3 == 0) {
{ // Dibuja la linea
// Dibuja la linea if (j >= selector_pos_[i]) {
if (j >= selector_pos_[i]) SDL_SetRenderDrawColor(renderer_, color.r, color.g, color.b, 255);
{ SDL_RenderLine(renderer_, rect.x, rect.y + rect.h, rect.x + rect.w, rect.y + rect.h);
SDL_SetRenderDrawColor(renderer_, color.r, color.g, color.b, 255); }
SDL_RenderLine(renderer_, rect.x, rect.y + rect.h, rect.x + rect.w, rect.y + rect.h);
}
// Dibuja la letra // Dibuja la letra
if (j < record_name_[i].size()) if (j < record_name_[i].size()) {
{ text_scoreboard_->writeColored(rect.x, rect.y, record_name_[i].substr(j, 1), color);
text_scoreboard_->writeColored(rect.x, rect.y, record_name_[i].substr(j, 1), color); }
} }
} rect.x += 7;
rect.x += 7; }
} }
} break;
break; }
} case ScoreboardMode::SHOW_NAME: {
case ScoreboardMode::SHOW_NAME: // SCORE
{ text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y, name_[i], 1, text_color1_);
// SCORE text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]), 1, text_color2_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y, name_[i], 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]), 1, text_color2_);
// NAME // NAME
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 11"), 1, text_color1_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 11"), 1, text_color1_);
/* TEXTO CENTRADO */ /* TEXTO CENTRADO */
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y, record_name_[i], 1, getColorLikeKnightRider(name_colors_, loop_counter_ / 5)); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y, record_name_[i], 1, getColorLikeKnightRider(name_colors_, loop_counter_ / 5));
/* TEXTO A LA IZQUIERDA */ /* TEXTO A LA IZQUIERDA */
// text_scoreboard_->writeColored(enter_name_pos_.x, enter_name_pos_.y, record_name_[i], getColorLikeKnightRider(name_colors_, loop_counter_ / 5)); // text_scoreboard_->writeColored(enter_name_pos_.x, enter_name_pos_.y, record_name_[i], getColorLikeKnightRider(name_colors_, loop_counter_ / 5));
break; break;
} }
case ScoreboardMode::GAME_COMPLETED: case ScoreboardMode::GAME_COMPLETED: {
{ // GAME OVER
// GAME OVER text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y + 4, Lang::getText("[SCOREBOARD] 7"), 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_1_.x, slot4_1_.y + 4, Lang::getText("[SCOREBOARD] 7"), 1, text_color1_);
// SCORE // SCORE
if (time_counter_ % 10 < 8) if (time_counter_ % 10 < 8) {
{ text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y - 2, Lang::getText("[SCOREBOARD] 14"), 1, text_color1_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_3_.x, slot4_3_.y - 2, Lang::getText("[SCOREBOARD] 14"), 1, text_color1_); text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y - 2, updateScoreText(score_[i]), 1, text_color2_);
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y - 2, updateScoreText(score_[i]), 1, text_color2_); }
} }
} default:
default: break;
break; }
} }
}
// Deja el renderizador apuntando donde estaba // Deja el renderizador apuntando donde estaba
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
} }
// Rellena la textura de fondo // Rellena la textura de fondo
void Scoreboard::fillBackgroundTexture() void Scoreboard::fillBackgroundTexture() {
{ // Rellena los diferentes paneles del marcador
// Rellena los diferentes paneles del marcador fillPanelTextures();
fillPanelTextures();
// Cambia el destino del renderizador // Cambia el destino del renderizador
SDL_Texture *temp = SDL_GetRenderTarget(renderer_); SDL_Texture *temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, background_); SDL_SetRenderTarget(renderer_, background_);
// Dibuja el fondo del marcador // Dibuja el fondo del marcador
SDL_SetRenderDrawColor(renderer_, color_.r, color_.g, color_.b, 255); SDL_SetRenderDrawColor(renderer_, color_.r, color_.g, color_.b, 255);
SDL_RenderClear(renderer_); SDL_RenderClear(renderer_);
// Copia las texturas de los paneles // Copia las texturas de los paneles
for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) {
{ SDL_RenderTexture(renderer_, panel_texture_[i], nullptr, &panel_[i].pos);
SDL_RenderTexture(renderer_, panel_texture_[i], nullptr, &panel_[i].pos); }
}
// Dibuja la linea que separa la zona de juego del marcador // Dibuja la linea que separa la zona de juego del marcador
renderSeparator(); renderSeparator();
// Deja el renderizador apuntando donde estaba // Deja el renderizador apuntando donde estaba
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
} }
// Recalcula las anclas de los elementos // Recalcula las anclas de los elementos
void Scoreboard::recalculateAnchors() void Scoreboard::recalculateAnchors() {
{ // Recalcula la posición y el tamaño de los paneles
// Recalcula la posición y el tamaño de los paneles const float panel_width = (float)rect_.w / (float)SCOREBOARD_MAX_PANELS;
const float panel_width = (float)rect_.w / (float)SCOREBOARD_MAX_PANELS; for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) {
for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) panel_[i].pos.x = roundf(panel_width * i);
{ panel_[i].pos.y = 0;
panel_[i].pos.x = roundf(panel_width * i); panel_[i].pos.w = roundf(panel_width * (i + 1)) - panel_[i].pos.x;
panel_[i].pos.y = 0; panel_[i].pos.h = rect_.h;
panel_[i].pos.w = roundf(panel_width * (i + 1)) - panel_[i].pos.x; }
panel_[i].pos.h = rect_.h;
}
// Constantes para definir las zonas del panel_: 4 filas y 1 columna // Constantes para definir las zonas del panel_: 4 filas y 1 columna
const int ROW_SIZE = rect_.h / 4; const int ROW_SIZE = rect_.h / 4;
const int TEXT_HEIGHT = 7; const int TEXT_HEIGHT = 7;
// Filas // Filas
const float ROW1 = 1 + (ROW_SIZE * 0) + (TEXT_HEIGHT / 2); const float ROW1 = 1 + (ROW_SIZE * 0) + (TEXT_HEIGHT / 2);
const float ROW2 = 1 + (ROW_SIZE * 1) + (TEXT_HEIGHT / 2) - 1; const float ROW2 = 1 + (ROW_SIZE * 1) + (TEXT_HEIGHT / 2) - 1;
const float ROW3 = 1 + (ROW_SIZE * 2) + (TEXT_HEIGHT / 2) - 2; const float ROW3 = 1 + (ROW_SIZE * 2) + (TEXT_HEIGHT / 2) - 2;
const float ROW4 = 1 + (ROW_SIZE * 3) + (TEXT_HEIGHT / 2) - 3; const float ROW4 = 1 + (ROW_SIZE * 3) + (TEXT_HEIGHT / 2) - 3;
// Columna // Columna
const float COL = panel_width / 2; const float COL = panel_width / 2;
// Slots de 4 // Slots de 4
slot4_1_ = {COL, ROW1}; slot4_1_ = {COL, ROW1};
slot4_2_ = {COL, ROW2}; slot4_2_ = {COL, ROW2};
slot4_3_ = {COL, ROW3}; slot4_3_ = {COL, ROW3};
slot4_4_ = {COL, ROW4}; slot4_4_ = {COL, ROW4};
// Primer cuadrado para poner el nombre de record // Primer cuadrado para poner el nombre de record
const int enter_name_lenght = text_scoreboard_->lenght(std::string(NAME_SIZE, 'A')); const int enter_name_lenght = text_scoreboard_->lenght(std::string(NAME_SIZE, 'A'));
enter_name_pos_.x = COL - (enter_name_lenght / 2); enter_name_pos_.x = COL - (enter_name_lenght / 2);
enter_name_pos_.y = ROW4; enter_name_pos_.y = ROW4;
// Recoloca los sprites // Recoloca los sprites
if (power_meter_sprite_) if (power_meter_sprite_) {
{ power_meter_sprite_->setX(slot4_2_.x - 20);
power_meter_sprite_->setX(slot4_2_.x - 20); power_meter_sprite_->setY(slot4_2_.y);
power_meter_sprite_->setY(slot4_2_.y); }
}
} }
// Crea la textura de fondo // Crea la textura de fondo
void Scoreboard::createBackgroundTexture() void Scoreboard::createBackgroundTexture() {
{ // Elimina la textura en caso de existir
// Elimina la textura en caso de existir if (background_) {
if (background_) SDL_DestroyTexture(background_);
{ }
SDL_DestroyTexture(background_);
}
// Recrea la textura de fondo // Recrea la textura de fondo
background_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h); background_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h);
SDL_SetTextureBlendMode(background_, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(background_, SDL_BLENDMODE_BLEND);
} }
// Crea las texturas de los paneles // Crea las texturas de los paneles
void Scoreboard::createPanelTextures() void Scoreboard::createPanelTextures() {
{ // Elimina las texturas en caso de existir
// Elimina las texturas en caso de existir for (auto texture : panel_texture_) {
for (auto texture : panel_texture_) if (texture != nullptr) {
{ SDL_DestroyTexture(texture);
if (texture != nullptr) }
{ }
SDL_DestroyTexture(texture); panel_texture_.clear();
}
}
panel_texture_.clear();
// Crea las texturas para cada panel_ // Crea las texturas para cada panel_
for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) {
{ SDL_Texture *tex = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, panel_[i].pos.w, panel_[i].pos.h);
SDL_Texture *tex = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, panel_[i].pos.w, panel_[i].pos.h); SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND);
SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND); panel_texture_.push_back(tex);
panel_texture_.push_back(tex); }
}
} }
// Dibuja la linea que separa la zona de juego del marcador // Dibuja la linea que separa la zona de juego del marcador
void Scoreboard::renderSeparator() void Scoreboard::renderSeparator() {
{ // Dibuja la linea que separa el marcador de la zona de juego
// Dibuja la linea que separa el marcador de la zona de juego auto color = param.scoreboard.separator_autocolor ? color_.darken() : param.scoreboard.separator_color;
auto color = param.scoreboard.separator_autocolor ? color_.darken() : param.scoreboard.separator_color; SDL_SetRenderDrawColor(renderer_, color.r, color.g, color.b, 255);
SDL_SetRenderDrawColor(renderer_, color.r, color.g, color.b, 255); SDL_RenderLine(renderer_, 0, 0, rect_.w, 0);
SDL_RenderLine(renderer_, 0, 0, rect_.w, 0);
} }
// Inicializa el vector de colores para el nombre // Inicializa el vector de colores para el nombre
void Scoreboard::iniNameColors() void Scoreboard::iniNameColors() {
{ Color color = color_.inverse();
Color color = color_.inverse();
name_colors_.clear(); name_colors_.clear();
name_colors_.emplace_back(color.lighten(50)); name_colors_.emplace_back(color.lighten(50));
name_colors_.emplace_back(color.lighten(25)); name_colors_.emplace_back(color.lighten(25));
name_colors_.emplace_back(color); name_colors_.emplace_back(color);
name_colors_.emplace_back(color.darken(25)); name_colors_.emplace_back(color.darken(25));
} }
+90 -92
View File
@@ -1,12 +1,13 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_FPoint, SDL_GetTicks, SDL_FRect, SDL_Texture, SDL_Renderer, Uint64 #include <SDL3/SDL.h> // Para SDL_FPoint, SDL_GetTicks, SDL_FRect, SDL_Texture, SDL_Renderer, Uint64
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <memory> // Para shared_ptr, unique_ptr
#include <string> // Para basic_string, string
#include <vector> // Para vector
#include "utils.h" // Para Color #include <memory> // Para shared_ptr, unique_ptr
#include <string> // Para basic_string, string
#include <vector> // Para vector
#include "utils.h" // Para Color
class Sprite; class Sprite;
class Text; class Text;
@@ -19,105 +20,102 @@ constexpr int SCOREBOARD_RIGHT_PANEL = 2;
constexpr int SCOREBOARD_MAX_PANELS = 3; constexpr int SCOREBOARD_MAX_PANELS = 3;
// --- Enums --- // --- Enums ---
enum class ScoreboardMode : int enum class ScoreboardMode : int {
{ SCORE,
SCORE, STAGE_INFO,
STAGE_INFO, CONTINUE,
CONTINUE, WAITING,
WAITING, GAME_OVER,
GAME_OVER, DEMO,
DEMO, ENTER_NAME,
ENTER_NAME, SHOW_NAME,
SHOW_NAME, GAME_COMPLETED,
GAME_COMPLETED, NUM_MODES,
NUM_MODES,
}; };
// --- Structs --- // --- Structs ---
struct Panel struct Panel {
{ ScoreboardMode mode; // Modo en el que se encuentra el panel
ScoreboardMode mode; // Modo en el que se encuentra el panel SDL_FRect pos; // Posición donde dibujar el panel dentro del marcador
SDL_FRect pos; // Posición donde dibujar el panel dentro del marcador
}; };
// --- Clase Scoreboard --- // --- Clase Scoreboard ---
class Scoreboard class Scoreboard {
{ public:
public: // --- Métodos de singleton ---
// --- Métodos de singleton --- static void init(); // Crea el objeto Scoreboard
static void init(); // Crea el objeto Scoreboard static void destroy(); // Libera el objeto Scoreboard
static void destroy(); // Libera el objeto Scoreboard static Scoreboard *get(); // Obtiene el puntero al objeto Scoreboard
static Scoreboard *get(); // Obtiene el puntero al objeto Scoreboard
// --- Métodos principales --- // --- Métodos principales ---
void update(); // Actualiza la lógica del marcador void update(); // Actualiza la lógica del marcador
void render(); // Pinta el marcador void render(); // Pinta el marcador
// --- Setters --- // --- Setters ---
void setColor(Color color); // Establece el color del marcador void setColor(Color color); // Establece el color del marcador
void setPos(SDL_FRect rect); // Establece la posición y tamaño del marcador void setPos(SDL_FRect rect); // Establece la posición y tamaño del marcador
void setContinue(int panel, int continue_counter) { continue_counter_[panel] = continue_counter; } void setContinue(int panel, int continue_counter) { continue_counter_[panel] = continue_counter; }
void setHiScore(int hi_score) { hi_score_ = hi_score; } void setHiScore(int hi_score) { hi_score_ = hi_score; }
void setHiScoreName(const std::string &name) { hi_score_name_ = name; } void setHiScoreName(const std::string &name) { hi_score_name_ = name; }
void setMode(int index, ScoreboardMode mode) { panel_[index].mode = mode; } void setMode(int index, ScoreboardMode mode) { panel_[index].mode = mode; }
void setMult(int panel, float mult) { mult_[panel] = mult; } void setMult(int panel, float mult) { mult_[panel] = mult; }
void setName(int panel, const std::string &name) { name_[panel] = name; } void setName(int panel, const std::string &name) { name_[panel] = name; }
void setPower(float power) { power_ = power; } void setPower(float power) { power_ = power; }
void setRecordName(int panel, const std::string &record_name) { record_name_[panel] = record_name; } void setRecordName(int panel, const std::string &record_name) { record_name_[panel] = record_name; }
void setScore(int panel, int score) { score_[panel] = score; } void setScore(int panel, int score) { score_[panel] = score; }
void setSelectorPos(int panel, int pos) { selector_pos_[panel] = pos; } void setSelectorPos(int panel, int pos) { selector_pos_[panel] = pos; }
void setStage(int stage) { stage_ = stage; } void setStage(int stage) { stage_ = stage; }
private: private:
// --- Singleton --- // --- Singleton ---
static Scoreboard *scoreboard_; static Scoreboard *scoreboard_;
// --- Objetos y punteros --- // --- Objetos y punteros ---
SDL_Renderer *renderer_; // El renderizador de la ventana SDL_Renderer *renderer_; // El renderizador de la ventana
std::shared_ptr<Texture> game_power_meter_texture_; // Textura con el marcador de poder de la fase std::shared_ptr<Texture> game_power_meter_texture_; // Textura con el marcador de poder de la fase
std::unique_ptr<Sprite> power_meter_sprite_; // Sprite para el medidor de poder de la fase std::unique_ptr<Sprite> power_meter_sprite_; // Sprite para el medidor de poder de la fase
std::shared_ptr<Text> text_scoreboard_; // Fuente para el marcador del juego std::shared_ptr<Text> text_scoreboard_; // Fuente para el marcador del juego
SDL_Texture *background_ = nullptr; // Textura para dibujar el marcador SDL_Texture *background_ = nullptr; // Textura para dibujar el marcador
std::vector<SDL_Texture *> panel_texture_; // Texturas para dibujar cada panel std::vector<SDL_Texture *> panel_texture_; // Texturas para dibujar cada panel
// --- Variables de estado --- // --- Variables de estado ---
std::string name_[SCOREBOARD_MAX_PANELS] = {}; // Nombre de cada jugador std::string name_[SCOREBOARD_MAX_PANELS] = {}; // Nombre de cada jugador
std::string record_name_[SCOREBOARD_MAX_PANELS] = {}; // Nombre introducido para la tabla de records std::string record_name_[SCOREBOARD_MAX_PANELS] = {}; // Nombre introducido para la tabla de records
size_t selector_pos_[SCOREBOARD_MAX_PANELS] = {}; // Posición del selector de letra para introducir el nombre size_t selector_pos_[SCOREBOARD_MAX_PANELS] = {}; // Posición del selector de letra para introducir el nombre
int score_[SCOREBOARD_MAX_PANELS] = {}; // Puntuación de los jugadores int score_[SCOREBOARD_MAX_PANELS] = {}; // Puntuación de los jugadores
float mult_[SCOREBOARD_MAX_PANELS] = {}; // Multiplicador de los jugadores float mult_[SCOREBOARD_MAX_PANELS] = {}; // Multiplicador de los jugadores
int continue_counter_[SCOREBOARD_MAX_PANELS] = {}; // Tiempo para continuar de los jugadores int continue_counter_[SCOREBOARD_MAX_PANELS] = {}; // Tiempo para continuar de los jugadores
Panel panel_[SCOREBOARD_MAX_PANELS] = {}; // Lista con todos los paneles del marcador Panel panel_[SCOREBOARD_MAX_PANELS] = {}; // Lista con todos los paneles del marcador
int stage_ = 1; // Número de fase actual int stage_ = 1; // Número de fase actual
int hi_score_ = 0; // Máxima puntuación int hi_score_ = 0; // Máxima puntuación
float power_ = 0; // Poder actual de la fase float power_ = 0; // Poder actual de la fase
std::string hi_score_name_ = std::string(); // Nombre del jugador con la máxima puntuación std::string hi_score_name_ = std::string(); // Nombre del jugador con la máxima puntuación
Color color_ = Color(); // Color del marcador Color color_ = Color(); // Color del marcador
SDL_FRect rect_ = {0, 0, 320, 40}; // Posición y dimensiones del marcador SDL_FRect rect_ = {0, 0, 320, 40}; // Posición y dimensiones del marcador
Uint64 ticks_ = SDL_GetTicks(); // Variable donde almacenar el valor de SDL_GetTicks() Uint64 ticks_ = SDL_GetTicks(); // Variable donde almacenar el valor de SDL_GetTicks()
int time_counter_ = 0; // Contador de segundos int time_counter_ = 0; // Contador de segundos
int loop_counter_ = 0; // Contador de bucle int loop_counter_ = 0; // Contador de bucle
std::vector<Color> name_colors_; // Colores para destacar el nombre una vez introducido std::vector<Color> name_colors_; // Colores para destacar el nombre una vez introducido
// --- Variables de aspecto --- // --- Variables de aspecto ---
Color text_color1_, text_color2_; // Colores para los marcadores del texto; Color text_color1_, text_color2_; // Colores para los marcadores del texto;
// --- Puntos predefinidos para colocar elementos en los paneles --- // --- Puntos predefinidos para colocar elementos en los paneles ---
SDL_FPoint slot4_1_, slot4_2_, slot4_3_, slot4_4_; SDL_FPoint slot4_1_, slot4_2_, slot4_3_, slot4_4_;
SDL_FPoint enter_name_pos_; SDL_FPoint enter_name_pos_;
// --- Métodos internos --- // --- Métodos internos ---
void recalculateAnchors(); // Recalcula las anclas de los elementos void recalculateAnchors(); // Recalcula las anclas de los elementos
std::string updateScoreText(int num); // Transforma un valor numérico en una cadena de 7 cifras std::string updateScoreText(int num); // Transforma un valor numérico en una cadena de 7 cifras
void createBackgroundTexture(); // Crea la textura de fondo void createBackgroundTexture(); // Crea la textura de fondo
void createPanelTextures(); // Crea las texturas de los paneles void createPanelTextures(); // Crea las texturas de los paneles
void fillPanelTextures(); // Rellena los diferentes paneles del marcador void fillPanelTextures(); // Rellena los diferentes paneles del marcador
void fillBackgroundTexture(); // Rellena la textura de fondo void fillBackgroundTexture(); // Rellena la textura de fondo
void updateTimeCounter(); // Actualiza el contador void updateTimeCounter(); // Actualiza el contador
void renderSeparator(); // Dibuja la línea que separa la zona de juego del marcador void renderSeparator(); // Dibuja la línea que separa la zona de juego del marcador
void iniNameColors(); // Inicializa el vector de colores para el nombre void iniNameColors(); // Inicializa el vector de colores para el nombre
// --- Constructor y destructor privados (singleton) --- // --- Constructor y destructor privados (singleton) ---
Scoreboard(); Scoreboard();
~Scoreboard(); ~Scoreboard();
}; };
+96 -147
View File
@@ -1,21 +1,22 @@
#include "screen.h" #include "screen.h"
#include <SDL3/SDL.h> // Para SDL_SetRenderTarget, SDL_LogCategory #include <SDL3/SDL.h> // Para SDL_SetRenderTarget, SDL_LogCategory
#include <algorithm> // Para min, max #include <algorithm> // Para min, max
#include <fstream> // Para basic_ifstream, ifstream #include <fstream> // Para basic_ifstream, ifstream
#include <iterator> // Para istreambuf_iterator, operator== #include <iterator> // Para istreambuf_iterator, operator==
#include <memory> // Para allocator, shared_ptr, __shared_pt... #include <memory> // Para allocator, shared_ptr, __shared_pt...
#include <string> // Para basic_string, char_traits, operator+ #include <string> // Para basic_string, char_traits, operator+
#include "asset.h" // Para Asset #include "asset.h" // Para Asset
#include "external/jail_shader.h" // Para init, render #include "external/jail_shader.h" // Para init, render
#include "mouse.h" // Para updateCursorVisibility #include "mouse.h" // Para updateCursorVisibility
#include "notifier.h" // Para Notifier #include "notifier.h" // Para Notifier
#include "options.h" // Para VideoOptions, video, WindowOptions #include "options.h" // Para VideoOptions, video, WindowOptions
#include "param.h" // Para Param, param, ParamGame, ParamDebug #include "param.h" // Para Param, param, ParamGame, ParamDebug
#include "text.h" // Para Text, TEXT_COLOR, TEXT_STROKE #include "text.h" // Para Text, TEXT_COLOR, TEXT_STROKE
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "ui/service_menu.h" // Para ServiceMenu #include "ui/service_menu.h" // Para ServiceMenu
// Singleton // Singleton
Screen *Screen::instance_ = nullptr; Screen *Screen::instance_ = nullptr;
@@ -27,7 +28,7 @@ void Screen::init() { Screen::instance_ = new Screen(); }
void Screen::destroy() { delete Screen::instance_; } void Screen::destroy() { delete Screen::instance_; }
// Obtiene la instancia // Obtiene la instancia
Screen *Screen::get() { return Screen::instance_; } auto Screen::get() -> Screen * { return Screen::instance_; }
// Constructor // Constructor
Screen::Screen() Screen::Screen()
@@ -36,9 +37,8 @@ Screen::Screen()
game_canvas_(nullptr), game_canvas_(nullptr),
service_menu_(nullptr), service_menu_(nullptr),
notifier_(nullptr), notifier_(nullptr),
src_rect_(SDL_FRect{0, 0, static_cast<float>(param.game.width), static_cast<float>(param.game.height)}), src_rect_(SDL_FRect{0, 0, param.game.width, param.game.height}),
dst_rect_(SDL_FRect{0, 0, static_cast<float>(param.game.width), static_cast<float>(param.game.height)}) dst_rect_(SDL_FRect{0, 0, param.game.width, param.game.height}) {
{
// Arranca SDL VIDEO, crea la ventana y el renderizador // Arranca SDL VIDEO, crea la ventana y el renderizador
initSDLVideo(); initSDLVideo();
@@ -61,16 +61,14 @@ Screen::Screen()
} }
// Destructor // Destructor
Screen::~Screen() Screen::~Screen() {
{
SDL_DestroyTexture(game_canvas_); SDL_DestroyTexture(game_canvas_);
SDL_DestroyRenderer(renderer_); SDL_DestroyRenderer(renderer_);
SDL_DestroyWindow(window_); SDL_DestroyWindow(window_);
} }
// Limpia la pantalla // Limpia la pantalla
void Screen::clean(Color color) void Screen::clean(Color color) {
{
SDL_SetRenderDrawColor(renderer_, color.r, color.g, color.b, 0xFF); SDL_SetRenderDrawColor(renderer_, color.r, color.g, color.b, 0xFF);
SDL_RenderClear(renderer_); SDL_RenderClear(renderer_);
} }
@@ -79,75 +77,59 @@ void Screen::clean(Color color)
void Screen::start() { SDL_SetRenderTarget(renderer_, game_canvas_); } void Screen::start() { SDL_SetRenderTarget(renderer_, game_canvas_); }
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
void Screen::render() void Screen::render() {
{
fps_.increment(); fps_.increment();
renderOverlays(); // Renderiza todos los overlays y efectos
// Renderiza todos los overlays y efectos renderScreen(); // Renderiza el contenido del game_canvas_
renderOverlays();
// Renderiza el contenido del game_canvas_
renderScreen();
} }
// Vuelca el contenido del renderizador en pantalla exceptuando ciertas partes // Vuelca el contenido del renderizador en pantalla exceptuando ciertas partes
void Screen::coreRender() void Screen::coreRender() {
{
fps_.increment(); fps_.increment();
#ifdef DEBUG #ifdef DEBUG
renderInfo(); renderInfo();
#endif #endif
renderScreen(); renderScreen(); // Renderiza el contenido del game_canvas_
} }
// Renderiza el contenido del game_canvas_ // Renderiza el contenido del game_canvas_
void Screen::renderScreen() void Screen::renderScreen() {
{
SDL_SetRenderTarget(renderer_, nullptr); SDL_SetRenderTarget(renderer_, nullptr);
clean(); clean();
if (Options::video.shaders) if (Options::video.shaders) {
{
shader::render(); shader::render();
} } else {
else
{
SDL_RenderTexture(renderer_, game_canvas_, nullptr, nullptr); SDL_RenderTexture(renderer_, game_canvas_, nullptr, nullptr);
SDL_RenderPresent(renderer_); SDL_RenderPresent(renderer_);
} }
} }
// Establece el modo de video // Establece el modo de video
void Screen::setFullscreenMode() void Screen::setFullscreenMode() {
{
SDL_SetWindowFullscreen(window_, Options::video.fullscreen); SDL_SetWindowFullscreen(window_, Options::video.fullscreen);
} }
// Camibia entre pantalla completa y ventana // Camibia entre pantalla completa y ventana
void Screen::toggleFullscreen() void Screen::toggleFullscreen() {
{
Options::video.fullscreen = !Options::video.fullscreen; Options::video.fullscreen = !Options::video.fullscreen;
setFullscreenMode(); setFullscreenMode();
} }
// Cambia el tamaño de la ventana // Cambia el tamaño de la ventana
void Screen::setWindowZoom(int zoom) void Screen::setWindowZoom(int zoom) {
{
Options::window.size = zoom; Options::window.size = zoom;
adjustWindowSize(); adjustWindowSize();
} }
// Reduce el tamaño de la ventana // Reduce el tamaño de la ventana
bool Screen::decWindowSize() auto Screen::decWindowSize() -> bool {
{ if (!Options::video.fullscreen) {
if (!Options::video.fullscreen)
{
const int PREVIOUS_ZOOM = Options::window.size; const int PREVIOUS_ZOOM = Options::window.size;
--Options::window.size; --Options::window.size;
Options::window.size = std::max(Options::window.size, 1); Options::window.size = std::max(Options::window.size, 1);
if (Options::window.size != PREVIOUS_ZOOM) if (Options::window.size != PREVIOUS_ZOOM) {
{
adjustWindowSize(); adjustWindowSize();
return true; return true;
} }
@@ -157,16 +139,13 @@ bool Screen::decWindowSize()
} }
// Aumenta el tamaño de la ventana // Aumenta el tamaño de la ventana
bool Screen::incWindowSize() auto Screen::incWindowSize() -> bool {
{ if (!Options::video.fullscreen) {
if (!Options::video.fullscreen)
{
const int PREVIOUS_ZOOM = Options::window.size; const int PREVIOUS_ZOOM = Options::window.size;
++Options::window.size; ++Options::window.size;
Options::window.size = std::min(Options::window.size, Options::window.max_size); Options::window.size = std::min(Options::window.size, Options::window.max_size);
if (Options::window.size != PREVIOUS_ZOOM) if (Options::window.size != PREVIOUS_ZOOM) {
{
adjustWindowSize(); adjustWindowSize();
return true; return true;
} }
@@ -176,45 +155,41 @@ bool Screen::incWindowSize()
} }
// Actualiza la lógica de la clase // Actualiza la lógica de la clase
void Screen::update() void Screen::update() {
{
fps_.calculate(SDL_GetTicks()); fps_.calculate(SDL_GetTicks());
shake_effect_.update(src_rect_, dst_rect_); shake_effect_.update(src_rect_, dst_rect_);
flash_effect_.update(); flash_effect_.update();
if (service_menu_) if (service_menu_ != nullptr) {
service_menu_->update(); service_menu_->update();
if (notifier_) }
if (notifier_ != nullptr) {
notifier_->update(); notifier_->update();
}
Mouse::updateCursorVisibility(); Mouse::updateCursorVisibility();
} }
// Actualiza los elementos mínimos // Actualiza los elementos mínimos
void Screen::coreUpdate() void Screen::coreUpdate() {
{
fps_.calculate(SDL_GetTicks()); fps_.calculate(SDL_GetTicks());
Mouse::updateCursorVisibility(); Mouse::updateCursorVisibility();
} }
// Actualiza y dibuja el efecto de flash en la pantalla // Actualiza y dibuja el efecto de flash en la pantalla
void Screen::renderFlash() void Screen::renderFlash() {
{ if (flash_effect_.isRendarable()) {
if (flash_effect_.isRendarable())
{
SDL_SetRenderDrawColor(renderer_, flash_effect_.color.r, flash_effect_.color.g, flash_effect_.color.b, 0xFF); SDL_SetRenderDrawColor(renderer_, flash_effect_.color.r, flash_effect_.color.g, flash_effect_.color.b, 0xFF);
SDL_RenderClear(renderer_); SDL_RenderClear(renderer_);
} }
} }
// Aplica el efecto de agitar la pantalla // Aplica el efecto de agitar la pantalla
void Screen::renderShake() void Screen::renderShake() {
{ if (shake_effect_.enabled) {
if (shake_effect_.enabled)
{
// Guarda el renderizador actual para dejarlo despues como estaba // Guarda el renderizador actual para dejarlo despues como estaba
auto current_target = SDL_GetRenderTarget(renderer_); auto *current_target = SDL_GetRenderTarget(renderer_);
// Crea una textura temporal // Crea una textura temporal
auto temp_texture = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height); auto *temp_texture = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);
// Vuelca game_canvas_ a la textura temporal // Vuelca game_canvas_ a la textura temporal
SDL_SetRenderTarget(renderer_, temp_texture); SDL_SetRenderTarget(renderer_, temp_texture);
@@ -233,10 +208,8 @@ void Screen::renderShake()
} }
#ifdef DEBUG #ifdef DEBUG
// Muestra información por pantalla // Muestra información por pantalla
void Screen::renderInfo() void Screen::renderInfo() {
{ if (debug_info_.show) {
if (debug_info_.show)
{
// Resolution // Resolution
debug_info_.text->writeDX(TEXT_COLOR | TEXT_STROKE, param.game.width - debug_info_.text->lenght(Options::video.info) - 2, 1, Options::video.info, 1, param.debug.color, 1, param.debug.color.darken(150)); debug_info_.text->writeDX(TEXT_COLOR | TEXT_STROKE, param.game.width - debug_info_.text->lenght(Options::video.info) - 2, 1, Options::video.info, 1, param.debug.color, 1, param.debug.color.darken(150));
@@ -247,10 +220,8 @@ void Screen::renderInfo()
} }
#endif #endif
// Carga el contenido del archivo GLSL // Carga el contenido del archivo GLSL
void Screen::loadShaders() void Screen::loadShaders() {
{ if (shader_source_.empty()) {
if (shader_source_.empty())
{
const std::string GLSL_FILE = param.game.game_area.rect.h == 256 ? "crtpi_256.glsl" : "crtpi_240.glsl"; const std::string GLSL_FILE = param.game.game_area.rect.h == 256 ? "crtpi_256.glsl" : "crtpi_240.glsl";
std::ifstream f(Asset::get()->get(GLSL_FILE).c_str()); std::ifstream f(Asset::get()->get(GLSL_FILE).c_str());
shader_source_ = std::string((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>()); shader_source_ = std::string((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
@@ -258,32 +229,30 @@ void Screen::loadShaders()
} }
// Inicializa los shaders // Inicializa los shaders
void Screen::initShaders() void Screen::initShaders() {
{ if (Options::video.shaders) {
if (Options::video.shaders)
{
loadShaders(); loadShaders();
shader::init(window_, game_canvas_, shader_source_); shader::init(window_, game_canvas_, shader_source_);
} }
} }
// Calcula el tamaño de la ventana // Calcula el tamaño de la ventana
void Screen::adjustWindowSize() void Screen::adjustWindowSize() {
{ if (!Options::video.fullscreen) {
if (!Options::video.fullscreen)
{
// Establece el nuevo tamaño // Establece el nuevo tamaño
const int WIDTH = param.game.width * Options::window.size; const int WIDTH = param.game.width * Options::window.size;
const int HEIGHT = param.game.height * Options::window.size; const int HEIGHT = param.game.height * Options::window.size;
int old_width, old_height; int old_width;
int old_height;
SDL_GetWindowSize(window_, &old_width, &old_height); SDL_GetWindowSize(window_, &old_width, &old_height);
int old_pos_x, old_pos_y; int old_pos_x;
int old_pos_y;
SDL_GetWindowPosition(window_, &old_pos_x, &old_pos_y); SDL_GetWindowPosition(window_, &old_pos_x, &old_pos_y);
const int NEW_POS_X = old_pos_x + (old_width - WIDTH) / 2; const int NEW_POS_X = old_pos_x + ((old_width - WIDTH) / 2);
const int NEW_POS_Y = old_pos_y + (old_height - HEIGHT) / 2; const int NEW_POS_Y = old_pos_y + ((old_height - HEIGHT) / 2);
SDL_SetWindowPosition(window_, std::max(NEW_POS_X, WINDOWS_DECORATIONS_), std::max(NEW_POS_Y, 0)); SDL_SetWindowPosition(window_, std::max(NEW_POS_X, WINDOWS_DECORATIONS_), std::max(NEW_POS_Y, 0));
SDL_SetWindowSize(window_, WIDTH, HEIGHT); SDL_SetWindowSize(window_, WIDTH, HEIGHT);
@@ -291,8 +260,7 @@ void Screen::adjustWindowSize()
} }
// Renderiza todos los overlays y efectos // Renderiza todos los overlays y efectos
void Screen::renderOverlays() void Screen::renderOverlays() {
{
// Dibuja efectos y elementos sobre el game_canvas_ // Dibuja efectos y elementos sobre el game_canvas_
renderShake(); renderShake();
renderFlash(); renderFlash();
@@ -305,24 +273,20 @@ void Screen::renderOverlays()
} }
// Atenua la pantalla // Atenua la pantalla
void Screen::renderAttenuate() void Screen::renderAttenuate() {
{ if (attenuate_effect_) {
if (attenuate_effect_)
{
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 64); SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 64);
SDL_RenderFillRect(renderer_, nullptr); SDL_RenderFillRect(renderer_, nullptr);
} }
} }
// Arranca SDL VIDEO y crea la ventana // Arranca SDL VIDEO y crea la ventana
bool Screen::initSDLVideo() auto Screen::initSDLVideo() -> bool {
{
// Inicializar SDL // Inicializar SDL
if (!SDL_Init(SDL_INIT_VIDEO)) if (!SDL_Init(SDL_INIT_VIDEO)) {
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"FATAL: Failed to initialize SDL_VIDEO! SDL Error: %s", "FATAL: Failed to initialize SDL_VIDEO! SDL Error: %s",
SDL_GetError()); SDL_GetError());
return false; return false;
} }
@@ -330,16 +294,14 @@ bool Screen::initSDLVideo()
getDisplayInfo(); getDisplayInfo();
// Configurar hint para OpenGL // Configurar hint para OpenGL
if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl")) if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl")) {
{
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"Warning: Failed to set OpenGL hint!"); "Warning: Failed to set OpenGL hint!");
} }
// Crear ventana // Crear ventana
SDL_WindowFlags window_flags = SDL_WINDOW_OPENGL; SDL_WindowFlags window_flags = SDL_WINDOW_OPENGL;
if (Options::video.fullscreen) if (Options::video.fullscreen) {
{
window_flags |= SDL_WINDOW_FULLSCREEN; window_flags |= SDL_WINDOW_FULLSCREEN;
} }
window_ = SDL_CreateWindow( window_ = SDL_CreateWindow(
@@ -348,22 +310,20 @@ bool Screen::initSDLVideo()
param.game.height * Options::window.size, param.game.height * Options::window.size,
window_flags); window_flags);
if (!window_) if (window_ == nullptr) {
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"FATAL: Failed to create window! SDL Error: %s", "FATAL: Failed to create window! SDL Error: %s",
SDL_GetError()); SDL_GetError());
SDL_Quit(); SDL_Quit();
return false; return false;
} }
// Crear renderer // Crear renderer
renderer_ = SDL_CreateRenderer(window_, nullptr); renderer_ = SDL_CreateRenderer(window_, nullptr);
if (!renderer_) if (renderer_ == nullptr) {
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"FATAL: Failed to create renderer! SDL Error: %s", "FATAL: Failed to create renderer! SDL Error: %s",
SDL_GetError()); SDL_GetError());
SDL_DestroyWindow(window_); SDL_DestroyWindow(window_);
window_ = nullptr; window_ = nullptr;
SDL_Quit(); SDL_Quit();
@@ -382,39 +342,35 @@ bool Screen::initSDLVideo()
} }
// Obtiene información sobre la pantalla // Obtiene información sobre la pantalla
void Screen::getDisplayInfo() void Screen::getDisplayInfo() {
{ int i;
int i, num_displays = 0; int num_displays = 0;
SDL_DisplayID *displays = SDL_GetDisplays(&num_displays); SDL_DisplayID *displays = SDL_GetDisplays(&num_displays);
if (displays) if (displays != nullptr) {
{ for (i = 0; i < num_displays; ++i) {
for (i = 0; i < num_displays; ++i)
{
SDL_DisplayID instance_id = displays[i]; SDL_DisplayID instance_id = displays[i];
const char *name = SDL_GetDisplayName(instance_id); const char *name = SDL_GetDisplayName(instance_id);
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Display %" SDL_PRIu32 ": %s", instance_id, name ? name : "Unknown"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Display %" SDL_PRIu32 ": %s", instance_id, (name != nullptr) ? name : "Unknown");
} }
auto DM = SDL_GetCurrentDisplayMode(displays[0]); const auto *dm = SDL_GetCurrentDisplayMode(displays[0]);
// Calcula el máximo factor de zoom que se puede aplicar a la pantalla // Calcula el máximo factor de zoom que se puede aplicar a la pantalla
Options::window.max_size = std::min(DM->w / param.game.width, DM->h / param.game.height); Options::window.max_size = std::min(dm->w / param.game.width, dm->h / param.game.height);
Options::window.size = std::min(Options::window.size, Options::window.max_size); Options::window.size = std::min(Options::window.size, Options::window.max_size);
// Muestra información sobre el tamaño de la pantalla y de la ventana de juego // Muestra información sobre el tamaño de la pantalla y de la ventana de juego
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Current display mode: %dx%d @ %dHz", SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Current display mode: %dx%d @ %dHz", static_cast<int>(dm->w), static_cast<int>(dm->h), static_cast<int>(dm->refresh_rate));
static_cast<int>(DM->w), static_cast<int>(DM->h), static_cast<int>(DM->refresh_rate));
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Window resolution: %dx%d x%d", SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Window resolution: %dx%d x%d", static_cast<int>(param.game.width), static_cast<int>(param.game.height), Options::window.size);
static_cast<int>(param.game.width), static_cast<int>(param.game.height), Options::window.size);
Options::video.info = std::to_string(static_cast<int>(DM->w)) + "x" + Options::video.info = std::to_string(static_cast<int>(dm->w)) + "x" +
std::to_string(static_cast<int>(DM->h)) + " @ " + std::to_string(static_cast<int>(dm->h)) + " @ " +
std::to_string(static_cast<int>(DM->refresh_rate)) + " Hz"; std::to_string(static_cast<int>(dm->refresh_rate)) + " Hz";
// Calcula el máximo factor de zoom que se puede aplicar a la pantalla // Calcula el máximo factor de zoom que se puede aplicar a la pantalla
const int MAX_ZOOM = std::min(DM->w / param.game.width, (DM->h - WINDOWS_DECORATIONS_) / param.game.height); const int MAX_ZOOM = std::min(dm->w / param.game.width, (dm->h - WINDOWS_DECORATIONS_) / param.game.height);
// Normaliza los valores de zoom // Normaliza los valores de zoom
Options::window.size = std::min(Options::window.size, MAX_ZOOM); Options::window.size = std::min(Options::window.size, MAX_ZOOM);
@@ -424,43 +380,37 @@ void Screen::getDisplayInfo()
} }
// Alterna entre activar y desactivar los shaders // Alterna entre activar y desactivar los shaders
void Screen::toggleShaders() void Screen::toggleShaders() {
{
Options::video.shaders = !Options::video.shaders; Options::video.shaders = !Options::video.shaders;
initShaders(); initShaders();
} }
// Alterna entre activar y desactivar el escalado entero // Alterna entre activar y desactivar el escalado entero
void Screen::toggleIntegerScale() void Screen::toggleIntegerScale() {
{
Options::video.integer_scale = !Options::video.integer_scale; Options::video.integer_scale = !Options::video.integer_scale;
SDL_SetRenderLogicalPresentation(renderer_, param.game.width, param.game.height, Options::video.integer_scale ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_LETTERBOX); SDL_SetRenderLogicalPresentation(renderer_, param.game.width, param.game.height, Options::video.integer_scale ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_LETTERBOX);
} }
// Alterna entre activar y desactivar el V-Sync // Alterna entre activar y desactivar el V-Sync
void Screen::toggleVSync() void Screen::toggleVSync() {
{
Options::video.v_sync = !Options::video.v_sync; Options::video.v_sync = !Options::video.v_sync;
SDL_SetRenderVSync(renderer_, Options::video.v_sync ? 1 : SDL_RENDERER_VSYNC_DISABLED); SDL_SetRenderVSync(renderer_, Options::video.v_sync ? 1 : SDL_RENDERER_VSYNC_DISABLED);
} }
// Establece el estado del V-Sync // Establece el estado del V-Sync
void Screen::setVSync(bool enabled) void Screen::setVSync(bool enabled) {
{
Options::video.v_sync = enabled; Options::video.v_sync = enabled;
SDL_SetRenderVSync(renderer_, enabled ? 1 : SDL_RENDERER_VSYNC_DISABLED); SDL_SetRenderVSync(renderer_, enabled ? 1 : SDL_RENDERER_VSYNC_DISABLED);
} }
// Obtiene los punteros a los singletones // Obtiene los punteros a los singletones
void Screen::getSingletons() void Screen::getSingletons() {
{
service_menu_ = ServiceMenu::get(); service_menu_ = ServiceMenu::get();
notifier_ = Notifier::get(); notifier_ = Notifier::get();
} }
// Aplica los valores de las opciones // Aplica los valores de las opciones
void Screen::applySettings() void Screen::applySettings() {
{
SDL_SetRenderVSync(renderer_, Options::video.v_sync ? 1 : SDL_RENDERER_VSYNC_DISABLED); SDL_SetRenderVSync(renderer_, Options::video.v_sync ? 1 : SDL_RENDERER_VSYNC_DISABLED);
SDL_SetRenderLogicalPresentation(Screen::get()->getRenderer(), param.game.width, param.game.height, Options::video.integer_scale ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_LETTERBOX); SDL_SetRenderLogicalPresentation(Screen::get()->getRenderer(), param.game.width, param.game.height, Options::video.integer_scale ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_LETTERBOX);
setFullscreenMode(); setFullscreenMode();
@@ -468,8 +418,7 @@ void Screen::applySettings()
} }
// Crea el objeto de texto // Crea el objeto de texto
void Screen::createText() void Screen::createText() {
{
auto texture = std::make_shared<Texture>(getRenderer(), Asset::get()->get("aseprite.png")); auto texture = std::make_shared<Texture>(getRenderer(), Asset::get()->get("aseprite.png"));
text_ = std::make_shared<Text>(texture, Asset::get()->get("aseprite.txt")); text_ = std::make_shared<Text>(texture, Asset::get()->get("aseprite.txt"));
} }
+169 -183
View File
@@ -1,225 +1,211 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_FRect, SDL_HideWindow, SDL_Renderer, SDL_ShowWindow, Uint32, SDL_Texture, SDL_Window #include <SDL3/SDL.h> // Para SDL_FRect, SDL_HideWindow, SDL_Renderer, SDL_ShowWindow, Uint32, SDL_Texture, SDL_Window
#include <memory> // Para shared_ptr
#include <string> // Para basic_string, string
#include "options.h" // Para VideoOptions, video #include <memory> // Para shared_ptr
#include "utils.h" // Para Color #include <string> // Para basic_string, string
#include "options.h" // Para VideoOptions, video
#include "utils.h" // Para Color
class Notifier; class Notifier;
class ServiceMenu; class ServiceMenu;
class Text; class Text;
// Clase Screen: gestiona la ventana, el renderizador y los efectos visuales globales // Clase Screen: gestiona la ventana, el renderizador y los efectos visuales globales
class Screen class Screen {
{ public:
public: // --- Métodos de singleton ---
// --- Métodos de singleton --- static void init(); // Inicializa el objeto Screen
static void init(); // Inicializa el objeto Screen static void destroy(); // Libera el objeto Screen
static void destroy(); // Libera el objeto Screen static Screen *get(); // Obtiene el puntero al objeto Screen
static Screen *get(); // Obtiene el puntero al objeto Screen
// --- Métodos principales --- // --- Métodos principales ---
void update(); // Actualiza la lógica de la clase void update(); // Actualiza la lógica de la clase
void coreUpdate(); // Actualiza los elementos mínimos void coreUpdate(); // Actualiza los elementos mínimos
void clean(Color color = Color(0x00, 0x00, 0x00)); // Limpia la pantalla void clean(Color color = Color(0x00, 0x00, 0x00)); // Limpia la pantalla
void start(); // Prepara para empezar a dibujar en la textura de juego void start(); // Prepara para empezar a dibujar en la textura de juego
void render(); // Vuelca el contenido del renderizador en pantalla void render(); // Vuelca el contenido del renderizador en pantalla
void coreRender(); // Vuelca el contenido del renderizador en pantalla exceptuando ciertas partes void coreRender(); // Vuelca el contenido del renderizador en pantalla exceptuando ciertas partes
// --- Configuración de ventana y render --- // --- Configuración de ventana y render ---
void setFullscreenMode(); // Establece el modo de pantalla completa void setFullscreenMode(); // Establece el modo de pantalla completa
void toggleFullscreen(); // Cambia entre pantalla completa y ventana void toggleFullscreen(); // Cambia entre pantalla completa y ventana
void setWindowZoom(int size); // Cambia el tamaño de la ventana void setWindowZoom(int size); // Cambia el tamaño de la ventana
bool decWindowSize(); // Reduce el tamaño de la ventana bool decWindowSize(); // Reduce el tamaño de la ventana
bool incWindowSize(); // Aumenta el tamaño de la ventana bool incWindowSize(); // Aumenta el tamaño de la ventana
void applySettings(); // Aplica los valores de las opciones void applySettings(); // Aplica los valores de las opciones
void initShaders(); // Inicializa los shaders void initShaders(); // Inicializa los shaders
// --- Efectos visuales --- // --- Efectos visuales ---
void shake(int desp = 2, int delay = 3, int lenght = 8) { shake_effect_.enable(src_rect_, dst_rect_, desp, delay, lenght); } // Agita la pantalla void shake(int desp = 2, int delay = 3, int lenght = 8) { shake_effect_.enable(src_rect_, dst_rect_, desp, delay, lenght); } // Agita la pantalla
void flash(Color color, int lenght = 10, int delay = 0) { flash_effect_ = FlashEffect(true, lenght, delay, color); } // Pone la pantalla de color void flash(Color color, int lenght = 10, int delay = 0) { flash_effect_ = FlashEffect(true, lenght, delay, color); } // Pone la pantalla de color
void toggleShaders(); // Alterna entre activar y desactivar los shaders void toggleShaders(); // Alterna entre activar y desactivar los shaders
void toggleIntegerScale(); // Alterna entre activar y desactivar el escalado entero void toggleIntegerScale(); // Alterna entre activar y desactivar el escalado entero
void toggleVSync(); // Alterna entre activar y desactivar el V-Sync void toggleVSync(); // Alterna entre activar y desactivar el V-Sync
void setVSync(bool enabled); // Establece el estado del V-Sync void setVSync(bool enabled); // Establece el estado del V-Sync
void attenuate(bool value) { attenuate_effect_ = value; } // Atenúa la pantalla void attenuate(bool value) { attenuate_effect_ = value; } // Atenúa la pantalla
// --- Getters --- // --- Getters ---
SDL_Renderer *getRenderer() { return renderer_; } // Obtiene el renderizador SDL_Renderer *getRenderer() { return renderer_; } // Obtiene el renderizador
void show() { SDL_ShowWindow(window_); } // Muestra la ventana void show() { SDL_ShowWindow(window_); } // Muestra la ventana
void hide() { SDL_HideWindow(window_); } // Oculta la ventana void hide() { SDL_HideWindow(window_); } // Oculta la ventana
void getSingletons(); // Obtiene los punteros a los singletones void getSingletons(); // Obtiene los punteros a los singletones
bool getVSync() const { return Options::video.v_sync; } // Obtiene el valor de V-Sync bool getVSync() const { return Options::video.v_sync; } // Obtiene el valor de V-Sync
std::shared_ptr<Text> getText() const { return text_; } // Obtiene el puntero al texto de Screen std::shared_ptr<Text> getText() const { return text_; } // Obtiene el puntero al texto de Screen
#ifdef DEBUG #ifdef DEBUG
// --- Debug --- // --- Debug ---
void toggleDebugInfo() { debug_info_.show = !debug_info_.show; } void toggleDebugInfo() { debug_info_.show = !debug_info_.show; }
void setDebugInfoEnabled(bool value) { debug_info_.show = value; } void setDebugInfoEnabled(bool value) { debug_info_.show = value; }
#endif #endif
private: private:
// --- Constantes --- // --- Constantes ---
static constexpr int WINDOWS_DECORATIONS_ = 35; static constexpr int WINDOWS_DECORATIONS_ = 35;
// --- Estructuras internas --- // --- Estructuras internas ---
struct FPS struct FPS {
{ Uint32 ticks; // Tiempo en milisegundos desde que se comenzó a contar.
Uint32 ticks; // Tiempo en milisegundos desde que se comenzó a contar. int frameCount; // Número acumulado de frames en el intervalo.
int frameCount; // Número acumulado de frames en el intervalo. int lastValue; // Número de frames calculado en el último segundo.
int lastValue; // Número de frames calculado en el último segundo.
FPS() : ticks(0), frameCount(0), lastValue(0) {} FPS() : ticks(0), frameCount(0), lastValue(0) {}
void increment() { frameCount++; } void increment() { frameCount++; }
int calculate(Uint32 currentTicks) int calculate(Uint32 currentTicks) {
{ if (currentTicks - ticks >= 1000) {
if (currentTicks - ticks >= 1000) lastValue = frameCount;
{ frameCount = 0;
lastValue = frameCount; ticks = currentTicks;
frameCount = 0; }
ticks = currentTicks; return lastValue;
} }
return lastValue; };
}
};
// Efecto de flash en pantalla: pinta la pantalla de un color durante unos frames // Efecto de flash en pantalla: pinta la pantalla de un color durante unos frames
struct FlashEffect struct FlashEffect {
{ bool enabled; // Indica si el efecto está activo
bool enabled; // Indica si el efecto está activo int lenght; // Duración total del efecto en frames
int lenght; // Duración total del efecto en frames int delay; // Retraso antes de mostrar el flash
int delay; // Retraso antes de mostrar el flash int counter; // Contador de frames restantes
int counter; // Contador de frames restantes Color color; // Color del flash
Color color; // Color del flash
explicit FlashEffect(bool enabled = false, int lenght = 0, int delay = 0, Color color = Color(0xFF, 0xFF, 0xFF)) explicit FlashEffect(bool enabled = false, int lenght = 0, int delay = 0, Color color = Color(0xFF, 0xFF, 0xFF))
: enabled(enabled), lenght(lenght), delay(delay), counter(lenght), color(color) {} : enabled(enabled), lenght(lenght), delay(delay), counter(lenght), color(color) {}
void update() { (enabled && counter > 0) ? counter-- : enabled = false; } void update() { (enabled && counter > 0) ? counter-- : enabled = false; }
bool isRendarable() { return enabled && counter < lenght - delay; } bool isRendarable() { return enabled && counter < lenght - delay; }
}; };
// Efecto de sacudida/agitación de pantalla: mueve la imagen para simular un temblor // Efecto de sacudida/agitación de pantalla: mueve la imagen para simular un temblor
struct ShakeEffect struct ShakeEffect {
{ int desp; // Desplazamiento máximo de la sacudida (en píxeles)
int desp; // Desplazamiento máximo de la sacudida (en píxeles) int delay; // Frames entre cada movimiento de sacudida
int delay; // Frames entre cada movimiento de sacudida int counter; // Contador de frames para el siguiente movimiento
int counter; // Contador de frames para el siguiente movimiento int lenght; // Duración total del efecto en frames
int lenght; // Duración total del efecto en frames int remaining; // Frames restantes de sacudida
int remaining; // Frames restantes de sacudida int original_pos; // Posición original de la imagen (x)
int original_pos; // Posición original de la imagen (x) int original_width; // Ancho original de la imagen
int original_width; // Ancho original de la imagen bool enabled; // Indica si el efecto está activo
bool enabled; // Indica si el efecto está activo
explicit ShakeEffect(bool en = false, int dp = 2, int dl = 3, int cnt = 0, int len = 8, int rem = 0, int origPos = 0, int origWidth = 800) explicit ShakeEffect(bool en = false, int dp = 2, int dl = 3, int cnt = 0, int len = 8, int rem = 0, int origPos = 0, int origWidth = 800)
: desp(dp), delay(dl), counter(cnt), lenght(len), remaining(rem), original_pos(origPos), original_width(origWidth), enabled(en) {} : desp(dp), delay(dl), counter(cnt), lenght(len), remaining(rem), original_pos(origPos), original_width(origWidth), enabled(en) {}
// Activa el efecto de sacudida y guarda la posición y tamaño originales // Activa el efecto de sacudida y guarda la posición y tamaño originales
void enable(SDL_FRect &src_rect, SDL_FRect &dst_rect, int new_desp = -1, int new_delay = -1, int new_lenght = -1) void enable(SDL_FRect &src_rect, SDL_FRect &dst_rect, int new_desp = -1, int new_delay = -1, int new_lenght = -1) {
{ if (!enabled) {
if (!enabled) enabled = true;
{ original_pos = src_rect.x;
enabled = true; original_width = src_rect.w;
original_pos = src_rect.x;
original_width = src_rect.w;
// Usar nuevos valores si se proporcionan, sino mantener los actuales // Usar nuevos valores si se proporcionan, sino mantener los actuales
if (new_desp != -1) if (new_desp != -1)
desp = new_desp; desp = new_desp;
if (new_delay != -1) if (new_delay != -1)
delay = new_delay; delay = new_delay;
if (new_lenght != -1) if (new_lenght != -1)
lenght = new_lenght; lenght = new_lenght;
src_rect.w -= desp; src_rect.w -= desp;
dst_rect.w = src_rect.w; dst_rect.w = src_rect.w;
} }
remaining = lenght; remaining = lenght;
counter = delay; counter = delay;
} }
// Actualiza el estado del efecto de sacudida // Actualiza el estado del efecto de sacudida
void update(SDL_FRect &src_rect, SDL_FRect &dst_rect) void update(SDL_FRect &src_rect, SDL_FRect &dst_rect) {
{ if (enabled) {
if (enabled) if (counter > 0) {
{ counter--;
if (counter > 0) } else {
{ counter = delay;
counter--; const auto SRC_DESP = (remaining % 2 == 0) ? 0 : desp;
} const auto DST_DESP = (remaining % 2 == 1) ? 0 : desp;
else src_rect.x = original_pos + SRC_DESP;
{ dst_rect.x = original_pos + DST_DESP;
counter = delay; remaining--;
const auto SRC_DESP = (remaining % 2 == 0) ? 0 : desp; if (remaining == -1) {
const auto DST_DESP = (remaining % 2 == 1) ? 0 : desp; enabled = false;
src_rect.x = original_pos + SRC_DESP; src_rect.x = original_pos;
dst_rect.x = original_pos + DST_DESP; src_rect.w = original_width;
remaining--; dst_rect.x = original_pos;
if (remaining == -1) dst_rect.w = original_width;
{ }
enabled = false; }
src_rect.x = original_pos; }
src_rect.w = original_width; }
dst_rect.x = original_pos;
dst_rect.w = original_width;
}
}
}
}
bool isEnabled() const { return enabled; } bool isEnabled() const { return enabled; }
}; };
#ifdef DEBUG #ifdef DEBUG
struct Debug struct Debug {
{ std::shared_ptr<Text> text;
std::shared_ptr<Text> text; bool show = false;
bool show = false; };
};
#endif #endif
// --- Singleton --- // --- Singleton ---
static Screen *instance_; static Screen *instance_;
// --- Objetos y punteros --- // --- Objetos y punteros ---
SDL_Window *window_; // Ventana de la aplicación SDL_Window *window_; // Ventana de la aplicación
SDL_Renderer *renderer_; // El renderizador de la ventana SDL_Renderer *renderer_; // El renderizador de la ventana
SDL_Texture *game_canvas_; // Textura donde se dibuja todo antes de volcarse al renderizador SDL_Texture *game_canvas_; // Textura donde se dibuja todo antes de volcarse al renderizador
ServiceMenu *service_menu_; // Objeto para mostrar el menú de servicio ServiceMenu *service_menu_; // Objeto para mostrar el menú de servicio
Notifier *notifier_; // Objeto para mostrar las notificaciones por pantalla Notifier *notifier_; // Objeto para mostrar las notificaciones por pantalla
// --- Variables de estado --- // --- Variables de estado ---
SDL_FRect src_rect_; // Coordenadas de origen para dibujar la textura del juego SDL_FRect src_rect_; // Coordenadas de origen para dibujar la textura del juego
SDL_FRect dst_rect_; // Coordenadas destino para dibujar la textura del juego SDL_FRect dst_rect_; // Coordenadas destino para dibujar la textura del juego
FPS fps_; // Gestión de frames por segundo FPS fps_; // Gestión de frames por segundo
std::string shader_source_; // Almacena el contenido del archivo GLSL std::string shader_source_; // Almacena el contenido del archivo GLSL
FlashEffect flash_effect_; // Efecto de flash en pantalla FlashEffect flash_effect_; // Efecto de flash en pantalla
ShakeEffect shake_effect_; // Efecto de agitar la pantalla ShakeEffect shake_effect_; // Efecto de agitar la pantalla
bool attenuate_effect_ = false; // Indica si la pantalla ha de estar atenuada bool attenuate_effect_ = false; // Indica si la pantalla ha de estar atenuada
#ifdef DEBUG #ifdef DEBUG
Debug debug_info_; // Información de debug Debug debug_info_; // Información de debug
#endif #endif
// --- Texto --- // --- Texto ---
std::shared_ptr<Text> text_; // Objeto para escribir texto en pantalla std::shared_ptr<Text> text_; // Objeto para escribir texto en pantalla
// --- Métodos internos --- // --- Métodos internos ---
bool initSDLVideo(); // Arranca SDL VIDEO y crea la ventana bool initSDLVideo(); // Arranca SDL VIDEO y crea la ventana
void renderFlash(); // Dibuja el efecto de flash en la pantalla void renderFlash(); // Dibuja el efecto de flash en la pantalla
void renderShake(); // Aplica el efecto de agitar la pantalla void renderShake(); // Aplica el efecto de agitar la pantalla
void renderInfo(); // Muestra información por pantalla void renderInfo(); // Muestra información por pantalla
void renderScreen(); // Selecciona y ejecuta el método de renderizado adecuado void renderScreen(); // Selecciona y ejecuta el método de renderizado adecuado
void loadShaders(); // Carga el contenido del archivo GLSL void loadShaders(); // Carga el contenido del archivo GLSL
void adjustWindowSize(); // Calcula el tamaño de la ventana void adjustWindowSize(); // Calcula el tamaño de la ventana
void getDisplayInfo(); // Obtiene información sobre la pantalla static void getDisplayInfo(); // Obtiene información sobre la pantalla
void renderOverlays(); // Renderiza todos los overlays y efectos void renderOverlays(); // Renderiza todos los overlays y efectos
void renderAttenuate(); // Atenúa la pantalla void renderAttenuate(); // Atenúa la pantalla
void createText(); // Crea el objeto de texto void createText(); // Crea el objeto de texto
// --- Constructores y destructor --- // --- Constructores y destructor ---
Screen(); Screen();
~Screen(); ~Screen();
}; };
+5 -6
View File
@@ -1,8 +1,7 @@
#include "section.h" #include "section.h"
namespace Section namespace Section {
{ Name name;
Name name; Options options;
Options options; AttractMode attract_mode;
AttractMode attract_mode; } // namespace Section
}
+37 -41
View File
@@ -6,47 +6,43 @@
Proporciona variables globales para gestionar el flujo entre secciones. Proporciona variables globales para gestionar el flujo entre secciones.
*/ */
namespace Section namespace Section {
{ // --- Enumeraciones de secciones del programa ---
// --- Enumeraciones de secciones del programa --- enum class Name {
enum class Name RESET, // Inicialización
{ LOGO, // Pantalla de logo
RESET, // Inicialización INTRO, // Introducción
LOGO, // Pantalla de logo TITLE, // Pantalla de título/menú principal
INTRO, // Introducción GAME, // Juego principal
TITLE, // Pantalla de título/menú principal HI_SCORE_TABLE, // Tabla de récords
GAME, // Juego principal GAME_DEMO, // Modo demo
HI_SCORE_TABLE, // Tabla de récords INSTRUCTIONS, // Instrucciones
GAME_DEMO, // Modo demo CREDITS, // Créditos
INSTRUCTIONS, // Instrucciones QUIT, // Salir del juego
CREDITS, // Créditos };
QUIT, // Salir del juego
};
// --- Opciones para la sección actual --- // --- Opciones para la sección actual ---
enum class Options enum class Options {
{ GAME_PLAY_1P, // Iniciar el juego con el jugador 1
GAME_PLAY_1P, // Iniciar el juego con el jugador 1 GAME_PLAY_2P, // Iniciar el juego con el jugador 2
GAME_PLAY_2P, // Iniciar el juego con el jugador 2 GAME_PLAY_BOTH, // Iniciar el juego con los dos jugadores
GAME_PLAY_BOTH, // Iniciar el juego con los dos jugadores TITLE_TIME_OUT, // Timeout en el título
TITLE_TIME_OUT, // Timeout en el título TITLE_1, // Opción 1 en el título
TITLE_1, // Opción 1 en el título TITLE_2, // Opción 2 en el título
TITLE_2, // Opción 2 en el título RELOAD, // Recargar sección
RELOAD, // Recargar sección HI_SCORE_AFTER_PLAYING, // Mostrar récord tras jugar
HI_SCORE_AFTER_PLAYING, // Mostrar récord tras jugar SHUTDOWN, // Apagar el sistema
SHUTDOWN, // Apagar el sistema NONE, // Sin opción
NONE, // Sin opción };
};
// --- Modos para el Attract Mode --- // --- Modos para el Attract Mode ---
enum class AttractMode enum class AttractMode {
{ TITLE_TO_DEMO, // Pasar de título a demo
TITLE_TO_DEMO, // Pasar de título a demo TITLE_TO_LOGO, // Pasar de título a logo
TITLE_TO_LOGO, // Pasar de título a logo };
};
// --- Variables globales de estado --- // --- Variables globales de estado ---
extern Name name; // Sección actual extern Name name; // Sección actual
extern Options options; // Opción seleccionada en la sección extern Options options; // Opción seleccionada en la sección
extern AttractMode attract_mode; // Estado del Attract Mode extern AttractMode attract_mode; // Estado del Attract Mode
} } // namespace Section
+83 -142
View File
@@ -1,7 +1,8 @@
// IWYU pragma: no_include <bits/std_abs.h> // IWYU pragma: no_include <bits/std_abs.h>
#include "credits.h" #include "credits.h"
#include <SDL3/SDL.h> // Para SDL_RenderFillRect, SDL_RenderTexture #include <SDL3/SDL.h> // Para SDL_RenderFillRect, SDL_RenderTexture
#include <algorithm> // Para max, min, clamp #include <algorithm> // Para max, min, clamp
#include <array> // Para array #include <array> // Para array
#include <cmath> // Para abs #include <cmath> // Para abs
@@ -9,24 +10,24 @@
#include <string> // Para basic_string, string #include <string> // Para basic_string, string
#include <vector> // Para vector #include <vector> // Para vector
#include "audio.h" // Para Audio #include "audio.h" // Para Audio
#include "balloon_manager.h" // Para BalloonManager #include "balloon_manager.h" // Para BalloonManager
#include "fade.h" // Para Fade, FadeType, FadeMode #include "fade.h" // Para Fade, FadeType, FadeMode
#include "global_events.h" // Para check #include "global_events.h" // Para check
#include "global_inputs.h" // Para check #include "global_inputs.h" // Para check
#include "input.h" // Para Input, INPUT_ALLOW_REPEAT #include "input.h" // Para Input, INPUT_ALLOW_REPEAT
#include "lang.h" // Para getText #include "lang.h" // Para getText
#include "param.h" // Para Param, param, ParamGame, ParamFade #include "param.h" // Para Param, param, ParamGame, ParamFade
#include "player.h" // Para Player, PlayerState #include "player.h" // Para Player, PlayerState
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "section.h" // Para Name, name #include "section.h" // Para Name, name
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "text.h" // Para Text, TEXT_CENTER, TEXT_SHADOW #include "text.h" // Para Text, TEXT_CENTER, TEXT_SHADOW
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "tiled_bg.h" // Para TiledBG, TiledBGMode #include "tiled_bg.h" // Para TiledBG, TiledBGMode
#include "ui/service_menu.h" // Para ServiceMenu #include "ui/service_menu.h" // Para ServiceMenu
#include "utils.h" // Para Color, Zone, SHADOW_TEXT_COLOR, NO_TEXT... #include "utils.h" // Para Color, Zone, SHADOW_TEXT_COLOR, NO_TEXT...
// Textos // Textos
constexpr const char TEXT_COPYRIGHT[] = "@2020,2025 JailDesigner"; constexpr const char TEXT_COPYRIGHT[] = "@2020,2025 JailDesigner";
@@ -38,10 +39,8 @@ Credits::Credits()
fade_in_(std::make_unique<Fade>()), fade_in_(std::make_unique<Fade>()),
fade_out_(std::make_unique<Fade>()), fade_out_(std::make_unique<Fade>()),
text_texture_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), text_texture_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
canvas_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)) canvas_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)) {
{ if (!text_texture_) {
if (!text_texture_)
{
throw std::runtime_error("Failed to create SDL texture for text."); throw std::runtime_error("Failed to create SDL texture for text.");
} }
Section::name = Section::Name::CREDITS; Section::name = Section::Name::CREDITS;
@@ -67,8 +66,7 @@ Credits::Credits()
} }
// Destructor // Destructor
Credits::~Credits() Credits::~Credits() {
{
SDL_DestroyTexture(text_texture_); SDL_DestroyTexture(text_texture_);
SDL_DestroyTexture(canvas_); SDL_DestroyTexture(canvas_);
resetVolume(); resetVolume();
@@ -76,26 +74,21 @@ Credits::~Credits()
} }
// Bucle principal // Bucle principal
void Credits::run() void Credits::run() {
{ while (Section::name == Section::Name::CREDITS) {
while (Section::name == Section::Name::CREDITS)
{
checkInput(); checkInput();
update(); update();
checkEvents(); // Tiene que ir antes del render checkEvents(); // Tiene que ir antes del render
render(); render();
} }
} }
// Actualiza las variables // Actualiza las variables
void Credits::update() void Credits::update() {
{ if (SDL_GetTicks() - ticks_ > param.game.speed) {
if (SDL_GetTicks() - ticks_ > param.game.speed)
{
ticks_ = SDL_GetTicks(); ticks_ = SDL_GetTicks();
const int REPEAT = want_to_pass_ ? 4 : 1; const int REPEAT = want_to_pass_ ? 4 : 1;
for (int i = 0; i < REPEAT; ++i) for (int i = 0; i < REPEAT; ++i) {
{
tiled_bg_->update(); tiled_bg_->update();
cycleColors(); cycleColors();
balloon_manager_->update(); balloon_manager_->update();
@@ -113,8 +106,7 @@ void Credits::update()
} }
// Dibuja Credits::en patalla // Dibuja Credits::en patalla
void Credits::render() void Credits::render() {
{
// Prepara para empezar a dibujar en la textura de juego // Prepara para empezar a dibujar en la textura de juego
Screen::get()->start(); Screen::get()->start();
@@ -126,30 +118,23 @@ void Credits::render()
} }
// Comprueba el manejador de eventos // Comprueba el manejador de eventos
void Credits::checkEvents() void Credits::checkEvents() {
{
SDL_Event event; SDL_Event event;
while (SDL_PollEvent(&event)) while (SDL_PollEvent(&event)) {
{
GlobalEvents::check(event); GlobalEvents::check(event);
} }
} }
// Comprueba las entradas // Comprueba las entradas
void Credits::checkInput() void Credits::checkInput() {
{
Input::get()->update(); Input::get()->update();
if (!ServiceMenu::get()->isEnabled()) if (!ServiceMenu::get()->isEnabled()) {
{
// Comprueba si se ha pulsado cualquier botón (de los usados para jugar) // Comprueba si se ha pulsado cualquier botón (de los usados para jugar)
if (Input::get()->checkAnyButton(INPUT_ALLOW_REPEAT)) if (Input::get()->checkAnyButton(INPUT_ALLOW_REPEAT)) {
{
want_to_pass_ = true; want_to_pass_ = true;
fading_ = mini_logo_on_position_; fading_ = mini_logo_on_position_;
} } else {
else
{
want_to_pass_ = false; want_to_pass_ = false;
} }
} }
@@ -159,8 +144,7 @@ void Credits::checkInput()
} }
// Crea la textura con el texto // Crea la textura con el texto
void Credits::fillTextTexture() void Credits::fillTextTexture() {
{
auto text = Resource::get()->getText("smb2"); auto text = Resource::get()->getText("smb2");
auto text_grad = Resource::get()->getText("smb2_grad"); auto text_grad = Resource::get()->getText("smb2_grad");
SDL_SetRenderTarget(Screen::get()->getRenderer(), text_texture_); SDL_SetRenderTarget(Screen::get()->getRenderer(), text_texture_);
@@ -248,8 +232,7 @@ void Credits::fillTextTexture()
} }
// Dibuja todos los sprites en la textura // Dibuja todos los sprites en la textura
void Credits::fillCanvas() void Credits::fillCanvas() {
{
// Cambia el destino del renderizador // Cambia el destino del renderizador
auto temp = SDL_GetRenderTarget(Screen::get()->getRenderer()); auto temp = SDL_GetRenderTarget(Screen::get()->getRenderer());
SDL_SetRenderTarget(Screen::get()->getRenderer(), canvas_); SDL_SetRenderTarget(Screen::get()->getRenderer(), canvas_);
@@ -279,8 +262,7 @@ void Credits::fillCanvas()
SDL_RenderRect(Screen::get()->getRenderer(), &red_rect); SDL_RenderRect(Screen::get()->getRenderer(), &red_rect);
// Si el mini_logo está en su destino, lo dibuja encima de lo anterior // Si el mini_logo está en su destino, lo dibuja encima de lo anterior
if (mini_logo_on_position_) if (mini_logo_on_position_) {
{
SDL_RenderTexture(Screen::get()->getRenderer(), text_texture_, &mini_logo_rect_src_, &mini_logo_rect_dst_); SDL_RenderTexture(Screen::get()->getRenderer(), text_texture_, &mini_logo_rect_src_, &mini_logo_rect_dst_);
} }
@@ -293,72 +275,57 @@ void Credits::fillCanvas()
} }
// Actualiza el destino de los rectangulos de las texturas // Actualiza el destino de los rectangulos de las texturas
void Credits::updateTextureDstRects() void Credits::updateTextureDstRects() {
{ if (counter_ % 10 == 0) {
if (counter_ % 10 == 0)
{
// Comprueba la posición de la textura con los titulos de credito // Comprueba la posición de la textura con los titulos de credito
if (credits_rect_dst_.y + credits_rect_dst_.h > play_area_.y) if (credits_rect_dst_.y + credits_rect_dst_.h > play_area_.y) {
{
--credits_rect_dst_.y; --credits_rect_dst_.y;
} }
// Comprueba la posición de la textura con el mini_logo // Comprueba la posición de la textura con el mini_logo
if (mini_logo_rect_dst_.y == mini_logo_final_pos_) if (mini_logo_rect_dst_.y == mini_logo_final_pos_) {
{
mini_logo_on_position_ = true; mini_logo_on_position_ = true;
// Si el jugador quiere pasar los titulos de credito, el fade se inicia solo // Si el jugador quiere pasar los titulos de credito, el fade se inicia solo
if (want_to_pass_) if (want_to_pass_) {
{
fading_ = true; fading_ = true;
} }
// Se activa el contador para evitar que la sección sea infinita // Se activa el contador para evitar que la sección sea infinita
if (counter_prevent_endless_ == 1000) if (counter_prevent_endless_ == 1000) {
{
fading_ = true; fading_ = true;
} } else {
else
{
++counter_prevent_endless_; ++counter_prevent_endless_;
} }
} } else {
else
{
--mini_logo_rect_dst_.y; --mini_logo_rect_dst_.y;
} }
} }
} }
// Tira globos al escenario // Tira globos al escenario
void Credits::throwBalloons() void Credits::throwBalloons() {
{
constexpr int speed = 200; constexpr int speed = 200;
const std::vector<int> sets = {0, 63, 25, 67, 17, 75, 13, 50}; const std::vector<int> sets = {0, 63, 25, 67, 17, 75, 13, 50};
if (counter_ > ((sets.size() - 1) * speed) * 3) if (counter_ > ((sets.size() - 1) * speed) * 3) {
{
return; return;
} }
if (counter_ % speed == 0) if (counter_ % speed == 0) {
{
const int index = (counter_ / speed) % sets.size(); const int index = (counter_ / speed) % sets.size();
balloon_manager_->deploySet(sets.at(index), -60); balloon_manager_->deploySet(sets.at(index), -60);
} }
if (counter_ % (speed * 4) == 0 && counter_ > 0) if (counter_ % (speed * 4) == 0 && counter_ > 0) {
{
balloon_manager_->createPowerBall(); balloon_manager_->createPowerBall();
} }
} }
// Inicializa los jugadores // Inicializa los jugadores
void Credits::initPlayers() void Credits::initPlayers() {
{ std::vector<std::vector<std::shared_ptr<Texture>>> player_textures; // Vector con todas las texturas de los jugadores;
std::vector<std::vector<std::shared_ptr<Texture>>> player_textures; // Vector con todas las texturas de los jugadores; std::vector<std::vector<std::string>> player_animations; // Vector con las animaciones del jugador
std::vector<std::vector<std::string>> player_animations; // Vector con las animaciones del jugador
// Texturas - Player1 // Texturas - Player1
{ {
@@ -397,14 +364,11 @@ void Credits::initPlayers()
} }
// Actualiza los rectangulos negros // Actualiza los rectangulos negros
void Credits::updateBlackRects() void Credits::updateBlackRects() {
{
static int current_step = steps_; static int current_step = steps_;
if (top_black_rect_.h != param.game.game_area.center_y - 1 && bottom_black_rect_.y != param.game.game_area.center_y + 1) if (top_black_rect_.h != param.game.game_area.center_y - 1 && bottom_black_rect_.y != param.game.game_area.center_y + 1) {
{
// Si los rectangulos superior e inferior no han llegado al centro // Si los rectangulos superior e inferior no han llegado al centro
if (counter_ % 4 == 0) if (counter_ % 4 == 0) {
{
// Incrementa la altura del rectangulo superior // Incrementa la altura del rectangulo superior
top_black_rect_.h = std::min(top_black_rect_.h + 1, param.game.game_area.center_y - 1); top_black_rect_.h = std::min(top_black_rect_.h + 1, param.game.game_area.center_y - 1);
@@ -415,12 +379,9 @@ void Credits::updateBlackRects()
--current_step; --current_step;
setVolume(static_cast<int>(initial_volume_ * current_step / steps_)); setVolume(static_cast<int>(initial_volume_ * current_step / steps_));
} }
} } else {
else
{
// Si los rectangulos superior e inferior han llegado al centro // Si los rectangulos superior e inferior han llegado al centro
if (left_black_rect_.w != param.game.game_area.center_x && right_black_rect_.x != param.game.game_area.center_x) if (left_black_rect_.w != param.game.game_area.center_x && right_black_rect_.x != param.game.game_area.center_x) {
{
constexpr int SPEED = 2; constexpr int SPEED = 2;
// Si los rectangulos izquierdo y derecho no han llegado al centro // Si los rectangulos izquierdo y derecho no han llegado al centro
// Incrementa la anchura del rectangulo situado a la izquierda // Incrementa la anchura del rectangulo situado a la izquierda
@@ -432,18 +393,13 @@ void Credits::updateBlackRects()
--current_step; --current_step;
setVolume(static_cast<int>(initial_volume_ * current_step / steps_)); setVolume(static_cast<int>(initial_volume_ * current_step / steps_));
} } else {
else
{
// Si los rectangulos izquierdo y derecho han llegado al centro // Si los rectangulos izquierdo y derecho han llegado al centro
setVolume(0); setVolume(0);
Audio::get()->stopMusic(); Audio::get()->stopMusic();
if (counter_pre_fade_ == 400) if (counter_pre_fade_ == 400) {
{
fade_out_->activate(); fade_out_->activate();
} } else {
else
{
++counter_pre_fade_; ++counter_pre_fade_;
} }
} }
@@ -451,8 +407,7 @@ void Credits::updateBlackRects()
} }
// Actualiza el rectangulo rojo // Actualiza el rectangulo rojo
void Credits::updateRedRect() void Credits::updateRedRect() {
{
red_rect.x = left_black_rect_.x + left_black_rect_.w; red_rect.x = left_black_rect_.x + left_black_rect_.w;
red_rect.y = top_black_rect_.y + top_black_rect_.h - 1; red_rect.y = top_black_rect_.y + top_black_rect_.h - 1;
red_rect.w = right_black_rect_.x - red_rect.x; red_rect.w = right_black_rect_.x - red_rect.x;
@@ -460,76 +415,66 @@ void Credits::updateRedRect()
} }
// Actualiza el estado de fade // Actualiza el estado de fade
void Credits::updateAllFades() void Credits::updateAllFades() {
{ if (fading_) {
if (fading_)
{
updateBlackRects(); updateBlackRects();
updateRedRect(); updateRedRect();
} }
fade_in_->update(); fade_in_->update();
if (fade_in_->hasEnded()) if (fade_in_->hasEnded()) {
{
Audio::get()->playMusic("credits.ogg"); Audio::get()->playMusic("credits.ogg");
} }
fade_out_->update(); fade_out_->update();
if (fade_out_->hasEnded()) if (fade_out_->hasEnded()) {
{
Section::name = Section::Name::HI_SCORE_TABLE; Section::name = Section::Name::HI_SCORE_TABLE;
} }
} }
// Establece el nivel de volumen // Establece el nivel de volumen
void Credits::setVolume(int amount) void Credits::setVolume(int amount) {
{
Options::audio.music.volume = std::clamp(amount, 0, 100); Options::audio.music.volume = std::clamp(amount, 0, 100);
Audio::get()->setMusicVolume(Options::audio.music.volume); Audio::get()->setMusicVolume(Options::audio.music.volume);
} }
// Reestablece el nivel de volumen // Reestablece el nivel de volumen
void Credits::resetVolume() void Credits::resetVolume() {
{
Options::audio.music.volume = initial_volume_; Options::audio.music.volume = initial_volume_;
Audio::get()->setMusicVolume(Options::audio.music.volume); Audio::get()->setMusicVolume(Options::audio.music.volume);
} }
// Cambia el color del fondo // Cambia el color del fondo
void Credits::cycleColors() void Credits::cycleColors() {
{
// constexpr int UPPER_LIMIT = 255; // Límite superior // constexpr int UPPER_LIMIT = 255; // Límite superior
// constexpr int LOWER_LIMIT = 80; // Límite inferior // constexpr int LOWER_LIMIT = 80; // Límite inferior
constexpr int UPPER_LIMIT = 140; // Límite superior constexpr int UPPER_LIMIT = 140; // Límite superior
constexpr int LOWER_LIMIT = 30; // Límite inferior constexpr int LOWER_LIMIT = 30; // Límite inferior
static float r = static_cast<float>(UPPER_LIMIT); static float r = static_cast<float>(UPPER_LIMIT);
static float g = static_cast<float>(LOWER_LIMIT); static float g = static_cast<float>(LOWER_LIMIT);
static float b = static_cast<float>(LOWER_LIMIT); static float b = static_cast<float>(LOWER_LIMIT);
static float stepR = -0.5f; // Paso flotante para transiciones suaves static float stepR = -0.5f; // Paso flotante para transiciones suaves
static float stepG = 0.3f; static float stepG = 0.3f;
static float stepB = 0.1f; static float stepB = 0.1f;
// Ajustar valores de R // Ajustar valores de R
r += stepR; r += stepR;
if (r >= UPPER_LIMIT || r <= LOWER_LIMIT) if (r >= UPPER_LIMIT || r <= LOWER_LIMIT) {
{ stepR = -stepR; // Cambia de dirección al alcanzar los límites
stepR = -stepR; // Cambia de dirección al alcanzar los límites
} }
// Ajustar valores de G // Ajustar valores de G
g += stepG; g += stepG;
if (g >= UPPER_LIMIT || g <= LOWER_LIMIT) if (g >= UPPER_LIMIT || g <= LOWER_LIMIT) {
{ stepG = -stepG; // Cambia de dirección al alcanzar los límites
stepG = -stepG; // Cambia de dirección al alcanzar los límites
} }
// Ajustar valores de B // Ajustar valores de B
b += stepB; b += stepB;
if (b >= UPPER_LIMIT || b <= LOWER_LIMIT) if (b >= UPPER_LIMIT || b <= LOWER_LIMIT) {
{ stepB = -stepB; // Cambia de dirección al alcanzar los límites
stepB = -stepB; // Cambia de dirección al alcanzar los límites
} }
// Aplicar el color, redondeando a enteros antes de usar // Aplicar el color, redondeando a enteros antes de usar
@@ -538,19 +483,15 @@ void Credits::cycleColors()
} }
// Actualza los jugadores // Actualza los jugadores
void Credits::updatePlayers() void Credits::updatePlayers() {
{ for (auto &player : players_) {
for (auto &player : players_)
{
player->update(); player->update();
} }
} }
// Renderiza los jugadores // Renderiza los jugadores
void Credits::renderPlayers() void Credits::renderPlayers() {
{ for (auto const &player : players_) {
for (auto const &player : players_)
{
player->render(); player->render();
} }
} }
+47 -47
View File
@@ -1,12 +1,13 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_FRect, Uint32, SDL_Texture, Uint64 #include <SDL3/SDL.h> // Para SDL_FRect, Uint32, SDL_Texture, Uint64
#include <memory> // Para unique_ptr, shared_ptr
#include <vector> // Para vector
#include "options.h" // Para AudioOptions, MusicOptions, audio #include <memory> // Para unique_ptr, shared_ptr
#include "param.h" // Para Param, ParamGame, param #include <vector> // Para vector
#include "utils.h" // Para Zone, Color
#include "options.h" // Para AudioOptions, MusicOptions, audio
#include "param.h" // Para Param, ParamGame, param
#include "utils.h" // Para Zone, Color
// Declaraciones adelantadas // Declaraciones adelantadas
class BalloonManager; class BalloonManager;
@@ -14,9 +15,8 @@ class Fade;
class Player; class Player;
class TiledBG; class TiledBG;
class Credits class Credits {
{ public:
public:
// --- Constructores y destructor --- // --- Constructores y destructor ---
Credits(); Credits();
~Credits(); ~Credits();
@@ -24,40 +24,40 @@ public:
// --- Bucle principal --- // --- Bucle principal ---
void run(); void run();
private: private:
// --- Constantes de clase --- // --- Constantes de clase ---
static constexpr int PLAY_AREA_HEIGHT = 200; static constexpr int PLAY_AREA_HEIGHT = 200;
// --- Objetos principales --- // --- Objetos principales ---
std::unique_ptr<BalloonManager> balloon_manager_; // Gestión de globos std::unique_ptr<BalloonManager> balloon_manager_; // Gestión de globos
std::unique_ptr<TiledBG> tiled_bg_; // Mosaico animado de fondo std::unique_ptr<TiledBG> tiled_bg_; // Mosaico animado de fondo
std::unique_ptr<Fade> fade_in_; // Fundido de entrada std::unique_ptr<Fade> fade_in_; // Fundido de entrada
std::unique_ptr<Fade> fade_out_; // Fundido de salida std::unique_ptr<Fade> fade_out_; // Fundido de salida
std::vector<std::shared_ptr<Player>> players_; // Vector de jugadores std::vector<std::shared_ptr<Player>> players_; // Vector de jugadores
// --- Gestión de texturas --- // --- Gestión de texturas ---
SDL_Texture *text_texture_; // Textura con el texto de créditos SDL_Texture *text_texture_; // Textura con el texto de créditos
SDL_Texture *canvas_; // Textura donde se dibuja todo SDL_Texture *canvas_; // Textura donde se dibuja todo
// --- Temporización y contadores --- // --- Temporización y contadores ---
Uint64 ticks_ = 0; // Control de velocidad del programa Uint64 ticks_ = 0; // Control de velocidad del programa
Uint32 counter_ = 0; // Contador principal de lógica Uint32 counter_ = 0; // Contador principal de lógica
Uint32 counter_pre_fade_ = 0; // Activación del fundido final Uint32 counter_pre_fade_ = 0; // Activación del fundido final
Uint32 counter_prevent_endless_ = 0; // Prevención de bucle infinito Uint32 counter_prevent_endless_ = 0; // Prevención de bucle infinito
// --- Variables de estado --- // --- Variables de estado ---
bool fading_ = false; // Estado del fade final bool fading_ = false; // Estado del fade final
bool want_to_pass_ = false; // Jugador quiere saltarse créditos bool want_to_pass_ = false; // Jugador quiere saltarse créditos
bool mini_logo_on_position_ = false; // Minilogo en posición final bool mini_logo_on_position_ = false; // Minilogo en posición final
// --- Diseño y posicionamiento --- // --- Diseño y posicionamiento ---
float black_bars_size_ = (param.game.game_area.rect.h - PLAY_AREA_HEIGHT) / 2; // Tamaño de las barras negras float black_bars_size_ = (param.game.game_area.rect.h - PLAY_AREA_HEIGHT) / 2; // Tamaño de las barras negras
int mini_logo_final_pos_ = 0; // Posición final del minilogo int mini_logo_final_pos_ = 0; // Posición final del minilogo
Color color_; // Color usado para los efectos Color color_; // Color usado para los efectos
// --- Control de audio --- // --- Control de audio ---
int initial_volume_ = Options::audio.music.volume; // Volumen inicial int initial_volume_ = Options::audio.music.volume; // Volumen inicial
int steps_ = 0; // Pasos para reducir audio int steps_ = 0; // Pasos para reducir audio
// --- Rectángulos de renderizado --- // --- Rectángulos de renderizado ---
// Texto de créditos // Texto de créditos
@@ -98,32 +98,32 @@ private:
2}; 2};
// Borde para la ventana // Borde para la ventana
SDL_FRect red_rect = play_area_; // Delimitador de ventana SDL_FRect red_rect = play_area_; // Delimitador de ventana
// --- Métodos del bucle principal --- // --- Métodos del bucle principal ---
void update(); // Actualización principal de la lógica void update(); // Actualización principal de la lógica
void render(); // Renderizado de la escena void render(); // Renderizado de la escena
void checkEvents(); // Manejo de eventos void checkEvents(); // Manejo de eventos
void checkInput(); // Procesamiento de entrada void checkInput(); // Procesamiento de entrada
// --- Métodos de renderizado --- // --- Métodos de renderizado ---
void fillTextTexture(); // Crear textura de texto de créditos void fillTextTexture(); // Crear textura de texto de créditos
void fillCanvas(); // Renderizar todos los sprites y fondos void fillCanvas(); // Renderizar todos los sprites y fondos
void updateTextureDstRects(); // Actualizar destinos de texturas void updateTextureDstRects(); // Actualizar destinos de texturas
void renderPlayers(); // Renderiza los jugadores void renderPlayers(); // Renderiza los jugadores
// --- Métodos de lógica del juego --- // --- Métodos de lógica del juego ---
void throwBalloons(); // Lanzar globos al escenario void throwBalloons(); // Lanzar globos al escenario
void initPlayers(); // Inicializar jugadores void initPlayers(); // Inicializar jugadores
void updateAllFades(); // Actualizar estados de fade void updateAllFades(); // Actualizar estados de fade
void cycleColors(); // Cambiar colores de fondo void cycleColors(); // Cambiar colores de fondo
void updatePlayers(); // Actualza los jugadores void updatePlayers(); // Actualza los jugadores
// --- Métodos de interfaz --- // --- Métodos de interfaz ---
void updateBlackRects(); // Actualizar rectángulos negros (letterbox) void updateBlackRects(); // Actualizar rectángulos negros (letterbox)
void updateRedRect(); // Actualizar rectángulo rojo (borde) void updateRedRect(); // Actualizar rectángulo rojo (borde)
// --- Métodos de audio --- // --- Métodos de audio ---
void setVolume(int amount); // Establecer volumen void setVolume(int amount); // Establecer volumen
void resetVolume(); // Restablecer volumen void resetVolume(); // Restablecer volumen
}; };
+1404 -1729
View File
File diff suppressed because it is too large. Load diff
+195 -197
View File
@@ -1,14 +1,15 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_Event, SDL_Renderer, SDL_Texture, Uint64, Uint8 #include <SDL3/SDL.h> // Para SDL_Event, SDL_Renderer, SDL_Texture, Uint64, Uint8
#include <memory> // Para shared_ptr, unique_ptr
#include <string> // Para string
#include <vector> // Para vector
#include "manage_hiscore_table.h" // Para HiScoreEntry #include <memory> // Para shared_ptr, unique_ptr
#include "options.h" // Para SettingsOptions, settings, DifficultyCode (ptr only) #include <string> // Para string
#include "player.h" // Para Player #include <vector> // Para vector
#include "utils.h" // Para Demo
#include "manage_hiscore_table.h" // Para HiScoreEntry
#include "options.h" // Para SettingsOptions, settings, DifficultyCode (ptr only)
#include "player.h" // Para Player
#include "utils.h" // Para Demo
class Background; class Background;
class Balloon; class Balloon;
@@ -35,216 +36,213 @@ constexpr bool GAME_MODE_DEMO_ON = true;
constexpr int TOTAL_SCORE_DATA = 3; constexpr int TOTAL_SCORE_DATA = 3;
// Clase Game // Clase Game
class Game class Game {
{ public:
public: // Constructor
// Constructor Game(int playerID, int current_stage, bool demo);
Game(int playerID, int current_stage, bool demo);
// Destructor // Destructor
~Game(); ~Game();
// Bucle principal del juego // Bucle principal del juego
void run(); void run();
private: private:
// --- Tipos internos --- // --- Tipos internos ---
enum class GameState enum class GameState {
{ FADE_IN,
FADE_IN, ENTERING_PLAYER,
ENTERING_PLAYER, SHOWING_GET_READY_MESSAGE,
SHOWING_GET_READY_MESSAGE, PLAYING,
PLAYING, COMPLETED,
COMPLETED, GAME_OVER,
GAME_OVER, };
};
// --- Constantes internas --- // --- Constantes internas ---
static constexpr int HELP_COUNTER_ = 1000; static constexpr int HELP_COUNTER_ = 1000;
static constexpr int GAME_COMPLETED_START_FADE_ = 500; static constexpr int GAME_COMPLETED_START_FADE_ = 500;
static constexpr int GAME_COMPLETED_END_ = 700; static constexpr int GAME_COMPLETED_END_ = 700;
static constexpr int GAME_OVER_COUNTER_ = 350; static constexpr int GAME_OVER_COUNTER_ = 350;
static constexpr int TIME_STOPPED_COUNTER_ = 360; static constexpr int TIME_STOPPED_COUNTER_ = 360;
static constexpr int ITEM_POINTS_1_DISK_ODDS_ = 10; static constexpr int ITEM_POINTS_1_DISK_ODDS_ = 10;
static constexpr int ITEM_POINTS_2_GAVINA_ODDS_ = 6; static constexpr int ITEM_POINTS_2_GAVINA_ODDS_ = 6;
static constexpr int ITEM_POINTS_3_PACMAR_ODDS_ = 3; static constexpr int ITEM_POINTS_3_PACMAR_ODDS_ = 3;
static constexpr int ITEM_CLOCK_ODDS_ = 5; static constexpr int ITEM_CLOCK_ODDS_ = 5;
static constexpr int ITEM_COFFEE_ODDS_ = 5; static constexpr int ITEM_COFFEE_ODDS_ = 5;
static constexpr int ITEM_POWER_BALL_ODDS_ = 0; static constexpr int ITEM_POWER_BALL_ODDS_ = 0;
static constexpr int ITEM_COFFEE_MACHINE_ODDS_ = 4; static constexpr int ITEM_COFFEE_MACHINE_ODDS_ = 4;
// --- Estructuras --- // --- Estructuras ---
struct Helper struct Helper {
{ bool need_coffee; // Indica si se necesitan cafes
bool need_coffee; // Indica si se necesitan cafes bool need_coffee_machine; // Indica si se necesita PowerUp
bool need_coffee_machine; // Indica si se necesita PowerUp bool need_power_ball; // Indica si se necesita una PowerBall
bool need_power_ball; // Indica si se necesita una PowerBall int counter; // Contador para no dar ayudas consecutivas
int counter; // Contador para no dar ayudas consecutivas int item_disk_odds; // Probabilidad de aparición del objeto
int item_disk_odds; // Probabilidad de aparición del objeto int item_gavina_odds; // Probabilidad de aparición del objeto
int item_gavina_odds; // Probabilidad de aparición del objeto int item_pacmar_odds; // Probabilidad de aparición del objeto
int item_pacmar_odds; // Probabilidad de aparición del objeto int item_clock_odds; // Probabilidad de aparición del objeto
int item_clock_odds; // Probabilidad de aparición del objeto int item_coffee_odds; // Probabilidad de aparición del objeto
int item_coffee_odds; // Probabilidad de aparición del objeto int item_coffee_machine_odds; // Probabilidad de aparición del objeto
int item_coffee_machine_odds; // Probabilidad de aparición del objeto
Helper() Helper()
: need_coffee(false), : need_coffee(false),
need_coffee_machine(false), need_coffee_machine(false),
need_power_ball(false), need_power_ball(false),
counter(HELP_COUNTER_), counter(HELP_COUNTER_),
item_disk_odds(ITEM_POINTS_1_DISK_ODDS_), item_disk_odds(ITEM_POINTS_1_DISK_ODDS_),
item_gavina_odds(ITEM_POINTS_2_GAVINA_ODDS_), item_gavina_odds(ITEM_POINTS_2_GAVINA_ODDS_),
item_pacmar_odds(ITEM_POINTS_3_PACMAR_ODDS_), item_pacmar_odds(ITEM_POINTS_3_PACMAR_ODDS_),
item_clock_odds(ITEM_CLOCK_ODDS_), item_clock_odds(ITEM_CLOCK_ODDS_),
item_coffee_odds(ITEM_COFFEE_ODDS_), item_coffee_odds(ITEM_COFFEE_ODDS_),
item_coffee_machine_odds(ITEM_COFFEE_MACHINE_ODDS_) {} item_coffee_machine_odds(ITEM_COFFEE_MACHINE_ODDS_) {}
}; };
// --- Objetos y punteros --- // --- Objetos y punteros ---
SDL_Renderer *renderer_; // El renderizador de la ventana SDL_Renderer *renderer_; // El renderizador de la ventana
Screen *screen_; // Objeto encargado de dibujar en pantalla Screen *screen_; // Objeto encargado de dibujar en pantalla
Input *input_; // Manejador de entrada Input *input_; // Manejador de entrada
Scoreboard *scoreboard_; // Objeto para dibujar el marcador Scoreboard *scoreboard_; // Objeto para dibujar el marcador
std::unique_ptr<Background> background_; // Objeto para dibujar el fondo del juego std::unique_ptr<Background> background_; // Objeto para dibujar el fondo del juego
SDL_Texture *canvas_; // Textura para dibujar la zona de juego SDL_Texture *canvas_; // Textura para dibujar la zona de juego
std::vector<std::shared_ptr<Player>> players_; // Vector con los jugadores std::vector<std::shared_ptr<Player>> players_; // Vector con los jugadores
std::vector<std::unique_ptr<Bullet>> bullets_; // Vector con las balas std::vector<std::unique_ptr<Bullet>> bullets_; // Vector con las balas
std::vector<std::unique_ptr<Item>> items_; // Vector con los items std::vector<std::unique_ptr<Item>> items_; // Vector con los items
std::vector<std::unique_ptr<SmartSprite>> smart_sprites_; // Vector con los smartsprites std::vector<std::unique_ptr<SmartSprite>> smart_sprites_; // Vector con los smartsprites
std::vector<std::unique_ptr<PathSprite>> path_sprites_; // Vector con los pathsprites std::vector<std::unique_ptr<PathSprite>> path_sprites_; // Vector con los pathsprites
std::vector<std::shared_ptr<Texture>> item_textures_; // Vector con las texturas de los items std::vector<std::shared_ptr<Texture>> item_textures_; // Vector con las texturas de los items
std::vector<std::vector<std::shared_ptr<Texture>>> player_textures_; // Vector con todas las texturas de los jugadores std::vector<std::vector<std::shared_ptr<Texture>>> player_textures_; // Vector con todas las texturas de los jugadores
std::vector<std::shared_ptr<Texture>> game_text_textures_; // Vector con las texturas para los sprites con textos std::vector<std::shared_ptr<Texture>> game_text_textures_; // Vector con las texturas para los sprites con textos
std::vector<std::vector<std::string>> item_animations_; // Vector con las animaciones de los items std::vector<std::vector<std::string>> item_animations_; // Vector con las animaciones de los items
std::vector<std::vector<std::string>> player_animations_; // Vector con las animaciones del jugador std::vector<std::vector<std::string>> player_animations_; // Vector con las animaciones del jugador
std::unique_ptr<Fade> fade_in_; // Objeto para renderizar fades std::unique_ptr<Fade> fade_in_; // Objeto para renderizar fades
std::unique_ptr<Fade> fade_out_; // Objeto para renderizar fades std::unique_ptr<Fade> fade_out_; // Objeto para renderizar fades
std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos
std::unique_ptr<Tabe> tabe_; // Objeto para gestionar el Tabe Volaor std::unique_ptr<Tabe> tabe_; // Objeto para gestionar el Tabe Volaor
std::vector<Path> paths_; // Vector con los recorridos precalculados almacenados std::vector<Path> paths_; // Vector con los recorridos precalculados almacenados
// --- Variables de estado --- // --- Variables de estado ---
HiScoreEntry hi_score_ = HiScoreEntry( HiScoreEntry hi_score_ = HiScoreEntry(
Options::settings.hi_score_table[0].name, Options::settings.hi_score_table[0].name,
Options::settings.hi_score_table[0].score); // Máxima puntuación y nombre de quien la ostenta Options::settings.hi_score_table[0].score); // Máxima puntuación y nombre de quien la ostenta
Demo demo_; // Variable con todas las variables relacionadas con el modo demo Demo demo_; // Variable con todas las variables relacionadas con el modo demo
Options::DifficultyCode difficulty_ = Options::settings.difficulty; // Dificultad del juego Options::DifficultyCode difficulty_ = Options::settings.difficulty; // Dificultad del juego
Helper helper_; // Variable para gestionar las ayudas Helper helper_; // Variable para gestionar las ayudas
Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
bool coffee_machine_enabled_ = false; // Indica si hay una máquina de café en el terreno de juego bool coffee_machine_enabled_ = false; // Indica si hay una máquina de café en el terreno de juego
bool hi_score_achieved_ = false; // Indica si se ha superado la puntuación máxima bool hi_score_achieved_ = false; // Indica si se ha superado la puntuación máxima
bool paused_ = false; // Indica si el juego está pausado (no se deberia de poder utilizar en el modo arcade) bool paused_ = false; // Indica si el juego está pausado (no se deberia de poder utilizar en el modo arcade)
// bool paused_by_service_menu_ = false; // bool paused_by_service_menu_ = false;
float difficulty_score_multiplier_; // Multiplicador de puntos en función de la dificultad float difficulty_score_multiplier_; // Multiplicador de puntos en función de la dificultad
int counter_ = 0; // Contador para el juego int counter_ = 0; // Contador para el juego
int game_completed_counter_ = 0; // Contador para el tramo final, cuando se ha completado la partida y ya no aparecen más enemigos int game_completed_counter_ = 0; // Contador para el tramo final, cuando se ha completado la partida y ya no aparecen más enemigos
int game_over_counter_ = GAME_OVER_COUNTER_; // Contador para el estado de fin de partida int game_over_counter_ = GAME_OVER_COUNTER_; // Contador para el estado de fin de partida
int time_stopped_counter_ = 0; // Temporizador para llevar la cuenta del tiempo detenido int time_stopped_counter_ = 0; // Temporizador para llevar la cuenta del tiempo detenido
int total_power_to_complete_game_; // La suma del poder necesario para completar todas las fases int total_power_to_complete_game_; // La suma del poder necesario para completar todas las fases
int menace_current_ = 0; // Nivel de amenaza actual int menace_current_ = 0; // Nivel de amenaza actual
int menace_threshold_ = 0; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el número de globos int menace_threshold_ = 0; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el número de globos
GameState state_ = GameState::FADE_IN; // Estado GameState state_ = GameState::FADE_IN; // Estado
std::vector<std::shared_ptr<Player>> players_to_reorder; std::vector<std::shared_ptr<Player>> players_to_reorder;
#ifdef DEBUG #ifdef DEBUG
bool auto_pop_balloons_ = false; // Si es true, incrementa automaticamente los globos explotados bool auto_pop_balloons_ = false; // Si es true, incrementa automaticamente los globos explotados
// Comprueba los eventos en el modo DEBUG // Comprueba los eventos en el modo DEBUG
void checkDebugEvents(const SDL_Event &event); void checkDebugEvents(const SDL_Event &event);
#endif #endif
// --- Métodos internos --- // --- Métodos internos ---
void update(); // Actualiza el juego void update(); // Actualiza el juego
void render(); // Dibuja el juego void render(); // Dibuja el juego
void checkEvents(); // Comprueba los eventos que hay en cola void checkEvents(); // Comprueba los eventos que hay en cola
void setResources(); // Asigna texturas y animaciones void setResources(); // Asigna texturas y animaciones
void updateHiScore(); // Actualiza el valor de HiScore en caso necesario void updateHiScore(); // Actualiza el valor de HiScore en caso necesario
void updatePlayers(); // Actualiza las variables del jugador void updatePlayers(); // Actualiza las variables del jugador
void renderPlayers(); // Dibuja a los jugadores void renderPlayers(); // Dibuja a los jugadores
void updateStage(); // Comprueba si hay cambio de fase y actualiza las variables void updateStage(); // Comprueba si hay cambio de fase y actualiza las variables
void updateGameStateGameOver(); // Actualiza el estado de fin de la partida void updateGameStateGameOver(); // Actualiza el estado de fin de la partida
void destroyAllItems(); // Destruye todos los items void destroyAllItems(); // Destruye todos los items
std::shared_ptr<Balloon> checkPlayerBalloonCollision(std::shared_ptr<Player> &player); // Comprueba la colisión entre el jugador y los globos activos std::shared_ptr<Balloon> checkPlayerBalloonCollision(std::shared_ptr<Player> &player); // Comprueba la colisión entre el jugador y los globos activos
void checkPlayerItemCollision(std::shared_ptr<Player> &player); // Comprueba la colisión entre el jugador y los items void checkPlayerItemCollision(std::shared_ptr<Player> &player); // Comprueba la colisión entre el jugador y los items
void checkBulletCollision(); // Comprueba y procesa la colisión de las balas void checkBulletCollision(); // Comprueba y procesa la colisión de las balas
void updateBullets(); // Mueve las balas activas void updateBullets(); // Mueve las balas activas
void renderBullets(); // Pinta las balas activas void renderBullets(); // Pinta las balas activas
void createBullet(int x, int y, BulletType kind, bool powered_up, int owner); // Crea un objeto bala void createBullet(int x, int y, BulletType kind, bool powered_up, int owner); // Crea un objeto bala
void freeBullets(); // Vacia el vector de balas void freeBullets(); // Vacia el vector de balas
void updateItems(); // Actualiza los items void updateItems(); // Actualiza los items
void renderItems(); // Pinta los items activos void renderItems(); // Pinta los items activos
ItemType dropItem(); // Devuelve un item en función del azar ItemType dropItem(); // Devuelve un item en función del azar
void createItem(ItemType type, float x, float y); // Crea un objeto item void createItem(ItemType type, float x, float y); // Crea un objeto item
void freeItems(); // Vacia el vector de items void freeItems(); // Vacia el vector de items
void createItemText(int x, std::shared_ptr<Texture> texture); // Crea un objeto PathSprite void createItemText(int x, std::shared_ptr<Texture> texture); // Crea un objeto PathSprite
void createMessage(const std::vector<Path> &paths, std::shared_ptr<Texture> texture); // Crea un objeto PathSprite void createMessage(const std::vector<Path> &paths, std::shared_ptr<Texture> texture); // Crea un objeto PathSprite
void freeSmartSprites(); // Vacia el vector de smartsprites void freeSmartSprites(); // Vacia el vector de smartsprites
void freePathSprites(); // Vacia el vector de pathsprites void freePathSprites(); // Vacia el vector de pathsprites
void throwCoffee(int x, int y); // Crea un SpriteSmart para arrojar el item café al recibir un impacto void throwCoffee(int x, int y); // Crea un SpriteSmart para arrojar el item café al recibir un impacto
void updateSmartSprites(); // Actualiza los SpriteSmarts void updateSmartSprites(); // Actualiza los SpriteSmarts
void renderSmartSprites(); // Pinta los SpriteSmarts activos void renderSmartSprites(); // Pinta los SpriteSmarts activos
void updatePathSprites(); // Actualiza los PathSprites void updatePathSprites(); // Actualiza los PathSprites
void renderPathSprites(); // Pinta los PathSprites activos void renderPathSprites(); // Pinta los PathSprites activos
void handlePlayerCollision(std::shared_ptr<Player> &player); // Acciones a realizar cuando el jugador colisiona con un globo void handlePlayerCollision(std::shared_ptr<Player> &player); // Acciones a realizar cuando el jugador colisiona con un globo
void updateTimeStopped(); // Actualiza y comprueba el valor de la variable void updateTimeStopped(); // Actualiza y comprueba el valor de la variable
void updateBackground(); // Actualiza el fondo void updateBackground(); // Actualiza el fondo
void initPaths(); // Inicializa las variables que contienen puntos de ruta para mover objetos void initPaths(); // Inicializa las variables que contienen puntos de ruta para mover objetos
void enableTimeStopItem(); // Habilita el efecto del item de detener el tiempo void enableTimeStopItem(); // Habilita el efecto del item de detener el tiempo
void disableTimeStopItem(); // Deshabilita el efecto del item de detener el tiempo void disableTimeStopItem(); // Deshabilita el efecto del item de detener el tiempo
void updateHelper(); // Actualiza las variables de ayuda void updateHelper(); // Actualiza las variables de ayuda
bool allPlayersAreWaitingOrGameOver(); // Comprueba si todos los jugadores han terminado de jugar bool allPlayersAreWaitingOrGameOver(); // Comprueba si todos los jugadores han terminado de jugar
bool allPlayersAreGameOver(); // Comprueba si todos los jugadores han terminado de jugar bool allPlayersAreGameOver(); // Comprueba si todos los jugadores han terminado de jugar
bool allPlayersAreNotPlaying(); // Comprueba si todos los jugadores han terminado de jugar bool allPlayersAreNotPlaying(); // Comprueba si todos los jugadores han terminado de jugar
void updateScoreboard(); // Actualiza el marcador void updateScoreboard(); // Actualiza el marcador
void fillCanvas(); // Dibuja los elementos de la zona de juego en su textura void fillCanvas(); // Dibuja los elementos de la zona de juego en su textura
void pause(bool value); // Pausa el juego void pause(bool value); // Pausa el juego
void addScoreToScoreBoard(const std::shared_ptr<Player> &player); // Añade una puntuación a la tabla de records void addScoreToScoreBoard(const std::shared_ptr<Player> &player); // Añade una puntuación a la tabla de records
void checkAndUpdatePlayerStatus(int active_player_index, int inactive_player_index); // Saca del estado de GAME OVER al jugador si el otro está activo void checkAndUpdatePlayerStatus(int active_player_index, int inactive_player_index); // Saca del estado de GAME OVER al jugador si el otro está activo
void checkPlayersStatusPlaying(); // Comprueba el estado de juego de los jugadores void checkPlayersStatusPlaying(); // Comprueba el estado de juego de los jugadores
std::shared_ptr<Player> getPlayer(int id); // Obtiene un jugador a partir de su "id" std::shared_ptr<Player> getPlayer(int id); // Obtiene un jugador a partir de su "id"
int getController(int playerId); // Obtiene un controlador a partir del "id" del jugador int getController(int playerId); // Obtiene un controlador a partir del "id" del jugador
void checkInput(); // Gestiona la entrada durante el juego void checkInput(); // Gestiona la entrada durante el juego
void checkPauseInput(); // Verifica si alguno de los controladores ha solicitado una pausa y actualiza el estado de pausa del juego. void checkPauseInput(); // Verifica si alguno de los controladores ha solicitado una pausa y actualiza el estado de pausa del juego.
void DEMO_handleInput(); // Gestiona las entradas de los jugadores en el modo demo, incluyendo movimientos y disparos automáticos. void DEMO_handleInput(); // Gestiona las entradas de los jugadores en el modo demo, incluyendo movimientos y disparos automáticos.
void DEMO_handlePassInput(); // Gestiona las entradas de los jugadores en el modo demo para saltarse la demo. void DEMO_handlePassInput(); // Gestiona las entradas de los jugadores en el modo demo para saltarse la demo.
void DEMO_handlePlayerInput(const std::shared_ptr<Player> &player, int index); // Procesa las entradas para un jugador específico durante el modo demo. void DEMO_handlePlayerInput(const std::shared_ptr<Player> &player, int index); // Procesa las entradas para un jugador específico durante el modo demo.
void handleFireInput(const std::shared_ptr<Player> &player, BulletType bulletType); // Maneja el disparo de un jugador, incluyendo la creación de balas y la gestión del tiempo de espera entre disparos. void handleFireInput(const std::shared_ptr<Player> &player, BulletType bulletType); // Maneja el disparo de un jugador, incluyendo la creación de balas y la gestión del tiempo de espera entre disparos.
void handlePlayersInput(); // Gestiona las entradas de todos los jugadores en el modo normal (fuera del modo demo). void handlePlayersInput(); // Gestiona las entradas de todos los jugadores en el modo normal (fuera del modo demo).
void handleNormalPlayerInput(const std::shared_ptr<Player> &player); // Maneja las entradas de movimiento y disparo para un jugador en modo normal. void handleNormalPlayerInput(const std::shared_ptr<Player> &player); // Maneja las entradas de movimiento y disparo para un jugador en modo normal.
void handleFireInputs(const std::shared_ptr<Player> &player, bool autofire, int controllerIndex); // Procesa las entradas de disparo del jugador, permitiendo disparos automáticos si está habilitado. void handleFireInputs(const std::shared_ptr<Player> &player, bool autofire, int controllerIndex); // Procesa las entradas de disparo del jugador, permitiendo disparos automáticos si está habilitado.
void handlePlayerContinue(const std::shared_ptr<Player> &player); // Maneja la continuación del jugador cuando no está jugando, permitiendo que continúe si se pulsa el botón de inicio. void handlePlayerContinue(const std::shared_ptr<Player> &player); // Maneja la continuación del jugador cuando no está jugando, permitiendo que continúe si se pulsa el botón de inicio.
void handleNameInput(const std::shared_ptr<Player> &player); // Procesa las entradas para la introducción del nombre del jugador. void handleNameInput(const std::shared_ptr<Player> &player); // Procesa las entradas para la introducción del nombre del jugador.
void initDemo(int player_id); // Inicializa las variables para el modo DEMO void initDemo(int player_id); // Inicializa las variables para el modo DEMO
void setTotalPower(); // Calcula el poder total necesario para completar el juego void setTotalPower(); // Calcula el poder total necesario para completar el juego
void initScoreboard(); // Inicializa el marcador void initScoreboard(); // Inicializa el marcador
void initDifficultyVars(); // Inicializa las opciones relacionadas con la dificultad void initDifficultyVars(); // Inicializa las opciones relacionadas con la dificultad
void initPlayers(int player_id); // Inicializa los jugadores void initPlayers(int player_id); // Inicializa los jugadores
void playMusic(); // Hace sonar la música void playMusic(); // Hace sonar la música
void stopMusic(); // Detiene la música void stopMusic(); // Detiene la música
void playSound(const std::string &name); // Hace sonar un sonido void playSound(const std::string &name); // Hace sonar un sonido
void updateDemo(); // Actualiza las variables durante el modo demo void updateDemo(); // Actualiza las variables durante el modo demo
void updateGameStateFadeIn(); // Actualiza las variables durante dicho estado void updateGameStateFadeIn(); // Actualiza las variables durante dicho estado
void updateGameStateEnteringPlayer(); // Actualiza las variables durante dicho estado void updateGameStateEnteringPlayer(); // Actualiza las variables durante dicho estado
void updateGameStateShowingGetReadyMessage(); // Actualiza las variables durante dicho estado void updateGameStateShowingGetReadyMessage(); // Actualiza las variables durante dicho estado
void updateGameStatePlaying(); // Actualiza las variables durante el transcurso normal del juego void updateGameStatePlaying(); // Actualiza las variables durante el transcurso normal del juego
void updateGameStateCompleted(); // Gestiona eventos para el estado del final del juego void updateGameStateCompleted(); // Gestiona eventos para el estado del final del juego
void checkState(); // Comprueba el estado del juego void checkState(); // Comprueba el estado del juego
void cleanVectors(); // Vacía los vectores de elementos deshabilitados void cleanVectors(); // Vacía los vectores de elementos deshabilitados
void updateMenace(); // Gestiona el nivel de amenaza void updateMenace(); // Gestiona el nivel de amenaza
void evaluateAndSetMenace(); // Calcula y establece el valor de amenaza en funcion de los globos activos void evaluateAndSetMenace(); // Calcula y establece el valor de amenaza en funcion de los globos activos
void checkAndUpdateBalloonSpeed(); // Actualiza la velocidad de los globos en funcion del poder acumulado de la fase void checkAndUpdateBalloonSpeed(); // Actualiza la velocidad de los globos en funcion del poder acumulado de la fase
void setState(GameState state); // Cambia el estado del juego void setState(GameState state); // Cambia el estado del juego
void movePlayersToFront(); // Organiza los jugadores para que los vivos se pinten sobre los muertos void movePlayersToFront(); // Organiza los jugadores para que los vivos se pinten sobre los muertos
void checkServiceMenu(); // Comprueba si está activo el menu de servicio para poner el juego en pausa void checkServiceMenu(); // Comprueba si está activo el menu de servicio para poner el juego en pausa
#ifdef RECORDING #ifdef RECORDING
void updateRecording(); // Actualiza las variables durante el modo de grabación void updateRecording(); // Actualiza las variables durante el modo de grabación
#endif #endif
}; };
+293 -336
View File
@@ -1,432 +1,389 @@
#include "hiscore_table.h" #include "hiscore_table.h"
#include <SDL3/SDL.h> // Para SDL_GetTicks, SDL_SetRenderTarget #include <SDL3/SDL.h> // Para SDL_GetTicks, SDL_SetRenderTarget
#include <stdlib.h> // Para rand, size_t #include <stdlib.h> // Para rand, size_t
#include <algorithm> // Para max
#include <functional> // Para function
#include <vector> // Para vector
#include "audio.h" // Para Audio #include <algorithm> // Para max
#include "background.h" // Para Background #include <functional> // Para function
#include "fade.h" // Para Fade, FadeMode, FadeType #include <vector> // Para vector
#include "global_events.h" // Para check
#include "global_inputs.h" // Para check #include "audio.h" // Para Audio
#include "input.h" // Para Input #include "background.h" // Para Background
#include "lang.h" // Para getText #include "fade.h" // Para Fade, FadeMode, FadeType
#include "manage_hiscore_table.h" // Para HiScoreEntry #include "global_events.h" // Para check
#include "options.h" // Para SettingsOptions, settings #include "global_inputs.h" // Para check
#include "param.h" // Para Param, param, ParamGame, ParamFade #include "input.h" // Para Input
#include "path_sprite.h" // Para PathSprite, Path, PathType #include "lang.h" // Para getText
#include "resource.h" // Para Resource #include "manage_hiscore_table.h" // Para HiScoreEntry
#include "screen.h" // Para Screen #include "options.h" // Para SettingsOptions, settings
#include "section.h" // Para Name, name, Options, options #include "param.h" // Para Param, param, ParamGame, ParamFade
#include "sprite.h" // Para Sprite #include "path_sprite.h" // Para PathSprite, Path, PathType
#include "text.h" // Para Text, TEXT_SHADOW, TEXT_COLOR #include "resource.h" // Para Resource
#include "texture.h" // Para Texture #include "screen.h" // Para Screen
#include "utils.h" // Para Color, easeOutQuint, NO_TEXT_COLOR #include "section.h" // Para Name, name, Options, options
#include "sprite.h" // Para Sprite
#include "text.h" // Para Text, TEXT_SHADOW, TEXT_COLOR
#include "texture.h" // Para Texture
#include "utils.h" // Para Color, easeOutQuint, NO_TEXT_COLOR
// Constructor // Constructor
HiScoreTable::HiScoreTable() HiScoreTable::HiScoreTable()
: renderer_(Screen::get()->getRenderer()), : renderer_(Screen::get()->getRenderer()),
backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
fade_(std::make_unique<Fade>()), fade_(std::make_unique<Fade>()),
background_(std::make_unique<Background>()), background_(std::make_unique<Background>()),
counter_(0), counter_(0),
ticks_(0), ticks_(0),
view_area_(SDL_FRect{0, 0, static_cast<float>(param.game.width), static_cast<float>(param.game.height)}), view_area_(SDL_FRect{0, 0, static_cast<float>(param.game.width), static_cast<float>(param.game.height)}),
fade_mode_(FadeMode::IN), fade_mode_(FadeMode::IN),
background_fade_color_(Color(0, 0, 0)) background_fade_color_(Color(0, 0, 0)) {
{ // Inicializa el resto
// Inicializa el resto Section::name = Section::Name::HI_SCORE_TABLE;
Section::name = Section::Name::HI_SCORE_TABLE; SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND); initFade();
initFade(); initBackground();
initBackground(); iniEntryColors();
iniEntryColors(); createSprites();
createSprites();
} }
// Destructor // Destructor
HiScoreTable::~HiScoreTable() HiScoreTable::~HiScoreTable() {
{ SDL_DestroyTexture(backbuffer_);
SDL_DestroyTexture(backbuffer_); Options::settings.clearLastHiScoreEntries();
Options::settings.clearLastHiScoreEntries();
} }
// Actualiza las variables // Actualiza las variables
void HiScoreTable::update() void HiScoreTable::update() {
{ if (SDL_GetTicks() - ticks_ > param.game.speed) {
if (SDL_GetTicks() - ticks_ > param.game.speed) // Actualiza el contador de ticks
{ ticks_ = SDL_GetTicks();
// Actualiza el contador de ticks
ticks_ = SDL_GetTicks();
// Actualiza las posiciones de los sprites de texto // Actualiza las posiciones de los sprites de texto
updateSprites(); updateSprites();
// Actualiza el fondo // Actualiza el fondo
background_->update(); background_->update();
// Gestiona el fade // Gestiona el fade
updateFade(); updateFade();
// Gestiona el contador y sus eventos // Gestiona el contador y sus eventos
updateCounter(); updateCounter();
// Dibuja los sprites en la textura // Dibuja los sprites en la textura
fillTexture(); fillTexture();
// Actualiza el objeto screen // Actualiza el objeto screen
Screen::get()->update(); Screen::get()->update();
// Actualiza las variables de globalInputs // Actualiza las variables de globalInputs
} }
} }
// Dibuja los sprites en la textura // Dibuja los sprites en la textura
void HiScoreTable::fillTexture() void HiScoreTable::fillTexture() {
{ // Pinta en el backbuffer el texto y los sprites
// Pinta en el backbuffer el texto y los sprites auto temp = SDL_GetRenderTarget(renderer_);
auto temp = SDL_GetRenderTarget(renderer_); SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_SetRenderTarget(renderer_, backbuffer_); SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0); SDL_RenderClear(renderer_);
SDL_RenderClear(renderer_);
// Escribe el texto: Mejores puntuaciones // Escribe el texto: Mejores puntuaciones
header_->render(); header_->render();
// Escribe los nombres de la tabla de puntuaciones // Escribe los nombres de la tabla de puntuaciones
for (auto const &entry : entry_names_) for (auto const &entry : entry_names_) {
{ entry->render();
entry->render(); }
}
// Cambia el destino de renderizado // Cambia el destino de renderizado
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
} }
// Pinta en pantalla // Pinta en pantalla
void HiScoreTable::render() void HiScoreTable::render() {
{ // Prepara para empezar a dibujar en la textura de juego
// Prepara para empezar a dibujar en la textura de juego Screen::get()->start();
Screen::get()->start();
// Limpia la pantalla // Limpia la pantalla
Screen::get()->clean(); Screen::get()->clean();
// Pinta el fondo // Pinta el fondo
background_->render(); background_->render();
// Establece la ventana del backbuffer // Establece la ventana del backbuffer
view_area_.y = std::max(0.0f, param.game.height - counter_ + 100); view_area_.y = std::max(0.0f, param.game.height - counter_ + 100);
// Copia el backbuffer al renderizador // Copia el backbuffer al renderizador
SDL_RenderTexture(renderer_, backbuffer_, nullptr, &view_area_); SDL_RenderTexture(renderer_, backbuffer_, nullptr, &view_area_);
// Renderiza el fade // Renderiza el fade
fade_->render(); fade_->render();
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
Screen::get()->render(); Screen::get()->render();
} }
// Comprueba los eventos // Comprueba los eventos
void HiScoreTable::checkEvents() void HiScoreTable::checkEvents() {
{ SDL_Event event;
SDL_Event event; while (SDL_PollEvent(&event)) {
while (SDL_PollEvent(&event)) GlobalEvents::check(event);
{ }
GlobalEvents::check(event);
}
} }
// Comprueba las entradas // Comprueba las entradas
void HiScoreTable::checkInput() void HiScoreTable::checkInput() {
{ Input::get()->update();
Input::get()->update(); GlobalInputs::check();
GlobalInputs::check();
} }
// Bucle para la pantalla de instrucciones // Bucle para la pantalla de instrucciones
void HiScoreTable::run() void HiScoreTable::run() {
{ Audio::get()->playMusic("title.ogg");
Audio::get()->playMusic("title.ogg"); while (Section::name == Section::Name::HI_SCORE_TABLE) {
while (Section::name == Section::Name::HI_SCORE_TABLE) checkInput();
{ update();
checkInput(); checkEvents(); // Tiene que ir antes del render
update(); render();
checkEvents(); // Tiene que ir antes del render }
render();
}
} }
// Gestiona el fade // Gestiona el fade
void HiScoreTable::updateFade() void HiScoreTable::updateFade() {
{ fade_->update();
fade_->update();
if (fade_->hasEnded() && fade_mode_ == FadeMode::IN) if (fade_->hasEnded() && fade_mode_ == FadeMode::IN) {
{ fade_->reset();
fade_->reset(); fade_mode_ = FadeMode::OUT;
fade_mode_ = FadeMode::OUT; fade_->setMode(fade_mode_);
fade_->setMode(fade_mode_); }
}
if (fade_->hasEnded() && fade_mode_ == FadeMode::OUT) if (fade_->hasEnded() && fade_mode_ == FadeMode::OUT) {
{ Section::name = (Section::options == Section::Options::HI_SCORE_AFTER_PLAYING)
Section::name = (Section::options == Section::Options::HI_SCORE_AFTER_PLAYING) ? Section::Name::TITLE
? Section::Name::TITLE : Section::Name::INSTRUCTIONS;
: Section::Name::INSTRUCTIONS; Section::options = Section::Options::NONE;
Section::options = Section::Options::NONE; }
}
} }
// Convierte un entero a un string con separadores de miles // Convierte un entero a un string con separadores de miles
std::string HiScoreTable::format(int number) std::string HiScoreTable::format(int number) {
{ const std::string separator = ".";
const std::string separator = "."; const std::string score = std::to_string(number);
const std::string score = std::to_string(number);
auto index = (int)score.size() - 1; auto index = (int)score.size() - 1;
std::string result; std::string result;
auto i = 0; auto i = 0;
while (index >= 0) while (index >= 0) {
{ result = score.at(index) + result;
result = score.at(index) + result; index--;
index--; i++;
i++; if (i == 3) {
if (i == 3) i = 0;
{ result = separator + result;
i = 0; }
result = separator + result; }
}
}
return result; return result;
} }
// Crea los sprites con los textos // Crea los sprites con los textos
void HiScoreTable::createSprites() void HiScoreTable::createSprites() {
{ auto header_text = Resource::get()->getText("04b_25_grey");
auto header_text = Resource::get()->getText("04b_25_grey"); auto entry_text = Resource::get()->getText("smb2");
auto entry_text = Resource::get()->getText("smb2");
// Obtiene el tamaño de la textura // Obtiene el tamaño de la textura
float backbuffer_width; float backbuffer_width;
float backbuffer_height; float backbuffer_height;
SDL_GetTextureSize(backbuffer_, &backbuffer_width, &backbuffer_height); SDL_GetTextureSize(backbuffer_, &backbuffer_width, &backbuffer_height);
constexpr int ENTRY_LENGHT = 22; constexpr int ENTRY_LENGHT = 22;
constexpr int MAX_NAMES = 10; constexpr int MAX_NAMES = 10;
const int space_between_header = entry_text->getCharacterSize() * 4; const int space_between_header = entry_text->getCharacterSize() * 4;
const int space_between_lines = entry_text->getCharacterSize() * 2; const int space_between_lines = entry_text->getCharacterSize() * 2;
const int size = space_between_header + space_between_lines * (MAX_NAMES - 1) + entry_text->getCharacterSize(); const int size = space_between_header + space_between_lines * (MAX_NAMES - 1) + entry_text->getCharacterSize();
const int first_line = (param.game.height - size) / 2; const int first_line = (param.game.height - size) / 2;
// Crea el sprite para el texto de cabecera // Crea el sprite para el texto de cabecera
header_ = std::make_unique<Sprite>(header_text->writeDXToTexture(TEXT_COLOR, Lang::getText("[HIGHSCORE_TABLE] CAPTION"), -2, background_fade_color_.inverse().lighten(25))); header_ = std::make_unique<Sprite>(header_text->writeDXToTexture(TEXT_COLOR, Lang::getText("[HIGHSCORE_TABLE] CAPTION"), -2, background_fade_color_.inverse().lighten(25)));
header_->setPosition(param.game.game_area.center_x - (header_->getWidth() / 2), first_line); header_->setPosition(param.game.game_area.center_x - (header_->getWidth() / 2), first_line);
// Crea los sprites para las entradas en la tabla de puntuaciones // Crea los sprites para las entradas en la tabla de puntuaciones
const int animation = rand() % 4; const int animation = rand() % 4;
const std::string sample_line(ENTRY_LENGHT + 3, ' '); const std::string sample_line(ENTRY_LENGHT + 3, ' ');
auto sample_entry = std::make_unique<Sprite>(entry_text->writeDXToTexture(TEXT_SHADOW, sample_line, 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR)); auto sample_entry = std::make_unique<Sprite>(entry_text->writeDXToTexture(TEXT_SHADOW, sample_line, 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR));
const auto entry_width = sample_entry->getWidth(); const auto entry_width = sample_entry->getWidth();
for (int i = 0; i < MAX_NAMES; ++i) for (int i = 0; i < MAX_NAMES; ++i) {
{ const auto table_position = format(i + 1) + ". ";
const auto table_position = format(i + 1) + ". "; const auto score = format(Options::settings.hi_score_table.at(i).score);
const auto score = format(Options::settings.hi_score_table.at(i).score); const auto num_dots = ENTRY_LENGHT - Options::settings.hi_score_table.at(i).name.size() - score.size();
const auto num_dots = ENTRY_LENGHT - Options::settings.hi_score_table.at(i).name.size() - score.size(); const auto one_cc = Options::settings.hi_score_table.at(i).one_credit_complete ? " }" : "";
const auto one_cc = Options::settings.hi_score_table.at(i).one_credit_complete ? " }" : ""; std::string dots;
std::string dots; for (int j = 0; j < (int)num_dots; ++j) {
for (int j = 0; j < (int)num_dots; ++j) dots = dots + ".";
{ }
dots = dots + "."; const auto line = table_position + Options::settings.hi_score_table.at(i).name + dots + score + one_cc;
}
const auto line = table_position + Options::settings.hi_score_table.at(i).name + dots + score + one_cc;
entry_names_.emplace_back(std::make_shared<PathSprite>(entry_text->writeDXToTexture(TEXT_SHADOW, line, 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR))); entry_names_.emplace_back(std::make_shared<PathSprite>(entry_text->writeDXToTexture(TEXT_SHADOW, line, 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR)));
const int default_pos_x = (backbuffer_width - entry_width) / 2; const int default_pos_x = (backbuffer_width - entry_width) / 2;
const int pos_x = (i < 9) ? default_pos_x : default_pos_x - entry_text->getCharacterSize(); const int pos_x = (i < 9) ? default_pos_x : default_pos_x - entry_text->getCharacterSize();
const int pos_y = (i * space_between_lines) + first_line + space_between_header; const int pos_y = (i * space_between_lines) + first_line + space_between_header;
constexpr int steps = 80; constexpr int steps = 80;
switch (animation) switch (animation) {
{ case 0: // Ambos lados alternativamente
case 0: // Ambos lados alternativamente {
{ if (i % 2 == 0) {
if (i % 2 == 0) entry_names_.back()->addPath(-entry_names_.back()->getWidth(), pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
{ entry_names_.back()->setPosition(-entry_names_.back()->getWidth(), 0);
entry_names_.back()->addPath(-entry_names_.back()->getWidth(), pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint); } else {
entry_names_.back()->setPosition(-entry_names_.back()->getWidth(), 0); entry_names_.back()->addPath(backbuffer_width, pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
} entry_names_.back()->setPosition(backbuffer_width, 0);
else }
{ break;
entry_names_.back()->addPath(backbuffer_width, pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint); }
entry_names_.back()->setPosition(backbuffer_width, 0);
}
break;
}
case 1: // Entran por la izquierda case 1: // Entran por la izquierda
{ {
entry_names_.back()->addPath(-entry_names_.back()->getWidth(), pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint); entry_names_.back()->addPath(-entry_names_.back()->getWidth(), pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
entry_names_.back()->setPosition(-entry_names_.back()->getWidth(), 0); entry_names_.back()->setPosition(-entry_names_.back()->getWidth(), 0);
break; break;
} }
case 2: // Entran por la derecha case 2: // Entran por la derecha
{ {
entry_names_.back()->addPath(backbuffer_width, pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint); entry_names_.back()->addPath(backbuffer_width, pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
entry_names_.back()->setPosition(backbuffer_width, 0); entry_names_.back()->setPosition(backbuffer_width, 0);
break; break;
} }
case 3: // Entran desde la parte inferior case 3: // Entran desde la parte inferior
{ {
entry_names_.back()->addPath(backbuffer_height, pos_y, PathType::VERTICAL, pos_x, steps, easeOutQuint); entry_names_.back()->addPath(backbuffer_height, pos_y, PathType::VERTICAL, pos_x, steps, easeOutQuint);
entry_names_.back()->setPosition(0, backbuffer_height); entry_names_.back()->setPosition(0, backbuffer_height);
} }
default: default:
break; break;
} }
} }
} }
// Actualiza las posiciones de los sprites de texto // Actualiza las posiciones de los sprites de texto
void HiScoreTable::updateSprites() void HiScoreTable::updateSprites() {
{ constexpr int init_counter = 190;
constexpr int init_counter = 190; const int counter_between_entries = 16;
const int counter_between_entries = 16; if (counter_ >= init_counter) {
if (counter_ >= init_counter) const int counter2 = counter_ - init_counter;
{ if (counter2 % counter_between_entries == 0) {
const int counter2 = counter_ - init_counter; int index = counter2 / counter_between_entries;
if (counter2 % counter_between_entries == 0) if (index < static_cast<int>(entry_names_.size())) {
{ entry_names_.at(index)->enable();
int index = counter2 / counter_between_entries; }
if (index < static_cast<int>(entry_names_.size())) }
{ }
entry_names_.at(index)->enable(); for (auto const &entry : entry_names_) {
} entry->update();
} }
}
for (auto const &entry : entry_names_)
{
entry->update();
}
glowEntryNames(); glowEntryNames();
} }
// Inicializa el fade // Inicializa el fade
void HiScoreTable::initFade() void HiScoreTable::initFade() {
{ fade_->setColor(param.fade.color);
fade_->setColor(param.fade.color); fade_->setType(FadeType::RANDOM_SQUARE);
fade_->setType(FadeType::RANDOM_SQUARE); fade_->setPostDuration(param.fade.post_duration);
fade_->setPostDuration(param.fade.post_duration); fade_->setMode(fade_mode_);
fade_->setMode(fade_mode_); fade_->activate();
fade_->activate();
} }
// Inicializa el fondo // Inicializa el fondo
void HiScoreTable::initBackground() void HiScoreTable::initBackground() {
{ background_->setPos(param.game.game_area.rect);
background_->setPos(param.game.game_area.rect); background_->setCloudsSpeed(-0.1f);
background_->setCloudsSpeed(-0.1f);
const int lucky = rand() % 3; const int lucky = rand() % 3;
switch (lucky) switch (lucky) {
{ case 0: // Fondo verde
case 0: // Fondo verde {
{ background_->setGradientNumber(2);
background_->setGradientNumber(2); background_->setTransition(0.0f);
background_->setTransition(0.0f); background_->setSunProgression(1.0f);
background_->setSunProgression(1.0f); background_->setMoonProgression(0.0f);
background_->setMoonProgression(0.0f); background_fade_color_ = GREEN_SKY_COLOR;
background_fade_color_ = GREEN_SKY_COLOR; break;
break; }
}
case 1: // Fondo naranja case 1: // Fondo naranja
{ {
background_->setGradientNumber(1); background_->setGradientNumber(1);
background_->setTransition(0.0f); background_->setTransition(0.0f);
background_->setSunProgression(0.65f); background_->setSunProgression(0.65f);
background_->setMoonProgression(0.0f); background_->setMoonProgression(0.0f);
background_fade_color_ = PINK_SKY_COLOR; background_fade_color_ = PINK_SKY_COLOR;
break; break;
} }
case 2: // Fondo azul case 2: // Fondo azul
{ {
background_->setGradientNumber(0); background_->setGradientNumber(0);
background_->setTransition(0.0f); background_->setTransition(0.0f);
background_->setSunProgression(0.0f); background_->setSunProgression(0.0f);
background_->setMoonProgression(0.0f); background_->setMoonProgression(0.0f);
background_fade_color_ = BLUE_SKY_COLOR; background_fade_color_ = BLUE_SKY_COLOR;
break; break;
} }
default: default:
break; break;
} }
} }
// Obtiene un color del vector de colores de entradas // Obtiene un color del vector de colores de entradas
Color HiScoreTable::getEntryColor(int counter_) Color HiScoreTable::getEntryColor(int counter_) {
{ int cycle_length = entry_colors_.size() * 2 - 2;
int cycle_length = entry_colors_.size() * 2 - 2; size_t n = counter_ % cycle_length;
size_t n = counter_ % cycle_length;
size_t index; size_t index;
if (n < entry_colors_.size()) if (n < entry_colors_.size()) {
{ index = n; // Avanza: 0,1,2,3
index = n; // Avanza: 0,1,2,3 } else {
} index = 2 * (entry_colors_.size() - 1) - n; // Retrocede: 2,1
else }
{
index = 2 * (entry_colors_.size() - 1) - n; // Retrocede: 2,1
}
return entry_colors_[index]; return entry_colors_[index];
} }
// Inicializa los colores de las entradas // Inicializa los colores de las entradas
void HiScoreTable::iniEntryColors() void HiScoreTable::iniEntryColors() {
{ entry_colors_.clear();
entry_colors_.clear(); entry_colors_.emplace_back(background_fade_color_.inverse().lighten(75));
entry_colors_.emplace_back(background_fade_color_.inverse().lighten(75)); entry_colors_.emplace_back(background_fade_color_.inverse().lighten(50));
entry_colors_.emplace_back(background_fade_color_.inverse().lighten(50)); entry_colors_.emplace_back(background_fade_color_.inverse().lighten(25));
entry_colors_.emplace_back(background_fade_color_.inverse().lighten(25)); entry_colors_.emplace_back(background_fade_color_.inverse());
entry_colors_.emplace_back(background_fade_color_.inverse());
} }
// Hace brillar los nombres de la tabla de records // Hace brillar los nombres de la tabla de records
void HiScoreTable::glowEntryNames() void HiScoreTable::glowEntryNames() {
{ const Color entry_color = getEntryColor(counter_ / 5);
const Color entry_color = getEntryColor(counter_ / 5); for (const auto &entry_index : Options::settings.last_hi_score_entry) {
for (const auto &entry_index : Options::settings.last_hi_score_entry) if (entry_index != -1) {
{ entry_names_.at(entry_index)->getTexture()->setColor(entry_color);
if (entry_index != -1) }
{ }
entry_names_.at(entry_index)->getTexture()->setColor(entry_color);
}
}
} }
// Gestiona el contador // Gestiona el contador
void HiScoreTable::updateCounter() void HiScoreTable::updateCounter() {
{ ++counter_;
++counter_;
if (counter_ == 150) if (counter_ == 150) {
{ background_->setColor(background_fade_color_.darken());
background_->setColor(background_fade_color_.darken()); background_->setAlpha(96);
background_->setAlpha(96); }
}
if (counter_ == COUNTER_END_) if (counter_ == COUNTER_END_) {
{ fade_->activate();
fade_->activate(); }
}
} }
+54 -54
View File
@@ -1,11 +1,12 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para Uint16, SDL_FRect, SDL_Renderer, SDL_Texture, Uint64, Uint8 #include <SDL3/SDL.h> // Para Uint16, SDL_FRect, SDL_Renderer, SDL_Texture, Uint64, Uint8
#include <memory> // Para unique_ptr, shared_ptr
#include <string> // Para string
#include <vector> // Para vector
#include "utils.h" // Para Color #include <memory> // Para unique_ptr, shared_ptr
#include <string> // Para string
#include <vector> // Para vector
#include "utils.h" // Para Color
class Background; class Background;
class Fade; class Fade;
@@ -15,64 +16,63 @@ enum class FadeMode : Uint8;
struct Path; struct Path;
/* /*
Esta clase gestiona un estado del programa. Se encarga de mostrar la tabla con las puntuaciones Esta clase gestiona un estado del programa. Se encarga de mostrar la tabla con las puntuaciones
más altas. Para ello utiliza un objeto que se encarga de pintar el fondo y una textura más altas. Para ello utiliza un objeto que se encarga de pintar el fondo y una textura
sobre la que escribe las puntuaciones. Esta textura se recorre modificando la ventana de vista sobre la que escribe las puntuaciones. Esta textura se recorre modificando la ventana de vista
para dar el efecto de que la textura se mueve sobre la pantalla. para dar el efecto de que la textura se mueve sobre la pantalla.
Para mejorar la legibilidad de los textos, el objeto que dibuja el fondo es capaz de modificar Para mejorar la legibilidad de los textos, el objeto que dibuja el fondo es capaz de modificar
su atenuación. su atenuación.
*/ */
// Clase HiScoreTable // Clase HiScoreTable
class HiScoreTable class HiScoreTable {
{ public:
public: // Constructor
// Constructor HiScoreTable();
HiScoreTable();
// Destructor // Destructor
~HiScoreTable(); ~HiScoreTable();
// Bucle principal // Bucle principal
void run(); void run();
private: private:
// --- Constantes --- // --- Constantes ---
static constexpr Uint16 COUNTER_END_ = 800; // Valor final para el contador static constexpr Uint16 COUNTER_END_ = 800; // Valor final para el contador
// --- Objetos y punteros --- // --- Objetos y punteros ---
SDL_Renderer *renderer_; // El renderizador de la ventana SDL_Renderer *renderer_; // El renderizador de la ventana
SDL_Texture *backbuffer_; // Textura para usar como backbuffer SDL_Texture *backbuffer_; // Textura para usar como backbuffer
std::unique_ptr<Fade> fade_; // Objeto para renderizar fades std::unique_ptr<Fade> fade_; // Objeto para renderizar fades
std::unique_ptr<Background> background_; // Objeto para dibujar el fondo del juego std::unique_ptr<Background> background_; // Objeto para dibujar el fondo del juego
std::unique_ptr<Sprite> header_; // Sprite con la cabecera del texto std::unique_ptr<Sprite> header_; // Sprite con la cabecera del texto
std::vector<std::shared_ptr<PathSprite>> entry_names_; // Lista con los sprites de cada uno de los nombres de la tabla de records std::vector<std::shared_ptr<PathSprite>> entry_names_; // Lista con los sprites de cada uno de los nombres de la tabla de records
std::vector<Path> paths_; // Vector con los recorridos precalculados std::vector<Path> paths_; // Vector con los recorridos precalculados
// --- Variables --- // --- Variables ---
Uint16 counter_ = 0; // Contador Uint16 counter_ = 0; // Contador
Uint64 ticks_; // Contador de ticks para ajustar la velocidad del programa Uint64 ticks_; // Contador de ticks para ajustar la velocidad del programa
SDL_FRect view_area_; // Parte de la textura que se muestra en pantalla SDL_FRect view_area_; // Parte de la textura que se muestra en pantalla
FadeMode fade_mode_; // Modo de fade a utilizar FadeMode fade_mode_; // Modo de fade a utilizar
Color background_fade_color_; // Color de atenuación del fondo Color background_fade_color_; // Color de atenuación del fondo
std::vector<Color> entry_colors_; // Colores para destacar las entradas en la tabla std::vector<Color> entry_colors_; // Colores para destacar las entradas en la tabla
// --- Métodos internos --- // --- Métodos internos ---
void update(); // Actualiza las variables void update(); // Actualiza las variables
void render(); // Pinta en pantalla void render(); // Pinta en pantalla
void checkEvents(); // Comprueba los eventos void checkEvents(); // Comprueba los eventos
void checkInput(); // Comprueba las entradas void checkInput(); // Comprueba las entradas
std::string format(int number); // Convierte un entero a un string con separadores de miles std::string format(int number); // Convierte un entero a un string con separadores de miles
void fillTexture(); // Dibuja los sprites en la textura void fillTexture(); // Dibuja los sprites en la textura
void updateFade(); // Gestiona el fade void updateFade(); // Gestiona el fade
void createSprites(); // Crea los sprites con los textos void createSprites(); // Crea los sprites con los textos
void updateSprites(); // Actualiza las posiciones de los sprites de texto void updateSprites(); // Actualiza las posiciones de los sprites de texto
void initFade(); // Inicializa el fade void initFade(); // Inicializa el fade
void initBackground(); // Inicializa el fondo void initBackground(); // Inicializa el fondo
Color getEntryColor(int counter_); // Obtiene un color del vector de colores de entradas Color getEntryColor(int counter_); // Obtiene un color del vector de colores de entradas
void iniEntryColors(); // Inicializa los colores de las entradas void iniEntryColors(); // Inicializa los colores de las entradas
void glowEntryNames(); // Hace brillar los nombres de la tabla de records void glowEntryNames(); // Hace brillar los nombres de la tabla de records
void updateCounter(); // Gestiona el contador void updateCounter(); // Gestiona el contador
}; };
+255 -286
View File
@@ -1,382 +1,351 @@
#include "instructions.h" #include "instructions.h"
#include <SDL3/SDL.h> // Para SDL_GetTicks, SDL_SetRenderTarget, SDL_Re... #include <SDL3/SDL.h> // Para SDL_GetTicks, SDL_SetRenderTarget, SDL_Re...
#include <algorithm> // Para max
#include <array> // Para array
#include <string> // Para basic_string, string
#include <utility> // Para move
#include <vector> // Para vector
#include "audio.h" // Para Audio #include <algorithm> // Para max
#include "fade.h" // Para Fade, FadeMode, FadeType #include <array> // Para array
#include "global_events.h" // Para check #include <string> // Para basic_string, string
#include "global_inputs.h" // Para check #include <utility> // Para move
#include "input.h" // Para Input #include <vector> // Para vector
#include "lang.h" // Para getText
#include "param.h" // Para Param, param, ParamGame, ParamFade, Param... #include "audio.h" // Para Audio
#include "resource.h" // Para Resource #include "fade.h" // Para Fade, FadeMode, FadeType
#include "screen.h" // Para Screen #include "global_events.h" // Para check
#include "section.h" // Para Name, name, Options, options #include "global_inputs.h" // Para check
#include "sprite.h" // Para Sprite #include "input.h" // Para Input
#include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR, TEXT_SHADOW #include "lang.h" // Para getText
#include "tiled_bg.h" // Para TiledBG, TiledBGMode #include "param.h" // Para Param, param, ParamGame, ParamFade, Param...
#include "utils.h" // Para Color, SHADOW_TEXT_COLOR, Zone, NO_TEXT_C... #include "resource.h" // Para Resource
#include "screen.h" // Para Screen
#include "section.h" // Para Name, name, Options, options
#include "sprite.h" // Para Sprite
#include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR, TEXT_SHADOW
#include "tiled_bg.h" // Para TiledBG, TiledBGMode
#include "utils.h" // Para Color, SHADOW_TEXT_COLOR, Zone, NO_TEXT_C...
// Constructor // Constructor
Instructions::Instructions() Instructions::Instructions()
: renderer_(Screen::get()->getRenderer()), : renderer_(Screen::get()->getRenderer()),
texture_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), texture_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
text_(Resource::get()->getText("smb2")), text_(Resource::get()->getText("smb2")),
tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::STATIC)), tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::STATIC)),
fade_(std::make_unique<Fade>()) fade_(std::make_unique<Fade>()) {
{ // Configura las texturas
// Configura las texturas SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(texture_, SDL_BLENDMODE_BLEND);
SDL_SetTextureBlendMode(texture_, SDL_BLENDMODE_BLEND);
// Inicializa variables // Inicializa variables
Section::name = Section::Name::INSTRUCTIONS; Section::name = Section::Name::INSTRUCTIONS;
view_ = param.game.game_area.rect; view_ = param.game.game_area.rect;
// Inicializa objetos // Inicializa objetos
tiled_bg_->setColor(param.title.bg_color); tiled_bg_->setColor(param.title.bg_color);
fade_->setColor(param.fade.color); fade_->setColor(param.fade.color);
fade_->setType(FadeType::FULLSCREEN); fade_->setType(FadeType::FULLSCREEN);
fade_->setPostDuration(param.fade.post_duration); fade_->setPostDuration(param.fade.post_duration);
fade_->setMode(FadeMode::IN); fade_->setMode(FadeMode::IN);
fade_->activate(); fade_->activate();
// Inicializa las líneas con un retraso progresivo de 50 ms // Inicializa las líneas con un retraso progresivo de 50 ms
lines_ = initializeLines(256); lines_ = initializeLines(256);
// Rellena la textura de texto // Rellena la textura de texto
fillTexture(); fillTexture();
// Inicializa los sprites de los items // Inicializa los sprites de los items
iniSprites(); iniSprites();
} }
// Destructor // Destructor
Instructions::~Instructions() Instructions::~Instructions() {
{ item_textures_.clear();
item_textures_.clear(); sprites_.clear();
sprites_.clear();
SDL_DestroyTexture(backbuffer_); SDL_DestroyTexture(backbuffer_);
SDL_DestroyTexture(texture_); SDL_DestroyTexture(texture_);
} }
// Inicializa los sprites de los items // Inicializa los sprites de los items
void Instructions::iniSprites() void Instructions::iniSprites() {
{ // Inicializa las texturas
// Inicializa las texturas item_textures_.emplace_back(Resource::get()->getTexture("item_points1_disk.png"));
item_textures_.emplace_back(Resource::get()->getTexture("item_points1_disk.png")); item_textures_.emplace_back(Resource::get()->getTexture("item_points2_gavina.png"));
item_textures_.emplace_back(Resource::get()->getTexture("item_points2_gavina.png")); item_textures_.emplace_back(Resource::get()->getTexture("item_points3_pacmar.png"));
item_textures_.emplace_back(Resource::get()->getTexture("item_points3_pacmar.png")); item_textures_.emplace_back(Resource::get()->getTexture("item_clock.png"));
item_textures_.emplace_back(Resource::get()->getTexture("item_clock.png")); item_textures_.emplace_back(Resource::get()->getTexture("item_coffee.png"));
item_textures_.emplace_back(Resource::get()->getTexture("item_coffee.png"));
// Inicializa los sprites // Inicializa los sprites
for (int i = 0; i < (int)item_textures_.size(); ++i) for (int i = 0; i < (int)item_textures_.size(); ++i) {
{ auto sprite = std::make_unique<Sprite>(item_textures_[i], 0, 0, param.game.item_size, param.game.item_size);
auto sprite = std::make_unique<Sprite>(item_textures_[i], 0, 0, param.game.item_size, param.game.item_size); sprite->setPosition((SDL_FPoint){sprite_pos_.x, sprite_pos_.y + ((param.game.item_size + item_space_) * i)});
sprite->setPosition((SDL_FPoint){sprite_pos_.x, sprite_pos_.y + ((param.game.item_size + item_space_) * i)}); sprites_.push_back(std::move(sprite));
sprites_.push_back(std::move(sprite)); }
}
} }
// Actualiza los sprites // Actualiza los sprites
void Instructions::updateSprites() void Instructions::updateSprites() {
{ SDL_FRect src_rect = {0, 0, param.game.item_size, param.game.item_size};
SDL_FRect src_rect = {0, 0, param.game.item_size, param.game.item_size};
// Disquito // Disquito
src_rect.y = param.game.item_size * (((counter_ + 12) / 36) % 2); src_rect.y = param.game.item_size * (((counter_ + 12) / 36) % 2);
sprites_[0]->setSpriteClip(src_rect); sprites_[0]->setSpriteClip(src_rect);
// Gavina // Gavina
src_rect.y = param.game.item_size * (((counter_ + 9) / 36) % 2); src_rect.y = param.game.item_size * (((counter_ + 9) / 36) % 2);
sprites_[1]->setSpriteClip(src_rect); sprites_[1]->setSpriteClip(src_rect);
// Pacmar // Pacmar
src_rect.y = param.game.item_size * (((counter_ + 6) / 36) % 2); src_rect.y = param.game.item_size * (((counter_ + 6) / 36) % 2);
sprites_[2]->setSpriteClip(src_rect); sprites_[2]->setSpriteClip(src_rect);
// Time Stopper // Time Stopper
src_rect.y = param.game.item_size * (((counter_ + 3) / 36) % 2); src_rect.y = param.game.item_size * (((counter_ + 3) / 36) % 2);
sprites_[3]->setSpriteClip(src_rect); sprites_[3]->setSpriteClip(src_rect);
// Coffee // Coffee
src_rect.y = param.game.item_size * (((counter_ + 0) / 36) % 2); src_rect.y = param.game.item_size * (((counter_ + 0) / 36) % 2);
sprites_[4]->setSpriteClip(src_rect); sprites_[4]->setSpriteClip(src_rect);
} }
// Rellena la textura de texto // Rellena la textura de texto
void Instructions::fillTexture() void Instructions::fillTexture() {
{ const int desp_x = param.game.item_size + 8;
const int desp_x = param.game.item_size + 8;
// Modifica el renderizador para pintar en la textura // Modifica el renderizador para pintar en la textura
auto temp = SDL_GetRenderTarget(renderer_); auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, texture_); SDL_SetRenderTarget(renderer_, texture_);
// Limpia la textura // Limpia la textura
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0); SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
SDL_RenderClear(renderer_); SDL_RenderClear(renderer_);
// Constantes // Constantes
constexpr int num_lines = 4; constexpr int num_lines = 4;
constexpr int num_item_lines = 4; constexpr int num_item_lines = 4;
constexpr int num_post_headers = 2; constexpr int num_post_headers = 2;
constexpr int num_pre_headers = 1; constexpr int num_pre_headers = 1;
constexpr int space_post_header = 20; constexpr int space_post_header = 20;
constexpr int space_pre_header = 28; constexpr int space_pre_header = 28;
const int space_between_lines = text_->getCharacterSize() * 1.5f; const int space_between_lines = text_->getCharacterSize() * 1.5f;
const int space_between_item_lines = param.game.item_size + item_space_; const int space_between_item_lines = param.game.item_size + item_space_;
const int space_new_paragraph = space_between_lines * 0.5f; const int space_new_paragraph = space_between_lines * 0.5f;
const int size = (num_lines * space_between_lines) + (num_item_lines * space_between_item_lines) + (num_post_headers * space_post_header) + (num_pre_headers * space_pre_header) + (space_new_paragraph); const int size = (num_lines * space_between_lines) + (num_item_lines * space_between_item_lines) + (num_post_headers * space_post_header) + (num_pre_headers * space_pre_header) + (space_new_paragraph);
const int first_line = (param.game.height - size) / 2; const int first_line = (param.game.height - size) / 2;
// Calcula cual es el texto más largo de las descripciones de los items // Calcula cual es el texto más largo de las descripciones de los items
int lenght = 0; int lenght = 0;
const std::array<std::string, 5> ITEM_DESCRIPTIONS = { const std::array<std::string, 5> ITEM_DESCRIPTIONS = {
Lang::getText("[INSTRUCTIONS] 07"), Lang::getText("[INSTRUCTIONS] 07"),
Lang::getText("[INSTRUCTIONS] 08"), Lang::getText("[INSTRUCTIONS] 08"),
Lang::getText("[INSTRUCTIONS] 09"), Lang::getText("[INSTRUCTIONS] 09"),
Lang::getText("[INSTRUCTIONS] 10"), Lang::getText("[INSTRUCTIONS] 10"),
Lang::getText("[INSTRUCTIONS] 11")}; Lang::getText("[INSTRUCTIONS] 11")};
for (const auto &desc : ITEM_DESCRIPTIONS) for (const auto &desc : ITEM_DESCRIPTIONS) {
{ const int l = text_->lenght(desc);
const int l = text_->lenght(desc); lenght = l > lenght ? l : lenght;
lenght = l > lenght ? l : lenght; }
} const int ANCHOR_ITEM = (param.game.width - (lenght + desp_x)) / 2;
const int ANCHOR_ITEM = (param.game.width - (lenght + desp_x)) / 2;
constexpr Color ORANGE_COLOR = Color(0XFF, 0X7A, 0X00); constexpr Color ORANGE_COLOR = Color(0XFF, 0X7A, 0X00);
// Escribe el texto de las instrucciones // Escribe el texto de las instrucciones
text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, first_line, Lang::getText("[INSTRUCTIONS] 01"), 1, ORANGE_COLOR, 1, SHADOW_TEXT_COLOR); text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, first_line, Lang::getText("[INSTRUCTIONS] 01"), 1, ORANGE_COLOR, 1, SHADOW_TEXT_COLOR);
const int anchor1 = first_line + space_post_header; const int anchor1 = first_line + space_post_header;
text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_between_lines * 0, Lang::getText("[INSTRUCTIONS] 02"), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR); text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_between_lines * 0, Lang::getText("[INSTRUCTIONS] 02"), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_between_lines * 1, Lang::getText("[INSTRUCTIONS] 03"), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR); text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_between_lines * 1, Lang::getText("[INSTRUCTIONS] 03"), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_new_paragraph + space_between_lines * 2, Lang::getText("[INSTRUCTIONS] 04"), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR); text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_new_paragraph + space_between_lines * 2, Lang::getText("[INSTRUCTIONS] 04"), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_new_paragraph + space_between_lines * 3, Lang::getText("[INSTRUCTIONS] 05"), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR); text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_new_paragraph + space_between_lines * 3, Lang::getText("[INSTRUCTIONS] 05"), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
// Escribe el texto de los objetos y sus puntos // Escribe el texto de los objetos y sus puntos
const int anchor2 = anchor1 + space_pre_header + space_new_paragraph + space_between_lines * 3; const int anchor2 = anchor1 + space_pre_header + space_new_paragraph + space_between_lines * 3;
text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor2, Lang::getText("[INSTRUCTIONS] 06"), 1, ORANGE_COLOR, 1, SHADOW_TEXT_COLOR); text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor2, Lang::getText("[INSTRUCTIONS] 06"), 1, ORANGE_COLOR, 1, SHADOW_TEXT_COLOR);
const int anchor3 = anchor2 + space_post_header; const int anchor3 = anchor2 + space_post_header;
text_->writeShadowed(ANCHOR_ITEM + desp_x, anchor3 + space_between_item_lines * 0, Lang::getText("[INSTRUCTIONS] 07"), SHADOW_TEXT_COLOR); text_->writeShadowed(ANCHOR_ITEM + desp_x, anchor3 + space_between_item_lines * 0, Lang::getText("[INSTRUCTIONS] 07"), SHADOW_TEXT_COLOR);
text_->writeShadowed(ANCHOR_ITEM + desp_x, anchor3 + space_between_item_lines * 1, Lang::getText("[INSTRUCTIONS] 08"), SHADOW_TEXT_COLOR); text_->writeShadowed(ANCHOR_ITEM + desp_x, anchor3 + space_between_item_lines * 1, Lang::getText("[INSTRUCTIONS] 08"), SHADOW_TEXT_COLOR);
text_->writeShadowed(ANCHOR_ITEM + desp_x, anchor3 + space_between_item_lines * 2, Lang::getText("[INSTRUCTIONS] 09"), SHADOW_TEXT_COLOR); text_->writeShadowed(ANCHOR_ITEM + desp_x, anchor3 + space_between_item_lines * 2, Lang::getText("[INSTRUCTIONS] 09"), SHADOW_TEXT_COLOR);
text_->writeShadowed(ANCHOR_ITEM + desp_x, anchor3 + space_between_item_lines * 3, Lang::getText("[INSTRUCTIONS] 10"), SHADOW_TEXT_COLOR); text_->writeShadowed(ANCHOR_ITEM + desp_x, anchor3 + space_between_item_lines * 3, Lang::getText("[INSTRUCTIONS] 10"), SHADOW_TEXT_COLOR);
text_->writeShadowed(ANCHOR_ITEM + desp_x, anchor3 + space_between_item_lines * 4, Lang::getText("[INSTRUCTIONS] 11"), SHADOW_TEXT_COLOR); text_->writeShadowed(ANCHOR_ITEM + desp_x, anchor3 + space_between_item_lines * 4, Lang::getText("[INSTRUCTIONS] 11"), SHADOW_TEXT_COLOR);
// Deja el renderizador como estaba // Deja el renderizador como estaba
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
// Da valor a la variable // Da valor a la variable
sprite_pos_.x = ANCHOR_ITEM; sprite_pos_.x = ANCHOR_ITEM;
sprite_pos_.y = anchor3 - ((param.game.item_size - text_->getCharacterSize()) / 2); sprite_pos_.y = anchor3 - ((param.game.item_size - text_->getCharacterSize()) / 2);
} }
// Rellena el backbuffer // Rellena el backbuffer
void Instructions::fillBackbuffer() void Instructions::fillBackbuffer() {
{ // Modifica el renderizador para pintar en la textura
// Modifica el renderizador para pintar en la textura auto temp = SDL_GetRenderTarget(renderer_);
auto temp = SDL_GetRenderTarget(renderer_); SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_SetRenderTarget(renderer_, backbuffer_);
// Limpia la textura // Limpia la textura
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0); SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
SDL_RenderClear(renderer_); SDL_RenderClear(renderer_);
// Coloca el texto de fondo // Coloca el texto de fondo
SDL_RenderTexture(renderer_, texture_, nullptr, nullptr); SDL_RenderTexture(renderer_, texture_, nullptr, nullptr);
// Dibuja los sprites // Dibuja los sprites
for (auto &sprite : sprites_) for (auto &sprite : sprites_) {
{ sprite->render();
sprite->render(); }
}
// Deja el renderizador como estaba // Deja el renderizador como estaba
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
} }
// Actualiza las variables // Actualiza las variables
void Instructions::update() void Instructions::update() {
{ if (SDL_GetTicks() - ticks_ > param.game.speed) {
if (SDL_GetTicks() - ticks_ > param.game.speed) // Actualiza el contador de ticks
{ ticks_ = SDL_GetTicks();
// Actualiza el contador de ticks
ticks_ = SDL_GetTicks();
// Actualiza el objeto screen // Actualiza el objeto screen
Screen::get()->update(); Screen::get()->update();
// Incrementa el contador // Incrementa el contador
counter_++; counter_++;
// Actualiza los sprites // Actualiza los sprites
updateSprites(); updateSprites();
// Gestiona la textura con los graficos // Gestiona la textura con los graficos
updateBackbuffer(); updateBackbuffer();
// Actualiza el mosaico de fondo // Actualiza el mosaico de fondo
tiled_bg_->update(); tiled_bg_->update();
// Actualiza el objeto "fade" // Actualiza el objeto "fade"
fade_->update(); fade_->update();
// Rellena el backbuffer // Rellena el backbuffer
fillBackbuffer(); fillBackbuffer();
} }
} }
// Pinta en pantalla // Pinta en pantalla
void Instructions::render() void Instructions::render() {
{ // Prepara para empezar a dibujar en la textura de juego
// Prepara para empezar a dibujar en la textura de juego Screen::get()->start();
Screen::get()->start();
// Limpia la pantalla // Limpia la pantalla
Screen::get()->clean(); Screen::get()->clean();
// Dibuja el mosacico de fondo // Dibuja el mosacico de fondo
tiled_bg_->render(); tiled_bg_->render();
// Copia la textura y el backbuffer al renderizador // Copia la textura y el backbuffer al renderizador
if (view_.y == 0) if (view_.y == 0)
renderLines(renderer_, backbuffer_, lines_); renderLines(renderer_, backbuffer_, lines_);
else else
SDL_RenderTexture(renderer_, backbuffer_, nullptr, &view_); SDL_RenderTexture(renderer_, backbuffer_, nullptr, &view_);
fade_->render(); fade_->render();
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
Screen::get()->render(); Screen::get()->render();
} }
// Comprueba los eventos // Comprueba los eventos
void Instructions::checkEvents() void Instructions::checkEvents() {
{ SDL_Event event;
SDL_Event event; while (SDL_PollEvent(&event)) {
while (SDL_PollEvent(&event)) GlobalEvents::check(event);
{ }
GlobalEvents::check(event);
}
} }
// Comprueba las entradas // Comprueba las entradas
void Instructions::checkInput() void Instructions::checkInput() {
{ Input::get()->update();
Input::get()->update(); GlobalInputs::check();
GlobalInputs::check();
} }
// Bucle para la pantalla de instrucciones // Bucle para la pantalla de instrucciones
void Instructions::run() void Instructions::run() {
{ Audio::get()->playMusic("title.ogg");
Audio::get()->playMusic("title.ogg"); while (Section::name == Section::Name::INSTRUCTIONS) {
while (Section::name == Section::Name::INSTRUCTIONS) checkInput();
{ update();
checkInput(); checkEvents(); // Tiene que ir antes del render
update(); render();
checkEvents(); // Tiene que ir antes del render }
render();
}
} }
// Método para inicializar las líneas // Método para inicializar las líneas
std::vector<Line> Instructions::initializeLines(int height) std::vector<Line> Instructions::initializeLines(int height) {
{ std::vector<Line> lines;
std::vector<Line> lines; for (int y = 0; y < height; y++) {
for (int y = 0; y < height; y++) int direction = (y % 2 == 0) ? -1 : 1; // Pares a la izquierda, impares a la derecha
{ lines.emplace_back(y, 0.0f, direction);
int direction = (y % 2 == 0) ? -1 : 1; // Pares a la izquierda, impares a la derecha }
lines.emplace_back(y, 0.0f, direction); return lines;
}
return lines;
} }
// Método para mover las líneas con suavizado // Método para mover las líneas con suavizado
bool Instructions::moveLines(std::vector<Line> &lines, int width, float duration, Uint32 startDelay) bool Instructions::moveLines(std::vector<Line> &lines, int width, float duration, Uint32 startDelay) {
{ Uint32 current_time = SDL_GetTicks();
Uint32 current_time = SDL_GetTicks(); bool all_lines_off_screen = true;
bool all_lines_off_screen = true;
for (auto &line : lines) for (auto &line : lines) {
{ // Establecer startTime en el primer cuadro de animación
// Establecer startTime en el primer cuadro de animación if (line.startTime == 0) {
if (line.startTime == 0) line.startTime = current_time + line.y * startDelay;
{ }
line.startTime = current_time + line.y * startDelay;
}
float elapsed_time = (current_time - line.startTime) / 1000.0f; // Convertir a segundos float elapsed_time = (current_time - line.startTime) / 1000.0f; // Convertir a segundos
if (elapsed_time < 0) if (elapsed_time < 0) {
{ all_lines_off_screen = false; // Si aún no se debe mover esta línea, no están todas fuera de pantalla
all_lines_off_screen = false; // Si aún no se debe mover esta línea, no están todas fuera de pantalla continue;
continue; }
} if (elapsed_time >= duration) {
if (elapsed_time >= duration) continue; // Si la línea ha salido de los límites, no la muevas más
{ }
continue; // Si la línea ha salido de los límites, no la muevas más
}
float t = elapsed_time / duration; float t = elapsed_time / duration;
float smooth_factor = easeInOutQuint(t); float smooth_factor = easeInOutQuint(t);
line.x = line.direction * smooth_factor * width; line.x = line.direction * smooth_factor * width;
all_lines_off_screen = false; // Si alguna línea aún se está moviendo, no están todas fuera de pantalla all_lines_off_screen = false; // Si alguna línea aún se está moviendo, no están todas fuera de pantalla
} }
return all_lines_off_screen; return all_lines_off_screen;
} }
// Método para renderizar las líneas // Método para renderizar las líneas
void Instructions::renderLines(SDL_Renderer *renderer, SDL_Texture *texture, const std::vector<Line> &lines) void Instructions::renderLines(SDL_Renderer *renderer, SDL_Texture *texture, const std::vector<Line> &lines) {
{ for (const auto &LINE : lines) {
for (const auto &LINE : lines) SDL_FRect srcRect = {0, static_cast<float>(LINE.y), 320, 1};
{ SDL_FRect dstRect = {static_cast<float>(LINE.x), static_cast<float>(LINE.y), 320, 1};
SDL_FRect srcRect = {0, static_cast<float>(LINE.y), 320, 1}; SDL_RenderTexture(renderer, texture, &srcRect, &dstRect);
SDL_FRect dstRect = {static_cast<float>(LINE.x), static_cast<float>(LINE.y), 320, 1}; }
SDL_RenderTexture(renderer, texture, &srcRect, &dstRect);
}
} }
// Gestiona la textura con los graficos // Gestiona la textura con los graficos
void Instructions::updateBackbuffer() void Instructions::updateBackbuffer() {
{ // Establece la ventana del backbuffer
// Establece la ventana del backbuffer view_.y = std::max(0.0f, param.game.height - counter_ + 100);
view_.y = std::max(0.0f, param.game.height - counter_ + 100);
// Verifica si view_.y == 0 y gestiona el temporizador // Verifica si view_.y == 0 y gestiona el temporizador
if (view_.y == 0) if (view_.y == 0) {
{ if (!start_delay_triggered_) {
if (!start_delay_triggered_) // Activa el temporizador si no ha sido activado
{ start_delay_triggered_ = true;
// Activa el temporizador si no ha sido activado start_delay_time_ = SDL_GetTicks();
start_delay_triggered_ = true; } else if (SDL_GetTicks() - start_delay_time_ >= 4000) {
start_delay_time_ = SDL_GetTicks(); // Han pasado tres segundos, mover líneas
} all_lines_off_screen_ = moveLines(lines_, 320, 1.0f, 5);
else if (SDL_GetTicks() - start_delay_time_ >= 4000) }
{ }
// Han pasado tres segundos, mover líneas
all_lines_off_screen_ = moveLines(lines_, 320, 1.0f, 5);
}
}
// Comprueba si el contador ha llegado al final // Comprueba si el contador ha llegado al final
if (all_lines_off_screen_) if (all_lines_off_screen_) {
{ Section::name = Section::Name::TITLE;
Section::name = Section::Name::TITLE; Section::options = Section::Options::TITLE_1;
Section::options = Section::Options::TITLE_1; }
}
} }
+60 -61
View File
@@ -1,8 +1,9 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_Texture, Uint32, SDL_Renderer, SDL_FPoint, SDL_FRect, Uint64 #include <SDL3/SDL.h> // Para SDL_Texture, Uint32, SDL_Renderer, SDL_FPoint, SDL_FRect, Uint64
#include <memory> // Para unique_ptr, shared_ptr
#include <vector> // Para vector #include <memory> // Para unique_ptr, shared_ptr
#include <vector> // Para vector
class Fade; class Fade;
class Sprite; class Sprite;
@@ -11,78 +12,76 @@ class Texture;
class TiledBG; class TiledBG;
/* /*
Esta clase gestiona un estado del programa. Se encarga de poner en pantalla Esta clase gestiona un estado del programa. Se encarga de poner en pantalla
un texto explicativo para entender cómo se juega. un texto explicativo para entender cómo se juega.
Además muestra algunos items y explica para qué sirven. Además muestra algunos items y explica para qué sirven.
Utiliza dos texturas de apoyo, una con el texto ya escrito y otra donde se combina Utiliza dos texturas de apoyo, una con el texto ya escrito y otra donde se combina
tanto el texto de la primera textura como los sprites de los items. tanto el texto de la primera textura como los sprites de los items.
Finalmente, una ventana recorre la textura para dar el efecto de que todo se desplaza Finalmente, una ventana recorre la textura para dar el efecto de que todo se desplaza
por la pantalla sobre el mosaico de fondo (gestionado por el correspondiente objeto). por la pantalla sobre el mosaico de fondo (gestionado por el correspondiente objeto).
*/ */
// Estructura para almacenar información de línea animada // Estructura para almacenar información de línea animada
struct Line struct Line {
{ int y; // Coordenada Y de la línea
int y; // Coordenada Y de la línea float x; // Coordenada X inicial (usamos float para mayor precisión en el suavizado)
float x; // Coordenada X inicial (usamos float para mayor precisión en el suavizado) int direction; // Dirección de movimiento: -1 para izquierda, 1 para derecha
int direction; // Dirección de movimiento: -1 para izquierda, 1 para derecha Uint32 startTime; // Tiempo de inicio del movimiento
Uint32 startTime; // Tiempo de inicio del movimiento
// Constructor de Line // Constructor de Line
Line(int y, float x, int direction) Line(int y, float x, int direction)
: y(y), x(x), direction(direction), startTime(0) {} : y(y), x(x), direction(direction), startTime(0) {}
}; };
// Clase Instructions // Clase Instructions
class Instructions class Instructions {
{ public:
public: // Constructor
// Constructor Instructions();
Instructions();
// Destructor // Destructor
~Instructions(); ~Instructions();
// Bucle principal // Bucle principal
void run(); void run();
private: private:
// --- Objetos y punteros --- // --- Objetos y punteros ---
SDL_Renderer *renderer_; // El renderizador de la ventana SDL_Renderer *renderer_; // El renderizador de la ventana
SDL_Texture *texture_; // Textura fija con el texto SDL_Texture *texture_; // Textura fija con el texto
SDL_Texture *backbuffer_; // Textura para usar como backbuffer SDL_Texture *backbuffer_; // Textura para usar como backbuffer
std::vector<std::shared_ptr<Texture>> item_textures_; // Vector con las texturas de los items std::vector<std::shared_ptr<Texture>> item_textures_; // Vector con las texturas de los items
std::vector<std::unique_ptr<Sprite>> sprites_; // Vector con los sprites de los items std::vector<std::unique_ptr<Sprite>> sprites_; // Vector con los sprites de los items
std::shared_ptr<Text> text_; // Objeto para escribir texto std::shared_ptr<Text> text_; // Objeto para escribir texto
std::unique_ptr<TiledBG> tiled_bg_; // Objeto para dibujar el mosaico animado de fondo std::unique_ptr<TiledBG> tiled_bg_; // Objeto para dibujar el mosaico animado de fondo
std::unique_ptr<Fade> fade_; // Objeto para renderizar fades std::unique_ptr<Fade> fade_; // Objeto para renderizar fades
// --- Variables --- // --- Variables ---
int counter_ = 0; // Contador para manejar el progreso en la pantalla de instrucciones int counter_ = 0; // Contador para manejar el progreso en la pantalla de instrucciones
Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
SDL_FRect view_; // Vista del backbuffer que se va a mostrar por pantalla SDL_FRect view_; // Vista del backbuffer que se va a mostrar por pantalla
SDL_FPoint sprite_pos_ = {0, 0}; // Posición del primer sprite en la lista SDL_FPoint sprite_pos_ = {0, 0}; // Posición del primer sprite en la lista
float item_space_ = 2.0; // Espacio entre los items en pantalla float item_space_ = 2.0; // Espacio entre los items en pantalla
std::vector<Line> lines_; // Vector que contiene las líneas animadas en la pantalla std::vector<Line> lines_; // Vector que contiene las líneas animadas en la pantalla
bool all_lines_off_screen_ = false; // Indica si todas las líneas han salido de la pantalla bool all_lines_off_screen_ = false; // Indica si todas las líneas han salido de la pantalla
Uint32 start_delay_time_ = 0; // Tiempo de inicio del retraso para mover las líneas Uint32 start_delay_time_ = 0; // Tiempo de inicio del retraso para mover las líneas
bool start_delay_triggered_ = false; // Bandera para determinar si el retraso ha comenzado bool start_delay_triggered_ = false; // Bandera para determinar si el retraso ha comenzado
// --- Métodos internos --- // --- Métodos internos ---
void update(); // Actualiza las variables void update(); // Actualiza las variables
void render(); // Pinta en pantalla void render(); // Pinta en pantalla
void checkEvents(); // Comprueba los eventos void checkEvents(); // Comprueba los eventos
void checkInput(); // Comprueba las entradas void checkInput(); // Comprueba las entradas
void fillTexture(); // Rellena la textura de texto void fillTexture(); // Rellena la textura de texto
void fillBackbuffer(); // Rellena el backbuffer void fillBackbuffer(); // Rellena el backbuffer
void iniSprites(); // Inicializa los sprites de los items void iniSprites(); // Inicializa los sprites de los items
void updateSprites(); // Actualiza los sprites void updateSprites(); // Actualiza los sprites
std::vector<Line> initializeLines(int height); // Inicializa las líneas animadas std::vector<Line> initializeLines(int height); // Inicializa las líneas animadas
bool moveLines(std::vector<Line> &lines, int width, float duration, Uint32 startDelay); // Mueve las líneas bool moveLines(std::vector<Line> &lines, int width, float duration, Uint32 startDelay); // Mueve las líneas
void renderLines(SDL_Renderer *renderer, SDL_Texture *texture, const std::vector<Line> &lines); // Renderiza las líneas void renderLines(SDL_Renderer *renderer, SDL_Texture *texture, const std::vector<Line> &lines); // Renderiza las líneas
void updateBackbuffer(); // Gestiona la textura con los gráficos void updateBackbuffer(); // Gestiona la textura con los gráficos
}; };
+446 -505
View File
File diff suppressed because it is too large. Load diff
+56 -58
View File
@@ -1,74 +1,72 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para Uint32, Uint64 #include <SDL3/SDL.h> // Para Uint32, Uint64
#include <memory> // Para unique_ptr
#include <vector> // Para vector
#include "param.h" // Para Param, ParamIntro, param #include <memory> // Para unique_ptr
#include "path_sprite.h" // Para PathSprite #include <vector> // Para vector
#include "tiled_bg.h" // Para TiledBG
#include "utils.h" // Para Color #include "param.h" // Para Param, ParamIntro, param
#include "writer.h" // Para Writer #include "path_sprite.h" // Para PathSprite
#include "tiled_bg.h" // Para TiledBG
#include "utils.h" // Para Color
#include "writer.h" // Para Writer
/* /*
Esta clase gestiona un estado del programa. Se encarga de mostrar la secuencia Esta clase gestiona un estado del programa. Se encarga de mostrar la secuencia
de introducción. de introducción.
*/ */
// Clase Intro // Clase Intro
class Intro class Intro {
{ public:
public: // Constructor
// Constructor Intro();
Intro();
// Destructor // Destructor
~Intro() = default; ~Intro() = default;
// Bucle principal // Bucle principal
void run(); void run();
private: private:
// --- Estados internos --- // --- Estados internos ---
enum class IntroState enum class IntroState {
{ SCENES,
SCENES, POST,
POST, };
};
enum class IntroPostState enum class IntroPostState {
{ STOP_BG,
STOP_BG, END,
END, };
};
// --- Objetos --- // --- Objetos ---
std::vector<std::unique_ptr<PathSprite>> card_sprites_; // Vector con los sprites inteligentes para los dibujos de la intro std::vector<std::unique_ptr<PathSprite>> card_sprites_; // Vector con los sprites inteligentes para los dibujos de la intro
std::vector<std::unique_ptr<PathSprite>> shadow_sprites_; // Vector con los sprites inteligentes para las sombras std::vector<std::unique_ptr<PathSprite>> shadow_sprites_; // Vector con los sprites inteligentes para las sombras
std::vector<std::unique_ptr<Writer>> texts_; // Textos de la intro std::vector<std::unique_ptr<Writer>> texts_; // Textos de la intro
std::unique_ptr<TiledBG> tiled_bg_; // Fondo en mosaico std::unique_ptr<TiledBG> tiled_bg_; // Fondo en mosaico
// std::unique_ptr<Sprite> shadow_square_for_text_; // Sprite // std::unique_ptr<Sprite> shadow_square_for_text_; // Sprite
// --- Variables --- // --- Variables ---
Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
int scene_ = 0; // Indica qué escena está activa int scene_ = 0; // Indica qué escena está activa
IntroState state_ = IntroState::SCENES; // Estado principal de la intro IntroState state_ = IntroState::SCENES; // Estado principal de la intro
IntroPostState post_state_ = IntroPostState::STOP_BG; // Estado POST IntroPostState post_state_ = IntroPostState::STOP_BG; // Estado POST
Uint32 state_start_time_; // Tiempo de inicio del estado actual Uint32 state_start_time_; // Tiempo de inicio del estado actual
Color bg_color_ = param.intro.bg_color; // Color de fondo Color bg_color_ = param.intro.bg_color; // Color de fondo
// --- Métodos internos --- // --- Métodos internos ---
void update(); // Actualiza las variables del objeto void update(); // Actualiza las variables del objeto
void render(); // Dibuja el objeto en pantalla void render(); // Dibuja el objeto en pantalla
void checkEvents(); // Comprueba los eventos void checkEvents(); // Comprueba los eventos
void checkInput(); // Comprueba las entradas void checkInput(); // Comprueba las entradas
void updateScenes(); // Actualiza las escenas de la intro void updateScenes(); // Actualiza las escenas de la intro
void initSprites(); // Inicializa las imágenes void initSprites(); // Inicializa las imágenes
void initTexts(); // Inicializa los textos void initTexts(); // Inicializa los textos
void updateSprites(); // Actualiza los sprites void updateSprites(); // Actualiza los sprites
void updateTexts(); // Actualiza los textos void updateTexts(); // Actualiza los textos
void renderSprites(); // Dibuja los sprites void renderSprites(); // Dibuja los sprites
void renderTexts(); // Dibuja los textos void renderTexts(); // Dibuja los textos
void renderTextRect(); // Dibuja el rectangulo de fondo del texto; void renderTextRect(); // Dibuja el rectangulo de fondo del texto;
void updatePostState(); // Actualiza el estado POST void updatePostState(); // Actualiza el estado POST
}; };
+134 -164
View File
@@ -1,211 +1,181 @@
#include "logo.h" #include "logo.h"
#include <SDL3/SDL.h> // Para SDL_GetTicks, SDL_PollEvent, SDL_Event #include <SDL3/SDL.h> // Para SDL_GetTicks, SDL_PollEvent, SDL_Event
#include <string> // Para basic_string
#include <utility> // Para move
#include "audio.h" // Para Audio #include <string> // Para basic_string
#include "global_events.h" // Para check #include <utility> // Para move
#include "global_inputs.h" // Para check
#include "input.h" // Para Input #include "audio.h" // Para Audio
#include "param.h" // Para Param, ParamGame, param #include "global_events.h" // Para check
#include "resource.h" // Para Resource #include "global_inputs.h" // Para check
#include "screen.h" // Para Screen #include "input.h" // Para Input
#include "section.h" // Para Name, name #include "param.h" // Para Param, ParamGame, param
#include "sprite.h" // Para Sprite #include "resource.h" // Para Resource
#include "texture.h" // Para Texture #include "screen.h" // Para Screen
#include "utils.h" // Para Color, Zone #include "section.h" // Para Name, name
#include "sprite.h" // Para Sprite
#include "texture.h" // Para Texture
#include "utils.h" // Para Color, Zone
// Constructor // Constructor
Logo::Logo() Logo::Logo()
: since_texture_(Resource::get()->getTexture("logo_since_1998.png")), : since_texture_(Resource::get()->getTexture("logo_since_1998.png")),
since_sprite_(std::make_unique<Sprite>(since_texture_)), since_sprite_(std::make_unique<Sprite>(since_texture_)),
jail_texture_(Resource::get()->getTexture("logo_jailgames.png")) jail_texture_(Resource::get()->getTexture("logo_jailgames.png")) {
{ // Inicializa variables
Section::name = Section::Name::LOGO;
dest_.x = param.game.game_area.center_x - jail_texture_->getWidth() / 2;
dest_.y = param.game.game_area.center_y - jail_texture_->getHeight() / 2;
since_sprite_->setPosition(SDL_FRect{
static_cast<float>((param.game.width - since_texture_->getWidth()) / 2),
static_cast<float>(83 + jail_texture_->getHeight() + 5),
static_cast<float>(since_texture_->getWidth()),
static_cast<float>(since_texture_->getHeight())});
since_sprite_->setY(dest_.y + jail_texture_->getHeight() + 5);
since_sprite_->setSpriteClip(0, 0, since_texture_->getWidth(), since_texture_->getHeight());
since_texture_->setColor(0x00, 0x00, 0x00);
// Inicializa variables // Crea los sprites de cada linea
Section::name = Section::Name::LOGO; for (int i = 0; i < jail_texture_->getHeight(); ++i) {
dest_.x = param.game.game_area.center_x - jail_texture_->getWidth() / 2; auto temp = std::make_unique<Sprite>(jail_texture_, 0, i, jail_texture_->getWidth(), 1);
dest_.y = param.game.game_area.center_y - jail_texture_->getHeight() / 2; temp->setSpriteClip(0, i, jail_texture_->getWidth(), 1);
since_sprite_->setPosition(SDL_FRect{ const int POS_X = (i % 2 == 0) ? param.game.width + (i * 3) : -jail_texture_->getWidth() - (i * 3);
static_cast<float>((param.game.width - since_texture_->getWidth()) / 2), temp->setX(POS_X);
static_cast<float>(83 + jail_texture_->getHeight() + 5), temp->setY(dest_.y + i);
static_cast<float>(since_texture_->getWidth()), jail_sprite_.push_back(std::move(temp));
static_cast<float>(since_texture_->getHeight())}); }
since_sprite_->setY(dest_.y + jail_texture_->getHeight() + 5);
since_sprite_->setSpriteClip(0, 0, since_texture_->getWidth(), since_texture_->getHeight());
since_texture_->setColor(0x00, 0x00, 0x00);
// Crea los sprites de cada linea // Inicializa el vector de colores
for (int i = 0; i < jail_texture_->getHeight(); ++i) color_.push_back(Color(0x00, 0x00, 0x00)); // Black
{ color_.push_back(Color(0x00, 0x00, 0xd8)); // Blue
auto temp = std::make_unique<Sprite>(jail_texture_, 0, i, jail_texture_->getWidth(), 1); color_.push_back(Color(0xd8, 0x00, 0x00)); // Red
temp->setSpriteClip(0, i, jail_texture_->getWidth(), 1); color_.push_back(Color(0xd8, 0x00, 0xd8)); // Magenta
const int POS_X = (i % 2 == 0) ? param.game.width + (i * 3) : -jail_texture_->getWidth() - (i * 3); color_.push_back(Color(0x00, 0xd8, 0x00)); // Green
temp->setX(POS_X); color_.push_back(Color(0x00, 0xd8, 0xd8)); // Cyan
temp->setY(dest_.y + i); color_.push_back(Color(0xd8, 0xd8, 0x00)); // Yellow
jail_sprite_.push_back(std::move(temp)); color_.push_back(Color(0xFF, 0xFF, 0xFF)); // Bright white
}
// Inicializa el vector de colores
color_.push_back(Color(0x00, 0x00, 0x00)); // Black
color_.push_back(Color(0x00, 0x00, 0xd8)); // Blue
color_.push_back(Color(0xd8, 0x00, 0x00)); // Red
color_.push_back(Color(0xd8, 0x00, 0xd8)); // Magenta
color_.push_back(Color(0x00, 0xd8, 0x00)); // Green
color_.push_back(Color(0x00, 0xd8, 0xd8)); // Cyan
color_.push_back(Color(0xd8, 0xd8, 0x00)); // Yellow
color_.push_back(Color(0xFF, 0xFF, 0xFF)); // Bright white
} }
// Destructor // Destructor
Logo::~Logo() Logo::~Logo() {
{ jail_texture_->setColor(255, 255, 255);
jail_texture_->setColor(255, 255, 255); since_texture_->setColor(255, 255, 255);
since_texture_->setColor(255, 255, 255); Audio::get()->stopAllSounds();
Audio::get()->stopAllSounds(); Audio::get()->stopMusic();
Audio::get()->stopMusic();
} }
// Comprueba el manejador de eventos // Comprueba el manejador de eventos
void Logo::checkEvents() void Logo::checkEvents() {
{ SDL_Event event;
SDL_Event event; while (SDL_PollEvent(&event)) {
while (SDL_PollEvent(&event)) GlobalEvents::check(event);
{ }
GlobalEvents::check(event);
}
} }
// Comprueba las entradas // Comprueba las entradas
void Logo::checkInput() void Logo::checkInput() {
{ Input::get()->update();
Input::get()->update(); GlobalInputs::check();
GlobalInputs::check();
} }
// Gestiona el logo de JAILGAMES // Gestiona el logo de JAILGAMES
void Logo::updateJAILGAMES() void Logo::updateJAILGAMES() {
{ if (counter_ == 30) {
if (counter_ == 30) Audio::get()->playSound("logo.wav");
{ }
Audio::get()->playSound("logo.wav");
}
if (counter_ > 30) if (counter_ > 30) {
{ for (int i = 0; i < (int)jail_sprite_.size(); ++i) {
for (int i = 0; i < (int)jail_sprite_.size(); ++i) if (jail_sprite_[i]->getX() != dest_.x) {
{ if (i % 2 == 0) {
if (jail_sprite_[i]->getX() != dest_.x) jail_sprite_[i]->incX(-SPEED);
{ if (jail_sprite_[i]->getX() < dest_.x) {
if (i % 2 == 0) jail_sprite_[i]->setX(dest_.x);
{ }
jail_sprite_[i]->incX(-SPEED); } else {
if (jail_sprite_[i]->getX() < dest_.x) jail_sprite_[i]->incX(SPEED);
{ if (jail_sprite_[i]->getX() > dest_.x) {
jail_sprite_[i]->setX(dest_.x); jail_sprite_[i]->setX(dest_.x);
} }
} }
else }
{ }
jail_sprite_[i]->incX(SPEED); }
if (jail_sprite_[i]->getX() > dest_.x)
{
jail_sprite_[i]->setX(dest_.x);
}
}
}
}
}
// Comprueba si ha terminado el logo // Comprueba si ha terminado el logo
if (counter_ == END_LOGO_COUNTER_MARK + POST_LOGO_DURATION) if (counter_ == END_LOGO_COUNTER_MARK + POST_LOGO_DURATION) {
{ Section::name = Section::Name::INTRO;
Section::name = Section::Name::INTRO; }
}
} }
// Gestiona el color de las texturas // Gestiona el color de las texturas
void Logo::updateTextureColors() void Logo::updateTextureColors() {
{ constexpr int inc = 4;
constexpr int inc = 4;
// Manejo de 'sinceTexture' // Manejo de 'sinceTexture'
for (int i = 0; i <= 7; ++i) for (int i = 0; i <= 7; ++i) {
{ if (counter_ == SHOW_SINCE_SPRITE_COUNTER_MARK + inc * i) {
if (counter_ == SHOW_SINCE_SPRITE_COUNTER_MARK + inc * i) since_texture_->setColor(color_[i].r, color_[i].g, color_[i].b);
{ }
since_texture_->setColor(color_[i].r, color_[i].g, color_[i].b); }
}
}
// Manejo de 'jailTexture' y 'sinceTexture' en el fade // Manejo de 'jailTexture' y 'sinceTexture' en el fade
for (int i = 0; i <= 6; ++i) for (int i = 0; i <= 6; ++i) {
{ if (counter_ == INIT_FADE_COUNTER_MARK + inc * i) {
if (counter_ == INIT_FADE_COUNTER_MARK + inc * i) jail_texture_->setColor(color_[6 - i].r, color_[6 - i].g, color_[6 - i].b);
{ since_texture_->setColor(color_[6 - i].r, color_[6 - i].g, color_[6 - i].b);
jail_texture_->setColor(color_[6 - i].r, color_[6 - i].g, color_[6 - i].b); }
since_texture_->setColor(color_[6 - i].r, color_[6 - i].g, color_[6 - i].b); }
}
}
} }
// Actualiza las variables // Actualiza las variables
void Logo::update() void Logo::update() {
{ if (SDL_GetTicks() - ticks_ > param.game.speed) {
if (SDL_GetTicks() - ticks_ > param.game.speed) // Actualiza el contador de ticks
{ ticks_ = SDL_GetTicks();
// Actualiza el contador de ticks
ticks_ = SDL_GetTicks();
// Actualiza el objeto screen // Actualiza el objeto screen
Screen::get()->update(); Screen::get()->update();
// Comprueba las entradas // Comprueba las entradas
checkInput(); checkInput();
updateJAILGAMES(); updateJAILGAMES();
updateTextureColors(); updateTextureColors();
// Gestiona el contador // Gestiona el contador
++counter_; ++counter_;
} }
} }
// Dibuja en pantalla // Dibuja en pantalla
void Logo::render() void Logo::render() {
{ Screen::get()->start();
Screen::get()->start(); Screen::get()->clean();
Screen::get()->clean();
renderJAILGAMES(); renderJAILGAMES();
Screen::get()->render(); Screen::get()->render();
} }
// Bucle para el logo del juego // Bucle para el logo del juego
void Logo::run() void Logo::run() {
{ while (Section::name == Section::Name::LOGO) {
while (Section::name == Section::Name::LOGO) checkInput();
{ update();
checkInput(); checkEvents(); // Tiene que ir antes del render
update(); render();
checkEvents(); // Tiene que ir antes del render }
render();
}
} }
// Renderiza el logo de JAILGAMES // Renderiza el logo de JAILGAMES
void Logo::renderJAILGAMES() void Logo::renderJAILGAMES() {
{ // Dibuja los sprites
// Dibuja los sprites for (auto &sprite : jail_sprite_) {
for (auto &sprite : jail_sprite_) sprite->render();
{ }
sprite->render();
}
if (counter_ >= SHOW_SINCE_SPRITE_COUNTER_MARK) if (counter_ >= SHOW_SINCE_SPRITE_COUNTER_MARK) {
{ since_sprite_->render();
since_sprite_->render(); }
}
} }
+42 -42
View File
@@ -1,60 +1,60 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_FPoint, Uint64 #include <SDL3/SDL.h> // Para SDL_FPoint, Uint64
#include <memory> // Para shared_ptr, unique_ptr
#include <vector> // Para vector #include <memory> // Para shared_ptr, unique_ptr
#include <vector> // Para vector
class Sprite; class Sprite;
class Texture; class Texture;
struct Color; struct Color;
/* /*
Esta clase gestiona un estado del programa. Se encarga de dibujar por pantalla el Esta clase gestiona un estado del programa. Se encarga de dibujar por pantalla el
logo de "JAILGAMES" utilizando un sencillo efecto consistente en generar un sprite por logo de "JAILGAMES" utilizando un sencillo efecto consistente en generar un sprite por
cada línea del bitmap que forma la palabra "JAILGAMES". Posteriormente realiza una cada línea del bitmap que forma la palabra "JAILGAMES". Posteriormente realiza una
modulación de color sobre la textura para simular un fade to black al estilo modulación de color sobre la textura para simular un fade to black al estilo
ZX Spectrum. ZX Spectrum.
*/ */
// --- Clase Logo --- // --- Clase Logo ---
class Logo class Logo {
{ public:
public: // Constructor
// Constructor Logo();
Logo();
// Destructor // Destructor
~Logo(); ~Logo();
// Bucle principal // Bucle principal
void run(); void run();
private: private:
// --- Constantes --- // --- Constantes ---
static constexpr int SHOW_SINCE_SPRITE_COUNTER_MARK = 70; // Tiempo del contador en el que empieza a verse el sprite de "SINCE 1998" static constexpr int SHOW_SINCE_SPRITE_COUNTER_MARK = 70; // Tiempo del contador en el que empieza a verse el sprite de "SINCE 1998"
static constexpr int INIT_FADE_COUNTER_MARK = 300; // Tiempo del contador cuando inicia el fade a negro static constexpr int INIT_FADE_COUNTER_MARK = 300; // Tiempo del contador cuando inicia el fade a negro
static constexpr int END_LOGO_COUNTER_MARK = 400; // Tiempo del contador para terminar el logo static constexpr int END_LOGO_COUNTER_MARK = 400; // Tiempo del contador para terminar el logo
static constexpr int POST_LOGO_DURATION = 20; // Tiempo que dura el logo con el fade al máximo static constexpr int POST_LOGO_DURATION = 20; // Tiempo que dura el logo con el fade al máximo
static constexpr int SPEED = 8; // Velocidad de desplazamiento de cada línea static constexpr int SPEED = 8; // Velocidad de desplazamiento de cada línea
// --- Objetos y punteros --- // --- Objetos y punteros ---
std::shared_ptr<Texture> since_texture_; // Textura con los gráficos "Since 1998" std::shared_ptr<Texture> since_texture_; // Textura con los gráficos "Since 1998"
std::unique_ptr<Sprite> since_sprite_; // Sprite para manejar la since_texture std::unique_ptr<Sprite> since_sprite_; // Sprite para manejar la since_texture
std::shared_ptr<Texture> jail_texture_; // Textura con los gráficos "JAILGAMES" std::shared_ptr<Texture> jail_texture_; // Textura con los gráficos "JAILGAMES"
std::vector<std::unique_ptr<Sprite>> jail_sprite_; // Vector con los sprites de cada línea que forman el bitmap JAILGAMES std::vector<std::unique_ptr<Sprite>> jail_sprite_; // Vector con los sprites de cada línea que forman el bitmap JAILGAMES
// --- Variables --- // --- Variables ---
std::vector<Color> color_; // Vector con los colores para el fade std::vector<Color> color_; // Vector con los colores para el fade
int counter_ = 0; // Contador int counter_ = 0; // Contador
Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
SDL_FPoint dest_; // Posición donde dibujar el logo SDL_FPoint dest_; // Posición donde dibujar el logo
// --- Métodos internos --- // --- Métodos internos ---
void update(); // Actualiza las variables void update(); // Actualiza las variables
void render(); // Dibuja en pantalla void render(); // Dibuja en pantalla
void checkEvents(); // Comprueba el manejador de eventos void checkEvents(); // Comprueba el manejador de eventos
void checkInput(); // Comprueba las entradas void checkInput(); // Comprueba las entradas
void updateJAILGAMES(); // Gestiona el logo de JAILGAMES void updateJAILGAMES(); // Gestiona el logo de JAILGAMES
void renderJAILGAMES(); // Renderiza el logo de JAILGAMES void renderJAILGAMES(); // Renderiza el logo de JAILGAMES
void updateTextureColors(); // Gestiona el color de las texturas void updateTextureColors(); // Gestiona el color de las texturas
}; };
+400 -456
View File
@@ -1,579 +1,523 @@
#include "title.h" #include "title.h"
#include <SDL3/SDL.h> // Para SDL_GetTicks, Uint32, SDL_EventType #include <SDL3/SDL.h> // Para SDL_GetTicks, Uint32, SDL_EventType
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <algorithm> // Para find_if
#include <iostream> // Para basic_ostream, basic_ostream::operator<<
#include <string> // Para basic_string, char_traits, operator+
#include <vector> // Para vector
#include "audio.h" // Para Audio #include <algorithm> // Para find_if
#include "define_buttons.h" // Para DefineButtons #include <iostream> // Para basic_ostream, basic_ostream::operator<<
#include "fade.h" // Para Fade, FadeType #include <string> // Para basic_string, char_traits, operator+
#include "game_logo.h" // Para GameLogo #include <vector> // Para vector
#include "global_events.h" // Para check
#include "global_inputs.h" // Para check #include "audio.h" // Para Audio
#include "input.h" // Para Input, INPUT_DO_NOT_ALLOW_REPEAT, Input... #include "define_buttons.h" // Para DefineButtons
#include "lang.h" // Para getText #include "fade.h" // Para Fade, FadeType
#include "notifier.h" // Para Notifier #include "game_logo.h" // Para GameLogo
#include "options.h" // Para GamepadOptions, controllers, getPlayerW... #include "global_events.h" // Para check
#include "param.h" // Para Param, param, ParamGame, ParamTitle #include "global_inputs.h" // Para check
#include "player.h" // Para Player, PlayerState #include "input.h" // Para Input, INPUT_DO_NOT_ALLOW_REPEAT, Input...
#include "resource.h" // Para Resource #include "lang.h" // Para getText
#include "screen.h" // Para Screen #include "notifier.h" // Para Notifier
#include "section.h" // Para Name, name, Options, options, AttractMode #include "options.h" // Para GamepadOptions, controllers, getPlayerW...
#include "sprite.h" // Para Sprite #include "param.h" // Para Param, param, ParamGame, ParamTitle
#include "text.h" // Para TEXT_CENTER, TEXT_SHADOW, Text #include "player.h" // Para Player, PlayerState
#include "tiled_bg.h" // Para TiledBG, TiledBGMode #include "resource.h" // Para Resource
#include "ui/service_menu.h" // Para ServiceMenu #include "screen.h" // Para Screen
#include "utils.h" // Para Color, Zone, NO_TEXT_COLOR, TITLE_SHADO... #include "section.h" // Para Name, name, Options, options, AttractMode
#include "sprite.h" // Para Sprite
#include "text.h" // Para TEXT_CENTER, TEXT_SHADOW, Text
#include "tiled_bg.h" // Para TiledBG, TiledBGMode
#include "ui/service_menu.h" // Para ServiceMenu
#include "utils.h" // Para Color, Zone, NO_TEXT_COLOR, TITLE_SHADO...
class Texture; class Texture;
#ifdef DEBUG #ifdef DEBUG
#include <iomanip> // Para operator<<, setfill, setw #include <iomanip> // Para operator<<, setfill, setw
#endif #endif
// Constructor // Constructor
Title::Title() Title::Title()
: text_(Resource::get()->getText("smb2_grad")), : text_(Resource::get()->getText("smb2_grad")),
fade_(std::make_unique<Fade>()), fade_(std::make_unique<Fade>()),
tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::RANDOM)), tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::RANDOM)),
game_logo_(std::make_unique<GameLogo>(param.game.game_area.center_x, param.title.title_c_c_position)), game_logo_(std::make_unique<GameLogo>(param.game.game_area.center_x, param.title.title_c_c_position)),
mini_logo_sprite_(std::make_unique<Sprite>(Resource::get()->getTexture("logo_jailgames_mini.png"))), mini_logo_sprite_(std::make_unique<Sprite>(Resource::get()->getTexture("logo_jailgames_mini.png"))),
define_buttons_(std::make_unique<DefineButtons>()), define_buttons_(std::make_unique<DefineButtons>()),
num_controllers_(Input::get()->getNumControllers()), num_controllers_(Input::get()->getNumControllers()),
state_(TitleState::LOGO_ANIMATING) state_(TitleState::LOGO_ANIMATING) {
{ // Configura objetos
// Configura objetos tiled_bg_->setColor(param.title.bg_color);
tiled_bg_->setColor(param.title.bg_color); game_logo_->enable();
game_logo_->enable(); mini_logo_sprite_->setX(param.game.game_area.center_x - mini_logo_sprite_->getWidth() / 2);
mini_logo_sprite_->setX(param.game.game_area.center_x - mini_logo_sprite_->getWidth() / 2); fade_->setColor(param.fade.color);
fade_->setColor(param.fade.color); fade_->setType(FadeType::RANDOM_SQUARE);
fade_->setType(FadeType::RANDOM_SQUARE); fade_->setPostDuration(param.fade.post_duration);
fade_->setPostDuration(param.fade.post_duration); initPlayers();
initPlayers();
// Asigna valores a otras variables // Asigna valores a otras variables
Section::options = Section::Options::TITLE_1; Section::options = Section::Options::TITLE_1;
const bool IS_TITLE_TO_DEMO = (Section::attract_mode == Section::AttractMode::TITLE_TO_DEMO); const bool IS_TITLE_TO_DEMO = (Section::attract_mode == Section::AttractMode::TITLE_TO_DEMO);
next_section_ = IS_TITLE_TO_DEMO ? Section::Name::GAME_DEMO : Section::Name::LOGO; next_section_ = IS_TITLE_TO_DEMO ? Section::Name::GAME_DEMO : Section::Name::LOGO;
Section::attract_mode = IS_TITLE_TO_DEMO ? Section::AttractMode::TITLE_TO_LOGO : Section::AttractMode::TITLE_TO_DEMO; Section::attract_mode = IS_TITLE_TO_DEMO ? Section::AttractMode::TITLE_TO_LOGO : Section::AttractMode::TITLE_TO_DEMO;
// Define los anclajes de los elementos // Define los anclajes de los elementos
anchor_.mini_logo = (param.game.height / 5 * 4) + BLOCK; anchor_.mini_logo = (param.game.height / 5 * 4) + BLOCK;
mini_logo_sprite_->setY(anchor_.mini_logo); mini_logo_sprite_->setY(anchor_.mini_logo);
anchor_.copyright_text = anchor_.mini_logo + mini_logo_sprite_->getHeight() + 3; anchor_.copyright_text = anchor_.mini_logo + mini_logo_sprite_->getHeight() + 3;
} }
// Destructor // Destructor
Title::~Title() Title::~Title() {
{ Audio::get()->stopAllSounds();
Audio::get()->stopAllSounds(); if (Section::name == Section::Name::LOGO) {
if (Section::name == Section::Name::LOGO) Audio::get()->fadeOutMusic(300);
{ }
Audio::get()->fadeOutMusic(300);
}
} }
// Actualiza las variables del objeto // Actualiza las variables del objeto
void Title::update() void Title::update() {
{ if (SDL_GetTicks() - ticks_ > param.game.speed) {
if (SDL_GetTicks() - ticks_ > param.game.speed) ticks_ = SDL_GetTicks();
{ updateFade();
ticks_ = SDL_GetTicks(); updateState();
updateFade(); updateStartPrompt();
updateState(); updatePlayers();
updateStartPrompt(); Screen::get()->update();
updatePlayers(); }
Screen::get()->update();
}
} }
// Dibuja el objeto en pantalla // Dibuja el objeto en pantalla
void Title::render() void Title::render() {
{ Screen::get()->start();
Screen::get()->start(); Screen::get()->clean();
Screen::get()->clean();
tiled_bg_->render(); tiled_bg_->render();
game_logo_->render(); game_logo_->render();
renderPlayers(); renderPlayers();
renderStartPrompt(); renderStartPrompt();
renderCopyright(); renderCopyright();
define_buttons_->render(); define_buttons_->render();
fade_->render(); fade_->render();
Screen::get()->render(); Screen::get()->render();
} }
// Comprueba los eventos // Comprueba los eventos
void Title::checkEvents() void Title::checkEvents() {
{ SDL_Event event;
SDL_Event event; while (SDL_PollEvent(&event)) {
while (SDL_PollEvent(&event))
{
#ifdef DEBUG #ifdef DEBUG
if (event.type == SDL_EVENT_KEY_DOWN && event.key.repeat == 1) if (event.type == SDL_EVENT_KEY_DOWN && event.key.repeat == 1) {
{ static Color color = param.title.bg_color;
static Color color = param.title.bg_color; switch (event.key.key) {
switch (event.key.key) case SDLK_A:
{ if (color.r < 255)
case SDLK_A: ++color.r;
if (color.r < 255) break;
++color.r;
break;
case SDLK_Z: case SDLK_Z:
if (color.r > 0) if (color.r > 0)
--color.r; --color.r;
break; break;
case SDLK_S: case SDLK_S:
if (color.g < 255) if (color.g < 255)
++color.g; ++color.g;
break; break;
case SDLK_X: case SDLK_X:
if (color.g > 0) if (color.g > 0)
--color.g; --color.g;
break; break;
case SDLK_D: case SDLK_D:
if (color.b < 255) if (color.b < 255)
++color.b; ++color.b;
break; break;
case SDLK_C: case SDLK_C:
if (color.b > 0) if (color.b > 0)
--color.b; --color.b;
break; break;
case SDLK_F: case SDLK_F:
if (color.r < 255) if (color.r < 255)
++color.r; ++color.r;
if (color.g < 255) if (color.g < 255)
++color.g; ++color.g;
if (color.b < 255) if (color.b < 255)
++color.b; ++color.b;
break; break;
case SDLK_V: case SDLK_V:
if (color.r > 0) if (color.r > 0)
--color.r; --color.r;
if (color.g > 0) if (color.g > 0)
--color.g; --color.g;
if (color.b > 0) if (color.b > 0)
--color.b; --color.b;
break; break;
default: default:
break; break;
} }
counter_ = 0; counter_ = 0;
tiled_bg_->setColor(color); tiled_bg_->setColor(color);
std::cout << "#" std::cout << "#"
<< std::hex << std::setw(2) << std::setfill('0') << (int)color.r << std::hex << std::setw(2) << std::setfill('0') << (int)color.r
<< std::setw(2) << std::setfill('0') << (int)color.g << std::setw(2) << std::setfill('0') << (int)color.g
<< std::setw(2) << std::setfill('0') << (int)color.b << std::setw(2) << std::setfill('0') << (int)color.b
<< std::endl; << std::endl;
} }
#endif #endif
if (event.type == SDL_EVENT_KEY_DOWN && event.key.repeat == 0) if (event.type == SDL_EVENT_KEY_DOWN && event.key.repeat == 0) {
{ switch (event.key.key) {
switch (event.key.key) case SDLK_1: // Redefine los botones del mando #0
{ define_buttons_->enable(0);
case SDLK_1: // Redefine los botones del mando #0 resetCounter();
define_buttons_->enable(0); break;
resetCounter();
break;
case SDLK_2: // Redefine los botones del mando #1 case SDLK_2: // Redefine los botones del mando #1
define_buttons_->enable(1); define_buttons_->enable(1);
resetCounter(); resetCounter();
break; break;
case SDLK_3: // Intercambia los mandos entre los dos jugadores case SDLK_3: // Intercambia los mandos entre los dos jugadores
swapControllers(); swapControllers();
resetCounter(); resetCounter();
break; break;
case SDLK_4: // Intercambia la asignación del teclado case SDLK_4: // Intercambia la asignación del teclado
swapKeyboard(); swapKeyboard();
resetCounter(); resetCounter();
break; break;
case SDLK_5: // Muestra la asignación de mandos y teclado case SDLK_5: // Muestra la asignación de mandos y teclado
showControllers(); showControllers();
resetCounter(); resetCounter();
break; break;
default: default:
break; break;
} }
} }
GlobalEvents::check(event); GlobalEvents::check(event);
define_buttons_->checkEvents(event); define_buttons_->checkEvents(event);
} }
} }
// Comprueba las entradas // Comprueba las entradas
void Title::checkInput() void Title::checkInput() {
{ // Comprueba las entradas solo si no se estan definiendo los botones
// Comprueba las entradas solo si no se estan definiendo los botones if (define_buttons_->isEnabled())
if (define_buttons_->isEnabled()) return;
return;
Input::get()->update(); Input::get()->update();
if (!ServiceMenu::get()->isEnabled()) if (!ServiceMenu::get()->isEnabled()) {
{ // Comprueba todos los métodos de control
// Comprueba todos los métodos de control for (const auto &CONTROLLER : Options::controllers) {
for (const auto &CONTROLLER : Options::controllers) // Boton START
{ if (Input::get()->checkInput(InputAction::START, INPUT_DO_NOT_ALLOW_REPEAT, CONTROLLER.type, CONTROLLER.index)) {
// Boton START if ((state_ != TitleState::LOGO_ANIMATING || ALLOW_TITLE_ANIMATION_SKIP)) {
if (Input::get()->checkInput(InputAction::START, INPUT_DO_NOT_ALLOW_REPEAT, CONTROLLER.type, CONTROLLER.index)) if (CONTROLLER.player_id == 1) {
{ if (!player1_start_pressed_) {
if ((state_ != TitleState::LOGO_ANIMATING || ALLOW_TITLE_ANIMATION_SKIP)) player1_start_pressed_ = true;
{ getPlayer(1)->setPlayingState(PlayerState::TITLE_ANIMATION);
if (CONTROLLER.player_id == 1) setState(TitleState::START_HAS_BEEN_PRESSED);
{ counter_ = 0;
if (!player1_start_pressed_) }
{ }
player1_start_pressed_ = true;
getPlayer(1)->setPlayingState(PlayerState::TITLE_ANIMATION);
setState(TitleState::START_HAS_BEEN_PRESSED);
counter_ = 0;
}
}
if (CONTROLLER.player_id == 2) if (CONTROLLER.player_id == 2) {
{ if (!player2_start_pressed_) {
if (!player2_start_pressed_) player2_start_pressed_ = true;
{ getPlayer(2)->setPlayingState(PlayerState::TITLE_ANIMATION);
player2_start_pressed_ = true; setState(TitleState::START_HAS_BEEN_PRESSED);
getPlayer(2)->setPlayingState(PlayerState::TITLE_ANIMATION); counter_ = 0;
setState(TitleState::START_HAS_BEEN_PRESSED); }
counter_ = 0; }
} }
} }
} }
} }
}
}
// Comprueba los inputs que se pueden introducir en cualquier sección del juego // Comprueba los inputs que se pueden introducir en cualquier sección del juego
GlobalInputs::check(); GlobalInputs::check();
} }
// Bucle para el titulo del juego // Bucle para el titulo del juego
void Title::run() void Title::run() {
{ while (Section::name == Section::Name::TITLE) {
while (Section::name == Section::Name::TITLE) checkInput();
{ update();
checkInput(); checkEvents(); // Tiene que ir antes del render
update(); render();
checkEvents(); // Tiene que ir antes del render }
render();
}
} }
// Reinicia el contador interno // Reinicia el contador interno
void Title::resetCounter() { counter_ = 0; } void Title::resetCounter() { counter_ = 0; }
// Intercambia la asignación de mandos a los jugadores // Intercambia la asignación de mandos a los jugadores
void Title::swapControllers() void Title::swapControllers() {
{ if (Input::get()->getNumControllers() == 0)
if (Input::get()->getNumControllers() == 0) return;
return;
Options::swapControllers(); Options::swapControllers();
showControllers(); showControllers();
} }
// Intercambia el teclado de jugador // Intercambia el teclado de jugador
void Title::swapKeyboard() void Title::swapKeyboard() {
{ Options::swapKeyboard();
Options::swapKeyboard(); std::string text = Lang::getText("[DEFINE_BUTTONS] PLAYER") + std::to_string(Options::getPlayerWhoUsesKeyboard()) + ": " + Lang::getText("[DEFINE_BUTTONS] KEYBOARD");
std::string text = Lang::getText("[DEFINE_BUTTONS] PLAYER") + std::to_string(Options::getPlayerWhoUsesKeyboard()) + ": " + Lang::getText("[DEFINE_BUTTONS] KEYBOARD"); Notifier::get()->show({text});
Notifier::get()->show({text});
} }
// Muestra información sobre los controles y los jugadores // Muestra información sobre los controles y los jugadores
void Title::showControllers() void Title::showControllers() {
{ // Crea vectores de texto vacíos para un número máximo de mandos
// Crea vectores de texto vacíos para un número máximo de mandos constexpr size_t NUM_CONTROLLERS = 2;
constexpr size_t NUM_CONTROLLERS = 2; std::vector<std::string> text(NUM_CONTROLLERS);
std::vector<std::string> text(NUM_CONTROLLERS); std::vector<int> player_controller_index(NUM_CONTROLLERS, -1);
std::vector<int> player_controller_index(NUM_CONTROLLERS, -1);
// Obtiene de cada jugador el índice del mando que tiene asignado // Obtiene de cada jugador el índice del mando que tiene asignado
for (size_t i = 0; i < NUM_CONTROLLERS; ++i) for (size_t i = 0; i < NUM_CONTROLLERS; ++i) {
{ // Ejemplo: el jugador 1 tiene el mando 2
// Ejemplo: el jugador 1 tiene el mando 2 player_controller_index.at(Options::controllers.at(i).player_id - 1) = i;
player_controller_index.at(Options::controllers.at(i).player_id - 1) = i; }
}
// Genera el texto correspondiente // Genera el texto correspondiente
for (size_t i = 0; i < NUM_CONTROLLERS; ++i) for (size_t i = 0; i < NUM_CONTROLLERS; ++i) {
{ const size_t index = player_controller_index.at(i);
const size_t index = player_controller_index.at(i); if (Options::controllers.at(index).plugged) {
if (Options::controllers.at(index).plugged) text.at(i) = Lang::getText("[DEFINE_BUTTONS] PLAYER") + std::to_string(i + 1) + ": " + Options::controllers.at(index).name;
{ }
text.at(i) = Lang::getText("[DEFINE_BUTTONS] PLAYER") + std::to_string(i + 1) + ": " + Options::controllers.at(index).name; }
}
}
// Muestra la notificación // Muestra la notificación
Notifier::get()->show({text.at(0), text.at(1)}); Notifier::get()->show({text.at(0), text.at(1)});
} }
// Actualiza el fade // Actualiza el fade
void Title::updateFade() void Title::updateFade() {
{ fade_->update();
fade_->update(); if (fade_->hasEnded()) {
if (fade_->hasEnded()) const int COMBO = (player1_start_pressed_ ? 1 : 0) | (player2_start_pressed_ ? 2 : 0);
{
const int COMBO = (player1_start_pressed_ ? 1 : 0) | (player2_start_pressed_ ? 2 : 0);
switch (COMBO) switch (COMBO) {
{ case 0: // Ningún jugador ha pulsado Start
case 0: // Ningún jugador ha pulsado Start Section::name = next_section_;
Section::name = next_section_; break;
break;
case 1: // Solo el jugador 1 ha pulsado Start case 1: // Solo el jugador 1 ha pulsado Start
Section::name = Section::Name::GAME; Section::name = Section::Name::GAME;
Section::options = Section::Options::GAME_PLAY_1P; Section::options = Section::Options::GAME_PLAY_1P;
Audio::get()->stopMusic(); Audio::get()->stopMusic();
break; break;
case 2: // Solo el jugador 2 ha pulsado Start case 2: // Solo el jugador 2 ha pulsado Start
Section::name = Section::Name::GAME; Section::name = Section::Name::GAME;
Section::options = Section::Options::GAME_PLAY_2P; Section::options = Section::Options::GAME_PLAY_2P;
Audio::get()->stopMusic(); Audio::get()->stopMusic();
break; break;
case 3: // Ambos jugadores han pulsado Start case 3: // Ambos jugadores han pulsado Start
Section::name = Section::Name::GAME; Section::name = Section::Name::GAME;
Section::options = Section::Options::GAME_PLAY_BOTH; Section::options = Section::Options::GAME_PLAY_BOTH;
Audio::get()->stopMusic(); Audio::get()->stopMusic();
break; break;
} }
} }
} }
// Actualiza el estado // Actualiza el estado
void Title::updateState() void Title::updateState() {
{ // Establece la lógica según el estado
// Establece la lógica según el estado switch (state_) {
switch (state_) case TitleState::LOGO_ANIMATING: {
{ game_logo_->update();
case TitleState::LOGO_ANIMATING: if (game_logo_->hasFinished()) {
{ setState(TitleState::LOGO_FINISHED);
game_logo_->update(); }
if (game_logo_->hasFinished()) break;
{ }
setState(TitleState::LOGO_FINISHED); case TitleState::LOGO_FINISHED: {
} // El contador solo sube si no estamos definiendo botones
break; counter_ = define_buttons_->isEnabled() ? 0 : counter_ + 1;
}
case TitleState::LOGO_FINISHED:
{
// El contador solo sube si no estamos definiendo botones
counter_ = define_buttons_->isEnabled() ? 0 : counter_ + 1;
// Actualiza el logo con el título del juego // Actualiza el logo con el título del juego
game_logo_->update(); game_logo_->update();
// Actualiza el mosaico de fondo // Actualiza el mosaico de fondo
tiled_bg_->update(); tiled_bg_->update();
if (counter_ == param.title.title_duration) if (counter_ == param.title.title_duration) {
{ // El menu ha hecho time out
// El menu ha hecho time out fade_->setPostDuration(0);
fade_->setPostDuration(0); fade_->activate();
fade_->activate(); selection_ = Section::Options::TITLE_TIME_OUT;
selection_ = Section::Options::TITLE_TIME_OUT; }
}
break; break;
} }
case TitleState::START_HAS_BEEN_PRESSED: case TitleState::START_HAS_BEEN_PRESSED: {
{ // Actualiza el logo con el título del juego
// Actualiza el logo con el título del juego game_logo_->update();
game_logo_->update();
// Actualiza el mosaico de fondo // Actualiza el mosaico de fondo
tiled_bg_->update(); tiled_bg_->update();
if (counter_ == 100) if (counter_ == 100) {
{ fade_->activate();
fade_->activate(); }
} ++counter_;
++counter_; break;
break; }
}
default: default:
break; break;
} }
} }
void Title::updateStartPrompt() void Title::updateStartPrompt() {
{ constexpr Uint32 LOGO_BLINK_PERIOD = 833; // milisegundos
constexpr Uint32 LOGO_BLINK_PERIOD = 833; // milisegundos constexpr Uint32 LOGO_BLINK_ON_TIME = 583; // 833 - 250
constexpr Uint32 LOGO_BLINK_ON_TIME = 583; // 833 - 250
constexpr Uint32 START_BLINK_PERIOD = 167; constexpr Uint32 START_BLINK_PERIOD = 167;
constexpr Uint32 START_BLINK_ON_TIME = 83; // 167 - 83 constexpr Uint32 START_BLINK_ON_TIME = 83; // 167 - 83
Uint32 time_ms = SDL_GetTicks(); Uint32 time_ms = SDL_GetTicks();
bool condition_met = false; bool condition_met = false;
if (!define_buttons_->isEnabled()) if (!define_buttons_->isEnabled()) {
{ switch (state_) {
switch (state_) case TitleState::LOGO_FINISHED:
{ condition_met = (time_ms % LOGO_BLINK_PERIOD) >= (LOGO_BLINK_PERIOD - LOGO_BLINK_ON_TIME);
case TitleState::LOGO_FINISHED: break;
condition_met = (time_ms % LOGO_BLINK_PERIOD) >= (LOGO_BLINK_PERIOD - LOGO_BLINK_ON_TIME);
break;
case TitleState::START_HAS_BEEN_PRESSED: case TitleState::START_HAS_BEEN_PRESSED:
condition_met = (time_ms % START_BLINK_PERIOD) >= (START_BLINK_PERIOD - START_BLINK_ON_TIME); condition_met = (time_ms % START_BLINK_PERIOD) >= (START_BLINK_PERIOD - START_BLINK_ON_TIME);
break; break;
default: default:
break; break;
} }
} }
should_render_start_prompt = condition_met; should_render_start_prompt = condition_met;
} }
void Title::renderStartPrompt() void Title::renderStartPrompt() {
{ if (should_render_start_prompt) {
if (should_render_start_prompt) text_->writeDX(TEXT_CENTER | TEXT_SHADOW,
{ param.game.game_area.center_x,
text_->writeDX(TEXT_CENTER | TEXT_SHADOW, param.title.press_start_position,
param.game.game_area.center_x, Lang::getText("[TITLE] PRESS_BUTTON_TO_PLAY"),
param.title.press_start_position, 1,
Lang::getText("[TITLE] PRESS_BUTTON_TO_PLAY"), NO_TEXT_COLOR,
1, 1,
NO_TEXT_COLOR, TITLE_SHADOW_TEXT_COLOR);
1, }
TITLE_SHADOW_TEXT_COLOR);
}
} }
void Title::renderCopyright() void Title::renderCopyright() {
{ if (state_ != TitleState::LOGO_ANIMATING) {
if (state_ != TitleState::LOGO_ANIMATING) // Mini logo
{ mini_logo_sprite_->render();
// Mini logo
mini_logo_sprite_->render();
// Texto con el copyright // Texto con el copyright
text_->writeDX(TEXT_CENTER | TEXT_SHADOW, text_->writeDX(TEXT_CENTER | TEXT_SHADOW,
param.game.game_area.center_x, param.game.game_area.center_x,
anchor_.copyright_text, anchor_.copyright_text,
TEXT_COPYRIGHT, TEXT_COPYRIGHT,
1, 1,
NO_TEXT_COLOR, NO_TEXT_COLOR,
1, 1,
TITLE_SHADOW_TEXT_COLOR); TITLE_SHADOW_TEXT_COLOR);
} }
} }
// Cambia el estado // Cambia el estado
void Title::setState(TitleState state) void Title::setState(TitleState state) {
{ if (state_ == state)
if (state_ == state) return;
return;
state_ = state; state_ = state;
switch (state_) switch (state_) {
{ case TitleState::LOGO_ANIMATING:
case TitleState::LOGO_ANIMATING: break;
break; case TitleState::LOGO_FINISHED:
case TitleState::LOGO_FINISHED: Audio::get()->playMusic("title.ogg");
Audio::get()->playMusic("title.ogg"); break;
break; case TitleState::START_HAS_BEEN_PRESSED:
case TitleState::START_HAS_BEEN_PRESSED: Audio::get()->fadeOutMusic(1500);
Audio::get()->fadeOutMusic(1500); break;
break; }
}
} }
// Inicializa los jugadores // Inicializa los jugadores
void Title::initPlayers() void Title::initPlayers() {
{ std::vector<std::vector<std::shared_ptr<Texture>>> player_textures; // Vector con todas las texturas de los jugadores;
std::vector<std::vector<std::shared_ptr<Texture>>> player_textures; // Vector con todas las texturas de los jugadores; std::vector<std::vector<std::string>> player_animations; // Vector con las animaciones del jugador
std::vector<std::vector<std::string>> player_animations; // Vector con las animaciones del jugador
// Texturas - Player1 // Texturas - Player1
{ {
std::vector<std::shared_ptr<Texture>> player_texture; std::vector<std::shared_ptr<Texture>> player_texture;
player_texture.emplace_back(Resource::get()->getTexture("player1.gif")); player_texture.emplace_back(Resource::get()->getTexture("player1.gif"));
player_texture.emplace_back(Resource::get()->getTexture("player1_power.png")); player_texture.emplace_back(Resource::get()->getTexture("player1_power.png"));
player_textures.push_back(player_texture); player_textures.push_back(player_texture);
} }
// Texturas - Player2 // Texturas - Player2
{ {
std::vector<std::shared_ptr<Texture>> player_texture; std::vector<std::shared_ptr<Texture>> player_texture;
player_texture.emplace_back(Resource::get()->getTexture("player2.gif")); player_texture.emplace_back(Resource::get()->getTexture("player2.gif"));
player_texture.emplace_back(Resource::get()->getTexture("player2_power.png")); player_texture.emplace_back(Resource::get()->getTexture("player2_power.png"));
player_textures.push_back(player_texture); player_textures.push_back(player_texture);
} }
// Animaciones -- Jugador // Animaciones -- Jugador
{ {
player_animations.emplace_back(Resource::get()->getAnimation("player.ani")); player_animations.emplace_back(Resource::get()->getAnimation("player.ani"));
player_animations.emplace_back(Resource::get()->getAnimation("player_power.ani")); player_animations.emplace_back(Resource::get()->getAnimation("player_power.ani"));
} }
// Crea los dos jugadores // Crea los dos jugadores
constexpr int PLAYER_WIDTH = 32; constexpr int PLAYER_WIDTH = 32;
constexpr int PLAYER_HEIGHT = 32; constexpr int PLAYER_HEIGHT = 32;
const int Y = param.title.press_start_position - (PLAYER_HEIGHT / 2); const int Y = param.title.press_start_position - (PLAYER_HEIGHT / 2);
constexpr bool DEMO = false; constexpr bool DEMO = false;
players_.emplace_back(std::make_unique<Player>(1, param.game.game_area.center_x - (PLAYER_WIDTH / 2), Y, DEMO, param.game.play_area.rect, player_textures.at(0), player_animations)); players_.emplace_back(std::make_unique<Player>(1, param.game.game_area.center_x - (PLAYER_WIDTH / 2), Y, DEMO, param.game.play_area.rect, player_textures.at(0), player_animations));
players_.back()->setPlayingState(PlayerState::TITLE_HIDDEN); players_.back()->setPlayingState(PlayerState::TITLE_HIDDEN);
players_.emplace_back(std::make_unique<Player>(2, param.game.game_area.center_x - (PLAYER_WIDTH / 2), Y, DEMO, param.game.play_area.rect, player_textures.at(1), player_animations)); players_.emplace_back(std::make_unique<Player>(2, param.game.game_area.center_x - (PLAYER_WIDTH / 2), Y, DEMO, param.game.play_area.rect, player_textures.at(1), player_animations));
players_.back()->setPlayingState(PlayerState::TITLE_HIDDEN); players_.back()->setPlayingState(PlayerState::TITLE_HIDDEN);
} }
// Actualza los jugadores // Actualza los jugadores
void Title::updatePlayers() void Title::updatePlayers() {
{ for (auto &player : players_) {
for (auto &player : players_) player->update();
{ }
player->update();
}
} }
// Renderiza los jugadores // Renderiza los jugadores
void Title::renderPlayers() void Title::renderPlayers() {
{ for (auto const &player : players_) {
for (auto const &player : players_) player->render();
{ }
player->render();
}
} }
// Obtiene un jugador a partir de su "id" // Obtiene un jugador a partir de su "id"
std::shared_ptr<Player> Title::getPlayer(int id) std::shared_ptr<Player> Title::getPlayer(int id) {
{ auto it = std::find_if(players_.begin(), players_.end(), [id](const auto &player) { return player->getId() == id; });
auto it = std::find_if(players_.begin(), players_.end(), [id](const auto &player)
{ return player->getId() == id; });
if (it != players_.end()) if (it != players_.end()) {
{ return *it;
return *it; }
} return nullptr;
return nullptr;
} }
+65 -67
View File
@@ -1,10 +1,11 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para Uint32 #include <SDL3/SDL.h> // Para Uint32
#include <memory> // Para unique_ptr, shared_ptr
#include <memory> // Para unique_ptr, shared_ptr
#include <vector> #include <vector>
#include "section.h" // Para Options #include "section.h" // Para Options
class DefineButtons; class DefineButtons;
class Fade; class Fade;
@@ -21,78 +22,75 @@ constexpr const char TEXT_COPYRIGHT[] = "@2020,2025 JailDesigner";
constexpr bool ALLOW_TITLE_ANIMATION_SKIP = false; constexpr bool ALLOW_TITLE_ANIMATION_SKIP = false;
/* /*
Clase que gestiona el estado de título/menú principal del juego. Clase que gestiona el estado de título/menú principal del juego.
Responsable de mostrar el logo, el fondo animado y gestionar la entrada para comenzar la partida. Responsable de mostrar el logo, el fondo animado y gestionar la entrada para comenzar la partida.
No permite saltar la animación del título salvo que se cambie el define. No permite saltar la animación del título salvo que se cambie el define.
*/ */
// Clase Title // Clase Title
class Title class Title {
{ public:
public: // --- Constructores y destructor ---
// --- Constructores y destructor --- Title();
Title(); ~Title();
~Title();
// --- Método principal --- // --- Método principal ---
void run(); // Bucle para el título del juego void run(); // Bucle para el título del juego
private: private:
// --- Enumeraciones --- // --- Enumeraciones ---
enum class TitleState enum class TitleState {
{ LOGO_ANIMATING, // El logo está animándose
LOGO_ANIMATING, // El logo está animándose LOGO_FINISHED, // El logo ha terminado de animarse
LOGO_FINISHED, // El logo ha terminado de animarse START_HAS_BEEN_PRESSED, // Se ha pulsado el botón de start
START_HAS_BEEN_PRESSED, // Se ha pulsado el botón de start };
};
// --- Estructura para definir anclas --- // --- Estructura para definir anclas ---
struct Anchor struct Anchor {
{ int mini_logo;
int mini_logo; int copyright_text;
int copyright_text; };
};
// --- Objetos y punteros --- // --- Objetos y punteros ---
std::shared_ptr<Text> text_; // Objeto de texto para escribir en pantalla std::shared_ptr<Text> text_; // Objeto de texto para escribir en pantalla
std::unique_ptr<Fade> fade_; // Fundido en pantalla std::unique_ptr<Fade> fade_; // Fundido en pantalla
std::unique_ptr<TiledBG> tiled_bg_; // Fondo animado de tiles std::unique_ptr<TiledBG> tiled_bg_; // Fondo animado de tiles
std::unique_ptr<GameLogo> game_logo_; // Logo del juego std::unique_ptr<GameLogo> game_logo_; // Logo del juego
std::unique_ptr<Sprite> mini_logo_sprite_; // Logo JailGames mini std::unique_ptr<Sprite> mini_logo_sprite_; // Logo JailGames mini
std::unique_ptr<DefineButtons> define_buttons_; // Definición de botones del joystick std::unique_ptr<DefineButtons> define_buttons_; // Definición de botones del joystick
std::vector<std::shared_ptr<Player>> players_; // Vector de jugadores std::vector<std::shared_ptr<Player>> players_; // Vector de jugadores
// --- Variables de estado --- // --- Variables de estado ---
int counter_ = 0; // Temporizador para la pantalla de título int counter_ = 0; // Temporizador para la pantalla de título
Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad Uint64 ticks_ = 0; // Contador de ticks para ajustar la velocidad
Section::Name next_section_; // Siguiente sección a cargar Section::Name next_section_; // Siguiente sección a cargar
Section::Options selection_ = Section::Options::TITLE_TIME_OUT; // Opción elegida en el título Section::Options selection_ = Section::Options::TITLE_TIME_OUT; // Opción elegida en el título
int num_controllers_; // Número de mandos conectados int num_controllers_; // Número de mandos conectados
TitleState state_; // Estado actual de la sección TitleState state_; // Estado actual de la sección
bool should_render_start_prompt = false; // Indica si se muestra o no el texto de PRESS START BUTTON TO PLAY bool should_render_start_prompt = false; // Indica si se muestra o no el texto de PRESS START BUTTON TO PLAY
bool player1_start_pressed_ = false; // Indica si se ha pulsdo el boton de empezar a jugar para el jugador 1 bool player1_start_pressed_ = false; // Indica si se ha pulsdo el boton de empezar a jugar para el jugador 1
bool player2_start_pressed_ = false; // Indica si se ha pulsdo el boton de empezar a jugar para el jugador 2 bool player2_start_pressed_ = false; // Indica si se ha pulsdo el boton de empezar a jugar para el jugador 2
// -- Variables de diseño --- // -- Variables de diseño ---
Anchor anchor_; // Anclas para definir la posición de los elementos del titulo Anchor anchor_; // Anclas para definir la posición de los elementos del titulo
// --- Métodos internos --- // --- Métodos internos ---
void update(); // Actualiza las variables del objeto void update(); // Actualiza las variables del objeto
void render(); // Dibuja el objeto en pantalla void render(); // Dibuja el objeto en pantalla
void checkEvents(); // Comprueba los eventos void checkEvents(); // Comprueba los eventos
void checkInput(); // Comprueba las entradas void checkInput(); // Comprueba las entradas
void resetCounter(); // Reinicia el contador interno void resetCounter(); // Reinicia el contador interno
void swapControllers(); // Intercambia la asignación de mandos a los jugadores void swapControllers(); // Intercambia la asignación de mandos a los jugadores
void swapKeyboard(); // Intercambia el teclado de jugador void swapKeyboard(); // Intercambia el teclado de jugador
void showControllers(); // Muestra información sobre los controles y los jugadores void showControllers(); // Muestra información sobre los controles y los jugadores
void updateFade(); // Actualiza el efecto de fundido (fade in/out) void updateFade(); // Actualiza el efecto de fundido (fade in/out)
void updateState(); // Actualiza el estado actual del título void updateState(); // Actualiza el estado actual del título
void updateStartPrompt(); // Actualiza el mensaje de "Pulsa Start" void updateStartPrompt(); // Actualiza el mensaje de "Pulsa Start"
void renderStartPrompt(); // Dibuja el mensaje de "Pulsa Start" en pantalla void renderStartPrompt(); // Dibuja el mensaje de "Pulsa Start" en pantalla
void renderCopyright(); // Dibuja el aviso de copyright void renderCopyright(); // Dibuja el aviso de copyright
void setState(TitleState state); // Cambia el estado del título void setState(TitleState state); // Cambia el estado del título
void initPlayers(); // Inicializa los jugadores void initPlayers(); // Inicializa los jugadores
void renderPlayers(); // Renderiza los jugadores void renderPlayers(); // Renderiza los jugadores
void updatePlayers(); // Actualza los jugadores void updatePlayers(); // Actualza los jugadores
std::shared_ptr<Player> getPlayer(int id); // Obtiene un jugador a partir de su "id" std::shared_ptr<Player> getPlayer(int id); // Obtiene un jugador a partir de su "id"
}; };
+66 -84
View File
@@ -1,104 +1,86 @@
#include "smart_sprite.h" #include "smart_sprite.h"
#include "moving_sprite.h" // Para MovingSprite #include "moving_sprite.h" // Para MovingSprite
// Actualiza la posición y comprueba si ha llegado a su destino // Actualiza la posición y comprueba si ha llegado a su destino
void SmartSprite::update() void SmartSprite::update() {
{ if (enabled_) {
if (enabled_) MovingSprite::update();
{ checkMove();
MovingSprite::update(); checkFinished();
checkMove(); }
checkFinished();
}
} }
// Dibuja el sprite // Dibuja el sprite
void SmartSprite::render() void SmartSprite::render() {
{ if (enabled_) {
if (enabled_) MovingSprite::render();
{ }
MovingSprite::render();
}
} }
// Comprueba el movimiento // Comprueba el movimiento
void SmartSprite::checkMove() void SmartSprite::checkMove() {
{ // Comprueba si se desplaza en el eje X hacia la derecha
// Comprueba si se desplaza en el eje X hacia la derecha if (getAccelX() > 0 || getVelX() > 0) {
if (getAccelX() > 0 || getVelX() > 0) // Comprueba si ha llegado al destino
{ if (getPosX() > dest_x_) {
// Comprueba si ha llegado al destino // Lo coloca en posición
if (getPosX() > dest_x_) setPosX(dest_x_);
{
// Lo coloca en posición
setPosX(dest_x_);
// Lo detiene // Lo detiene
setVelX(0.0f); setVelX(0.0f);
setAccelX(0.0f); setAccelX(0.0f);
} }
} }
// Comprueba si se desplaza en el eje X hacia la izquierda // Comprueba si se desplaza en el eje X hacia la izquierda
else if (getAccelX() < 0 || getVelX() < 0) else if (getAccelX() < 0 || getVelX() < 0) {
{ // Comprueba si ha llegado al destino
// Comprueba si ha llegado al destino if (getPosX() < dest_x_) {
if (getPosX() < dest_x_) // Lo coloca en posición
{ setPosX(dest_x_);
// Lo coloca en posición
setPosX(dest_x_);
// Lo detiene // Lo detiene
setVelX(0.0f); setVelX(0.0f);
setAccelX(0.0f); setAccelX(0.0f);
} }
} }
// Comprueba si se desplaza en el eje Y hacia abajo // Comprueba si se desplaza en el eje Y hacia abajo
if (getAccelY() > 0 || getVelY() > 0) if (getAccelY() > 0 || getVelY() > 0) {
{ // Comprueba si ha llegado al destino
// Comprueba si ha llegado al destino if (getPosY() > dest_y_) {
if (getPosY() > dest_y_) // Lo coloca en posición
{ setPosY(dest_y_);
// Lo coloca en posición
setPosY(dest_y_);
// Lo detiene // Lo detiene
setVelY(0.0f); setVelY(0.0f);
setAccelY(0.0f); setAccelY(0.0f);
} }
} }
// Comprueba si se desplaza en el eje Y hacia arriba // Comprueba si se desplaza en el eje Y hacia arriba
else if (getAccelY() < 0 || getVelY() < 0) else if (getAccelY() < 0 || getVelY() < 0) {
{ // Comprueba si ha llegado al destino
// Comprueba si ha llegado al destino if (getPosY() < dest_y_) {
if (getPosY() < dest_y_) // Lo coloca en posición
{ setPosY(dest_y_);
// Lo coloca en posición
setPosY(dest_y_);
// Lo detiene // Lo detiene
setVelY(0.0f); setVelY(0.0f);
setAccelY(0.0f); setAccelY(0.0f);
} }
} }
} }
// Comprueba si ha terminado // Comprueba si ha terminado
void SmartSprite::checkFinished() void SmartSprite::checkFinished() {
{ // Comprueba si ha llegado a su destino
// Comprueba si ha llegado a su destino on_destination_ = (getPosX() == dest_x_ && getPosY() == dest_y_);
on_destination_ = (getPosX() == dest_x_ && getPosY() == dest_y_);
if (on_destination_) if (on_destination_) {
{ if (finished_counter_ == 0) {
if (finished_counter_ == 0) finished_ = true;
{ } else {
finished_ = true; --finished_counter_;
} }
else }
{
--finished_counter_;
}
}
} }
+32 -33
View File
@@ -1,46 +1,45 @@
#pragma once #pragma once
#include <memory> // Para shared_ptr #include <memory> // Para shared_ptr
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
class Texture; class Texture;
// Clase SmartSprite: Sprite animado que se mueve hacia un destino y puede deshabilitarse automáticamente // Clase SmartSprite: Sprite animado que se mueve hacia un destino y puede deshabilitarse automáticamente
class SmartSprite : public AnimatedSprite class SmartSprite : public AnimatedSprite {
{ public:
public: // --- Constructor y destructor ---
// --- Constructor y destructor --- explicit SmartSprite(std::shared_ptr<Texture> texture)
explicit SmartSprite(std::shared_ptr<Texture> texture) : AnimatedSprite(texture) {}
: AnimatedSprite(texture) {} ~SmartSprite() override = default;
~SmartSprite() override = default;
// --- Métodos principales --- // --- Métodos principales ---
void update() override; // Actualiza la posición y comprueba si ha llegado a su destino void update() override; // Actualiza la posición y comprueba si ha llegado a su destino
void render() override; // Dibuja el sprite void render() override; // Dibuja el sprite
// --- Getters --- // --- Getters ---
int getDestX() const { return dest_x_; } // Obtiene la posición de destino en X int getDestX() const { return dest_x_; } // Obtiene la posición de destino en X
int getDestY() const { return dest_y_; } // Obtiene la posición de destino en Y int getDestY() const { return dest_y_; } // Obtiene la posición de destino en Y
bool isOnDestination() const { return on_destination_; } // Indica si está en el destino bool isOnDestination() const { return on_destination_; } // Indica si está en el destino
bool hasFinished() const { return finished_; } // Indica si ya ha terminado bool hasFinished() const { return finished_; } // Indica si ya ha terminado
// --- Setters --- // --- Setters ---
void setFinishedCounter(int value) { finished_counter_ = value; } // Establece el contador para deshabilitarlo void setFinishedCounter(int value) { finished_counter_ = value; } // Establece el contador para deshabilitarlo
void setDestX(int x) { dest_x_ = x; } // Establece la posición de destino en X void setDestX(int x) { dest_x_ = x; } // Establece la posición de destino en X
void setDestY(int y) { dest_y_ = y; } // Establece la posición de destino en Y void setDestY(int y) { dest_y_ = y; } // Establece la posición de destino en Y
void setEnabled(bool value) { enabled_ = value; } // Habilita o deshabilita el objeto void setEnabled(bool value) { enabled_ = value; } // Habilita o deshabilita el objeto
private: private:
// --- Variables internas --- // --- Variables internas ---
bool on_destination_ = false; // Indica si está en el destino bool on_destination_ = false; // Indica si está en el destino
int dest_x_ = 0; // Posición de destino en el eje X int dest_x_ = 0; // Posición de destino en el eje X
int dest_y_ = 0; // Posición de destino en el eje Y int dest_y_ = 0; // Posición de destino en el eje Y
int finished_counter_ = 0; // Contador para deshabilitarlo int finished_counter_ = 0; // Contador para deshabilitarlo
bool finished_ = false; // Indica si ya ha terminado bool finished_ = false; // Indica si ya ha terminado
bool enabled_ = false; // Indica si el objeto está habilitado bool enabled_ = false; // Indica si el objeto está habilitado
// --- Métodos internos --- // --- Métodos internos ---
void checkFinished(); // Comprueba si ha terminado void checkFinished(); // Comprueba si ha terminado
void checkMove(); // Comprueba el movimiento void checkMove(); // Comprueba el movimiento
}; };
+21 -25
View File
@@ -1,46 +1,42 @@
#include "sprite.h" #include "sprite.h"
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
// Constructor // Constructor
Sprite::Sprite(std::shared_ptr<Texture> texture, float x, float y, float w, float h) Sprite::Sprite(std::shared_ptr<Texture> texture, float x, float y, float w, float h)
: texture_(texture), : texture_(texture),
pos_((SDL_FRect){x, y, w, h}), pos_((SDL_FRect){x, y, w, h}),
sprite_clip_((SDL_FRect){0, 0, pos_.w, pos_.h}) {} sprite_clip_((SDL_FRect){0, 0, pos_.w, pos_.h}) {}
Sprite::Sprite(std::shared_ptr<Texture> texture, SDL_FRect rect) Sprite::Sprite(std::shared_ptr<Texture> texture, SDL_FRect rect)
: texture_(texture), : texture_(texture),
pos_(rect), pos_(rect),
sprite_clip_((SDL_FRect){0, 0, pos_.w, pos_.h}) {} sprite_clip_((SDL_FRect){0, 0, pos_.w, pos_.h}) {}
Sprite::Sprite(std::shared_ptr<Texture> texture) Sprite::Sprite(std::shared_ptr<Texture> texture)
: texture_(texture), : texture_(texture),
pos_(SDL_FRect{0, 0, static_cast<float>(texture_->getWidth()), static_cast<float>(texture_->getHeight())}), pos_(SDL_FRect{0, 0, static_cast<float>(texture_->getWidth()), static_cast<float>(texture_->getHeight())}),
sprite_clip_(pos_) {} sprite_clip_(pos_) {}
// Muestra el sprite por pantalla // Muestra el sprite por pantalla
void Sprite::render() void Sprite::render() {
{ texture_->render(pos_.x, pos_.y, &sprite_clip_, zoom_, zoom_);
texture_->render(pos_.x, pos_.y, &sprite_clip_, zoom_, zoom_);
} }
// Establece la posición del objeto // Establece la posición del objeto
void Sprite::setPosition(float x, float y) void Sprite::setPosition(float x, float y) {
{ pos_.x = x;
pos_.x = x; pos_.y = y;
pos_.y = y;
} }
// Establece la posición del objeto // Establece la posición del objeto
void Sprite::setPosition(SDL_FPoint p) void Sprite::setPosition(SDL_FPoint p) {
{ pos_.x = p.x;
pos_.x = p.x; pos_.y = p.y;
pos_.y = p.y;
} }
// Reinicia las variables a cero // Reinicia las variables a cero
void Sprite::clear() void Sprite::clear() {
{ pos_ = {0, 0, 0, 0};
pos_ = {0, 0, 0, 0}; sprite_clip_ = {0, 0, 0, 0};
sprite_clip_ = {0, 0, 0, 0};
} }
+12 -12
View File
@@ -1,14 +1,14 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_FRect, SDL_FPoint #include <SDL3/SDL.h> // Para SDL_FRect, SDL_FPoint
#include <memory> // Para shared_ptr
#include <memory> // Para shared_ptr
class Texture; class Texture;
// Clase Sprite: representa un objeto gráfico básico con posición, tamaño y textura // Clase Sprite: representa un objeto gráfico básico con posición, tamaño y textura
class Sprite class Sprite {
{ public:
public:
// --- Constructores y destructor --- // --- Constructores y destructor ---
Sprite(std::shared_ptr<Texture> texture, float x, float y, float w, float h); Sprite(std::shared_ptr<Texture> texture, float x, float y, float w, float h);
Sprite(std::shared_ptr<Texture> texture, SDL_FRect rect); Sprite(std::shared_ptr<Texture> texture, SDL_FRect rect);
@@ -16,8 +16,8 @@ public:
virtual ~Sprite() = default; virtual ~Sprite() = default;
// --- Renderizado y control --- // --- Renderizado y control ---
virtual void render(); // Muestra el sprite por pantalla virtual void render(); // Muestra el sprite por pantalla
virtual void clear(); // Reinicia las variables a cero virtual void clear(); // Reinicia las variables a cero
// --- Getters de posición y tamaño --- // --- Getters de posición y tamaño ---
float getX() const { return pos_.x; } float getX() const { return pos_.x; }
@@ -52,10 +52,10 @@ public:
std::shared_ptr<Texture> getTexture() const { return texture_; } std::shared_ptr<Texture> getTexture() const { return texture_; }
void setTexture(std::shared_ptr<Texture> texture) { texture_ = texture; } void setTexture(std::shared_ptr<Texture> texture) { texture_ = texture; }
protected: protected:
// --- Variables internas --- // --- Variables internas ---
std::shared_ptr<Texture> texture_; // Textura donde están todos los dibujos del sprite std::shared_ptr<Texture> texture_; // Textura donde están todos los dibujos del sprite
SDL_FRect pos_; // Posición y tamaño donde dibujar el sprite SDL_FRect pos_; // Posición y tamaño donde dibujar el sprite
SDL_FRect sprite_clip_; // Rectángulo de origen de la textura que se dibujará en pantalla SDL_FRect sprite_clip_; // Rectángulo de origen de la textura que se dibujará en pantalla
double zoom_ = 1.0f; // Zoom aplicado a la textura double zoom_ = 1.0f; // Zoom aplicado a la textura
}; };
+35 -39
View File
@@ -1,47 +1,43 @@
#include "stage.h" #include "stage.h"
#include <algorithm> // Para min #include <algorithm> // Para min
#include <vector> // Para vector #include <vector> // Para vector
namespace Stage namespace Stage {
{
std::vector<Stage> stages; // Variable con los datos de cada pantalla std::vector<Stage> stages; // Variable con los datos de cada pantalla
int power = 0; // Poder acumulado en la fase int power = 0; // Poder acumulado en la fase
int total_power = 0; // Poder total necesario para completar el juego int total_power = 0; // Poder total necesario para completar el juego
int number = 0; // Fase actual int number = 0; // Fase actual
bool power_can_be_added = true; // Habilita la recolecta de poder bool power_can_be_added = true; // Habilita la recolecta de poder
// Devuelve una fase // Devuelve una fase
Stage get(int index) { return stages.at(std::min(9, index)); } Stage get(int index) { return stages.at(std::min(9, index)); }
// Inicializa las variables del namespace Stage // Inicializa las variables del namespace Stage
void init() void init() {
{ stages.clear();
stages.clear(); stages.emplace_back(Stage(200, 7 + (4 * 1), 7 + (4 * 3)));
stages.emplace_back(Stage(200, 7 + (4 * 1), 7 + (4 * 3))); stages.emplace_back(Stage(300, 7 + (4 * 2), 7 + (4 * 4)));
stages.emplace_back(Stage(300, 7 + (4 * 2), 7 + (4 * 4))); stages.emplace_back(Stage(600, 7 + (4 * 3), 7 + (4 * 5)));
stages.emplace_back(Stage(600, 7 + (4 * 3), 7 + (4 * 5))); stages.emplace_back(Stage(600, 7 + (4 * 3), 7 + (4 * 5)));
stages.emplace_back(Stage(600, 7 + (4 * 3), 7 + (4 * 5))); stages.emplace_back(Stage(600, 7 + (4 * 4), 7 + (4 * 6)));
stages.emplace_back(Stage(600, 7 + (4 * 4), 7 + (4 * 6))); stages.emplace_back(Stage(600, 7 + (4 * 4), 7 + (4 * 6)));
stages.emplace_back(Stage(600, 7 + (4 * 4), 7 + (4 * 6))); stages.emplace_back(Stage(650, 7 + (4 * 5), 7 + (4 * 7)));
stages.emplace_back(Stage(650, 7 + (4 * 5), 7 + (4 * 7))); stages.emplace_back(Stage(750, 7 + (4 * 5), 7 + (4 * 7)));
stages.emplace_back(Stage(750, 7 + (4 * 5), 7 + (4 * 7))); stages.emplace_back(Stage(850, 7 + (4 * 6), 7 + (4 * 8)));
stages.emplace_back(Stage(850, 7 + (4 * 6), 7 + (4 * 8))); stages.emplace_back(Stage(950, 7 + (4 * 7), 7 + (4 * 10)));
stages.emplace_back(Stage(950, 7 + (4 * 7), 7 + (4 * 10)));
power = 0; power = 0;
total_power = 0; total_power = 0;
number = 0; number = 0;
}
// Añade poder
void addPower(int amount) {
if (power_can_be_added) {
power += amount;
total_power += amount;
} }
}
// Añade poder } // namespace Stage
void addPower(int amount)
{
if (power_can_be_added)
{
power += amount;
total_power += amount;
}
}
}
+21 -23
View File
@@ -7,29 +7,27 @@
Permite consultar y modificar el poder necesario, la amenaza y el estado de cada fase. Permite consultar y modificar el poder necesario, la amenaza y el estado de cada fase.
*/ */
namespace Stage namespace Stage {
{ // --- Estructura con los datos de una fase ---
// --- Estructura con los datos de una fase --- struct Stage {
struct Stage int power_to_complete; // Cantidad de poder que se necesita para completar la fase
{ int min_menace; // Umbral mínimo de amenaza de la fase
int power_to_complete; // Cantidad de poder que se necesita para completar la fase int max_menace; // Umbral máximo de amenaza de la fase
int min_menace; // Umbral mínimo de amenaza de la fase
int max_menace; // Umbral máximo de amenaza de la fase
// Constructor // Constructor
Stage(int power_to_complete, int min_menace, int max_menace) Stage(int power_to_complete, int min_menace, int max_menace)
: power_to_complete(power_to_complete), min_menace(min_menace), max_menace(max_menace) {} : power_to_complete(power_to_complete), min_menace(min_menace), max_menace(max_menace) {}
}; };
// --- Variables globales del estado de las fases --- // --- Variables globales del estado de las fases ---
extern std::vector<Stage> stages; // Vector con los datos de cada pantalla extern std::vector<Stage> stages; // Vector con los datos de cada pantalla
extern int power; // Poder acumulado en la fase actual extern int power; // Poder acumulado en la fase actual
extern int total_power; // Poder total necesario para completar el juego extern int total_power; // Poder total necesario para completar el juego
extern int number; // Índice de la fase actual extern int number; // Índice de la fase actual
extern bool power_can_be_added; // Indica si se puede añadir poder a la fase extern bool power_can_be_added; // Indica si se puede añadir poder a la fase
// --- Funciones principales --- // --- Funciones principales ---
Stage get(int index); // Devuelve una fase por índice Stage get(int index); // Devuelve una fase por índice
void init(); // Inicializa las variables del namespace Stage void init(); // Inicializa las variables del namespace Stage
void addPower(int amount); // Añade poder a la fase actual void addPower(int amount); // Añade poder a la fase actual
} } // namespace Stage
+76 -108
View File
@@ -1,16 +1,17 @@
// IWYU pragma: no_include <bits/std_abs.h> // IWYU pragma: no_include <bits/std_abs.h>
#include "tabe.h" #include "tabe.h"
#include <SDL3/SDL.h> // Para SDL_FlipMode, SDL_GetTicks #include <SDL3/SDL.h> // Para SDL_FlipMode, SDL_GetTicks
#include <stdlib.h> // Para rand, abs #include <stdlib.h> // Para rand, abs
#include <algorithm> // Para max #include <algorithm> // Para max
#include <cmath> // Para abs #include <cmath> // Para abs
#include <string> // Para basic_string #include <string> // Para basic_string
#include "audio.h" // Para Audio #include "audio.h" // Para Audio
#include "param.h" // Para Param, ParamGame, param #include "param.h" // Para Param, ParamGame, param
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
#include "utils.h" // Para Zone #include "utils.h" // Para Zone
// Constructor // Constructor
Tabe::Tabe() Tabe::Tabe()
@@ -18,33 +19,27 @@ Tabe::Tabe()
timer_(TabeTimer(2.5f, 4.0f)) {} timer_(TabeTimer(2.5f, 4.0f)) {}
// Actualiza la lógica // Actualiza la lógica
void Tabe::update() void Tabe::update() {
{ if (enabled_) {
if (enabled_)
{
sprite_->update(); sprite_->update();
move(); move();
updateState(); updateState();
} }
timer_.update(); timer_.update();
if (timer_.should_spawn()) if (timer_.should_spawn()) {
{
enable(); enable();
} }
} }
// Dibuja el objeto // Dibuja el objeto
void Tabe::render() void Tabe::render() {
{ if (enabled_) {
if (enabled_)
{
sprite_->render(); sprite_->render();
} }
} }
// Mueve el objeto // Mueve el objeto
void Tabe::move() void Tabe::move() {
{
const int x = static_cast<int>(x_); const int x = static_cast<int>(x_);
speed_ += accel_; speed_ += accel_;
x_ += speed_; x_ += speed_;
@@ -53,48 +48,37 @@ void Tabe::move()
// Comprueba si sale por los bordes // Comprueba si sale por los bordes
const float min_x = param.game.game_area.rect.x - WIDTH_; const float min_x = param.game.game_area.rect.x - WIDTH_;
const float max_x = param.game.game_area.rect.x + param.game.game_area.rect.w; const float max_x = param.game.game_area.rect.x + param.game.game_area.rect.w;
switch (destiny_) switch (destiny_) {
{ case TabeDirection::TO_THE_LEFT: {
case TabeDirection::TO_THE_LEFT: if (x_ < min_x) {
{ disable();
if (x_ < min_x) }
{ if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_ && direction_ == TabeDirection::TO_THE_RIGHT) {
disable(); setRandomFlyPath(TabeDirection::TO_THE_LEFT, 80);
x_ = param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_;
}
break;
} }
if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_ && direction_ == TabeDirection::TO_THE_RIGHT)
{ case TabeDirection::TO_THE_RIGHT: {
setRandomFlyPath(TabeDirection::TO_THE_LEFT, 80); if (x_ > max_x) {
x_ = param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_; disable();
}
if (x_ < param.game.game_area.rect.x && direction_ == TabeDirection::TO_THE_LEFT) {
setRandomFlyPath(TabeDirection::TO_THE_RIGHT, 80);
x_ = param.game.game_area.rect.x;
}
break;
} }
break; default:
break;
} }
case TabeDirection::TO_THE_RIGHT: if (fly_distance_ <= 0) {
{ if (waiting_counter_ > 0) {
if (x_ > max_x)
{
disable();
}
if (x_ < param.game.game_area.rect.x && direction_ == TabeDirection::TO_THE_LEFT)
{
setRandomFlyPath(TabeDirection::TO_THE_RIGHT, 80);
x_ = param.game.game_area.rect.x;
}
break;
}
default:
break;
}
if (fly_distance_ <= 0)
{
if (waiting_counter_ > 0)
{
accel_ = speed_ = 0.0f; accel_ = speed_ = 0.0f;
--waiting_counter_; --waiting_counter_;
} } else {
else
{
constexpr int CHOICES = 4; constexpr int CHOICES = 4;
const TabeDirection left[CHOICES] = {TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_RIGHT}; const TabeDirection left[CHOICES] = {TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_RIGHT};
const TabeDirection right[CHOICES] = {TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_RIGHT, TabeDirection::TO_THE_RIGHT, TabeDirection::TO_THE_RIGHT}; const TabeDirection right[CHOICES] = {TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_RIGHT, TabeDirection::TO_THE_RIGHT, TabeDirection::TO_THE_RIGHT};
@@ -107,10 +91,8 @@ void Tabe::move()
} }
// Habilita el objeto // Habilita el objeto
void Tabe::enable() void Tabe::enable() {
{ if (!enabled_) {
if (!enabled_)
{
enabled_ = true; enabled_ = true;
has_bonus_ = true; has_bonus_ = true;
hit_counter_ = 0; hit_counter_ = 0;
@@ -130,8 +112,7 @@ void Tabe::enable()
} }
// Establece un vuelo aleatorio // Establece un vuelo aleatorio
void Tabe::setRandomFlyPath(TabeDirection direction, int lenght) void Tabe::setRandomFlyPath(TabeDirection direction, int lenght) {
{
direction_ = direction; direction_ = direction;
fly_distance_ = lenght; fly_distance_ = lenght;
waiting_counter_ = 5 + rand() % 15; waiting_counter_ = 5 + rand() % 15;
@@ -139,72 +120,61 @@ void Tabe::setRandomFlyPath(TabeDirection direction, int lenght)
constexpr float SPEED = 2.0f; constexpr float SPEED = 2.0f;
switch (direction) switch (direction) {
{ case TabeDirection::TO_THE_LEFT: {
case TabeDirection::TO_THE_LEFT: speed_ = -1.0f * SPEED;
{ accel_ = -1.0f * (1 + rand() % 10) / 30.0f;
speed_ = -1.0f * SPEED; sprite_->setFlip(SDL_FLIP_NONE);
accel_ = -1.0f * (1 + rand() % 10) / 30.0f; break;
sprite_->setFlip(SDL_FLIP_NONE); }
break;
}
case TabeDirection::TO_THE_RIGHT: case TabeDirection::TO_THE_RIGHT: {
{ speed_ = SPEED;
speed_ = SPEED; accel_ = (1 + rand() % 10) / 30.0f;
accel_ = (1 + rand() % 10) / 30.0f; sprite_->setFlip(SDL_FLIP_HORIZONTAL);
sprite_->setFlip(SDL_FLIP_HORIZONTAL); break;
break; }
}
default: default:
break; break;
} }
} }
// Establece el estado // Establece el estado
void Tabe::setState(TabeState state) void Tabe::setState(TabeState state) {
{ if (enabled_) {
if (enabled_)
{
state_ = state; state_ = state;
switch (state) switch (state) {
{ case TabeState::FLY:
case TabeState::FLY: sprite_->setCurrentAnimation("fly");
sprite_->setCurrentAnimation("fly"); break;
break;
case TabeState::HIT: case TabeState::HIT:
sprite_->setCurrentAnimation("hit"); sprite_->setCurrentAnimation("hit");
hit_counter_ = 5; hit_counter_ = 5;
++number_of_hits_; ++number_of_hits_;
break; break;
default: default:
break; break;
} }
} }
} }
// Actualiza el estado // Actualiza el estado
void Tabe::updateState() void Tabe::updateState() {
{ if (state_ == TabeState::HIT) {
if (state_ == TabeState::HIT)
{
--hit_counter_; --hit_counter_;
if (hit_counter_ == 0) if (hit_counter_ == 0) {
{
setState(TabeState::FLY); setState(TabeState::FLY);
} }
} }
} }
// Intenta obtener el bonus // Intenta obtener el bonus
bool Tabe::tryToGetBonus() bool Tabe::tryToGetBonus() {
{ if (has_bonus_ && rand() % std::max(1, 15 - number_of_hits_) == 0) {
if (has_bonus_ && rand() % std::max(1, 15 - number_of_hits_) == 0)
{
has_bonus_ = false; has_bonus_ = false;
return true; return true;
} }
@@ -212,16 +182,14 @@ bool Tabe::tryToGetBonus()
} }
// Actualiza el temporizador // Actualiza el temporizador
void Tabe::updateTimer() void Tabe::updateTimer() {
{
timer_.current_time = SDL_GetTicks(); timer_.current_time = SDL_GetTicks();
timer_.delta_time = timer_.current_time - timer_.last_time; timer_.delta_time = timer_.current_time - timer_.last_time;
timer_.last_time = timer_.current_time; timer_.last_time = timer_.current_time;
} }
// Deshabilita el objeto // Deshabilita el objeto
void Tabe::disable() void Tabe::disable() {
{
enabled_ = false; enabled_ = false;
timer_.reset(); timer_.reset();
} }
+51 -62
View File
@@ -1,122 +1,111 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para Uint32, SDL_GetTicks, SDL_FRect #include <SDL3/SDL.h> // Para Uint32, SDL_GetTicks, SDL_FRect
#include <stdlib.h> // Para rand #include <stdlib.h> // Para rand
#include <memory> // Para unique_ptr
#include "animated_sprite.h" // Para AnimatedSprite #include <memory> // Para unique_ptr
#include "animated_sprite.h" // Para AnimatedSprite
// --- Enumeraciones para dirección y estado --- // --- Enumeraciones para dirección y estado ---
enum class TabeDirection : int enum class TabeDirection : int {
{
TO_THE_LEFT = 0, TO_THE_LEFT = 0,
TO_THE_RIGHT = 1, TO_THE_RIGHT = 1,
}; };
enum class TabeState : int enum class TabeState : int {
{
FLY = 0, FLY = 0,
HIT = 1, HIT = 1,
}; };
// --- Estructura para el temporizador del Tabe --- // --- Estructura para el temporizador del Tabe ---
struct TabeTimer struct TabeTimer {
{ Uint32 time_until_next_spawn; // Tiempo restante para la próxima aparición
Uint32 time_until_next_spawn; // Tiempo restante para la próxima aparición Uint32 min_spawn_time; // Tiempo mínimo entre apariciones
Uint32 min_spawn_time; // Tiempo mínimo entre apariciones Uint32 max_spawn_time; // Tiempo máximo entre apariciones
Uint32 max_spawn_time; // Tiempo máximo entre apariciones Uint32 current_time; // Tiempo actual
Uint32 current_time; // Tiempo actual Uint32 delta_time; // Diferencia de tiempo desde la última actualización
Uint32 delta_time; // Diferencia de tiempo desde la última actualización Uint32 last_time; // Tiempo de la última actualización
Uint32 last_time; // Tiempo de la última actualización
// Constructor // Constructor
TabeTimer(float minTime, float maxTime) TabeTimer(float minTime, float maxTime)
: min_spawn_time(minTime * 60000), max_spawn_time(maxTime * 60000), : min_spawn_time(minTime * 60000), max_spawn_time(maxTime * 60000), current_time(SDL_GetTicks()) {
current_time(SDL_GetTicks())
{
reset(); reset();
} }
// Restablece el temporizador con un nuevo tiempo hasta la próxima aparición // Restablece el temporizador con un nuevo tiempo hasta la próxima aparición
void reset() void reset() {
{
Uint32 range = max_spawn_time - min_spawn_time; Uint32 range = max_spawn_time - min_spawn_time;
time_until_next_spawn = min_spawn_time + rand() % (range + 1); time_until_next_spawn = min_spawn_time + rand() % (range + 1);
last_time = SDL_GetTicks(); last_time = SDL_GetTicks();
} }
// Actualiza el temporizador, decrementando el tiempo hasta la próxima aparición // Actualiza el temporizador, decrementando el tiempo hasta la próxima aparición
void update() void update() {
{
current_time = SDL_GetTicks(); current_time = SDL_GetTicks();
delta_time = current_time - last_time; delta_time = current_time - last_time;
last_time = current_time; last_time = current_time;
if (time_until_next_spawn > delta_time) if (time_until_next_spawn > delta_time) {
{
time_until_next_spawn -= delta_time; time_until_next_spawn -= delta_time;
} } else {
else
{
time_until_next_spawn = 0; time_until_next_spawn = 0;
} }
} }
// Indica si el temporizador ha finalizado // Indica si el temporizador ha finalizado
bool should_spawn() const bool should_spawn() const {
{
return time_until_next_spawn == 0; return time_until_next_spawn == 0;
} }
}; };
// --- Clase Tabe --- // --- Clase Tabe ---
class Tabe class Tabe {
{ public:
public:
// --- Constructores y destructor --- // --- Constructores y destructor ---
Tabe(); Tabe();
~Tabe() = default; ~Tabe() = default;
// --- Métodos principales --- // --- Métodos principales ---
void update(); // Actualiza la lógica void update(); // Actualiza la lógica
void render(); // Dibuja el objeto void render(); // Dibuja el objeto
void enable(); // Habilita el objeto void enable(); // Habilita el objeto
void setState(TabeState state); // Establece el estado void setState(TabeState state); // Establece el estado
bool tryToGetBonus(); // Intenta obtener el bonus bool tryToGetBonus(); // Intenta obtener el bonus
// --- Getters --- // --- Getters ---
SDL_FRect &getCollider() { return sprite_->getRect(); } // Obtiene el área de colisión SDL_FRect &getCollider() { return sprite_->getRect(); } // Obtiene el área de colisión
bool isEnabled() const { return enabled_; } // Indica si el objeto está activo bool isEnabled() const { return enabled_; } // Indica si el objeto está activo
private: private:
// --- Constantes --- // --- Constantes ---
static constexpr int WIDTH_ = 32; static constexpr int WIDTH_ = 32;
static constexpr int HEIGHT_ = 32; static constexpr int HEIGHT_ = 32;
// --- Objetos y punteros --- // --- Objetos y punteros ---
std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos y animaciones std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos y animaciones
// --- Variables de estado --- // --- Variables de estado ---
float x_ = 0; // Posición X float x_ = 0; // Posición X
float y_ = 0; // Posición Y float y_ = 0; // Posición Y
float speed_ = 0.0f; // Velocidad de movimiento float speed_ = 0.0f; // Velocidad de movimiento
float accel_ = 0.0f; // Aceleración float accel_ = 0.0f; // Aceleración
int fly_distance_ = 0; // Distancia de vuelo int fly_distance_ = 0; // Distancia de vuelo
int waiting_counter_ = 0; // Tiempo que pasa quieto int waiting_counter_ = 0; // Tiempo que pasa quieto
bool enabled_ = false; // Indica si el objeto está activo bool enabled_ = false; // Indica si el objeto está activo
TabeDirection direction_ = TabeDirection::TO_THE_LEFT; // Dirección actual TabeDirection direction_ = TabeDirection::TO_THE_LEFT; // Dirección actual
TabeDirection destiny_ = TabeDirection::TO_THE_LEFT; // Destino TabeDirection destiny_ = TabeDirection::TO_THE_LEFT; // Destino
TabeState state_ = TabeState::FLY; // Estado actual TabeState state_ = TabeState::FLY; // Estado actual
int hit_counter_ = 0; // Contador para el estado HIT int hit_counter_ = 0; // Contador para el estado HIT
int number_of_hits_ = 0; // Cantidad de disparos recibidos int number_of_hits_ = 0; // Cantidad de disparos recibidos
bool has_bonus_ = true; // Indica si aún tiene el bonus para soltar bool has_bonus_ = true; // Indica si aún tiene el bonus para soltar
TabeTimer timer_; // Temporizador para gestionar la aparición TabeTimer timer_; // Temporizador para gestionar la aparición
// --- Métodos internos --- // --- Métodos internos ---
void move(); // Mueve el objeto void move(); // Mueve el objeto
void shiftSprite() { sprite_->setPos(x_, y_); } // Actualiza la posición del sprite void shiftSprite() { sprite_->setPos(x_, y_); } // Actualiza la posición del sprite
void setRandomFlyPath(TabeDirection direction, int lenght); // Establece un vuelo aleatorio void setRandomFlyPath(TabeDirection direction, int lenght); // Establece un vuelo aleatorio
void updateState(); // Actualiza el estado void updateState(); // Actualiza el estado
void updateTimer(); // Actualiza el temporizador void updateTimer(); // Actualiza el temporizador
void disable(); // Deshabilita el objeto void disable(); // Deshabilita el objeto
}; };
+184 -216
View File
@@ -1,290 +1,258 @@
#include "text.h" #include "text.h"
#include <SDL3/SDL.h> // Para SDL_SetRenderTarget, SDL_GetRenderTarget, Uint8 #include <SDL3/SDL.h> // Para SDL_SetRenderTarget, SDL_GetRenderTarget, Uint8
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <fstream> // Para basic_ifstream, basic_istream, basic_ostream
#include <iostream> // Para cerr #include <fstream> // Para basic_ifstream, basic_istream, basic_ostream
#include <iostream> // Para cerr
#include <stdexcept> // Para runtime_error #include <stdexcept> // Para runtime_error
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "utils.h" // Para Color, getFileName, printWithDots #include "utils.h" // Para Color, getFileName, printWithDots
// Llena una estructuta TextFile desde un fichero // Llena una estructuta TextFile desde un fichero
std::shared_ptr<TextFile> loadTextFile(const std::string &file_path) std::shared_ptr<TextFile> loadTextFile(const std::string &file_path) {
{ auto tf = std::make_shared<TextFile>();
auto tf = std::make_shared<TextFile>();
// Inicializa a cero el vector con las coordenadas // Inicializa a cero el vector con las coordenadas
for (int i = 0; i < 128; ++i) for (int i = 0; i < 128; ++i) {
{ tf->offset[i].x = 0;
tf->offset[i].x = 0; tf->offset[i].y = 0;
tf->offset[i].y = 0; tf->offset[i].w = 0;
tf->offset[i].w = 0; tf->box_width = 0;
tf->box_width = 0; tf->box_height = 0;
tf->box_height = 0; }
}
// Abre el fichero para leer los valores // Abre el fichero para leer los valores
std::ifstream file(file_path); std::ifstream file(file_path);
if (file.is_open() && file.good()) if (file.is_open() && file.good()) {
{ std::string buffer;
std::string buffer;
// Lee los dos primeros valores del fichero // Lee los dos primeros valores del fichero
std::getline(file, buffer); std::getline(file, buffer);
std::getline(file, buffer); std::getline(file, buffer);
tf->box_width = std::stoi(buffer); tf->box_width = std::stoi(buffer);
std::getline(file, buffer); std::getline(file, buffer);
std::getline(file, buffer); std::getline(file, buffer);
tf->box_height = std::stoi(buffer); tf->box_height = std::stoi(buffer);
// lee el resto de datos del fichero // lee el resto de datos del fichero
auto index = 32; auto index = 32;
auto line_read = 0; auto line_read = 0;
while (std::getline(file, buffer)) while (std::getline(file, buffer)) {
{ // Almacena solo las lineas impares
// Almacena solo las lineas impares if (line_read % 2 == 1)
if (line_read % 2 == 1) tf->offset[index++].w = std::stoi(buffer);
tf->offset[index++].w = std::stoi(buffer);
// Limpia el buffer // Limpia el buffer
buffer.clear(); buffer.clear();
line_read++; line_read++;
}; };
// Cierra el fichero // Cierra el fichero
printWithDots("Text File : ", getFileName(file_path), "[ LOADED ]"); printWithDots("Text File : ", getFileName(file_path), "[ LOADED ]");
file.close(); file.close();
} }
// El fichero no se puede abrir // El fichero no se puede abrir
else else {
{ std::cerr << "Error: Fichero no encontrado " << getFileName(file_path) << std::endl;
std::cerr << "Error: Fichero no encontrado " << getFileName(file_path) << std::endl; throw std::runtime_error("Fichero no encontrado: " + getFileName(file_path));
throw std::runtime_error("Fichero no encontrado: " + getFileName(file_path)); }
}
// Establece las coordenadas para cada caracter ascii de la cadena y su ancho // Establece las coordenadas para cada caracter ascii de la cadena y su ancho
for (int i = 32; i < 128; ++i) for (int i = 32; i < 128; ++i) {
{ tf->offset[i].x = ((i - 32) % 15) * tf->box_width;
tf->offset[i].x = ((i - 32) % 15) * tf->box_width; tf->offset[i].y = ((i - 32) / 15) * tf->box_height;
tf->offset[i].y = ((i - 32) / 15) * tf->box_height; }
}
return tf; return tf;
} }
// Constructor // Constructor
Text::Text(std::shared_ptr<Texture> texture, const std::string &text_file) Text::Text(std::shared_ptr<Texture> texture, const std::string &text_file) {
{ // Carga los offsets desde el fichero
// Carga los offsets desde el fichero auto tf = loadTextFile(text_file);
auto tf = loadTextFile(text_file);
// Inicializa variables desde la estructura // Inicializa variables desde la estructura
box_height_ = tf->box_height; box_height_ = tf->box_height;
box_width_ = tf->box_width; box_width_ = tf->box_width;
for (int i = 0; i < 128; ++i) for (int i = 0; i < 128; ++i) {
{ offset_[i].x = tf->offset[i].x;
offset_[i].x = tf->offset[i].x; offset_[i].y = tf->offset[i].y;
offset_[i].y = tf->offset[i].y; offset_[i].w = tf->offset[i].w;
offset_[i].w = tf->offset[i].w; }
}
// Crea los objetos // Crea los objetos
sprite_ = std::make_unique<Sprite>(texture, (SDL_FRect){0, 0, static_cast<float>(box_width_), static_cast<float>(box_height_)}); sprite_ = std::make_unique<Sprite>(texture, (SDL_FRect){0, 0, static_cast<float>(box_width_), static_cast<float>(box_height_)});
// Inicializa variables // Inicializa variables
fixed_width_ = false; fixed_width_ = false;
} }
// Constructor // Constructor
Text::Text(std::shared_ptr<Texture> texture, std::shared_ptr<TextFile> text_file) Text::Text(std::shared_ptr<Texture> texture, std::shared_ptr<TextFile> text_file) {
{ // Inicializa variables desde la estructura
// Inicializa variables desde la estructura box_height_ = text_file->box_height;
box_height_ = text_file->box_height; box_width_ = text_file->box_width;
box_width_ = text_file->box_width; for (int i = 0; i < 128; ++i) {
for (int i = 0; i < 128; ++i) offset_[i].x = text_file->offset[i].x;
{ offset_[i].y = text_file->offset[i].y;
offset_[i].x = text_file->offset[i].x; offset_[i].w = text_file->offset[i].w;
offset_[i].y = text_file->offset[i].y; }
offset_[i].w = text_file->offset[i].w;
}
// Crea los objetos // Crea los objetos
sprite_ = std::make_unique<Sprite>(texture, (SDL_FRect){0, 0, static_cast<float>(box_width_), static_cast<float>(box_height_)}); sprite_ = std::make_unique<Sprite>(texture, (SDL_FRect){0, 0, static_cast<float>(box_width_), static_cast<float>(box_height_)});
// Inicializa variables // Inicializa variables
fixed_width_ = false; fixed_width_ = false;
} }
// Escribe texto en pantalla // Escribe texto en pantalla
void Text::write(int x, int y, const std::string &text, int kerning, int lenght) void Text::write(int x, int y, const std::string &text, int kerning, int lenght) {
{ int shift = 0;
int shift = 0;
if (lenght == -1) if (lenght == -1)
lenght = text.length(); lenght = text.length();
sprite_->setY(y); sprite_->setY(y);
for (int i = 0; i < lenght; ++i) for (int i = 0; i < lenght; ++i) {
{ auto index = static_cast<int>(text[i]);
auto index = static_cast<int>(text[i]); sprite_->setSpriteClip(offset_[index].x, offset_[index].y, box_width_, box_height_);
sprite_->setSpriteClip(offset_[index].x, offset_[index].y, box_width_, box_height_); sprite_->setX(x + shift);
sprite_->setX(x + shift); sprite_->render();
sprite_->render(); shift += offset_[static_cast<int>(text[i])].w + kerning;
shift += offset_[static_cast<int>(text[i])].w + kerning; }
}
} }
// Escribe texto en pantalla // Escribe texto en pantalla
void Text::write2X(int x, int y, const std::string &text, int kerning) void Text::write2X(int x, int y, const std::string &text, int kerning) {
{ int shift = 0;
int shift = 0; for (size_t i = 0; i < text.length(); ++i) {
for (size_t i = 0; i < text.length(); ++i) auto index = static_cast<size_t>(text[i]);
{ SDL_FRect rect = {static_cast<float>(offset_[index].x), static_cast<float>(offset_[index].y), static_cast<float>(box_width_), static_cast<float>(box_height_)};
auto index = static_cast<size_t>(text[i]); sprite_->getTexture()->render(x + shift, y, &rect, 2.0f, 2.0f);
SDL_FRect rect = {static_cast<float>(offset_[index].x), static_cast<float>(offset_[index].y), static_cast<float>(box_width_), static_cast<float>(box_height_)}; shift += (offset_[index].w + kerning) * 2;
sprite_->getTexture()->render(x + shift, y, &rect, 2.0f, 2.0f); }
shift += (offset_[index].w + kerning) * 2;
}
} }
// Escribe el texto en una textura // Escribe el texto en una textura
std::shared_ptr<Texture> Text::writeToTexture(const std::string &text, int zoom, int kerning) std::shared_ptr<Texture> Text::writeToTexture(const std::string &text, int zoom, int kerning) {
{ auto renderer = Screen::get()->getRenderer();
auto renderer = Screen::get()->getRenderer(); auto texture = std::make_shared<Texture>(renderer);
auto texture = std::make_shared<Texture>(renderer); auto width = lenght(text, kerning) * zoom;
auto width = lenght(text, kerning) * zoom; auto height = box_height_ * zoom;
auto height = box_height_ * zoom; auto temp = SDL_GetRenderTarget(renderer);
auto temp = SDL_GetRenderTarget(renderer); texture->createBlank(width, height, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET);
texture->createBlank(width, height, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET); texture->setBlendMode(SDL_BLENDMODE_BLEND);
texture->setBlendMode(SDL_BLENDMODE_BLEND); texture->setAsRenderTarget(renderer);
texture->setAsRenderTarget(renderer); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_RenderClear(renderer);
SDL_RenderClear(renderer); zoom == 1 ? write(0, 0, text, kerning) : write2X(0, 0, text, kerning);
zoom == 1 ? write(0, 0, text, kerning) : write2X(0, 0, text, kerning); SDL_SetRenderTarget(renderer, temp);
SDL_SetRenderTarget(renderer, temp);
return texture; return texture;
} }
// Escribe el texto con extras en una textura // Escribe el texto con extras en una textura
std::shared_ptr<Texture> Text::writeDXToTexture(Uint8 flags, const std::string &text, int kerning, Color textColor, Uint8 shadow_distance, Color shadow_color, int lenght) std::shared_ptr<Texture> Text::writeDXToTexture(Uint8 flags, const std::string &text, int kerning, Color textColor, Uint8 shadow_distance, Color shadow_color, int lenght) {
{ auto renderer = Screen::get()->getRenderer();
auto renderer = Screen::get()->getRenderer(); auto texture = std::make_shared<Texture>(renderer);
auto texture = std::make_shared<Texture>(renderer); auto width = Text::lenght(text, kerning) + shadow_distance;
auto width = Text::lenght(text, kerning) + shadow_distance; auto height = box_height_ + shadow_distance;
auto height = box_height_ + shadow_distance; auto temp = SDL_GetRenderTarget(renderer);
auto temp = SDL_GetRenderTarget(renderer); texture->createBlank(width, height, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET);
texture->createBlank(width, height, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET); texture->setBlendMode(SDL_BLENDMODE_BLEND);
texture->setBlendMode(SDL_BLENDMODE_BLEND); texture->setAsRenderTarget(renderer);
texture->setAsRenderTarget(renderer); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_RenderClear(renderer);
SDL_RenderClear(renderer); writeDX(flags, 0, 0, text, kerning, textColor, shadow_distance, shadow_color, lenght);
writeDX(flags, 0, 0, text, kerning, textColor, shadow_distance, shadow_color, lenght); SDL_SetRenderTarget(renderer, temp);
SDL_SetRenderTarget(renderer, temp);
return texture; return texture;
} }
// Escribe el texto con colores // Escribe el texto con colores
void Text::writeColored(int x, int y, const std::string &text, Color color, int kerning, int lenght) void Text::writeColored(int x, int y, const std::string &text, Color color, int kerning, int lenght) {
{ sprite_->getTexture()->setColor(color.r, color.g, color.b);
sprite_->getTexture()->setColor(color.r, color.g, color.b); write(x, y, text, kerning, lenght);
write(x, y, text, kerning, lenght); sprite_->getTexture()->setColor(255, 255, 255);
sprite_->getTexture()->setColor(255, 255, 255);
} }
// Escribe el texto con sombra // Escribe el texto con sombra
void Text::writeShadowed(int x, int y, const std::string &text, Color color, Uint8 shadow_distance, int kerning, int lenght) void Text::writeShadowed(int x, int y, const std::string &text, Color color, Uint8 shadow_distance, int kerning, int lenght) {
{ sprite_->getTexture()->setColor(color.r, color.g, color.b);
sprite_->getTexture()->setColor(color.r, color.g, color.b); write(x + shadow_distance, y + shadow_distance, text, kerning, lenght);
write(x + shadow_distance, y + shadow_distance, text, kerning, lenght); sprite_->getTexture()->setColor(255, 255, 255);
sprite_->getTexture()->setColor(255, 255, 255); write(x, y, text, kerning, lenght);
write(x, y, text, kerning, lenght);
} }
// Escribe el texto centrado en un punto x // Escribe el texto centrado en un punto x
void Text::writeCentered(int x, int y, const std::string &text, int kerning, int lenght) void Text::writeCentered(int x, int y, const std::string &text, int kerning, int lenght) {
{ x -= (Text::lenght(text, kerning) / 2);
x -= (Text::lenght(text, kerning) / 2); write(x, y, text, kerning, lenght);
write(x, y, text, kerning, lenght);
} }
// Escribe texto con extras // Escribe texto con extras
void Text::writeDX(Uint8 flags, int x, int y, const std::string &text, int kerning, Color textColor, Uint8 shadow_distance, Color shadow_color, int lenght) void Text::writeDX(Uint8 flags, int x, int y, const std::string &text, int kerning, Color textColor, Uint8 shadow_distance, Color shadow_color, int lenght) {
{ const auto centered = ((flags & TEXT_CENTER) == TEXT_CENTER);
const auto centered = ((flags & TEXT_CENTER) == TEXT_CENTER); const auto shadowed = ((flags & TEXT_SHADOW) == TEXT_SHADOW);
const auto shadowed = ((flags & TEXT_SHADOW) == TEXT_SHADOW); const auto colored = ((flags & TEXT_COLOR) == TEXT_COLOR);
const auto colored = ((flags & TEXT_COLOR) == TEXT_COLOR); const auto stroked = ((flags & TEXT_STROKE) == TEXT_STROKE);
const auto stroked = ((flags & TEXT_STROKE) == TEXT_STROKE);
if (centered) if (centered) {
{ x -= (Text::lenght(text, kerning) / 2);
x -= (Text::lenght(text, kerning) / 2); }
}
if (shadowed) if (shadowed) {
{ writeColored(x + shadow_distance, y + shadow_distance, text, shadow_color, kerning, lenght);
writeColored(x + shadow_distance, y + shadow_distance, text, shadow_color, kerning, lenght); }
}
if (stroked) if (stroked) {
{ for (int dist = 1; dist <= shadow_distance; ++dist) {
for (int dist = 1; dist <= shadow_distance; ++dist) for (int dy = -dist; dy <= dist; ++dy) {
{ for (int dx = -dist; dx <= dist; ++dx) {
for (int dy = -dist; dy <= dist; ++dy) writeColored(x + dx, y + dy, text, shadow_color, kerning, lenght);
{ }
for (int dx = -dist; dx <= dist; ++dx) }
{ }
writeColored(x + dx, y + dy, text, shadow_color, kerning, lenght); }
}
}
}
}
if (colored) if (colored) {
{ writeColored(x, y, text, textColor, kerning, lenght);
writeColored(x, y, text, textColor, kerning, lenght); } else {
} write(x, y, text, kerning, lenght);
else }
{
write(x, y, text, kerning, lenght);
}
} }
// Obtiene la longitud en pixels de una cadena // Obtiene la longitud en pixels de una cadena
int Text::lenght(const std::string &text, int kerning) const int Text::lenght(const std::string &text, int kerning) const {
{ int shift = 0;
int shift = 0; for (size_t i = 0; i < text.length(); ++i)
for (size_t i = 0; i < text.length(); ++i) shift += (offset_[static_cast<int>(text[i])].w + kerning);
shift += (offset_[static_cast<int>(text[i])].w + kerning);
// Descuenta el kerning del último caracter // Descuenta el kerning del último caracter
return shift - kerning; return shift - kerning;
} }
// Devuelve el valor de la variable // Devuelve el valor de la variable
int Text::getCharacterSize() const int Text::getCharacterSize() const {
{ return box_width_;
return box_width_;
} }
// Establece si se usa un tamaño fijo de letra // Establece si se usa un tamaño fijo de letra
void Text::setFixedWidth(bool value) void Text::setFixedWidth(bool value) {
{ fixed_width_ = value;
fixed_width_ = value;
} }
// Establece una paleta // Establece una paleta
void Text::setPalette(int number) void Text::setPalette(int number) {
{ auto temp = SDL_GetRenderTarget(Screen::get()->getRenderer());
auto temp = SDL_GetRenderTarget(Screen::get()->getRenderer()); SDL_SetRenderTarget(Screen::get()->getRenderer(), nullptr);
SDL_SetRenderTarget(Screen::get()->getRenderer(), nullptr); sprite_->getTexture()->setPalette(number);
sprite_->getTexture()->setPalette(number); SDL_SetRenderTarget(Screen::get()->getRenderer(), temp);
SDL_SetRenderTarget(Screen::get()->getRenderer(), temp);
} }
+43 -45
View File
@@ -1,11 +1,12 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para Uint8 #include <SDL3/SDL.h> // Para Uint8
#include <memory> // Para unique_ptr, shared_ptr
#include <string> // Para string
#include "sprite.h" // Para Sprite #include <memory> // Para unique_ptr, shared_ptr
#include "utils.h" // Para Color #include <string> // Para string
#include "sprite.h" // Para Sprite
#include "utils.h" // Para Color
class Texture; class Texture;
@@ -16,59 +17,56 @@ constexpr int TEXT_CENTER = 4;
constexpr int TEXT_STROKE = 8; constexpr int TEXT_STROKE = 8;
// --- Estructuras auxiliares --- // --- Estructuras auxiliares ---
struct TextOffset struct TextOffset {
{ int x, y, w;
int x, y, w;
}; };
struct TextFile struct TextFile {
{ int box_width; // Anchura de la caja de cada caracter en el png
int box_width; // Anchura de la caja de cada caracter en el png int box_height; // Altura de la caja de cada caracter en el png
int box_height; // Altura de la caja de cada caracter en el png TextOffset offset[128]; // Vector con las posiciones y ancho de cada letra
TextOffset offset[128]; // Vector con las posiciones y ancho de cada letra
}; };
// Llena una estructura TextFile desde un fichero // Llena una estructura TextFile desde un fichero
std::shared_ptr<TextFile> loadTextFile(const std::string &file_path); std::shared_ptr<TextFile> loadTextFile(const std::string &file_path);
// --- Clase Text: pinta texto en pantalla a partir de un bitmap --- // --- Clase Text: pinta texto en pantalla a partir de un bitmap ---
class Text class Text {
{ public:
public: // --- Constructores y destructor ---
// --- Constructores y destructor --- Text(std::shared_ptr<Texture> texture, const std::string &text_file);
Text(std::shared_ptr<Texture> texture, const std::string &text_file); Text(std::shared_ptr<Texture> texture, std::shared_ptr<TextFile> text_file);
Text(std::shared_ptr<Texture> texture, std::shared_ptr<TextFile> text_file); ~Text() = default;
~Text() = default;
// --- Métodos de escritura en pantalla --- // --- Métodos de escritura en pantalla ---
void write(int x, int y, const std::string &text, int kerning = 1, int lenght = -1); // Escribe el texto en pantalla void write(int x, int y, const std::string &text, int kerning = 1, int lenght = -1); // Escribe el texto en pantalla
void write2X(int x, int y, const std::string &text, int kerning = 1); // Escribe el texto al doble de tamaño void write2X(int x, int y, const std::string &text, int kerning = 1); // Escribe el texto al doble de tamaño
// --- Escritura en textura --- // --- Escritura en textura ---
std::shared_ptr<Texture> writeToTexture(const std::string &text, int zoom = 1, int kerning = 1); // Escribe el texto en una textura std::shared_ptr<Texture> writeToTexture(const std::string &text, int zoom = 1, int kerning = 1); // Escribe el texto en una textura
std::shared_ptr<Texture> writeDXToTexture(Uint8 flags, const std::string &text, int kerning = 1, Color textColor = Color(), Uint8 shadow_distance = 1, Color shadow_color = Color(), int lenght = -1); // Escribe el texto con extras en una textura std::shared_ptr<Texture> writeDXToTexture(Uint8 flags, const std::string &text, int kerning = 1, Color textColor = Color(), Uint8 shadow_distance = 1, Color shadow_color = Color(), int lenght = -1); // Escribe el texto con extras en una textura
// --- Métodos de escritura avanzada --- // --- Métodos de escritura avanzada ---
void writeColored(int x, int y, const std::string &text, Color color, int kerning = 1, int lenght = -1); // Escribe el texto con colores void writeColored(int x, int y, const std::string &text, Color color, int kerning = 1, int lenght = -1); // Escribe el texto con colores
void writeShadowed(int x, int y, const std::string &text, Color color, Uint8 shadow_distance = 1, int kerning = 1, int lenght = -1); // Escribe el texto con sombra void writeShadowed(int x, int y, const std::string &text, Color color, Uint8 shadow_distance = 1, int kerning = 1, int lenght = -1); // Escribe el texto con sombra
void writeCentered(int x, int y, const std::string &text, int kerning = 1, int lenght = -1); // Escribe el texto centrado en un punto x void writeCentered(int x, int y, const std::string &text, int kerning = 1, int lenght = -1); // Escribe el texto centrado en un punto x
void writeDX(Uint8 flags, int x, int y, const std::string &text, int kerning = 1, Color textColor = Color(), Uint8 shadow_distance = 1, Color shadow_color = Color(), int lenght = -1); // Escribe texto con extras void writeDX(Uint8 flags, int x, int y, const std::string &text, int kerning = 1, Color textColor = Color(), Uint8 shadow_distance = 1, Color shadow_color = Color(), int lenght = -1); // Escribe texto con extras
// --- Utilidades --- // --- Utilidades ---
int lenght(const std::string &text, int kerning = 1) const; // Obtiene la longitud en pixels de una cadena int lenght(const std::string &text, int kerning = 1) const; // Obtiene la longitud en pixels de una cadena
int getCharacterSize() const; // Devuelve el tamaño de caracter actual int getCharacterSize() const; // Devuelve el tamaño de caracter actual
// --- Configuración --- // --- Configuración ---
void setFixedWidth(bool value); // Establece si se usa un tamaño fijo de letra void setFixedWidth(bool value); // Establece si se usa un tamaño fijo de letra
void setPalette(int number); // Establece una paleta void setPalette(int number); // Establece una paleta
private: private:
// --- Objetos y punteros --- // --- Objetos y punteros ---
std::unique_ptr<Sprite> sprite_ = nullptr; // Objeto con los gráficos para el texto std::unique_ptr<Sprite> sprite_ = nullptr; // Objeto con los gráficos para el texto
// --- Variables --- // --- Variables ---
int box_width_ = 0; // Anchura de la caja de cada caracter en el png int box_width_ = 0; // Anchura de la caja de cada caracter en el png
int box_height_ = 0; // Altura de la caja de cada caracter en el png int box_height_ = 0; // Altura de la caja de cada caracter en el png
bool fixed_width_ = false; // Indica si el texto se ha de escribir con longitud fija en todas las letras bool fixed_width_ = false; // Indica si el texto se ha de escribir con longitud fija en todas las letras
TextOffset offset_[128] = {}; // Vector con las posiciones y ancho de cada letra TextOffset offset_[128] = {}; // Vector con las posiciones y ancho de cada letra
}; };
+265 -322
View File
@@ -1,438 +1,381 @@
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include "texture.h" #include "texture.h"
#include <SDL3/SDL.h> // Para SDL_LogError, SDL_LogCategory, Uint8, SDL_... #include <SDL3/SDL.h> // Para SDL_LogError, SDL_LogCategory, Uint8, SDL_...
#include <stdint.h> // Para uint32_t #include <stdint.h> // Para uint32_t
#include <cstring> // Para memcpy
#include <fstream> // Para basic_ifstream, basic_istream, basic_ios
#include <sstream> // Para basic_istringstream
#include <stdexcept> // Para runtime_error
#include <string> // Para basic_string, char_traits, operator+, string
#include <vector> // Para vector
#include "external/gif.h" // Para Gif #include <cstring> // Para memcpy
#include "stb_image.h" // Para stbi_image_free, stbi_load, STBI_rgb_alpha #include <fstream> // Para basic_ifstream, basic_istream, basic_ios
#include "utils.h" // Para getFileName, Color, printWithDots #include <sstream> // Para basic_istringstream
#include <stdexcept> // Para runtime_error
#include <string> // Para basic_string, char_traits, operator+, string
#include <vector> // Para vector
#include "external/gif.h" // Para Gif
#include "stb_image.h" // Para stbi_image_free, stbi_load, STBI_rgb_alpha
#include "utils.h" // Para getFileName, Color, printWithDots
// Constructor // Constructor
Texture::Texture(SDL_Renderer *renderer, const std::string &path) Texture::Texture(SDL_Renderer *renderer, const std::string &path)
: renderer_(renderer), : renderer_(renderer),
path_(path) path_(path) {
{ // Carga el fichero en la textura
// Carga el fichero en la textura if (!path_.empty()) {
if (!path_.empty()) // Obtiene la extensión
{ const std::string extension = path_.substr(path_.find_last_of(".") + 1);
// Obtiene la extensión
const std::string extension = path_.substr(path_.find_last_of(".") + 1);
// .png // .png
if (extension == "png") if (extension == "png") {
{ loadFromFile(path_);
loadFromFile(path_); }
}
// .gif // .gif
else if (extension == "gif") else if (extension == "gif") {
{ // Crea la surface desde un fichero
// Crea la surface desde un fichero surface_ = loadSurface(path_);
surface_ = loadSurface(path_);
// Añade la propia paleta del fichero a la lista // Añade la propia paleta del fichero a la lista
addPaletteFromGifFile(path_); addPaletteFromGifFile(path_);
// Crea la textura, establece el BlendMode y copia la surface a la textura // Crea la textura, establece el BlendMode y copia la surface a la textura
createBlank(width_, height_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING); createBlank(width_, height_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING);
SDL_SetTextureBlendMode(texture_, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(texture_, SDL_BLENDMODE_BLEND);
flipSurface(); flipSurface();
} }
} }
} }
// Destructor // Destructor
Texture::~Texture() Texture::~Texture() {
{ unloadTexture();
unloadTexture(); unloadSurface();
unloadSurface(); palettes_.clear();
palettes_.clear();
} }
// Carga una imagen desde un fichero // Carga una imagen desde un fichero
bool Texture::loadFromFile(const std::string &file_path) bool Texture::loadFromFile(const std::string &file_path) {
{ if (file_path.empty())
if (file_path.empty()) return false;
return false;
int req_format = STBI_rgb_alpha; int req_format = STBI_rgb_alpha;
int width, height, orig_format; int width, height, orig_format;
unsigned char *data = stbi_load(file_path.c_str(), &width, &height, &orig_format, req_format); unsigned char *data = stbi_load(file_path.c_str(), &width, &height, &orig_format, req_format);
if (!data) if (!data) {
{ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", getFileName(file_path).c_str());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", getFileName(file_path).c_str()); throw std::runtime_error("Fichero no encontrado: " + getFileName(file_path));
throw std::runtime_error("Fichero no encontrado: " + getFileName(file_path)); } else {
} printWithDots("Texture : ", getFileName(file_path), "[ LOADED ]");
else }
{
printWithDots("Texture : ", getFileName(file_path), "[ LOADED ]");
}
int pitch; int pitch;
SDL_PixelFormat pixel_format; SDL_PixelFormat pixel_format;
// STBI_rgb_alpha (RGBA) // STBI_rgb_alpha (RGBA)
pitch = 4 * width; pitch = 4 * width;
pixel_format = SDL_PIXELFORMAT_RGBA32; pixel_format = SDL_PIXELFORMAT_RGBA32;
// Limpia // Limpia
unloadTexture(); unloadTexture();
// La textura final // La textura final
SDL_Texture *new_texture = nullptr; SDL_Texture *new_texture = nullptr;
// Carga la imagen desde una ruta específica // Carga la imagen desde una ruta específica
auto loaded_surface = SDL_CreateSurfaceFrom(width, height, pixel_format, static_cast<void *>(data), pitch); auto loaded_surface = SDL_CreateSurfaceFrom(width, height, pixel_format, static_cast<void *>(data), pitch);
if (loaded_surface == nullptr) if (loaded_surface == nullptr) {
{ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to load image %s", file_path.c_str());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to load image %s", file_path.c_str()); } else {
} // Crea la textura desde los pixels de la surface
else new_texture = SDL_CreateTextureFromSurface(renderer_, loaded_surface);
{ if (new_texture == nullptr) {
// Crea la textura desde los pixels de la surface SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create texture from %s! SDL Error: %s", file_path.c_str(), SDL_GetError());
new_texture = SDL_CreateTextureFromSurface(renderer_, loaded_surface); } else {
if (new_texture == nullptr) // Obtiene las dimensiones de la imagen
{ width_ = loaded_surface->w;
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create texture from %s! SDL Error: %s", file_path.c_str(), SDL_GetError()); height_ = loaded_surface->h;
} }
else
{
// Obtiene las dimensiones de la imagen
width_ = loaded_surface->w;
height_ = loaded_surface->h;
}
// Elimina la textura cargada // Elimina la textura cargada
SDL_DestroySurface(loaded_surface); SDL_DestroySurface(loaded_surface);
} }
// Return success // Return success
stbi_image_free(data); stbi_image_free(data);
texture_ = new_texture; texture_ = new_texture;
return texture_ != nullptr; return texture_ != nullptr;
} }
// Crea una textura en blanco // Crea una textura en blanco
bool Texture::createBlank(int width, int height, SDL_PixelFormat format, SDL_TextureAccess access) bool Texture::createBlank(int width, int height, SDL_PixelFormat format, SDL_TextureAccess access) {
{ // Crea una textura sin inicializar
// Crea una textura sin inicializar texture_ = SDL_CreateTexture(renderer_, format, access, width, height);
texture_ = SDL_CreateTexture(renderer_, format, access, width, height); if (!texture_) {
if (!texture_) SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create blank texture! SDL Error: %s", SDL_GetError());
{ } else {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create blank texture! SDL Error: %s", SDL_GetError()); width_ = width;
} height_ = height;
else }
{
width_ = width;
height_ = height;
}
return texture_ != nullptr; return texture_ != nullptr;
} }
// Libera la memoria de la textura // Libera la memoria de la textura
void Texture::unloadTexture() void Texture::unloadTexture() {
{ // Libera la textura
// Libera la textura if (texture_) {
if (texture_) SDL_DestroyTexture(texture_);
{ texture_ = nullptr;
SDL_DestroyTexture(texture_); width_ = 0;
texture_ = nullptr; height_ = 0;
width_ = 0; }
height_ = 0;
}
} }
// Establece el color para la modulacion // Establece el color para la modulacion
void Texture::setColor(Uint8 red, Uint8 green, Uint8 blue) void Texture::setColor(Uint8 red, Uint8 green, Uint8 blue) {
{ SDL_SetTextureColorMod(texture_, red, green, blue);
SDL_SetTextureColorMod(texture_, red, green, blue);
} }
void Texture::setColor(Color color) void Texture::setColor(Color color) {
{ SDL_SetTextureColorMod(texture_, color.r, color.g, color.b);
SDL_SetTextureColorMod(texture_, color.r, color.g, color.b);
} }
// Establece el blending // Establece el blending
void Texture::setBlendMode(SDL_BlendMode blending) void Texture::setBlendMode(SDL_BlendMode blending) {
{ SDL_SetTextureBlendMode(texture_, blending);
SDL_SetTextureBlendMode(texture_, blending);
} }
// Establece el alpha para la modulación // Establece el alpha para la modulación
void Texture::setAlpha(Uint8 alpha) void Texture::setAlpha(Uint8 alpha) {
{ SDL_SetTextureAlphaMod(texture_, alpha);
SDL_SetTextureAlphaMod(texture_, alpha);
} }
// Renderiza la textura en un punto específico // Renderiza la textura en un punto específico
void Texture::render(int x, int y, SDL_FRect *clip, float zoomW, float zoomH, double angle, SDL_FPoint *center, SDL_FlipMode flip) void Texture::render(int x, int y, SDL_FRect *clip, float zoomW, float zoomH, double angle, SDL_FPoint *center, SDL_FlipMode flip) {
{ // Establece el destino de renderizado en la pantalla
// Establece el destino de renderizado en la pantalla SDL_FRect renderQuad = {static_cast<float>(x), static_cast<float>(y), static_cast<float>(width_), static_cast<float>(height_)};
SDL_FRect renderQuad = {static_cast<float>(x), static_cast<float>(y), static_cast<float>(width_), static_cast<float>(height_)};
// Obtiene las dimesiones del clip de renderizado // Obtiene las dimesiones del clip de renderizado
if (clip != nullptr) if (clip != nullptr) {
{ renderQuad.w = clip->w;
renderQuad.w = clip->w; renderQuad.h = clip->h;
renderQuad.h = clip->h; }
}
// Calcula el zoom y las coordenadas // Calcula el zoom y las coordenadas
if (zoomH != 1.0f || zoomW != 1.0f) if (zoomH != 1.0f || zoomW != 1.0f) {
{ renderQuad.x = renderQuad.x + (renderQuad.w / 2);
renderQuad.x = renderQuad.x + (renderQuad.w / 2); renderQuad.y = renderQuad.y + (renderQuad.h / 2);
renderQuad.y = renderQuad.y + (renderQuad.h / 2); renderQuad.w = renderQuad.w * zoomW;
renderQuad.w = renderQuad.w * zoomW; renderQuad.h = renderQuad.h * zoomH;
renderQuad.h = renderQuad.h * zoomH; renderQuad.x = renderQuad.x - (renderQuad.w / 2);
renderQuad.x = renderQuad.x - (renderQuad.w / 2); renderQuad.y = renderQuad.y - (renderQuad.h / 2);
renderQuad.y = renderQuad.y - (renderQuad.h / 2); }
}
// Renderiza a pantalla // Renderiza a pantalla
SDL_RenderTextureRotated(renderer_, texture_, clip, &renderQuad, angle, center, flip); SDL_RenderTextureRotated(renderer_, texture_, clip, &renderQuad, angle, center, flip);
} }
// Establece la textura como objetivo de renderizado // Establece la textura como objetivo de renderizado
void Texture::setAsRenderTarget(SDL_Renderer *renderer) void Texture::setAsRenderTarget(SDL_Renderer *renderer) {
{ SDL_SetRenderTarget(renderer, texture_);
SDL_SetRenderTarget(renderer, texture_);
} }
// Obtiene el ancho de la imagen // Obtiene el ancho de la imagen
int Texture::getWidth() int Texture::getWidth() {
{ return width_;
return width_;
} }
// Obtiene el alto de la imagen // Obtiene el alto de la imagen
int Texture::getHeight() int Texture::getHeight() {
{ return height_;
return height_;
} }
// Recarga la textura // Recarga la textura
bool Texture::reLoad() bool Texture::reLoad() {
{ return loadFromFile(path_);
return loadFromFile(path_);
} }
// Obtiene la textura // Obtiene la textura
SDL_Texture *Texture::getSDLTexture() SDL_Texture *Texture::getSDLTexture() {
{ return texture_;
return texture_;
} }
// Desencadenar la superficie actual // Desencadenar la superficie actual
void Texture::unloadSurface() void Texture::unloadSurface() {
{ surface_.reset(); // Resetea el shared_ptr
surface_.reset(); // Resetea el shared_ptr width_ = 0;
width_ = 0; height_ = 0;
height_ = 0;
} }
// Crea una surface desde un fichero .gif // Crea una surface desde un fichero .gif
std::shared_ptr<Surface> Texture::loadSurface(const std::string &file_path) std::shared_ptr<Surface> Texture::loadSurface(const std::string &file_path) {
{ // Libera la superficie actual
// Libera la superficie actual unloadSurface();
unloadSurface();
// Abrir el archivo usando std::ifstream para manejo automático del recurso // Abrir el archivo usando std::ifstream para manejo automático del recurso
std::ifstream file(file_path, std::ios::binary | std::ios::ate); std::ifstream file(file_path, std::ios::binary | std::ios::ate);
if (!file) if (!file) {
{ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str()); throw std::runtime_error("Fichero no encontrado: " + file_path);
throw std::runtime_error("Fichero no encontrado: " + file_path); }
}
// Obtener el tamaño del archivo // Obtener el tamaño del archivo
std::streamsize size = file.tellg(); std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg); file.seekg(0, std::ios::beg);
// Leer el contenido del archivo en un buffer // Leer el contenido del archivo en un buffer
std::vector<Uint8> buffer(size); std::vector<Uint8> buffer(size);
if (!file.read(reinterpret_cast<char *>(buffer.data()), size)) if (!file.read(reinterpret_cast<char *>(buffer.data()), size)) {
{ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al leer el fichero %s", file_path.c_str());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al leer el fichero %s", file_path.c_str()); throw std::runtime_error("Error al leer el fichero: " + file_path);
throw std::runtime_error("Error al leer el fichero: " + file_path); }
}
// Crear un objeto Gif y llamar a la función loadGif // Crear un objeto Gif y llamar a la función loadGif
GIF::Gif gif; GIF::Gif gif;
Uint16 w = 0, h = 0; Uint16 w = 0, h = 0;
std::vector<Uint8> rawPixels = gif.loadGif(buffer.data(), w, h); std::vector<Uint8> rawPixels = gif.loadGif(buffer.data(), w, h);
if (rawPixels.empty()) if (rawPixels.empty()) {
{ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo cargar el GIF %s", file_path.c_str());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo cargar el GIF %s", file_path.c_str()); return nullptr;
return nullptr; }
}
// Si el constructor de Surface espera un std::shared_ptr<Uint8[]>: // Si el constructor de Surface espera un std::shared_ptr<Uint8[]>:
size_t pixelCount = rawPixels.size(); size_t pixelCount = rawPixels.size();
auto pixels = std::shared_ptr<Uint8[]>(new Uint8[pixelCount], std::default_delete<Uint8[]>()); auto pixels = std::shared_ptr<Uint8[]>(new Uint8[pixelCount], std::default_delete<Uint8[]>());
std::memcpy(pixels.get(), rawPixels.data(), pixelCount); std::memcpy(pixels.get(), rawPixels.data(), pixelCount);
auto surface = std::make_shared<Surface>(w, h, pixels); auto surface = std::make_shared<Surface>(w, h, pixels);
// Actualizar las dimensiones // Actualizar las dimensiones
width_ = w; width_ = w;
height_ = h; height_ = h;
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "GIF %s cargado correctamente.", file_path.c_str()); SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "GIF %s cargado correctamente.", file_path.c_str());
return surface; return surface;
} }
// Vuelca la surface en la textura // Vuelca la surface en la textura
void Texture::flipSurface() void Texture::flipSurface() {
{ // Limpia la textura
// Limpia la textura auto temp = SDL_GetRenderTarget(renderer_);
auto temp = SDL_GetRenderTarget(renderer_); SDL_SetRenderTarget(renderer_, texture_);
SDL_SetRenderTarget(renderer_, texture_); SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0); SDL_RenderClear(renderer_);
SDL_RenderClear(renderer_); SDL_SetRenderTarget(renderer_, temp);
SDL_SetRenderTarget(renderer_, temp);
// Vuelca los datos // Vuelca los datos
Uint32 *pixels; Uint32 *pixels;
int pitch; int pitch;
SDL_LockTexture(texture_, nullptr, reinterpret_cast<void **>(&pixels), &pitch); SDL_LockTexture(texture_, nullptr, reinterpret_cast<void **>(&pixels), &pitch);
for (int i = 0; i < width_ * height_; ++i) for (int i = 0; i < width_ * height_; ++i) {
{ pixels[i] = palettes_[current_palette_][surface_->data[i]];
pixels[i] = palettes_[current_palette_][surface_->data[i]]; }
} SDL_UnlockTexture(texture_);
SDL_UnlockTexture(texture_);
} }
// Establece un color de la paleta // Establece un color de la paleta
void Texture::setPaletteColor(int palette, int index, Uint32 color) void Texture::setPaletteColor(int palette, int index, Uint32 color) {
{ palettes_.at(palette)[index] = color;
palettes_.at(palette)[index] = color;
} }
// Carga una paleta desde un fichero // Carga una paleta desde un fichero
Palette Texture::loadPaletteFromFile(const std::string &file_path) Palette Texture::loadPaletteFromFile(const std::string &file_path) {
{ Palette palette;
Palette palette;
// Abrir el archivo GIF // Abrir el archivo GIF
std::ifstream file(file_path, std::ios::binary | std::ios::ate); std::ifstream file(file_path, std::ios::binary | std::ios::ate);
if (!file) if (!file) {
{ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str()); throw std::runtime_error("Fichero no encontrado: " + file_path);
throw std::runtime_error("Fichero no encontrado: " + file_path); } else {
} printWithDots("Palette : ", getFileName(file_path), "[ LOADED ]");
else }
{
printWithDots("Palette : ", getFileName(file_path), "[ LOADED ]");
}
// Obtener el tamaño del archivo y leerlo en un buffer // Obtener el tamaño del archivo y leerlo en un buffer
std::streamsize size = file.tellg(); std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg); file.seekg(0, std::ios::beg);
std::vector<Uint8> buffer(size); std::vector<Uint8> buffer(size);
if (!file.read(reinterpret_cast<char *>(buffer.data()), size)) if (!file.read(reinterpret_cast<char *>(buffer.data()), size)) {
{ SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo leer completamente el fichero %s", file_path.c_str());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo leer completamente el fichero %s", file_path.c_str()); throw std::runtime_error("Error al leer el fichero: " + file_path);
throw std::runtime_error("Error al leer el fichero: " + file_path); }
}
// Usar la nueva función loadPalette, que devuelve un vector<uint32_t> // Usar la nueva función loadPalette, que devuelve un vector<uint32_t>
GIF::Gif gif; GIF::Gif gif;
std::vector<uint32_t> pal = gif.loadPalette(buffer.data()); std::vector<uint32_t> pal = gif.loadPalette(buffer.data());
if (pal.empty()) if (pal.empty()) {
{ SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Advertencia: No se encontró paleta en el archivo %s", file_path.c_str());
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Advertencia: No se encontró paleta en el archivo %s", file_path.c_str()); return palette; // Devuelve un vector vacío si no hay paleta
return palette; // Devuelve un vector vacío si no hay paleta }
}
// Modificar la conversión para obtener formato RGBA (0xRRGGBBAA) // Modificar la conversión para obtener formato RGBA (0xRRGGBBAA)
for (size_t i = 0; i < pal.size() && i < palette.size(); ++i) for (size_t i = 0; i < pal.size() && i < palette.size(); ++i) {
{ palette[i] = (pal[i] << 8) | 0xFF; // Resultado: 0xRRGGBBAA
palette[i] = (pal[i] << 8) | 0xFF; // Resultado: 0xRRGGBBAA }
}
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "Paleta cargada correctamente desde %s", file_path.c_str()); SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "Paleta cargada correctamente desde %s", file_path.c_str());
return palette; return palette;
} }
// Añade una paleta a la lista // Añade una paleta a la lista
void Texture::addPaletteFromGifFile(const std::string &path) void Texture::addPaletteFromGifFile(const std::string &path) {
{ palettes_.emplace_back(loadPaletteFromFile(path));
palettes_.emplace_back(loadPaletteFromFile(path)); setPaletteColor(palettes_.size() - 1, 0, 0x00000000);
setPaletteColor(palettes_.size() - 1, 0, 0x00000000);
} }
// Añade una paleta a la lista // Añade una paleta a la lista
void Texture::addPaletteFromPalFile(const std::string &path) void Texture::addPaletteFromPalFile(const std::string &path) {
{ palettes_.emplace_back(readPalFile(path));
palettes_.emplace_back(readPalFile(path)); setPaletteColor(palettes_.size() - 1, 0, 0x00000000);
setPaletteColor(palettes_.size() - 1, 0, 0x00000000);
} }
// Cambia la paleta de la textura // Cambia la paleta de la textura
void Texture::setPalette(size_t palette) void Texture::setPalette(size_t palette) {
{ if (palette < palettes_.size()) {
if (palette < palettes_.size()) current_palette_ = palette;
{ flipSurface();
current_palette_ = palette; }
flipSurface();
}
} }
// Obtiene el renderizador // Obtiene el renderizador
SDL_Renderer *Texture::getRenderer() { return renderer_; } SDL_Renderer *Texture::getRenderer() { return renderer_; }
// Carga una paleta desde un archivo .pal // Carga una paleta desde un archivo .pal
Palette Texture::readPalFile(const std::string &file_path) Palette Texture::readPalFile(const std::string &file_path) {
{ Palette palette{};
Palette palette{}; palette.fill(0); // Inicializar todo con 0 (transparente por defecto)
palette.fill(0); // Inicializar todo con 0 (transparente por defecto)
std::ifstream file(file_path); std::ifstream file(file_path);
if (!file.is_open()) if (!file.is_open()) {
{ throw std::runtime_error("No se pudo abrir el archivo .pal");
throw std::runtime_error("No se pudo abrir el archivo .pal"); }
}
std::string line; std::string line;
int line_number = 0; int line_number = 0;
int color_index = 0; int color_index = 0;
while (std::getline(file, line)) while (std::getline(file, line)) {
{ ++line_number;
++line_number;
// Ignorar las tres primeras líneas del archivo // Ignorar las tres primeras líneas del archivo
if (line_number <= 3) if (line_number <= 3) {
{ continue;
continue; }
}
// Procesar las líneas restantes con valores RGB // Procesar las líneas restantes con valores RGB
std::istringstream ss(line); std::istringstream ss(line);
int r, g, b; int r, g, b;
if (ss >> r >> g >> b) if (ss >> r >> g >> b) {
{ // Construir el color RGBA (A = 255 por defecto)
// Construir el color RGBA (A = 255 por defecto) Uint32 color = (r << 24) | (g << 16) | (b << 8) | 255;
Uint32 color = (r << 24) | (g << 16) | (b << 8) | 255; palette[color_index++] = color;
palette[color_index++] = color;
// Limitar a un máximo de 256 colores (opcional) // Limitar a un máximo de 256 colores (opcional)
if (color_index >= 256) if (color_index >= 256) {
{ break;
break; }
} }
} }
}
file.close(); file.close();
return palette; return palette;
} }
+42 -43
View File
@@ -1,11 +1,12 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para Uint8, SDL_Renderer, Uint16, SDL_FlipMode, SDL_PixelFormat, SDL_TextureAccess, SDL_Texture, Uint32, SDL_BlendMode, SDL_FPoint, SDL_FRect #include <SDL3/SDL.h> // Para Uint8, SDL_Renderer, Uint16, SDL_FlipMode, SDL_PixelFormat, SDL_TextureAccess, SDL_Texture, Uint32, SDL_BlendMode, SDL_FPoint, SDL_FRect
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <array> // Para array
#include <memory> // Para shared_ptr #include <array> // Para array
#include <string> // Para string, basic_string #include <memory> // Para shared_ptr
#include <vector> // Para vector #include <string> // Para string, basic_string
#include <vector> // Para vector
struct Color; struct Color;
@@ -13,8 +14,7 @@ struct Color;
using Palette = std::array<Uint32, 256>; using Palette = std::array<Uint32, 256>;
// Definición de Surface para imágenes con paleta // Definición de Surface para imágenes con paleta
struct Surface struct Surface {
{
std::shared_ptr<Uint8[]> data; std::shared_ptr<Uint8[]> data;
Uint16 w, h; Uint16 w, h;
@@ -24,58 +24,57 @@ struct Surface
}; };
// Clase Texture: gestiona texturas, paletas y renderizado // Clase Texture: gestiona texturas, paletas y renderizado
class Texture class Texture {
{ public:
public:
// --- Constructores y destructor --- // --- Constructores y destructor ---
explicit Texture(SDL_Renderer *renderer, const std::string &path = std::string()); explicit Texture(SDL_Renderer *renderer, const std::string &path = std::string());
~Texture(); ~Texture();
// --- Carga y creación --- // --- Carga y creación ---
bool loadFromFile(const std::string &path); // Carga una imagen desde un fichero bool loadFromFile(const std::string &path); // Carga una imagen desde un fichero
bool createBlank(int width, int height, SDL_PixelFormat format = SDL_PIXELFORMAT_RGBA8888, SDL_TextureAccess access = SDL_TEXTUREACCESS_STREAMING); // Crea una textura en blanco bool createBlank(int width, int height, SDL_PixelFormat format = SDL_PIXELFORMAT_RGBA8888, SDL_TextureAccess access = SDL_TEXTUREACCESS_STREAMING); // Crea una textura en blanco
bool reLoad(); // Recarga la textura bool reLoad(); // Recarga la textura
// --- Renderizado --- // --- Renderizado ---
void render(int x, int y, SDL_FRect *clip = nullptr, float zoomW = 1, float zoomH = 1, double angle = 0.0, SDL_FPoint *center = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE); // Renderiza la textura en un punto específico void render(int x, int y, SDL_FRect *clip = nullptr, float zoomW = 1, float zoomH = 1, double angle = 0.0, SDL_FPoint *center = nullptr, SDL_FlipMode flip = SDL_FLIP_NONE); // Renderiza la textura en un punto específico
void setAsRenderTarget(SDL_Renderer *renderer); // Establece la textura como objetivo de renderizado void setAsRenderTarget(SDL_Renderer *renderer); // Establece la textura como objetivo de renderizado
// --- Modificadores de color y blending --- // --- Modificadores de color y blending ---
void setColor(Uint8 red, Uint8 green, Uint8 blue); // Establece el color para la modulación void setColor(Uint8 red, Uint8 green, Uint8 blue); // Establece el color para la modulación
void setColor(Color color); // Establece el color para la modulación void setColor(Color color); // Establece el color para la modulación
void setBlendMode(SDL_BlendMode blending); // Establece el blending void setBlendMode(SDL_BlendMode blending); // Establece el blending
void setAlpha(Uint8 alpha); // Establece el alpha para la modulación void setAlpha(Uint8 alpha); // Establece el alpha para la modulación
// --- Paletas --- // --- Paletas ---
void addPaletteFromGifFile(const std::string &path); // Añade una paleta a la lista void addPaletteFromGifFile(const std::string &path); // Añade una paleta a la lista
void addPaletteFromPalFile(const std::string &path); // Añade una paleta a la lista void addPaletteFromPalFile(const std::string &path); // Añade una paleta a la lista
void setPaletteColor(int palette, int index, Uint32 color); // Establece un color de la paleta void setPaletteColor(int palette, int index, Uint32 color); // Establece un color de la paleta
void setPalette(size_t palette); // Cambia la paleta de la textura void setPalette(size_t palette); // Cambia la paleta de la textura
// --- Getters --- // --- Getters ---
int getWidth(); // Obtiene el ancho de la imagen int getWidth(); // Obtiene el ancho de la imagen
int getHeight(); // Obtiene el alto de la imagen int getHeight(); // Obtiene el alto de la imagen
SDL_Texture *getSDLTexture(); // Obtiene la textura SDL SDL_Texture *getSDLTexture(); // Obtiene la textura SDL
SDL_Renderer *getRenderer(); // Obtiene el renderizador SDL_Renderer *getRenderer(); // Obtiene el renderizador
private: private:
// --- Objetos y punteros --- // --- Objetos y punteros ---
SDL_Renderer *renderer_; // Renderizador donde dibujar la textura SDL_Renderer *renderer_; // Renderizador donde dibujar la textura
SDL_Texture *texture_ = nullptr; // La textura SDL_Texture *texture_ = nullptr; // La textura
std::shared_ptr<Surface> surface_ = nullptr; // Surface para usar imágenes en formato gif con paleta std::shared_ptr<Surface> surface_ = nullptr; // Surface para usar imágenes en formato gif con paleta
// --- Variables --- // --- Variables ---
std::string path_; // Ruta de la imagen de la textura std::string path_; // Ruta de la imagen de la textura
int width_ = 0; // Ancho de la imagen int width_ = 0; // Ancho de la imagen
int height_ = 0; // Alto de la imagen int height_ = 0; // Alto de la imagen
std::vector<Palette> palettes_; // Vector con las diferentes paletas std::vector<Palette> palettes_; // Vector con las diferentes paletas
int current_palette_ = 0; // Índice de la paleta en uso int current_palette_ = 0; // Índice de la paleta en uso
// --- Métodos internos --- // --- Métodos internos ---
std::shared_ptr<Surface> loadSurface(const std::string &file_name); // Crea una surface desde un fichero .gif std::shared_ptr<Surface> loadSurface(const std::string &file_name); // Crea una surface desde un fichero .gif
void flipSurface(); // Vuelca la surface en la textura void flipSurface(); // Vuelca la surface en la textura
Palette loadPaletteFromFile(const std::string &file_name); // Carga una paleta desde un fichero Palette loadPaletteFromFile(const std::string &file_name); // Carga una paleta desde un fichero
void unloadTexture(); // Libera la memoria de la textura void unloadTexture(); // Libera la memoria de la textura
void unloadSurface(); // Libera la surface actual void unloadSurface(); // Libera la surface actual
Palette readPalFile(const std::string &file_path); // Carga una paleta desde un archivo .pal Palette readPalFile(const std::string &file_path); // Carga una paleta desde un archivo .pal
}; };
+56 -72
View File
@@ -1,21 +1,21 @@
#include "tiled_bg.h" #include "tiled_bg.h"
#include <SDL3/SDL.h> // Para SDL_SetRenderTarget, SDL_CreateTexture, SDL_De... #include <SDL3/SDL.h> // Para SDL_SetRenderTarget, SDL_CreateTexture, SDL_De...
#include <stdlib.h> // Para rand #include <stdlib.h> // Para rand
#include <cmath> // Para sin
#include <memory> // Para unique_ptr, make_unique
#include <string> // Para basic_string
#include "resource.h" // Para Resource #include <cmath> // Para sin
#include "screen.h" // Para Screen #include <memory> // Para unique_ptr, make_unique
#include "sprite.h" // Para Sprite #include <string> // Para basic_string
#include "resource.h" // Para Resource
#include "screen.h" // Para Screen
#include "sprite.h" // Para Sprite
// Constructor // Constructor
TiledBG::TiledBG(SDL_FRect pos, TiledBGMode mode) TiledBG::TiledBG(SDL_FRect pos, TiledBGMode mode)
: renderer_(Screen::get()->getRenderer()), : renderer_(Screen::get()->getRenderer()),
pos_(pos), pos_(pos),
mode_(mode == TiledBGMode::RANDOM ? static_cast<TiledBGMode>(rand() % 2) : mode) mode_(mode == TiledBGMode::RANDOM ? static_cast<TiledBGMode>(rand() % 2) : mode) {
{
// Crea la textura para el mosaico de fondo // Crea la textura para el mosaico de fondo
canvas_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, pos_.w * 2, pos_.h * 2); canvas_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, pos_.w * 2, pos_.h * 2);
@@ -23,39 +23,35 @@ TiledBG::TiledBG(SDL_FRect pos, TiledBGMode mode)
fillTexture(); fillTexture();
// Inicializa variables // Inicializa variables
switch (mode_) switch (mode_) {
{ case TiledBGMode::STATIC:
case TiledBGMode::STATIC: window_ = {0, 0, pos_.w, pos_.h};
window_ = {0, 0, pos_.w, pos_.h}; speed_ = 0.0f;
speed_ = 0.0f; break;
break; case TiledBGMode::DIAGONAL:
case TiledBGMode::DIAGONAL: window_ = {0, 0, pos_.w, pos_.h};
window_ = {0, 0, pos_.w, pos_.h}; break;
break; case TiledBGMode::CIRCLE:
case TiledBGMode::CIRCLE: window_ = {128, 128, pos_.w, pos_.h};
window_ = {128, 128, pos_.w, pos_.h}; break;
break; default:
default: window_ = {0, 0, pos_.w, pos_.h};
window_ = {0, 0, pos_.w, pos_.h}; break;
break;
} }
// Inicializa los valores del vector con los valores del seno // Inicializa los valores del vector con los valores del seno
for (int i = 0; i < 360; ++i) for (int i = 0; i < 360; ++i) {
{ sin_[i] = std::sin(i * 3.14159 / 180.0); // Convierte grados a radianes y calcula el seno
sin_[i] = std::sin(i * 3.14159 / 180.0); // Convierte grados a radianes y calcula el seno
} }
} }
// Destructor // Destructor
TiledBG::~TiledBG() TiledBG::~TiledBG() {
{
SDL_DestroyTexture(canvas_); SDL_DestroyTexture(canvas_);
} }
// Rellena la textura con el contenido // Rellena la textura con el contenido
void TiledBG::fillTexture() void TiledBG::fillTexture() {
{
// Crea los objetos para pintar en la textura de fondo // Crea los objetos para pintar en la textura de fondo
auto tile = std::make_unique<Sprite>(Resource::get()->getTexture("title_bg_tile.png"), (SDL_FRect){0, 0, TILE_WIDTH_, TILE_HEIGHT_}); auto tile = std::make_unique<Sprite>(Resource::get()->getTexture("title_bg_tile.png"), (SDL_FRect){0, 0, TILE_WIDTH_, TILE_HEIGHT_});
@@ -67,10 +63,8 @@ void TiledBG::fillTexture()
const auto i_max = pos_.w * 2 / TILE_WIDTH_; const auto i_max = pos_.w * 2 / TILE_WIDTH_;
const auto j_max = pos_.h * 2 / TILE_HEIGHT_; const auto j_max = pos_.h * 2 / TILE_HEIGHT_;
tile->setSpriteClip(0, 0, TILE_WIDTH_, TILE_HEIGHT_); tile->setSpriteClip(0, 0, TILE_WIDTH_, TILE_HEIGHT_);
for (int i = 0; i < i_max; ++i) for (int i = 0; i < i_max; ++i) {
{ for (int j = 0; j < j_max; ++j) {
for (int j = 0; j < j_max; ++j)
{
tile->setX(i * TILE_WIDTH_); tile->setX(i * TILE_WIDTH_);
tile->setY(j * TILE_HEIGHT_); tile->setY(j * TILE_HEIGHT_);
tile->render(); tile->render();
@@ -82,65 +76,55 @@ void TiledBG::fillTexture()
} }
// Pinta la clase en pantalla // Pinta la clase en pantalla
void TiledBG::render() void TiledBG::render() {
{
SDL_RenderTexture(renderer_, canvas_, &window_, &pos_); SDL_RenderTexture(renderer_, canvas_, &window_, &pos_);
} }
// Actualiza la lógica de la clase // Actualiza la lógica de la clase
void TiledBG::update() void TiledBG::update() {
{
updateDesp(); updateDesp();
updateStop(); updateStop();
switch (mode_) switch (mode_) {
{ case TiledBGMode::DIAGONAL: {
case TiledBGMode::DIAGONAL: // El tileado de fondo se desplaza en diagonal
{ window_.x = static_cast<int>(desp_) % TILE_WIDTH_;
// El tileado de fondo se desplaza en diagonal window_.y = static_cast<int>(desp_) % TILE_HEIGHT_;
window_.x = static_cast<int>(desp_) % TILE_WIDTH_;
window_.y = static_cast<int>(desp_) % TILE_HEIGHT_;
break; break;
} }
case TiledBGMode::CIRCLE: case TiledBGMode::CIRCLE: {
{ // El tileado de fondo se desplaza en circulo
// El tileado de fondo se desplaza en circulo const int INDEX = static_cast<int>(desp_) % 360;
const int INDEX = static_cast<int>(desp_) % 360;
window_.x = 128 + (static_cast<int>(sin_[(INDEX + 270) % 360] * 128)); window_.x = 128 + (static_cast<int>(sin_[(INDEX + 270) % 360] * 128));
window_.y = 128 + (static_cast<int>(sin_[(360 - INDEX) % 360] * 96)); window_.y = 128 + (static_cast<int>(sin_[(360 - INDEX) % 360] * 96));
break; break;
} }
default: default:
break; break;
} }
} }
// Detiene el desplazamiento de forma ordenada // Detiene el desplazamiento de forma ordenada
void TiledBG::updateStop() void TiledBG::updateStop() {
{ if (stopping_) {
if (stopping_) const int UMBRAL = 20 * speed_; // Ajusta este valor según la precisión deseada
{
const int UMBRAL = 20 * speed_; // Ajusta este valor según la precisión deseada
// Desacelerar si estamos cerca de completar el ciclo (ventana a punto de regresar a 0) // Desacelerar si estamos cerca de completar el ciclo (ventana a punto de regresar a 0)
if (window_.x >= TILE_WIDTH_ - UMBRAL) if (window_.x >= TILE_WIDTH_ - UMBRAL) {
{ speed_ /= 1.05f; // Reduce gradualmente la velocidad
speed_ /= 1.05f; // Reduce gradualmente la velocidad
// Asegura que no baje demasiado // Asegura que no baje demasiado
if (speed_ < 0.1f) if (speed_ < 0.1f) {
{
speed_ = 0.1f; speed_ = 0.1f;
} }
} }
// Si estamos en 0, detener // Si estamos en 0, detener
if (window_.x == 0) if (window_.x == 0) {
{
speed_ = 0.0f; speed_ = 0.0f;
stopping_ = false; // Desactivamos el estado de "stopping" stopping_ = false; // Desactivamos el estado de "stopping"
} }
} }
} }
Loaded 100 of 112 files, more files were not shown because too many files have changed in this diff. Show more