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

This commit is contained in:
2025-07-18 20:01:13 +02:00
parent 734c220fb0
commit dabba41179
112 changed files with 22361 additions and 26474 deletions

11
.clang-format Normal file
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
.clang-tidy Normal file
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 }

View File

@@ -2,6 +2,7 @@
#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 <algorithm> // Para min
#include <fstream> // Para basic_istream, basic_ifstream, basic_ios, ifst... #include <fstream> // Para basic_istream, basic_ifstream, basic_ios, ifst...
#include <sstream> // Para basic_stringstream #include <sstream> // Para basic_stringstream
@@ -12,11 +13,9 @@
#include "utils.h" // Para printWithDots #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()); 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);
} }
@@ -25,8 +24,7 @@ AnimationsFileBuffer loadAnimationsFromFile(const std::string &file_path)
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);
} }
@@ -36,11 +34,9 @@ AnimationsFileBuffer loadAnimationsFromFile(const std::string &file_path)
// 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); AnimationsFileBuffer v = loadAnimationsFromFile(file_path);
loadFromAnimationsFileBuffer(v); loadFromAnimationsFileBuffer(v);
} }
@@ -48,20 +44,16 @@ AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const std::stri
// 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 // Si se encuentra la animación en el mapa, devuelve su índice
return it->second; return it->second;
} }
@@ -72,10 +64,8 @@ int AnimatedSprite::getIndex(const std::string &name)
} }
// 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;
} }
@@ -84,22 +74,17 @@ void AnimatedSprite::animate()
// 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)
{ // Si no hay loop, deja el último frame
animations_[current_animation_].current_frame = animations_[current_animation_].frames.size(); animations_[current_animation_].current_frame = animations_[current_animation_].frames.size();
animations_[current_animation_].completed = true; animations_[current_animation_].completed = true;
} } else { // Si hay loop, vuelve al frame indicado
else
{ // Si hay loop, vuelve al frame indicado
animations_[current_animation_].counter = 0; animations_[current_animation_].counter = 0;
animations_[current_animation_].current_frame = animations_[current_animation_].loop; animations_[current_animation_].current_frame = animations_[current_animation_].loop;
} }
} }
// En caso contrario // En caso contrario
else else {
{
// Escoge el frame correspondiente de la animación // Escoge el frame correspondiente de la animación
setSpriteClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]); setSpriteClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]);
@@ -109,27 +94,21 @@ void AnimatedSprite::animate()
} }
// 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_; const auto OLD_ANIMATION = current_animation_;
current_animation_ = NEW_ANIMATION; current_animation_ = NEW_ANIMATION;
if (reset) if (reset) {
{
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;
} } else {
else
{
animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size()); 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_].counter = animations_[OLD_ANIMATION].counter;
animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed; animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed;
@@ -138,21 +117,16 @@ void AnimatedSprite::setCurrentAnimation(const std::string &name, bool reset)
} }
// 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_; const auto OLD_ANIMATION = current_animation_;
current_animation_ = NEW_ANIMATION; current_animation_ = NEW_ANIMATION;
if (reset) if (reset) {
{
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;
} } else {
else
{
animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size()); 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_].counter = animations_[OLD_ANIMATION].counter;
animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed; animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed;
@@ -161,42 +135,36 @@ void AnimatedSprite::setCurrentAnimation(int index, bool reset)
} }
// 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")
@@ -214,17 +182,14 @@ void AnimatedSprite::loadFromAnimationsFileBuffer(const AnimationsFileBuffer &so
} }
// 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++; index++;
line = source.at(index); line = source.at(index);
size_t pos = line.find("="); 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);
@@ -234,25 +199,21 @@ void AnimatedSprite::loadFromAnimationsFileBuffer(const AnimationsFileBuffer &so
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 // Comprueba que el tile no sea mayor que el máximo índice permitido
const int num_tile = std::stoi(tmp); const int num_tile = std::stoi(tmp);
if (num_tile <= max_tiles) if (num_tile <= max_tiles) {
{
rect.x = (num_tile % frames_per_row) * frame_width; rect.x = (num_tile % frames_per_row) * frame_width;
rect.y = (num_tile / frames_per_row) * frame_height; rect.y = (num_tile / frames_per_row) * frame_height;
animation.frames.emplace_back(rect); animation.frames.emplace_back(rect);
} }
} }
} } 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());
} }
} while (line != "[/animation]"); } while (line != "[/animation]");
@@ -274,7 +235,6 @@ void AnimatedSprite::loadFromAnimationsFileBuffer(const AnimationsFileBuffer &so
} }
// 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;
} }

View File

@@ -2,6 +2,7 @@
#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 <memory> // Para shared_ptr
#include <string> // Para basic_string, string, hash #include <string> // Para basic_string, string, hash
#include <unordered_map> // Para unordered_map #include <unordered_map> // Para unordered_map
@@ -13,8 +14,7 @@
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
@@ -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);
@@ -56,7 +55,7 @@ public:
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

View File

@@ -1,6 +1,7 @@
#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+
@@ -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(),
[&text](const auto &f)
{
return getFileName(f.file) == text; 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,10 +95,8 @@ 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: case AssetType::BITMAP:
return "BITMAP"; return "BITMAP";
case AssetType::MUSIC: case AssetType::MUSIC:
@@ -141,14 +121,11 @@ std::string Asset::getTypeName(AssetType type) const
} }
// 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);
} }
} }

View File

@@ -4,8 +4,7 @@
#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,
@@ -19,9 +18,8 @@ enum class AssetType : int
}; };
// 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
@@ -33,10 +31,9 @@ public:
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

View File

@@ -1,6 +1,7 @@
#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...
@@ -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);

View File

@@ -3,11 +3,9 @@
#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
@@ -49,16 +47,14 @@ public:
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

View File

@@ -2,6 +2,7 @@
#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
@@ -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));
} }

View File

@@ -2,6 +2,7 @@
#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 <memory> // Para unique_ptr, shared_ptr
#include <vector> // Para vector #include <vector> // Para vector
@@ -25,9 +26,8 @@ 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();
@@ -52,7 +52,7 @@ public:
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

View File

@@ -24,12 +24,9 @@ Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel
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: {
{
case BalloonType::BALLOON:
{
vy_ = 0; vy_ = 0;
max_vy_ = 3.0f; max_vy_ = 3.0f;
@@ -46,8 +43,7 @@ Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel
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;
@@ -62,8 +58,7 @@ Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel
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];
@@ -99,8 +94,7 @@ Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel
} }
// 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_;
@@ -108,10 +102,8 @@ void Balloon::alignTo(int 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()); auto sp = std::make_unique<Sprite>(sprite_->getTexture(), sprite_->getPosition());
@@ -120,8 +112,7 @@ void Balloon::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();
@@ -133,19 +124,14 @@ void Balloon::render()
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 // Renderizado para el resto de globos
if (isBeingCreated()) if (isBeingCreated()) {
{
// Renderizado con transparencia // Renderizado con transparencia
sprite_->getTexture()->setAlpha(255 - (int)((float)creation_counter_ * (255.0f / (float)creation_counter_ini_))); sprite_->getTexture()->setAlpha(255 - (int)((float)creation_counter_ * (255.0f / (float)creation_counter_ini_)));
sprite_->render(); sprite_->render();
sprite_->getTexture()->setAlpha(255); sprite_->getTexture()->setAlpha(255);
} } else {
else
{
// Renderizado normal // Renderizado normal
sprite_->render(); sprite_->render();
} }
@@ -153,11 +139,9 @@ void Balloon::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 // Mueve el globo en horizontal
x_ += vx_ * speed_; x_ += vx_ * speed_;
@@ -165,19 +149,15 @@ void Balloon::move()
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(); sprite_->switchRotate();
} } else {
else
{
enableBounce(); enableBounce();
} }
} }
@@ -186,11 +166,9 @@ void Balloon::move()
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_) if (bouncing_sound_enabled_)
playSound(bouncing_sound_); playSound(bouncing_sound_);
y_ = min_y; y_ = min_y;
@@ -201,18 +179,14 @@ void Balloon::move()
// 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(); enableBounce();
} } else {
else
{
setInvulnerable(false); setInvulnerable(false);
} }
} }
@@ -230,8 +204,7 @@ void Balloon::move()
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;
@@ -242,8 +215,7 @@ void Balloon::move()
} }
// 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();
@@ -254,20 +226,16 @@ void Balloon::update()
} }
// 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 // Actualiza el valor de las variables
stop(); stop();
setInvulnerable(true); 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_++; y_++;
x_ += vx_; x_ += vx_;
@@ -275,8 +243,7 @@ void Balloon::updateState()
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_;
@@ -285,8 +252,7 @@ void Balloon::updateState()
--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();
@@ -297,13 +263,11 @@ void Balloon::updateState()
} }
// 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";
@@ -326,100 +290,84 @@ void Balloon::setAnimation()
} }
// 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; const int index = bouncing_.counter / bouncing_.speed;
bouncing_.zoomW = bouncing_.w[index]; bouncing_.zoomW = bouncing_.w[index];
bouncing_.zoomH = bouncing_.h[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; use_reversed_colors_ = true;
setAnimation(); 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;
@@ -428,10 +376,8 @@ void Balloon::playSound(const std::string &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_) if (poping_sound_enabled_)
playSound(popping_sound_); playSound(popping_sound_);
} }

View File

@@ -1,6 +1,7 @@
#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 <memory> // Para shared_ptr, unique_ptr
#include <string> // Para basic_string, string #include <string> // Para basic_string, string
#include <vector> // Para vector #include <vector> // Para vector
@@ -20,16 +21,14 @@ 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,
@@ -48,9 +47,8 @@ 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,
@@ -105,10 +103,9 @@ public:
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
@@ -121,8 +118,7 @@ private:
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;

View File

@@ -4,8 +4,7 @@
#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];
@@ -46,8 +45,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -56,8 +54,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -66,8 +63,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -76,8 +72,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -86,8 +81,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -96,8 +90,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -106,8 +99,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -116,8 +108,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -126,8 +117,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -136,8 +126,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -146,8 +135,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -156,8 +144,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -166,8 +153,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -176,8 +162,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -186,8 +171,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -196,8 +180,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -206,8 +189,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -216,8 +198,7 @@ void BalloonFormations::initBalloonFormations()
// #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);
@@ -227,14 +208,10 @@ void BalloonFormations::initBalloonFormations()
{ {
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)); init_params.emplace_back(x4_0 + (i * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME + (0 * i));
} } else {
else
{
init_params.emplace_back(x4_100 - ((i - half) * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_NEGATIVE, 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));
} }
} }
@@ -245,14 +222,10 @@ void BalloonFormations::initBalloonFormations()
{ {
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)); init_params.emplace_back(x4_0 + (i * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE4, CREATION_TIME + (0 * i));
} } else {
else
{
init_params.emplace_back(x4_100 - ((i - half) * (BALLOON_SIZE[3] + 1)), y4, BALLOON_VELX_NEGATIVE, 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));
} }
} }
@@ -263,14 +236,10 @@ void BalloonFormations::initBalloonFormations()
{ {
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)); init_params.emplace_back(x2_0 + (i * (BALLOON_SIZE[1] + 1)), y2, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE2, CREATION_TIME - (3 * i));
} } else {
else
{
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))); 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)));
} }
} }
@@ -281,14 +250,10 @@ void BalloonFormations::initBalloonFormations()
{ {
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)); init_params.emplace_back(x3_0 + (i * (BALLOON_SIZE[2] * 2)), y3, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i));
} } else {
else
{
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))); 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)));
} }
} }
@@ -299,14 +264,10 @@ void BalloonFormations::initBalloonFormations()
{ {
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)); init_params.emplace_back(x3_0 + (i * (BALLOON_SIZE[2] + 1)), y3, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE3, CREATION_TIME - (10 * i));
} } else {
else
{
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))); 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)));
} }
} }
@@ -317,14 +278,10 @@ void BalloonFormations::initBalloonFormations()
{ {
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)); init_params.emplace_back(x1_50, y1, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME + (5 * i));
} } else {
else
{
init_params.emplace_back(x1_50, y1, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME + (5 * (i - half))); init_params.emplace_back(x1_50, y1, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME + (5 * (i - half)));
} }
} }
@@ -335,14 +292,10 @@ void BalloonFormations::initBalloonFormations()
{ {
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)); init_params.emplace_back(x1_50 + 20, y1, BALLOON_VELX_NEGATIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME - (5 * i));
} } else {
else
{
init_params.emplace_back(x1_50 - 20, y1, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME - (5 * (i - half))); init_params.emplace_back(x1_50 - 20, y1, BALLOON_VELX_POSITIVE, BalloonType::BALLOON, BalloonSize::SIZE1, CREATION_TIME - (5 * (i - half)));
} }
} }
@@ -353,11 +306,9 @@ void BalloonFormations::initBalloonFormations()
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( init_params.emplace_back(
balloon_formation_.at(k).init.at(i).x, balloon_formation_.at(k).init.at(i).x,
balloon_formation_.at(k).init.at(i).y, balloon_formation_.at(k).init.at(i).y,
@@ -380,78 +331,47 @@ void BalloonFormations::initBalloonFormations()
} }
// 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)};
} }

View File

@@ -11,8 +11,7 @@ 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
@@ -28,8 +27,7 @@ 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
@@ -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,7 +56,7 @@ 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

View File

@@ -1,6 +1,7 @@
#include "balloon_manager.h" #include "balloon_manager.h"
#include <stdlib.h> // Para rand #include <stdlib.h> // Para rand
#include <algorithm> // Para remove_if #include <algorithm> // Para remove_if
#include <numeric> // Para accumulate #include <numeric> // Para accumulate
@@ -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,13 +255,11 @@ 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;
@@ -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);
} }
} }

View File

@@ -1,6 +1,7 @@
#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 <memory> // Para shared_ptr, unique_ptr
#include <string> // Para string #include <string> // Para string
#include <vector> // Para vector #include <vector> // Para vector
@@ -16,9 +17,8 @@ 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;
@@ -77,7 +77,7 @@ public:
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

View File

@@ -12,15 +12,13 @@ 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;
@@ -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_);
} }

View File

@@ -1,14 +1,14 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para Uint8 #include <SDL3/SDL.h> // Para Uint8
#include <memory> // Para unique_ptr #include <memory> // Para unique_ptr
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
#include "utils.h" // Para Circle #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,
@@ -16,16 +16,14 @@ enum class BulletType : Uint8
}; };
// 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;
@@ -46,7 +44,7 @@ public:
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;

View File

@@ -10,25 +10,21 @@
// 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,12 +57,9 @@ 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) {
{
switch (event.type)
{
case SDL_EVENT_GAMEPAD_BUTTON_DOWN: case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
doControllerButtonDown(event.gbutton); doControllerButtonDown(event.gbutton);
break; break;
@@ -85,10 +73,8 @@ void DefineButtons::checkEvents(const SDL_Event &event)
} }
// 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();

View File

