Files
coffee_crisis_arcade_edition/source/scoreboard.cpp
Sergio Valor afe092c742 Muntat a c++14 per a make_unique
Mes autos, const i constexpr perl codi
Ara la classe Screen es un poc pitjor
2024-10-06 14:58:00 +02:00

500 lines
12 KiB
C++

#include "scoreboard.h"
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND
#include <SDL2/SDL_pixels.h> // for SDL_PIXELFORMAT_RGBA8888
#include <SDL2/SDL_timer.h> // for SDL_GetTicks
#include <math.h> // 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<Texture>(new Texture(renderer, Asset::get()->get("game_power_meter.png")));
powerMeterSprite = std::unique_ptr<Sprite>(new Sprite(slot4_2.x - 20, slot4_2.y, 40, 7, gamePowerMeterTexture.get()));
textScoreBoard = std::unique_ptr<Text>(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);
}