From 9e089e9092b9c965efb2c3d0cb6016ff244f3aec Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Mon, 26 Sep 2022 10:17:54 +0200 Subject: [PATCH] =?UTF-8?q?A=C3=B1adiendo=20la=20clase=20asset?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/asset.cpp | 160 +++++++ source/asset.h | 64 +++ source/director.cpp | 183 +++++---- source/director.h | 69 ++-- source/game.cpp | 102 ++--- source/game.h | 5 +- source/instructions.cpp | 14 +- source/instructions.h | 5 +- source/intro.cpp | 32 +- source/intro.h | 9 +- source/lang.cpp | 12 +- source/lang.h | 5 +- source/logo.cpp | 10 +- source/logo.h | 11 +- source/menu.cpp | 892 +++++++++++++++++++++++++++------------- source/menu.h | 180 ++++---- source/title.cpp | 36 +- source/title.h | 23 +- 18 files changed, 1190 insertions(+), 622 deletions(-) create mode 100644 source/asset.cpp create mode 100644 source/asset.h diff --git a/source/asset.cpp b/source/asset.cpp new file mode 100644 index 0000000..62f2114 --- /dev/null +++ b/source/asset.cpp @@ -0,0 +1,160 @@ +#include "asset.h" + +// Constructor +Asset::Asset(std::string path) +{ + executablePath = path; + longest_name = 0; +} + +// Destructor +Asset::~Asset() +{ +} + +// Añade un elemento a la lista +void Asset::add(std::string file, enum assetType type, bool required) +{ + item_t temp; + temp.file = executablePath + file; + temp.type = type; + temp.required = required; + fileList.push_back(temp); + + const std::string filename = file.substr(file.find_last_of("\\/") + 1); + longest_name = SDL_max(longest_name, filename.size()); +} + +// Devuelve el fichero de un elemento de la lista a partir de una cadena +std::string Asset::get(std::string text) +{ + for (auto f : fileList) + { + if (f.file.find(text) != std::string::npos) + { + return f.file; + } + } + + printf("Warning: file %s not found\n", text.c_str()); + return ""; +} + +// Comprueba que existen todos los elementos +bool Asset::check() +{ + bool success = true; + + printf("\n** Checking files.\n"); + + // Comprueba la lista de ficheros clasificandolos por tipo + for (int type = 0; type < maxAssetType; ++type) + { + // Comprueba si hay ficheros de ese tipo + bool any = false; + + for (auto f : fileList) + { + if ((f.required) && (f.type == type)) + { + any = true; + } + } + + // Si hay ficheros de ese tipo, comprueba si existen + if (any) + { + printf("\n>> %s FILES\n", getTypeName(type).c_str()); + + for (auto f : fileList) + { + if ((f.required) && (f.type == type)) + { + success &= checkFile(f.file); + } + } + } + } + + // Resultado + if (success) + { + printf("\n** All files OK.\n\n"); + } + else + { + printf("\n** A file is missing. Exiting.\n\n"); + } + + return success; +} + +// Comprueba que existe un fichero +bool Asset::checkFile(std::string path) +{ + bool success = false; + std::string result = "ERROR"; + + // Comprueba si existe el fichero + const std::string filename = path.substr(path.find_last_of("\\/") + 1); + SDL_RWops *file = SDL_RWFromFile(path.c_str(), "r+b"); + + if (file != nullptr) + { + result = "OK"; + success = true; + SDL_RWclose(file); + } + + const std::string s = "Checking file %-" + std::to_string(longest_name) + "s [" + result + "]\n"; + printf(s.c_str(), filename.c_str()); + + return success; +} + +// Devuelve el nombre del tipo de recurso +std::string Asset::getTypeName(int type) +{ + switch (type) + { + case bitmap: + return "BITMAP"; + break; + + case music: + return "MUSIC"; + break; + + case sound: + return "SOUND"; + break; + + case font: + return "FONT"; + break; + + case lang: + return "LANG"; + break; + + case data: + return "DATA"; + break; + + case room: + return "ROOM"; + break; + + case enemy: + return "ENEMY"; + break; + + case item: + return "ITEM"; + break; + + default: + return "ERROR"; + break; + } +} \ No newline at end of file diff --git a/source/asset.h b/source/asset.h new file mode 100644 index 0000000..242231b --- /dev/null +++ b/source/asset.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include +#include + +#ifndef ASSET_H +#define ASSET_H + +enum assetType +{ + bitmap, + music, + sound, + font, + lang, + data, + room, + enemy, + item, + maxAssetType +}; + +// Clase Asset +class Asset +{ +private: + // Estructura para definir un item + struct item_t + { + std::string file; // Ruta del fichero desde la raiz del directorio + enum assetType type; // Indica el tipo de recurso + bool required; // Indica si es un fichero que debe de existir + }; + + int longest_name; // Contiene la longitud del nombre de fichero mas largo + + std::vector fileList; + std::string executablePath; + + // Comprueba que existe un fichero + bool checkFile(std::string path); + + // Devuelve el nombre del tipo de recurso + std::string getTypeName(int type); + +public: + // Constructor + Asset(std::string path); + + // Destructor + ~Asset(); + + // Añade un elemento a la lista + void add(std::string file, enum assetType type, bool required = true); + + // Devuelve un elemento de la lista a partir de una cadena + std::string get(std::string text); + + // Comprueba que existen todos los elementos + bool check(); +}; + +#endif diff --git a/source/director.cpp b/source/director.cpp index 46582b5..f1e9787 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -7,26 +7,26 @@ // Constructor Director::Director(std::string path) { - // Inicializa la ruta - setExecutablePath(path); + // Crea el objeto que controla los ficheros de recursos + mAsset = new Asset(path.substr(0, path.find_last_of("\\/")) + "../"); + // Establece la lista de ficheros - setFileList(); - - // Si falta algún fichero no inicies el programa Uint8 section = PROG_SECTION_LOGO; - if (!checkFileList()) + if (!setFileList()) + {// Si falta algún fichero no inicies el programa section = PROG_SECTION_QUIT; + } // Crea el objeto de idioma - mLang = new Lang(mFileList); + mLang = new Lang(mAsset); // Crea el puntero a la estructura y carga el fichero de configuración mOptions = new options_t; loadConfigFile(); // Crea los objetos - mInput = new Input(mFileList[53]); + mInput = new Input(mAsset->get("controllerdb.txt")); // Inicializa SDL initSDL(); @@ -48,6 +48,9 @@ Director::~Director() { saveConfigFile(); + delete mAsset; + mAsset = nullptr; + delete mInput; mInput = nullptr; @@ -172,10 +175,82 @@ bool Director::initSDL() } // Crea el indice de ficheros -void Director::setFileList() +bool Director::setFileList() { + // Ficheros binarios + mAsset->add("data/score.bin", data, false); + mAsset->add("data/demo.bin", data); + mAsset->add("data/config.bin", data, false); + + // Musicas + mAsset->add("media/music/intro.ogg", music); + mAsset->add("media/music/playing.ogg", music); + mAsset->add("media/music/title.ogg", music); + + // Sonidos + mAsset->add("media/sound/balloon.wav", sound); + mAsset->add("media/sound/bubble1.wav", sound); + mAsset->add("media/sound/bubble2.wav", sound); + mAsset->add("media/sound/bubble3.wav", sound); + mAsset->add("media/sound/bubble4.wav", sound); + mAsset->add("media/sound/bullet.wav", sound); + mAsset->add("media/sound/coffeeout.wav", sound); + mAsset->add("media/sound/hiscore.wav", sound); + mAsset->add("media/sound/itemdrop.wav", sound); + mAsset->add("media/sound/itempickup.wav", sound); + mAsset->add("media/sound/menu_cancel.wav", sound); + mAsset->add("media/sound/menu_move.wav", sound); + mAsset->add("media/sound/menu_select.wav", sound); + mAsset->add("media/sound/player_collision.wav", sound); + mAsset->add("media/sound/stage_change.wav", sound); + mAsset->add("media/sound/title.wav", sound); + mAsset->add("media/sound/clock.wav", sound); + mAsset->add("media/sound/powerball.wav", sound); + + // Texturas + mAsset->add("media/gfx/balloon.png", bitmap); + mAsset->add("media/gfx/bullet.png", bitmap); + mAsset->add("media/gfx/game_bg.png", bitmap); + mAsset->add("media/gfx/game_text.png", bitmap); + mAsset->add("media/gfx/intro.png", bitmap); + mAsset->add("media/gfx/items.png", bitmap); + mAsset->add("media/gfx/logo.png", bitmap); + mAsset->add("media/gfx/player1_body.png", bitmap); + mAsset->add("media/gfx/player1_death.png", bitmap); + mAsset->add("media/gfx/player1_legs.png", bitmap); + mAsset->add("media/gfx/title.png", bitmap); + mAsset->add("media/gfx/player1_head.png", bitmap); + mAsset->add("media/gfx/player2_body.png", bitmap); + mAsset->add("media/gfx/player2_death.png", bitmap); + mAsset->add("media/gfx/player2_legs.png", bitmap); + mAsset->add("media/gfx/player2_head.png", bitmap); + + // Fuentes + mAsset->add("media/font/8bithud.png", font); + mAsset->add("media/font/8bithud.txt", font); + mAsset->add("media/font/nokia.png", font); + mAsset->add("media/font/nokia_big2.png", font); + mAsset->add("media/font/nokia.txt", font); + mAsset->add("media/font/nokia2.png", font); + mAsset->add("media/font/nokia2.txt", font); + mAsset->add("media/font/nokia_big2.txt", font); + mAsset->add("media/font/smb2_big.png", font); + mAsset->add("media/font/smb2_big.txt", font); + mAsset->add("media/font/smb2.png", font); + mAsset->add("media/font/smb2.txt", font); + + // Textos + mAsset->add("media/lang/es_ES.txt", lang); + mAsset->add("media/lang/en_UK.txt", lang); + mAsset->add("media/lang/ba_BA.txt", lang); + + // DATA + mAsset->add("data/gamecontrollerdb.txt", data); + + return mAsset->check(); + // Inicializa el vector - for (int i = 0; i < MAX_FILE_LIST; i++) + /*for (int i = 0; i < MAX_FILE_LIST; i++) mFileList[i] = ""; // Ficheros binarios @@ -247,69 +322,7 @@ void Director::setFileList() // DATA mFileList[53] = mExecutablePath + "/" + "../data/gamecontrollerdb.txt"; -} - -// Comprueba los ficheros del vector de ficheros que coinciden con una ruta dada -bool Director::checkFolder(std::string name, std::string path) -{ - bool success = true; - std::string p; - std::string filename; - SDL_RWops *file; - - // Comprueba los ficheros de la carpeta - printf("\n>> %s FILES\n", name.c_str()); - for (int i = 3; i < MAX_FILE_LIST; i++) - { - if (mFileList[i].find(path.c_str()) != std::string::npos) - { - p = mFileList[i].c_str(); - filename = p.substr(p.find_last_of("\\/") + 1); - file = SDL_RWFromFile(p.c_str(), "r+b"); - if (file != nullptr) - { - printf("Checking file %-20s [OK]\n", filename.c_str()); - } - else - { - printf("Checking file %-20s [ERROR]\n", filename.c_str()); - success = false; - break; - } - SDL_RWclose(file); - } - } - return success; -} - -// Comprueba que todos los ficheros existen -bool Director::checkFileList() -{ - bool success = true; - printf("Checking files...\n"); - - if (success) - success &= checkFolder("MUSIC", "/media/music/"); - - if (success) - success &= checkFolder("SOUND", "/media/sound/"); - - if (success) - success &= checkFolder("BITMAP", "/media/gfx/"); - - if (success) - success &= checkFolder("FONT", "/media/font/"); - - if (success) - success &= checkFolder("LANG", "/media/lang/"); - - // Resultado - if (success) - printf("\n** All files OK.\n\n"); - else - printf("\n** A file is missing. Exiting.\n\n"); - - return success; + */ } // Carga el fichero de configuración @@ -332,7 +345,7 @@ bool Director::loadConfigFile() // Indicador de éxito en la carga bool success = true; - const std::string p = mFileList[2]; + const std::string p = mAsset->get("config.bin"); std::string filename = p.substr(p.find_last_of("\\/") + 1); SDL_RWops *file = SDL_RWFromFile(p.c_str(), "r+b"); @@ -409,7 +422,7 @@ bool Director::loadConfigFile() bool Director::saveConfigFile() { bool success = true; - const std::string p = mFileList[2]; + const std::string p = mAsset->get("config.bin"); std::string filename = p.substr(p.find_last_of("\\/") + 1); SDL_RWops *file = SDL_RWFromFile(p.c_str(), "w+b"); if (file != nullptr) @@ -440,12 +453,6 @@ bool Director::saveConfigFile() return success; } -// Establece el valor de la variable -void Director::setExecutablePath(std::string path) -{ - mExecutablePath = path.substr(0, path.find_last_of("\\/")); -} - // Obtiene el valor de la variable Uint8 Director::getSubsection() { @@ -466,21 +473,21 @@ void Director::setSection(section_t section) void Director::runLogo() { - mLogo = new Logo(mRenderer, mScreen, mFileList); + mLogo = new Logo(mRenderer, mScreen, mAsset); setSection(mLogo->run()); delete mLogo; } void Director::runIntro() { - mIntro = new Intro(mRenderer, mScreen, mFileList, mLang); + mIntro = new Intro(mRenderer, mScreen, mAsset, mLang); setSection(mIntro->run()); delete mIntro; } void Director::runTitle() { - mTitle = new Title(mWindow, mRenderer, mScreen, mInput, mFileList, mOptions, mLang); + mTitle = new Title(mWindow, mRenderer, mScreen, mInput, mAsset, mOptions, mLang); setSection(mTitle->run(mSection.subsection)); delete mTitle; } @@ -489,14 +496,14 @@ void Director::runGame() { if (mSection.subsection == GAME_SECTION_PLAY_1P) { - mGame = new Game(1, 8, mRenderer, mScreen, mFileList, mLang, mInput, false, mOptions); + mGame = new Game(1, 0, mRenderer, mScreen, mAsset, mLang, mInput, false, mOptions); } - + else if (mSection.subsection == GAME_SECTION_PLAY_2P) { - mGame = new Game(2, 0, mRenderer, mScreen, mFileList, mLang, mInput, false, mOptions); + mGame = new Game(2, 0, mRenderer, mScreen, mAsset, mLang, mInput, false, mOptions); } - + setSection(mGame->run()); delete mGame; } diff --git a/source/director.h b/source/director.h index 03f53fc..01bf554 100644 --- a/source/director.h +++ b/source/director.h @@ -1,27 +1,28 @@ #pragma once #include -#include "sprite.h" -#include "movingsprite.h" -#include "smartsprite.h" -#include "player.h" +#include "asset.h" #include "balloon.h" #include "bullet.h" #include "coffeedrop.h" -#include "item.h" -#include "text.h" -#include "writer.h" -#include "menu.h" #include "const.h" -#include "jail_audio.h" -#include "utils.h" -#include "logo.h" -#include "intro.h" -#include "title.h" +#include "fade.h" #include "game.h" #include "input.h" +#include "intro.h" +#include "item.h" +#include "jail_audio.h" +#include "logo.h" +#include "menu.h" +#include "movingsprite.h" +#include "player.h" #include "screen.h" -#include "fade.h" +#include "smartsprite.h" +#include "sprite.h" +#include "text.h" +#include "title.h" +#include "utils.h" +#include "writer.h" #ifndef DIRECTOR_H #define DIRECTOR_H @@ -29,26 +30,23 @@ // Textos #define WINDOW_CAPTION "Coffee Crisis" -// Cantidad máxima de elementos para el vector con las rutas de los ficheros de recursos -#define MAX_FILE_LIST 100 - // Clase Director class Director { private: - SDL_Window *mWindow; // La ventana donde dibujamos - SDL_Renderer *mRenderer; // El renderizador de la ventana - Screen *mScreen; // Objeto encargado de dibujar en pantalla - Logo *mLogo; // Objeto para la sección del logo - Intro *mIntro; // Objeto para la sección de la intro - Title *mTitle; // Objeto para la sección del titulo y el menu de opciones - Game *mGame; // Objeto para la sección del juego - Input *mInput; // Objeto Input para gestionar las entradas - Lang *mLang; // Objeto para gestionar los textos en diferentes idiomas - std::string mFileList[MAX_FILE_LIST]; // Vector con las rutas a los ficheros de recursos - struct options_t *mOptions; // Variable con todas las opciones del programa - std::string mExecutablePath; // Path del ejecutable - section_t mSection; // Sección y subsección actual del programa; + SDL_Window *mWindow; // La ventana donde dibujamos + SDL_Renderer *mRenderer; // El renderizador de la ventana + Screen *mScreen; // Objeto encargado de dibujar en pantalla + Logo *mLogo; // Objeto para la sección del logo + Intro *mIntro; // Objeto para la sección de la intro + Title *mTitle; // Objeto para la sección del titulo y el menu de opciones + Game *mGame; // Objeto para la sección del juego + Input *mInput; // Objeto Input para gestionar las entradas + Lang *mLang; // Objeto para gestionar los textos en diferentes idiomas + Asset *mAsset; // Objeto que gestiona todos los ficheros de recursos + struct options_t *mOptions; // Variable con todas las opciones del programa + std::string mExecutablePath; // Path del ejecutable + section_t mSection; // Sección y subsección actual del programa; // Inicializa jail_audio void initJailAudio(); @@ -57,10 +55,7 @@ private: bool initSDL(); // Crea el indice de ficheros - void setFileList(); - - // Comprueba que todos los ficheros existen - bool checkFileList(); + bool setFileList(); // Carga el fichero de configuración bool loadConfigFile(); @@ -68,9 +63,6 @@ private: // Guarda el fichero de configuración bool saveConfigFile(); - // Establece el valor de la variable - void setExecutablePath(std::string path); - // Obtiene el valor de la variable Uint8 getSubsection(); @@ -92,9 +84,6 @@ private: // Ejecuta la seccion de juego donde se juega void runGame(); - // Comprueba los ficheros del vector de ficheros que coinciden con una ruta dada - bool checkFolder(std::string name, std::string path); - public: // Constructor Director(std::string path); diff --git a/source/game.cpp b/source/game.cpp index 040c7e9..47b86ce 100644 --- a/source/game.cpp +++ b/source/game.cpp @@ -1,12 +1,12 @@ #include "game.h" // Constructor -Game::Game(int numPlayers, int currentStage, SDL_Renderer *renderer, Screen *screen, std::string *filelist, Lang *lang, Input *input, bool demo, options_t *options) +Game::Game(int numPlayers, int currentStage, SDL_Renderer *renderer, Screen *screen, Asset *mAsset, Lang *lang, Input *input, bool demo, options_t *options) { // Copia los punteros mRenderer = renderer; mScreen = screen; - mFileList = filelist; + this->mAsset = mAsset; mLang = lang; mInput = input; mOptions = options; @@ -68,14 +68,14 @@ Game::Game(int numPlayers, int currentStage, SDL_Renderer *renderer, Screen *scr mTextureTextNokia2 = new LTexture(mRenderer); mTextureTextNokiaBig2 = new LTexture(mRenderer); - mText = new Text(mFileList[48], mTextureText, mRenderer); - mTextScoreBoard = new Text(mFileList[46], mTextureTextScoreBoard, mRenderer); - mTextBig = new Text(mFileList[47], mTextureTextBig, mRenderer); - mTextNokia2 = new Text(mFileList[57], mTextureTextNokia2, mRenderer); - mTextNokiaBig2 = new Text(mFileList[55], mTextureTextNokiaBig2, mRenderer); + mText = new Text(mAsset->get("smb2.txt"), mTextureText, mRenderer); + mTextScoreBoard = new Text(mAsset->get("8bithud.txt"), mTextureTextScoreBoard, mRenderer); + mTextBig = new Text(mAsset->get("smb2_big.txt"), mTextureTextBig, mRenderer); + mTextNokia2 = new Text(mAsset->get("nokia2.txt"), mTextureTextNokia2, mRenderer); + mTextNokiaBig2 = new Text(mAsset->get("nokia_big2.txt"), mTextureTextNokiaBig2, mRenderer); - mMenuGameOver = new Menu(mRenderer, mText, mInput, mFileList); - mMenuPause = new Menu(mRenderer, mText, mInput, mFileList); + mMenuGameOver = new Menu(mRenderer, mText, mInput, mAsset); + mMenuPause = new Menu(mRenderer, mText, mInput, mAsset); mFade = new Fade(mRenderer); mEventHandler = new SDL_Event(); @@ -104,7 +104,7 @@ Game::~Game() mRenderer = nullptr; mScreen = nullptr; - mFileList = nullptr; + mAsset = nullptr; mLang = nullptr; mInput = nullptr; @@ -549,47 +549,47 @@ bool Game::loadMedia() bool success = true; // Texturas - success &= loadTextureFromFile(mTextureText, mFileList[30], mRenderer); - success &= loadTextureFromFile(mTextureTextScoreBoard, mFileList[27], mRenderer); - success &= loadTextureFromFile(mTextureTextBig, mFileList[29], mRenderer); - success &= loadTextureFromFile(mTextureTextNokia2, mFileList[56], mRenderer); - success &= loadTextureFromFile(mTextureTextNokiaBig2, mFileList[54], mRenderer); + success &= loadTextureFromFile(mTextureText, mAsset->get("smb2.png"), mRenderer); + success &= loadTextureFromFile(mTextureTextScoreBoard, mAsset->get("8bithud.png"), mRenderer); + success &= loadTextureFromFile(mTextureTextBig, mAsset->get("smb2_big.png"), mRenderer); + success &= loadTextureFromFile(mTextureTextNokia2, mAsset->get("nokia2.png"), mRenderer); + success &= loadTextureFromFile(mTextureTextNokiaBig2, mAsset->get("nokia_big2.png"), mRenderer); - success &= loadTextureFromFile(mTexturePlayer1Legs, mFileList[39], mRenderer); - success &= loadTextureFromFile(mTexturePlayer1Head, mFileList[41], mRenderer); - success &= loadTextureFromFile(mTexturePlayer1Body, mFileList[37], mRenderer); - success &= loadTextureFromFile(mTexturePlayer1Death, mFileList[38], mRenderer); + success &= loadTextureFromFile(mTexturePlayer1Legs, mAsset->get("player1_legs.png"), mRenderer); + success &= loadTextureFromFile(mTexturePlayer1Head, mAsset->get("player1_head.png"), mRenderer); + success &= loadTextureFromFile(mTexturePlayer1Body, mAsset->get("player1_body.png"), mRenderer); + success &= loadTextureFromFile(mTexturePlayer1Death, mAsset->get("player1_death.png"), mRenderer); - success &= loadTextureFromFile(mTexturePlayer2Legs, mFileList[44], mRenderer); - success &= loadTextureFromFile(mTexturePlayer2Head, mFileList[45], mRenderer); - success &= loadTextureFromFile(mTexturePlayer2Body, mFileList[42], mRenderer); - success &= loadTextureFromFile(mTexturePlayer2Death, mFileList[43], mRenderer); + success &= loadTextureFromFile(mTexturePlayer2Legs, mAsset->get("player2_legs.png"), mRenderer); + success &= loadTextureFromFile(mTexturePlayer2Head, mAsset->get("player2_head.png"), mRenderer); + success &= loadTextureFromFile(mTexturePlayer2Body, mAsset->get("player2_body.png"), mRenderer); + success &= loadTextureFromFile(mTexturePlayer2Death, mAsset->get("player2_death.png"), mRenderer); - success &= loadTextureFromFile(mTextureBalloon, mFileList[24], mRenderer); - success &= loadTextureFromFile(mTextureBullet, mFileList[25], mRenderer); - success &= loadTextureFromFile(mTextureGameBG, mFileList[31], mRenderer); - success &= loadTextureFromFile(mTextureItems, mFileList[34], mRenderer); - success &= loadTextureFromFile(mTextureGameText, mFileList[32], mRenderer); + success &= loadTextureFromFile(mTextureBalloon, mAsset->get("balloon.png"), mRenderer); + success &= loadTextureFromFile(mTextureBullet, mAsset->get("bullet.png"), mRenderer); + success &= loadTextureFromFile(mTextureGameBG, mAsset->get("game_bg.png"), mRenderer); + success &= loadTextureFromFile(mTextureItems, mAsset->get("items.png"), mRenderer); + success &= loadTextureFromFile(mTextureGameText, mAsset->get("game_text.png"), mRenderer); // Sonidos - mSoundBalloon = JA_LoadSound(mFileList[6].c_str()); - mSoundBubble1 = JA_LoadSound(mFileList[7].c_str()); - mSoundBubble2 = JA_LoadSound(mFileList[8].c_str()); - mSoundBubble3 = JA_LoadSound(mFileList[9].c_str()); - mSoundBubble4 = JA_LoadSound(mFileList[10].c_str()); - mSoundBullet = JA_LoadSound(mFileList[11].c_str()); - mSoundClock = JA_LoadSound(mFileList[22].c_str()); - mSoundCoffeeOut = JA_LoadSound(mFileList[12].c_str()); - mSoundHiScore = JA_LoadSound(mFileList[13].c_str()); - mSoundItemDrop = JA_LoadSound(mFileList[14].c_str()); - mSoundItemPickup = JA_LoadSound(mFileList[15].c_str()); - mSoundPlayerCollision = JA_LoadSound(mFileList[19].c_str()); - mSoundPowerBall = JA_LoadSound(mFileList[23].c_str()); - mSoundStageChange = JA_LoadSound(mFileList[20].c_str()); - mSoundCollision = JA_LoadSound(mFileList[21].c_str()); + mSoundBalloon = JA_LoadSound(mAsset->get("balloon.wav").c_str()); + mSoundBubble1 = JA_LoadSound(mAsset->get("bubble1.wav").c_str()); + mSoundBubble2 = JA_LoadSound(mAsset->get("bubble2.wav").c_str()); + mSoundBubble3 = JA_LoadSound(mAsset->get("bubble3.wav").c_str()); + mSoundBubble4 = JA_LoadSound(mAsset->get("bubble4.wav").c_str()); + mSoundBullet = JA_LoadSound(mAsset->get("bullet.wav").c_str()); + mSoundClock = JA_LoadSound(mAsset->get("clock.wav").c_str()); + mSoundCoffeeOut = JA_LoadSound(mAsset->get("coffeeout.wav").c_str()); + mSoundHiScore = JA_LoadSound(mAsset->get("hiscore.wav").c_str()); + mSoundItemDrop = JA_LoadSound(mAsset->get("itemdrop.wav").c_str()); + mSoundItemPickup = JA_LoadSound(mAsset->get("itempickup.wav").c_str()); + mSoundPlayerCollision = JA_LoadSound(mAsset->get("player_collision.wav").c_str()); + mSoundPowerBall = JA_LoadSound(mAsset->get("powerball.wav").c_str()); + mSoundStageChange = JA_LoadSound(mAsset->get("stage_change.wav").c_str()); + mSoundCollision = JA_LoadSound(mAsset->get("title.wav").c_str()); // Musicas - mMusicPlaying = JA_LoadMusic(mFileList[4].c_str()); + mMusicPlaying = JA_LoadMusic(mAsset->get("playing.ogg").c_str()); return success; } @@ -599,7 +599,7 @@ bool Game::loadScoreFile() { // Indicador de éxito en la carga bool success = true; - const std::string p = mFileList[0]; + const std::string p = mAsset->get("score.bin"); const std::string filename = p.substr(p.find_last_of("\\/") + 1); SDL_RWops *file = SDL_RWFromFile(p.c_str(), "r+b"); @@ -644,12 +644,12 @@ bool Game::loadScoreFile() // Establece el valor de la máxima puntuación a partir del vector con los datos if (mScoreDataFile[0] == 0) - mHiScore = 10000; + {mHiScore = 10000;} // Comprueba el checksum para ver si se ha modificado el fichero else if (mScoreDataFile[0] % 43 == mScoreDataFile[1]) - mHiScore = mScoreDataFile[0]; + {mHiScore = mScoreDataFile[0];} else - mHiScore = 10000; + {mHiScore = 10000;} return success; } @@ -659,7 +659,7 @@ bool Game::loadDemoFile() { // Indicador de éxito en la carga bool success = true; - const std::string p = mFileList[1]; + const std::string p = mAsset->get("demo.bin"); const std::string filename = p.substr(p.find_last_of("\\/") + 1); SDL_RWops *file = SDL_RWFromFile(p.c_str(), "r+b"); @@ -715,7 +715,7 @@ bool Game::loadDemoFile() bool Game::saveScoreFile() { bool success = true; - const std::string p = mFileList[0]; + const std::string p = mAsset->get("score.bin"); const std::string filename = p.substr(p.find_last_of("\\/") + 1); SDL_RWops *file = SDL_RWFromFile(p.c_str(), "w+b"); if (file != nullptr) @@ -742,7 +742,7 @@ bool Game::saveScoreFile() bool Game::saveDemoFile() { bool success = true; - const std::string p = mFileList[1]; + const std::string p = mAsset->get("demo.bin"); const std::string filename = p.substr(p.find_last_of("\\/") + 1); if (mDemo.recording) { diff --git a/source/game.h b/source/game.h index 42d4667..86deb78 100644 --- a/source/game.h +++ b/source/game.h @@ -1,6 +1,7 @@ #pragma once #include +#include "asset.h" #include "balloon.h" #include "bullet.h" #include "const.h" @@ -129,7 +130,7 @@ private: SDL_Renderer *mRenderer; // El renderizador de la ventana Screen *mScreen; // Objeto encargado de dibujar en pantalla - std::string *mFileList; // Lista de ficheros con los recursos + Asset *mAsset; // Objeto que gestiona todos los ficheros de recursos Lang *mLang; // Objeto para gestionar los textos en diferentes idiomas int mNumPlayers; // Numero de jugadores @@ -518,7 +519,7 @@ private: public: // Constructor - Game(int numPlayers, int currentStage, SDL_Renderer *renderer, Screen *screen, std::string *filelist, Lang *lang, Input *input, bool demo, options_t *options); + Game(int numPlayers, int currentStage, SDL_Renderer *renderer, Screen *screen, Asset *mAsset, Lang *lang, Input *input, bool demo, options_t *options); // Destructor ~Game(); diff --git a/source/instructions.cpp b/source/instructions.cpp index 40ecf54..9fb9e10 100644 --- a/source/instructions.cpp +++ b/source/instructions.cpp @@ -3,12 +3,12 @@ const Uint8 SELF = 0; // Constructor -Instructions::Instructions(SDL_Renderer *renderer, Screen *screen, std::string *fileList, Lang *lang) +Instructions::Instructions(SDL_Renderer *renderer, Screen *screen, Asset *mAsset, Lang *lang) { // Copia los punteros mRenderer = renderer; mScreen = screen; - mFileList = fileList; + this->mAsset = mAsset; mLang = lang; // Reserva memoria para los punteros @@ -16,12 +16,14 @@ Instructions::Instructions(SDL_Renderer *renderer, Screen *screen, std::string * mItemTexture = new LTexture(mRenderer); mTextTexture = new LTexture(mRenderer); mSprite = new Sprite(); - mText = new Text(mFileList[48], mTextTexture, mRenderer); + mText = new Text(mAsset->get("smb2.txt"), mTextTexture, mRenderer); // Crea un backbuffer para el renderizador mBackbuffer = SDL_CreateTexture(mRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, SCREEN_WIDTH, SCREEN_HEIGHT); if (mBackbuffer == nullptr) + { printf("Backbuffer could not be created!\nSDL Error: %s\n", SDL_GetError()); + } } // Destructor @@ -29,7 +31,7 @@ Instructions::~Instructions() { mRenderer = nullptr; mScreen = nullptr; - mFileList = nullptr; + mAsset = nullptr; mLang = nullptr; mItemTexture->unload(); @@ -58,8 +60,8 @@ bool Instructions::loadMedia() { bool success = true; - success &= loadTextureFromFile(mItemTexture, mFileList[34], mRenderer); - success &= loadTextureFromFile(mTextTexture, mFileList[30], mRenderer); + success &= loadTextureFromFile(mItemTexture, mAsset->get("items.png"), mRenderer); + success &= loadTextureFromFile(mTextTexture, mAsset->get("smb2.png"), mRenderer); return success; } diff --git a/source/instructions.h b/source/instructions.h index bc8c4e8..4bfc3cd 100644 --- a/source/instructions.h +++ b/source/instructions.h @@ -1,6 +1,7 @@ #pragma once #include +#include "asset.h" #include "const.h" #include "jail_audio.h" #include "screen.h" @@ -29,7 +30,7 @@ private: SDL_Event *mEventHandler; // Manejador de eventos SDL_Texture *mBackbuffer; // Textura para usar como backbuffer Sprite *mSprite; // Sprite con la textura de las instrucciones - std::string *mFileList; // Lista de ficheros + Asset *mAsset; // Objeto que gestiona todos los ficheros de recursos Lang *mLang; // Objeto para gestionar los textos en diferentes idiomas Text *mText; // Objeto para escribir texto Uint16 mCounter; // Contador @@ -52,7 +53,7 @@ private: public: // Constructor - Instructions(SDL_Renderer *renderer, Screen *screen, std::string *fileList, Lang *lang); + Instructions(SDL_Renderer *renderer, Screen *screen, Asset *mAsset, Lang *lang); // Destructor ~Instructions(); diff --git a/source/intro.cpp b/source/intro.cpp index 04b6201..474613e 100644 --- a/source/intro.cpp +++ b/source/intro.cpp @@ -1,25 +1,29 @@ #include "intro.h" // Constructor -Intro::Intro(SDL_Renderer *renderer, Screen *screen, std::string *fileList, Lang *lang) +Intro::Intro(SDL_Renderer *renderer, Screen *screen, Asset *mAsset, Lang *lang) { // Copia los punteros mRenderer = renderer; mScreen = screen; - mFileList = fileList; mLang = lang; + this->mAsset = mAsset; // Reserva memoria para los punteros mEventHandler = new SDL_Event(); mBitmapTexture = new LTexture(mRenderer); mTextTexture = new LTexture(mRenderer); - mText = new Text(mFileList[52], mTextTexture, mRenderer); + mText = new Text(mAsset->get("nokia.txt"), mTextTexture, mRenderer); for (int i = 0; i < INTRO_TOTAL_BITMAPS; i++) + { mBitmap[i] = new SmartSprite(); + } for (int i = 0; i < INTRO_TOTAL_TEXTS; i++) + { mWriter[i] = new Writer(mText); + } } // Destructor @@ -27,7 +31,7 @@ Intro::~Intro() { mRenderer = nullptr; mScreen = nullptr; - mFileList = nullptr; + mAsset = nullptr; mLang = nullptr; delete mEventHandler; @@ -192,11 +196,11 @@ bool Intro::loadMedia() bool success = true; // Texturas - success &= loadTextureFromFile(mBitmapTexture, mFileList[33], mRenderer); - success &= loadTextureFromFile(mTextTexture, mFileList[28], mRenderer); + success &= loadTextureFromFile(mBitmapTexture, mAsset->get("intro.png"), mRenderer); + success &= loadTextureFromFile(mTextTexture, mAsset->get("nokia.png"), mRenderer); // Musicas - mMusic = JA_LoadMusic(mFileList[3].c_str()); + mMusic = JA_LoadMusic(mAsset->get("intro.ogg").c_str()); return success; } @@ -208,7 +212,9 @@ section_t Intro::run() // Si la música no está sonando la hace sonar if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED)) + { JA_PlayMusic(mMusic, 0); + } while (mSection.name == PROG_SECTION_INTRO) { @@ -237,9 +243,13 @@ section_t Intro::run() // Actualiza los objetos for (int i = 0; i < INTRO_TOTAL_BITMAPS; i++) + { mBitmap[i]->update(); + } for (int i = 0; i < INTRO_TOTAL_TEXTS; i++) + { mWriter[i]->update(); + } // Guión de eventos // Primera imagen - UPV @@ -361,10 +371,14 @@ section_t Intro::run() mScreen->clean(bgColor); // Dibuja los objetos - for (int i = 0; i < INTRO_TOTAL_BITMAPS; i++) + for (int i = 0; i < INTRO_TOTAL_BITMAPS; ++i) + { mBitmap[i]->render(); - for (int i = 0; i < INTRO_TOTAL_TEXTS; i++) + } + for (int i = 0; i < INTRO_TOTAL_TEXTS; ++i) + { mWriter[i]->render(); + } // Vuelca el contenido del renderizador en pantalla mScreen->blit(); diff --git a/source/intro.h b/source/intro.h index dd320c8..6fb09df 100644 --- a/source/intro.h +++ b/source/intro.h @@ -1,12 +1,13 @@ #pragma once #include +#include "asset.h" #include "const.h" -#include "utils.h" +#include "jail_audio.h" #include "screen.h" #include "smartsprite.h" +#include "utils.h" #include "writer.h" -#include "jail_audio.h" #ifndef INTRO_H #define INTRO_H @@ -42,7 +43,7 @@ private: LTexture *mBitmapTexture; // Textura con los graficos LTexture *mTextTexture; // Textura con los caracteres de texto SDL_Event *mEventHandler; // Manejador de eventos - std::string *mFileList; // Lista de ficheros + Asset *mAsset; // Objeto que gestiona todos los ficheros de recursos Lang *mLang; // Objeto para gestionar los textos en diferentes idiomas section_t mSection; // Estado del bucle principal para saber si continua o se sale Uint32 mTicks; // Contador de ticks para ajustar la velocidad del programa @@ -58,7 +59,7 @@ private: public: // Constructor - Intro(SDL_Renderer *renderer, Screen *screen, std::string *fileList, Lang *lang); + Intro(SDL_Renderer *renderer, Screen *screen, Asset *mAsset, Lang *lang); // Destructor ~Intro(); diff --git a/source/lang.cpp b/source/lang.cpp index c739dd3..2a97501 100644 --- a/source/lang.cpp +++ b/source/lang.cpp @@ -3,9 +3,9 @@ #include // Constructor -Lang::Lang(std::string *fileList) +Lang::Lang(Asset *mAsset) { - mFileList = fileList; + this->mAsset = mAsset; } // Destructor @@ -21,19 +21,19 @@ bool Lang::setLang(Uint8 lang) switch (lang) { case es_ES: - file = mFileList[49]; + file = mAsset->get("es_ES.txt"); break; case en_UK: - file = mFileList[50]; + file = mAsset->get("en_UK.txt"); break; case ba_BA: - file = mFileList[51]; + file = mAsset->get("ba_BA.txt"); break; default: - file = mFileList[50]; + file = mAsset->get("en_UK.txt"); break; } diff --git a/source/lang.h b/source/lang.h index f7adc30..7cbe52b 100644 --- a/source/lang.h +++ b/source/lang.h @@ -1,6 +1,7 @@ #pragma once #include +#include "asset.h" #include #ifndef LANG_H @@ -19,12 +20,12 @@ class Lang { private: - std::string *mFileList; // Lista de ficheros con los recursos + Asset *mAsset; // Objeto que gestiona todos los ficheros de recursos std::string mTextStrings[MAX_TEXT_STRINGS]; // Vector con los textos public: // Constructor - Lang(std::string *fileList); + Lang(Asset *mAsset); // Destructor ~Lang(); diff --git a/source/logo.cpp b/source/logo.cpp index ddb96ab..0a4cbcb 100644 --- a/source/logo.cpp +++ b/source/logo.cpp @@ -4,12 +4,12 @@ #define END_LOGO 200 // Constructor -Logo::Logo(SDL_Renderer *renderer, Screen *screen, std::string *fileList) +Logo::Logo(SDL_Renderer *renderer, Screen *screen, Asset *mAsset) { // Copia la dirección de los objetos mRenderer = renderer; mScreen = screen; - mFileList = fileList; + this->mAsset = mAsset; // Reserva memoria para los punteros mEventHandler = new SDL_Event(); @@ -19,7 +19,9 @@ Logo::Logo(SDL_Renderer *renderer, Screen *screen, std::string *fileList) // Crea un backbuffer para el renderizador mBackbuffer = SDL_CreateTexture(mRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, SCREEN_WIDTH, SCREEN_HEIGHT); if (mBackbuffer == nullptr) + { printf("Backbuffer could not be created!\nSDL Error: %s\n", SDL_GetError()); + } } // Destructor @@ -27,7 +29,7 @@ Logo::~Logo() { mRenderer = nullptr; mScreen = nullptr; - mFileList = nullptr; + mAsset = nullptr; mTexture->unload(); delete mTexture; @@ -63,7 +65,7 @@ bool Logo::loadMedia() { bool success = true; - success &= loadTextureFromFile(mTexture, mFileList[35], mRenderer); + success &= loadTextureFromFile(mTexture, mAsset->get("logo.png"), mRenderer); return success; } diff --git a/source/logo.h b/source/logo.h index e95222b..5196cde 100644 --- a/source/logo.h +++ b/source/logo.h @@ -1,11 +1,12 @@ #pragma once #include +#include "asset.h" #include "const.h" -#include "utils.h" -#include "sprite.h" -#include "screen.h" #include "jail_audio.h" +#include "screen.h" +#include "sprite.h" +#include "utils.h" #ifndef LOGO_H #define LOGO_H @@ -16,7 +17,7 @@ class Logo private: SDL_Renderer *mRenderer; // El renderizador de la ventana Screen *mScreen; // Objeto encargado de dibujar en pantalla - std::string *mFileList; // Lista de ficheros + Asset *mAsset; // Objeto que gestiona todos los ficheros de recursos LTexture *mTexture; // Textura con los graficos SDL_Event *mEventHandler; // Manejador de eventos SDL_Texture *mBackbuffer; // Textura para usar como backbuffer @@ -28,7 +29,7 @@ private: public: // Constructor - Logo(SDL_Renderer *renderer, Screen *screen, std::string *fileList); + Logo(SDL_Renderer *renderer, Screen *screen, Asset *mAsset); // Destructor ~Logo(); diff --git a/source/menu.cpp b/source/menu.cpp index 62271d8..78a2627 100644 --- a/source/menu.cpp +++ b/source/menu.cpp @@ -2,194 +2,477 @@ #include "menu.h" // Constructor -Menu::Menu(SDL_Renderer *renderer, Text *text, Input *input, std::string *fileList) +Menu::Menu(SDL_Renderer *renderer, Asset *asset, Input *input, std::string file) { - mRenderer = renderer; - mText = text; - mInput = input; - mFileList = fileList; + this->renderer = renderer; + this->asset = asset; + this->input = input; + + soundMove = nullptr; + soundAccept = nullptr; + soundCancel = nullptr; + + init(); + if (file != "") + { + load(file); + } + reorganize(); } Menu::~Menu() { - mRenderer = nullptr; - mText = nullptr; - mInput = nullptr; - mFileList = nullptr; -} + renderer = nullptr; + asset = nullptr; + input = nullptr; -// Inicializador -void Menu::init(std::string name, int x, int y, int backgroundType) -{ - loadMedia(); - - // Inicia variables - mName = name; - mSelector.index = 0; - mTotalItems = 0; - mItemSelected = MENU_NO_OPTION; - mPosX = x; - mPosY = y; - mRectBG.rect.x = 0; - mRectBG.rect.y = 0; - mRectBG.rect.w = 0; - mRectBG.rect.h = 0; - mRectBG.r = 0; - mRectBG.g = 0; - mRectBG.b = 0; - mBackgroundType = backgroundType; - mIsCenteredOnX = false; - mIsCenteredOnY = false; - mAreElementsCenteredOnX = false; - mCenterX = 0; - mCenterY = 0; - mWidestItem = 0; - mColorGreyed = {128, 128, 128}; - - // Selector - mSelector.originY = 0; - mSelector.targetY = 0; - mSelector.despY = 0; - mSelector.originH = 0; - mSelector.targetH = 0; - mSelector.incH = 0; - mSelector.y = 0.0f; - mSelector.h = 0.0f; - mSelector.numJumps = 8; - mSelector.moving = false; - mSelector.resizing = false; - mSelector.rect = {0, 0, 0, 0}; - mSelector.r = 0; - mSelector.g = 0; - mSelector.b = 0; - mSelector.a = 255; - - // Elementos del menu - for (int i = 0; i < MENU_MAX_ITEMS; i++) + if (soundMove) { - mItem[i].label = ""; - mItem[i].rect = {0, 0, 0, 0}; - mItem[i].hPaddingDown = 0; - mItem[i].selectable = false; - mItem[i].greyed = false; - mItem[i].linkedDown = false; - mItem[i].linkedUp = false; + JA_DeleteSound(soundMove); + } + + if (soundAccept) + { + JA_DeleteSound(soundAccept); + } + + if (soundCancel) + { + JA_DeleteSound(soundCancel); + } + + if (text != nullptr) + { + delete text; } } -// Carga los recursos necesarios para la sección 'Title' -bool Menu::loadMedia() +// Carga la configuración del menu desde un archivo de texto +bool Menu::load(std::string file_path) { // Indicador de éxito en la carga bool success = true; - // Sonidos - mSoundMove = JA_LoadSound(mFileList[17].c_str()); - mSoundAccept = JA_LoadSound(mFileList[18].c_str()); - mSoundCancel = JA_LoadSound(mFileList[16].c_str()); + // Indica si se ha creado ya el objeto de texto + bool textAllocated = false; + + std::string filename = file_path.substr(file_path.find_last_of("\\/") + 1); + std::string line; + std::ifstream file(file_path); + + // El fichero se puede abrir + if (file.good()) + { + // Procesa el fichero linea a linea + printf("Reading file %s\n", filename.c_str()); + while (std::getline(file, line)) + { + if (line == "[item]") + { + item_t item; + item.label = ""; + item.hPaddingDown = 1; + item.selectable = true; + item.greyed = false; + item.linkedDown = false; + + do + { + + std::getline(file, line); + + // Encuentra la posición del caracter '=' + int pos = line.find("="); + + // Procesa las dos subcadenas + if (!setItem(&item, line.substr(0, pos), line.substr(pos + 1, line.length()))) + { + printf("Warning: file %s\n, unknown parameter \"%s\"\n", filename.c_str(), line.substr(0, pos).c_str()); + success = false; + } + + } while (line != "[/item]"); + + addItem(item.label, item.hPaddingDown, item.selectable, item.greyed, item.linkedDown); + } + + // En caso contrario se parsea el fichero para buscar las variables y los valores + else + { + // Encuentra la posición del caracter '=' + int pos = line.find("="); + // Procesa las dos subcadenas + if (!setVars(line.substr(0, pos), line.substr(pos + 1, line.length()))) + { + printf("Warning: file %s, unknown parameter \"%s\"\n", filename.c_str(), line.substr(0, pos).c_str()); + success = false; + } + + // Crea el objeto text tan pronto como se pueda. Necesario para añadir items + if (font_png != "" && font_txt != "" && !textAllocated) + { + text = new Text(asset->get(font_png), asset->get(font_txt), renderer); + textAllocated = true; + } + } + } + + // Cierra el fichero + printf("Closing file %s\n\n", filename.c_str()); + file.close(); + } + // El fichero no se puede abrir + else + { + printf("Warning: Unable to open %s file\n", filename.c_str()); + success = false; + } return success; } +// Asigna variables a partir de dos cadenas +bool Menu::setItem(item_t *item, std::string var, std::string value) +{ + // Indicador de éxito en la asignación + bool success = true; + + if (var == "text") + { + item->label = value; + } + + else if (var == "hPaddingDown") + { + item->hPaddingDown = std::stoi(value); + } + + else if (var == "selectable") + { + item->selectable = value == "true" ? true : false; + } + + else if (var == "greyed") + { + item->greyed = value == "true" ? true : false; + } + + else if (var == "linkedDown") + { + item->linkedDown = value == "true" ? true : false; + } + + else if ((var == "") || (var == "[/item]")) + { + } + else + { + success = false; + } + + return success; +} + +// Asigna variables a partir de dos cadenas +bool Menu::setVars(std::string var, std::string value) +{ + // Indicador de éxito en la asignación + bool success = true; + + if (var == "font_png") + { + font_png = value; + } + + else if (var == "font_txt") + { + font_txt = value; + } + + else if (var == "sound_cancel") + { + soundCancel = JA_LoadSound(asset->get(value).c_str()); + } + + else if (var == "sound_accept") + { + soundAccept = JA_LoadSound(asset->get(value).c_str()); + } + + else if (var == "sound_move") + { + soundMove = JA_LoadSound(asset->get(value).c_str()); + } + + else if (var == "name") + { + name = value; + } + + else if (var == "x") + { + x = std::stoi(value); + } + + else if (var == "centerX") + { + centerX = std::stoi(value); + } + + else if (var == "centerY") + { + centerY = std::stoi(value); + } + + else if (var == "y") + { + y = std::stoi(value); + } + + else if (var == "backgroundType") + { + backgroundType = std::stoi(value); + } + + else if (var == "backgroundColor") + { + // Se introducen los valores separados por comas en un vector + std::stringstream ss(value); + std::string tmp; + getline(ss, tmp, ','); + rectBG.color.r = std::stoi(tmp); + getline(ss, tmp, ','); + rectBG.color.g = std::stoi(tmp); + getline(ss, tmp, ','); + rectBG.color.b = std::stoi(tmp); + getline(ss, tmp, ','); + rectBG.a = std::stoi(tmp); + } + + else if (var == "selector_color") + { + // Se introducen los valores separados por comas en un vector + std::stringstream ss(value); + std::string tmp; + getline(ss, tmp, ','); + selector.color.r = std::stoi(tmp); + getline(ss, tmp, ','); + selector.color.g = std::stoi(tmp); + getline(ss, tmp, ','); + selector.color.b = std::stoi(tmp); + getline(ss, tmp, ','); + selector.a = std::stoi(tmp); + } + + else if (var == "selector_text_color") + { + // Se introducen los valores separados por comas en un vector + std::stringstream ss(value); + std::string tmp; + getline(ss, tmp, ','); + selector.itemColor.r = std::stoi(tmp); + getline(ss, tmp, ','); + selector.itemColor.g = std::stoi(tmp); + getline(ss, tmp, ','); + selector.itemColor.b = std::stoi(tmp); + } + + else if (var == "areElementsCenteredOnX") + { + areElementsCenteredOnX = value == "true" ? true : false; + } + + else if (var == "isCenteredOnX") + { + isCenteredOnX = value == "true" ? true : false; + } + + else if (var == "isCenteredOnY") + { + isCenteredOnY = value == "true" ? true : false; + } + + else if (var == "defaultActionWhenCancel") + { + defaultActionWhenCancel = std::stoi(value); + } + + else if (var == "") + { + } + + else + { + success = false; + } + + return success; +} + +// Inicializa las variables +void Menu::init() +{ + // Inicia variables + name = ""; + selector.index = 0; + itemSelected = MENU_NO_OPTION; + x = 0; + y = 0; + rectBG.rect = {0, 0, 0, 0}; + rectBG.color = {0, 0, 0}; + rectBG.a = 0; + backgroundType = MENU_BACKGROUND_SOLID; + isCenteredOnX = false; + isCenteredOnY = false; + areElementsCenteredOnX = false; + centerX = 0; + centerY = 0; + widestItem = 0; + colorGreyed = {128, 128, 128}; + defaultActionWhenCancel = 0; + font_png = ""; + font_txt = ""; + + // Selector + selector.originY = 0; + selector.targetY = 0; + selector.despY = 0; + selector.originH = 0; + selector.targetH = 0; + selector.incH = 0; + selector.y = 0.0f; + selector.h = 0.0f; + selector.numJumps = 8; + selector.moving = false; + selector.resizing = false; + selector.rect = {0, 0, 0, 0}; + selector.color = {0, 0, 0}; + selector.itemColor = {0, 0, 0}; + selector.a = 255; +} + +// Carga los ficheros de audio +void Menu::loadAudioFile(std::string file, int sound) +{ + switch (sound) + { + case SOUND_ACCEPT: + soundAccept = JA_LoadSound(file.c_str()); + break; + + case SOUND_CANCEL: + soundCancel = JA_LoadSound(file.c_str()); + break; + + case SOUND_MOVE: + soundMove = JA_LoadSound(file.c_str()); + break; + + default: + break; + } +} + // Obtiene el nombre del menu std::string Menu::getName() { - return mName; + return name; } // Obtiene el valor de la variable -Uint8 Menu::getItemSelected() +int Menu::getItemSelected() { // Al llamar a esta funcion, se obtiene el valor y se borra - const int temp = mItemSelected; - mItemSelected = MENU_NO_OPTION; + const int temp = itemSelected; + itemSelected = MENU_NO_OPTION; return temp; } // Actualiza la posicion y el estado del selector void Menu::updateSelector() { - if (mSelector.moving) + if (selector.moving) { // Calcula el desplazamiento en Y - mSelector.y += mSelector.despY; - if (mSelector.despY > 0) // Va hacia abajo + selector.y += selector.despY; + if (selector.despY > 0) // Va hacia abajo { - if (mSelector.y > mSelector.targetY) // Ha llegado al destino + if (selector.y > selector.targetY) // Ha llegado al destino { - mSelector.originY = mSelector.y = mSelector.targetY; - mSelector.moving = false; + selector.originY = selector.y = selector.targetY; + selector.moving = false; } } - if (mSelector.despY < 0) // Va hacia arriba + if (selector.despY < 0) // Va hacia arriba { - if (mSelector.y < mSelector.targetY) // Ha llegado al destino + if (selector.y < selector.targetY) // Ha llegado al destino { - mSelector.originY = mSelector.y = mSelector.targetY; - mSelector.moving = false; + selector.originY = selector.y = selector.targetY; + selector.moving = false; } } - mSelector.rect.y = int(mSelector.y); + selector.rect.y = int(selector.y); } else { - mSelector.rect.y = int(mSelector.y); + selector.rect.y = int(selector.y); } - if (mSelector.resizing) + if (selector.resizing) { // Calcula el incremento en H - mSelector.h += mSelector.incH; - if (mSelector.incH > 0) // Crece + selector.h += selector.incH; + if (selector.incH > 0) // Crece { - if (mSelector.h > mSelector.targetH) // Ha llegado al destino + if (selector.h > selector.targetH) // Ha llegado al destino { - // mSelector.originH = mSelector.targetH = mSelector.rect.h = getSelectorHeight(mSelector.index); - mSelector.originH = mSelector.h = mSelector.targetH; - mSelector.resizing = false; + // selector.originH = selector.targetH = selector.rect.h = getSelectorHeight(selector.index); + selector.originH = selector.h = selector.targetH; + selector.resizing = false; } } - if (mSelector.incH < 0) // Decrece + if (selector.incH < 0) // Decrece { - if (mSelector.h < mSelector.targetH) // Ha llegado al destino + if (selector.h < selector.targetH) // Ha llegado al destino { - // mSelector.originH = mSelector.targetH = mSelector.rect.h = getSelectorHeight(mSelector.index); - mSelector.originH = mSelector.h = mSelector.targetH; - mSelector.resizing = false; + // selector.originH = selector.targetH = selector.rect.h = getSelectorHeight(selector.index); + selector.originH = selector.h = selector.targetH; + selector.resizing = false; } } - mSelector.rect.h = int(mSelector.h); + selector.rect.h = int(selector.h); } else { - mSelector.rect.h = getSelectorHeight(mSelector.index); + selector.rect.h = getSelectorHeight(selector.index); } } // Coloca el selector en una posición específica -void Menu::setSelectorPos(Uint8 index) +void Menu::setSelectorPos(int index) { - if (index < mTotalItems) + if (index < (int)item.size()) { - mSelector.index = index; - mSelector.rect.y = mSelector.y = mSelector.originY = mSelector.targetY = mItem[mSelector.index].rect.y; - mSelector.rect.w = mRectBG.rect.w; - mSelector.rect.x = mRectBG.rect.x; - mSelector.originH = mSelector.targetH = mSelector.rect.h = getSelectorHeight(mSelector.index); - mSelector.moving = false; - mSelector.resizing = false; + selector.index = index; + selector.rect.y = selector.y = selector.originY = selector.targetY = item[selector.index].rect.y; + selector.rect.w = rectBG.rect.w; + selector.rect.x = rectBG.rect.x; + selector.originH = selector.targetH = selector.rect.h = getSelectorHeight(selector.index); + selector.moving = false; + selector.resizing = false; } } // Obtiene la anchura del elemento más ancho del menu -Uint16 Menu::getWidestItem() +int Menu::getWidestItem() { - Uint16 result = 0; + int result = 0; // Obtenemos la anchura del item mas ancho - for (int i = 0; i < mTotalItems; i++) - if (mItem[i].rect.w > result) - result = mItem[i].rect.w; + for (auto &i : item) + { + result = std::max(result, i.rect.w); + } return result; } @@ -197,102 +480,114 @@ Uint16 Menu::getWidestItem() // Deja el menu apuntando al primer elemento void Menu::reset() { - mItemSelected = MENU_NO_OPTION; - mSelector.index = 0; - mSelector.originY = mSelector.targetY = mSelector.y = mItem[0].rect.y; - mSelector.originH = mSelector.targetH = mItem[0].rect.h; - mSelector.moving = false; - mSelector.resizing = false; + itemSelected = MENU_NO_OPTION; + selector.index = 0; + selector.originY = selector.targetY = selector.y = item[0].rect.y; + selector.originH = selector.targetH = item[0].rect.h; + selector.moving = false; + selector.resizing = false; } // Actualiza el menu para recolocarlo correctamente y establecer el tamaño void Menu::reorganize() { setRectSize(); - if (mIsCenteredOnX) - centerMenuOnX(mCenterX); - if (mIsCenteredOnY) - centerMenuOnY(mCenterY); - if (mAreElementsCenteredOnX) + + if (isCenteredOnX) + { + centerMenuOnX(centerX); + } + + if (isCenteredOnY) + { + centerMenuOnY(centerY); + } + + if (areElementsCenteredOnX) + { centerMenuElementsOnX(); + } } // Deja el menu apuntando al siguiente elemento bool Menu::increaseSelectorIndex() { - bool success = false; - // Obten las coordenadas del elemento actual - mSelector.y = mSelector.originY = mItem[mSelector.index].rect.y; - mSelector.h = mSelector.originH = getSelectorHeight(mSelector.index); + selector.y = selector.originY = item[selector.index].rect.y; + selector.h = selector.originH = getSelectorHeight(selector.index); // Calcula cual es el siguiente elemento - ++mSelector.index %= mTotalItems; - while (!mItem[mSelector.index].selectable) - // mSelector.index++; - ++mSelector.index %= mTotalItems; - success = true; - - // Establece las coordenadas y altura de destino - if (success) + ++selector.index %= item.size(); + while (!item[selector.index].selectable) { - mSelector.targetY = mItem[mSelector.index].rect.y; - mSelector.despY = (mSelector.targetY - mSelector.originY) / mSelector.numJumps; - - mSelector.targetH = getSelectorHeight(mSelector.index); - mSelector.incH = (mSelector.targetH - mSelector.originH) / mSelector.numJumps; - - mSelector.moving = true; - if (mSelector.incH != 0) - mSelector.resizing = true; + ++selector.index %= item.size(); } - return success; + // Establece las coordenadas y altura de destino + selector.targetY = item[selector.index].rect.y; + selector.despY = (selector.targetY - selector.originY) / selector.numJumps; + + selector.targetH = getSelectorHeight(selector.index); + selector.incH = (selector.targetH - selector.originH) / selector.numJumps; + + selector.moving = true; + if (selector.incH != 0) + { + selector.resizing = true; + } + + return true; } // Deja el menu apuntando al elemento anterior bool Menu::decreaseSelectorIndex() { - bool success = false; - // Obten las coordenadas del elemento actual - mSelector.y = mSelector.originY = mItem[mSelector.index].rect.y; - mSelector.h = mSelector.originH = getSelectorHeight(mSelector.index); + selector.y = selector.originY = item[selector.index].rect.y; + selector.h = selector.originH = getSelectorHeight(selector.index); // Calcula cual es el siguiente elemento - if (mSelector.index == 0) - mSelector.index = mTotalItems; - else - mSelector.index--; - while (!mItem[mSelector.index].selectable) + if (selector.index == 0) { - if (mSelector.index == 0) - mSelector.index = mTotalItems; - else - mSelector.index--; + selector.index = item.size(); + } + else + { + selector.index--; + } + + while (!item[selector.index].selectable) + { + if (selector.index == 0) + { + selector.index = item.size(); + } + else + { + selector.index--; + } } - success = true; // Establece las coordenadas y altura de destino - if (success) + selector.targetY = item[selector.index].rect.y; + selector.despY = (selector.targetY - selector.originY) / selector.numJumps; + + selector.targetH = getSelectorHeight(selector.index); + selector.incH = (selector.targetH - selector.originH) / selector.numJumps; + + selector.moving = true; + if (selector.incH != 0) { - mSelector.targetY = mItem[mSelector.index].rect.y; - mSelector.despY = (mSelector.targetY - mSelector.originY) / mSelector.numJumps; - - mSelector.targetH = getSelectorHeight(mSelector.index); - mSelector.incH = (mSelector.targetH - mSelector.originH) / mSelector.numJumps; - - mSelector.moving = true; - if (mSelector.incH != 0) - mSelector.resizing = true; + selector.resizing = true; } - return success; + return true; } // Actualiza la logica del menu void Menu::update() { + checkInput(); updateSelector(); } @@ -300,52 +595,53 @@ void Menu::update() void Menu::render() { // Rendereritza el fondo del menu - if (mBackgroundType == MENU_BACKGROUND_SOLID) + if (backgroundType == MENU_BACKGROUND_SOLID) { - SDL_SetRenderDrawColor(mRenderer, mRectBG.r, mRectBG.g, mRectBG.b, mRectBG.a); - SDL_RenderFillRect(mRenderer, &mRectBG.rect); + SDL_SetRenderDrawColor(renderer, rectBG.color.r, rectBG.color.g, rectBG.color.b, rectBG.a); + SDL_RenderFillRect(renderer, &rectBG.rect); } // Renderiza el rectangulo del selector - SDL_Rect temp = mSelector.rect; - temp.y--; - temp.h++; - SDL_SetRenderDrawColor(mRenderer, mSelector.r, mSelector.g, mSelector.b, mSelector.a); - SDL_RenderFillRect(mRenderer, &temp); + const SDL_Rect temp = {selector.rect.x, selector.rect.y - 1, selector.rect.w, selector.rect.h + 1}; + // temp.y--; + // temp.h++; + SDL_SetRenderDrawColor(renderer, selector.color.r, selector.color.g, selector.color.b, selector.a); + SDL_RenderFillRect(renderer, &temp); // Renderiza el borde del fondo - if (mBackgroundType == MENU_BACKGROUND_SOLID) + if (backgroundType == MENU_BACKGROUND_SOLID) { - SDL_SetRenderDrawColor(mRenderer, mRectBG.r, mRectBG.g, mRectBG.b, 255); - SDL_RenderDrawRect(mRenderer, &mRectBG.rect); + SDL_SetRenderDrawColor(renderer, rectBG.color.r, rectBG.color.g, rectBG.color.b, 255); + SDL_RenderDrawRect(renderer, &rectBG.rect); } - // Renderitza el texto - for (int i = 0; i < mTotalItems; i++) + // Renderiza el texto + for (int i = 0; i < (int)item.size(); ++i) { - if (i == mSelector.index) + if (i == selector.index) { - const color_t color = {mSelector.itemR, mSelector.itemG, mSelector.itemB}; - mText->writeColored(mItem[i].rect.x, mItem[i].rect.y, mItem[i].label, color); + const color_t color = {selector.itemColor.r, selector.itemColor.g, selector.itemColor.b}; + text->writeColored(item[i].rect.x, item[i].rect.y, item[i].label, color); } - else if (mItem[i].selectable) + else if (item[i].selectable) { - mText->write(mItem[i].rect.x, mItem[i].rect.y, mItem[i].label); + text->write(item[i].rect.x, item[i].rect.y, item[i].label); } - else if (mItem[i].greyed) + else if (item[i].greyed) { - mText->writeColored(mItem[i].rect.x, mItem[i].rect.y, mItem[i].label, mColorGreyed); + text->writeColored(item[i].rect.x, item[i].rect.y, item[i].label, colorGreyed); } - else // No seleccionable + else + // No seleccionable { - if ((mItem[i].linkedUp) && (i == mSelector.index + 1)) + if ((item[i].linkedUp) && (i == selector.index + 1)) { - const color_t color = {mSelector.itemR, mSelector.itemG, mSelector.itemB}; - mText->writeColored(mItem[i].rect.x, mItem[i].rect.y, mItem[i].label, color); + const color_t color = {selector.itemColor.r, selector.itemColor.g, selector.itemColor.b}; + text->writeColored(item[i].rect.x, item[i].rect.y, item[i].label, color); } else // No enlazado con el de arriba { - mText->write(mItem[i].rect.x, mItem[i].rect.y, mItem[i].label); + text->write(item[i].rect.x, item[i].rect.y, item[i].label); } } } @@ -354,65 +650,53 @@ void Menu::render() // Establece el rectangulo de fondo del menu y el selector void Menu::setRectSize() { - mRectBG.rect.w = findWidth() + mText->getCharacterWidth(); - mRectBG.rect.h = findHeight() + mText->getCharacterWidth(); + rectBG.rect.w = findWidth() + text->getCharacterSize(); + rectBG.rect.h = findHeight() + text->getCharacterSize(); // La posición X es la del menú menos medio caracter - mRectBG.rect.x = mPosX - (mText->getCharacterWidth() / 2); + rectBG.rect.x = x - (text->getCharacterSize() / 2); // La posición Y es la del menu menos la altura de medio caracter - mRectBG.rect.y = mPosY - (mText->getCharacterWidth() / 2); + rectBG.rect.y = y - (text->getCharacterSize() / 2); // Establecemos los valores del rectangulo del selector a partir de los valores del rectangulo de fondo - setSelectorPos(mSelector.index); -} - -// Establece el valor de la variable -void Menu::setTotalItems(int num) -{ - mTotalItems = num; - if (mTotalItems > MENU_MAX_ITEMS) - mTotalItems = MENU_MAX_ITEMS; + setSelectorPos(selector.index); } // Establece el color del rectangulo de fondo -void Menu::setBackgroundColor(int r, int g, int b, int alpha) +void Menu::setBackgroundColor(color_t color, int alpha) { - mRectBG.r = r; - mRectBG.g = g; - mRectBG.b = b; - mRectBG.a = alpha; + rectBG.color = color; + rectBG.a = alpha; } // Establece el color del rectangulo del selector -void Menu::setSelectorColor(int r, int g, int b, int alpha) +void Menu::setSelectorColor(color_t color, int alpha) { - mSelector.r = r; - mSelector.g = g; - mSelector.b = b; - mSelector.a = alpha; + selector.color = color; + selector.a = alpha; } // Establece el color del texto del selector -void Menu::setSelectorTextColor(int r, int g, int b) +void Menu::setSelectorTextColor(color_t color) { - mSelector.itemR = r; - mSelector.itemG = g; - mSelector.itemB = b; + selector.itemColor = color; } // Centra el menu respecto un punto en el eje X void Menu::centerMenuOnX(int value) { - mIsCenteredOnX = true; - mCenterX = value; + isCenteredOnX = true; + centerX = value; // Establece la nueva posición centrada en funcion del elemento más ancho - mPosX = (value) - (findWidth() / 2); + x = (value) - (findWidth() / 2); // Reposiciona los elementos del menu - for (int i = 0; i < MENU_MAX_ITEMS; i++) - mItem[i].rect.x = mPosX; + for (auto &i : item) + { + i.rect.x = x; + } // Recalcula el rectangulo de fondo setRectSize(); @@ -421,11 +705,11 @@ void Menu::centerMenuOnX(int value) // Centra el menu respecto un punto en el eje Y void Menu::centerMenuOnY(int value) { - mIsCenteredOnY = true; - mCenterY = value; + isCenteredOnY = true; + centerY = value; // Establece la nueva posición centrada en funcion del elemento más ancho - mPosY = (value) - (findHeight() / 2); + y = (value) - (findHeight() / 2); // Reposiciona los elementos del menu replaceElementsOnY(); @@ -437,134 +721,170 @@ void Menu::centerMenuOnY(int value) // Centra los elementos del menu en el eje X void Menu::centerMenuElementsOnX() { - mAreElementsCenteredOnX = true; + areElementsCenteredOnX = true; - for (int i = 0; i < mTotalItems; i++) - mItem[i].rect.x = (mCenterX - (mItem[i].rect.w / 2)); + for (auto &i : item) + { + i.rect.x = (centerX - (i.rect.w / 2)); + } } // Añade un item al menu -void Menu::addItem(std::string text, Uint8 hPaddingDown, bool selectable, bool greyed, bool linkedDown) +void Menu::addItem(std::string text, int hPaddingDown, bool selectable, bool greyed, bool linkedDown) { + item_t temp; // Si es el primer item coge la posición en el eje Y del propio menu - if (mTotalItems == 0) - mItem[mTotalItems].rect.y = mPosY; + if (item.size() == 0) + { + temp.rect.y = y; + } else - // En caso contrario, coge la posición en el eje Y a partir del elemento anterior - mItem[mTotalItems].rect.y = mItem[mTotalItems - 1].rect.y + mItem[mTotalItems - 1].rect.h + mItem[mTotalItems - 1].hPaddingDown; + // En caso contrario, coge la posición en el eje Y a partir del elemento anterior + { + temp.rect.y = item.back().rect.y + item.back().rect.h + item.back().hPaddingDown; + } - setItemCaption(mTotalItems, text); - mItem[mTotalItems].rect.x = mPosX; - mItem[mTotalItems].hPaddingDown = hPaddingDown; - mItem[mTotalItems].selectable = selectable; - mItem[mTotalItems].greyed = greyed; - mItem[mTotalItems].linkedDown = linkedDown; - if (mTotalItems > 0) - if (mItem[mTotalItems - 1].linkedDown) - mItem[mTotalItems].linkedUp = true; + temp.rect.x = x; + temp.hPaddingDown = hPaddingDown; + temp.selectable = selectable; + temp.greyed = greyed; + temp.linkedDown = linkedDown; - setTotalItems(mTotalItems + 1); - mCenterX = mPosX + (findWidth() / 2); + item.push_back(temp); + setItemCaption(item.size() - 1, text); + + if (item.size() > 0) + { + if (item[item.size() - 1].linkedDown) + { + item[item.size()].linkedUp = true; + } + } + + centerX = x + (findWidth() / 2); reorganize(); } // Cambia el texto de un item -void Menu::setItemCaption(Uint8 index, std::string text) +void Menu::setItemCaption(int index, std::string text) { - mItem[index].label = text; - mItem[index].rect.w = mText->lenght(mItem[index].label); - mItem[index].rect.h = mText->getCharacterWidth(); + item[index].label = text; + item[index].rect.w = this->text->lenght(item[index].label); + item[index].rect.h = this->text->getCharacterSize(); reorganize(); + + const std::string texto = item[index].label + ":" + std::to_string(item[index].rect.w); + printf("Adding menu item -> %s\n", texto.c_str()); } // Establece el indice del itemm que se usará por defecto al cancelar el menu -void Menu::setDefaultActionWhenCancel(Uint8 item) +void Menu::setDefaultActionWhenCancel(int item) { - mDefaultActionWhenCancel = item; + defaultActionWhenCancel = item; } // Gestiona la entrada de teclado y mando durante el menu void Menu::checkInput() { - if (mInput->checkInput(INPUT_UP, REPEAT_FALSE)) + if (input->checkInput(INPUT_UP, REPEAT_FALSE)) { if (decreaseSelectorIndex()) { - JA_PlaySound(mSoundMove); + if (soundMove) + { + JA_PlaySound(soundMove); + } } } - if (mInput->checkInput(INPUT_DOWN, REPEAT_FALSE)) + if (input->checkInput(INPUT_DOWN, REPEAT_FALSE)) { if (increaseSelectorIndex()) { - JA_PlaySound(mSoundMove); + if (soundMove) + { + JA_PlaySound(soundMove); + } } } - if (mInput->checkInput(INPUT_ACCEPT, REPEAT_FALSE)) + if (input->checkInput(INPUT_ACCEPT, REPEAT_FALSE)) { - mItemSelected = mSelector.index; - JA_PlaySound(mSoundAccept); + itemSelected = selector.index; + if (soundAccept) + { + JA_PlaySound(soundAccept); + } } - if (mInput->checkInput(INPUT_CANCEL, REPEAT_FALSE)) + if (input->checkInput(INPUT_CANCEL, REPEAT_FALSE)) { - mItemSelected = mDefaultActionWhenCancel; - JA_PlaySound(mSoundCancel); + itemSelected = defaultActionWhenCancel; + if (soundCancel) + { + JA_PlaySound(soundCancel); + } } } // Calcula el ancho del menu -Uint16 Menu::findWidth() +int Menu::findWidth() { return getWidestItem(); } // Calcula el alto del menu -Uint16 Menu::findHeight() +int Menu::findHeight() { - Uint16 height = 0; + int height = 0; // Obtenemos la altura de la suma de alturas de los items - for (int i = 0; i < mTotalItems; i++) - height += mItem[i].rect.h + mItem[i].hPaddingDown; + for (auto &i : item) + { + height += i.rect.h + i.hPaddingDown; + } - return height - mItem[mTotalItems - 1].hPaddingDown; + return height - item.back().hPaddingDown; } // Recoloca los elementos del menu en el eje Y void Menu::replaceElementsOnY() { - mItem[0].rect.y = mPosY; + item[0].rect.y = y; - for (int i = 1; i < mTotalItems; i++) - mItem[i].rect.y = mItem[i - 1].rect.y + mItem[i - 1].rect.h + mItem[i - 1].hPaddingDown; + for (int i = 1; i < (int)item.size(); i++) + { + item[i].rect.y = item[i - 1].rect.y + item[i - 1].rect.h + item[i - 1].hPaddingDown; + } } // Establece el estado seleccionable de un item -void Menu::setSelectable(Uint8 index, bool value) +void Menu::setSelectable(int index, bool value) { - mItem[index].selectable = value; + item[index].selectable = value; } // Establece el estado agrisado de un item -void Menu::setGreyed(Uint8 index, bool value) +void Menu::setGreyed(int index, bool value) { - mItem[index].greyed = value; + item[index].greyed = value; } // Establece el estado de enlace de un item -void Menu::setLinkedDown(Uint8 index, bool value) +void Menu::setLinkedDown(int index, bool value) { - mItem[index].linkedDown = value; + item[index].linkedDown = value; } // Calcula la altura del selector int Menu::getSelectorHeight(int value) { - if (mItem[value].linkedDown) - return mItem[value].rect.h + mItem[value].hPaddingDown + mItem[value + 1].rect.h; + if (item[value].linkedDown) + { + return item[value].rect.h + item[value].hPaddingDown + item[value + 1].rect.h; + } else - return mItem[value].rect.h; + { + return item[value].rect.h; + } } \ No newline at end of file diff --git a/source/menu.h b/source/menu.h index 6f9e229..09a001c 100644 --- a/source/menu.h +++ b/source/menu.h @@ -1,21 +1,28 @@ #pragma once #include +#include #include "sprite.h" #include "text.h" +#include "asset.h" #include "input.h" +#include "utils.h" #include "jail_audio.h" +#include +#include #ifndef MENU_H #define MENU_H -// Cantidad máxima de items en el menu -#define MENU_MAX_ITEMS 50 - // Tipos de fondos para el menu #define MENU_BACKGROUND_TRANSPARENT 0 #define MENU_BACKGROUND_SOLID 1 +// Tipos de archivos de audio +#define SOUND_ACCEPT 0 +#define SOUND_MOVE 1 +#define SOUND_CANCEL 2 + // Opciones de menu #define MENU_NO_OPTION -1 @@ -23,82 +30,83 @@ class Menu { private: - std::string mName; // Nombre del menu - int mPosX; // Posición en el eje X de la primera letra del primer elemento - int mPosY; // Posición en el eje Y de la primera letra del primer elemento - Uint16 mHeight; // Altura del menu - Uint16 mWidth; // Anchura del menu - Uint8 mTotalItems; // Numero total de items del menu - int mItemSelected; // Índice del item del menu que ha sido seleccionado - Uint8 mDefaultActionWhenCancel; // Indice del item del menu que se selecciona cuando se cancela el menu - Uint8 mBackgroundType; // Tipo de fondo para el menu - bool mIsCenteredOnX; // Variable para saber si el menu debe estar centrado respecto a un punto en el eje X - bool mIsCenteredOnY; // Variable para saber si el menu debe estar centrado respecto a un punto en el eje Y - int mCenterX; // Centro del menu en el eje X - int mCenterY; // Centro del menu en el eje Y - bool mAreElementsCenteredOnX; // Variable para saber si los elementos van centrados en el eje X - Uint16 mWidestItem; // Anchura del elemento más ancho - JA_Sound mSoundAccept; // Sonido al aceptar o elegir una opción del menu - JA_Sound mSoundCancel; // Sonido al cancelar el menu - JA_Sound mSoundMove; // Sonido al mover el selector - SDL_Renderer *mRenderer; // Puntero al renderizador de la ventana - std::string *mFileList; // Lista de ficheros - Text *mText; // Texto para poder escribir los items del menu - Input *mInput; // Gestor de eventos de entrada de teclado o gamepad - color_t mColorGreyed; // Color para los elementos agrisados - - struct rectangle + struct rectangle_t { SDL_Rect rect; // Rectangulo - Uint8 r; // Rojo - Uint8 g; // Verde - Uint8 b; // Azul - Uint8 a; // Transparencia + color_t color; // Color + int a; // Transparencia }; - rectangle mRectBG; // Rectangulo de fondo del menu - struct item + struct item_t { - std::string label; // Texto - SDL_Rect rect; // Rectangulo que delimita el elemento - Uint8 hPaddingDown; // Espaciado bajo el elemento - bool selectable; // Indica si se puede seleccionar - bool greyed; // Indica si ha de aparecer con otro color mas oscuro - bool linkedDown; // Indica si el elemento actual y el siguiente se tratan como uno solo. Afecta al selector - bool linkedUp; // Indica si el elemento actual y el anterior se tratan como uno solo. Afecta al selector + std::string label; // Texto + SDL_Rect rect; // Rectangulo que delimita el elemento + int hPaddingDown; // Espaciado bajo el elemento + bool selectable; // Indica si se puede seleccionar + bool greyed; // Indica si ha de aparecer con otro color mas oscuro + bool linkedDown; // Indica si el elemento actual y el siguiente se tratan como uno solo. Afecta al selector + bool linkedUp; // Indica si el elemento actual y el anterior se tratan como uno solo. Afecta al selector }; - item mItem[MENU_MAX_ITEMS]; // Estructura para cada elemento del menu - struct selector + struct selector_t { - float originY; // Coordenada de origen - float targetY; // Coordenada de destino - float despY; // Cantidad de pixeles que se desplaza el selector en cada salto: (target - origin) / numJumps - bool moving; // Indica si el selector está avanzando hacia el destino - float originH; // Altura de origen - float targetH; // Altura de destino - float incH; // Cantidad de pixels que debe incrementar o decrementar el selector en cada salto - bool resizing; // Indica si el selector está cambiando de tamaño - float y; // Coordenada actual, usado para el desplazamiento - float h; // Altura actual, usado para el cambio de tamaño - Uint8 numJumps; // Numero de pasos preestablecido para llegar al destino - Uint8 index; // Elemento del menu que tiene el foco - SDL_Rect rect; // Rectangulo del selector - Uint8 r; // Cantidad de color rojo para el rectangulo del selector - Uint8 g; // Cantidad de color verde para el rectangulo del selector - Uint8 b; // Cantidad de color azul para el rectangulo del selector - Uint8 a; // Cantidad de transparencia para el rectangulo del selector - Uint8 itemR; // Cantidad de color rojo para el texto del elemento seleccionado - Uint8 itemG; // Cantidad de color verde para el texto del elemento seleccionado - Uint8 itemB; // Cantidad de color azul para el texto del elemento seleccionado + float originY; // Coordenada de origen + float targetY; // Coordenada de destino + float despY; // Cantidad de pixeles que se desplaza el selector en cada salto: (target - origin) / numJumps + bool moving; // Indica si el selector está avanzando hacia el destino + float originH; // Altura de origen + float targetH; // Altura de destino + float incH; // Cantidad de pixels que debe incrementar o decrementar el selector en cada salto + bool resizing; // Indica si el selector está cambiando de tamaño + float y; // Coordenada actual, usado para el desplazamiento + float h; // Altura actual, usado para el cambio de tamaño + int numJumps; // Numero de pasos preestablecido para llegar al destino + int index; // Elemento del menu que tiene el foco + SDL_Rect rect; // Rectangulo del selector + color_t color; // Color del selector + color_t itemColor; // Color del item + int a; // Cantidad de transparencia para el rectangulo del selector }; - selector mSelector; // Variables para pintar el selector del menu - // Carga los recursos necesarios para la sección 'Title' - bool loadMedia(); + std::string name; // Nombre del menu + int x; // Posición en el eje X de la primera letra del primer elemento + int y; // Posición en el eje Y de la primera letra del primer elemento + int h; // Altura del menu + int w; // Anchura del menu + int itemSelected; // Índice del item del menu que ha sido seleccionado + int defaultActionWhenCancel; // Indice del item del menu que se selecciona cuando se cancela el menu + int backgroundType; // Tipo de fondo para el menu + int centerX; // Centro del menu en el eje X + int centerY; // Centro del menu en el eje Y + bool isCenteredOnX; // Variable para saber si el menu debe estar centrado respecto a un punto en el eje X + bool isCenteredOnY; // Variable para saber si el menu debe estar centrado respecto a un punto en el eje Y + bool areElementsCenteredOnX; // Variable para saber si los elementos van centrados en el eje X + int widestItem; // Anchura del elemento más ancho + JA_Sound soundAccept; // Sonido al aceptar o elegir una opción del menu + JA_Sound soundCancel; // Sonido al cancelar el menu + JA_Sound soundMove; // Sonido al mover el selector + SDL_Renderer *renderer; // Puntero al renderizador de la ventana + Text *text; // Texto para poder escribir los items del menu + Input *input; // Gestor de eventos de entrada de teclado o gamepad + Asset *asset; // Objeto para gestionar los ficheros de recursos + color_t colorGreyed; // Color para los elementos agrisados + rectangle_t rectBG; // Rectangulo de fondo del menu + std::vector item; // Estructura para cada elemento del menu + selector_t selector; // Variables para pintar el selector del menu + std::string font_png; + std::string font_txt; - // Establece el valor de la variable - void setTotalItems(int num); + // Carga la configuración del menu desde un archivo de texto + bool load(std::string file_path); + + // Asigna variables a partir de dos cadenas + bool setVars(std::string var, std::string value); + + // Asigna variables a partir de dos cadenas + bool setItem(item_t *item, std::string var, std::string value); + + // Inicializa las variables + void init(); // Establece el rectangulo de fondo del menu void setRectSize(); @@ -116,16 +124,16 @@ private: void updateSelector(); // Obtiene la anchura del elemento más ancho del menu - Uint16 getWidestItem(); + int getWidestItem(); // Gestiona la entrada de teclado y mando durante el menu void checkMenuInput(Menu *menu); // Calcula el ancho del menu - Uint16 findWidth(); + int findWidth(); // Calcula el alto del menu - Uint16 findHeight(); + int findHeight(); // Recoloca los elementos del menu en el eje Y void replaceElementsOnY(); @@ -135,19 +143,19 @@ private: public: // Constructor - Menu(SDL_Renderer *renderer, Text *text, Input *input, std::string *fileList); + Menu(SDL_Renderer *renderer, Asset *asset, Input *input, std::string file=""); // Destructor ~Menu(); - // Inicializador - void init(std::string name, int x, int y, int backgroundType); + // Carga los ficheros de audio + void loadAudioFile(std::string file, int sound); // Obtiene el nombre del menu std::string getName(); // Obtiene el valor de la variable - Uint8 getItemSelected(); + int getItemSelected(); // Deja el menu apuntando al primer elemento void reset(); @@ -162,13 +170,13 @@ public: void render(); // Establece el color del rectangulo de fondo - void setBackgroundColor(int r, int g, int b, int alpha); + void setBackgroundColor(color_t color, int alpha); // Establece el color del rectangulo del selector - void setSelectorColor(int r, int g, int b, int alpha); + void setSelectorColor(color_t color, int alpha); // Establece el color del texto del selector - void setSelectorTextColor(int r, int g, int b); + void setSelectorTextColor(color_t color); // Centra el menu respecto a un punto en el eje X void centerMenuOnX(int value); @@ -180,25 +188,27 @@ public: void centerMenuElementsOnX(); // Añade un item al menu - void addItem(std::string text, Uint8 hPaddingDown = 1, bool selectable = true, bool greyed = false, bool linkedDown = false); + void addItem(std::string text, int hPaddingDown = 1, bool selectable = true, bool greyed = false, bool linkedDown = false); // Cambia el texto de un item - void setItemCaption(Uint8 index, std::string text); + void setItemCaption(int index, std::string text); // Establece el indice del item que se usará por defecto al cancelar el menu - void setDefaultActionWhenCancel(Uint8 item); + void setDefaultActionWhenCancel(int item); // Coloca el selector en una posición específica - void setSelectorPos(Uint8 index); + void setSelectorPos(int index); // Establece el estado seleccionable de un item - void setSelectable(Uint8 index, bool value); + void setSelectable(int index, bool value); // Establece el estado agrisado de un item - void setGreyed(Uint8 index, bool value); + void setGreyed(int index, bool value); // Establece el estado de enlace de un item - void setLinkedDown(Uint8 index, bool value); + void setLinkedDown(int index, bool value); + + // hacer procedimientos para establecer el titulo, la x, la y, la tipografia y el tipo de fondo }; #endif diff --git a/source/title.cpp b/source/title.cpp index 679d360..337f0b7 100644 --- a/source/title.cpp +++ b/source/title.cpp @@ -1,14 +1,14 @@ #include "title.h" // Constructor -Title::Title(SDL_Window *window, SDL_Renderer *renderer, Screen *screen, Input *input, std::string *fileList, options_t *options, Lang *lang) +Title::Title(SDL_Window *window, SDL_Renderer *renderer, Screen *screen, Input *input, Asset *mAsset, options_t *options, Lang *lang) { // Copia las direcciones de los punteros mWindow = window; mRenderer = renderer; mScreen = screen; mInput = input; - mFileList = fileList; + this->mAsset = mAsset; mOptions = options; mLang = lang; @@ -25,10 +25,10 @@ Title::Title(SDL_Window *window, SDL_Renderer *renderer, Screen *screen, Input * mDustBitmapR = new AnimatedSprite(); mTile = new Sprite(); mGradient = new Sprite(); - mText = new Text(mFileList[48], mTextTexture, mRenderer); - mText2 = new Text(mFileList[46], mTextTexture2, mRenderer); - mMenu.title = new Menu(mRenderer, mText, mInput, mFileList); - mMenu.options = new Menu(mRenderer, mText, mInput, mFileList); + mText = new Text(mAsset->get("smb2.txt"), mTextTexture, mRenderer); + mText2 = new Text(mAsset->get("8bithud.txt"), mTextTexture2, mRenderer); + mMenu.title = new Menu(mRenderer, mText, mInput, mAsset); + mMenu.options = new Menu(mRenderer, mText, mInput, mAsset); // Crea la textura para el mosaico de fondo mBackground = SDL_CreateTexture(mRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, SCREEN_WIDTH * 2, SCREEN_HEIGHT * 2); @@ -45,7 +45,7 @@ Title::~Title() mRenderer = nullptr; mScreen = nullptr; mInput = nullptr; - mFileList = nullptr; + mAsset = nullptr; mOptions = nullptr; mLang = nullptr; @@ -108,12 +108,6 @@ Title::~Title() SDL_DestroyTexture(mBackground); mBackground = nullptr; - - mWindow = nullptr; - mRenderer = nullptr; - mInput = nullptr; - mFileList = nullptr; - mOptions = nullptr; } // Inicializa las variables necesarias para la sección 'Title' @@ -302,16 +296,16 @@ bool Title::loadMedia() bool success = true; // Texturas - success &= loadTextureFromFile(mTitleTexture, mFileList[40], mRenderer); - success &= loadTextureFromFile(mItemsTexture, mFileList[34], mRenderer); - success &= loadTextureFromFile(mTextTexture, mFileList[30], mRenderer); - success &= loadTextureFromFile(mTextTexture2, mFileList[27], mRenderer); + success &= loadTextureFromFile(mTitleTexture, mAsset->get("title.png"), mRenderer); + success &= loadTextureFromFile(mItemsTexture, mAsset->get("items.png"), mRenderer); + success &= loadTextureFromFile(mTextTexture, mAsset->get("smb2.png"), mRenderer); + success &= loadTextureFromFile(mTextTexture2, mAsset->get("8bithud.png"), mRenderer); // Sonidos - mSound = JA_LoadSound(mFileList[21].c_str()); + mSound = JA_LoadSound(mAsset->get("title.wav").c_str()); // Musicas - mMusic = JA_LoadMusic(mFileList[5].c_str()); + mMusic = JA_LoadMusic(mAsset->get("title.ogg").c_str()); return success; } @@ -920,7 +914,7 @@ section_t Title::run(Uint8 subsection) // Ejecuta la parte donde se muestran las instrucciones void Title::runInstructions(Uint8 mode) { - mInstructions = new Instructions(mRenderer, mScreen, mFileList, mLang); + mInstructions = new Instructions(mRenderer, mScreen, mAsset, mLang); mInstructions->run(mode); delete mInstructions; } @@ -928,7 +922,7 @@ void Title::runInstructions(Uint8 mode) // Ejecuta el juego en modo demo void Title::runDemoGame() { - mDemoGame = new Game(1, 0, mRenderer, mScreen, mFileList, mLang, mInput, true, mOptions); + mDemoGame = new Game(1, 0, mRenderer, mScreen, mAsset, mLang, mInput, true, mOptions); mDemoGame->run(); delete mDemoGame; } diff --git a/source/title.h b/source/title.h index 5b9e7d1..c03239c 100644 --- a/source/title.h +++ b/source/title.h @@ -1,20 +1,21 @@ #pragma once #include +#include "asset.h" #include "const.h" -#include "utils.h" -#include "sprite.h" -#include "movingsprite.h" -#include "smartsprite.h" -#include "item.h" -#include "text.h" -#include "menu.h" #include "fade.h" +#include "game.h" #include "input.h" #include "instructions.h" -#include "game.h" -#include "screen.h" +#include "item.h" #include "jail_audio.h" +#include "menu.h" +#include "movingsprite.h" +#include "screen.h" +#include "smartsprite.h" +#include "sprite.h" +#include "text.h" +#include "utils.h" #ifndef TITLE_H #define TITLE_H @@ -52,7 +53,7 @@ private: SmartSprite *mCrisisBitmap; // Sprite con la palabra CRISIS para la pantalla de titulo Sprite *mTile; // Sprite para dibujar el fondo de pantalla del título Sprite *mGradient; // Sprite para dibujar el degradado del titulo - std::string *mFileList; // Lista de ficheros + Asset *mAsset; // Objeto que gestiona todos los ficheros de recursos Lang *mLang; // Objeto para gestionar los textos en diferentes idiomas Uint16 mBackgroundCounter; // Temporizador para el fondo de tiles de la pantalla de titulo Uint16 mCounter; // Temporizador para la pantalla de titulo @@ -114,7 +115,7 @@ private: public: // Constructor - Title(SDL_Window *window, SDL_Renderer *renderer, Screen *screen, Input *input, std::string *fileList, options_t *options, Lang *lang); + Title(SDL_Window *window, SDL_Renderer *renderer, Screen *screen, Input *input, Asset *mAsset, options_t *options, Lang *lang); // Destructor ~Title();