@@ -2,6 +2,7 @@
#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 <memory> // Para shared_ptr
#include <string> // Para basic_string, string #include <string> // Para basic_string, string
#include <vector> // Para vector #include <vector> // Para vector
@@ -12,8 +13,7 @@ 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
@@ -23,9 +23,8 @@ struct DefineButtonsButton
}; };
// Clase DefineButtons // Clase DefineButtons
class DefineButtons class DefineButtons {
{ public:
public:
DefineButtons(); DefineButtons();
~DefineButtons() = default; ~DefineButtons() = default;
@@ -34,7 +33,7 @@ public:
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

View File

@@ -6,6 +6,7 @@
#include <stdio.h> // Para printf, perror #include <stdio.h> // Para printf, perror
#include <sys/stat.h> // Para mkdir, stat, S_IRWXU #include <sys/stat.h> // Para mkdir, stat, S_IRWXU
#include <unistd.h> // Para getuid #include <unistd.h> // Para getuid
#include <algorithm> // Para min #include <algorithm> // Para min
#include <cstdlib> // Para exit, EXIT_FAILURE, size_t, srand #include <cstdlib> // Para exit, EXIT_FAILURE, size_t, srand
#include <ctime> // Para time #include <ctime> // Para time
@@ -40,8 +41,7 @@
#endif #endif
// Constructor // Constructor
Director::Director(int argc, const char *argv[]) Director::Director(int argc, const char *argv[]) {
{
#ifdef RECORDING #ifdef RECORDING
Section::name = Section::Name::GAME; Section::name = Section::Name::GAME;
Section::options = Section::Options::GAME_PLAY_1P; Section::options = Section::Options::GAME_PLAY_1P;
@@ -73,15 +73,13 @@ Director::Director(int argc, const char *argv[])
init(); init();
} }
Director::~Director() Director::~Director() {
{
close(); close();
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\nBye!"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\nBye!");
} }
// Inicializa todo // Inicializa todo
void Director::init() void Director::init() {
{
// Configuración inicial de recursos // Configuración inicial de recursos
Asset::init(executable_path_); // Inicializa el sistema de gestión de archivos Asset::init(executable_path_); // Inicializa el sistema de gestión de archivos
setFileList(); // Crea el índice de archivos setFileList(); // Crea el índice de archivos
@@ -102,8 +100,7 @@ void Director::init()
} }
// Cierra todo y libera recursos del sistema y de los singletons // Cierra todo y libera recursos del sistema y de los singletons
void Director::close() void Director::close() {
{
// Guarda las opciones actuales en el archivo de configuración // Guarda las opciones actuales en el archivo de configuración
Options::saveToFile(); Options::saveToFile();
@@ -124,8 +121,7 @@ void Director::close()
} }
// Carga los parametros // Carga los parametros
void Director::loadParams() void Director::loadParams() {
{
// Carga los parametros para configurar el juego // Carga los parametros para configurar el juego
#ifdef ANBERNIC #ifdef ANBERNIC
const std::string paramFilePath = asset->get("param_320x240.txt"); const std::string paramFilePath = asset->get("param_320x240.txt");
@@ -136,26 +132,21 @@ void Director::loadParams()
} }
// Carga el fichero de puntuaciones // Carga el fichero de puntuaciones
void Director::loadScoreFile() void Director::loadScoreFile() {
{
auto manager = std::make_unique<ManageHiScoreTable>(Options::settings.hi_score_table); auto manager = std::make_unique<ManageHiScoreTable>(Options::settings.hi_score_table);
#ifdef DEBUG #ifdef DEBUG
manager->clear(); manager->clear();
#else #else
if (overrides.clear_hi_score_table) if (overrides.clear_hi_score_table) {
{
manager->clear(); manager->clear();
} } else {
else
{
manager->loadFromFile(Asset::get()->get("score.bin")); manager->loadFromFile(Asset::get()->get("score.bin"));
} }
#endif #endif
} }
// Asigna los botones y teclas al objeto Input // Asigna los botones y teclas al objeto Input
void Director::bindInputs() void Director::bindInputs() {
{
// Teclado - Movimiento del jugador // Teclado - Movimiento del jugador
Input::get()->bindKey(InputAction::UP, SDL_SCANCODE_UP); Input::get()->bindKey(InputAction::UP, SDL_SCANCODE_UP);
Input::get()->bindKey(InputAction::DOWN, SDL_SCANCODE_DOWN); Input::get()->bindKey(InputAction::DOWN, SDL_SCANCODE_DOWN);
@@ -196,8 +187,7 @@ void Director::bindInputs()
// Asigna botones a inputs // Asigna botones a inputs
const int NUM_GAMEPADS = Input::get()->getNumControllers(); const int NUM_GAMEPADS = Input::get()->getNumControllers();
for (int i = 0; i < NUM_GAMEPADS; ++i) for (int i = 0; i < NUM_GAMEPADS; ++i) {
{
// Mando - Movimiento del jugador // Mando - Movimiento del jugador
Input::get()->bindGameControllerButton(i, InputAction::UP, SDL_GAMEPAD_BUTTON_DPAD_UP); Input::get()->bindGameControllerButton(i, InputAction::UP, SDL_GAMEPAD_BUTTON_DPAD_UP);
Input::get()->bindGameControllerButton(i, InputAction::DOWN, SDL_GAMEPAD_BUTTON_DPAD_DOWN); Input::get()->bindGameControllerButton(i, InputAction::DOWN, SDL_GAMEPAD_BUTTON_DPAD_DOWN);
@@ -216,14 +206,10 @@ void Director::bindInputs()
// Mapea las asignaciones a los botones desde el archivo de configuración, si se da el caso // Mapea las asignaciones a los botones desde el archivo de configuración, si se da el caso
const size_t max_controllers = std::min(2, NUM_GAMEPADS); const size_t max_controllers = std::min(2, NUM_GAMEPADS);
for (size_t i = 0; i < max_controllers; ++i) for (size_t i = 0; i < max_controllers; ++i) {
{ for (auto &controller : Options::controllers) {
for (auto &controller : Options::controllers) if (Input::get()->getControllerName(i) == controller.name) {
{ for (size_t j = 0; j < controller.inputs.size(); ++j) {
if (Input::get()->getControllerName(i) == controller.name)
{
for (size_t j = 0; j < controller.inputs.size(); ++j)
{
Input::get()->bindGameControllerButton(i, controller.inputs.at(j), controller.buttons.at(j)); Input::get()->bindGameControllerButton(i, controller.inputs.at(j), controller.buttons.at(j));
} }
} }
@@ -231,37 +217,32 @@ void Director::bindInputs()
} }
// Asigna botones a inputs desde otros inputs // Asigna botones a inputs desde otros inputs
for (int i = 0; i < NUM_GAMEPADS; ++i) for (int i = 0; i < NUM_GAMEPADS; ++i) {
{
// Mando - Menu de servicio // Mando - Menu de servicio
Input::get()->bindGameControllerButton(i, InputAction::SM_SELECT, InputAction::FIRE_LEFT); Input::get()->bindGameControllerButton(i, InputAction::SM_SELECT, InputAction::FIRE_LEFT);
Input::get()->bindGameControllerButton(i, InputAction::SM_BACK, InputAction::FIRE_CENTER); Input::get()->bindGameControllerButton(i, InputAction::SM_BACK, InputAction::FIRE_CENTER);
} }
// Guarda las asignaciones de botones en las opciones de los dos primeros mandos // Guarda las asignaciones de botones en las opciones de los dos primeros mandos
for (size_t i = 0; i < max_controllers; ++i) for (size_t i = 0; i < max_controllers; ++i) {
{
// Variables asociadas al mando // Variables asociadas al mando
Options::controllers.at(i).index = i; Options::controllers.at(i).index = i;
Options::controllers.at(i).name = Input::get()->getControllerName(i); Options::controllers.at(i).name = Input::get()->getControllerName(i);
Options::controllers.at(i).plugged = true; Options::controllers.at(i).plugged = true;
// Asignaciones de botones // Asignaciones de botones
for (size_t j = 0; j < Options::controllers.at(i).inputs.size(); ++j) for (size_t j = 0; j < Options::controllers.at(i).inputs.size(); ++j) {
{
Options::controllers.at(i).buttons.at(j) = Input::get()->getControllerBinding(i, Options::controllers.at(i).inputs.at(j)); Options::controllers.at(i).buttons.at(j) = Input::get()->getControllerBinding(i, Options::controllers.at(i).inputs.at(j));
} }
} }
// Asegura que algún jugador tenga el teclado asignado // Asegura que algún jugador tenga el teclado asignado
if (Options::getPlayerWhoUsesKeyboard() == 0) if (Options::getPlayerWhoUsesKeyboard() == 0) {
{
Options::setKeyboardToPlayer(1); Options::setKeyboardToPlayer(1);
} }
} }
// Crea el indice de ficheros // Crea el indice de ficheros
void Director::setFileList() void Director::setFileList() {
{
#ifdef MACOS_BUNDLE #ifdef MACOS_BUNDLE
const std::string prefix = "/../Resources"; const std::string prefix = "/../Resources";
#else #else
@@ -447,37 +428,30 @@ void Director::setFileList()
Asset::get()->add(prefix + "/data/lang/ba_BA.json", AssetType::LANG); Asset::get()->add(prefix + "/data/lang/ba_BA.json", AssetType::LANG);
// Si falta algun fichero, sale del programa // Si falta algun fichero, sale del programa
if (!Asset::get()->check()) if (!Asset::get()->check()) {
{
throw std::runtime_error("Falta algun fichero"); throw std::runtime_error("Falta algun fichero");
} }
} }
// Comprueba los parametros del programa // Comprueba los parametros del programa
void Director::checkProgramArguments(int argc, const char *argv[]) void Director::checkProgramArguments(int argc, const char *argv[]) {
{
// Establece la ruta del programa // Establece la ruta del programa
executable_path_ = getPath(argv[0]); executable_path_ = getPath(argv[0]);
// Comprueba el resto de parámetros // Comprueba el resto de parámetros
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i) {
{
std::string arg = argv[i]; std::string arg = argv[i];
if (arg == "--320x240") if (arg == "--320x240") {
{
overrides.param_file = arg; overrides.param_file = arg;
} } else if (arg == "--clear_score") {
else if (arg == "--clear_score")
{
overrides.clear_hi_score_table = true; overrides.clear_hi_score_table = true;
} }
} }
} }
// Crea la carpeta del sistema donde guardar datos // Crea la carpeta del sistema donde guardar datos
void Director::createSystemFolder(const std::string &folder) void Director::createSystemFolder(const std::string &folder) {
{
#ifdef _WIN32 #ifdef _WIN32
system_folder_ = std::string(getenv("APPDATA")) + "/" + folder; system_folder_ = std::string(getenv("APPDATA")) + "/" + folder;
#elif __APPLE__ #elif __APPLE__
@@ -493,8 +467,7 @@ void Director::createSystemFolder(const std::string &folder)
// Intenta crear ".config", per si no existeix // Intenta crear ".config", per si no existeix
std::string config_base_folder = std::string(homedir) + "/.config"; std::string config_base_folder = std::string(homedir) + "/.config";
int ret = mkdir(config_base_folder.c_str(), S_IRWXU); int ret = mkdir(config_base_folder.c_str(), S_IRWXU);
if (ret == -1 && errno != EEXIST) if (ret == -1 && errno != EEXIST) {
{
printf("ERROR CREATING CONFIG BASE FOLDER."); printf("ERROR CREATING CONFIG BASE FOLDER.");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -502,8 +475,7 @@ void Director::createSystemFolder(const std::string &folder)
#endif #endif
struct stat st = {0}; struct stat st = {0};
if (stat(system_folder_.c_str(), &st) == -1) if (stat(system_folder_.c_str(), &st) == -1) {
{
errno = 0; errno = 0;
#ifdef _WIN32 #ifdef _WIN32
int ret = mkdir(system_folder_.c_str()); int ret = mkdir(system_folder_.c_str());
@@ -511,10 +483,8 @@ void Director::createSystemFolder(const std::string &folder)
int ret = mkdir(system_folder_.c_str(), S_IRWXU); int ret = mkdir(system_folder_.c_str(), S_IRWXU);
#endif #endif
if (ret == -1) if (ret == -1) {
{ switch (errno) {
switch (errno)
{
case EACCES: case EACCES:
printf("the parent directory does not allow write"); printf("the parent directory does not allow write");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@@ -536,33 +506,28 @@ void Director::createSystemFolder(const std::string &folder)
} }
// Ejecuta la sección con el logo // Ejecuta la sección con el logo
void Director::runLogo() void Director::runLogo() {
{
auto logo = std::make_unique<Logo>(); auto logo = std::make_unique<Logo>();
logo->run(); logo->run();
} }
// Ejecuta la sección con la secuencia de introducción // Ejecuta la sección con la secuencia de introducción
void Director::runIntro() void Director::runIntro() {
{
auto intro = std::make_unique<Intro>(); auto intro = std::make_unique<Intro>();
intro->run(); intro->run();
} }
// Ejecuta la sección con el título del juego // Ejecuta la sección con el título del juego
void Director::runTitle() void Director::runTitle() {
{
auto title = std::make_unique<Title>(); auto title = std::make_unique<Title>();
title->run(); title->run();
} }
// Ejecuta la sección donde se juega al juego // Ejecuta la sección donde se juega al juego
void Director::runGame() void Director::runGame() {
{
int player_id = 1; int player_id = 1;
switch (Section::options) switch (Section::options) {
{
case Section::Options::GAME_PLAY_1P: case Section::Options::GAME_PLAY_1P:
player_id = 1; player_id = 1;
break; break;
@@ -590,29 +555,25 @@ void Director::runGame()
} }
// Ejecuta la sección donde se muestran las instrucciones // Ejecuta la sección donde se muestran las instrucciones
void Director::runInstructions() void Director::runInstructions() {
{
auto instructions = std::make_unique<Instructions>(); auto instructions = std::make_unique<Instructions>();
instructions->run(); instructions->run();
} }
// Ejecuta la sección donde se muestran los creditos del programa // Ejecuta la sección donde se muestran los creditos del programa
void Director::runCredits() void Director::runCredits() {
{
auto credits = std::make_unique<Credits>(); auto credits = std::make_unique<Credits>();
credits->run(); credits->run();
} }
// Ejecuta la sección donde se muestra la tabla de puntuaciones // Ejecuta la sección donde se muestra la tabla de puntuaciones
void Director::runHiScoreTable() void Director::runHiScoreTable() {
{
auto hi_score_table = std::make_unique<HiScoreTable>(); auto hi_score_table = std::make_unique<HiScoreTable>();
hi_score_table->run(); hi_score_table->run();
} }
// Ejecuta el juego en modo demo // Ejecuta el juego en modo demo
void Director::runDemoGame() void Director::runDemoGame() {
{
const auto PLAYER_ID = (rand() % 2) + 1; const auto PLAYER_ID = (rand() % 2) + 1;
constexpr auto CURRENT_STAGE = 0; constexpr auto CURRENT_STAGE = 0;
auto game = std::make_unique<Game>(PLAYER_ID, CURRENT_STAGE, GAME_MODE_DEMO_ON); auto game = std::make_unique<Game>(PLAYER_ID, CURRENT_STAGE, GAME_MODE_DEMO_ON);
@@ -620,15 +581,13 @@ void Director::runDemoGame()
} }
// Reinicia objetos y vuelve a la sección inicial // Reinicia objetos y vuelve a la sección inicial
void Director::reset() void Director::reset() {
{
Options::saveToFile(); Options::saveToFile();
Options::loadFromFile(); Options::loadFromFile();
Lang::setLanguage(Options::settings.language); Lang::setLanguage(Options::settings.language);
Audio::get()->stopMusic(); Audio::get()->stopMusic();
Audio::get()->stopAllSounds(); Audio::get()->stopAllSounds();
if (Section::options == Section::Options::RELOAD || true) if (Section::options == Section::Options::RELOAD || true) {
{
Resource::get()->reload(); Resource::get()->reload();
} }
Input::get()->discoverGameControllers(); Input::get()->discoverGameControllers();
@@ -637,13 +596,10 @@ void Director::reset()
Section::name = Section::Name::LOGO; Section::name = Section::Name::LOGO;
} }
int Director::run() int Director::run() {
{
// Bucle principal // Bucle principal
while (Section::name != Section::Name::QUIT) while (Section::name != Section::Name::QUIT) {
{ switch (Section::name) {
switch (Section::name)
{
case Section::Name::RESET: case Section::Name::RESET:
reset(); reset();
break; break;
@@ -680,10 +636,8 @@ int Director::run()
} }
// Apaga el sistema // Apaga el sistema
void Director::shutdownSystem(bool should_shutdown) void Director::shutdownSystem(bool should_shutdown) {
{ if (should_shutdown) {
if (should_shutdown)
{
#ifdef _WIN32 #ifdef _WIN32
// Apaga el sistema en Windows // Apaga el sistema en Windows
system("shutdown /s /t 5"); system("shutdown /s /t 5");

View File

@@ -2,14 +2,12 @@
#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();
@@ -17,7 +15,7 @@ public:
// --- 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

View File

@@ -2,6 +2,7 @@
#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 <string_view> // Para basic_string_view, string_view
#include "utils.h" // Para trim #include "utils.h" // Para trim
@@ -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;

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <array> // Para array #include <array> // Para array
#include <string> // Para string, basic_string #include <string> // Para string, basic_string
@@ -10,9 +11,8 @@
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;
@@ -29,7 +29,7 @@ public:
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

View File

@@ -5,10 +5,8 @@
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;
} }
} }

View File

@@ -9,8 +9,7 @@
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
@@ -20,9 +19,8 @@ struct ExplosionTexture
}; };
// 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_;

View File

@@ -1,22 +1,19 @@
#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); std::memcpy(dst, buffer, size);
buffer += size; buffer += size;
} }
void Gif::decompress(int code_length, const uint8_t *input, int input_length, uint8_t *out) void Gif::decompress(int code_length, const uint8_t *input, int input_length, uint8_t *out) {
{ if (code_length < 2 || code_length > 12) {
if (code_length < 2 || code_length > 12)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid LZW code length: %d", code_length); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Invalid LZW code length: %d", code_length);
throw std::runtime_error("Invalid LZW code length"); throw std::runtime_error("Invalid LZW code length");
} }
@@ -32,28 +29,23 @@ namespace GIF
int match_len = 0; int match_len = 0;
dictionary.resize(1 << (code_length + 1)); dictionary.resize(1 << (code_length + 1));
for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) {
{
dictionary[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind); dictionary[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind);
dictionary[dictionary_ind].prev = -1; dictionary[dictionary_ind].prev = -1;
dictionary[dictionary_ind].len = 1; dictionary[dictionary_ind].len = 1;
} }
dictionary_ind += 2; dictionary_ind += 2;
while (input_length > 0) while (input_length > 0) {
{
int code = 0; int code = 0;
for (i = 0; i < (code_length + 1); i++) for (i = 0; i < (code_length + 1); i++) {
{ if (input_length <= 0) {
if (input_length <= 0)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unexpected end of input in decompress"); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unexpected end of input in decompress");
throw std::runtime_error("Unexpected end of input in decompress"); throw std::runtime_error("Unexpected end of input in decompress");
} }
bit = ((*input & mask) != 0) ? 1 : 0; bit = ((*input & mask) != 0) ? 1 : 0;
mask <<= 1; mask <<= 1;
if (mask == 0x100) if (mask == 0x100) {
{
mask = 0x01; mask = 0x01;
input++; input++;
input_length--; input_length--;
@@ -61,12 +53,10 @@ namespace GIF
code |= (bit << i); code |= (bit << i);
} }
if (code == clear_code) if (code == clear_code) {
{
code_length = reset_code_length; code_length = reset_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++) for (dictionary_ind = 0; dictionary_ind < (1 << code_length); dictionary_ind++) {
{
dictionary[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind); dictionary[dictionary_ind].byte = static_cast<uint8_t>(dictionary_ind);
dictionary[dictionary_ind].prev = -1; dictionary[dictionary_ind].prev = -1;
dictionary[dictionary_ind].len = 1; dictionary[dictionary_ind].len = 1;
@@ -74,30 +64,23 @@ namespace GIF
dictionary_ind += 2; dictionary_ind += 2;
prev = -1; prev = -1;
continue; continue;
} } else if (code == stop_code) {
else if (code == stop_code)
{
break; break;
} }
if (prev > -1 && code_length < 12) if (prev > -1 && code_length < 12) {
{ if (code > dictionary_ind) {
if (code > dictionary_ind)
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "LZW error: code (%d) exceeds dictionary_ind (%d)", 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."); throw std::runtime_error("LZW error: code exceeds dictionary_ind.");
} }
int ptr; int ptr;
if (code == dictionary_ind) if (code == dictionary_ind) {
{
ptr = prev; ptr = prev;
while (dictionary[ptr].prev != -1) while (dictionary[ptr].prev != -1)
ptr = dictionary[ptr].prev; ptr = dictionary[ptr].prev;
dictionary[dictionary_ind].byte = dictionary[ptr].byte; dictionary[dictionary_ind].byte = dictionary[ptr].byte;
} } else {
else
{
ptr = code; ptr = code;
while (dictionary[ptr].prev != -1) while (dictionary[ptr].prev != -1)
ptr = dictionary[ptr].prev; ptr = dictionary[ptr].prev;
@@ -107,8 +90,7 @@ namespace GIF
dictionary[dictionary_ind].len = dictionary[prev].len + 1; dictionary[dictionary_ind].len = dictionary[prev].len + 1;
dictionary_ind++; dictionary_ind++;
if ((dictionary_ind == (1 << (code_length + 1))) && (code_length < 11)) if ((dictionary_ind == (1 << (code_length + 1))) && (code_length < 11)) {
{
code_length++; code_length++;
dictionary.resize(1 << (code_length + 1)); dictionary.resize(1 << (code_length + 1));
} }
@@ -116,19 +98,16 @@ namespace GIF
prev = code; prev = code;
if (code < 0 || static_cast<size_t>(code) >= dictionary.size()) 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())); 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"); throw std::runtime_error("LZW error: invalid code encountered");
} }
int curCode = code; int curCode = code;
match_len = dictionary[curCode].len; match_len = dictionary[curCode].len;
while (curCode != -1) while (curCode != -1) {
{
out[dictionary[curCode].len - 1] = dictionary[curCode].byte; out[dictionary[curCode].len - 1] = dictionary[curCode].byte;
if (dictionary[curCode].prev == curCode) if (dictionary[curCode].prev == curCode) {
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Internal error; self-reference detected."); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Internal error; self-reference detected.");
throw std::runtime_error("Internal error in decompress: self-reference"); throw std::runtime_error("Internal error in decompress: self-reference");
} }
@@ -136,25 +115,22 @@ namespace GIF
} }
out += match_len; out += match_len;
} }
} }
std::vector<uint8_t> Gif::readSubBlocks(const uint8_t *&buffer) std::vector<uint8_t> Gif::readSubBlocks(const uint8_t *&buffer) {
{
std::vector<uint8_t> data; std::vector<uint8_t> data;
uint8_t block_size = *buffer; uint8_t block_size = *buffer;
buffer++; buffer++;
while (block_size != 0) while (block_size != 0) {
{
data.insert(data.end(), buffer, buffer + block_size); data.insert(data.end(), buffer, buffer + block_size);
buffer += block_size; buffer += block_size;
block_size = *buffer; block_size = *buffer;
buffer++; buffer++;
} }
return data; return data;
} }
std::vector<uint8_t> Gif::processImageDescriptor(const uint8_t *&buffer, const std::vector<RGB> &gct, int resolution_bits) std::vector<uint8_t> Gif::processImageDescriptor(const uint8_t *&buffer, const std::vector<RGB> &gct, int resolution_bits) {
{
ImageDescriptor image_descriptor; ImageDescriptor image_descriptor;
readBytes(buffer, &image_descriptor, sizeof(ImageDescriptor)); readBytes(buffer, &image_descriptor, sizeof(ImageDescriptor));
@@ -167,10 +143,9 @@ namespace GIF
decompress(lzw_code_size, compressed_data.data(), static_cast<int>(compressed_data.size()), uncompressed_data.data()); decompress(lzw_code_size, compressed_data.data(), static_cast<int>(compressed_data.size()), uncompressed_data.data());
return uncompressed_data; return uncompressed_data;
} }
std::vector<uint32_t> Gif::loadPalette(const uint8_t *buffer) std::vector<uint32_t> Gif::loadPalette(const uint8_t *buffer) {
{
uint8_t header[6]; uint8_t header[6];
std::memcpy(header, buffer, 6); std::memcpy(header, buffer, 6);
buffer += 6; buffer += 6;
@@ -180,12 +155,10 @@ namespace GIF
buffer += sizeof(ScreenDescriptor); buffer += sizeof(ScreenDescriptor);
std::vector<uint32_t> global_color_table; std::vector<uint32_t> global_color_table;
if (screen_descriptor.fields & 0x80) if (screen_descriptor.fields & 0x80) {
{
int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1)); int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1));
global_color_table.resize(global_color_table_size); global_color_table.resize(global_color_table_size);
for (int i = 0; i < global_color_table_size; ++i) for (int i = 0; i < global_color_table_size; ++i) {
{
uint8_t r = buffer[0]; uint8_t r = buffer[0];
uint8_t g = buffer[1]; uint8_t g = buffer[1];
uint8_t b = buffer[2]; uint8_t b = buffer[2];
@@ -194,17 +167,15 @@ namespace GIF
} }
} }
return global_color_table; return global_color_table;
} }
std::vector<uint8_t> Gif::processGifStream(const uint8_t *buffer, uint16_t &w, uint16_t &h) std::vector<uint8_t> Gif::processGifStream(const uint8_t *buffer, uint16_t &w, uint16_t &h) {
{
uint8_t header[6]; uint8_t header[6];
std::memcpy(header, buffer, 6); std::memcpy(header, buffer, 6);
buffer += 6; buffer += 6;
std::string headerStr(reinterpret_cast<char *>(header), 6); std::string headerStr(reinterpret_cast<char *>(header), 6);
if (headerStr != "GIF87a" && headerStr != "GIF89a") if (headerStr != "GIF87a" && headerStr != "GIF89a") {
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Formato de archivo GIF inválido: %s", headerStr.c_str()); 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."); throw std::runtime_error("Formato de archivo GIF inválido.");
} }
@@ -221,8 +192,7 @@ namespace GIF
int color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1; int color_resolution_bits = ((screen_descriptor.fields & 0x70) >> 4) + 1;
std::vector<RGB> global_color_table; std::vector<RGB> global_color_table;
if (screen_descriptor.fields & 0x80) if (screen_descriptor.fields & 0x80) {
{
int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1)); int global_color_table_size = 1 << (((screen_descriptor.fields & 0x07) + 1));
global_color_table.resize(global_color_table_size); global_color_table.resize(global_color_table_size);
std::memcpy(global_color_table.data(), buffer, 3 * global_color_table_size); std::memcpy(global_color_table.data(), buffer, 3 * global_color_table_size);
@@ -230,20 +200,15 @@ namespace GIF
} }
uint8_t block_type = *buffer++; uint8_t block_type = *buffer++;
while (block_type != TRAILER) while (block_type != TRAILER) {
{ if (block_type == EXTENSION_INTRODUCER) {
if (block_type == EXTENSION_INTRODUCER)
{
uint8_t extension_label = *buffer++; uint8_t extension_label = *buffer++;
switch (extension_label) switch (extension_label) {
{ case GRAPHIC_CONTROL: {
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,38 +216,30 @@ 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 {
else
{
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Unrecognized block type: 0x%X", block_type); SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Unrecognized block type: 0x%X", block_type);
return std::vector<uint8_t>{}; return std::vector<uint8_t>{};
} }
@@ -291,11 +248,10 @@ namespace GIF
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "GIF procesado correctamente."); SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "GIF procesado correctamente.");
return std::vector<uint8_t>{}; return std::vector<uint8_t>{};
} }
std::vector<uint8_t> Gif::loadGif(const uint8_t *buffer, uint16_t &w, uint16_t &h) std::vector<uint8_t> Gif::loadGif(const uint8_t *buffer, uint16_t &w, uint16_t &h) {
{
return processGifStream(buffer, w, h); return processGifStream(buffer, w, h);
} }
} // namespace GIF } // namespace GIF

64
source/external/gif.h vendored
View File

@@ -3,78 +3,68 @@
#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.
@@ -97,6 +87,6 @@ namespace GIF
// 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

View File

@@ -12,15 +12,13 @@
#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;

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,

View File

@@ -2,6 +2,7 @@
#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
@@ -19,41 +20,39 @@
#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");
@@ -73,33 +72,30 @@ namespace shader
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, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Error OpenGL en %s: 0x%x", operation, error); "Error OpenGL en %s: 0x%x",
} operation,
error);
} }
}
// Función para compilar un shader a partir de un std::string // Función para compilar un shader a partir de un std::string
GLuint compileShader(const std::string &source, GLuint shader_type) GLuint compileShader(const std::string &source, GLuint shader_type) {
{ if (source.empty()) {
if (source.empty())
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR FATAL: El código fuente del shader está vacío."); 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."); throw std::runtime_error("ERROR FATAL: El código fuente del shader está vacío.");
} }
// Crear identificador del shader // Crear identificador del shader
GLuint shader_id = glCreateShader(shader_type); GLuint shader_id = glCreateShader(shader_type);
if (shader_id == INVALID_SHADER_ID) if (shader_id == INVALID_SHADER_ID) {
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al crear el shader."); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al crear el shader.");
checkGLError("glCreateShader"); checkGLError("glCreateShader");
return INVALID_SHADER_ID; return INVALID_SHADER_ID;
@@ -123,13 +119,11 @@ namespace shader
// Verificar si la compilación fue exitosa // Verificar si la compilación fue exitosa
GLint compiled_ok = GL_FALSE; GLint compiled_ok = GL_FALSE;
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &compiled_ok); glGetShaderiv(shader_id, GL_COMPILE_STATUS, &compiled_ok);
if (compiled_ok != GL_TRUE) if (compiled_ok != GL_TRUE) {
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error en la compilación del shader (%d)!", shader_id); 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); glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0) if (log_length > 0) {
{
std::vector<GLchar> log(log_length); std::vector<GLchar> log(log_length);
glGetShaderInfoLog(shader_id, log_length, &log_length, log.data()); glGetShaderInfoLog(shader_id, log_length, &log_length, log.data());
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Registro de compilación del shader: %s", log.data()); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Registro de compilación del shader: %s", log.data());
@@ -138,14 +132,12 @@ namespace shader
return INVALID_SHADER_ID; return INVALID_SHADER_ID;
} }
return shader_id; return shader_id;
} }
// Función para compilar un programa de shaders (vertex y fragment) a partir de std::string // 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 compileProgram(const std::string &vertex_shader_source, const std::string &fragment_shader_source) {
{
GLuint program_id = glCreateProgram(); GLuint program_id = glCreateProgram();
if (program_id == INVALID_PROGRAM_ID) if (program_id == INVALID_PROGRAM_ID) {
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al crear el programa de shaders."); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al crear el programa de shaders.");
checkGLError("glCreateProgram"); checkGLError("glCreateProgram");
return INVALID_PROGRAM_ID; return INVALID_PROGRAM_ID;
@@ -155,8 +147,7 @@ namespace shader
GLuint vertex_shader_id = compileShader(vertex_shader_source, GL_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); 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) if (vertex_shader_id != INVALID_SHADER_ID && fragment_shader_id != INVALID_SHADER_ID) {
{
// Asociar los shaders al programa // Asociar los shaders al programa
glAttachShader(program_id, vertex_shader_id); glAttachShader(program_id, vertex_shader_id);
checkGLError("glAttachShader vertex"); checkGLError("glAttachShader vertex");
@@ -169,22 +160,18 @@ namespace shader
// Verificar el estado del enlace // Verificar el estado del enlace
GLint isLinked = GL_FALSE; GLint isLinked = GL_FALSE;
glGetProgramiv(program_id, GL_LINK_STATUS, &isLinked); glGetProgramiv(program_id, GL_LINK_STATUS, &isLinked);
if (isLinked == GL_FALSE) if (isLinked == GL_FALSE) {
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al enlazar el programa de shaders."); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al enlazar el programa de shaders.");
GLint log_length; GLint log_length;
glGetProgramiv(program_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<char> log(log_length);
glGetProgramInfoLog(program_id, log_length, &log_length, log.data()); glGetProgramInfoLog(program_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 enlace del programa: %s", log.data());
} }
glDeleteProgram(program_id); glDeleteProgram(program_id);
program_id = INVALID_PROGRAM_ID; program_id = INVALID_PROGRAM_ID;
} } else {
else
{
glValidateProgram(program_id); glValidateProgram(program_id);
checkGLError("glValidateProgram"); checkGLError("glValidateProgram");
@@ -198,30 +185,25 @@ namespace shader
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Registro de información del programa:\n%s", log.data()); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Registro de información del programa:\n%s", log.data());
} }
} }
} } else {
else
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudieron compilar los shaders."); 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;
} }
// Limpiar los shaders (ya no son necesarios después del enlace) // Limpiar los shaders (ya no son necesarios después del enlace)
if (vertex_shader_id != INVALID_SHADER_ID) if (vertex_shader_id != INVALID_SHADER_ID) {
{
glDeleteShader(vertex_shader_id); glDeleteShader(vertex_shader_id);
} }
if (fragment_shader_id != INVALID_SHADER_ID) if (fragment_shader_id != INVALID_SHADER_ID) {
{
glDeleteShader(fragment_shader_id); glDeleteShader(fragment_shader_id);
} }
return program_id; return program_id;
} }
// Función para obtener el ID de textura OpenGL desde SDL3 // Función para obtener el ID de textura OpenGL desde SDL3
GLuint getTextureID(SDL_Texture *texture) GLuint getTextureID(SDL_Texture *texture) {
{
if (!texture) if (!texture)
return DEFAULT_TEXTURE_ID; return DEFAULT_TEXTURE_ID;
@@ -233,36 +215,32 @@ namespace shader
textureId = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "SDL.texture.opengl.texture", nullptr); textureId = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "SDL.texture.opengl.texture", nullptr);
// Si la primera no funciona, intentar con el nombre alternativo // Si la primera no funciona, intentar con el nombre alternativo
if (textureId == 0) if (textureId == 0) {
{
textureId = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "texture.opengl.texture", nullptr); textureId = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "texture.opengl.texture", nullptr);
} }
// Si aún no funciona, intentar obtener como número // Si aún no funciona, intentar obtener como número
if (textureId == 0) if (textureId == 0) {
{
textureId = (GLuint)SDL_GetNumberProperty(props, "SDL.texture.opengl.texture", DEFAULT_TEXTURE_ID); textureId = (GLuint)SDL_GetNumberProperty(props, "SDL.texture.opengl.texture", DEFAULT_TEXTURE_ID);
} }
// Si ninguna funciona, usar el método manual de bindeo de textura // Si ninguna funciona, usar el método manual de bindeo de textura
if (textureId == 0) if (textureId == 0) {
{
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"No se pudo obtener el ID de textura OpenGL, usando ID por defecto (%d)", DEFAULT_TEXTURE_ID); "No se pudo obtener el ID de textura OpenGL, usando ID por defecto (%d)",
DEFAULT_TEXTURE_ID);
textureId = DEFAULT_TEXTURE_ID; textureId = DEFAULT_TEXTURE_ID;
} }
return textureId; return textureId;
} }
bool init(SDL_Window *window, SDL_Texture *back_buffer_texture, const std::string &vertex_shader, const std::string &fragment_shader) bool init(SDL_Window *window, SDL_Texture *back_buffer_texture, const std::string &vertex_shader, const std::string &fragment_shader) {
{
shader::win = window; shader::win = window;
shader::renderer = SDL_GetRenderer(window); shader::renderer = SDL_GetRenderer(window);
shader::backBuffer = back_buffer_texture; shader::backBuffer = back_buffer_texture;
if (!shader::renderer) if (!shader::renderer) {
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo obtener el renderer de la ventana."); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo obtener el renderer de la ventana.");
return false; return false;
} }
@@ -271,18 +249,15 @@ namespace shader
SDL_GetTextureSize(back_buffer_texture, &tex_size.x, &tex_size.y); SDL_GetTextureSize(back_buffer_texture, &tex_size.x, &tex_size.y);
const auto render_name = SDL_GetRendererName(renderer); const auto render_name = SDL_GetRendererName(renderer);
if (!render_name) if (!render_name) {
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo obtener el nombre del renderer."); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo obtener el nombre del renderer.");
return false; return false;
} }
// Verificar que el renderer sea OpenGL // Verificar que el renderer sea OpenGL
if (!strncmp(render_name, "opengl", 6)) 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; usingOpenGL = false;
return false; return false;
@@ -290,15 +265,12 @@ namespace shader
#endif #endif
// Compilar el programa de shaders utilizando std::string // Compilar el programa de shaders utilizando std::string
programId = compileProgram(vertex_shader, fragment_shader); programId = compileProgram(vertex_shader, fragment_shader);
if (programId == INVALID_PROGRAM_ID) if (programId == INVALID_PROGRAM_ID) {
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR: No se pudo compilar el programa de shaders."); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR: No se pudo compilar el programa de shaders.");
usingOpenGL = false; usingOpenGL = false;
return false; return false;
} }
} } else {
else
{
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "ADVERTENCIA: El driver del renderer no es OpenGL (%s).", render_name); 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;
@@ -307,17 +279,15 @@ namespace shader
usingOpenGL = true; usingOpenGL = true;
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Shader system initialized successfully."); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Shader system initialized successfully.");
return true; return true;
} }
void render() void render() {
{
// Establece el color de fondo // Establece el color de fondo
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_SetRenderTarget(renderer, nullptr); SDL_SetRenderTarget(renderer, nullptr);
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
if (usingOpenGL && programId != INVALID_PROGRAM_ID) if (usingOpenGL && programId != INVALID_PROGRAM_ID) {
{
// Guardar estados de OpenGL // Guardar estados de OpenGL
GLint oldProgramId; GLint oldProgramId;
glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgramId); glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgramId);
@@ -343,8 +313,7 @@ namespace shader
int logicalW, logicalH; int logicalW, logicalH;
SDL_RendererLogicalPresentation mode; SDL_RendererLogicalPresentation mode;
SDL_GetRenderLogicalPresentation(renderer, &logicalW, &logicalH, &mode); SDL_GetRenderLogicalPresentation(renderer, &logicalW, &logicalH, &mode);
if (logicalW == 0 || logicalH == 0) if (logicalW == 0 || logicalH == 0) {
{
logicalW = win_size.x; logicalW = win_size.x;
logicalH = win_size.y; logicalH = win_size.y;
} }
@@ -352,33 +321,26 @@ namespace shader
// Cálculo del viewport // Cálculo del viewport
int viewportX = 0, viewportY = 0, viewportW = win_size.x, viewportH = win_size.y; int viewportX = 0, viewportY = 0, viewportW = win_size.x, viewportH = win_size.y;
const bool USE_INTEGER_SCALE = mode == SDL_LOGICAL_PRESENTATION_INTEGER_SCALE; const bool USE_INTEGER_SCALE = mode == SDL_LOGICAL_PRESENTATION_INTEGER_SCALE;
if (USE_INTEGER_SCALE) if (USE_INTEGER_SCALE) {
{
// Calcula el factor de escalado entero máximo que se puede aplicar // Calcula el factor de escalado entero máximo que se puede aplicar
int scaleX = win_size.x / logicalW; int scaleX = win_size.x / logicalW;
int scaleY = win_size.y / logicalH; int scaleY = win_size.y / logicalH;
int scale = (scaleX < scaleY ? scaleX : scaleY); int scale = (scaleX < scaleY ? scaleX : scaleY);
if (scale < 1) if (scale < 1) {
{
scale = 1; scale = 1;
} }
viewportW = logicalW * scale; viewportW = logicalW * scale;
viewportH = logicalH * scale; viewportH = logicalH * scale;
viewportX = (win_size.x - viewportW) / 2; viewportX = (win_size.x - viewportW) / 2;
viewportY = (win_size.y - viewportH) / 2; viewportY = (win_size.y - viewportH) / 2;
} } else {
else
{
// Letterboxing: preserva la relación de aspecto usando una escala flotante // Letterboxing: preserva la relación de aspecto usando una escala flotante
float windowAspect = static_cast<float>(win_size.x) / win_size.y; float windowAspect = static_cast<float>(win_size.x) / win_size.y;
float logicalAspect = static_cast<float>(logicalW) / logicalH; float logicalAspect = static_cast<float>(logicalW) / logicalH;
if (windowAspect > logicalAspect) if (windowAspect > logicalAspect) {
{
viewportW = static_cast<int>(logicalAspect * win_size.y); viewportW = static_cast<int>(logicalAspect * win_size.y);
viewportX = (win_size.x - viewportW) / 2; viewportX = (win_size.x - viewportW) / 2;
} } else {
else
{
viewportH = static_cast<int>(win_size.x / logicalAspect); viewportH = static_cast<int>(win_size.x / logicalAspect);
viewportY = (win_size.y - viewportH) / 2; viewportY = (win_size.y - viewportH) / 2;
} }
@@ -419,24 +381,19 @@ namespace shader
// Restaurar estados de OpenGL // Restaurar estados de OpenGL
glUseProgram(oldProgramId); glUseProgram(oldProgramId);
glBindTexture(GL_TEXTURE_2D, oldTextureId); glBindTexture(GL_TEXTURE_2D, oldTextureId);
if (!wasTextureEnabled) if (!wasTextureEnabled) {
{
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
} }
glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]); glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
} } else {
else
{
// Fallback a renderizado normal de SDL // Fallback a renderizado normal de SDL
SDL_RenderTexture(renderer, backBuffer, nullptr, nullptr); SDL_RenderTexture(renderer, backBuffer, nullptr, nullptr);
SDL_RenderPresent(renderer); SDL_RenderPresent(renderer);
} }
} }
void cleanup() void cleanup() {
{ if (programId != INVALID_PROGRAM_ID) {
if (programId != INVALID_PROGRAM_ID)
{
glDeleteProgram(programId); glDeleteProgram(programId);
programId = INVALID_PROGRAM_ID; programId = INVALID_PROGRAM_ID;
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Programa de shaders liberado."); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Programa de shaders liberado.");
@@ -447,15 +404,13 @@ namespace shader
renderer = nullptr; renderer = nullptr;
backBuffer = nullptr; backBuffer = nullptr;
usingOpenGL = false; usingOpenGL = false;
}
bool isUsingOpenGL()
{
return usingOpenGL;
}
GLuint getProgramId()
{
return programId;
}
} }
bool isUsingOpenGL() {
return usingOpenGL;
}
GLuint getProgramId() {
return programId;
}
} // namespace shader

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 #include <string> // Para basic_string, string
namespace shader namespace shader {
{ bool init(SDL_Window *ventana, SDL_Texture *texturaBackBuffer, const std::string &vertexShader, const std::string &fragmentShader = "");
bool init(SDL_Window *ventana, SDL_Texture *texturaBackBuffer, const std::string &vertexShader, const std::string &fragmentShader = ""); void render();
void render(); } // namespace shader
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@
#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
@@ -10,8 +11,7 @@
// 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);
@@ -21,14 +21,12 @@ Fade::Fade()
} }
// 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;
@@ -47,67 +45,53 @@ void Fade::init()
} }
// 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 // Actualiza el contador
if (pre_counter_ == pre_duration_) if (pre_counter_ == pre_duration_) {
{
state_ = FadeState::FADING; state_ = FadeState::FADING;
} } else {
else
{
pre_counter_++; pre_counter_++;
} }
} }
if (state_ == FadeState::FADING) if (state_ == FadeState::FADING) {
{ switch (type_) {
switch (type_) case FadeType::FULLSCREEN: {
{
case FadeType::FULLSCREEN:
{
// Modifica la transparencia // Modifica la transparencia
a_ = mode_ == FadeMode::OUT ? std::min(counter_ * 4, 255) : 255 - std::min(counter_ * 4, 255); 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);
@@ -121,18 +105,15 @@ void Fade::update()
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 // Cambia el renderizador al backbuffer_ y modifica sus opciones
auto temp = SDL_GetRenderTarget(renderer_); auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_); SDL_SetRenderTarget(renderer_, backbuffer_);
@@ -143,8 +124,7 @@ void Fade::update()
// 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]);
} }
@@ -157,19 +137,16 @@ void Fade::update()
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_ // Dibuja sobre el backbuffer_
auto temp = SDL_GetRenderTarget(renderer_); auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_); SDL_SetRenderTarget(renderer_, backbuffer_);
@@ -179,8 +156,7 @@ void Fade::update()
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_); 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);
} }
@@ -190,24 +166,19 @@ void Fade::update()
// 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); value_ = calculateValue(0, square_.size() - 1, completed);
} } else {
else
{
state_ = FadeState::POST; state_ = FadeState::POST;
} }
@@ -219,15 +190,11 @@ void Fade::update()
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; state_ = FadeState::FINISHED;
} } else {
else
{
post_counter_++; post_counter_++;
} }
@@ -237,11 +204,9 @@ void Fade::update()
} }
// 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;
} }
@@ -250,31 +215,26 @@ void Fade::activate()
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 // Pinta el backbuffer_ de color sólido
cleanBackbuffer(r_, g_, b_, 255); cleanBackbuffer(r_, g_, b_, 255);
break; 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_);
@@ -282,8 +242,7 @@ void Fade::activate()
// 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];
@@ -301,8 +260,7 @@ void Fade::activate()
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_);
@@ -315,8 +273,7 @@ void Fade::activate()
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_);
} }
@@ -327,24 +284,21 @@ void Fade::activate()
} }
// 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_);
@@ -358,15 +312,12 @@ void Fade::cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
} }
// 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;
} }

