456 lines
13 KiB
C++
456 lines
13 KiB
C++
#include "scoreboard.h"
|
|
#include <SDL3/SDL_blendmode.h> // Para SDL_BLENDMODE_BLEND
|
|
#include <SDL3/SDL_pixels.h> // Para SDL_PIXELFORMAT_RGBA8888
|
|
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
|
#include <math.h> // Para roundf
|
|
#include <iomanip> // Para operator<<, setfill, setw
|
|
#include <sstream> // Para basic_ostream, basic_ostringstream
|
|
#include "enter_name.h" // Para MAX_NAME_LENGHT
|
|
#include "lang.h" // Para getText
|
|
#include "resource.h" // Para Resource
|
|
#include "screen.h" // Para Screen
|
|
#include "sprite.h" // Para Sprite
|
|
#include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR
|
|
|
|
// [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()
|
|
{
|
|
Scoreboard::scoreboard_ = new Scoreboard();
|
|
}
|
|
|
|
// [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()
|
|
: renderer_(Screen::get()->getRenderer()),
|
|
game_power_meter_texture_(Resource::get()->getTexture("game_power_meter.png")),
|
|
power_meter_sprite_(std::make_unique<Sprite>(game_power_meter_texture_)),
|
|
text_scoreboard_(Resource::get()->getText("8bithud"))
|
|
{
|
|
// 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(SDL_FRect{
|
|
static_cast<float>(slot4_2_.x - 20),
|
|
static_cast<float>(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();
|
|
|
|
// Inicializa el vector de colores para el nombre
|
|
iniNameColors();
|
|
}
|
|
|
|
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 7 cifras
|
|
std::string Scoreboard::updateScoreText(int num)
|
|
{
|
|
std::ostringstream oss;
|
|
oss << std::setw(7) << std::setfill('0') << num;
|
|
return oss.str();
|
|
}
|
|
|
|
// Actualiza el contador
|
|
void Scoreboard::updateTimeCounter()
|
|
{
|
|
constexpr int TICKS_SPEED = 100;
|
|
|
|
if (SDL_GetTicks() - ticks_ > TICKS_SPEED)
|
|
{
|
|
ticks_ = SDL_GetTicks();
|
|
++time_counter_;
|
|
}
|
|
}
|
|
|
|
// Actualiza la lógica del marcador
|
|
void Scoreboard::update()
|
|
{
|
|
fillBackgroundTexture();
|
|
updateTimeCounter();
|
|
++loop_counter_;
|
|
}
|
|
|
|
// Pinta el marcador
|
|
void Scoreboard::render()
|
|
{
|
|
SDL_RenderTexture(renderer_, background_, nullptr, &rect_);
|
|
}
|
|
|
|
// Establece el valor de la variable
|
|
void Scoreboard::setColor(Color color)
|
|
{
|
|
color_ = color;
|
|
fillBackgroundTexture();
|
|
}
|
|
|
|
// Establece el valor de la variable
|
|
void Scoreboard::setPos(SDL_FRect rect)
|
|
{
|
|
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
|
|
auto temp = SDL_GetRenderTarget(renderer_);
|
|
|
|
// Genera el contenido de cada panel_
|
|
for (size_t 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, "x" + 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 (time_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 (time_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 (time_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));
|
|
const std::string name = hi_score_name_ == "" ? "" : hi_score_name_ + " - ";
|
|
text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y, 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_FRect rect = {enter_name_pos_.x, enter_name_pos_.y, 5.0f, 7.0f};
|
|
|
|
// Recorre todos los slots de letras del nombre
|
|
for (size_t j = 0; j < MAX_NAME_LENGHT; ++j)
|
|
{
|
|
// Selecciona el color
|
|
const Color color = j < selector_pos_[i] ? ORANGE_SOFT_COLOR.lighten() : Color(0xFF, 0xFF, 0xEB);
|
|
|
|
if (j != selector_pos_[i] || time_counter_ % 3 == 0)
|
|
{
|
|
// Dibuja la linea
|
|
if (j >= selector_pos_[i])
|
|
{
|
|
SDL_SetRenderDrawColor(renderer_, color.r, color.g, color.b, 255);
|
|
SDL_RenderLine(renderer_, rect.x, rect.y + rect.h, rect.x + rect.w, rect.y + rect.h);
|
|
}
|
|
|
|
// Dibuja la letra
|
|
if (j < record_name_->size())
|
|
{
|
|
text_scoreboard_->writeColored(rect.x, rect.y, record_name_[i].substr(j, 1), color);
|
|
}
|
|
}
|
|
rect.x += 7;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ScoreboardMode::SHOW_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]));
|
|
|
|
// NAME
|
|
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y, lang::getText(106));
|
|
/* TEXTO CENTRADO */
|
|
// text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y, record_name_[i], 1, getColorLikeKnightRider(name_colors_, loop_counter_ / 5));
|
|
|
|
/* TEXTO A LA IZQUIERDA */
|
|
text_scoreboard_->writeColored(enter_name_pos_.x, enter_name_pos_.y, record_name_[i], getColorLikeKnightRider(name_colors_, loop_counter_ / 5));
|
|
break;
|
|
}
|
|
case ScoreboardMode::GAME_COMPLETED:
|
|
{
|
|
// GAME OVER
|
|
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y + 4, lang::getText(102));
|
|
|
|
// SCORE
|
|
if (time_counter_ % 10 < 8)
|
|
{
|
|
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y - 2, lang::getText(120));
|
|
text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y - 2, updateScoreText(score_[i]));
|
|
}
|
|
}
|
|
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_RenderTexture(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 panel_width = (float)rect_.w / (float)SCOREBOARD_MAX_PANELS;
|
|
for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i)
|
|
{
|
|
panel_[i].pos.x = roundf(panel_width * i);
|
|
panel_[i].pos.y = 0;
|
|
panel_[i].pos.w = roundf(panel_width * (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 ROW_SIZE = rect_.h / 4;
|
|
const int TEXT_HEIGHT = 7;
|
|
|
|
// Filas
|
|
const float ROW1 = (ROW_SIZE * 0) + (TEXT_HEIGHT / 2);
|
|
const float ROW2 = (ROW_SIZE * 1) + (TEXT_HEIGHT / 2) - 1;
|
|
const float ROW3 = (ROW_SIZE * 2) + (TEXT_HEIGHT / 2) - 2;
|
|
const float ROW4 = (ROW_SIZE * 3) + (TEXT_HEIGHT / 2) - 3;
|
|
|
|
// Columna
|
|
const float COL = panel_width / 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 enter_name_lenght = text_scoreboard_->lenght(std::string(MAX_NAME_LENGHT, 'A'));
|
|
enter_name_pos_.x = COL - (enter_name_lenght / 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);
|
|
}
|
|
}
|
|
|
|
// 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_RenderLine(renderer_, 0, 0, rect_.w, 0);
|
|
}
|
|
|
|
// Inicializa el vector de colores para el nombre
|
|
void Scoreboard::iniNameColors()
|
|
{
|
|
Color color = GREEN_COLOR;
|
|
|
|
name_colors_.clear();
|
|
name_colors_.emplace_back(color.lighten(50));
|
|
name_colors_.emplace_back(color.lighten(25));
|
|
name_colors_.emplace_back(color);
|
|
name_colors_.emplace_back(color.darken(25));
|
|
} |