Files
coffee_crisis_arcade_edition/source/scoreboard.cpp
Sergio Valor a4b4e188cd Precàrrega de tots els recursos al inici del joc
8.000.000 de cherrypickings que he anat fent pel codi
2024-10-20 11:06:10 +02:00

475 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 <iomanip>
#include <sstream>
#include "asset.h" // for Asset
#include "lang.h" // for getText
#include "resource.h" // for Resource
#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 score_board con esta función estática
void Scoreboard::init(SDL_Renderer *renderer)
{
Scoreboard::scoreboard_ = new Scoreboard(renderer);
}
// [SINGLETON] Destruiremos el objeto score_board con esta función estática
void Scoreboard::destroy()
{
delete Scoreboard::scoreboard_;
}
// [SINGLETON] Con este método obtenemos el objeto score_board y podemos trabajar con él
Scoreboard *Scoreboard::get()
{
return Scoreboard::scoreboard_;
}
// Constructor
Scoreboard::Scoreboard(SDL_Renderer *renderer)
: renderer_(renderer),
game_power_meter_texture_(Resource::get()->getTexture("game_power_meter.png")),
power_meter_sprite_(std::make_unique<Sprite>(game_power_meter_texture_)),
text_scoreboard_(std::make_unique<Text>(Resource::get()->getTexture("8bithud.png"), Resource::get()->getTextFile("8bithud.txt"))),
stage_(1),
hi_score_(0),
power_(0),
hi_score_name_(std::string()),
color_({0, 0, 0}),
rect_({0, 0, 320, 40}),
ticks_(SDL_GetTicks()),
counter_(0)
{
// Inicializa variables
for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i)
{
name_[i].clear();
record_name_[i].clear();
selector_pos_[i] = 0;
score_[i] = 0;
mult_[i] = 0;
continue_counter_[i] = 0;
}
panel_[SCOREBOARD_LEFT_PANEL].mode = ScoreboardMode::SCORE;
panel_[SCOREBOARD_RIGHT_PANEL].mode = ScoreboardMode::SCORE;
panel_[SCOREBOARD_CENTER_PANEL].mode = ScoreboardMode::STAGE_INFO;
// Recalcula las anclas de los elementos
recalculateAnchors();
power_meter_sprite_->setPosition({slot4_2_.x - 20, slot4_2_.y, 40, 7});
// 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 : panel_texture_)
{
if (texture)
{
SDL_DestroyTexture(texture);
}
}
}
// Transforma un valor numérico en una cadena de 6 cifras
std::string Scoreboard::updateScoreText(int num)
{
std::ostringstream oss;
oss << std::setw(8) << std::setfill('0') << num;
return oss.str();
}
// 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_, const std::string &name_)
{
this->name_[panel_] = name_;
}
// Establece el valor de la variable
void Scoreboard::setRecordName(int panel_, const std::string &record_name_)
{
this->record_name_[panel_] = record_name_;
}
// Establece el valor de la variable
void Scoreboard::setSelectorPos(int panel_, int pos)
{
selector_pos_[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)
{
continue_counter_[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 hi_score_)
{
this->hi_score_ = hi_score_;
}
// Establece el valor de la variable
void Scoreboard::setPower(float power_)
{
this->power_ = power_;
}
// Establece el valor de la variable
void Scoreboard::setHiScoreName(const std::string &name_)
{
hi_score_name_ = name_;
}
// Establece el valor de la variable
void Scoreboard::setColor(Color 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_, panel_texture_[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
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y, name_[i]);
text_scoreboard_->writeCentered(slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]));
// MULT
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y, lang::getText(55));
text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y, std::to_string(mult_[i]).substr(0, 3));
break;
}
case ScoreboardMode::DEMO:
{
// DEMO MODE
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y + 4, lang::getText(101));
// PRESS START TO PLAY
if (counter_ % 10 < 8)
{
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y - 2, lang::getText(103));
text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y - 2, lang::getText(104));
}
break;
}
case ScoreboardMode::WAITING:
{
// GAME OVER
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y + 4, lang::getText(102));
// PRESS START TO PLAY
if (counter_ % 10 < 8)
{
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y - 2, lang::getText(103));
text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y - 2, lang::getText(104));
}
break;
}
case ScoreboardMode::GAME_OVER:
{
// GAME OVER
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y + 4, lang::getText(102));
// PLEASE WAIT
if (counter_ % 10 < 8)
{
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y - 2, lang::getText(114));
text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y - 2, lang::getText(115));
}
break;
}
case ScoreboardMode::STAGE_INFO:
{
// STAGE
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y, lang::getText(57) + std::to_string(stage_));
// POWERMETER
power_meter_sprite_->setSpriteClip(0, 0, 40, 7);
power_meter_sprite_->render();
power_meter_sprite_->setSpriteClip(40, 0, int(power_ * 40.0f), 7);
power_meter_sprite_->render();
// HI-SCORE
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y, lang::getText(56));
text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y, hi_score_name_ + " - " + updateScoreText(hi_score_));
break;
}
case ScoreboardMode::CONTINUE:
{
// SCORE
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y, name_[i]);
text_scoreboard_->writeCentered(slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]));
// CONTINUE
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y, lang::getText(105));
text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y, std::to_string(continue_counter_[i]));
break;
}
case ScoreboardMode::ENTER_NAME:
{
// SCORE
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y, name_[i]);
text_scoreboard_->writeCentered(slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]));
// ENTER NAME
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y, lang::getText(106));
SDL_Rect rect = {enter_name_pos_.x, enter_name_pos_.y, 5, 7};
SDL_SetRenderDrawColor(renderer_, 0xFF, 0xFF, 0xEB, 255);
for (int j = 0; j < (int)record_name_[i].size(); ++j)
{
if (j == selector_pos_[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);
text_scoreboard_->write(rect.x, rect.y, record_name_[i].substr(j, 1));
}
}
else
{
SDL_RenderDrawLine(renderer_, rect.x, rect.y + rect.h, rect.x + rect.w, rect.y + rect.h);
text_scoreboard_->write(rect.x, rect.y, record_name_[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_, panel_texture_[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;
enter_name_pos_.x = (panelWidth - enterNameLenght) / 2;
enter_name_pos_.y = row4;
// Recoloca los sprites
if (power_meter_sprite_)
{
power_meter_sprite_->setX(slot4_2_.x - 20);
power_meter_sprite_->setY(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 : panel_texture_)
{
if (texture != nullptr)
{
SDL_DestroyTexture(texture);
}
}
panel_texture_.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);
panel_texture_.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_, separator_color.r, separator_color.g, separator_color.b, 255);
SDL_RenderDrawLine(renderer_, 0, 0, rect_.w, 0);
}