View File

@@ -1,13 +1,13 @@
#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,
@@ -15,15 +15,13 @@ enum class FadeType : Uint8
}; };
// 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,
@@ -31,9 +29,8 @@ enum class FadeState : Uint8
FINISHED = 4, FINISHED = 4,
}; };
class Fade class Fade {
{ public:
public:
// --- Constructores y destructor --- // --- Constructores y destructor ---
Fade(); Fade();
~Fade(); ~Fade();
@@ -57,7 +54,7 @@ public:
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

View File

@@ -1,6 +1,7 @@
#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
@@ -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,18 +112,14 @@ 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: {
{
case Status::MOVING:
{
coffee_sprite_->update(); coffee_sprite_->update();
crisis_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
@@ -137,26 +131,19 @@ void GameLogo::update()
break; break;
} }
case Status::SHAKING: case Status::SHAKING: {
{
// Agita "COFFEE CRISIS" // Agita "COFFEE CRISIS"
if (shake_.remaining > 0) if (shake_.remaining > 0) {
{ if (shake_.counter > 0) {
if (shake_.counter > 0)
{
shake_.counter--; shake_.counter--;
} } else {
else
{
shake_.counter = shake_.delay; shake_.counter = shake_.delay;
const auto desp = shake_.remaining % 2 == 0 ? shake_.desp * (-1) : shake_.desp; const auto desp = shake_.remaining % 2 == 0 ? shake_.desp * (-1) : shake_.desp;
coffee_sprite_->setPosX(shake_.origin + desp); coffee_sprite_->setPosX(shake_.origin + desp);
crisis_sprite_->setPosX(shake_.origin + desp + 15); crisis_sprite_->setPosX(shake_.origin + desp + 15);
shake_.remaining--; shake_.remaining--;
} }
} } else {
else
{
coffee_sprite_->setPosX(shake_.origin); coffee_sprite_->setPosX(shake_.origin);
crisis_sprite_->setPosX(shake_.origin + 15); crisis_sprite_->setPosX(shake_.origin + 15);
coffee_crisis_status_ = Status::FINISHED; coffee_crisis_status_ = Status::FINISHED;
@@ -169,8 +156,7 @@ void GameLogo::update()
break; break;
} }
case Status::FINISHED: case Status::FINISHED: {
{
dust_right_sprite_->update(); dust_right_sprite_->update();
dust_left_sprite_->update(); dust_left_sprite_->update();
@@ -181,14 +167,11 @@ void GameLogo::update()
break; break;
} }
switch (arcade_edition_status_) switch (arcade_edition_status_) {
{ case Status::MOVING: {
case Status::MOVING:
{
zoom_ -= 0.1f * ZOOM_FACTOR; zoom_ -= 0.1f * ZOOM_FACTOR;
arcade_edition_sprite_->setZoom(zoom_); arcade_edition_sprite_->setZoom(zoom_);
if (zoom_ <= 1.0f) if (zoom_ <= 1.0f) {
{
arcade_edition_status_ = Status::SHAKING; arcade_edition_status_ = Status::SHAKING;
zoom_ = 1.0f; zoom_ = 1.0f;
arcade_edition_sprite_->setZoom(zoom_); arcade_edition_sprite_->setZoom(zoom_);
@@ -200,25 +183,18 @@ void GameLogo::update()
break; break;
} }
case Status::SHAKING: case Status::SHAKING: {
{
// Agita "ARCADE EDITION" // Agita "ARCADE EDITION"
if (shake_.remaining > 0) if (shake_.remaining > 0) {
{ if (shake_.counter > 0) {
if (shake_.counter > 0)
{
shake_.counter--; shake_.counter--;
} } else {
else
{
shake_.counter = shake_.delay; shake_.counter = shake_.delay;
const auto desp = shake_.remaining % 2 == 0 ? shake_.desp * (-1) : shake_.desp; const auto desp = shake_.remaining % 2 == 0 ? shake_.desp * (-1) : shake_.desp;
arcade_edition_sprite_->setX(shake_.origin + desp); arcade_edition_sprite_->setX(shake_.origin + desp);
shake_.remaining--; shake_.remaining--;
} }
} } else {
else
{
arcade_edition_sprite_->setX(shake_.origin); arcade_edition_sprite_->setX(shake_.origin);
arcade_edition_status_ = Status::FINISHED; arcade_edition_status_ = Status::FINISHED;
} }
@@ -231,28 +207,24 @@ void GameLogo::update()
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_;

View File

@@ -9,9 +9,8 @@
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;
@@ -24,18 +23,16 @@ public:
// --- 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
@@ -47,8 +44,7 @@ private:
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;

View File

@@ -6,13 +6,10 @@
#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) {
{
switch (event.type)
{
case SDL_EVENT_QUIT: // Evento de salida de la aplicación 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;
@@ -32,5 +29,5 @@ namespace GlobalEvents
} }
Mouse::handleEvent(event); Mouse::handleEvent(event);
}
} }
} // namespace GlobalEvents

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
}

View File

@@ -14,74 +14,59 @@
#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"; const std::string CODE = "QUIT";
if (Notifier::get()->checkCode(CODE)) if (Notifier::get()->checkCode(CODE)) {
{
// Si la notificación de salir está activa, cambia de sección // Si la notificación de salir está activa, cambia de sección
Section::name = Section::Name::QUIT; Section::name = Section::Name::QUIT;
Section::options = Section::Options::NONE; Section::options = Section::Options::NONE;
} } else {
else
{
// Si la notificación de salir no está activa, muestra la notificación // Si la notificación de salir no está activa, muestra la notificación
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 01"), std::string()}, -1, CODE); 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; Section::name = Section::Name::RESET;
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 15")}); Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 15")});
} } else {
else
{
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 03"), std::string()}, -1, CODE); 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;
@@ -92,13 +77,11 @@ namespace GlobalInputs
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;
@@ -109,46 +92,38 @@ namespace GlobalInputs
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); Options::settings.language = Lang::getNextLangCode(Options::settings.language);
Lang::loadFromFile(getLangFile(static_cast<Lang::Code>(Options::settings.language))); Lang::loadFromFile(getLangFile(static_cast<Lang::Code>(Options::settings.language)));
Section::name = Section::Name::RESET; Section::name = Section::Name::RESET;
Section::options = Section::Options::RELOAD; Section::options = Section::Options::RELOAD;
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 05") + getLangName(Options::settings.language)}); Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 05") + getLangName(Options::settings.language)});
} } else {
else
{
const auto NEXT = Lang::getNextLangCode(Options::settings.language); const auto NEXT = Lang::getNextLangCode(Options::settings.language);
Notifier::get()->show({Lang::getText("[NOTIFICATIONS] 04") + getLangName(NEXT), std::string()}, -1, CODE); 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;
@@ -157,110 +132,93 @@ namespace GlobalInputs
default: default:
break; break;
} }
} }
// Activa el menu de servicio // Activa el menu de servicio
void toggleServiceMenu() void toggleServiceMenu() {
{
ServiceMenu::get()->toggle(); ServiceMenu::get()->toggle();
} }
// Cambia el modo de pantalla completa // Cambia el modo de pantalla completa
void toggleFullscreen() void toggleFullscreen() {
{
Screen::get()->toggleFullscreen(); Screen::get()->toggleFullscreen();
const std::string MODE = Options::video.fullscreen ? Lang::getText("[NOTIFICATIONS] 11") : Lang::getText("[NOTIFICATIONS] 10"); const std::string MODE = Options::video.fullscreen ? Lang::getText("[NOTIFICATIONS] 11") : Lang::getText("[NOTIFICATIONS] 10");
Notifier::get()->show({MODE}); Notifier::get()->show({MODE});
} }
// Reduce el tamaño de la ventana // Reduce el tamaño de la ventana
void decWindowSize() void decWindowSize() {
{ 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)});
} }
} }
// Aumenta el tamaño de la ventana // Aumenta el tamaño de la ventana
void incWindowSize() void incWindowSize() {
{ 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)});
} }
} }
// Comprueba el boton de servicio // Comprueba el boton de servicio
bool checkServiceButton() bool checkServiceButton() {
{
// Teclado // Teclado
if (Input::get()->checkInput(InputAction::SERVICE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::SERVICE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
{
toggleServiceMenu(); toggleServiceMenu();
return true; return true;
} }
// Mandos // Mandos
{ {
for (int i = 0; i < Input::get()->getNumControllers(); ++i) for (int i = 0; i < Input::get()->getNumControllers(); ++i) {
{ if (Input::get()->checkInput(InputAction::SERVICE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i)) {
if (Input::get()->checkInput(InputAction::SERVICE, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i))
{
toggleServiceMenu(); toggleServiceMenu();
return true; return true;
} }
} }
} }
return false; return false;
} }
// Comprueba las entradas del menú de servicio // Comprueba las entradas del menú de servicio
bool checkServiceInputs() bool checkServiceInputs() {
{
if (!ServiceMenu::get()->isEnabled()) if (!ServiceMenu::get()->isEnabled())
return false; return false;
// Teclado // 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::KEYBOARD)) {
{
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::KEYBOARD)) {
{
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::KEYBOARD)) {
{
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::KEYBOARD)) {
{
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::KEYBOARD)) {
{
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::KEYBOARD)) {
{
ServiceMenu::get()->moveBack(); ServiceMenu::get()->moveBack();
return true; return true;
} }
@@ -268,62 +226,53 @@ namespace GlobalInputs
// Mandos // Mandos
{ {
for (int i = 0; i < Input::get()->getNumControllers(); ++i) for (int i = 0; i < Input::get()->getNumControllers(); ++i) {
{
// Arriba // Arriba
if (Input::get()->checkInput(InputAction::UP, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::CONTROLLER, i)) 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::CONTROLLER, i)) 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::CONTROLLER, i)) 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::CONTROLLER, i)) 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::CONTROLLER, i)) 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::CONTROLLER, i)) 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;
} }
} }
} }
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 // Comprueba el teclado para cambiar entre pantalla completa y ventana
if (Input::get()->checkInput(InputAction::WINDOW_FULLSCREEN, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) if (Input::get()->checkInput(InputAction::WINDOW_FULLSCREEN, INPUT_DO_NOT_ALLOW_REPEAT, InputDevice::KEYBOARD)) {
{
Screen::get()->toggleFullscreen(); Screen::get()->toggleFullscreen();
const std::string MODE = Options::video.fullscreen ? Lang::getText("[NOTIFICATIONS] 11") : Lang::getText("[NOTIFICATIONS] 10"); const std::string MODE = Options::video.fullscreen ? Lang::getText("[NOTIFICATIONS] 11") : Lang::getText("[NOTIFICATIONS] 10");
Notifier::get()->show({MODE}); Notifier::get()->show({MODE});
@@ -331,103 +280,88 @@ namespace GlobalInputs
} }
// 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 #endif
} }
return false; 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())
@@ -435,5 +369,5 @@ namespace GlobalInputs
if (checkInputs()) if (checkInputs())
return true; return true;
return false; return false;
}
} }
} // namespace GlobalInputs

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
}

View File

@@ -2,6 +2,7 @@
#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 <algorithm> // Para find
#include <iterator> // Para distance #include <iterator> // Para distance
#include <unordered_map> // Para unordered_map, _Node_const_iterator, operat... #include <unordered_map> // Para unordered_map, _Node_const_iterator, operat...
@@ -21,8 +22,7 @@ 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();
@@ -35,62 +35,46 @@ Input::Input(const std::string &game_controller_db_path)
} }
// 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)
{ // El usuario quiere saber si está pulsada (estado mantenido)
success_keyboard = key_bindings_[input_index].is_held; success_keyboard = key_bindings_[input_index].is_held;
} } else { // El usuario quiere saber si ACABA de ser pulsada (evento de un solo fotograma)
else
{ // El usuario quiere saber si ACABA de ser pulsada (evento de un solo fotograma)
success_keyboard = key_bindings_[input_index].just_pressed; 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)
{ // El usuario quiere saber si está pulsada (estado mantenido)
success_controller = controller_bindings_.at(controller_index).at(input_index).is_held; success_controller = controller_bindings_.at(controller_index).at(input_index).is_held;
} } else { // El usuario quiere saber si ACABA de ser pulsada (evento de un solo fotograma)
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; success_controller = controller_bindings_.at(controller_index).at(input_index).just_pressed;
} }
} }
@@ -101,20 +85,16 @@ bool Input::checkInput(InputAction input, bool repeat, InputDevice device, int c
} }
// 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(). // Simplemente leemos el estado pre-calculado por Input::update().
// Ya no se llama a SDL_GetKeyboardState ni se modifica el estado '.active'. // Ya no se llama a SDL_GetKeyboardState ni se modifica el estado '.active'.
if (key_bindings_.at(i).just_pressed) if (key_bindings_.at(i).just_pressed) {
{
return true; // Se encontró una acción recién pulsada. return true; // Se encontró una acción recién pulsada.
} }
} }
@@ -122,16 +102,12 @@ bool Input::checkAnyInput(InputDevice device, int controller_index)
// --- 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. // Bucle CORREGIDO: Iteramos sobre todas las acciones, no sobre el número de mandos.
for (int i = 0; i < num_actions; ++i) for (int i = 0; i < num_actions; ++i) {
{
// Leemos el estado pre-calculado para el mando y la acción específicos. // Leemos el estado pre-calculado para el mando y la acción específicos.
if (controller_bindings_.at(controller_index).at(i).just_pressed) if (controller_bindings_.at(controller_index).at(i).just_pressed) {
{
return true; // Se encontró una acción recién pulsada en el mando. return true; // Se encontró una acción recién pulsada en el mando.
} }
} }
@@ -143,22 +119,17 @@ bool Input::checkAnyInput(InputDevice device, int controller_index)
} }
// 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 // Comprueba el teclado
if (checkInput(bi, repeat, InputDevice::KEYBOARD)) if (checkInput(bi, repeat, InputDevice::KEYBOARD)) {
{
return 1; 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;
} }
} }
@@ -168,12 +139,10 @@ int Input::checkAnyButton(bool repeat)
} }
// 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());
} }
@@ -183,43 +152,34 @@ bool Input::discoverGameControllers()
// 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 {
else
{
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Gamepads found: %d", num_gamepads_); 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 // Abre el mando usando el ID del joystick
auto pad = SDL_OpenGamepad(joystick_ids[i]); auto pad = SDL_OpenGamepad(joystick_ids[i]);
if (pad != nullptr) if (pad != nullptr) {
{
connected_controllers_.push_back(pad); connected_controllers_.push_back(pad);
// Obtener el nombre usando el ID del joystick // Obtener el nombre usando el ID del joystick
@@ -228,9 +188,7 @@ bool Input::discoverGameControllers()
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());
} }
} }
@@ -240,8 +198,7 @@ bool Input::discoverGameControllers()
} }
// Liberar el array de IDs // Liberar el array de IDs
if (joystick_ids) if (joystick_ids) {
{
SDL_free(joystick_ids); SDL_free(joystick_ids);
} }
@@ -259,12 +216,9 @@ 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) {
{
if (SDL_GetJoystickID(joysticks_[i]) == id)
{
return i; return i;
} }
} }
@@ -272,17 +226,13 @@ int Input::getJoyIndex(SDL_JoystickID id) const
} }
// 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;
} }
@@ -290,31 +240,26 @@ void Input::printBindings(InputDevice device, int controller_index) const
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: case InputAction::FIRE_LEFT:
return "input_fire_left"; return "input_fire_left";
case InputAction::FIRE_CENTER: case InputAction::FIRE_CENTER:
@@ -331,8 +276,7 @@ std::string Input::to_string(InputAction input) const
} }
// 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},
@@ -345,13 +289,11 @@ InputAction Input::to_inputs_e(const std::string &name) const
} }
// 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;
@@ -371,22 +313,16 @@ bool Input::checkAxisInput(InputAction input, int controller_index, bool repeat)
// 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 {
else
{
// Si no se permite repetir, aplicamos la lógica de transición // Si no se permite repetir, aplicamos la lógica de transición
if (axis_active_now && !binding.axis_active) if (axis_active_now && !binding.axis_active) {
{
// Transición de inactivo a activo // Transición de inactivo a activo
binding.axis_active = true; binding.axis_active = true;
return true; return true;
} } else if (!axis_active_now && binding.axis_active) {
else if (!axis_active_now && binding.axis_active)
{
// Transición de activo a inactivo // Transición de activo a inactivo
binding.axis_active = false; binding.axis_active = false;
} }
@@ -395,16 +331,11 @@ bool Input::checkAxisInput(InputAction input, int controller_index, bool repeat)
} }
} }
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)) {
{
if (!SDL_InitSubSystem(SDL_INIT_GAMEPAD))
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GAMEPAD could not initialize! SDL Error: %s", SDL_GetError()); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GAMEPAD could not initialize! SDL Error: %s", SDL_GetError());
} } else {
else
{
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "\n** SDL_GAMEPAD: INITIALIZING"); SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "\n** SDL_GAMEPAD: INITIALIZING");
discoverGameControllers(); discoverGameControllers();
SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "** SDL_GAMEPAD: INITIALIZATION COMPLETE\n"); SDL_LogInfo(SDL_LOG_CATEGORY_TEST, "** SDL_GAMEPAD: INITIALIZATION COMPLETE\n");
@@ -412,32 +343,26 @@ void Input::initSDLGamePad()
} }
} }
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.is_held = false;
key.just_pressed = false; key.just_pressed = false;
} }
// Resetear todos los ControllerBindings.active a false // Resetear todos los ControllerBindings.active a false
for (auto &controller_vec : controller_bindings_) for (auto &controller_vec : controller_bindings_) {
{ for (auto &binding : controller_vec) {
for (auto &binding : controller_vec)
{
binding.is_held = false; binding.is_held = false;
binding.just_pressed = 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
@@ -446,10 +371,8 @@ void Input::update()
} }
// --- 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

View File

@@ -1,6 +1,7 @@
#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 <string> // Para basic_string, string
#include <vector> // Para vector #include <vector> // Para vector
@@ -14,8 +15,7 @@ device contiene el tipo de dispositivo a comprobar:
*/ */
// 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,
@@ -60,17 +60,15 @@ 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
@@ -104,13 +102,12 @@ public:
// --- 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
@@ -119,8 +116,7 @@ private:
: 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

View File

@@ -1,6 +1,7 @@
#include "item.h" #include "item.h"
#include <stdlib.h> // Para rand #include <stdlib.h> // Para rand
#include <algorithm> // Para clamp #include <algorithm> // Para clamp
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
@@ -11,12 +12,9 @@ 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: {
{
case ItemType::COFFEE_MACHINE:
{
width_ = COFFEE_MACHINE_WIDTH; width_ = COFFEE_MACHINE_WIDTH;
height_ = COFFEE_MACHINE_HEIGHT; height_ = COFFEE_MACHINE_HEIGHT;
pos_x_ = getCoffeeMachineSpawn(x, width_, play_area_.w); pos_x_ = getCoffeeMachineSpawn(x, width_, play_area_.w);
@@ -27,8 +25,7 @@ Item::Item(ItemType type, float x, float y, SDL_FRect &play_area, std::shared_pt
collider_.r = 10; collider_.r = 10;
break; break;
} }
default: default: {
{
width_ = param.game.item_size; width_ = param.game.item_size;
height_ = param.game.item_size; height_ = param.game.item_size;
pos_x_ = x; pos_x_ = x;
@@ -46,8 +43,7 @@ Item::Item(ItemType type, float x, float y, SDL_FRect &play_area, std::shared_pt
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;
@@ -61,23 +57,17 @@ void Item::alignTo(int x)
shiftColliders(); shiftColliders();
} }
void Item::render() void Item::render() {
{ if (enabled_) {
if (enabled_) if (time_to_live_ > 200) {
{
if (time_to_live_ > 200)
{
sprite_->render(); sprite_->render();
} } else if (time_to_live_ % 20 > 10) {
else if (time_to_live_ % 20 > 10)
{
sprite_->render(); sprite_->render();
} }
} }
} }
void Item::move() void Item::move() {
{
floor_collision_ = false; floor_collision_ = false;
// Calcula la nueva posición // Calcula la nueva posición
@@ -94,14 +84,12 @@ void Item::move()
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;
@@ -110,23 +98,18 @@ void Item::move()
} }
// 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 // Si la velocidad vertical es baja, detiene el objeto
vel_y_ = vel_x_ = accel_x_ = accel_y_ = 0; vel_y_ = vel_x_ = accel_x_ = accel_y_ = 0;
} } else {
else
{
// Si la velocidad vertical es alta, el objeto rebota y pierde velocidad // Si la velocidad vertical es alta, el objeto rebota y pierde velocidad
vel_y_ *= -0.20f; vel_y_ *= -0.20f;
vel_x_ *= 0.75f; vel_x_ *= 0.75f;
@@ -134,13 +117,10 @@ void Item::move()
break; break;
default: default:
// Si no es una máquina de café // Si no es una máquina de café
if (vel_y_ < 1.0f) if (vel_y_ < 1.0f) {
{
// Si la velocidad vertical es baja, detiene el objeto // Si la velocidad vertical es baja, detiene el objeto
vel_y_ = vel_x_ = accel_x_ = accel_y_ = 0; vel_y_ = vel_x_ = accel_x_ = accel_y_ = 0;
} } else {
else
{
// Si la velocidad vertical es alta, el objeto rebota y pierde velocidad // Si la velocidad vertical es alta, el objeto rebota y pierde velocidad
vel_y_ *= -0.5f; vel_y_ *= -0.5f;
vel_x_ *= 0.75f; vel_x_ *= 0.75f;
@@ -156,40 +136,32 @@ void Item::move()
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_--; time_to_live_--;
} } else {
else
{
disable(); 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;
@@ -206,43 +178,30 @@ int Item::getCoffeeMachineSpawn(int player_x, int item_width, int area_width, in
// 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 // Lado izquierdo
return rand() % (exclude_left - LEFT_BOUND) + LEFT_BOUND; return rand() % (exclude_left - LEFT_BOUND) + LEFT_BOUND;
} } else {
else
{
// Lado derecho // Lado derecho
return rand() % (RIGHT_BOUND - exclude_right) + exclude_right; return rand() % (RIGHT_BOUND - exclude_right) + exclude_right;
} }
} } else if (can_spawn_left) {
else if (can_spawn_left)
{
// Solo lado izquierdo disponible // Solo lado izquierdo disponible
return rand() % (exclude_left - LEFT_BOUND) + LEFT_BOUND; return rand() % (exclude_left - LEFT_BOUND) + LEFT_BOUND;
} } else if (can_spawn_right) {
else if (can_spawn_right)
{
// Solo lado derecho disponible // Solo lado derecho disponible
return rand() % (RIGHT_BOUND - exclude_right) + exclude_right; return rand() % (RIGHT_BOUND - exclude_right) + exclude_right;
} } else {
else
{
// No hay espacio suficiente lejos del jugador // No hay espacio suficiente lejos del jugador
// Por ahora, intentar spawn en el extremo más lejano posible // Por ahora, intentar spawn en el extremo más lejano posible
int distance_to_left = abs(player_x - LEFT_BOUND); int distance_to_left = abs(player_x - LEFT_BOUND);
int distance_to_right = abs(RIGHT_BOUND - player_x); 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 {
else
{
return RIGHT_BOUND - item_width; return RIGHT_BOUND - item_width;
} }
} }

View File

@@ -1,6 +1,7 @@
#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 <memory> // Para shared_ptr, unique_ptr
#include <string> // Para string #include <string> // Para string
#include <vector> // Para vector #include <vector> // Para vector
@@ -12,8 +13,7 @@ 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
@@ -26,9 +26,8 @@ enum class ItemType : int
// 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,7 +63,7 @@ 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

View File

@@ -1,6 +1,7 @@
#include "lang.h" #include "lang.h"
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <exception> // Para exception #include <exception> // Para exception
#include <fstream> // Para basic_ifstream, basic_istream, ifstream #include <fstream> // Para basic_ifstream, basic_istream, ifstream
#include <unordered_map> // Para unordered_map, _Node_iterator, operator== #include <unordered_map> // Para unordered_map, _Node_iterator, operator==
@@ -13,111 +14,92 @@
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; return true;
} }
// Obtiene el texto por clave // Obtiene el texto por clave
std::string getText(const std::string &key) std::string getText(const std::string &key) {
{
auto it = texts.find(key); auto it = texts.find(key);
if (it != texts.end()) if (it != texts.end())
return it->second; return it->second;
else else
return "[missing text: " + key + "]"; return "[missing text: " + key + "]";
} }
// Obtiene el código del siguiente idioma disponible // Obtiene el código del siguiente idioma disponible
Code getNextLangCode(Code lang) Code getNextLangCode(Code lang) {
{ for (size_t i = 0; i < languages.size(); ++i) {
for (size_t i = 0; i < languages.size(); ++i) if (languages[i].code == lang) {
{
if (languages[i].code == lang)
{
return languages[(i + 1) % languages.size()].code; return languages[(i + 1) % languages.size()].code;
} }
} }
// Si no se encuentra, devuelve el primero por defecto // Si no se encuentra, devuelve el primero por defecto
return languages[0].code; 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) if (lang.code == code)
return lang; return lang;
} }
// Si no se encuentra, devuelve el primero por defecto // Si no se encuentra, devuelve el primero por defecto
return languages[0]; 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) if (lang.name == name)
return lang.code; return lang.code;
} }
// Si no se encuentra, devuelve el primero por defecto // Si no se encuentra, devuelve el primero por defecto
return languages[0].code; 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) if (lang.code == code)
return lang.name; return lang.name;
} }
// Si no se encuentra, devuelve el nombre del primer idioma por defecto // Si no se encuentra, devuelve el nombre del primer idioma por defecto
return languages[0].name; 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;
@@ -132,15 +114,12 @@ namespace Lang
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;
@@ -155,26 +134,23 @@ namespace Lang
break; break;
} }
} }
} }
// Obtiene una fichero a partir de un lang::Code // Obtiene una fichero a partir de un lang::Code
std::string getLanguageFileName(Lang::Code code) std::string getLanguageFileName(Lang::Code code) {
{ for (const auto &lang : languages) {
for (const auto &lang : languages)
{
if (lang.code == code) if (lang.code == code)
return Asset::get()->get(lang.file_name); return Asset::get()->get(lang.file_name);
} }
// Si no se encuentra, devuelve el fichero del primer idioma por defecto // Si no se encuentra, devuelve el fichero del primer idioma por defecto
return Asset::get()->get(languages[0].file_name); return Asset::get()->get(languages[0].file_name);
} }
// Establece el idioma // Establece el idioma
void setLanguage(Code lang) void setLanguage(Code lang) {
{
Options::settings.language = lang; Options::settings.language = lang;
loadFromFile(Asset::get()->get(getLanguage(lang).file_name)); loadFromFile(Asset::get()->get(getLanguage(lang).file_name));
updateLanguageNames(); updateLanguageNames();
updateDifficultyNames(); updateDifficultyNames();
}
} }
} // namespace Lang

