From 09a205a2882f03d22bc11ab955c78a954b4fe9be Mon Sep 17 00:00:00 2001 From: Sergio Valor Martinez Date: Mon, 5 Dec 2022 09:13:04 +0100 Subject: [PATCH] Actualizando las clases comunes a sus ultimas versiones --- source/common/notify.cpp | 146 +++++++++++++++++------- source/common/notify.h | 8 +- source/common/screen.cpp | 151 +++++++++++++++---------- source/common/screen.h | 47 ++++---- source/common/text.cpp | 234 ++++++++++++++++++++++++++------------- source/common/text.h | 39 ++++--- source/common/utils.h | 56 ++++++++-- source/director.cpp | 76 ++++++------- source/game.cpp | 4 +- source/intro.cpp | 2 +- source/logo.cpp | 2 +- source/title.cpp | 16 +-- 12 files changed, 506 insertions(+), 275 deletions(-) diff --git a/source/common/notify.cpp b/source/common/notify.cpp index 26ef9e1..108bdb7 100644 --- a/source/common/notify.cpp +++ b/source/common/notify.cpp @@ -1,24 +1,30 @@ #include "notify.h" #include #include +#include // Constructor -Notify::Notify(SDL_Renderer *renderer, std::string bitmapFile, std::string textFile) +Notify::Notify(SDL_Renderer *renderer, std::string bitmapFile, std::string textFile, std::string soundFile, options_t *options) { // Inicializa variables this->renderer = renderer; - bgColor = {64, 64, 64}; + this->options = options; + bgColor = options->notifications.color; waitTime = 300; // Crea objetos - text = new Text(bitmapFile, textFile, renderer); + texture = new Texture(renderer, bitmapFile); + text = new Text(textFile, texture, renderer); + sound = JA_LoadSound(soundFile.c_str()); } // Destructor Notify::~Notify() { // Libera la memoria de los objetos + delete texture; delete text; + JA_DeleteSound(sound); for (auto notification : notifications) { @@ -32,7 +38,7 @@ void Notify::render() { for (int i = (int)notifications.size() - 1; i >= 0; --i) { - notifications.at(i).sprite->render(); + notifications[i].sprite->render(); } } @@ -41,49 +47,63 @@ void Notify::update() { for (int i = 0; i < (int)notifications.size(); ++i) { - notifications.at(i).counter++; + notifications[i].counter++; // Comprueba los estados - if (notifications.at(i).state == ns_rising) + if (notifications[i].state == ns_rising) { - const float step = ((float)notifications.at(i).counter / notifications.at(i).travelDist); + const float step = ((float)notifications[i].counter / notifications[i].travelDist); const int alpha = 255 * step; - notifications.at(i).rect.y++; - notifications.at(i).texture->setAlpha(alpha); - - if (notifications.at(i).rect.y == notifications.at(i).y) + if (options->notifications.posV == pos_top) { - notifications.at(i).state = ns_stay; - notifications.at(i).texture->setAlpha(255); - notifications.at(i).counter = 0; + notifications[i].rect.y++; + } + else + { + notifications[i].rect.y--; + } + notifications[i].texture->setAlpha(alpha); + + if (notifications[i].rect.y == notifications[i].y) + { + notifications[i].state = ns_stay; + notifications[i].texture->setAlpha(255); + notifications[i].counter = 0; } } - else if (notifications.at(i).state == ns_stay) + else if (notifications[i].state == ns_stay) { - if (notifications.at(i).counter == waitTime) + if (notifications[i].counter == waitTime) { - notifications.at(i).state = ns_vanishing; - notifications.at(i).counter = 0; + notifications[i].state = ns_vanishing; + notifications[i].counter = 0; } } - else if (notifications.at(i).state == ns_vanishing) + else if (notifications[i].state == ns_vanishing) { - const float step = (notifications.at(i).counter / (float)notifications.at(i).travelDist); + const float step = (notifications[i].counter / (float)notifications[i].travelDist); const int alpha = 255 * (1 - step); - notifications.at(i).rect.y--; - notifications.at(i).texture->setAlpha(alpha); - - if (notifications.at(i).rect.y == notifications.at(i).y - notifications.at(i).travelDist) + if (options->notifications.posV == pos_top) { - notifications.at(i).state = ns_finished; + notifications[i].rect.y--; + } + else + { + notifications[i].rect.y++; + } + notifications[i].texture->setAlpha(alpha); + + if (notifications[i].rect.y == notifications[i].y - notifications[i].travelDist) + { + notifications[i].state = ns_finished; } } - notifications.at(i).sprite->setRect(notifications.at(i).rect); + notifications[i].sprite->setRect(notifications[i].rect); } clearFinishedNotifications(); @@ -94,10 +114,10 @@ void Notify::clearFinishedNotifications() { for (int i = (int)notifications.size() - 1; i >= 0; --i) { - if (notifications.at(i).state == ns_finished) + if (notifications[i].state == ns_finished) { - delete notifications.at(i).sprite; - delete notifications.at(i).texture; + delete notifications[i].sprite; + delete notifications[i].texture; notifications.erase(notifications.begin() + i); } } @@ -106,24 +126,67 @@ void Notify::clearFinishedNotifications() // Muestra una notificación de texto por pantalla; void Notify::showText(std::string text) { - // Crea constantes + // Inicializa variables const int width = this->text->lenght(text) + (this->text->getCharacterSize() * 2); const int height = this->text->getCharacterSize() * 2; - const int despH = this->text->getCharacterSize() / 2; - const int despV = despH; - const int travelDist = height + despV; - const int offset = (int)notifications.size() > 0 ? notifications.back().y + travelDist : despV; + const int padding = (this->text->getCharacterSize() / 2); + + // Posición horizontal + int despH = 0; + if (options->notifications.posH == pos_left) + { + despH = padding; + } + else if (options->notifications.posH == pos_middle) + { + despH = ((options->screen.windowWidth * options->windowSize) / 2 - (width / 2)); + } + else + { + despH = (options->screen.windowWidth * options->windowSize) - width - padding; + } + + // Posición vertical + int despV = 0; + if (options->notifications.posV == pos_top) + { + despV = padding; + } + else + { + despV = (options->screen.windowHeight * options->windowSize) - height - padding; + } + + const int travelDist = height + padding; + + // Offset + int offset = 0; + if (options->notifications.posV == pos_top) + { + offset = (int)notifications.size() > 0 ? notifications.back().y + travelDist : despV; + } + else + { + offset = (int)notifications.size() > 0 ? notifications.back().y - travelDist : despV; + } // Crea la notificacion notification_t n; - // inicializa variables + // Inicializa variables n.y = offset; n.travelDist = travelDist; n.counter = 0; n.state = ns_rising; n.text = text; - n.rect = {despH, offset - travelDist, width, height}; + if (options->notifications.posV == pos_top) + { + n.rect = {despH, offset - travelDist, width, height}; + } + else + { + n.rect = {despH, offset + travelDist, width, height}; + } // Crea la textura n.texture = new Texture(renderer); @@ -132,13 +195,20 @@ void Notify::showText(std::string text) SDL_SetRenderDrawColor(renderer, bgColor.r, bgColor.g, bgColor.b, 255); SDL_RenderClear(renderer); n.texture->setBlendMode(SDL_BLENDMODE_BLEND); - this->text->writeDX(TXT_CENTER | TXT_STROKE, width / 2, despV, text, 1, {255, 255, 255}, 1, {0, 0, 0}); + this->text->writeDX(TXT_CENTER | TXT_STROKE, width / 2, padding, text, 1, {255, 255, 255}, 1, {0, 0, 0}); + SDL_SetRenderTarget(renderer, nullptr); // Crea el sprite n.sprite = new Sprite(n.rect, n.texture, renderer); // Añade la notificación a la lista notifications.push_back(n); + + // Reproduce el sonido de la notificación + if (options->notifications.sound) + { + JA_PlaySound(sound); + } } // Indica si hay notificaciones activas @@ -148,6 +218,6 @@ bool Notify::active() { return true; } - + return false; } \ No newline at end of file diff --git a/source/common/notify.h b/source/common/notify.h index c4d7f06..746055d 100644 --- a/source/common/notify.h +++ b/source/common/notify.h @@ -1,9 +1,10 @@ #pragma once #include +#include "jail_audio.h" +#include "sprite.h" #include "text.h" #include "texture.h" -#include "sprite.h" #include "utils.h" #include @@ -48,12 +49,15 @@ private: // Objetos y punteros SDL_Renderer *renderer; // El renderizador de la ventana + Texture *texture; // Textura para la fuente de las notificaciones Text *text; // Objeto para dibujar texto + options_t *options; // Variable con todas las opciones del programa // Variables color_t bgColor; // Color de fondo de las notificaciones int waitTime; // Tiempo que se ve la notificación std::vector notifications; // La lista de notificaciones activas + JA_Sound_t* sound; // Sonido a reproducir cuando suena la notificación // Elimina las notificaciones finalizadas void clearFinishedNotifications(); @@ -66,7 +70,7 @@ public: void update(); // Constructor - Notify(SDL_Renderer *renderer, std::string bitmapFile, std::string textFile); + Notify(SDL_Renderer *renderer, std::string bitmapFile, std::string textFile, std::string soundFile, options_t *options); // Destructor ~Notify(); diff --git a/source/common/screen.cpp b/source/common/screen.cpp index d017c43..fcfc9f4 100644 --- a/source/common/screen.cpp +++ b/source/common/screen.cpp @@ -1,9 +1,9 @@ #include "screen.h" #include -#include +#include // Constructor -Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options_t *options, int gameInternalResX, int gameInternalResY) +Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options_t *options) { // Inicializa variables this->window = window; @@ -12,10 +12,14 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options this->asset = asset; // Crea los objetos - notify = new Notify(renderer, asset->get("smb2.png"), asset->get("smb2.txt")); + notify = new Notify(renderer, asset->get("smb2.png"), asset->get("smb2.txt"), asset->get("notify.wav"), options); - gameCanvasWidth = gameInternalResX; - gameCanvasHeight = gameInternalResY; + gameCanvasWidth = options->gameWidth; + gameCanvasHeight = options->gameHeight; + borderWidth = options->borderWidth * 2; + borderHeight = options->borderHeight * 2; + notificationLogicalWidth = gameCanvasWidth; + notificationLogicalHeight = gameCanvasHeight; iniFade(); iniSpectrumFade(); @@ -27,19 +31,14 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options gameCanvas = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, gameCanvasWidth, gameCanvasHeight); if (gameCanvas == nullptr) { - printf("TitleSurface could not be created!\nSDL Error: %s\n", SDL_GetError()); + if (options->console) + { + std::cout << "TitleSurface could not be created!\nSDL Error: " << SDL_GetError() << std::endl; + } } // Establece el modo de video - setVideoMode(options->fullScreenMode); - - // Calcula los anclajes - anchor.left = 0; - anchor.right = gameCanvasWidth; - anchor.center = gameCanvasWidth / 2; - anchor.top = 0; - anchor.bottom = gameCanvasHeight; - anchor.middle = gameCanvasHeight / 2; + setVideoMode(options->videoMode); // Inicializa variables notifyActive = false; @@ -85,96 +84,103 @@ void Screen::blit() } // Establece el modo de video -void Screen::setVideoMode(int fullScreenMode) +void Screen::setVideoMode(int videoMode) { + // Muestra el puntero + SDL_ShowCursor(SDL_ENABLE); + // Aplica el modo de video - SDL_SetWindowFullscreen(window, fullScreenMode); + SDL_SetWindowFullscreen(window, videoMode); // Si está activo el modo ventana quita el borde - if (fullScreenMode == 0) + if (videoMode == 0) { if (options->borderEnabled) { - const int incWidth = gameCanvasWidth * options->borderSize; - const int incHeight = gameCanvasHeight * options->borderSize; - screenWidth = gameCanvasWidth + incWidth; - screenHeight = gameCanvasHeight + incHeight; - dest = {0 + (incWidth / 2), 0 + (incHeight / 2), gameCanvasWidth, gameCanvasHeight}; + windowWidth = gameCanvasWidth + borderWidth; + windowHeight = gameCanvasHeight + borderHeight; + dest = {0 + (borderWidth / 2), 0 + (borderHeight / 2), gameCanvasWidth, gameCanvasHeight}; } else { - screenWidth = gameCanvasWidth * options->windowSize; - screenHeight = gameCanvasHeight * options->windowSize; + windowWidth = gameCanvasWidth; + windowHeight = gameCanvasHeight; dest = {0, 0, gameCanvasWidth, gameCanvasHeight}; } // Modifica el tamaño del renderizador y de la ventana - // SDL_RenderSetLogicalSize(renderer, screenWidth, screenHeight); - // SDL_SetWindowSize(window, screenWidth * options->windowSize, screenHeight * options->windowSize); - SDL_RenderSetLogicalSize(renderer, gameCanvasWidth, gameCanvasHeight); - SDL_SetWindowSize(window, screenWidth, screenHeight); + SDL_RenderSetLogicalSize(renderer, windowWidth, windowHeight); + SDL_SetWindowSize(window, windowWidth * options->windowSize, windowHeight * options->windowSize); } // Si está activo el modo de pantalla completa añade el borde - else if (fullScreenMode == SDL_WINDOW_FULLSCREEN_DESKTOP) + else if (videoMode == SDL_WINDOW_FULLSCREEN_DESKTOP) { + // Oculta el puntero + SDL_ShowCursor(SDL_DISABLE); + // Obten el alto y el ancho de la ventana - SDL_GetWindowSize(window, &screenWidth, &screenHeight); + SDL_GetWindowSize(window, &windowWidth, &windowHeight); // Aplica el escalado al rectangulo donde se pinta la textura del juego if (options->integerScale) { // Calcula el tamaño de la escala máxima int scale = 0; - while (((gameCanvasWidth * (scale + 1)) <= screenWidth) && ((gameCanvasHeight * (scale + 1)) <= screenHeight)) + while (((gameCanvasWidth * (scale + 1)) <= windowWidth) && ((gameCanvasHeight * (scale + 1)) <= windowHeight)) { scale++; } dest.w = gameCanvasWidth * scale; dest.h = gameCanvasHeight * scale; - dest.x = (screenWidth - dest.w) / 2; - dest.y = (screenHeight - dest.h) / 2; + dest.x = (windowWidth - dest.w) / 2; + dest.y = (windowHeight - dest.h) / 2; } else if (options->keepAspect) { float ratio = (float)gameCanvasWidth / (float)gameCanvasHeight; - if ((screenWidth - gameCanvasWidth) >= (screenHeight - gameCanvasHeight)) + if ((windowWidth - gameCanvasWidth) >= (windowHeight - gameCanvasHeight)) { - dest.h = screenHeight; - dest.w = (int)((screenHeight * ratio) + 0.5f); - dest.x = (screenWidth - dest.w) / 2; - dest.y = (screenHeight - dest.h) / 2; + dest.h = windowHeight; + dest.w = (int)((windowHeight * ratio) + 0.5f); + dest.x = (windowWidth - dest.w) / 2; + dest.y = (windowHeight - dest.h) / 2; } else { - dest.w = screenWidth; - dest.h = (int)((screenWidth / ratio) + 0.5f); - dest.x = (screenWidth - dest.w) / 2; - dest.y = (screenHeight - dest.h) / 2; + dest.w = windowWidth; + dest.h = (int)((windowWidth / ratio) + 0.5f); + dest.x = (windowWidth - dest.w) / 2; + dest.y = (windowHeight - dest.h) / 2; } } else { - dest.w = screenWidth; - dest.h = screenHeight; + dest.w = windowWidth; + dest.h = windowHeight; dest.x = dest.y = 0; } // Modifica el tamaño del renderizador - SDL_RenderSetLogicalSize(renderer, screenWidth, screenHeight); + SDL_RenderSetLogicalSize(renderer, windowWidth, windowHeight); } - // Actualiza el valor de la variable - options->fullScreenMode = fullScreenMode; + // Actualiza las opciones + options->videoMode = videoMode; + options->screen.windowWidth = windowWidth; + options->screen.windowHeight = windowHeight; + + // Establece el tamaño de las notificaciones + setNotificationSize(); } // Camibia entre pantalla completa y ventana void Screen::switchVideoMode() { - options->fullScreenMode = (options->fullScreenMode == 0) ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0; - setVideoMode(options->fullScreenMode); + options->videoMode = (options->videoMode == 0) ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0; + setVideoMode(options->videoMode); } // Cambia el tamaño de la ventana @@ -197,9 +203,15 @@ void Screen::setBlendMode(SDL_BlendMode blendMode) } // Establece el tamaño del borde -void Screen::setBorderSize(float s) +void Screen::setBorderWidth(int s) { - options->borderSize = s; + options->borderWidth = s; +} + +// Establece el tamaño del borde +void Screen::setBorderHeight(int s) +{ + options->borderHeight = s; } // Establece si se ha de ver el borde en el modo ventana @@ -301,7 +313,7 @@ void Screen::iniSpectrumFade() const std::vector vColors = {"black", "blue", "red", "magenta", "green", "cyan", "yellow", "bright_white"}; for (auto v : vColors) { - spectrumColor.push_back(stringToColor(p_zxspectrum, v)); + spectrumColor.push_back(stringToColor(options->palette, v)); } } @@ -332,7 +344,7 @@ void Screen::renderSpectrumFade() const float step = (float)spectrumFadeCounter / (float)spectrumFadeLenght; const int max = spectrumColor.size() - 1; const int index = max + (0 - max) * step; - const color_t c = spectrumColor.at(index); + const color_t c = spectrumColor[index]; SDL_SetTextureColorMod(gameCanvas, c.r, c.g, c.b); } @@ -358,7 +370,7 @@ void Screen::updateNotifier() } // Muestra una notificación de texto por pantalla; -void Screen::showText(std::string text) +void Screen::showNotification(std::string text) { notify->showText(text); } @@ -371,8 +383,31 @@ void Screen::renderNotifications() return; } - //SDL_RenderSetLogicalSize(renderer, screenWidth, screenHeight); - SDL_RenderSetLogicalSize(renderer, gameCanvasWidth*2, gameCanvasHeight*2); + //SDL_RenderSetLogicalSize(renderer, notificationLogicalWidth, notificationLogicalHeight); notify->render(); - SDL_RenderSetLogicalSize(renderer, gameCanvasWidth, gameCanvasHeight); + //SDL_RenderSetLogicalSize(renderer, windowWidth, windowHeight); +} + +// Establece el tamaño de las notificaciones +void Screen::setNotificationSize() +{ + if (options->videoMode == 0) + { + if (options->windowSize == 3) + { + notificationLogicalWidth = (windowWidth * 3) / 2; + notificationLogicalHeight = (windowHeight * 3) / 2; + } + else + { + notificationLogicalWidth = windowWidth * 2; + notificationLogicalHeight = windowHeight * 2; + } + } + + if (options->videoMode == SDL_WINDOW_FULLSCREEN_DESKTOP) + { + notificationLogicalWidth = windowWidth / 3; + notificationLogicalHeight = windowHeight / 3; + } } \ No newline at end of file diff --git a/source/common/screen.h b/source/common/screen.h index bcc5a3c..0c19343 100644 --- a/source/common/screen.h +++ b/source/common/screen.h @@ -12,21 +12,10 @@ #define FILTER_NEAREST 0 #define FILTER_LINEAL 1 -struct anchor_t -{ - int left; // Parte izquierda de la pantalla de juego - int right; // Parte drecha de la pantalla de juego - int center; // Parte central horizontal de la pantalla de juego - int top; // Parte superior de la pantalla de juego - int bottom; // Parte infoerior de la pantalla de juego - int middle; // Parte central vertical de la pantalla de juego -}; - -// Clase Screen class Screen { private: - // Objetos y variables + // Objetos y punteros SDL_Window *window; // Ventana de la aplicación SDL_Renderer *renderer; // El renderizador de la ventana Asset *asset; // Objeto con el listado de recursos @@ -34,16 +23,20 @@ private: options_t *options; // Variable con todas las opciones del programa Notify *notify; // Dibuja notificaciones por pantalla - int screenWidth; // Ancho de la pantalla o ventana - int screenHeight; // Alto de la pantalla o ventana - int gameCanvasWidth; // Resolución interna del juego. Es el ancho de la textura donde se dibuja el juego - int gameCanvasHeight; // Resolución interna del juego. Es el alto de la textura donde se dibuja el juego - anchor_t anchor; // Variable con los anclajes de la pantalla - SDL_Rect dest; // Coordenadas donde se va a dibujar la textura del juego sobre la pantalla o ventana - color_t borderColor; // Color del borde añadido a la textura de juego para rellenar la pantalla - bool notifyActive; // Indica si hay notificaciones activas + // Variables + int windowWidth; // Ancho de la pantalla o ventana + int windowHeight; // Alto de la pantalla o ventana + int gameCanvasWidth; // Resolución interna del juego. Es el ancho de la textura donde se dibuja el juego + int gameCanvasHeight; // Resolución interna del juego. Es el alto de la textura donde se dibuja el juego + int borderWidth; // Anchura del borde + int borderHeight; // Anltura del borde + SDL_Rect dest; // Coordenadas donde se va a dibujar la textura del juego sobre la pantalla o ventana + color_t borderColor; // Color del borde añadido a la textura de juego para rellenar la pantalla + bool notifyActive; // Indica si hay notificaciones activas + int notificationLogicalWidth; // Ancho lógico de las notificaciones en relación al tamaño de pantalla + int notificationLogicalHeight; // Alto lógico de las notificaciones en relación al tamaño de pantalla - // EFECTOS + // Variables - Efectos bool fade; // Indica si esta activo el efecto de fade int fadeCounter; // Temporizador para el efecto de fade int fadeLenght; // Duración del fade @@ -73,9 +66,12 @@ private: // Dibuja las notificaciones void renderNotifications(); + // Establece el tamaño de las notificaciones + void setNotificationSize(); + public: // Constructor - Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options_t *options, int gameInternalResX, int gameInternalResY); + Screen(SDL_Window *window, SDL_Renderer *renderer, Asset *asset, options_t *options); // Destructor ~Screen(); @@ -90,7 +86,7 @@ public: void blit(); // Establece el modo de video - void setVideoMode(int fullScreenMode); + void setVideoMode(int videoMode); // Camibia entre pantalla completa y ventana void switchVideoMode(); @@ -105,7 +101,8 @@ public: void setBlendMode(SDL_BlendMode blendMode); // Establece el tamaño del borde - void setBorderSize(float s); + void setBorderWidth(int s); + void setBorderHeight(int s); // Establece si se ha de ver el borde en el modo ventana void setBorderEnabled(bool value); @@ -135,7 +132,7 @@ public: void updateNotifier(); // Muestra una notificación de texto por pantalla; - void showText(std::string text); + void showNotification(std::string text); }; #endif diff --git a/source/common/text.cpp b/source/common/text.cpp index 8ff51eb..8b93493 100644 --- a/source/common/text.cpp +++ b/source/common/text.cpp @@ -3,22 +3,151 @@ #include #include +// Llena una estructuta textFile_t desde un fichero +textFile_t LoadTextFile(std::string file, bool verbose) +{ + textFile_t tf; + + // Inicializa a cero el vector con las coordenadas + for (int i = 0; i < 128; ++i) + { + tf.offset[i].x = 0; + tf.offset[i].y = 0; + tf.offset[i].w = 0; + } + + // Abre el fichero para leer los valores + const std::string filename = file.substr(file.find_last_of("\\/") + 1).c_str(); + std::ifstream rfile(file); + + if (rfile.is_open() && rfile.good()) + { + std::string buffer; + + // Lee los dos primeros valores del fichero + std::getline(rfile, buffer); + std::getline(rfile, buffer); + tf.boxWidth = std::stoi(buffer); + + std::getline(rfile, buffer); + std::getline(rfile, buffer); + tf.boxHeight = std::stoi(buffer); + + // lee el resto de datos del fichero + int index = 32; + int line_read = 0; + while (std::getline(rfile, buffer)) + { + // Almacena solo las lineas impares + if (line_read % 2 == 1) + { + tf.offset[index++].w = std::stoi(buffer); + } + + // Limpia el buffer + buffer.clear(); + line_read++; + }; + + // Cierra el fichero + if (verbose) + { + std::cout << "Text loaded: " << filename.c_str() << std::endl; + } + rfile.close(); + } + + // El fichero no se puede abrir + else + { + if (verbose) + { + std::cout << "Warning: Unable to open " << filename.c_str() << " file" << std::endl; + } + } + + // Establece las coordenadas para cada caracter ascii de la cadena y su ancho + for (int i = 32; i < 128; ++i) + { + tf.offset[i].x = ((i - 32) % 15) * tf.boxWidth; + tf.offset[i].y = ((i - 32) / 15) * tf.boxHeight; + } + + return tf; +} + // Constructor Text::Text(std::string bitmapFile, std::string textFile, SDL_Renderer *renderer) { // Carga los offsets desde el fichero - initOffsetFromFile(textFile); + textFile_t tf = LoadTextFile(textFile); + + // Inicializa variables desde la estructura + boxHeight = tf.boxHeight; + boxWidth = tf.boxWidth; + for (int i = 0; i < 128; ++i) + { + offset[i].x = tf.offset[i].x; + offset[i].y = tf.offset[i].y; + offset[i].w = tf.offset[i].w; + } // Crea los objetos texture = new Texture(renderer, bitmapFile); sprite = new Sprite({0, 0, boxWidth, boxHeight}, texture, renderer); } +// Constructor +Text::Text(std::string textFile, Texture *texture, SDL_Renderer *renderer) +{ + // Carga los offsets desde el fichero + textFile_t tf = LoadTextFile(textFile); + + // Inicializa variables desde la estructura + boxHeight = tf.boxHeight; + boxWidth = tf.boxWidth; + for (int i = 0; i < 128; ++i) + { + offset[i].x = tf.offset[i].x; + offset[i].y = tf.offset[i].y; + offset[i].w = tf.offset[i].w; + } + + // Crea los objetos + sprite = new Sprite({0, 0, boxWidth, boxHeight}, texture, renderer); + + // Inicializa variables + fixedWidth = false; +} + +// Constructor +Text::Text(textFile_t *textFile, Texture *texture, SDL_Renderer *renderer) +{ + // Inicializa variables desde la estructura + boxHeight = textFile->boxHeight; + boxWidth = textFile->boxWidth; + for (int i = 0; i < 128; ++i) + { + offset[i].x = textFile->offset[i].x; + offset[i].y = textFile->offset[i].y; + offset[i].w = textFile->offset[i].w; + } + + // Crea los objetos + sprite = new Sprite({0, 0, boxWidth, boxHeight}, texture, renderer); + + // Inicializa variables + fixedWidth = false; +} + // Destructor Text::~Text() { - delete texture; delete sprite; + if (texture) + { + delete texture; + } } // Escribe texto en pantalla @@ -35,7 +164,8 @@ void Text::write(int x, int y, std::string text, int kerning, int lenght) sprite->setPosX(x + shift); sprite->setPosY(y); sprite->render(); - shift += (offset[int(text[i])].w + kerning); + // shift += (offset[int(text[i])].w + kerning); + shift += fixedWidth ? boxWidth : (offset[int(text[i])].w + kerning); } } @@ -72,28 +202,37 @@ void Text::writeDX(Uint8 flags, int x, int y, std::string text, int kerning, col const bool stroked = ((flags & TXT_STROKE) == TXT_STROKE); if (centered) + { x -= (Text::lenght(text, kerning) / 2); + } if (shadowed) + { writeColored(x + shadowDistance, y + shadowDistance, text, shadowColor, kerning, lenght); + } if (stroked) { - writeColored(x + shadowDistance, y + shadowDistance, text, shadowColor, kerning, lenght); - writeColored(x - shadowDistance, y + shadowDistance, text, shadowColor, kerning, lenght); - writeColored(x + shadowDistance, y - shadowDistance, text, shadowColor, kerning, lenght); - writeColored(x - shadowDistance, y - shadowDistance, text, shadowColor, kerning, lenght); - - writeColored(x, y + shadowDistance, text, shadowColor, kerning, lenght); - writeColored(x, y - shadowDistance, text, shadowColor, kerning, lenght); - writeColored(x + shadowDistance, y, text, shadowColor, kerning, lenght); - writeColored(x - shadowDistance, y, text, shadowColor, kerning, lenght); + for (int dist = 1; dist <= shadowDistance; ++dist) + { + for (int dy = -dist; dy <= dist; ++dy) + { + for (int dx = -dist; dx <= dist; ++dx) + { + writeColored(x + dx, y + dy, text, shadowColor, kerning, lenght); + } + } + } } if (colored) + { writeColored(x, y, text, textColor, kerning, lenght); + } else + { write(x, y, text, kerning, lenght); + } } // Obtiene la longitud en pixels de una cadena @@ -108,69 +247,6 @@ int Text::lenght(std::string text, int kerning) return shift - kerning; } -// Inicializa el vector de offsets desde un fichero -void Text::initOffsetFromFile(std::string file) -{ - // Inicializa a cero el vector con las coordenadas - for (int i = 0; i < 128; ++i) - { - offset[i].x = 0; - offset[i].y = 0; - offset[i].w = 0; - } - - // Abre el fichero para leer los valores - const std::string filename = file.substr(file.find_last_of("\\/") + 1).c_str(); - std::ifstream rfile(file); - - if (rfile.is_open() && rfile.good()) - { - std::string buffer; - - // Lee los dos primeros valores del fichero - std::getline(rfile, buffer); - std::getline(rfile, buffer); - boxWidth = std::stoi(buffer); - - std::getline(rfile, buffer); - std::getline(rfile, buffer); - boxHeight = std::stoi(buffer); - - // lee el resto de datos del fichero - int index = 32; - int line_read = 0; - while (std::getline(rfile, buffer)) - { - // Almacena solo las lineas impares - if (line_read % 2 == 1) - { - offset[index++].w = std::stoi(buffer); - } - - // Limpia el buffer - buffer.clear(); - line_read++; - }; - - // Cierra el fichero - printf("Text loaded: %s\n", filename.c_str()); - rfile.close(); - } - - // El fichero no se puede abrir - else - { - printf("Warning: Unable to open %s file\n", filename.c_str()); - } - - // Establece las coordenadas para cada caracter ascii de la cadena y su ancho - for (int i = 32; i < 128; ++i) - { - offset[i].x = ((i - 32) % 15) * boxWidth; - offset[i].y = ((i - 32) / 15) * boxHeight; - } -} - // Devuelve el valor de la variable int Text::getCharacterSize() { @@ -180,5 +256,11 @@ int Text::getCharacterSize() // Recarga la textura void Text::reLoadTexture() { - texture->reLoad(); + sprite->getTexture()->reLoad(); +} + +// Establece si se usa un tamaño fijo de letra +void Text::setFixedWidth(bool value) +{ + fixedWidth = value; } \ No newline at end of file diff --git a/source/common/text.h b/source/common/text.h index df6b415..87bccb0 100644 --- a/source/common/text.h +++ b/source/common/text.h @@ -11,32 +11,42 @@ #define TXT_CENTER 4 #define TXT_STROKE 8 +struct offset_t +{ + int x; + int y; + int w; +}; + +struct textFile_t +{ + int boxWidth; // Anchura de la caja de cada caracter en el png + int boxHeight; // Altura de la caja de cada caracter en el png + offset_t offset[128]; // Vector con las posiciones y ancho de cada letra +}; + +// Llena una estructuta textFile_t desde un fichero +textFile_t LoadTextFile(std::string file, bool verbose = false); + // Clase texto. Pinta texto en pantalla a partir de un bitmap class Text { private: - struct offset_t - { - int x; - int y; - int w; - }; - // Objetos y punteros - Sprite *sprite; // Objeto con los graficos para el texto + Sprite *sprite; // Objeto con los graficos para el texto Texture *texture; // Textura con los bitmaps del texto // Variables - int boxWidth; // Anchura de la caja de cada caracter en el png - int boxHeight; // Altura de la caja de cada caracter en el png + int boxWidth; // Anchura de la caja de cada caracter en el png + int boxHeight; // Altura de la caja de cada caracter en el png + bool fixedWidth; // Indica si el texto se ha de escribir con longitud fija en todas las letras offset_t offset[128]; // Vector con las posiciones y ancho de cada letra - // Inicializa el vector de offsets desde un fichero - void initOffsetFromFile(std::string file); - public: // Constructor Text(std::string bitmapFile, std::string textFile, SDL_Renderer *renderer); + Text(std::string textFile, Texture *texture, SDL_Renderer *renderer); + Text(textFile_t *textFile, Texture *texture, SDL_Renderer *renderer); // Destructor ~Text(); @@ -64,6 +74,9 @@ public: // Recarga la textura void reLoadTexture(); + + // Establece si se usa un tamaño fijo de letra + void setFixedWidth(bool value); }; #endif diff --git a/source/common/utils.h b/source/common/utils.h index 8d0e0b5..f4172e8 100644 --- a/source/common/utils.h +++ b/source/common/utils.h @@ -64,6 +64,16 @@ enum palette_e p_zxarne }; +// Posiciones de las notificaciones +enum not_pos_e +{ + pos_top, + pos_bottom, + pos_left, + pos_middle, + pos_right +}; + // Estructura para saber la seccion y subseccion del programa struct section_t { @@ -94,6 +104,7 @@ struct input_t struct online_t { bool enabled; // Indica si se quiere usar el modo online o no + bool sessionEnabled; // Indica ya se ha hecho login std::string server; // Servidor para los servicios online int port; // Puerto del servidor std::string gameID; // Identificador del juego para los servicios online @@ -101,6 +112,22 @@ struct online_t int score; // Puntuación almacenada online }; +// Estructura con opciones de la pantalla +struct op_screen_t +{ + int windowWidth; // Ancho de la ventana + int windowHeight; // Alto de la ventana +}; + +// Estructura para las opciones de las notificaciones +struct op_notification_t +{ + not_pos_e posH; // Ubicación de las notificaciones en pantalla + not_pos_e posV; // Ubicación de las notificaciones en pantalla + bool sound; // Indica si las notificaciones suenan + color_t color; // Color de las notificaciones +}; + // Estructura con todas las opciones de configuración del programa struct options_t { @@ -108,17 +135,24 @@ struct options_t Uint8 playerSelected; // Jugador seleccionado para el modo 1P std::vector input; // Modo de control (teclado o mando) Uint8 language; // Idioma usado en el juego - Uint32 fullScreenMode; // Contiene el valor del modo de pantalla completa - Uint8 windowSize; // Contiene el valor por el que se multiplica el tamaño de la ventana - Uint32 filter; // Filtro usado para el escalado de la imagen - bool vSync; // Indica si se quiere usar vsync o no - int screenWidth; // Ancho de la pantalla/ventana - int screenHeight; // Alto de la pantalla/ventana - bool integerScale; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa - bool keepAspect; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa - bool borderEnabled; // Indica si ha de mostrar el borde en el modo de ventana - float borderSize; // Porcentaje de borde que se añade a lo ventana - online_t online; // Datos del servicio online + + Uint32 videoMode; // Contiene el valor del modo de pantalla completa + int windowSize; // Contiene el valor por el que se multiplica el tamaño de la ventana + Uint32 filter; // Filtro usado para el escalado de la imagen + bool vSync; // Indica si se quiere usar vsync o no + int gameWidth; // Ancho de la resolucion nativa del juego + int gameHeight; // Alto de la resolucion nativa del juego + bool integerScale; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa + bool keepAspect; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa + bool borderEnabled; // Indica si ha de mostrar el borde en el modo de ventana + int borderWidth; // Cantidad de pixels que se añade en el borde de la ventana + int borderHeight; // Cantidad de pixels que se añade en el borde de la ventana + palette_e palette; // Paleta de colores a usar en el juego + bool console; // Indica si ha de mostrar información por la consola de texto + + online_t online; // Datos del servicio online + op_screen_t screen; // Opciones relativas a la clase screen + op_notification_t notifications; // Opciones relativas a las notificaciones; }; // Calcula el cuadrado de la distancia entre dos puntos diff --git a/source/director.cpp b/source/director.cpp index 88e1cf5..c426053 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -40,7 +40,7 @@ Director::Director(std::string path) input = new Input(asset->get("controllerdb.txt")); initInput(); - screen = new Screen(window, renderer, asset, options, GAME_WIDTH, GAME_HEIGHT); + screen = new Screen(window, renderer, asset, options); // Inicializa los servicios online initOnline(); @@ -123,7 +123,14 @@ bool Director::initSDL() } // Crea la ventana - window = SDL_CreateWindow(WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, options->screenWidth * options->windowSize, options->screenHeight * options->windowSize, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI); + int incW = 0; + int incH = 0; + if (options->borderEnabled) + { + incW = options->borderWidth * 2; + incH = options->borderHeight * 2; + } + window = SDL_CreateWindow(WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (options->gameWidth + incW) * options->windowSize, (options->gameHeight + incH) * options->windowSize, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI); if (window == nullptr) { printf("Window could not be created!\nSDL Error: %s\n", SDL_GetError()); @@ -152,7 +159,7 @@ bool Director::initSDL() SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF); // Establece el tamaño del buffer de renderizado - SDL_RenderSetLogicalSize(renderer, options->screenWidth, options->screenHeight); + SDL_RenderSetLogicalSize(renderer, options->gameWidth, options->gameHeight); // Establece el modo de mezcla SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); @@ -314,18 +321,17 @@ void Director::initOptions() inp.deviceType = INPUT_USE_GAMECONTROLLER; options->input.push_back(inp); - options->fullScreenMode = 0; + options->videoMode = 0; options->windowSize = 3; options->language = ba_BA; options->difficulty = DIFFICULTY_NORMAL; options->playerSelected = 0; options->filter = FILTER_NEAREST; options->vSync = true; - options->screenWidth = GAME_WIDTH; - options->screenHeight = GAME_HEIGHT; options->integerScale = true; options->keepAspect = true; - options->borderSize = 0.0f; + options->borderWidth = 0; + options->borderHeight = 0; options->borderEnabled = false; // Online @@ -381,12 +387,12 @@ bool Director::loadConfigFile() } // Normaliza los valores - const bool a = options->fullScreenMode == 0; - const bool b = options->fullScreenMode == SDL_WINDOW_FULLSCREEN; - const bool c = options->fullScreenMode == SDL_WINDOW_FULLSCREEN_DESKTOP; + const bool a = options->videoMode == 0; + const bool b = options->videoMode == SDL_WINDOW_FULLSCREEN; + const bool c = options->videoMode == SDL_WINDOW_FULLSCREEN_DESKTOP; if (!(a || b || c)) { - options->fullScreenMode = 0; + options->videoMode = 0; } if (options->windowSize < 1 || options->windowSize > 4) @@ -412,17 +418,17 @@ bool Director::saveConfigFile() // Escribe en el fichero file << "## VISUAL OPTIONS\n"; - if (options->fullScreenMode == 0) + if (options->videoMode == 0) { file << "fullScreenMode=0\n"; } - else if (options->fullScreenMode == SDL_WINDOW_FULLSCREEN) + else if (options->videoMode == SDL_WINDOW_FULLSCREEN) { file << "fullScreenMode=SDL_WINDOW_FULLSCREEN\n"; } - else if (options->fullScreenMode == SDL_WINDOW_FULLSCREEN_DESKTOP) + else if (options->videoMode == SDL_WINDOW_FULLSCREEN_DESKTOP) { file << "fullScreenMode=SDL_WINDOW_FULLSCREEN_DESKTOP\n"; } @@ -442,9 +448,8 @@ bool Director::saveConfigFile() file << "integerScale=" + boolToString(options->integerScale) + "\n"; file << "keepAspect=" + boolToString(options->keepAspect) + "\n"; file << "borderEnabled=" + boolToString(options->borderEnabled) + "\n"; - file << "borderSize=" + std::to_string(options->borderSize) + "\n"; - file << "screenWidth=" + std::to_string(options->screenWidth) + "\n"; - file << "screenHeight=" + std::to_string(options->screenHeight) + "\n"; + file << "borderWidth=" + std::to_string(options->borderWidth) + "\n"; + file << "borderHeight=" + std::to_string(options->borderHeight) + "\n"; file << "\n## OTHER OPTIONS\n"; file << "language=" + std::to_string(options->language) + "\n"; @@ -536,7 +541,7 @@ void Director::initOnline() // Obten el Jailer ID if (options->online.jailerID == "") { // Jailer ID no definido - screen->showText("No ha especificado ningun Jailer ID"); + screen->showNotification("No ha especificado ningun Jailer ID"); std::cout << "No ha especificado ningun Jailer ID" << std::endl; } else @@ -548,16 +553,16 @@ void Director::initOnline() // Obtiene la información online if (jscore::initOnlineScore(options->online.gameID)) { - screen->showText(options->online.jailerID + " ha iniciado sesion"); + screen->showNotification(options->online.jailerID + " ha iniciado sesion"); std::cout << options->online.jailerID << " ha iniciado sesion" << std::endl; } else { - screen->showText("Fallo al conectar a " + options->online.server); + screen->showNotification("Fallo al conectar a " + options->online.server); std::cout << "Fallo al conectar a " << options->online.server << std::endl; - options->online.enabled = false; - + options->online.enabled = false; + return; } @@ -565,7 +570,7 @@ void Director::initOnline() const int points = jscore::getUserPoints(options->online.gameID, options->online.jailerID); if (points == 0) { // Fallo de conexión o no hay registros - screen->showText("No se ha podido obtener la puntuacion online"); + screen->showNotification("No se ha podido obtener la puntuacion online"); std::cout << "No se ha podido obtener la puntuacion online" << std::endl; } else @@ -581,19 +586,19 @@ bool Director::setOptions(options_t *options, std::string var, std::string value // Indicador de éxito en la asignación bool success = true; - if (var == "fullScreenMode") + if (var == "videoMode") { if (value == "SDL_WINDOW_FULLSCREEN_DESKTOP") { - options->fullScreenMode = SDL_WINDOW_FULLSCREEN_DESKTOP; + options->videoMode = SDL_WINDOW_FULLSCREEN_DESKTOP; } else if (value == "SDL_WINDOW_FULLSCREEN") { - options->fullScreenMode = SDL_WINDOW_FULLSCREEN; + options->videoMode = SDL_WINDOW_FULLSCREEN; } else { - options->fullScreenMode = 0; + options->videoMode = 0; } } @@ -638,23 +643,14 @@ bool Director::setOptions(options_t *options, std::string var, std::string value options->borderEnabled = stringToBool(value); } - else if (var == "borderSize") + else if (var == "borderWidth") { - options->borderSize = std::stof(value); - if (options->borderSize < 0.0f || options->borderSize > 0.5f) - { - options->borderSize = 0.1f; - } + options->borderWidth = std::stoi(value); } - else if (var == "screenWidth") + else if (var == "borderHeight") { - options->screenWidth = std::stoi(value); - } - - else if (var == "screenHeight") - { - options->screenHeight = std::stoi(value); + options->borderHeight = std::stoi(value); } else if (var == "language") diff --git a/source/game.cpp b/source/game.cpp index 781bd1e..3c3e3cc 100644 --- a/source/game.cpp +++ b/source/game.cpp @@ -744,12 +744,12 @@ bool Game::sendOnlineScore() if (jscore::updateUserPoints("coffee_crisis", options->online.jailerID, score)) { options->online.score = score; - screen->showText("PUNTUACION ENVIADA: " + std::to_string(score) + " PUNTOS"); + screen->showNotification("PUNTUACION ENVIADA: " + std::to_string(score) + " PUNTOS"); return true; } else { - screen->showText("NO SE HA PODIDO ENVIAR LA PUNTUACION"); + screen->showNotification("NO SE HA PODIDO ENVIAR LA PUNTUACION"); return false; } } diff --git a/source/intro.cpp b/source/intro.cpp index c786b10..c6c1d9c 100644 --- a/source/intro.cpp +++ b/source/intro.cpp @@ -215,7 +215,7 @@ void Intro::checkEventHandler() break; case SDL_SCANCODE_F5: - screen->showText("HOLA MAMA!"); + screen->showNotification("HOLA MAMA!"); break; default: diff --git a/source/logo.cpp b/source/logo.cpp index e494315..5c18785 100644 --- a/source/logo.cpp +++ b/source/logo.cpp @@ -88,7 +88,7 @@ void Logo::checkEventHandler() break; case SDL_SCANCODE_F5: - screen->showText("Conectado a Jailers.net"); + screen->showNotification("Conectado a Jailers.net"); break; default: diff --git a/source/title.cpp b/source/title.cpp index 9f715a7..57856c8 100644 --- a/source/title.cpp +++ b/source/title.cpp @@ -426,7 +426,7 @@ void Title::update() case 6: // Display mode switchFullScreenModeVar(); - if (options->fullScreenMode != 0) + if (options->videoMode != 0) { menu.options->setSelectable(8, false); menu.options->setGreyed(8, true); @@ -742,20 +742,20 @@ void Title::updateBG() // Cambia el valor de la variable de modo de pantalla completa void Title::switchFullScreenModeVar() { - switch (options->fullScreenMode) + switch (options->videoMode) { case 0: - options->fullScreenMode = SDL_WINDOW_FULLSCREEN; + options->videoMode = SDL_WINDOW_FULLSCREEN; break; case SDL_WINDOW_FULLSCREEN: - options->fullScreenMode = SDL_WINDOW_FULLSCREEN_DESKTOP; + options->videoMode = SDL_WINDOW_FULLSCREEN_DESKTOP; break; case SDL_WINDOW_FULLSCREEN_DESKTOP: - options->fullScreenMode = 0; + options->videoMode = 0; break; default: - options->fullScreenMode = 0; + options->videoMode = 0; break; } } @@ -869,7 +869,7 @@ void Title::updateMenuLabels() i++; // DISPLAY MODE - OPTIONS - switch (options->fullScreenMode) + switch (options->videoMode) { case 0: menu.options->setItemCaption(i, lang->getText(4)); // WINDOW @@ -945,7 +945,7 @@ void Title::updateMenuLabels() // Aplica las opciones de menu seleccionadas void Title::applyOptions() { - screen->setVideoMode(options->fullScreenMode); + screen->setVideoMode(options->videoMode); lang->setLang(options->language);