segon commit
This commit is contained in:
183
source/game/gameplay/scoreboard.cpp
Normal file
183
source/game/gameplay/scoreboard.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
#include "game/gameplay/scoreboard.hpp"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "core/locale/locale.hpp" // Para Locale
|
||||
#include "core/rendering/screen.hpp" // Para Screen
|
||||
#include "core/rendering/sprite/animated_sprite.hpp" // Para SAnimatedSprite
|
||||
#include "core/rendering/surface.hpp" // Para Surface
|
||||
#include "core/rendering/text.hpp" // Para Text
|
||||
#include "core/resources/resource_cache.hpp" // Para Resource
|
||||
#include "game/entities/player.hpp" // Para Player::skinToAnimationPath
|
||||
#include "game/options.hpp" // Para Options, options, Cheat, OptionsGame
|
||||
#include "utils/defines.hpp" // Para BLOCK
|
||||
#include "utils/utils.hpp" // Para stringToColor
|
||||
|
||||
// Constructor
|
||||
Scoreboard::Scoreboard(std::shared_ptr<Data> data)
|
||||
: item_surface_(Resource::Cache::get()->getSurface("items.gif")),
|
||||
data_(std::move(std::move(data))) {
|
||||
const float SURFACE_WIDTH = Options::game.width;
|
||||
constexpr float SURFACE_HEIGHT = 6.0F * Tile::SIZE;
|
||||
|
||||
// Reserva memoria para los objetos
|
||||
const std::string PLAYER_ANIM_PATH = Player::skinToAnimationPath(Options::game.player_skin);
|
||||
const auto& player_animation_data = Resource::Cache::get()->getAnimationData(PLAYER_ANIM_PATH);
|
||||
player_sprite_ = std::make_shared<AnimatedSprite>(player_animation_data);
|
||||
player_sprite_->setCurrentAnimation("default");
|
||||
|
||||
surface_ = std::make_shared<Surface>(SURFACE_WIDTH, SURFACE_HEIGHT);
|
||||
surface_dest_ = {.x = 0, .y = Options::game.height - SURFACE_HEIGHT, .w = SURFACE_WIDTH, .h = SURFACE_HEIGHT};
|
||||
|
||||
// Inicializa el color de items
|
||||
items_color_ = stringToColor("white");
|
||||
|
||||
// Inicializa el vector de colores
|
||||
const std::vector<std::string> COLORS = {"blue", "magenta", "green", "cyan", "yellow", "white", "bright_blue", "bright_magenta", "bright_green", "bright_cyan", "bright_yellow", "bright_white"};
|
||||
for (const auto& color : COLORS) {
|
||||
color_.push_back(stringToColor(color));
|
||||
}
|
||||
}
|
||||
|
||||
// Pinta el objeto en pantalla
|
||||
void Scoreboard::render() {
|
||||
surface_->render(nullptr, &surface_dest_);
|
||||
}
|
||||
|
||||
// Actualiza las variables del objeto
|
||||
void Scoreboard::update(float delta_time) {
|
||||
// Acumular tiempo para animaciones
|
||||
time_accumulator_ += delta_time;
|
||||
|
||||
// Actualiza el color de la cantidad de items recogidos
|
||||
updateItemsColor(delta_time);
|
||||
|
||||
// Dibuja la textura
|
||||
fillTexture();
|
||||
|
||||
if (!is_paused_) {
|
||||
// Si está en pausa no se actualiza el reloj
|
||||
clock_ = getTime();
|
||||
}
|
||||
}
|
||||
|
||||
// Obtiene el tiempo transcurrido de partida
|
||||
auto Scoreboard::getTime() -> Scoreboard::ClockData { // NOLINT(readability-convert-member-functions-to-static)
|
||||
const Uint32 TIME_ELAPSED = SDL_GetTicks() - data_->ini_clock - paused_time_elapsed_;
|
||||
|
||||
ClockData time;
|
||||
time.hours = TIME_ELAPSED / 3600000;
|
||||
time.minutes = TIME_ELAPSED / 60000;
|
||||
time.seconds = TIME_ELAPSED / 1000;
|
||||
time.separator = (TIME_ELAPSED % 1000 <= 500) ? ":" : " ";
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
// Actualiza el sprite del jugador con la skin actual
|
||||
void Scoreboard::refreshPlayerSkin() {
|
||||
const std::string PLAYER_ANIM_PATH = Player::skinToAnimationPath(Options::game.player_skin);
|
||||
const auto& player_animation_data = Resource::Cache::get()->getAnimationData(PLAYER_ANIM_PATH);
|
||||
player_sprite_ = std::make_shared<AnimatedSprite>(player_animation_data);
|
||||
player_sprite_->setCurrentAnimation("default");
|
||||
}
|
||||
|
||||
// Pone el marcador en modo pausa
|
||||
void Scoreboard::setPaused(bool value) {
|
||||
if (is_paused_ == value) {
|
||||
// Evita ejecutar lógica si el estado no cambia
|
||||
return;
|
||||
}
|
||||
|
||||
is_paused_ = value;
|
||||
|
||||
if (is_paused_) {
|
||||
// Guarda el tiempo actual al pausar
|
||||
paused_time_ = SDL_GetTicks();
|
||||
} else {
|
||||
// Calcula el tiempo pausado acumulado al reanudar
|
||||
paused_time_elapsed_ += SDL_GetTicks() - paused_time_;
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el color de la cantidad de items recogidos
|
||||
void Scoreboard::updateItemsColor(float delta_time) {
|
||||
if (!data_->jail_is_open) {
|
||||
return;
|
||||
}
|
||||
|
||||
items_color_timer_ += delta_time;
|
||||
|
||||
// Resetear timer cada 2 ciclos (0.666s total)
|
||||
if (items_color_timer_ >= ITEMS_COLOR_BLINK_DURATION * 2.0F) {
|
||||
items_color_timer_ = 0.0F;
|
||||
}
|
||||
|
||||
// Alternar color cada ITEMS_COLOR_BLINK_DURATION
|
||||
if (items_color_timer_ < ITEMS_COLOR_BLINK_DURATION) {
|
||||
items_color_ = stringToColor("white");
|
||||
} else {
|
||||
items_color_ = stringToColor("magenta");
|
||||
}
|
||||
}
|
||||
|
||||
// Devuelve la cantidad de minutos de juego transcurridos
|
||||
auto Scoreboard::getMinutes() -> int {
|
||||
return getTime().minutes;
|
||||
}
|
||||
|
||||
// Dibuja los elementos del marcador en la textura
|
||||
void Scoreboard::fillTexture() {
|
||||
// Empieza a dibujar en la textura
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(surface_);
|
||||
|
||||
// Limpia la textura
|
||||
surface_->clear(stringToColor("black"));
|
||||
|
||||
// Dibuja las vidas
|
||||
const int WALK_FRAMES = player_sprite_->getCurrentAnimationSize();
|
||||
const int DESP = static_cast<int>(time_accumulator_ / SPRITE_WALK_CYCLE_DURATION) % (WALK_FRAMES * 2);
|
||||
const int FRAME = DESP % WALK_FRAMES;
|
||||
player_sprite_->setCurrentAnimationFrame(FRAME);
|
||||
player_sprite_->setPosY(LINE2_Y);
|
||||
for (int i = 0; i < data_->lives; ++i) {
|
||||
player_sprite_->setPosX(LIVES_START_X + (LIVES_SPACING * i) + DESP);
|
||||
const int INDEX = i % color_.size();
|
||||
player_sprite_->render(1, color_.at(INDEX));
|
||||
}
|
||||
|
||||
// Muestra si suena la música
|
||||
if (data_->music) {
|
||||
const Uint8 C = data_->color;
|
||||
SDL_FRect clip = {.x = 0, .y = 8, .w = 8, .h = 8};
|
||||
item_surface_->renderWithColorReplace(MUSIC_ICON_X, LINE2_Y, 1, C, &clip);
|
||||
}
|
||||
|
||||
// Escribe los textos
|
||||
auto text = Resource::Cache::get()->getText("smb2");
|
||||
const std::string TIME_TEXT = std::to_string((clock_.minutes % 100) / 10) + std::to_string(clock_.minutes % 10) + clock_.separator + std::to_string((clock_.seconds % 60) / 10) + std::to_string(clock_.seconds % 10);
|
||||
const std::string ITEMS_TEXT = std::to_string(data_->items / 100) + std::to_string((data_->items % 100) / 10) + std::to_string(data_->items % 10);
|
||||
text->writeColored(ITEMS_LABEL_X, LINE1_Y, Locale::get()->get("scoreboard.items"), data_->color); // NOLINT(readability-static-accessed-through-instance)
|
||||
text->writeColored(ITEMS_VALUE_X, LINE1_Y, ITEMS_TEXT, items_color_);
|
||||
text->writeColored(TIME_LABEL_X, LINE1_Y, Locale::get()->get("scoreboard.time"), data_->color); // NOLINT(readability-static-accessed-through-instance)
|
||||
text->writeColored(TIME_VALUE_X, LINE1_Y, TIME_TEXT, stringToColor("white"));
|
||||
|
||||
const std::string ROOMS_TEXT = std::to_string(data_->rooms / 100) + std::to_string((data_->rooms % 100) / 10) + std::to_string(data_->rooms % 10);
|
||||
text->writeColored(ROOMS_LABEL_X, LINE2_Y, Locale::get()->get("scoreboard.rooms"), stringToColor("white")); // NOLINT(readability-static-accessed-through-instance)
|
||||
text->writeColored(ROOMS_VALUE_X, LINE2_Y, ROOMS_TEXT, stringToColor("white"));
|
||||
|
||||
// Indicadores de trucos activos (fuente 8bithud)
|
||||
auto cheat_text = Resource::Cache::get()->getText("8bithud");
|
||||
if (Options::cheats.infinite_lives == Options::Cheat::State::ENABLED) {
|
||||
cheat_text->writeColored(CHEAT_INF_LIVES_X, CHEAT_INF_LIVES_Y, Locale::get()->get("scoreboard.cheat_infinite_lives"), data_->color); // NOLINT(readability-static-accessed-through-instance)
|
||||
}
|
||||
if (Options::cheats.invincible == Options::Cheat::State::ENABLED) {
|
||||
cheat_text->writeColored(CHEAT_INVINCIBLE_X, CHEAT_INVINCIBLE_Y, Locale::get()->get("scoreboard.cheat_invincibility"), data_->color); // NOLINT(readability-static-accessed-through-instance)
|
||||
}
|
||||
|
||||
// Deja el renderizador como estaba
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
}
|
||||
Reference in New Issue
Block a user