View File

@@ -2,51 +2,48 @@
#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, SPANISH = 0,
VALENCIAN = 1, VALENCIAN = 1,
ENGLISH = 2 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

View File

@@ -11,8 +11,7 @@ Actualizando a la versión "Arcade Edition" en 08/05/2024
#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));

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,25 +36,21 @@ 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,14 +70,12 @@ 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
@@ -91,8 +83,7 @@ bool ManageHiScoreTable::loadFromFile(const std::string &file_path)
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
@@ -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;
} }

View File

@@ -12,8 +12,7 @@
*/ */
// --- 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
@@ -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_;

View File

@@ -2,32 +2,26 @@
#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(); last_mouse_move_time = SDL_GetTicks();
if (!cursor_visible) if (!cursor_visible) {
{
SDL_ShowCursor(); SDL_ShowCursor();
cursor_visible = true; cursor_visible = true;
} }
} }
} }
void updateCursorVisibility() void updateCursorVisibility() {
{
Uint32 current_time = SDL_GetTicks(); Uint32 current_time = SDL_GetTicks();
if (cursor_visible && (current_time - last_mouse_move_time > cursor_hide_time)) if (cursor_visible && (current_time - last_mouse_move_time > cursor_hide_time)) {
{
SDL_HideCursor(); SDL_HideCursor();
cursor_visible = false; cursor_visible = false;
} }
}
} }
} // namespace Mouse

View File

@@ -2,14 +2,13 @@
#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

View File

@@ -31,8 +31,7 @@ MovingSprite::MovingSprite(std::shared_ptr<Texture> texture)
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
@@ -53,8 +52,7 @@ void MovingSprite::clear()
} }
// Mueve el sprite // Mueve el sprite
void MovingSprite::move() void MovingSprite::move() {
{
x_ += vx_; x_ += vx_;
y_ += vy_; y_ += vy_;
@@ -66,8 +64,7 @@ void MovingSprite::move()
} }
// Actualiza las variables internas del objeto // Actualiza las variables internas del objeto
void MovingSprite::update() void MovingSprite::update() {
{
move(); move();
rotate(); rotate();
} }
@@ -76,13 +73,10 @@ void MovingSprite::update()
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; ++rotate_.counter;
if (rotate_.counter % rotate_.speed == 0) if (rotate_.counter % rotate_.speed == 0) {
{
updateAngle(); updateAngle();
rotate_.counter = 0; rotate_.counter = 0;
} }
@@ -90,15 +84,13 @@ void MovingSprite::rotate()
} }
// 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);
@@ -106,8 +98,7 @@ void MovingSprite::setPos(SDL_FRect 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;
@@ -116,15 +107,13 @@ void MovingSprite::setPos(float x, float 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_);
} }

View File

@@ -1,6 +1,7 @@
#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
@@ -9,12 +10,10 @@
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
@@ -72,7 +71,7 @@ public:
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

View File

@@ -1,6 +1,7 @@
#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
@@ -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,8 +153,7 @@ 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;
@@ -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;

View File

@@ -1,6 +1,7 @@
#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 <memory> // Para shared_ptr
#include <string> // Para basic_string, string #include <string> // Para basic_string, string
#include <vector> // Para vector #include <vector> // Para vector
@@ -12,9 +13,8 @@ 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
@@ -30,28 +30,25 @@ public:
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
@@ -65,8 +62,7 @@ private:
// 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 ---

View File

@@ -1,6 +1,7 @@
#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
@@ -11,28 +12,26 @@
#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");
@@ -47,11 +46,10 @@ namespace Options
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();
@@ -62,21 +60,17 @@ namespace Options
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 // Comprueba que la línea no sea un comentario
if (line.substr(0, 1) != "#") if (line.substr(0, 1) != "#") {
{
// Encuentra la posición del carácter '=' // Encuentra la posición del carácter '='
int pos = line.find("="); int pos = line.find("=");
// Procesa las dos subcadenas // Procesa las dos subcadenas
if (!set(line.substr(0, pos), line.substr(pos + 1, line.length()))) 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()); SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Unknown parameter: %s", line.substr(0, pos).c_str());
success = false; success = false;
} }
@@ -85,29 +79,25 @@ namespace Options
file.close(); file.close();
} }
// El fichero no existe // El fichero no existe
else else {
{
saveToFile(); // Crea el fichero con los valores por defecto 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;
} }
@@ -155,8 +145,7 @@ namespace Options
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";
@@ -175,249 +164,165 @@ namespace Options
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") {
else if (var == "window.zoom")
{
window.size = std::stoi(value); window.size = std::stoi(value);
} } else if (var == "video.scale_mode") {
else if (var == "video.scale_mode")
{
video.scale_mode = static_cast<SDL_ScaleMode>(std::stoi(value)); video.scale_mode = static_cast<SDL_ScaleMode>(std::stoi(value));
} } else if (var == "video.shaders") {
else if (var == "video.shaders")
{
video.shaders = stringToBool(value); video.shaders = stringToBool(value);
} } else if (var == "video.integer_scale") {
else if (var == "video.integer_scale")
{
video.integer_scale = stringToBool(value); video.integer_scale = stringToBool(value);
} } else if (var == "video.v_sync") {
else if (var == "video.v_sync")
{
video.v_sync = stringToBool(value); 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") {
else if (var == "audio.volume")
{
audio.volume = std::clamp(std::stoi(value), 0, 100); audio.volume = std::clamp(std::stoi(value), 0, 100);
} } else if (var == "audio.music.enabled") {
else if (var == "audio.music.enabled")
{
audio.music.enabled = stringToBool(value); audio.music.enabled = stringToBool(value);
} } else if (var == "audio.music.volume") {
else if (var == "audio.music.volume")
{
audio.music.volume = std::clamp(std::stoi(value), 0, 100); audio.music.volume = std::clamp(std::stoi(value), 0, 100);
} } else if (var == "audio.sound.enabled") {
else if (var == "audio.sound.enabled")
{
audio.sound.enabled = stringToBool(value); audio.sound.enabled = stringToBool(value);
} } else if (var == "audio.sound.volume") {
else if (var == "audio.sound.volume")
{
audio.sound.volume = std::clamp(std::stoi(value), 0, 100); 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") {
else if (var == "game.difficulty")
{
settings.difficulty = static_cast<DifficultyCode>(std::stoi(value)); settings.difficulty = static_cast<DifficultyCode>(std::stoi(value));
pending_changes.new_difficulty = settings.difficulty; pending_changes.new_difficulty = settings.difficulty;
} } else if (var == "game.autofire") {
else if (var == "game.autofire")
{
settings.autofire = stringToBool(value); settings.autofire = stringToBool(value);
} } else if (var == "game.shutdown_enabled") {
else if (var == "game.shutdown_enabled")
{
settings.shutdown_enabled = stringToBool(value); 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") {
else if (var == "controller.0.player")
{
controllers.at(0).player_id = std::clamp(std::stoi(value), 1, 2); controllers.at(0).player_id = std::clamp(std::stoi(value), 1, 2);
} } else if (var == "controller.0.type") {
else if (var == "controller.0.type")
{
controllers.at(0).type = static_cast<InputDevice>(std::stoi(value)); controllers.at(0).type = static_cast<InputDevice>(std::stoi(value));
} } else if (var == "controller.0.button.fire_left") {
else if (var == "controller.0.button.fire_left")
{
controllers.at(0).buttons.at(0) = 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.fire_center") {
else if (var == "controller.0.button.fire_center")
{
controllers.at(0).buttons.at(1) = static_cast<SDL_GamepadButton>(std::stoi(value)); controllers.at(0).buttons.at(1) = static_cast<SDL_GamepadButton>(std::stoi(value));
} } else if (var == "controller.0.button.fire_right") {
else if (var == "controller.0.button.fire_right")
{
controllers.at(0).buttons.at(2) = static_cast<SDL_GamepadButton>(std::stoi(value)); controllers.at(0).buttons.at(2) = static_cast<SDL_GamepadButton>(std::stoi(value));
} } else if (var == "controller.0.button.start") {
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(3) = static_cast<SDL_GamepadButton>(std::stoi(value));
} } else if (var == "controller.0.button.service") {
else if (var == "controller.0.button.service")
{
controllers.at(0).buttons.at(4) = 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.name") {
else if (var == "controller.1.name")
{
controllers.at(1).name = value; controllers.at(1).name = value;
} } else if (var == "controller.1.player") {
else if (var == "controller.1.player")
{
controllers.at(1).player_id = std::clamp(std::stoi(value), 1, 2); controllers.at(1).player_id = std::clamp(std::stoi(value), 1, 2);
} } else if (var == "controller.1.type") {
else if (var == "controller.1.type")
{
controllers.at(1).type = static_cast<InputDevice>(std::stoi(value)); controllers.at(1).type = static_cast<InputDevice>(std::stoi(value));
} } else if (var == "controller.1.button.fire_left") {
else if (var == "controller.1.button.fire_left")
{
controllers.at(1).buttons.at(0) = static_cast<SDL_GamepadButton>(std::stoi(value)); controllers.at(1).buttons.at(0) = static_cast<SDL_GamepadButton>(std::stoi(value));
} } else if (var == "controller.1.button.fire_center") {
else if (var == "controller.1.button.fire_center")
{
controllers.at(1).buttons.at(1) = static_cast<SDL_GamepadButton>(std::stoi(value)); controllers.at(1).buttons.at(1) = static_cast<SDL_GamepadButton>(std::stoi(value));
} } else if (var == "controller.1.button.fire_right") {
else if (var == "controller.1.button.fire_right")
{
controllers.at(1).buttons.at(2) = static_cast<SDL_GamepadButton>(std::stoi(value)); controllers.at(1).buttons.at(2) = static_cast<SDL_GamepadButton>(std::stoi(value));
} } else if (var == "controller.1.button.start") {
else if (var == "controller.1.button.start")
{
controllers.at(1).buttons.at(3) = static_cast<SDL_GamepadButton>(std::stoi(value)); controllers.at(1).buttons.at(3) = static_cast<SDL_GamepadButton>(std::stoi(value));
} } else if (var == "controller.1.button.service") {
else if (var == "controller.1.button.service")
{
controllers.at(1).buttons.at(4) = static_cast<SDL_GamepadButton>(std::stoi(value)); 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 {
}
else
{
success = false; 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) {
{
if (controller.player_id == player_id)
{
controller.type = InputDevice::ANY; controller.type = InputDevice::ANY;
} } else {
else
{
controller.type = InputDevice::CONTROLLER; 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) {
{
if (controller.type == InputDevice::ANY)
{
return controller.player_id; 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.language = pending_changes.new_language;
settings.difficulty = pending_changes.new_difficulty; settings.difficulty = pending_changes.new_difficulty;
pending_changes.has_pending_changes = false; 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; pending_changes.has_pending_changes = true;
} } else {
else
{
pending_changes.has_pending_changes = false; 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) if (difficulty.name == name)
return difficulty.code; return difficulty.code;
} }
// Si no se encuentra, devuelve el primero por defecto // Si no se encuentra, devuelve el primero por defecto
return difficulties[0].code; 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) if (difficulty.code == code)
return difficulty.name; return difficulty.name;
} }
// Si no se encuentra, devuelve el nombre del primero por defecto // Si no se encuentra, devuelve el nombre del primero por defecto
return difficulties[0].name; return difficulties[0].name;
} }
} // namespace Options } // namespace Options

View File

@@ -1,6 +1,7 @@
#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 <string> // Para string, basic_string
#include <vector> // Para vector #include <vector> // Para vector
@@ -10,29 +11,25 @@
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, EASY = 0,
NORMAL = 1, NORMAL = 1,
HARD = 2, 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
@@ -42,11 +39,10 @@ namespace Options
: 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
@@ -62,11 +58,10 @@ namespace Options
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
@@ -74,11 +69,10 @@ namespace Options
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
@@ -86,11 +80,10 @@ namespace Options
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
@@ -102,11 +95,10 @@ namespace Options
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
@@ -125,16 +117,14 @@ namespace Options
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
@@ -162,11 +152,10 @@ namespace Options
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
@@ -176,27 +165,27 @@ namespace Options
: 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

View File

@@ -1,6 +1,7 @@
#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 <fstream> // Para basic_istream, basic_ifstream, ifstream
#include <sstream> // Para basic_istringstream #include <sstream> // Para basic_istringstream
#include <stdexcept> // Para runtime_error #include <stdexcept> // Para runtime_error
@@ -17,8 +18,7 @@ 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;
@@ -89,15 +89,13 @@ void initParam()
} }
// 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);
} }
@@ -105,21 +103,17 @@ void loadParamsFromFile(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());
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());
} }
} }
@@ -133,361 +127,289 @@ void loadParamsFromFile(const std::string &file_path)
} }
// 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") else if (var == "game.height") {
{
param.game.height = std::stoi(value); param.game.height = std::stoi(value);
} }
else if (var == "game.item_size") else if (var == "game.item_size") {
{
param.game.item_size = std::stoi(value); param.game.item_size = std::stoi(value);
} }
else if (var == "game.play_area.rect.x") else if (var == "game.play_area.rect.x") {
{
param.game.play_area.rect.x = std::stoi(value); param.game.play_area.rect.x = std::stoi(value);
} }
else if (var == "game.play_area.rect.y") else if (var == "game.play_area.rect.y") {
{
param.game.play_area.rect.y = std::stoi(value); param.game.play_area.rect.y = std::stoi(value);
} }
else if (var == "game.play_area.rect.w") else if (var == "game.play_area.rect.w") {
{
param.game.play_area.rect.w = std::stoi(value); param.game.play_area.rect.w = std::stoi(value);
} }
else if (var == "game.play_area.rect.h") else if (var == "game.play_area.rect.h") {
{
param.game.play_area.rect.h = std::stoi(value); param.game.play_area.rect.h = std::stoi(value);
} }
else if (var == "game.name_entry_idle_time") else if (var == "game.name_entry_idle_time") {
{
param.game.name_entry_idle_time = std::stoi(value); param.game.name_entry_idle_time = std::stoi(value);
} }
else if (var == "game.name_entry_total_time") else if (var == "game.name_entry_total_time") {
{
param.game.name_entry_total_time = std::stoi(value); param.game.name_entry_total_time = std::stoi(value);
} }
else if (var == "game.hit_stop") else if (var == "game.hit_stop") {
{
param.game.hit_stop = stringToBool(value); param.game.hit_stop = stringToBool(value);
} }
else if (var == "game.hit_stop_ms") else if (var == "game.hit_stop_ms") {
{
param.game.hit_stop_ms = std::stoi(value); param.game.hit_stop_ms = std::stoi(value);
} }
// FADE // FADE
else if (var == "fade.color") else if (var == "fade.color") {
{
param.fade.color = Color::fromHex(value); param.fade.color = Color::fromHex(value);
} }
else if (var == "fade.num_squares_width") else if (var == "fade.num_squares_width") {
{
param.fade.num_squares_width = std::stoi(value); param.fade.num_squares_width = std::stoi(value);
} }
else if (var == "fade.num_squares_height") else if (var == "fade.num_squares_height") {
{
param.fade.num_squares_height = std::stoi(value); param.fade.num_squares_height = std::stoi(value);
} }
else if (var == "fade.random_squares_delay") else if (var == "fade.random_squares_delay") {
{
param.fade.random_squares_delay = std::stoi(value); param.fade.random_squares_delay = std::stoi(value);
} }
else if (var == "fade.random_squares_mult") else if (var == "fade.random_squares_mult") {
{
param.fade.random_squares_mult = std::stoi(value); param.fade.random_squares_mult = std::stoi(value);
} }
else if (var == "fade.post_duration") else if (var == "fade.post_duration") {
{
param.fade.post_duration = std::stoi(value); param.fade.post_duration = std::stoi(value);
} }
else if (var == "fade.venetian_size") else if (var == "fade.venetian_size") {
{
param.fade.venetian_size = std::stoi(value); param.fade.venetian_size = std::stoi(value);
} }
// SCOREBOARD // SCOREBOARD
else if (var == "scoreboard.rect.x") else if (var == "scoreboard.rect.x") {
{
param.scoreboard.rect.x = std::stoi(value); param.scoreboard.rect.x = std::stoi(value);
} }
else if (var == "scoreboard.rect.y") else if (var == "scoreboard.rect.y") {
{
param.scoreboard.rect.y = std::stoi(value); param.scoreboard.rect.y = std::stoi(value);
} }
else if (var == "scoreboard.rect.w") else if (var == "scoreboard.rect.w") {
{
param.scoreboard.rect.w = std::stoi(value); param.scoreboard.rect.w = std::stoi(value);
} }
else if (var == "scoreboard.rect.h") else if (var == "scoreboard.rect.h") {
{
param.scoreboard.rect.h = std::stoi(value); param.scoreboard.rect.h = std::stoi(value);
} }
else if (var == "scoreboard.separator_autocolor") else if (var == "scoreboard.separator_autocolor") {
{
param.scoreboard.separator_autocolor = stringToBool(value); param.scoreboard.separator_autocolor = stringToBool(value);
} }
else if (var == "scoreboard.separator_color") else if (var == "scoreboard.separator_color") {
{
param.scoreboard.separator_color = Color::fromHex(value); param.scoreboard.separator_color = Color::fromHex(value);
} }
else if (var == "scoreboard.easy_color") else if (var == "scoreboard.easy_color") {
{
param.scoreboard.easy_color = Color::fromHex(value); param.scoreboard.easy_color = Color::fromHex(value);
} }
else if (var == "scoreboard.normal_color") else if (var == "scoreboard.normal_color") {
{
param.scoreboard.normal_color = Color::fromHex(value); param.scoreboard.normal_color = Color::fromHex(value);
} }
else if (var == "scoreboard.hard_color") else if (var == "scoreboard.hard_color") {
{
param.scoreboard.hard_color = Color::fromHex(value); param.scoreboard.hard_color = Color::fromHex(value);
} }
else if (var == "scoreboard.text_autocolor") else if (var == "scoreboard.text_autocolor") {
{
param.scoreboard.text_autocolor = stringToBool(value); param.scoreboard.text_autocolor = stringToBool(value);
} }
else if (var == "scoreboard.text_color1") else if (var == "scoreboard.text_color1") {
{
param.scoreboard.text_color1 = Color::fromHex(value); param.scoreboard.text_color1 = Color::fromHex(value);
} }
else if (var == "scoreboard.text_color2") else if (var == "scoreboard.text_color2") {
{
param.scoreboard.text_color2 = Color::fromHex(value); param.scoreboard.text_color2 = Color::fromHex(value);
} }
else if (var == "scoreboard.skip_countdown_value") else if (var == "scoreboard.skip_countdown_value") {
{
param.scoreboard.skip_countdown_value = std::stoi(value); param.scoreboard.skip_countdown_value = std::stoi(value);
} }
// TITLE // TITLE
else if (var == "title.press_start_position") else if (var == "title.press_start_position") {
{
param.title.press_start_position = std::stoi(value); param.title.press_start_position = std::stoi(value);
} }
else if (var == "title.title_duration") else if (var == "title.title_duration") {
{
param.title.title_duration = std::stoi(value); param.title.title_duration = std::stoi(value);
} }
else if (var == "title.arcade_edition_position") else if (var == "title.arcade_edition_position") {
{
param.title.arcade_edition_position = std::stoi(value); param.title.arcade_edition_position = std::stoi(value);
} }
else if (var == "title.title_c_c_position") else if (var == "title.title_c_c_position") {
{
param.title.title_c_c_position = std::stoi(value); param.title.title_c_c_position = std::stoi(value);
} }
else if (var == "title.bg_color") else if (var == "title.bg_color") {
{
param.title.bg_color = Color::fromHex(value); param.title.bg_color = Color::fromHex(value);
} }
// BACKGROUND // BACKGROUND
else if (var == "background.attenuate_color") else if (var == "background.attenuate_color") {
{
param.background.attenuate_color = Color::fromHex(value); param.background.attenuate_color = Color::fromHex(value);
} }
// BALLOON // BALLOON
else if (var == "balloon.settings[0].vel") else if (var == "balloon.settings[0].vel") {
{
param.balloon.settings.at(0).vel = std::stof(value); param.balloon.settings.at(0).vel = std::stof(value);
} }
else if (var == "balloon.settings[0].grav") else if (var == "balloon.settings[0].grav") {
{
param.balloon.settings.at(0).grav = std::stof(value); param.balloon.settings.at(0).grav = std::stof(value);
} }
else if (var == "balloon.settings[1].vel") else if (var == "balloon.settings[1].vel") {
{
param.balloon.settings.at(1).vel = std::stof(value); param.balloon.settings.at(1).vel = std::stof(value);
} }
else if (var == "balloon.settings[1].grav") else if (var == "balloon.settings[1].grav") {
{
param.balloon.settings.at(1).grav = std::stof(value); param.balloon.settings.at(1).grav = std::stof(value);
} }
else if (var == "balloon.settings[2].vel") else if (var == "balloon.settings[2].vel") {
{
param.balloon.settings.at(2).vel = std::stof(value); param.balloon.settings.at(2).vel = std::stof(value);
} }
else if (var == "balloon.settings[2].grav") else if (var == "balloon.settings[2].grav") {
{
param.balloon.settings.at(2).grav = std::stof(value); param.balloon.settings.at(2).grav = std::stof(value);
} }
else if (var == "balloon.settings[3].vel") else if (var == "balloon.settings[3].vel") {
{
param.balloon.settings.at(3).vel = std::stof(value); param.balloon.settings.at(3).vel = std::stof(value);
} }
else if (var == "balloon.settings[3].grav") else if (var == "balloon.settings[3].grav") {
{
param.balloon.settings.at(3).grav = std::stof(value); param.balloon.settings.at(3).grav = std::stof(value);
} }
else if (var == "balloon.color[0]") else if (var == "balloon.color[0]") {
{
param.balloon.color.at(0) = value; param.balloon.color.at(0) = value;
} }
else if (var == "balloon.color[1]") else if (var == "balloon.color[1]") {
{
param.balloon.color.at(1) = value; param.balloon.color.at(1) = value;
} }
else if (var == "balloon.color[2]") else if (var == "balloon.color[2]") {
{
param.balloon.color.at(2) = value; param.balloon.color.at(2) = value;
} }
else if (var == "balloon.color[3]") else if (var == "balloon.color[3]") {
{
param.balloon.color.at(3) = value; param.balloon.color.at(3) = value;
} }
else if (var == "balloon.bouncing_sound") else if (var == "balloon.bouncing_sound") {
{
param.balloon.bouncing_sound = stringToBool(value); param.balloon.bouncing_sound = stringToBool(value);
} }
// NOTIFICACIONES // NOTIFICACIONES
else if (var == "notification.pos_h") else if (var == "notification.pos_h") {
{ if (value == "LEFT") {
if (value == "LEFT")
{
param.notification.pos_h = NotifyPosition::LEFT; param.notification.pos_h = NotifyPosition::LEFT;
} } else if (value == "MIDDLE") {
else if (value == "MIDDLE")
{
param.notification.pos_h = NotifyPosition::MIDDLE; param.notification.pos_h = NotifyPosition::MIDDLE;
} } else {
else
{
param.notification.pos_h = NotifyPosition::RIGHT; param.notification.pos_h = NotifyPosition::RIGHT;
} }
} }
else if (var == "notification.pos_v") else if (var == "notification.pos_v") {
{
param.notification.pos_v = value == "TOP" ? NotifyPosition::TOP : NotifyPosition::BOTTOM; param.notification.pos_v = value == "TOP" ? NotifyPosition::TOP : NotifyPosition::BOTTOM;
} }
else if (var == "notification.sound") else if (var == "notification.sound") {
{
param.notification.sound = stringToBool(value); param.notification.sound = stringToBool(value);
} }
else if (var == "notification.color") else if (var == "notification.color") {
{
param.notification.color = Color::fromHex(value); param.notification.color = Color::fromHex(value);
} }
// SERVICE MENU // SERVICE MENU
else if (var == "service_menu.title_color") else if (var == "service_menu.title_color") {
{
param.service_menu.title_color = Color::fromHex(value); param.service_menu.title_color = Color::fromHex(value);
} }
else if (var == "service_menu.text_color") else if (var == "service_menu.text_color") {
{
param.service_menu.text_color = Color::fromHex(value); param.service_menu.text_color = Color::fromHex(value);
} }
else if (var == "service_menu.selected_color") else if (var == "service_menu.selected_color") {
{
param.service_menu.selected_color = Color::fromHex(value); param.service_menu.selected_color = Color::fromHex(value);
} }
else if (var == "service_menu.bg_color") else if (var == "service_menu.bg_color") {
{
param.service_menu.bg_color = Color::fromHex(value); param.service_menu.bg_color = Color::fromHex(value);
} }
else if (var == "service_menu.drop_shadow") else if (var == "service_menu.drop_shadow") {
{
param.service_menu.drop_shadow = stringToBool(value); param.service_menu.drop_shadow = stringToBool(value);
} }
// INTRO // INTRO
else if (var == "intro.bg_color") else if (var == "intro.bg_color") {
{
param.intro.bg_color = Color::fromHex(value); param.intro.bg_color = Color::fromHex(value);
} }
else if (var == "intro.card_color") else if (var == "intro.card_color") {
{
param.intro.card_color = Color::fromHex(value); param.intro.card_color = Color::fromHex(value);
} }
else if (var == "intro.shadow_color") else if (var == "intro.shadow_color") {
{
param.intro.shadow_color = Color::fromHex(value); param.intro.shadow_color = Color::fromHex(value);
} }
else if (var == "intro.text_distance_from_bottom") else if (var == "intro.text_distance_from_bottom") {
{
param.intro.text_distance_from_bottom = std::stoi(value); param.intro.text_distance_from_bottom = std::stoi(value);
} }
// DEBUG // DEBUG
else if (var == "debug.color") else if (var == "debug.color") {
{
param.debug.color = Color::fromHex(value); param.debug.color = Color::fromHex(value);
} }
// RESOURCE // RESOURCE
else if (var == "resource.color") else if (var == "resource.color") {
{
param.resource.color = Color::fromHex(value); param.resource.color = Color::fromHex(value);
} }
// RESTO // RESTO
else else {
{
success = false; success = false;
} }
@@ -495,8 +417,7 @@ bool setParams(const std::string &var, const std::string &value)
} }
// 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;

