#include "scoreboard.h" #include // for SDL_BLENDMODE_BLEND #include // for SDL_PIXELFORMAT_RGBA8888 #include // for SDL_GetTicks #include // for roundf #include "asset.h" // for Asset #include "lang.h" // for getText #include "sprite.h" // for Sprite #include "text.h" // for Text #include "texture.h" // for Texture // [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado Scoreboard *Scoreboard::scoreboard = nullptr; // [SINGLETON] Crearemos el objeto scoreboard con esta función estática void Scoreboard::init(SDL_Renderer *renderer) { Scoreboard::scoreboard = new Scoreboard(renderer); } // [SINGLETON] Destruiremos el objeto scoreboard con esta función estática void Scoreboard::destroy() { delete Scoreboard::scoreboard; } // [SINGLETON] Con este método obtenemos el objeto scoreboard y podemos trabajar con él Scoreboard *Scoreboard::get() { return Scoreboard::scoreboard; } // Constructor Scoreboard::Scoreboard(SDL_Renderer *renderer) : renderer(renderer) { // Inicializa punteros gamePowerMeterTexture = nullptr; powerMeterSprite = nullptr; textScoreBoard = nullptr; // Inicializa variables stage = 1; for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) { name[i] = ""; recordName[i] = ""; selectorPos[i] = 0; score[i] = 0; mult[i] = 0; continueCounter[i] = 0; } hiScore = 0; power = 0; hiScoreName = ""; color = {0, 0, 0}; rect = {0, 0, 320, 40}; panel[SCOREBOARD_LEFT_PANEL].mode = scoreboardMode::SCORE; panel[SCOREBOARD_RIGHT_PANEL].mode = scoreboardMode::SCORE; panel[SCOREBOARD_CENTER_PANEL].mode = scoreboardMode::STAGE_INFO; ticks = SDL_GetTicks(); counter = 0; // Recalcula las anclas de los elementos recalculateAnchors(); // Crea objetos gamePowerMeterTexture = std::unique_ptr(new Texture(renderer, Asset::get()->get("game_power_meter.png"))); powerMeterSprite = std::unique_ptr(new Sprite(slot4_2.x - 20, slot4_2.y, 40, 7, gamePowerMeterTexture.get())); textScoreBoard = std::unique_ptr(new Text(Asset::get()->get("8bithud.png"), Asset::get()->get("8bithud.txt"), renderer)); // Crea la textura de fondo background = nullptr; createBackgroundTexture(); // Crea las texturas de los paneles createPanelTextures(); // Rellena la textura de fondo fillBackgroundTexture(); } Scoreboard::~Scoreboard() { if (background) { SDL_DestroyTexture(background); } for (auto texture : panelTexture) { if (texture) { SDL_DestroyTexture(texture); } } } // Transforma un valor numérico en una cadena de 6 cifras std::string Scoreboard::updateScoreText(Uint32 num) { if ((num >= 0) && (num <= 9)) { return ("000000" + std::to_string(num)); } if ((num >= 10) && (num <= 99)) { return ("00000" + std::to_string(num)); } if ((num >= 100) && (num <= 999)) { return ("0000" + std::to_string(num)); } if ((num >= 1000) && (num <= 9999)) { return ("000" + std::to_string(num)); } if ((num >= 010000) && (num <= 99999)) { return ("00" + std::to_string(num)); } if ((num >= 100000) && (num <= 999999)) { return ("0" + std::to_string(num)); } if ((num >= 1000000) && (num <= 9999999)) { return (std::to_string(num)); } return (std::to_string(num)); } // Actualiza el contador void Scoreboard::updateCounter() { if (SDL_GetTicks() - ticks > SCOREBOARD_TICK_SPEED) { ticks = SDL_GetTicks(); counter++; } } // Actualiza la lógica del marcador void Scoreboard::update() { fillBackgroundTexture(); updateCounter(); } // Pinta el marcador void Scoreboard::render() { SDL_RenderCopy(renderer, background, nullptr, &rect); } // Establece el valor de la variable void Scoreboard::setName(int panel, std::string name) { this->name[panel] = name; } // Establece el valor de la variable void Scoreboard::setRecordName(int panel, std::string recordName) { this->recordName[panel] = recordName; } // Establece el valor de la variable void Scoreboard::setSelectorPos(int panel, int pos) { selectorPos[panel] = pos; } // Establece el valor de la variable void Scoreboard::setScore(int panel, int score) { this->score[panel] = score; } // Establece el valor de la variable void Scoreboard::setMult(int panel, float mult) { this->mult[panel] = mult; } // Establece el valor de la variable void Scoreboard::setContinue(int panel, int value) { continueCounter[panel] = value; } // Establece el valor de la variable void Scoreboard::setStage(int stage) { this->stage = stage; } // Establece el valor de la variable void Scoreboard::setHiScore(int hiScore) { this->hiScore = hiScore; } // Establece el valor de la variable void Scoreboard::setPower(float power) { this->power = power; } // Establece el valor de la variable void Scoreboard::setHiScoreName(std::string name) { hiScoreName = name; } // Establece el valor de la variable void Scoreboard::setColor(color_t color) { this->color = color; fillBackgroundTexture(); } // Establece el valor de la variable void Scoreboard::setPos(SDL_Rect rect) { this->rect = rect; // Recalcula las anclas de los elementos recalculateAnchors(); // Crea la textura de fondo createBackgroundTexture(); // Crea las texturas de los paneles createPanelTextures(); // Rellena la textura de fondo fillBackgroundTexture(); } // Rellena los diferentes paneles del marcador void Scoreboard::fillPanelTextures() { // Guarda a donde apunta actualmente el renderizador SDL_Texture *temp = SDL_GetRenderTarget(renderer); // Genera el contenidoi de cada panel for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) { // Cambia el destino del renderizador SDL_SetRenderTarget(renderer, panelTexture[i]); // Dibuja el fondo de la textura SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_RenderClear(renderer); switch (panel[i].mode) { case scoreboardMode::SCORE: { // SCORE textScoreBoard->writeCentered(slot4_1.x, slot4_1.y, name[i]); textScoreBoard->writeCentered(slot4_2.x, slot4_2.y, updateScoreText(score[i])); // MULT textScoreBoard->writeCentered(slot4_3.x, slot4_3.y, lang::getText(55)); textScoreBoard->writeCentered(slot4_4.x, slot4_4.y, std::to_string(mult[i]).substr(0, 3)); break; } case scoreboardMode::DEMO: { // DEMO MODE textScoreBoard->writeCentered(slot4_1.x, slot4_1.y + 4, lang::getText(101)); // PRESS START TO PLAY if (counter % 10 < 8) { textScoreBoard->writeCentered(slot4_3.x, slot4_3.y - 2, lang::getText(103)); textScoreBoard->writeCentered(slot4_4.x, slot4_4.y - 2, lang::getText(104)); } break; } case scoreboardMode::WAITING: { // GAME OVER textScoreBoard->writeCentered(slot4_1.x, slot4_1.y + 4, lang::getText(102)); // PRESS START TO PLAY if (counter % 10 < 8) { textScoreBoard->writeCentered(slot4_3.x, slot4_3.y - 2, lang::getText(103)); textScoreBoard->writeCentered(slot4_4.x, slot4_4.y - 2, lang::getText(104)); } break; } case scoreboardMode::GAME_OVER: { // GAME OVER textScoreBoard->writeCentered(slot4_1.x, slot4_1.y + 4, lang::getText(102)); break; } case scoreboardMode::STAGE_INFO: { // STAGE textScoreBoard->writeCentered(slot4_1.x, slot4_1.y, lang::getText(57) + std::to_string(stage)); // POWERMETER powerMeterSprite->setSpriteClip(0, 0, 40, 7); powerMeterSprite->render(); powerMeterSprite->setSpriteClip(40, 0, int(power * 40.0f), 7); powerMeterSprite->render(); // HI-SCORE textScoreBoard->writeCentered(slot4_3.x, slot4_3.y, lang::getText(56)); textScoreBoard->writeCentered(slot4_4.x, slot4_4.y, hiScoreName + " - " + updateScoreText(hiScore)); break; } case scoreboardMode::CONTINUE: { // SCORE textScoreBoard->writeCentered(slot4_1.x, slot4_1.y, name[i]); textScoreBoard->writeCentered(slot4_2.x, slot4_2.y, updateScoreText(score[i])); // CONTINUE textScoreBoard->writeCentered(slot4_3.x, slot4_3.y, lang::getText(105)); textScoreBoard->writeCentered(slot4_4.x, slot4_4.y, std::to_string(continueCounter[i])); break; } case scoreboardMode::ENTER_NAME: { // SCORE textScoreBoard->writeCentered(slot4_1.x, slot4_1.y, name[i]); textScoreBoard->writeCentered(slot4_2.x, slot4_2.y, updateScoreText(score[i])); // ENTER NAME textScoreBoard->writeCentered(slot4_3.x, slot4_3.y, lang::getText(106)); SDL_Rect rect = {enterNamePos.x, enterNamePos.y, 5, 7}; SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xEB, 255); for (int j = 0; j < (int)recordName[i].size(); ++j) { if (j == selectorPos[i]) { // La letra seleccionada se pinta de forma intermitente if (counter % 3 > 0) { SDL_RenderDrawLine(renderer, rect.x, rect.y + rect.h, rect.x + rect.w, rect.y + rect.h); textScoreBoard->write(rect.x, rect.y, recordName[i].substr(j, 1)); } } else { SDL_RenderDrawLine(renderer, rect.x, rect.y + rect.h, rect.x + rect.w, rect.y + rect.h); textScoreBoard->write(rect.x, rect.y, recordName[i].substr(j, 1)); } rect.x += 7; } break; } default: break; } } // Deja el renderizador apuntando donde estaba SDL_SetRenderTarget(renderer, temp); } // Rellena la textura de fondo void Scoreboard::fillBackgroundTexture() { // Rellena los diferentes paneles del marcador fillPanelTextures(); // Cambia el destino del renderizador SDL_Texture *temp = SDL_GetRenderTarget(renderer); SDL_SetRenderTarget(renderer, background); // Dibuja el fondo del marcador SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, 255); SDL_RenderClear(renderer); // Copia las texturas de los paneles for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) { SDL_RenderCopy(renderer, panelTexture[i], nullptr, &panel[i].pos); } // Dibuja la linea que separa la zona de juego del marcador renderSeparator(); // Deja el renderizador apuntando donde estaba SDL_SetRenderTarget(renderer, temp); } // Recalcula las anclas de los elementos void Scoreboard::recalculateAnchors() { // Recalcula la posición y el tamaño de los paneles const float panelWidth = (float)rect.w / (float)SCOREBOARD_MAX_PANELS; for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) { panel[i].pos.x = roundf(panelWidth * i); panel[i].pos.y = 0; panel[i].pos.w = roundf(panelWidth * (i + 1)) - panel[i].pos.x; panel[i].pos.h = rect.h; } // Constantes para definir las zonas del panel: 4 filas y 1 columna const int rowSize = rect.h / 4; const int textHeight = 7; // Filas const int row1 = (rowSize * 0) + (textHeight / 2); const int row2 = (rowSize * 1) + (textHeight / 2) - 1; const int row3 = (rowSize * 2) + (textHeight / 2) - 2; const int row4 = (rowSize * 3) + (textHeight / 2) - 3; // Columna const int col = panelWidth / 2; // Slots de 4 slot4_1 = {col, row1}; slot4_2 = {col, row2}; slot4_3 = {col, row3}; slot4_4 = {col, row4}; // Primer cuadrado para poner el nombre de record const int enterNameLenght = 8 * 7; enterNamePos.x = (panelWidth - enterNameLenght) / 2; enterNamePos.y = row4; // Recoloca los sprites if (powerMeterSprite) { powerMeterSprite->setPosX(slot4_2.x - 20); powerMeterSprite->setPosY(slot4_2.y); } } // Establece el modo del marcador void Scoreboard::setMode(int index, scoreboardMode mode) { panel[index].mode = mode; } // Crea la textura de fondo void Scoreboard::createBackgroundTexture() { // Elimina la textura en caso de existir if (background) { SDL_DestroyTexture(background); } // Recrea la textura de fondo background = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect.w, rect.h); SDL_SetTextureBlendMode(background, SDL_BLENDMODE_BLEND); } // Crea las texturas de los paneles void Scoreboard::createPanelTextures() { // Elimina las texturas en caso de existir for (auto texture : panelTexture) { if (texture != nullptr) { SDL_DestroyTexture(texture); } } panelTexture.clear(); // Crea las texturas para cada panel for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) { SDL_Texture *tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, panel[i].pos.w, panel[i].pos.h); SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND); panelTexture.push_back(tex); } } // Dibuja la linea que separa la zona de juego del marcador void Scoreboard::renderSeparator() { // Dibuja la linea que separa el marcador de la zona de juego SDL_SetRenderDrawColor(renderer, separatorColor.r, separatorColor.g, separatorColor.b, 255); SDL_RenderDrawLine(renderer, 0, 0, rect.w, 0); }