View File

@@ -1,14 +1,14 @@
#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 <array> // Para array
#include <string> // Para basic_string, string #include <string> // Para basic_string, string
#include "utils.h" // Para Color, NotifyPosition (ptr only), Zone #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
@@ -22,8 +22,7 @@ struct ParamGame
}; };
// --- 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
@@ -34,8 +33,7 @@ struct ParamFade
}; };
// --- 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"
@@ -44,16 +42,13 @@ struct ParamTitle
}; };
// --- 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 grav; // Aceleración en el eje Y. Modifica la velocidad
float vel; // Velocidad inicial al rebotar contra el suelo float vel; // Velocidad inicial al rebotar contra el suelo
@@ -68,8 +63,7 @@ struct ParamBalloon
}; };
// --- 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
@@ -77,8 +71,7 @@ struct ParamNotification
}; };
// --- 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
@@ -92,8 +85,7 @@ struct ParamScoreboard
}; };
// --- 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,20 +102,17 @@ 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
@@ -139,8 +127,7 @@ struct Param
// 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 ---

View File

@@ -6,23 +6,19 @@
#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;
@@ -38,43 +34,35 @@ std::vector<SDL_FPoint> createPath(float start, float end, PathType type, float
} }
// 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(); moveThroughCurrentPath();
goToNextPathOrDie(); 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; const int x = path.spots.back().x - pos_.w / 2;
for (auto &spot : path.spots) for (auto &spot : path.spots)
spot.x = x; spot.x = x;
paths_.emplace_back(path); paths_.emplace_back(path);
break; break;
} }
case PathCentered::ON_Y: case PathCentered::ON_Y: {
{
const int y = path.spots.back().y - pos_.h / 2; const int y = path.spots.back().y - pos_.h / 2;
for (auto &spot : path.spots) for (auto &spot : path.spots)
spot.y = y; spot.y = y;
@@ -88,22 +76,18 @@ void PathSprite::addPath(Path path, bool centered)
} }
// 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;
} }
@@ -116,8 +100,7 @@ void PathSprite::enable()
} }
// 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
@@ -125,42 +108,33 @@ void PathSprite::moveThroughCurrentPath()
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.on_destination = true;
path.counter = static_cast<int>(path.spots.size()) - 1; 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; path.finished = true;
} } else {
else
{
--path.waiting_counter; --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;
} }

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para SDL_FPoint #include <SDL3/SDL.h> // Para SDL_FPoint
#include <functional> // Para std::function #include <functional> // Para std::function
#include <memory> // Para shared_ptr #include <memory> // Para shared_ptr
#include <vector> // Para vector #include <vector> // Para vector
@@ -10,23 +11,20 @@
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
@@ -42,9 +40,8 @@ struct Path
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) {}
@@ -66,7 +63,7 @@ public:
// --- 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

View File

@@ -2,6 +2,7 @@
#include <SDL3/SDL.h> // Para SDL_GetTicks, SDL_FlipMode, SDL_FRect #include <SDL3/SDL.h> // Para SDL_GetTicks, SDL_FlipMode, SDL_FRect
#include <stdlib.h> // Para rand #include <stdlib.h> // Para rand
#include <algorithm> // Para clamp, max, min #include <algorithm> // Para clamp, max, min
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
@@ -23,8 +24,7 @@ Player::Player(int id, float x, int y, bool demo, SDL_FRect &play_area, std::vec
play_area_(play_area), play_area_(play_area),
default_pos_x_(x), default_pos_x_(x),
default_pos_y_(y), default_pos_y_(y),
demo_(demo) demo_(demo) {
{
// Configura objetos // Configura objetos
player_sprite_->getTexture()->setPalette(coffees_); player_sprite_->getTexture()->setPalette(coffees_);
power_sprite_->getTexture()->setAlpha(224); power_sprite_->getTexture()->setAlpha(224);
@@ -39,8 +39,7 @@ Player::Player(int id, float x, int y, bool demo, SDL_FRect &play_area, std::vec
} }
// Iniciador // Iniciador
void Player::init() void Player::init() {
{
// Inicializa variables de estado // Inicializa variables de estado
pos_y_ = default_pos_y_; pos_y_ = default_pos_y_;
walking_state_ = PlayerState::WALKING_STOP; walking_state_ = PlayerState::WALKING_STOP;
@@ -72,18 +71,14 @@ void Player::init()
} }
// Actua en consecuencia de la entrada recibida // Actua en consecuencia de la entrada recibida
void Player::setInput(InputAction input) void Player::setInput(InputAction input) {
{ switch (playing_state_) {
switch (playing_state_) case PlayerState::PLAYING: {
{
case PlayerState::PLAYING:
{
setInputPlaying(input); setInputPlaying(input);
break; break;
} }
case PlayerState::ENTERING_NAME: case PlayerState::ENTERING_NAME:
case PlayerState::ENTERING_NAME_GAME_COMPLETED: case PlayerState::ENTERING_NAME_GAME_COMPLETED: {
{
setInputEnteringName(input); setInputEnteringName(input);
break; break;
} }
@@ -93,39 +88,31 @@ void Player::setInput(InputAction input)
} }
// Procesa inputs para cuando está jugando // Procesa inputs para cuando está jugando
void Player::setInputPlaying(InputAction input) void Player::setInputPlaying(InputAction input) {
{ switch (input) {
switch (input) case InputAction::LEFT: {
{
case InputAction::LEFT:
{
vel_x_ = -BASE_SPEED_; vel_x_ = -BASE_SPEED_;
setWalkingState(PlayerState::WALKING_LEFT); setWalkingState(PlayerState::WALKING_LEFT);
break; break;
} }
case InputAction::RIGHT: case InputAction::RIGHT: {
{
vel_x_ = BASE_SPEED_; vel_x_ = BASE_SPEED_;
setWalkingState(PlayerState::WALKING_RIGHT); setWalkingState(PlayerState::WALKING_RIGHT);
break; break;
} }
case InputAction::FIRE_CENTER: case InputAction::FIRE_CENTER: {
{
setFiringState(PlayerState::FIRING_UP); setFiringState(PlayerState::FIRING_UP);
break; break;
} }
case InputAction::FIRE_LEFT: case InputAction::FIRE_LEFT: {
{
setFiringState(PlayerState::FIRING_LEFT); setFiringState(PlayerState::FIRING_LEFT);
break; break;
} }
case InputAction::FIRE_RIGHT: case InputAction::FIRE_RIGHT: {
{
setFiringState(PlayerState::FIRING_RIGHT); setFiringState(PlayerState::FIRING_RIGHT);
break; break;
} }
default: default: {
{
vel_x_ = 0; vel_x_ = 0;
setWalkingState(PlayerState::WALKING_STOP); setWalkingState(PlayerState::WALKING_STOP);
break; break;
@@ -134,10 +121,8 @@ void Player::setInputPlaying(InputAction input)
} }
// Procesa inputs para cuando está introduciendo el nombre // Procesa inputs para cuando está introduciendo el nombre
void Player::setInputEnteringName(InputAction input) void Player::setInputEnteringName(InputAction input) {
{ switch (input) {
switch (input)
{
case InputAction::LEFT: case InputAction::LEFT:
enter_name_->decPosition(); enter_name_->decPosition();
break; break;
@@ -160,12 +145,9 @@ void Player::setInputEnteringName(InputAction input)
} }
// Mueve el jugador a la posición y animación que le corresponde // Mueve el jugador a la posición y animación que le corresponde
void Player::move() void Player::move() {
{ switch (playing_state_) {
switch (playing_state_) case PlayerState::PLAYING: {
{
case PlayerState::PLAYING:
{
// Mueve el jugador a derecha o izquierda // Mueve el jugador a derecha o izquierda
pos_x_ += vel_x_; pos_x_ += vel_x_;
@@ -177,24 +159,20 @@ void Player::move()
shiftSprite(); shiftSprite();
break; break;
} }
case PlayerState::ROLLING: case PlayerState::ROLLING: {
{
// Si el jugador abandona el area de juego por los laterales lo hace rebotar // Si el jugador abandona el area de juego por los laterales lo hace rebotar
const int X = player_sprite_->getPosX(); const int X = player_sprite_->getPosX();
const int MIN_X = play_area_.x; const int MIN_X = play_area_.x;
const int MAX_X = play_area_.x + play_area_.w - WIDTH_; const int MAX_X = play_area_.x + play_area_.w - WIDTH_;
if ((X < MIN_X) || (X > MAX_X)) if ((X < MIN_X) || (X > MAX_X)) {
{
player_sprite_->setPosX(std::clamp(X, MIN_X, MAX_X)); player_sprite_->setPosX(std::clamp(X, MIN_X, MAX_X));
player_sprite_->setVelX(-player_sprite_->getVelX()); player_sprite_->setVelX(-player_sprite_->getVelX());
playSound("jump.wav"); playSound("jump.wav");
} }
// Si el jugador toca el suelo rebota y si tiene poca velocidad, se detiene y cambia de estado // Si el jugador toca el suelo rebota y si tiene poca velocidad, se detiene y cambia de estado
if (player_sprite_->getPosY() > play_area_.h - HEIGHT_) if (player_sprite_->getPosY() > play_area_.h - HEIGHT_) {
{ if (player_sprite_->getVelY() < 2.0f) {
if (player_sprite_->getVelY() < 2.0f)
{
// Si la velocidad de rebote es baja, lo detiene y cambia de estado // Si la velocidad de rebote es baja, lo detiene y cambia de estado
const auto nextPlayerStatus = IsEligibleForHighScore() ? PlayerState::ENTERING_NAME : PlayerState::CONTINUE; const auto nextPlayerStatus = IsEligibleForHighScore() ? PlayerState::ENTERING_NAME : PlayerState::CONTINUE;
demo_ ? setPlayingState(PlayerState::LYING_ON_THE_FLOOR_FOREVER) : setPlayingState(nextPlayerStatus); demo_ ? setPlayingState(PlayerState::LYING_ON_THE_FLOOR_FOREVER) : setPlayingState(nextPlayerStatus);
@@ -203,9 +181,7 @@ void Player::move()
player_sprite_->clear(); player_sprite_->clear();
shiftSprite(); shiftSprite();
playSound("jump.wav"); playSound("jump.wav");
} } else {
else
{
// Decrementa las velocidades de rebote // Decrementa las velocidades de rebote
player_sprite_->setPosY(play_area_.h - HEIGHT_); player_sprite_->setPosY(play_area_.h - HEIGHT_);
player_sprite_->setVelY(player_sprite_->getVelY() * -0.5f); player_sprite_->setVelY(player_sprite_->getVelY() * -0.5f);
@@ -216,8 +192,7 @@ void Player::move()
} }
break; break;
} }
case PlayerState::TITLE_ANIMATION: case PlayerState::TITLE_ANIMATION: {
{
// Si el jugador abandona el area de juego por los laterales lo detiene // Si el jugador abandona el area de juego por los laterales lo detiene
/*const int X = player_sprite_->getPosX(); /*const int X = player_sprite_->getPosX();
const int MIN_X = play_area_.x - WIDTH_; const int MIN_X = play_area_.x - WIDTH_;
@@ -233,8 +208,7 @@ void Player::move()
setPlayingState(PlayerState::TITLE_HIDDEN); setPlayingState(PlayerState::TITLE_HIDDEN);
}*/ }*/
switch (id_) switch (id_) {
{
case 1: case 1:
setInputPlaying(InputAction::LEFT); setInputPlaying(InputAction::LEFT);
break; break;
@@ -250,31 +224,25 @@ void Player::move()
pos_x_ = std::clamp(pos_x_, MIN_X, MAX_X); pos_x_ = std::clamp(pos_x_, MIN_X, MAX_X);
shiftSprite(); shiftSprite();
if (pos_x_ == MIN_X || pos_x_ == MAX_X) if (pos_x_ == MIN_X || pos_x_ == MAX_X) {
{
setPlayingState(PlayerState::TITLE_HIDDEN); setPlayingState(PlayerState::TITLE_HIDDEN);
} }
break; break;
} }
case PlayerState::CONTINUE_TIME_OUT: case PlayerState::CONTINUE_TIME_OUT: {
{
// Si el cadaver desaparece por el suelo, cambia de estado // Si el cadaver desaparece por el suelo, cambia de estado
if (player_sprite_->getPosY() > play_area_.h) if (player_sprite_->getPosY() > play_area_.h) {
{
setPlayingState(PlayerState::WAITING); setPlayingState(PlayerState::WAITING);
} }
break; break;
} }
case PlayerState::LEAVING_SCREEN: case PlayerState::LEAVING_SCREEN: {
{
++step_counter_; ++step_counter_;
if (step_counter_ % 10 == 0) if (step_counter_ % 10 == 0) {
{
playSound("walk.wav"); playSound("walk.wav");
} }
switch (id_) switch (id_) {
{
case 1: case 1:
setInputPlaying(InputAction::LEFT); setInputPlaying(InputAction::LEFT);
break; break;
@@ -290,27 +258,22 @@ void Player::move()
pos_x_ = std::clamp(pos_x_, MIN_X, MAX_X); pos_x_ = std::clamp(pos_x_, MIN_X, MAX_X);
shiftSprite(); shiftSprite();
if (pos_x_ == MIN_X || pos_x_ == MAX_X) if (pos_x_ == MIN_X || pos_x_ == MAX_X) {
{
setPlayingState(PlayerState::GAME_OVER); setPlayingState(PlayerState::GAME_OVER);
} }
break; break;
} }
case PlayerState::ENTERING_SCREEN: case PlayerState::ENTERING_SCREEN: {
{
++step_counter_; ++step_counter_;
if (step_counter_ % 10 == 0) if (step_counter_ % 10 == 0) {
{
playSound("walk.wav"); playSound("walk.wav");
} }
switch (id_) switch (id_) {
{
case 1: case 1:
setInputPlaying(InputAction::RIGHT); setInputPlaying(InputAction::RIGHT);
pos_x_ += vel_x_; pos_x_ += vel_x_;
if (pos_x_ > default_pos_x_) if (pos_x_ > default_pos_x_) {
{
pos_x_ = default_pos_x_; pos_x_ = default_pos_x_;
setPlayingState(PlayerState::PLAYING); setPlayingState(PlayerState::PLAYING);
setInvulnerable(false); setInvulnerable(false);
@@ -319,8 +282,7 @@ void Player::move()
case 2: case 2:
setInputPlaying(InputAction::LEFT); setInputPlaying(InputAction::LEFT);
pos_x_ += vel_x_; pos_x_ += vel_x_;
if (pos_x_ < default_pos_x_) if (pos_x_ < default_pos_x_) {
{
pos_x_ = default_pos_x_; pos_x_ = default_pos_x_;
setPlayingState(PlayerState::PLAYING); setPlayingState(PlayerState::PLAYING);
setInvulnerable(false); setInvulnerable(false);
@@ -332,34 +294,25 @@ void Player::move()
shiftSprite(); shiftSprite();
break; break;
} }
case PlayerState::CREDITS: case PlayerState::CREDITS: {
{
pos_x_ += vel_x_ / 2.0f; pos_x_ += vel_x_ / 2.0f;
if (vel_x_ > 0) if (vel_x_ > 0) {
{
// setInputPlaying(InputAction::RIGHT); // setInputPlaying(InputAction::RIGHT);
if (pos_x_ > param.game.game_area.rect.w - WIDTH_) if (pos_x_ > param.game.game_area.rect.w - WIDTH_) {
{
pos_x_ = param.game.game_area.rect.w - WIDTH_; pos_x_ = param.game.game_area.rect.w - WIDTH_;
vel_x_ *= -1; vel_x_ *= -1;
} }
} } else {
else
{
// setInputPlaying(InputAction::LEFT); // setInputPlaying(InputAction::LEFT);
if (pos_x_ < param.game.game_area.rect.x) if (pos_x_ < param.game.game_area.rect.x) {
{
pos_x_ = param.game.game_area.rect.x; pos_x_ = param.game.game_area.rect.x;
vel_x_ *= -1; vel_x_ *= -1;
} }
} }
if (pos_x_ > param.game.game_area.center_x - WIDTH_ / 2) if (pos_x_ > param.game.game_area.center_x - WIDTH_ / 2) {
{
setWalkingState(PlayerState::WALKING_LEFT); setWalkingState(PlayerState::WALKING_LEFT);
} } else {
else
{
setWalkingState(PlayerState::WALKING_RIGHT); setWalkingState(PlayerState::WALKING_RIGHT);
} }
shiftSprite(); shiftSprite();
@@ -371,34 +324,27 @@ void Player::move()
} }
// Pinta el jugador en pantalla // Pinta el jugador en pantalla
void Player::render() void Player::render() {
{ if (power_up_ && isPlaying()) {
if (power_up_ && isPlaying()) if (power_up_counter_ > (POWERUP_COUNTER_ / 4) || power_up_counter_ % 20 > 4) {
{
if (power_up_counter_ > (POWERUP_COUNTER_ / 4) || power_up_counter_ % 20 > 4)
{
power_sprite_->render(); power_sprite_->render();
} }
} }
if (isRenderable()) if (isRenderable()) {
{
player_sprite_->render(); player_sprite_->render();
} }
} }
// Establece la animación correspondiente al estado // Establece la animación correspondiente al estado
void Player::setAnimation() void Player::setAnimation() {
{ switch (playing_state_) {
switch (playing_state_)
{
case PlayerState::PLAYING: case PlayerState::PLAYING:
case PlayerState::ENTERING_NAME_GAME_COMPLETED: case PlayerState::ENTERING_NAME_GAME_COMPLETED:
case PlayerState::ENTERING_SCREEN: case PlayerState::ENTERING_SCREEN:
case PlayerState::LEAVING_SCREEN: case PlayerState::LEAVING_SCREEN:
case PlayerState::TITLE_ANIMATION: case PlayerState::TITLE_ANIMATION:
case PlayerState::CREDITS: case PlayerState::CREDITS: {
{
// Crea cadenas de texto para componer el nombre de la animación // Crea cadenas de texto para componer el nombre de la animación
const std::string WALK_ANIMATION = walking_state_ == PlayerState::WALKING_STOP ? "stand" : "walk"; const std::string WALK_ANIMATION = walking_state_ == PlayerState::WALKING_STOP ? "stand" : "walk";
const std::string FIRE_ANIMATION = firing_state_ == PlayerState::FIRING_UP ? "-fire-center" : "-fire-side"; const std::string FIRE_ANIMATION = firing_state_ == PlayerState::FIRING_UP ? "-fire-center" : "-fire-side";
@@ -411,26 +357,19 @@ void Player::setAnimation()
const SDL_FlipMode FLIP_COOL = firing_state_ == PlayerState::COOLING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; const SDL_FlipMode FLIP_COOL = firing_state_ == PlayerState::COOLING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
// Establece la animación a partir de las cadenas // Establece la animación a partir de las cadenas
if (firing_state_ == PlayerState::FIRING_NONE) if (firing_state_ == PlayerState::FIRING_NONE) {
{
// No esta disparando // No esta disparando
player_sprite_->setCurrentAnimation(WALK_ANIMATION, false); player_sprite_->setCurrentAnimation(WALK_ANIMATION, false);
player_sprite_->setFlip(FLIP_WALK); player_sprite_->setFlip(FLIP_WALK);
} } else if (isRecoiling()) {
else if (isRecoiling())
{
// Retroceso // Retroceso
player_sprite_->setCurrentAnimation(WALK_ANIMATION + RECOIL_ANIMATION, false); player_sprite_->setCurrentAnimation(WALK_ANIMATION + RECOIL_ANIMATION, false);
player_sprite_->setFlip(FLIP_RECOIL); player_sprite_->setFlip(FLIP_RECOIL);
} } else if (isCooling()) {
else if (isCooling())
{
// Acaba de disparar // Acaba de disparar
player_sprite_->setCurrentAnimation(WALK_ANIMATION + COOL_ANIMATION, false); player_sprite_->setCurrentAnimation(WALK_ANIMATION + COOL_ANIMATION, false);
player_sprite_->setFlip(FLIP_COOL); player_sprite_->setFlip(FLIP_COOL);
} } else {
else
{
// Está disparando // Está disparando
player_sprite_->setCurrentAnimation(WALK_ANIMATION + FIRE_ANIMATION, false); player_sprite_->setCurrentAnimation(WALK_ANIMATION + FIRE_ANIMATION, false);
// Si dispara de lado, invierte el sprite segun hacia donde dispara // Si dispara de lado, invierte el sprite segun hacia donde dispara
@@ -440,20 +379,17 @@ void Player::setAnimation()
break; break;
} }
case PlayerState::ROLLING: case PlayerState::ROLLING:
case PlayerState::CONTINUE_TIME_OUT: case PlayerState::CONTINUE_TIME_OUT: {
{
player_sprite_->setCurrentAnimation("rolling"); player_sprite_->setCurrentAnimation("rolling");
break; break;
} }
case PlayerState::LYING_ON_THE_FLOOR_FOREVER: case PlayerState::LYING_ON_THE_FLOOR_FOREVER:
case PlayerState::ENTERING_NAME: case PlayerState::ENTERING_NAME:
case PlayerState::CONTINUE: case PlayerState::CONTINUE: {
{
player_sprite_->setCurrentAnimation("dead"); player_sprite_->setCurrentAnimation("dead");
break; break;
} }
case PlayerState::CELEBRATING: case PlayerState::CELEBRATING: {
{
player_sprite_->setCurrentAnimation("celebration"); player_sprite_->setCurrentAnimation("celebration");
break; break;
} }
@@ -467,20 +403,15 @@ void Player::setAnimation()
} }
// Actualiza el valor de la variable // Actualiza el valor de la variable
void Player::updateCooldown() void Player::updateCooldown() {
{ if (playing_state_ == PlayerState::PLAYING) {
if (playing_state_ == PlayerState::PLAYING) if (cant_fire_counter_ > 0) {
{
if (cant_fire_counter_ > 0)
{
cooling_state_counter_ = COOLING_DURATION_; cooling_state_counter_ = COOLING_DURATION_;
// La mitad del tiempo que no puede disparar tiene el brazo arriba (PlayerState::FIRING) // La mitad del tiempo que no puede disparar tiene el brazo arriba (PlayerState::FIRING)
// y la otra mitad en retroceso (PlayerState::RECOILING) // y la otra mitad en retroceso (PlayerState::RECOILING)
if (cant_fire_counter_ == recoiling_state_duration_ / 2) if (cant_fire_counter_ == recoiling_state_duration_ / 2) {
{ switch (firing_state_) {
switch (firing_state_)
{
case PlayerState::FIRING_LEFT: case PlayerState::FIRING_LEFT:
setFiringState(PlayerState::RECOILING_LEFT); setFiringState(PlayerState::RECOILING_LEFT);
break; break;
@@ -496,25 +427,16 @@ void Player::updateCooldown()
} }
--cant_fire_counter_; --cant_fire_counter_;
if (cant_fire_counter_ == 0) if (cant_fire_counter_ == 0) {
{
recoiling_state_counter_ = recoiling_state_duration_; recoiling_state_counter_ = recoiling_state_duration_;
} }
} } else {
else if (recoiling_state_counter_ > 0) {
{
if (recoiling_state_counter_ > 0)
{
--recoiling_state_counter_; --recoiling_state_counter_;
} } else {
else if (cooling_state_counter_ > COOLING_COMPLETE_) {
{ if (cooling_state_counter_ == COOLING_DURATION_) {
if (cooling_state_counter_ > COOLING_COMPLETE_) switch (firing_state_) {
{
if (cooling_state_counter_ == COOLING_DURATION_)
{
switch (firing_state_)
{
case PlayerState::RECOILING_LEFT: case PlayerState::RECOILING_LEFT:
setFiringState(PlayerState::COOLING_LEFT); setFiringState(PlayerState::COOLING_LEFT);
break; break;
@@ -532,8 +454,7 @@ void Player::updateCooldown()
--cooling_state_counter_; --cooling_state_counter_;
} }
if (cooling_state_counter_ == COOLING_COMPLETE_) if (cooling_state_counter_ == COOLING_COMPLETE_) {
{
setFiringState(PlayerState::FIRING_NONE); setFiringState(PlayerState::FIRING_NONE);
cooling_state_counter_ = -1; cooling_state_counter_ = -1;
} }
@@ -543,8 +464,7 @@ void Player::updateCooldown()
} }
// Actualiza al jugador a su posicion, animación y controla los contadores // Actualiza al jugador a su posicion, animación y controla los contadores
void Player::update() void Player::update() {
{
move(); move();
setAnimation(); setAnimation();
shiftColliders(); shiftColliders();
@@ -558,27 +478,21 @@ void Player::update()
} }
// Incrementa la puntuación del jugador // Incrementa la puntuación del jugador
void Player::addScore(int score) void Player::addScore(int score) {
{ if (isPlaying()) {
if (isPlaying())
{
score_ += score; score_ += score;
} }
} }
// Actualiza el panel del marcador // Actualiza el panel del marcador
void Player::updateScoreboard() void Player::updateScoreboard() {
{ switch (playing_state_) {
switch (playing_state_) case PlayerState::CONTINUE: {
{
case PlayerState::CONTINUE:
{
Scoreboard::get()->setContinue(getScoreBoardPanel(), getContinueCounter()); Scoreboard::get()->setContinue(getScoreBoardPanel(), getContinueCounter());
break; break;
} }
case PlayerState::ENTERING_NAME: case PlayerState::ENTERING_NAME:
case PlayerState::ENTERING_NAME_GAME_COMPLETED: case PlayerState::ENTERING_NAME_GAME_COMPLETED: {
{
Scoreboard::get()->setRecordName(getScoreBoardPanel(), enter_name_->getCurrentName()); Scoreboard::get()->setRecordName(getScoreBoardPanel(), enter_name_->getCurrentName());
Scoreboard::get()->setSelectorPos(getScoreBoardPanel(), getRecordNamePos()); Scoreboard::get()->setSelectorPos(getScoreBoardPanel(), getRecordNamePos());
break; break;
@@ -589,38 +503,31 @@ void Player::updateScoreboard()
} }
// Cambia el modo del marcador // Cambia el modo del marcador
void Player::setScoreboardMode(ScoreboardMode mode) void Player::setScoreboardMode(ScoreboardMode mode) {
{ if (!demo_) {
if (!demo_)
{
Scoreboard::get()->setMode(getScoreBoardPanel(), mode); Scoreboard::get()->setMode(getScoreBoardPanel(), mode);
} }
} }
// Establece el estado del jugador en el juego // Establece el estado del jugador en el juego
void Player::setPlayingState(PlayerState state) void Player::setPlayingState(PlayerState state) {
{
playing_state_ = state; playing_state_ = state;
switch (playing_state_) switch (playing_state_) {
{ case PlayerState::RESPAWNING: {
case PlayerState::RESPAWNING:
{
setInvulnerable(true); setInvulnerable(true);
addCredit(); addCredit();
playSound("voice_thankyou.wav"); playSound("voice_thankyou.wav");
setPlayingState(PlayerState::PLAYING); setPlayingState(PlayerState::PLAYING);
} }
case PlayerState::PLAYING: case PlayerState::PLAYING: {
{
init(); init();
playing_state_ = PlayerState::PLAYING; playing_state_ = PlayerState::PLAYING;
setScoreboardMode(ScoreboardMode::SCORE); setScoreboardMode(ScoreboardMode::SCORE);
Stage::power_can_be_added = true; Stage::power_can_be_added = true;
break; break;
} }
case PlayerState::CONTINUE: case PlayerState::CONTINUE: {
{
// Inicializa el contador de continuar // Inicializa el contador de continuar
continue_ticks_ = SDL_GetTicks(); continue_ticks_ = SDL_GetTicks();
continue_counter_ = 9; continue_counter_ = 9;
@@ -628,27 +535,23 @@ void Player::setPlayingState(PlayerState state)
playSound("continue_clock.wav"); playSound("continue_clock.wav");
break; break;
} }
case PlayerState::WAITING: case PlayerState::WAITING: {
{
pos_x_ = default_pos_x_; pos_x_ = default_pos_x_;
setScoreboardMode(ScoreboardMode::WAITING); setScoreboardMode(ScoreboardMode::WAITING);
break; break;
} }
case PlayerState::ENTERING_NAME: case PlayerState::ENTERING_NAME: {
{
setScoreboardMode(ScoreboardMode::ENTER_NAME); setScoreboardMode(ScoreboardMode::ENTER_NAME);
break; break;
} }
case PlayerState::SHOWING_NAME: case PlayerState::SHOWING_NAME: {
{
showing_name_ticks_ = SDL_GetTicks(); showing_name_ticks_ = SDL_GetTicks();
setScoreboardMode(ScoreboardMode::SHOW_NAME); setScoreboardMode(ScoreboardMode::SHOW_NAME);
Scoreboard::get()->setRecordName(scoreboard_panel_, last_enter_name_); Scoreboard::get()->setRecordName(scoreboard_panel_, last_enter_name_);
addScoreToScoreBoard(); addScoreToScoreBoard();
break; break;
} }
case PlayerState::ROLLING: case PlayerState::ROLLING: {
{
// Activa la animación de rodar // Activa la animación de rodar
player_sprite_->setCurrentAnimation("rolling"); player_sprite_->setCurrentAnimation("rolling");
player_sprite_->setAnimationSpeed(4); player_sprite_->setAnimationSpeed(4);
@@ -657,21 +560,18 @@ void Player::setPlayingState(PlayerState state)
(rand() % 2 == 0) ? player_sprite_->setVelX(3.3f) : player_sprite_->setVelX(-3.3f); (rand() % 2 == 0) ? player_sprite_->setVelX(3.3f) : player_sprite_->setVelX(-3.3f);
break; break;
} }
case PlayerState::TITLE_ANIMATION: case PlayerState::TITLE_ANIMATION: {
{
// Activa la animación de rodar // Activa la animación de rodar
player_sprite_->setCurrentAnimation("walk"); player_sprite_->setCurrentAnimation("walk");
playSound("voice_thankyou.wav"); playSound("voice_thankyou.wav");
break; break;
} }
case PlayerState::TITLE_HIDDEN: case PlayerState::TITLE_HIDDEN: {
{
player_sprite_->setVelX(0.0f); player_sprite_->setVelX(0.0f);
player_sprite_->setVelY(0.0f); player_sprite_->setVelY(0.0f);
break; break;
} }
case PlayerState::CONTINUE_TIME_OUT: case PlayerState::CONTINUE_TIME_OUT: {
{
// Activa la animación de morir // Activa la animación de morir
player_sprite_->setAccelY(0.2f); player_sprite_->setAccelY(0.2f);
player_sprite_->setVelY(-4.0f); player_sprite_->setVelY(-4.0f);
@@ -683,36 +583,30 @@ void Player::setPlayingState(PlayerState state)
playSound("jump.wav"); playSound("jump.wav");
break; break;
} }
case PlayerState::GAME_OVER: case PlayerState::GAME_OVER: {
{
setScoreboardMode(ScoreboardMode::GAME_OVER); setScoreboardMode(ScoreboardMode::GAME_OVER);
break; break;
} }
case PlayerState::CELEBRATING: case PlayerState::CELEBRATING: {
{
game_completed_ = true; game_completed_ = true;
setScoreboardMode(ScoreboardMode::SCORE); setScoreboardMode(ScoreboardMode::SCORE);
break; break;
} }
case PlayerState::ENTERING_NAME_GAME_COMPLETED: case PlayerState::ENTERING_NAME_GAME_COMPLETED: {
{
setWalkingState(PlayerState::WALKING_STOP); setWalkingState(PlayerState::WALKING_STOP);
setFiringState(PlayerState::FIRING_NONE); setFiringState(PlayerState::FIRING_NONE);
setScoreboardMode(ScoreboardMode::ENTER_NAME); setScoreboardMode(ScoreboardMode::ENTER_NAME);
break; break;
} }
case PlayerState::LEAVING_SCREEN: case PlayerState::LEAVING_SCREEN: {
{
step_counter_ = 0; step_counter_ = 0;
setScoreboardMode(ScoreboardMode::GAME_COMPLETED); setScoreboardMode(ScoreboardMode::GAME_COMPLETED);
break; break;
} }
case PlayerState::ENTERING_SCREEN: case PlayerState::ENTERING_SCREEN: {
{
step_counter_ = 0; step_counter_ = 0;
setScoreboardMode(ScoreboardMode::SCORE); setScoreboardMode(ScoreboardMode::SCORE);
switch (id_) switch (id_) {
{
case 1: case 1:
pos_x_ = param.game.game_area.rect.x - WIDTH_; pos_x_ = param.game.game_area.rect.x - WIDTH_;
break; break;
@@ -726,8 +620,7 @@ void Player::setPlayingState(PlayerState state)
} }
break; break;
} }
case PlayerState::CREDITS: case PlayerState::CREDITS: {
{
vel_x_ = (walking_state_ == PlayerState::WALKING_RIGHT) ? BASE_SPEED_ : -BASE_SPEED_; vel_x_ = (walking_state_ == PlayerState::WALKING_RIGHT) ? BASE_SPEED_ : -BASE_SPEED_;
break; break;
} }
@@ -737,39 +630,31 @@ void Player::setPlayingState(PlayerState state)
} }
// Aumenta el valor de la variable hasta un máximo // Aumenta el valor de la variable hasta un máximo
void Player::incScoreMultiplier() void Player::incScoreMultiplier() {
{
score_multiplier_ += 0.1f; score_multiplier_ += 0.1f;
score_multiplier_ = std::min(score_multiplier_, 5.0f); score_multiplier_ = std::min(score_multiplier_, 5.0f);
} }
// Decrementa el valor de la variable hasta un mínimo // Decrementa el valor de la variable hasta un mínimo
void Player::decScoreMultiplier() void Player::decScoreMultiplier() {
{
score_multiplier_ -= 0.1f; score_multiplier_ -= 0.1f;
score_multiplier_ = std::max(score_multiplier_, 1.0f); score_multiplier_ = std::max(score_multiplier_, 1.0f);
} }
// Establece el valor del estado // Establece el valor del estado
void Player::setInvulnerable(bool value) void Player::setInvulnerable(bool value) {
{
invulnerable_ = value; invulnerable_ = value;
invulnerable_counter_ = invulnerable_ ? INVULNERABLE_COUNTER_ : 0; invulnerable_counter_ = invulnerable_ ? INVULNERABLE_COUNTER_ : 0;
} }
// Monitoriza el estado // Monitoriza el estado
void Player::updateInvulnerable() void Player::updateInvulnerable() {
{
if (playing_state_ == PlayerState::PLAYING) if (playing_state_ == PlayerState::PLAYING)
if (invulnerable_) if (invulnerable_) {
{ if (invulnerable_counter_ > 0) {
if (invulnerable_counter_ > 0)
{
--invulnerable_counter_; --invulnerable_counter_;
invulnerable_counter_ % 8 > 3 ? player_sprite_->getTexture()->setPalette(coffees_) : player_sprite_->getTexture()->setPalette(3); invulnerable_counter_ % 8 > 3 ? player_sprite_->getTexture()->setPalette(coffees_) : player_sprite_->getTexture()->setPalette(3);
} } else {
else
{
setInvulnerable(false); setInvulnerable(false);
player_sprite_->getTexture()->setPalette(coffees_); player_sprite_->getTexture()->setPalette(coffees_);
} }
@@ -777,39 +662,32 @@ void Player::updateInvulnerable()
} }
// Establece el valor de la variable // Establece el valor de la variable
void Player::setPowerUp() void Player::setPowerUp() {
{
power_up_ = true; power_up_ = true;
power_up_counter_ = POWERUP_COUNTER_; power_up_counter_ = POWERUP_COUNTER_;
} }
// Actualiza el valor de la variable // Actualiza el valor de la variable
void Player::updatePowerUp() void Player::updatePowerUp() {
{
if (playing_state_ == PlayerState::PLAYING) if (playing_state_ == PlayerState::PLAYING)
if (power_up_) if (power_up_) {
{
--power_up_counter_; --power_up_counter_;
power_up_ = power_up_counter_ > 0; power_up_ = power_up_counter_ > 0;
} }
} }
// Concede un toque extra al jugador // Concede un toque extra al jugador
void Player::giveExtraHit() void Player::giveExtraHit() {
{
extra_hit_ = true; extra_hit_ = true;
if (coffees_ < 2) if (coffees_ < 2) {
{
coffees_++; coffees_++;
player_sprite_->getTexture()->setPalette(coffees_); player_sprite_->getTexture()->setPalette(coffees_);
} }
} }
// Quita el toque extra al jugador // Quita el toque extra al jugador
void Player::removeExtraHit() void Player::removeExtraHit() {
{ if (coffees_ > 0) {
if (coffees_ > 0)
{
coffees_--; coffees_--;
setInvulnerable(true); setInvulnerable(true);
player_sprite_->getTexture()->setPalette(coffees_); player_sprite_->getTexture()->setPalette(coffees_);
@@ -819,76 +697,60 @@ void Player::removeExtraHit()
} }
// Actualiza el circulo de colisión a la posición del jugador // Actualiza el circulo de colisión a la posición del jugador
void Player::shiftColliders() void Player::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));
} }
// Pone las texturas del jugador // Pone las texturas del jugador
void Player::setPlayerTextures(const std::vector<std::shared_ptr<Texture>> &texture) void Player::setPlayerTextures(const std::vector<std::shared_ptr<Texture>> &texture) {
{
player_sprite_->setTexture(texture[0]); player_sprite_->setTexture(texture[0]);
power_sprite_->setTexture(texture[1]); power_sprite_->setTexture(texture[1]);
} }
// Actualiza el contador de continue // Actualiza el contador de continue
void Player::updateContinueCounter() void Player::updateContinueCounter() {
{ if (playing_state_ == PlayerState::CONTINUE) {
if (playing_state_ == PlayerState::CONTINUE)
{
constexpr int TICKS_SPEED = 1000; constexpr int TICKS_SPEED = 1000;
if (SDL_GetTicks() - continue_ticks_ > TICKS_SPEED) if (SDL_GetTicks() - continue_ticks_ > TICKS_SPEED) {
{
decContinueCounter(); decContinueCounter();
} }
} }
} }
// Actualiza el contador de entrar nombre // Actualiza el contador de entrar nombre
void Player::updateEnterNameCounter() void Player::updateEnterNameCounter() {
{ if (playing_state_ == PlayerState::ENTERING_NAME || playing_state_ == PlayerState::ENTERING_NAME_GAME_COMPLETED) {
if (playing_state_ == PlayerState::ENTERING_NAME || playing_state_ == PlayerState::ENTERING_NAME_GAME_COMPLETED)
{
constexpr int TICKS_SPEED = 1000; constexpr int TICKS_SPEED = 1000;
if (SDL_GetTicks() - name_entry_ticks_ > TICKS_SPEED) if (SDL_GetTicks() - name_entry_ticks_ > TICKS_SPEED) {
{
decNameEntryCounter(); decNameEntryCounter();
} }
} }
} }
// Actualiza el estado de SHOWING_NAME // Actualiza el estado de SHOWING_NAME
void Player::updateShowingName() void Player::updateShowingName() {
{ if (playing_state_ == PlayerState::SHOWING_NAME) {
if (playing_state_ == PlayerState::SHOWING_NAME)
{
constexpr int TICKS_SPEED = 5000; constexpr int TICKS_SPEED = 5000;
if (SDL_GetTicks() - name_entry_ticks_ > TICKS_SPEED) if (SDL_GetTicks() - name_entry_ticks_ > TICKS_SPEED) {
{
game_completed_ ? setPlayingState(PlayerState::LEAVING_SCREEN) : setPlayingState(PlayerState::CONTINUE); game_completed_ ? setPlayingState(PlayerState::LEAVING_SCREEN) : setPlayingState(PlayerState::CONTINUE);
} }
} }
} }
// Decrementa el contador de continuar // Decrementa el contador de continuar
void Player::decContinueCounter() void Player::decContinueCounter() {
{
continue_ticks_ = SDL_GetTicks(); continue_ticks_ = SDL_GetTicks();
--continue_counter_; --continue_counter_;
if (continue_counter_ < 0) if (continue_counter_ < 0) {
{
setPlayingState(PlayerState::CONTINUE_TIME_OUT); setPlayingState(PlayerState::CONTINUE_TIME_OUT);
} } else {
else
{
playSound("continue_clock.wav"); playSound("continue_clock.wav");
} }
} }
// Decrementa el contador de entrar nombre // Decrementa el contador de entrar nombre
void Player::decNameEntryCounter() void Player::decNameEntryCounter() {
{
name_entry_ticks_ = SDL_GetTicks(); name_entry_ticks_ = SDL_GetTicks();
// Actualiza contadores // Actualiza contadores
@@ -897,27 +759,21 @@ void Player::decNameEntryCounter()
// Comprueba los contadores // Comprueba los contadores
if ((name_entry_total_counter_ >= param.game.name_entry_total_time) || if ((name_entry_total_counter_ >= param.game.name_entry_total_time) ||
(name_entry_idle_counter_ >= param.game.name_entry_idle_time)) (name_entry_idle_counter_ >= param.game.name_entry_idle_time)) {
{
name_entry_total_counter_ = 0; name_entry_total_counter_ = 0;
name_entry_idle_counter_ = 0; name_entry_idle_counter_ = 0;
if (playing_state_ == PlayerState::ENTERING_NAME) if (playing_state_ == PlayerState::ENTERING_NAME) {
{
last_enter_name_ = getRecordName(); last_enter_name_ = getRecordName();
setPlayingState(PlayerState::SHOWING_NAME); setPlayingState(PlayerState::SHOWING_NAME);
} } else {
else
{
setPlayingState(PlayerState::LEAVING_SCREEN); setPlayingState(PlayerState::LEAVING_SCREEN);
} }
} }
} }
// Obtiene la posición que se está editando del nombre del jugador para la tabla de mejores puntuaciones // Obtiene la posición que se está editando del nombre del jugador para la tabla de mejores puntuaciones
int Player::getRecordNamePos() const int Player::getRecordNamePos() const {
{ if (enter_name_) {
if (enter_name_)
{
return enter_name_->getPosition(); return enter_name_->getPosition();
} }
@@ -925,15 +781,13 @@ int Player::getRecordNamePos() const
} }
// Recoloca los sprites // Recoloca los sprites
void Player::shiftSprite() void Player::shiftSprite() {
{
player_sprite_->setPosX(pos_x_); player_sprite_->setPosX(pos_x_);
player_sprite_->setPosY(pos_y_); player_sprite_->setPosY(pos_y_);
power_sprite_->setPosX(getPosX() - power_up_desp_x_); power_sprite_->setPosX(getPosX() - power_up_desp_x_);
} }
void Player::playSound(const std::string &name) void Player::playSound(const std::string &name) {
{
if (demo_) if (demo_)
return; return;
@@ -942,8 +796,7 @@ void Player::playSound(const std::string &name)
} }
// Añade una puntuación a la tabla de records // Añade una puntuación a la tabla de records
void Player::addScoreToScoreBoard() void Player::addScoreToScoreBoard() {
{
const auto entry = HiScoreEntry(trim(getLastEnterName()), getScore(), get1CC()); const auto entry = HiScoreEntry(trim(getLastEnterName()), getScore(), get1CC());
auto manager = std::make_unique<ManageHiScoreTable>(Options::settings.hi_score_table); auto manager = std::make_unique<ManageHiScoreTable>(Options::settings.hi_score_table);
Options::settings.last_hi_score_entry.at(getId() - 1) = manager->add(entry); Options::settings.last_hi_score_entry.at(getId() - 1) = manager->add(entry);

View File

@@ -1,6 +1,7 @@
#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 <memory> // Para unique_ptr, shared_ptr
#include <string> // Para basic_string, string #include <string> // Para basic_string, string
#include <vector> // Para vector #include <vector> // Para vector
@@ -16,8 +17,7 @@ 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
@@ -60,9 +60,8 @@ enum class PlayerState
}; };
// --- 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;
@@ -160,7 +159,7 @@ 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

View File

@@ -2,6 +2,7 @@
#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
@@ -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();
@@ -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,19 +409,15 @@ 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); exit(0);
break; break;
case SDL_EVENT_KEY_DOWN: case SDL_EVENT_KEY_DOWN:
if (event.key.key == SDLK_ESCAPE) if (event.key.key == SDLK_ESCAPE) {
{
exit(0); exit(0);
} }
break; break;
@@ -483,8 +426,7 @@ void Resource::checkEvents()
} }
// 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();
} }

View File

@@ -2,6 +2,7 @@
#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 <memory> // Para shared_ptr
#include <string> // Para basic_string, string #include <string> // Para basic_string, string
#include <vector> // Para vector #include <vector> // Para vector
@@ -15,9 +16,8 @@ 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
@@ -36,10 +36,9 @@ public:
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
@@ -47,8 +46,7 @@ private:
: 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
@@ -56,8 +54,7 @@ private:
: 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
@@ -65,8 +62,7 @@ private:
: 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
@@ -74,8 +70,7 @@ private:
: 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
@@ -83,8 +78,7 @@ private:
: 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
@@ -93,8 +87,7 @@ private:
}; };
// --- 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
@@ -103,8 +96,7 @@ private:
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;
} }
}; };

View File

@@ -2,6 +2,7 @@
#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 <iomanip> // Para operator<<, setfill, setw
#include <sstream> // Para basic_ostringstream, basic_ostream, basic_os... #include <sstream> // Para basic_ostringstream, basic_ostream, basic_os...
@@ -18,20 +19,17 @@
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_;
} }
@@ -40,11 +38,9 @@ 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(); name_[i].clear();
record_name_[i].clear(); record_name_[i].clear();
selector_pos_[i] = 0; selector_pos_[i] = 0;
@@ -79,59 +75,49 @@ Scoreboard::Scoreboard()
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;
@@ -144,8 +130,7 @@ void Scoreboard::setColor(Color color)
} }
// 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
@@ -155,14 +140,12 @@ void Scoreboard::setPos(SDL_FRect rect)
} }
// 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]);
@@ -170,10 +153,8 @@ void Scoreboard::fillPanelTextures()
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 // SCORE
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_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_); text_scoreboard_->writeDX(TEXT_COLOR | TEXT_CENTER, slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]), 1, text_color2_);
@@ -184,50 +165,43 @@ void Scoreboard::fillPanelTextures()
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_);
@@ -244,8 +218,7 @@ void Scoreboard::fillPanelTextures()
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_);
@@ -256,8 +229,7 @@ void Scoreboard::fillPanelTextures()
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_);
@@ -268,23 +240,19 @@ void Scoreboard::fillPanelTextures()
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_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_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);
} }
} }
@@ -293,8 +261,7 @@ void Scoreboard::fillPanelTextures()
} }
break; break;
} }
case ScoreboardMode::SHOW_NAME: case ScoreboardMode::SHOW_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_);
@@ -309,14 +276,12 @@ void Scoreboard::fillPanelTextures()
// 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_);
} }
@@ -331,8 +296,7 @@ void Scoreboard::fillPanelTextures()
} }
// 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();
@@ -345,8 +309,7 @@ void Scoreboard::fillBackgroundTexture()
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);
} }
@@ -358,12 +321,10 @@ void Scoreboard::fillBackgroundTexture()
} }
// 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.x = roundf(panel_width * i);
panel_[i].pos.y = 0; panel_[i].pos.y = 0;
panel_[i].pos.w = roundf(panel_width * (i + 1)) - panel_[i].pos.x; panel_[i].pos.w = roundf(panel_width * (i + 1)) - panel_[i].pos.x;
@@ -395,19 +356,16 @@ void Scoreboard::recalculateAnchors()
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_);
} }
@@ -417,21 +375,17 @@ void Scoreboard::createBackgroundTexture()
} }
// 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) {
if (texture != nullptr)
{
SDL_DestroyTexture(texture); 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);
@@ -439,8 +393,7 @@ void Scoreboard::createPanelTextures()
} }
// 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);
@@ -448,8 +401,7 @@ void Scoreboard::renderSeparator()
} }
// 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();

View File

@@ -2,6 +2,7 @@
#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 <memory> // Para shared_ptr, unique_ptr
#include <string> // Para basic_string, string #include <string> // Para basic_string, string
#include <vector> // Para vector #include <vector> // Para vector
@@ -19,8 +20,7 @@ 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,
@@ -34,16 +34,14 @@ enum class ScoreboardMode : int
}; };
// --- 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
@@ -68,7 +66,7 @@ public:
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_;

View File

@@ -1,6 +1,7 @@
#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==
@@ -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,21 +273,17 @@ 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());
@@ -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,8 +310,7 @@ 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());
@@ -359,8 +320,7 @@ bool Screen::initSDLVideo()
// 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());
@@ -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"));
} }

View File

@@ -1,6 +1,7 @@
#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 <memory> // Para shared_ptr
#include <string> // Para basic_string, string #include <string> // Para basic_string, string
@@ -12,9 +13,8 @@ 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
@@ -60,23 +60,20 @@ public:
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; lastValue = frameCount;
frameCount = 0; frameCount = 0;
ticks = currentTicks; ticks = currentTicks;
@@ -86,8 +83,7 @@ private:
}; };
// 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
@@ -102,8 +98,7 @@ private:
}; };
// 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
@@ -117,10 +112,8 @@ private:
: 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; enabled = true;
original_pos = src_rect.x; original_pos = src_rect.x;
original_width = src_rect.w; original_width = src_rect.w;
@@ -141,24 +134,18 @@ private:
} }
// 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) {
{
if (counter > 0)
{
counter--; counter--;
} } else {
else
{
counter = delay; counter = delay;
const auto SRC_DESP = (remaining % 2 == 0) ? 0 : desp; const auto SRC_DESP = (remaining % 2 == 0) ? 0 : desp;
const auto DST_DESP = (remaining % 2 == 1) ? 0 : desp; const auto DST_DESP = (remaining % 2 == 1) ? 0 : desp;
src_rect.x = original_pos + SRC_DESP; src_rect.x = original_pos + SRC_DESP;
dst_rect.x = original_pos + DST_DESP; dst_rect.x = original_pos + DST_DESP;
remaining--; remaining--;
if (remaining == -1) if (remaining == -1) {
{
enabled = false; enabled = false;
src_rect.x = original_pos; src_rect.x = original_pos;
src_rect.w = original_width; src_rect.w = original_width;
@@ -173,8 +160,7 @@ private:
}; };
#ifdef DEBUG #ifdef DEBUG
struct Debug struct Debug {
{
std::shared_ptr<Text> text; std::shared_ptr<Text> text;
bool show = false; bool show = false;
}; };
@@ -214,7 +200,7 @@ private:
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

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
}

View File

@@ -6,11 +6,9 @@
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 RESET, // Inicialización
LOGO, // Pantalla de logo LOGO, // Pantalla de logo
INTRO, // Introducción INTRO, // Introducción
@@ -21,11 +19,10 @@ namespace Section
INSTRUCTIONS, // Instrucciones INSTRUCTIONS, // Instrucciones
CREDITS, // Créditos CREDITS, // Créditos
QUIT, // Salir del juego 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
@@ -36,17 +33,16 @@ namespace Section
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

View File

@@ -2,6 +2,7 @@
#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
@@ -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,10 +74,8 @@ 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
@@ -88,14 +84,11 @@ void Credits::run()
} }
// 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,70 +275,55 @@ 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
@@ -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,44 +415,37 @@ 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
@@ -513,22 +461,19 @@ void Credits::cycleColors()
// 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
} }
@@ -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();
} }
} }

View File

@@ -1,6 +1,7 @@
#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 <memory> // Para unique_ptr, shared_ptr
#include <vector> // Para vector #include <vector> // Para vector
@@ -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,7 +24,7 @@ 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;

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,7 @@
#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 <memory> // Para shared_ptr, unique_ptr
#include <string> // Para string #include <string> // Para string
#include <vector> // Para vector #include <vector> // Para vector
@@ -35,9 +36,8 @@ 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);
@@ -47,10 +47,9 @@ public:
// 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,
@@ -74,8 +73,7 @@ private:
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

View File

@@ -2,6 +2,7 @@
#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 <algorithm> // Para max
#include <functional> // Para function #include <functional> // Para function
#include <vector> // Para vector #include <vector> // Para vector
@@ -35,8 +36,7 @@ HiScoreTable::HiScoreTable()
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);
@@ -47,17 +47,14 @@ HiScoreTable::HiScoreTable()
} }
// 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 // Actualiza el contador de ticks
ticks_ = SDL_GetTicks(); ticks_ = SDL_GetTicks();
@@ -84,8 +81,7 @@ void HiScoreTable::update()
} }
// 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_);
@@ -96,8 +92,7 @@ void HiScoreTable::fillTexture()
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();
} }
@@ -106,8 +101,7 @@ void HiScoreTable::fillTexture()
} }
// 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();
@@ -131,28 +125,23 @@ void HiScoreTable::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(); checkInput();
update(); update();
checkEvents(); // Tiene que ir antes del render checkEvents(); // Tiene que ir antes del render
@@ -161,19 +150,16 @@ void HiScoreTable::run()
} }
// 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;
@@ -182,21 +168,18 @@ void HiScoreTable::updateFade()
} }
// 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; i = 0;
result = separator + result; result = separator + result;
} }
@@ -206,8 +189,7 @@ std::string HiScoreTable::format(int number)
} }
// 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");
@@ -232,15 +214,13 @@ void HiScoreTable::createSprites()
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;
@@ -250,17 +230,13 @@ void HiScoreTable::createSprites()
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()->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);
} } else {
else
{
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);
} }
@@ -294,24 +270,19 @@ void HiScoreTable::createSprites()
} }
// 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; const int counter2 = counter_ - init_counter;
if (counter2 % counter_between_entries == 0) if (counter2 % counter_between_entries == 0) {
{
int index = counter2 / counter_between_entries; int index = counter2 / counter_between_entries;
if (index < static_cast<int>(entry_names_.size())) if (index < static_cast<int>(entry_names_.size())) {
{
entry_names_.at(index)->enable(); entry_names_.at(index)->enable();
} }
} }
} }
for (auto const &entry : entry_names_) for (auto const &entry : entry_names_) {
{
entry->update(); entry->update();
} }
@@ -319,8 +290,7 @@ void HiScoreTable::updateSprites()
} }
// 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);
@@ -329,14 +299,12 @@ void HiScoreTable::initFade()
} }
// 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);
@@ -373,18 +341,14 @@ void HiScoreTable::initBackground()
} }
// 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 {
else
{
index = 2 * (entry_colors_.size() - 1) - n; // Retrocede: 2,1 index = 2 * (entry_colors_.size() - 1) - n; // Retrocede: 2,1
} }
@@ -392,8 +356,7 @@ Color HiScoreTable::getEntryColor(int counter_)
} }
// 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));
@@ -402,31 +365,25 @@ void HiScoreTable::iniEntryColors()
} }
// 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) {
if (entry_index != -1)
{
entry_names_.at(entry_index)->getTexture()->setColor(entry_color); 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();
} }
} }

View File

@@ -1,6 +1,7 @@
#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 <memory> // Para unique_ptr, shared_ptr
#include <string> // Para string #include <string> // Para string
#include <vector> // Para vector #include <vector> // Para vector
@@ -25,9 +26,8 @@ struct Path;
*/ */
// Clase HiScoreTable // Clase HiScoreTable
class HiScoreTable class HiScoreTable {
{ public:
public:
// Constructor // Constructor
HiScoreTable(); HiScoreTable();
@@ -37,7 +37,7 @@ public:
// 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

View File

@@ -1,6 +1,7 @@
#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 <algorithm> // Para max
#include <array> // Para array #include <array> // Para array
#include <string> // Para basic_string, string #include <string> // Para basic_string, string
@@ -29,8 +30,7 @@ Instructions::Instructions()
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);
@@ -58,8 +58,7 @@ Instructions::Instructions()
} }
// Destructor // Destructor
Instructions::~Instructions() Instructions::~Instructions() {
{
item_textures_.clear(); item_textures_.clear();
sprites_.clear(); sprites_.clear();
@@ -68,8 +67,7 @@ Instructions::~Instructions()
} }
// 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"));
@@ -78,8 +76,7 @@ void Instructions::iniSprites()
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));
@@ -87,8 +84,7 @@ void Instructions::iniSprites()
} }
// 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
@@ -113,8 +109,7 @@ void Instructions::updateSprites()
} }
// 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
@@ -148,8 +143,7 @@ void Instructions::fillTexture()
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;
} }
@@ -186,8 +180,7 @@ void Instructions::fillTexture()
} }
// 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_);
@@ -200,8 +193,7 @@ void Instructions::fillBackbuffer()
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();
} }
@@ -210,10 +202,8 @@ void Instructions::fillBackbuffer()
} }
// 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 // Actualiza el contador de ticks
ticks_ = SDL_GetTicks(); ticks_ = SDL_GetTicks();
@@ -241,8 +231,7 @@ void Instructions::update()
} }
// 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();
@@ -265,28 +254,23 @@ void Instructions::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(); checkInput();
update(); update();
checkEvents(); // Tiene que ir antes del render checkEvents(); // Tiene que ir antes del render
@@ -295,11 +279,9 @@ void Instructions::run()
} }
// 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 int direction = (y % 2 == 0) ? -1 : 1; // Pares a la izquierda, impares a la derecha
lines.emplace_back(y, 0.0f, direction); lines.emplace_back(y, 0.0f, direction);
} }
@@ -307,27 +289,22 @@ std::vector<Line> Instructions::initializeLines(int height)
} }
// 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
} }
@@ -341,10 +318,8 @@ bool Instructions::moveLines(std::vector<Line> &lines, int width, float duration
} }
// 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 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 dstRect = {static_cast<float>(LINE.x), static_cast<float>(LINE.y), 320, 1};
SDL_RenderTexture(renderer, texture, &srcRect, &dstRect); SDL_RenderTexture(renderer, texture, &srcRect, &dstRect);
@@ -352,30 +327,24 @@ void Instructions::renderLines(SDL_Renderer *renderer, SDL_Texture *texture, con
} }
// 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 // Activa el temporizador si no ha sido activado
start_delay_triggered_ = true; start_delay_triggered_ = true;
start_delay_time_ = SDL_GetTicks(); start_delay_time_ = SDL_GetTicks();
} } else if (SDL_GetTicks() - start_delay_time_ >= 4000) {
else if (SDL_GetTicks() - start_delay_time_ >= 4000)
{
// Han pasado tres segundos, mover líneas // Han pasado tres segundos, mover líneas
all_lines_off_screen_ = moveLines(lines_, 320, 1.0f, 5); 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;
} }

View File

@@ -1,6 +1,7 @@
#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 <memory> // Para unique_ptr, shared_ptr
#include <vector> // Para vector #include <vector> // Para vector
@@ -24,8 +25,7 @@ class TiledBG;
*/ */
// 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
@@ -37,9 +37,8 @@ struct Line
}; };
// Clase Instructions // Clase Instructions
class Instructions class Instructions {
{ public:
public:
// Constructor // Constructor
Instructions(); Instructions();
@@ -49,7 +48,7 @@ public:
// 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

View File

@@ -1,6 +1,7 @@
#include "intro.h" #include "intro.h"
#include <SDL3/SDL.h> // Para SDL_GetTicks, SDL_SetRenderDrawColor, SDL... #include <SDL3/SDL.h> // Para SDL_GetTicks, SDL_SetRenderDrawColor, SDL...
#include <array> // Para array #include <array> // Para array
#include <functional> // Para function #include <functional> // Para function
#include <iostream> // Para basic_ostream, basic_ostream::operator<< #include <iostream> // Para basic_ostream, basic_ostream::operator<<
@@ -29,8 +30,7 @@
// Constructor // Constructor
Intro::Intro() Intro::Intro()
: tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::DIAGONAL)) : tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::DIAGONAL)) {
{
// Inicializa variables // Inicializa variables
Section::name = Section::Name::INTRO; Section::name = Section::Name::INTRO;
Section::options = Section::Options::NONE; Section::options = Section::Options::NONE;
@@ -47,17 +47,13 @@ Intro::Intro()
} }
// Comprueba los eventos // Comprueba los eventos
void Intro::checkEvents() void Intro::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.intro.bg_color; static Color color = param.intro.bg_color;
switch (event.key.key) switch (event.key.key) {
{
case SDLK_A: case SDLK_A:
if (color.r < 255) if (color.r < 255)
++color.r; ++color.r;
@@ -122,78 +118,65 @@ void Intro::checkEvents()
} }
// Comprueba las entradas // Comprueba las entradas
void Intro::checkInput() void Intro::checkInput() {
{
Input::get()->update(); Input::get()->update();
GlobalInputs::check(); GlobalInputs::check();
} }
// Actualiza las escenas de la intro // Actualiza las escenas de la intro
void Intro::updateScenes() void Intro::updateScenes() {
{ switch (scene_) {
switch (scene_) case 0: {
{
case 0:
{
// Primera imagen - UPV // Primera imagen - UPV
card_sprites_.at(0)->enable(); card_sprites_.at(0)->enable();
shadow_sprites_.at(0)->enable(); shadow_sprites_.at(0)->enable();
// Primer texto de la primera imagen // Primer texto de la primera imagen
if (card_sprites_.at(0)->hasFinished() && !texts_.at(0)->hasFinished()) if (card_sprites_.at(0)->hasFinished() && !texts_.at(0)->hasFinished()) {
{
texts_.at(0)->setEnabled(true); texts_.at(0)->setEnabled(true);
} }
// Segundo texto de la primera imagen // Segundo texto de la primera imagen
if (texts_.at(0)->hasFinished() && !texts_.at(1)->hasFinished()) if (texts_.at(0)->hasFinished() && !texts_.at(1)->hasFinished()) {
{
texts_.at(0)->setEnabled(false); texts_.at(0)->setEnabled(false);
texts_.at(1)->setEnabled(true); texts_.at(1)->setEnabled(true);
} }
// Tercer texto de la primera imagen // Tercer texto de la primera imagen
if (texts_.at(1)->hasFinished() && !texts_.at(2)->hasFinished()) if (texts_.at(1)->hasFinished() && !texts_.at(2)->hasFinished()) {
{
texts_.at(1)->setEnabled(false); texts_.at(1)->setEnabled(false);
texts_.at(2)->setEnabled(true); texts_.at(2)->setEnabled(true);
} }
// Fin de la primera escena // Fin de la primera escena
if (texts_.at(2)->hasFinished()) if (texts_.at(2)->hasFinished()) {
{
texts_.at(2)->setEnabled(false); texts_.at(2)->setEnabled(false);
scene_++; scene_++;
} }
break; break;
} }
case 1: case 1: {
{
// Segunda imagen - Máquina // Segunda imagen - Máquina
card_sprites_.at(1)->enable(); card_sprites_.at(1)->enable();
shadow_sprites_.at(1)->enable(); shadow_sprites_.at(1)->enable();
// Primer texto de la segunda imagen // Primer texto de la segunda imagen
if (card_sprites_.at(1)->hasFinished() && !texts_.at(3)->hasFinished()) if (card_sprites_.at(1)->hasFinished() && !texts_.at(3)->hasFinished()) {
{
texts_.at(3)->setEnabled(true); texts_.at(3)->setEnabled(true);
} }
// Fin de la segunda escena // Fin de la segunda escena
if (texts_.at(3)->hasFinished()) if (texts_.at(3)->hasFinished()) {
{
texts_.at(3)->setEnabled(false); texts_.at(3)->setEnabled(false);
scene_++; scene_++;
} }
break; break;
} }
case 2: case 2: {
{
// Tercera imagen junto con primer texto - GRITO // Tercera imagen junto con primer texto - GRITO
if (!texts_.at(4)->hasFinished()) if (!texts_.at(4)->hasFinished()) {
{
card_sprites_.at(2)->enable(); card_sprites_.at(2)->enable();
shadow_sprites_.at(2)->enable(); shadow_sprites_.at(2)->enable();
@@ -201,82 +184,70 @@ void Intro::updateScenes()
} }
// Fin de la tercera escena // Fin de la tercera escena
if (card_sprites_.at(2)->hasFinished() && texts_.at(4)->hasFinished()) if (card_sprites_.at(2)->hasFinished() && texts_.at(4)->hasFinished()) {
{
texts_.at(4)->setEnabled(false); texts_.at(4)->setEnabled(false);
scene_++; scene_++;
} }
break; break;
} }
case 3: case 3: {
{
// Cuarta imagen junto con primer texto - Reflexión // Cuarta imagen junto con primer texto - Reflexión
card_sprites_.at(3)->enable(); card_sprites_.at(3)->enable();
shadow_sprites_.at(3)->enable(); shadow_sprites_.at(3)->enable();
if (!texts_.at(5)->hasFinished()) if (!texts_.at(5)->hasFinished()) {
{
texts_.at(5)->setEnabled(true); texts_.at(5)->setEnabled(true);
} }
// Segundo texto de la cuarta imagen // Segundo texto de la cuarta imagen
if (texts_.at(5)->hasFinished() && !texts_.at(6)->hasFinished()) if (texts_.at(5)->hasFinished() && !texts_.at(6)->hasFinished()) {
{
texts_.at(5)->setEnabled(false); texts_.at(5)->setEnabled(false);
texts_.at(6)->setEnabled(true); texts_.at(6)->setEnabled(true);
} }
// Fin de la cuarta escena // Fin de la cuarta escena
if (card_sprites_.at(3)->hasFinished() && texts_.at(6)->hasFinished()) if (card_sprites_.at(3)->hasFinished() && texts_.at(6)->hasFinished()) {
{
texts_.at(6)->setEnabled(false); texts_.at(6)->setEnabled(false);
scene_++; scene_++;
} }
break; break;
} }
case 4: case 4: {
{
// Quinta imagen - Patada // Quinta imagen - Patada
card_sprites_.at(4)->enable(); card_sprites_.at(4)->enable();
shadow_sprites_.at(4)->enable(); shadow_sprites_.at(4)->enable();
// Primer texto de la quinta imagen // Primer texto de la quinta imagen
if (!texts_.at(7)->hasFinished()) if (!texts_.at(7)->hasFinished()) {
{
texts_.at(7)->setEnabled(true); texts_.at(7)->setEnabled(true);
} }
// Fin de la quinta escena // Fin de la quinta escena
if (card_sprites_.at(4)->hasFinished() && texts_.at(7)->hasFinished()) if (card_sprites_.at(4)->hasFinished() && texts_.at(7)->hasFinished()) {
{
texts_.at(7)->setEnabled(false); texts_.at(7)->setEnabled(false);
scene_++; scene_++;
} }
break; break;
} }
case 5: case 5: {
{
// Sexta imagen junto con texto - Globos de café // Sexta imagen junto con texto - Globos de café
card_sprites_.at(5)->enable(); card_sprites_.at(5)->enable();
shadow_sprites_.at(5)->enable(); shadow_sprites_.at(5)->enable();
if (!texts_.at(8)->hasFinished()) if (!texts_.at(8)->hasFinished()) {
{
texts_.at(8)->setEnabled(true); texts_.at(8)->setEnabled(true);
} }
// Acaba el último texto // Acaba el último texto
if (texts_.at(8)->hasFinished()) if (texts_.at(8)->hasFinished()) {
{
texts_.at(8)->setEnabled(false); texts_.at(8)->setEnabled(false);
} }
// Acaba la ultima imagen // Acaba la ultima imagen
if (card_sprites_.at(5)->hasFinished() && texts_.at(8)->hasFinished()) if (card_sprites_.at(5)->hasFinished() && texts_.at(8)->hasFinished()) {
{
state_ = IntroState::POST; state_ = IntroState::POST;
state_start_time_ = SDL_GetTicks(); state_start_time_ = SDL_GetTicks();
} }
@@ -289,18 +260,15 @@ void Intro::updateScenes()
} }
// Actualiza las variables del objeto // Actualiza las variables del objeto
void Intro::update() void Intro::update() {
{ if (SDL_GetTicks() - ticks_ > param.game.speed) {
if (SDL_GetTicks() - ticks_ > param.game.speed)
{
// Actualiza el contador de ticks // Actualiza el contador de ticks
ticks_ = SDL_GetTicks(); ticks_ = SDL_GetTicks();
// Actualiza el fondo // Actualiza el fondo
tiled_bg_->update(); tiled_bg_->update();
switch (state_) switch (state_) {
{
case IntroState::SCENES: case IntroState::SCENES:
updateSprites(); updateSprites();
updateTexts(); updateTexts();
@@ -318,8 +286,7 @@ void Intro::update()
} }
// Dibuja el objeto en pantalla // Dibuja el objeto en pantalla
void Intro::render() void Intro::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();
@@ -329,10 +296,8 @@ void Intro::render()
// Dibuja el fondo // Dibuja el fondo
tiled_bg_->render(); tiled_bg_->render();
switch (state_) switch (state_) {
{ case IntroState::SCENES: {
case IntroState::SCENES:
{
renderTextRect(); renderTextRect();
renderSprites(); renderSprites();
renderTexts(); renderTexts();
@@ -347,11 +312,9 @@ void Intro::render()
} }
// Bucle principal // Bucle principal
void Intro::run() void Intro::run() {
{
Audio::get()->playMusic("intro.ogg", 0); Audio::get()->playMusic("intro.ogg", 0);
while (Section::name == Section::Name::INTRO) while (Section::name == Section::Name::INTRO) {
{
checkInput(); checkInput();
update(); update();
checkEvents(); // Tiene que ir antes del render checkEvents(); // Tiene que ir antes del render
@@ -360,8 +323,7 @@ void Intro::run()
} }
// Inicializa las imagens // Inicializa las imagens
void Intro::initSprites() void Intro::initSprites() {
{
// Listado de imagenes a usar // Listado de imagenes a usar
const std::array<std::string, 6> TEXTURE_LIST = { const std::array<std::string, 6> TEXTURE_LIST = {
"intro1.png", "intro1.png",
@@ -382,8 +344,7 @@ void Intro::initSprites()
// Crea las texturas para las tarjetas // Crea las texturas para las tarjetas
std::vector<std::shared_ptr<Texture>> card_textures; std::vector<std::shared_ptr<Texture>> card_textures;
for (int i = 0; i < TOTAL_SPRITES; ++i) for (int i = 0; i < TOTAL_SPRITES; ++i) {
{
// Crea la textura // Crea la textura
auto card_texture = std::make_shared<Texture>(Screen::get()->getRenderer()); auto card_texture = std::make_shared<Texture>(Screen::get()->getRenderer());
card_texture->createBlank(CARD_WIDTH, CARD_HEIGHT, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET); card_texture->createBlank(CARD_WIDTH, CARD_HEIGHT, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET);
@@ -415,8 +376,7 @@ void Intro::initSprites()
} }
// Inicializa los sprites para las tarjetas // Inicializa los sprites para las tarjetas
for (int i = 0; i < TOTAL_SPRITES; ++i) for (int i = 0; i < TOTAL_SPRITES; ++i) {
{
auto sprite = std::make_unique<PathSprite>(card_textures.at(i)); auto sprite = std::make_unique<PathSprite>(card_textures.at(i));
sprite->setWidth(CARD_WIDTH); sprite->setWidth(CARD_WIDTH);
sprite->setHeight(CARD_HEIGHT); sprite->setHeight(CARD_HEIGHT);
@@ -465,8 +425,7 @@ void Intro::initSprites()
SDL_SetRenderTarget(Screen::get()->getRenderer(), temp); SDL_SetRenderTarget(Screen::get()->getRenderer(), temp);
// Inicializa los sprites para la sombras usando la texturas con la sombra // Inicializa los sprites para la sombras usando la texturas con la sombra
for (int i = 0; i < TOTAL_SPRITES; ++i) for (int i = 0; i < TOTAL_SPRITES; ++i) {
{
auto color = param.intro.shadow_color; auto color = param.intro.shadow_color;
auto sprite = std::make_unique<PathSprite>(shadow_texture); auto sprite = std::make_unique<PathSprite>(shadow_texture);
sprite->setWidth(SHADOW_SPRITE_WIDTH); sprite->setWidth(SHADOW_SPRITE_WIDTH);
@@ -489,11 +448,9 @@ void Intro::initSprites()
} }
// Inicializa los textos // Inicializa los textos
void Intro::initTexts() void Intro::initTexts() {
{
constexpr int TOTAL_TEXTS = 9; constexpr int TOTAL_TEXTS = 9;
for (int i = 0; i < TOTAL_TEXTS; ++i) for (int i = 0; i < TOTAL_TEXTS; ++i) {
{
auto w = std::make_unique<Writer>(Resource::get()->getText("04b_25_metal")); auto w = std::make_unique<Writer>(Resource::get()->getText("04b_25_metal"));
w->setPosX(0); w->setPosX(0);
w->setPosY(param.game.height - param.intro.text_distance_from_bottom); w->setPosY(param.game.height - param.intro.text_distance_from_bottom);
@@ -539,66 +496,53 @@ void Intro::initTexts()
texts_.at(8)->setCaption(Lang::getText("[INTRO] 9")); texts_.at(8)->setCaption(Lang::getText("[INTRO] 9"));
texts_.at(8)->setSpeed(20); texts_.at(8)->setSpeed(20);
for (auto &text : texts_) for (auto &text : texts_) {
{
text->center(param.game.game_area.center_x); text->center(param.game.game_area.center_x);
} }
} }
// Actualiza los sprites // Actualiza los sprites
void Intro::updateSprites() void Intro::updateSprites() {
{ for (auto &sprite : card_sprites_) {
for (auto &sprite : card_sprites_)
{
sprite->update(); sprite->update();
} }
for (auto &sprite : shadow_sprites_) for (auto &sprite : shadow_sprites_) {
{
sprite->update(); sprite->update();
} }
} }
// Actualiza los textos // Actualiza los textos
void Intro::updateTexts() void Intro::updateTexts() {
{ for (auto &text : texts_) {
for (auto &text : texts_)
{
text->update(); text->update();
} }
} }
// Dibuja los sprites // Dibuja los sprites
void Intro::renderSprites() void Intro::renderSprites() {
{
shadow_sprites_.at(scene_)->render(); shadow_sprites_.at(scene_)->render();
card_sprites_.at(scene_)->render(); card_sprites_.at(scene_)->render();
} }
// Dibuja los textos // Dibuja los textos
void Intro::renderTexts() void Intro::renderTexts() {
{ for (const auto &text : texts_) {
for (const auto &text : texts_)
{
text->render(); text->render();
} }
} }
// Actualiza el estado POST // Actualiza el estado POST
void Intro::updatePostState() void Intro::updatePostState() {
{
const Uint32 ELAPSED_TIME = SDL_GetTicks() - state_start_time_; const Uint32 ELAPSED_TIME = SDL_GetTicks() - state_start_time_;
switch (post_state_) switch (post_state_) {
{
case IntroPostState::STOP_BG: case IntroPostState::STOP_BG:
// EVENTO: Detiene el fondo después de 1 segundo // EVENTO: Detiene el fondo después de 1 segundo
if (ELAPSED_TIME >= 1000) if (ELAPSED_TIME >= 1000) {
{
tiled_bg_->stopGracefully(); tiled_bg_->stopGracefully();
if (!bg_color_.isEqualTo(param.title.bg_color)) if (!bg_color_.isEqualTo(param.title.bg_color)) {
{
bg_color_ = bg_color_.approachTo(param.title.bg_color, 1); bg_color_ = bg_color_.approachTo(param.title.bg_color, 1);
} }
@@ -606,8 +550,7 @@ void Intro::updatePostState()
} }
// Cambia de estado si el fondo se ha detenido y recuperado el color // Cambia de estado si el fondo se ha detenido y recuperado el color
if (tiled_bg_->isStopped() && bg_color_.isEqualTo(param.title.bg_color)) if (tiled_bg_->isStopped() && bg_color_.isEqualTo(param.title.bg_color)) {
{
post_state_ = IntroPostState::END; post_state_ = IntroPostState::END;
state_start_time_ = SDL_GetTicks(); state_start_time_ = SDL_GetTicks();
} }
@@ -615,8 +558,7 @@ void Intro::updatePostState()
case IntroPostState::END: case IntroPostState::END:
// Finaliza la intro después de 1 segundo // Finaliza la intro después de 1 segundo
if (ELAPSED_TIME >= 1000) if (ELAPSED_TIME >= 1000) {
{
Audio::get()->stopMusic(); Audio::get()->stopMusic();
Section::name = Section::Name::TITLE; Section::name = Section::Name::TITLE;
Section::options = Section::Options::TITLE_1; Section::options = Section::Options::TITLE_1;
@@ -628,8 +570,7 @@ void Intro::updatePostState()
} }
} }
void Intro::renderTextRect() void Intro::renderTextRect() {
{
static const float HEIGHT = Resource::get()->getText("04b_25_metal")->getCharacterSize(); static const float HEIGHT = Resource::get()->getText("04b_25_metal")->getCharacterSize();
static SDL_FRect rect = {0.0f, param.game.height - param.intro.text_distance_from_bottom - HEIGHT, param.game.width, HEIGHT * 3}; static SDL_FRect rect = {0.0f, param.game.height - param.intro.text_distance_from_bottom - HEIGHT, param.game.width, HEIGHT * 3};
SDL_SetRenderDrawColor(Screen::get()->getRenderer(), param.intro.shadow_color.r, param.intro.shadow_color.g, param.intro.shadow_color.b, param.intro.shadow_color.a); SDL_SetRenderDrawColor(Screen::get()->getRenderer(), param.intro.shadow_color.r, param.intro.shadow_color.g, param.intro.shadow_color.b, param.intro.shadow_color.a);

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para Uint32, Uint64 #include <SDL3/SDL.h> // Para Uint32, Uint64
#include <memory> // Para unique_ptr #include <memory> // Para unique_ptr
#include <vector> // Para vector #include <vector> // Para vector
@@ -16,9 +17,8 @@
*/ */
// Clase Intro // Clase Intro
class Intro class Intro {
{ public:
public:
// Constructor // Constructor
Intro(); Intro();
@@ -28,16 +28,14 @@ public:
// 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,
}; };

View File

@@ -1,6 +1,7 @@
#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 <string> // Para basic_string
#include <utility> // Para move #include <utility> // Para move
@@ -20,9 +21,7 @@
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 // Inicializa variables
Section::name = Section::Name::LOGO; Section::name = Section::Name::LOGO;
dest_.x = param.game.game_area.center_x - jail_texture_->getWidth() / 2; dest_.x = param.game.game_area.center_x - jail_texture_->getWidth() / 2;
@@ -37,8 +36,7 @@ Logo::Logo()
since_texture_->setColor(0x00, 0x00, 0x00); since_texture_->setColor(0x00, 0x00, 0x00);
// Crea los sprites de cada linea // Crea los sprites de cada linea
for (int i = 0; i < jail_texture_->getHeight(); ++i) for (int i = 0; i < jail_texture_->getHeight(); ++i) {
{
auto temp = std::make_unique<Sprite>(jail_texture_, 0, i, jail_texture_->getWidth(), 1); auto temp = std::make_unique<Sprite>(jail_texture_, 0, i, jail_texture_->getWidth(), 1);
temp->setSpriteClip(0, i, jail_texture_->getWidth(), 1); temp->setSpriteClip(0, i, jail_texture_->getWidth(), 1);
const int POS_X = (i % 2 == 0) ? param.game.width + (i * 3) : -jail_texture_->getWidth() - (i * 3); const int POS_X = (i % 2 == 0) ? param.game.width + (i * 3) : -jail_texture_->getWidth() - (i * 3);
@@ -59,8 +57,7 @@ Logo::Logo()
} }
// 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();
@@ -68,49 +65,36 @@ Logo::~Logo()
} }
// 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)
{
if (i % 2 == 0)
{
jail_sprite_[i]->incX(-SPEED); jail_sprite_[i]->incX(-SPEED);
if (jail_sprite_[i]->getX() < dest_.x) if (jail_sprite_[i]->getX() < dest_.x) {
{
jail_sprite_[i]->setX(dest_.x); jail_sprite_[i]->setX(dest_.x);
} }
} } else {
else
{
jail_sprite_[i]->incX(SPEED); jail_sprite_[i]->incX(SPEED);
if (jail_sprite_[i]->getX() > dest_.x) if (jail_sprite_[i]->getX() > dest_.x) {
{
jail_sprite_[i]->setX(dest_.x); jail_sprite_[i]->setX(dest_.x);
} }
} }
@@ -119,31 +103,25 @@ void Logo::updateJAILGAMES()
} }
// 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); 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); since_texture_->setColor(color_[6 - i].r, color_[6 - i].g, color_[6 - i].b);
} }
@@ -151,10 +129,8 @@ void Logo::updateTextureColors()
} }
// 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 // Actualiza el contador de ticks
ticks_ = SDL_GetTicks(); ticks_ = SDL_GetTicks();
@@ -173,8 +149,7 @@ void Logo::update()
} }
// Dibuja en pantalla // Dibuja en pantalla
void Logo::render() void Logo::render() {
{
Screen::get()->start(); Screen::get()->start();
Screen::get()->clean(); Screen::get()->clean();
@@ -184,10 +159,8 @@ void Logo::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(); checkInput();
update(); update();
checkEvents(); // Tiene que ir antes del render checkEvents(); // Tiene que ir antes del render
@@ -196,16 +169,13 @@ void Logo::run()
} }
// 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();
} }
} }

View File

@@ -1,6 +1,7 @@
#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 <memory> // Para shared_ptr, unique_ptr
#include <vector> // Para vector #include <vector> // Para vector
@@ -17,9 +18,8 @@ struct Color;
*/ */
// --- Clase Logo --- // --- Clase Logo ---
class Logo class Logo {
{ public:
public:
// Constructor // Constructor
Logo(); Logo();
@@ -29,7 +29,7 @@ public:
// 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

View File

@@ -2,6 +2,7 @@
#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 <algorithm> // Para find_if
#include <iostream> // Para basic_ostream, basic_ostream::operator<< #include <iostream> // Para basic_ostream, basic_ostream::operator<<
#include <string> // Para basic_string, char_traits, operator+ #include <string> // Para basic_string, char_traits, operator+
@@ -43,8 +44,7 @@ Title::Title()
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();
@@ -67,20 +67,16 @@ Title::Title()
} }
// 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(); ticks_ = SDL_GetTicks();
updateFade(); updateFade();
updateState(); updateState();
@@ -91,8 +87,7 @@ void Title::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();
@@ -109,17 +104,13 @@ void Title::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: case SDLK_A:
if (color.r < 255) if (color.r < 255)
++color.r; ++color.r;
@@ -180,10 +171,8 @@ void Title::checkEvents()
<< 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 case SDLK_1: // Redefine los botones del mando #0
define_buttons_->enable(0); define_buttons_->enable(0);
resetCounter(); resetCounter();
@@ -220,28 +209,21 @@ void Title::checkEvents()
} }
// 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 // Boton START
if (Input::get()->checkInput(InputAction::START, INPUT_DO_NOT_ALLOW_REPEAT, CONTROLLER.type, CONTROLLER.index)) if (Input::get()->checkInput(InputAction::START, INPUT_DO_NOT_ALLOW_REPEAT, CONTROLLER.type, CONTROLLER.index)) {
{ if ((state_ != TitleState::LOGO_ANIMATING || ALLOW_TITLE_ANIMATION_SKIP)) {
if ((state_ != TitleState::LOGO_ANIMATING || ALLOW_TITLE_ANIMATION_SKIP)) if (CONTROLLER.player_id == 1) {
{ if (!player1_start_pressed_) {
if (CONTROLLER.player_id == 1)
{
if (!player1_start_pressed_)
{
player1_start_pressed_ = true; player1_start_pressed_ = true;
getPlayer(1)->setPlayingState(PlayerState::TITLE_ANIMATION); getPlayer(1)->setPlayingState(PlayerState::TITLE_ANIMATION);
setState(TitleState::START_HAS_BEEN_PRESSED); setState(TitleState::START_HAS_BEEN_PRESSED);
@@ -249,10 +231,8 @@ void Title::checkInput()
} }
} }
if (CONTROLLER.player_id == 2) if (CONTROLLER.player_id == 2) {
{ if (!player2_start_pressed_) {
if (!player2_start_pressed_)
{
player2_start_pressed_ = true; player2_start_pressed_ = true;
getPlayer(2)->setPlayingState(PlayerState::TITLE_ANIMATION); getPlayer(2)->setPlayingState(PlayerState::TITLE_ANIMATION);
setState(TitleState::START_HAS_BEEN_PRESSED); setState(TitleState::START_HAS_BEEN_PRESSED);
@@ -269,10 +249,8 @@ void Title::checkInput()
} }
// 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(); checkInput();
update(); update();
checkEvents(); // Tiene que ir antes del render checkEvents(); // Tiene que ir antes del render
@@ -284,8 +262,7 @@ void Title::run()
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;
@@ -294,34 +271,29 @@ void Title::swapControllers()
} }
// 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;
} }
} }
@@ -331,15 +303,12 @@ void Title::showControllers()
} }
// 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;
@@ -366,22 +335,17 @@ void Title::updateFade()
} }
// 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: {
case TitleState::LOGO_ANIMATING:
{
game_logo_->update(); game_logo_->update();
if (game_logo_->hasFinished()) if (game_logo_->hasFinished()) {
{
setState(TitleState::LOGO_FINISHED); setState(TitleState::LOGO_FINISHED);
} }
break; break;
} }
case TitleState::LOGO_FINISHED: case TitleState::LOGO_FINISHED: {
{
// El contador solo sube si no estamos definiendo botones // El contador solo sube si no estamos definiendo botones
counter_ = define_buttons_->isEnabled() ? 0 : counter_ + 1; counter_ = define_buttons_->isEnabled() ? 0 : counter_ + 1;
@@ -391,8 +355,7 @@ void Title::updateState()
// 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();
@@ -401,16 +364,14 @@ void Title::updateState()
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_;
@@ -422,8 +383,7 @@ void Title::updateState()
} }
} }
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
@@ -433,10 +393,8 @@ void Title::updateStartPrompt()
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: case TitleState::LOGO_FINISHED:
condition_met = (time_ms % LOGO_BLINK_PERIOD) >= (LOGO_BLINK_PERIOD - LOGO_BLINK_ON_TIME); condition_met = (time_ms % LOGO_BLINK_PERIOD) >= (LOGO_BLINK_PERIOD - LOGO_BLINK_ON_TIME);
break; break;
@@ -453,10 +411,8 @@ void Title::updateStartPrompt()
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, text_->writeDX(TEXT_CENTER | TEXT_SHADOW,
param.game.game_area.center_x, param.game.game_area.center_x,
param.title.press_start_position, param.title.press_start_position,
@@ -468,10 +424,8 @@ void Title::renderStartPrompt()
} }
} }
void Title::renderCopyright() void Title::renderCopyright() {
{ if (state_ != TitleState::LOGO_ANIMATING) {
if (state_ != TitleState::LOGO_ANIMATING)
{
// Mini logo // Mini logo
mini_logo_sprite_->render(); mini_logo_sprite_->render();
@@ -488,14 +442,12 @@ void Title::renderCopyright()
} }
// 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:
@@ -508,8 +460,7 @@ void Title::setState(TitleState state)
} }
// 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
@@ -548,31 +499,24 @@ void Title::initPlayers()
} }
// 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;

View File

@@ -1,6 +1,7 @@
#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>
@@ -27,9 +28,8 @@ constexpr bool ALLOW_TITLE_ANIMATION_SKIP = false;
*/ */
// Clase Title // Clase Title
class Title class Title {
{ public:
public:
// --- Constructores y destructor --- // --- Constructores y destructor ---
Title(); Title();
~Title(); ~Title();
@@ -37,18 +37,16 @@ public:
// --- 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;
}; };

View File

@@ -3,10 +3,8 @@
#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(); MovingSprite::update();
checkMove(); checkMove();
checkFinished(); checkFinished();
@@ -14,23 +12,18 @@ void SmartSprite::update()
} }
// 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 // Comprueba si ha llegado al destino
if (getPosX() > dest_x_) if (getPosX() > dest_x_) {
{
// Lo coloca en posición // Lo coloca en posición
setPosX(dest_x_); setPosX(dest_x_);
@@ -40,11 +33,9 @@ void SmartSprite::checkMove()
} }
} }
// 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 // Lo coloca en posición
setPosX(dest_x_); setPosX(dest_x_);
@@ -55,11 +46,9 @@ void SmartSprite::checkMove()
} }
// 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 // Lo coloca en posición
setPosY(dest_y_); setPosY(dest_y_);
@@ -69,11 +58,9 @@ void SmartSprite::checkMove()
} }
} }
// 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 // Lo coloca en posición
setPosY(dest_y_); setPosY(dest_y_);
@@ -85,19 +72,14 @@ void SmartSprite::checkMove()
} }
// 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; finished_ = true;
} } else {
else
{
--finished_counter_; --finished_counter_;
} }
} }

View File

@@ -7,9 +7,8 @@
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) {}
@@ -31,7 +30,7 @@ public:
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

View File

@@ -19,28 +19,24 @@ Sprite::Sprite(std::shared_ptr<Texture> texture)
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};
} }

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);
@@ -52,7 +52,7 @@ 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

View File

@@ -3,21 +3,19 @@
#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)));
@@ -33,15 +31,13 @@ namespace Stage
power = 0; power = 0;
total_power = 0; total_power = 0;
number = 0; number = 0;
} }
// Añade poder // Añade poder
void addPower(int amount) void addPower(int amount) {
{ if (power_can_be_added) {
if (power_can_be_added)
{
power += amount; power += amount;
total_power += amount; total_power += amount;
} }
}
} }
} // namespace Stage

View File

@@ -7,11 +7,9 @@
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 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 min_menace; // Umbral mínimo de amenaza de la fase
int max_menace; // Umbral máximo de amenaza de la fase int max_menace; // Umbral máximo de amenaza de la fase
@@ -19,17 +17,17 @@ namespace Stage
// 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

View File

@@ -3,6 +3,7 @@
#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
@@ -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,30 +48,23 @@ 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) {
{
if (x_ < min_x)
{
disable(); disable();
} }
if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_ && direction_ == TabeDirection::TO_THE_RIGHT) if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_ && direction_ == TabeDirection::TO_THE_RIGHT) {
{
setRandomFlyPath(TabeDirection::TO_THE_LEFT, 80); setRandomFlyPath(TabeDirection::TO_THE_LEFT, 80);
x_ = param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_; x_ = param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_;
} }
break; break;
} }
case TabeDirection::TO_THE_RIGHT: case TabeDirection::TO_THE_RIGHT: {
{ if (x_ > max_x) {
if (x_ > max_x)
{
disable(); disable();
} }
if (x_ < param.game.game_area.rect.x && direction_ == TabeDirection::TO_THE_LEFT) if (x_ < param.game.game_area.rect.x && direction_ == TabeDirection::TO_THE_LEFT) {
{
setRandomFlyPath(TabeDirection::TO_THE_RIGHT, 80); setRandomFlyPath(TabeDirection::TO_THE_RIGHT, 80);
x_ = param.game.game_area.rect.x; x_ = param.game.game_area.rect.x;
} }
@@ -86,15 +74,11 @@ void Tabe::move()
break; break;
} }
if (fly_distance_ <= 0) if (fly_distance_ <= 0) {
{ if (waiting_counter_ > 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,18 +120,15 @@ 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; speed_ = -1.0f * SPEED;
accel_ = -1.0f * (1 + rand() % 10) / 30.0f; accel_ = -1.0f * (1 + rand() % 10) / 30.0f;
sprite_->setFlip(SDL_FLIP_NONE); sprite_->setFlip(SDL_FLIP_NONE);
break; 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);
@@ -163,14 +141,11 @@ void Tabe::setRandomFlyPath(TabeDirection direction, int lenght)
} }
// 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;
@@ -188,23 +163,18 @@ void Tabe::setState(TabeState state)
} }
// 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();
} }

View File

@@ -2,26 +2,24 @@
#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 <memory> // Para unique_ptr
#include "animated_sprite.h" // Para AnimatedSprite #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
@@ -31,48 +29,39 @@ struct TabeTimer
// 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;
@@ -88,7 +77,7 @@ public:
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;

View File

@@ -2,6 +2,7 @@
#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 <fstream> // Para basic_ifstream, basic_istream, basic_ostream
#include <iostream> // Para cerr #include <iostream> // Para cerr
#include <stdexcept> // Para runtime_error #include <stdexcept> // Para runtime_error
@@ -12,13 +13,11 @@
#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;
@@ -29,8 +28,7 @@ std::shared_ptr<TextFile> loadTextFile(const std::string &file_path)
// 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
@@ -45,8 +43,7 @@ std::shared_ptr<TextFile> loadTextFile(const std::string &file_path)
// 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);
@@ -62,15 +59,13 @@ std::shared_ptr<TextFile> loadTextFile(const std::string &file_path)
} }
// 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;
} }
@@ -79,16 +74,14 @@ std::shared_ptr<TextFile> loadTextFile(const std::string &file_path)
} }
// 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;
@@ -102,13 +95,11 @@ Text::Text(std::shared_ptr<Texture> texture, const std::string &text_file)
} }
// 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].x = text_file->offset[i].x;
offset_[i].y = text_file->offset[i].y; offset_[i].y = text_file->offset[i].y;
offset_[i].w = text_file->offset[i].w; offset_[i].w = text_file->offset[i].w;
@@ -122,16 +113,14 @@ Text::Text(std::shared_ptr<Texture> texture, std::shared_ptr<TextFile> text_file
} }
// 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);
@@ -141,11 +130,9 @@ void Text::write(int x, int y, const std::string &text, int kerning, int lenght)
} }
// 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]); 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_)}; 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_)};
sprite_->getTexture()->render(x + shift, y, &rect, 2.0f, 2.0f); sprite_->getTexture()->render(x + shift, y, &rect, 2.0f, 2.0f);
@@ -154,8 +141,7 @@ void Text::write2X(int x, int y, const std::string &text, int kerning)
} }
// 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;
@@ -173,8 +159,7 @@ std::shared_ptr<Texture> Text::writeToTexture(const std::string &text, int zoom,
} }
// 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;
@@ -192,16 +177,14 @@ std::shared_ptr<Texture> Text::writeDXToTexture(Uint8 flags, const std::string &
} }
// 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);
@@ -209,57 +192,45 @@ void Text::writeShadowed(int x, int y, const std::string &text, Color color, Uin
} }
// 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)
{
for (int dx = -dist; dx <= dist; ++dx)
{
writeColored(x + dx, y + dy, text, shadow_color, kerning, lenght); 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 {
else
{
write(x, y, text, kerning, lenght); 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);
@@ -269,20 +240,17 @@ int Text::lenght(const std::string &text, int kerning) const
} }
// 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);

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <SDL3/SDL.h> // Para Uint8 #include <SDL3/SDL.h> // Para Uint8
#include <memory> // Para unique_ptr, shared_ptr #include <memory> // Para unique_ptr, shared_ptr
#include <string> // Para string #include <string> // Para string
@@ -16,13 +17,11 @@ 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
@@ -32,9 +31,8 @@ struct TextFile
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);
@@ -62,7 +60,7 @@ public:
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

View File

@@ -3,6 +3,7 @@
#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 <cstring> // Para memcpy
#include <fstream> // Para basic_ifstream, basic_istream, basic_ios #include <fstream> // Para basic_ifstream, basic_istream, basic_ios
#include <sstream> // Para basic_istringstream #include <sstream> // Para basic_istringstream
@@ -17,23 +18,19 @@
// 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 // Obtiene la extensión
const std::string extension = path_.substr(path_.find_last_of(".") + 1); 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_);
@@ -49,29 +46,24 @@ Texture::Texture(SDL_Renderer *renderer, const std::string &path)
} }
// 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 {
else
{
printWithDots("Texture : ", getFileName(file_path), "[ LOADED ]"); printWithDots("Texture : ", getFileName(file_path), "[ LOADED ]");
} }
@@ -90,20 +82,14 @@ bool Texture::loadFromFile(const std::string &file_path)
// 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 {
else
{
// Crea la textura desde los pixels de la surface // Crea la textura desde los pixels de la surface
new_texture = SDL_CreateTextureFromSurface(renderer_, loaded_surface); new_texture = SDL_CreateTextureFromSurface(renderer_, loaded_surface);
if (new_texture == nullptr) if (new_texture == nullptr) {
{
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create texture from %s! SDL Error: %s", file_path.c_str(), SDL_GetError()); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create texture from %s! SDL Error: %s", file_path.c_str(), SDL_GetError());
} } else {
else
{
// Obtiene las dimensiones de la imagen // Obtiene las dimensiones de la imagen
width_ = loaded_surface->w; width_ = loaded_surface->w;
height_ = loaded_surface->h; height_ = loaded_surface->h;
@@ -120,16 +106,12 @@ bool Texture::loadFromFile(const std::string &file_path)
} }
// 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()); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Unable to create blank texture! SDL Error: %s", SDL_GetError());
} } else {
else
{
width_ = width; width_ = width;
height_ = height; height_ = height;
} }
@@ -138,11 +120,9 @@ bool Texture::createBlank(int width, int height, SDL_PixelFormat format, SDL_Tex
} }
// 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_); SDL_DestroyTexture(texture_);
texture_ = nullptr; texture_ = nullptr;
width_ = 0; width_ = 0;
@@ -151,43 +131,36 @@ void Texture::unloadTexture()
} }
// 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;
@@ -201,53 +174,45 @@ void Texture::render(int x, int y, SDL_FRect *clip, float zoomW, float zoomH, do
} }
// 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);
} }
@@ -258,8 +223,7 @@ std::shared_ptr<Surface> Texture::loadSurface(const std::string &file_path)
// 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);
} }
@@ -268,8 +232,7 @@ std::shared_ptr<Surface> Texture::loadSurface(const std::string &file_path)
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;
} }
@@ -290,8 +253,7 @@ std::shared_ptr<Surface> Texture::loadSurface(const std::string &file_path)
} }
// 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_);
@@ -303,33 +265,27 @@ void Texture::flipSurface()
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 {
else
{
printWithDots("Palette : ", getFileName(file_path), "[ LOADED ]"); printWithDots("Palette : ", getFileName(file_path), "[ LOADED ]");
} }
@@ -338,8 +294,7 @@ Palette Texture::loadPaletteFromFile(const std::string &file_path)
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);
} }
@@ -347,15 +302,13 @@ Palette Texture::loadPaletteFromFile(const std::string &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
} }
@@ -364,24 +317,20 @@ Palette Texture::loadPaletteFromFile(const std::string &file_path)
} }
// 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; current_palette_ = palette;
flipSurface(); flipSurface();
} }
@@ -391,14 +340,12 @@ void Texture::setPalette(size_t palette)
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");
} }
@@ -406,28 +353,24 @@ Palette Texture::readPalFile(const std::string &file_path)
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;
} }
} }

View File

@@ -2,6 +2,7 @@
#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 <array> // Para array
#include <memory> // Para shared_ptr #include <memory> // Para shared_ptr
#include <string> // Para string, basic_string #include <string> // Para string, basic_string
@@ -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,9 +24,8 @@ 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();
@@ -58,7 +57,7 @@ public:
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

View File

@@ -2,6 +2,7 @@
#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 <cmath> // Para sin
#include <memory> // Para unique_ptr, make_unique #include <memory> // Para unique_ptr, make_unique
#include <string> // Para basic_string #include <string> // Para basic_string
@@ -14,8 +15,7 @@
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,8 +23,7 @@ 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;
@@ -41,21 +40,18 @@ TiledBG::TiledBG(SDL_FRect pos, TiledBGMode mode)
} }
// 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,29 +76,24 @@ 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 // El tileado de fondo se desplaza en diagonal
window_.x = static_cast<int>(desp_) % TILE_WIDTH_; window_.x = static_cast<int>(desp_) % TILE_WIDTH_;
window_.y = static_cast<int>(desp_) % TILE_HEIGHT_; 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;
@@ -118,27 +107,22 @@ void TiledBG::update()
} }
// 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"
} }

Some files were not shown because too many files have changed in this diff Show More