Compare commits

12 Commits

Author SHA1 Message Date
84595da13a EnterName: si has plenat tots els slots de lletres, apretar una volta mes el de fixar lletra fixa el nom 2025-02-07 14:15:18 +01:00
01591175ef Pos pense que ja està tot apanyat lo de EnterName i Scoreboard 2025-02-07 13:45:07 +01:00
29bc4a64fd Afegit position_overflow_ per a EnterName i poder plenar tots els slots de lletres 2025-02-07 12:31:59 +01:00
559210652f Treballant en scoreboard::fillPanelTextures 2025-02-06 20:58:15 +01:00
44e4ca490d canvi de pc
treballant en enter name
2025-02-06 14:59:25 +01:00
3cebee2ae4 Implementat control de repetició per als eixos del joystick 2025-02-06 12:36:16 +01:00
270d7d1848 Duplicada la font 04b_25 per a tindre versió gris i versió negra. La gris es la que es por modular amb colors.
Eliminada la font nokia que ja no s'estava utilitzant.
Optimitzada la càrrega de fonts al permetre reutilitzar fitxers .txt de altres fonts
2025-02-06 10:31:32 +01:00
ccf005dce1 Afegit el disparador per a la aparició del enemic nou 2025-02-06 09:59:58 +01:00
5755947ff7 La tabla de puntuació ja mostra amb altre color la puntuació que s'acaba d'afegir
fix: la tabla de punts no guardava a disc el estat de 1CC de cada entrada
2025-02-05 22:52:19 +01:00
6f594b9a1f La tabla de puntuacions ja mostra aquelles aconseguides amb 1CC 2025-02-05 15:15:48 +01:00
7e2021da70 canvi de pc 2025-02-05 10:17:49 +01:00
0a9a92d4b7 El text de la tabla de puntuacion ja ix centrat i el "diferent" es el que fa 10 2025-02-05 09:45:30 +01:00
33 changed files with 650 additions and 675 deletions

View File

@@ -11,7 +11,7 @@ APP_NAME := Coffee Crisis Arcade Edition
RELEASE_FOLDER := ccae_release RELEASE_FOLDER := ccae_release
RELEASE_FILE := $(RELEASE_FOLDER)/$(TARGET_NAME) RELEASE_FILE := $(RELEASE_FOLDER)/$(TARGET_NAME)
RESOURCE_FILE := release/coffee.res RESOURCE_FILE := release/coffee.res
VERSION := 2025-01-05 VERSION := 2025-02-07
# Nombres para los ficheros de lanzamiento # Nombres para los ficheros de lanzamiento
WINDOWS_RELEASE := $(TARGET_NAME)-$(VERSION)-win32-x64.zip WINDOWS_RELEASE := $(TARGET_NAME)-$(VERSION)-win32-x64.zip

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
data/font/04b_25_grey.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -1,194 +0,0 @@
# box width
14
# box height
14
# 32 espacio ( )
8
# 33 !
5
# 34 "
8
# 35
10
# 36 $
10
# 37 %
9
# 38 &
11
# 39 '
5
# 40 (
7
# 41 )
7
# 42 *
7
# 43 +
9
# 44 ,
5
# 45 -
9
# 46 .
5
# 47 /
12
# 48 0
8
# 49 1
6
# 50 2
8
# 51 3
8
# 52 4
8
# 53 5
8
# 54 6
8
# 55 7
8
# 56 8
8
# 57 9
8
# 58 :
5
# 59 ;
5
# 60 <
8
# 61 =
8
# 62 >
8
# 63 ?
8
# 64 @
11
# 65 A
8
# 66 B
8
# 67 C
8
# 68 D
8
# 69 E
8
# 70 F
8
# 71 G
8
# 72 H
8
# 73 I
5
# 74 J
8
# 75 K
8
# 76 L
8
# 77 M
11
# 78 N
8
# 79 O
8
# 80 P
8
# 81 Q
8
# 82 R
8
# 83 S
8
# 84 T
9
# 85 U
8
# 86 V
8
# 87 W
11
# 88 X
8
# 89 Y
8
# 90 Z
8
# 91 [
7
# 92 \
11
# 93 ]
7
# 94 ^
6
# 95 _
7
# 96 `
6
# 97 a
8
# 98 b
8
# 99 c
8
# 100 d
8
# 101 e
8
# 102 f
8
# 103 g
8
# 104 h
8
# 105 i
5
# 106 j
8
# 107 k
8
# 108 l
8
# 109 m
11
# 110 n
8
# 111 o
8
# 112 p
8
# 113 q
8
# 114 r
8
# 115 s
8
# 116 t
9
# 117 u
8
# 118 v
8
# 119 w
11
# 120 x
8
# 121 y
8
# 122 z
8
# 123 {
1
# 124 |
1
# 125 }
1
# 126 ~
1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -1,194 +0,0 @@
# box width
10
# box height
10
# 32 espacio ( )
5
# 33 !
4
# 34 "
5
# 35 #
7
# 36 $
7
# 37 %
8
# 38 &
8
# 39 '
3
# 40 (
5
# 41 )
5
# 42 *
7
# 43 +
7
# 44 ,
4
# 45 -
6
# 46 .
4
# 47 /
5
# 48 0
7
# 49 1
5
# 50 2
7
# 51 3
7
# 52 4
7
# 53 5
7
# 54 6
7
# 55 7
7
# 56 8
7
# 57 9
7
# 58 :
4
# 59 ;
4
# 60 <
6
# 61 =
6
# 62 >
6
# 63 ?
7
# 64 @
8
# 65 A
7
# 66 B
7
# 67 C
7
# 68 D
7
# 69 E
7
# 70 F
7
# 71 G
7
# 72 H
7
# 73 I
4
# 74 J
6
# 75 K
8
# 76 L
6
# 77 M
9
# 78 N
8
# 79 O
8
# 80 P
7
# 81 Q
8
# 82 R
7
# 83 S
6
# 84 T
8
# 85 U
7
# 86 V
8
# 87 W
9
# 88 X
8
# 89 Y
8
# 90 Z
7
# 91 [
4
# 92 \
5
# 93 ]
4
# 94 ^
5
# 95 _
8
# 96 `
4
# 97 a
7
# 98 b
7
# 99 c
6
# 100 d
7
# 101 e
7
# 102 f
5
# 103 g
7
# 104 h
7
# 105 i
4
# 106 j
5
# 107 k
7
# 108 l
4
# 109 m
10
# 110 n
7
# 111 o
7
# 112 p
7
# 113 q
7
# 114 r
6
# 115 s
6
# 116 t
5
# 117 u
7
# 118 v
7
# 119 w
9
# 120 x
7
# 121 y
7
# 122 z
7
# 123 { -> ñ
7
# 124 | -> ç
7
# 125 }
0
# 126 ~
0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -52,7 +52,7 @@ Director::Director(int argc, const char *argv[])
section::name = section::Name::GAME; section::name = section::Name::GAME;
section::options = section::Options::GAME_PLAY_1P; section::options = section::Options::GAME_PLAY_1P;
#elif DEBUG #elif DEBUG
section::name = section::Name::CREDITS; section::name = section::Name::LOGO;
#else // NORMAL GAME #else // NORMAL GAME
section::name = section::Name::LOGO; section::name = section::Name::LOGO;
section::attract_mode = section::AttractMode::TITLE_TO_DEMO; section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
@@ -536,8 +536,6 @@ void Director::setFileList()
// Fuentes de texto // Fuentes de texto
Asset::get()->add(prefix + "/data/font/8bithud.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/font/8bithud.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/font/8bithud.txt", AssetType::FONT); Asset::get()->add(prefix + "/data/font/8bithud.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/nokia.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/font/nokia.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/smb2.gif", AssetType::BITMAP); Asset::get()->add(prefix + "/data/font/smb2.gif", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/font/smb2_palette1.pal", AssetType::PALETTE); Asset::get()->add(prefix + "/data/font/smb2_palette1.pal", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/font/smb2.txt", AssetType::FONT); Asset::get()->add(prefix + "/data/font/smb2.txt", AssetType::FONT);
@@ -545,8 +543,8 @@ void Director::setFileList()
Asset::get()->add(prefix + "/data/font/04b_25.txt", AssetType::FONT); Asset::get()->add(prefix + "/data/font/04b_25.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/04b_25_2x.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/font/04b_25_2x.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/font/04b_25_2x.txt", AssetType::FONT); Asset::get()->add(prefix + "/data/font/04b_25_2x.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/04b_25_var01.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/font/04b_25_metal.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/font/04b_25_var01.txt", AssetType::FONT); Asset::get()->add(prefix + "/data/font/04b_25_grey.png", AssetType::BITMAP);
// Textos // Textos
Asset::get()->add(prefix + "/data/lang/es_ES.txt", AssetType::LANG); Asset::get()->add(prefix + "/data/lang/es_ES.txt", AssetType::LANG);

View File

@@ -1,93 +1,164 @@
#include "enter_name.h" #include "enter_name.h"
#include "utils.h"
#include <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <algorithm> // Para max, min #include <algorithm> // Para max, min
#include <cassert> // Para assert
#include <iostream>
// Constructor // Constructor
EnterName::EnterName() EnterName::EnterName()
{ : character_list_(" ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-+-*/=?¿<>!\"#$%&/()") {}
init();
}
// Inicializa el objeto // Inicializa el objeto
void EnterName::init() void EnterName::init(const std::string &name)
{ {
// Obtiene el puntero al nombre // No se pasa ningún nombre
if (name == "")
{
name_ = "A"; name_ = "A";
// Inicia la lista de caracteres permitidos
character_list_ = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-+-*/=?¿<>!\"#$%&/()";
position_ = 0; position_ = 0;
num_characters_ = static_cast<int>(character_list_.size()); position_overflow_ = false;
}
// Se pasa un nombre
else
{
name_ = name;
position_ = name_.length();
position_overflow_ = position_ >= NAME_LENGHT ? true : false;
}
// Pone la lista de indices para que refleje el nombre // Inicializa el vector de indices con el nombre y espacios
updateCharacterIndex(); initCharacterIndex(name_);
// Actualiza el nombre para que ocupe 8 espacios
updateName();
} }
// Incrementa la posición // Incrementa la posición
void EnterName::incPosition() void EnterName::incPosition()
{ {
position_++; if (position_overflow_)
position_ = std::min(position_, NAME_LENGHT - 1); {
checkIfPositionHasBeenUsed(); // Si ya estamos en overflow, no incrementamos más.
return;
}
++position_;
if (position_ >= NAME_LENGHT)
{
position_ = NAME_LENGHT; // Mantenemos en el índice máximo válido.
position_overflow_ = true; // Activamos el flag de overflow.
}
else
{
// Copiamos el índice del carácter anterior si es posible.
if (position_ > 0 && position_ < NAME_LENGHT)
{
character_index_[position_] = character_index_[position_ - 1];
}
else
{
// Si position_ es 0, inicializamos el carácter actual.
character_index_[position_] = 0;
}
}
updateNameFromCharacterIndex();
} }
// Decrementa la posición // Decrementa la posición
void EnterName::decPosition() void EnterName::decPosition()
{ {
if (position_overflow_)
{
// Si estaba en overflow, lo desactivamos y mantenemos position_ en el máximo.
position_overflow_ = false;
position_ = NAME_LENGHT - 1;
}
else
{
if (position_ > 0)
{
--position_; --position_;
position_ = std::max(position_, 0);
// Limpiamos el carácter siguiente si el índice es válido.
if (position_ + 1 < NAME_LENGHT)
{
character_index_[position_ + 1] = 0;
}
}
else
{
// Si position_ es 0, aseguramos que no vaya a ser negativo y limpiamos el carácter actual.
position_ = 0;
character_index_[position_] = 0;
}
// Si position_ es menor que NAME_LENGHT, aseguramos que el overflow esté desactivado.
if (position_ < NAME_LENGHT)
{
position_overflow_ = false;
}
}
updateNameFromCharacterIndex();
} }
// Incrementa el índice // Incrementa el índice
void EnterName::incIndex() void EnterName::incIndex()
{ {
if (position_overflow_)
{
return;
}
++character_index_[position_]; ++character_index_[position_];
if (character_index_[position_] >= num_characters_) if (character_index_[position_] >= static_cast<int>(character_list_.size()))
{ {
character_index_[position_] = 0; character_index_[position_] = 0;
} }
updateName(); updateNameFromCharacterIndex();
} }
// Decrementa el índice // Decrementa el índice
void EnterName::decIndex() void EnterName::decIndex()
{ {
if (position_overflow_)
{
return;
}
--character_index_[position_]; --character_index_[position_];
if (character_index_[position_] < 0) if (character_index_[position_] < 0)
{ {
character_index_[position_] = num_characters_ - 1; character_index_[position_] = character_list_.size() - 1;
} }
updateName(); updateNameFromCharacterIndex();
} }
// Actualiza el nombre a partir de la lista de índices // Actualiza el nombre a partir de la lista de índices
void EnterName::updateName() void EnterName::updateNameFromCharacterIndex()
{ {
name_.clear(); name_.clear();
for (int i = 0; i < NAME_LENGHT; ++i) for (int i = 0; i < NAME_LENGHT; ++i)
{ {
name_.push_back(character_list_[character_index_[i]]); name_.push_back(character_list_[character_index_[i]]);
} }
name_ = trim(name_);
} }
// Actualiza la variable // Actualiza la variable
void EnterName::updateCharacterIndex() void EnterName::initCharacterIndex(const std::string &name)
{ {
// Rellena de espacios y marca como no usados // Rellena de espacios
for (size_t i = 0; i < NAME_LENGHT; ++i) for (size_t i = 0; i < NAME_LENGHT; ++i)
{ {
character_index_[i] = 0; character_index_[i] = 0;
position_has_been_used_[i] = false;
} }
// Coloca los índices en función de los caracteres que forman el nombre // Coloca los índices en función de los caracteres que forman el nombre
for (size_t i = 0; i < name_.size(); ++i) for (size_t i = 0; i < name.substr(0, NAME_LENGHT).size(); ++i)
{ {
character_index_[i] = findIndex(name_.at(i)); character_index_[i] = findIndex(name.at(i));
position_has_been_used_[i] = true;
} }
} }
@@ -99,27 +170,3 @@ int EnterName::findIndex(char character) const
return i; return i;
return 0; return 0;
} }
// Obtiene el nombre
std::string EnterName::getName() const
{
return name_;
}
// Obtiene la posición que se está editando
int EnterName::getPosition() const
{
return position_;
}
// Comprueba la posición y copia el caracter si es necesario
void EnterName::checkIfPositionHasBeenUsed()
{
auto used = position_has_been_used_[position_];
if (!used && position_ > 0)
character_index_[position_] = character_index_[position_ - 1];
position_has_been_used_[position_] = true;
updateName();
}

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <string> #include <string>
#include "utils.h"
constexpr int NAME_LENGHT = 6; constexpr int NAME_LENGHT = 6;
@@ -18,23 +19,19 @@ class EnterName
private: private:
std::string character_list_; // Lista de todos los caracteres permitidos std::string character_list_; // Lista de todos los caracteres permitidos
std::string name_; // Nombre introducido std::string name_; // Nombre introducido
int position_; // Posición a editar del nombre int position_ = 0; // Posición a editar del nombre
int num_characters_; // Cantidad de caracteres de la lista de caracteres bool position_overflow_ = false; // Indica si hemos incrementado la posición más allá del límite
int character_index_[NAME_LENGHT]; // Indice de la lista para cada uno de los caracteres que forman el nombre int character_index_[NAME_LENGHT]; // Indice de la lista para cada uno de los caracteres que forman el nombre
bool position_has_been_used_[NAME_LENGHT]; // Indica si en esa posición se ha puesto ya alguna letra. Se utiliza para replicar la letra anterior la primera vez
// Actualiza el nombre a partir de la lista de índices // Actualiza el nombre a partir de la lista de índices
void updateName(); void updateNameFromCharacterIndex();
// Actualiza la variable // Actualiza la variable
void updateCharacterIndex(); void initCharacterIndex(const std::string &name);
// Encuentra el indice de un caracter en "characterList" // Encuentra el indice de un caracter en "characterList"
int findIndex(char character) const; int findIndex(char character) const;
// Comprueba la posición y copia el caracter si es necesario
void checkIfPositionHasBeenUsed();
public: public:
// Constructor // Constructor
EnterName(); EnterName();
@@ -43,7 +40,7 @@ public:
~EnterName() = default; ~EnterName() = default;
// Inicializa el objeto // Inicializa el objeto
void init(); void init(const std::string &name = "");
// Incrementa la posición // Incrementa la posición
void incPosition(); void incPosition();
@@ -57,9 +54,9 @@ public:
// Decrementa el índice // Decrementa el índice
void decIndex(); void decIndex();
// Obtiene el nombre // Getters
std::string getName() const; std::string getFinalName() const { return trim(name_.substr(0, position_)); }
std::string getCurrentName() const { return trim(name_); }
// Obtiene la posición que se está editando int getPosition() const { return position_; }
int getPosition() const; bool getPositionOverflow() const { return position_overflow_; }
}; };

View File

@@ -1370,11 +1370,11 @@ void Game::pause(bool value)
} }
// Añade una puntuación a la tabla de records // Añade una puntuación a la tabla de records
void Game::addScoreToScoreBoard(const std::string &name, int score) void Game::addScoreToScoreBoard(const std::shared_ptr<Player> &player)
{ {
const auto entry = HiScoreEntry(trim(name), score); const auto entry = HiScoreEntry(trim(player->getRecordName()), player->getScore(), player->get1CC());
auto manager = std::make_unique<ManageHiScoreTable>(options.game.hi_score_table); auto manager = std::make_unique<ManageHiScoreTable>(options.game.hi_score_table);
manager->add(entry); options.game.last_hi_score_entry.at(player->getId() - 1) = manager->add(entry);
manager->saveToFile(asset_->get("score.bin")); manager->saveToFile(asset_->get("score.bin"));
hi_score_.name = options.game.hi_score_table.front().name; hi_score_.name = options.game.hi_score_table.front().name;
} }
@@ -1627,15 +1627,19 @@ void Game::handlePlayerContinue(const std::shared_ptr<Player> &player)
if (input_->checkInput(InputType::START, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index)) if (input_->checkInput(InputType::START, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index))
{ {
player->setPlayingState(PlayerState::PLAYING); player->setPlayingState(PlayerState::PLAYING);
player->addCredit();
} }
// Disminuye el contador de continuación si se presiona cualquier botón de disparo. // Disminuye el contador de continuación si se presiona cualquier botón de disparo.
if (input_->checkInput(InputType::FIRE_LEFT, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index) || if (input_->checkInput(InputType::FIRE_LEFT, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index) ||
input_->checkInput(InputType::FIRE_CENTER, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index) || input_->checkInput(InputType::FIRE_CENTER, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index) ||
input_->checkInput(InputType::FIRE_RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index)) input_->checkInput(InputType::FIRE_RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index))
{
if (player->getContinueCounter() < 7)
{ {
player->decContinueCounter(); player->decContinueCounter();
} }
}
} }
// Procesa las entradas para la introducción del nombre del jugador. // Procesa las entradas para la introducción del nombre del jugador.
@@ -1646,12 +1650,11 @@ void Game::handleNameInput(const std::shared_ptr<Player> &player)
input_->checkInput(InputType::FIRE_CENTER, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index) || input_->checkInput(InputType::FIRE_CENTER, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index) ||
input_->checkInput(InputType::FIRE_RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index)) input_->checkInput(InputType::FIRE_RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index))
{ {
if (player->getRecordNamePos() == NAME_LENGHT - 1) if (player->getEnterNamePositionOverflow())
{ {
player->setInput(InputType::START); player->setInput(InputType::START);
addScoreToScoreBoard(player->getRecordName(), player->getScore()); addScoreToScoreBoard(player);
const auto state = player->getPlayingState(); player->setPlayingState(PlayerState::SHOWING_NAME);
player->setPlayingState(state == PlayerState::ENTERING_NAME ? PlayerState::CONTINUE : PlayerState::LEAVING_SCREEN);
} }
else else
{ {
@@ -1673,9 +1676,8 @@ void Game::handleNameInput(const std::shared_ptr<Player> &player)
else if (input_->checkInput(InputType::START, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index)) else if (input_->checkInput(InputType::START, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index))
{ {
player->setInput(InputType::START); player->setInput(InputType::START);
addScoreToScoreBoard(player->getRecordName(), player->getScore()); addScoreToScoreBoard(player);
const auto state = player->getPlayingState(); player->setPlayingState(PlayerState::SHOWING_NAME);
player->setPlayingState(state == PlayerState::ENTERING_NAME ? PlayerState::CONTINUE : PlayerState::LEAVING_SCREEN);
} }
} }

View File

@@ -311,7 +311,7 @@ private:
void pause(bool value); void pause(bool value);
// Añade una puntuación a la tabla de records // Añade una puntuación a la tabla de records
void addScoreToScoreBoard(const std::string &name, int score); void addScoreToScoreBoard(const std::shared_ptr<Player> &player);
// Saca del estado de GAME OVER al jugador si el otro está activo // Saca del estado de GAME OVER al jugador si el otro está activo
void checkAndUpdatePlayerStatus(int active_player_index, int inactive_player_index); void checkAndUpdatePlayerStatus(int active_player_index, int inactive_player_index);

View File

@@ -44,6 +44,7 @@ HiScoreTable::HiScoreTable()
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
initFade(); initFade();
initBackground(); initBackground();
iniEntryColors();
createSprites(); createSprites();
} }
@@ -51,6 +52,7 @@ HiScoreTable::HiScoreTable()
HiScoreTable::~HiScoreTable() HiScoreTable::~HiScoreTable()
{ {
SDL_DestroyTexture(backbuffer_); SDL_DestroyTexture(backbuffer_);
options.game.clear_last_hi_score_entries();
} }
// Actualiza las variables // Actualiza las variables
@@ -258,7 +260,7 @@ std::string HiScoreTable::format(int number)
// Crea los sprites con los textos // Crea los sprites con los textos
void HiScoreTable::createSprites() void HiScoreTable::createSprites()
{ {
auto header_text = Resource::get()->getText("04b_25"); auto header_text = Resource::get()->getText("04b_25_grey");
auto entry_text = Resource::get()->getText("smb2"); auto entry_text = Resource::get()->getText("smb2");
// Obtiene el tamaño de la textura // Obtiene el tamaño de la textura
@@ -266,9 +268,9 @@ void HiScoreTable::createSprites()
int backbuffer_height; int backbuffer_height;
SDL_QueryTexture(backbuffer_, nullptr, nullptr, &backbuffer_width, &backbuffer_height); SDL_QueryTexture(backbuffer_, nullptr, nullptr, &backbuffer_width, &backbuffer_height);
// Hay 27 letras - 7 de puntos quedan 20 caracteres 20 - name_lenght 0 num_dots constexpr int entry_lenght = 22;
constexpr int max_names = 10; constexpr int max_names = 10;
constexpr int space_between_header = 32; const int space_between_header = entry_text->getCharacterSize() * 4;
const int space_between_lines = entry_text->getCharacterSize() * 2; const int space_between_lines = entry_text->getCharacterSize() * 2;
const int size = space_between_header + space_between_lines * (max_names - 1) + entry_text->getCharacterSize(); const int size = space_between_header + space_between_lines * (max_names - 1) + entry_text->getCharacterSize();
const int first_line = (param.game.height - size) / 2; const int first_line = (param.game.height - size) / 2;
@@ -279,45 +281,39 @@ void HiScoreTable::createSprites()
// Crea los sprites para las entradas en la tabla de puntuaciones // Crea los sprites para las entradas en la tabla de puntuaciones
const int animation = rand() % 4; const int animation = rand() % 4;
const std::string sample_line(entry_lenght + 3, ' ');
auto sample_entry = std::make_unique<Sprite>(entry_text->writeDXToTexture(TEXT_SHADOW, sample_line, 1, orange_color, 1, shdw_txt_color));
const auto entry_width = sample_entry->getWidth();
for (int i = 0; i < max_names; ++i) for (int i = 0; i < max_names; ++i)
{ {
const auto table_position = (i + 1 >= 10) ? format(i + 1) + ". " : " " + format(i + 1) + ". "; const auto table_position = format(i + 1) + ". ";
const auto score = format(options.game.hi_score_table.at(i).score); const auto score = format(options.game.hi_score_table.at(i).score);
const auto num_dots = 25 - table_position.size() - options.game.hi_score_table.at(i).name.size() - score.size(); const auto num_dots = entry_lenght - options.game.hi_score_table.at(i).name.size() - score.size();
const auto one_cc = options.game.hi_score_table.at(i).one_credit_complete ? " }" : "";
std::string dots; std::string dots;
for (int j = 0; j < (int)num_dots; ++j) for (int j = 0; j < (int)num_dots; ++j)
{ {
dots = dots + "."; dots = dots + ".";
} }
const auto line = table_position + options.game.hi_score_table.at(i).name + dots + score; const auto line = table_position + options.game.hi_score_table.at(i).name + dots + score + one_cc;
entry_names_.emplace_back(std::make_shared<PathSprite>(entry_text->writeDXToTexture(TEXT_SHADOW, line, 1, orange_color, 1, shdw_txt_color))); entry_names_.emplace_back(std::make_shared<PathSprite>(entry_text->writeDXToTexture(TEXT_SHADOW, line, 1, orange_color, 1, shdw_txt_color)));
const int default_pos_x = (backbuffer_width - entry_width) / 2;
const int pos_x = (i < 9) ? default_pos_x : default_pos_x - entry_text->getCharacterSize();
const int pos_y = (i * space_between_lines) + first_line + space_between_header;
constexpr int steps = 80;
switch (animation) switch (animation)
{ {
case 0: // Ambos lados alternativamente case 0: // Ambos lados alternativamente
{ {
if (i % 2 == 0) if (i % 2 == 0)
{ {
entry_names_.back()->addPath( entry_names_.back()->addPath(-entry_names_.back()->getWidth(), pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
-entry_names_.back()->getWidth(),
(backbuffer_width - entry_names_.back()->getWidth()) / 2,
PathType::HORIZONTAL,
(i * space_between_lines) + first_line + space_between_header,
80,
easeOutQuint,
0);
entry_names_.back()->setPosition(-entry_names_.back()->getWidth(), 0); entry_names_.back()->setPosition(-entry_names_.back()->getWidth(), 0);
} }
else else
{ {
entry_names_.back()->addPath( entry_names_.back()->addPath(backbuffer_width, pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
backbuffer_width,
(backbuffer_width - entry_names_.back()->getWidth()) / 2,
PathType::HORIZONTAL,
(i * space_between_lines) + first_line + space_between_header,
80,
easeOutQuint,
0);
entry_names_.back()->setPosition(backbuffer_width, 0); entry_names_.back()->setPosition(backbuffer_width, 0);
} }
break; break;
@@ -325,42 +321,21 @@ void HiScoreTable::createSprites()
case 1: // Entran por la izquierda case 1: // Entran por la izquierda
{ {
entry_names_.back()->addPath( entry_names_.back()->addPath(-entry_names_.back()->getWidth(), pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
-entry_names_.back()->getWidth(),
(backbuffer_width - entry_names_.back()->getWidth()) / 2,
PathType::HORIZONTAL,
(i * space_between_lines) + first_line + space_between_header,
80,
easeOutQuint,
0);
entry_names_.back()->setPosition(-entry_names_.back()->getWidth(), 0); entry_names_.back()->setPosition(-entry_names_.back()->getWidth(), 0);
break; break;
} }
case 2: // Entran por la derecha case 2: // Entran por la derecha
{ {
entry_names_.back()->addPath( entry_names_.back()->addPath(backbuffer_width, pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
backbuffer_width,
(backbuffer_width - entry_names_.back()->getWidth()) / 2,
PathType::HORIZONTAL,
(i * space_between_lines) + first_line + space_between_header,
80,
easeOutQuint,
0);
entry_names_.back()->setPosition(backbuffer_width, 0); entry_names_.back()->setPosition(backbuffer_width, 0);
break; break;
} }
case 3: // Entran desde la parte inferior case 3: // Entran desde la parte inferior
{ {
entry_names_.back()->addPath( entry_names_.back()->addPath(backbuffer_height, pos_y, PathType::VERTICAL, pos_x, steps, easeOutQuint);
backbuffer_height,
(i * space_between_lines) + first_line + space_between_header,
PathType::VERTICAL,
(backbuffer_width - entry_names_.back()->getWidth()) / 2,
80,
easeOutQuint,
0);
entry_names_.back()->setPosition(0, backbuffer_height); entry_names_.back()->setPosition(0, backbuffer_height);
} }
@@ -391,6 +366,8 @@ void HiScoreTable::updateSprites()
{ {
entry->update(); entry->update();
} }
glowEntryNames();
} }
// Inicializa el fade // Inicializa el fade
@@ -410,7 +387,6 @@ void HiScoreTable::initBackground()
background_->setCloudsSpeed(-0.1f); background_->setCloudsSpeed(-0.1f);
const int lucky = rand() % 3; const int lucky = rand() % 3;
//const int lucky = 2;
switch (lucky) switch (lucky)
{ {
case 0: // Fondo verde case 0: // Fondo verde
@@ -418,8 +394,8 @@ void HiScoreTable::initBackground()
background_->setGradientNumber(2); background_->setGradientNumber(2);
background_->setTransition(0.0f); background_->setTransition(0.0f);
background_->setSunProgression(1.0f); background_->setSunProgression(1.0f);
background_->setMoonProgression(0.4f); background_->setMoonProgression(0.0f);
background_fade_color_ = Color(0x00, 0x79, 0x6b); background_fade_color_ = green_sky_color;
break; break;
} }
@@ -429,7 +405,7 @@ void HiScoreTable::initBackground()
background_->setTransition(0.0f); background_->setTransition(0.0f);
background_->setSunProgression(0.65f); background_->setSunProgression(0.65f);
background_->setMoonProgression(0.0f); background_->setMoonProgression(0.0f);
background_fade_color_ = Color(0xff, 0x6b, 0x97); background_fade_color_ = pink_sky_color;
break; break;
} }
@@ -439,7 +415,7 @@ void HiScoreTable::initBackground()
background_->setTransition(0.0f); background_->setTransition(0.0f);
background_->setSunProgression(0.0f); background_->setSunProgression(0.0f);
background_->setMoonProgression(0.0f); background_->setMoonProgression(0.0f);
background_fade_color_ = Color(0x02, 0x88, 0xd1); background_fade_color_ = blue_sky_color;
break; break;
} }
@@ -447,3 +423,45 @@ void HiScoreTable::initBackground()
break; break;
} }
} }
// Obtiene un color del vector de colores de entradas
Color HiScoreTable::getEntryColor(int counter_)
{
int cycle_length = entry_colors_.size() * 2 - 2;
size_t n = counter_ % cycle_length;
size_t index;
if (n < entry_colors_.size())
{
index = n; // Avanza: 0,1,2,3
}
else
{
index = 2 * (entry_colors_.size() - 1) - n; // Retrocede: 2,1
}
return entry_colors_[index];
}
// Inicializa los colores de las entradas
void HiScoreTable::iniEntryColors()
{
entry_colors_.clear();
entry_colors_.emplace_back(background_fade_color_.getInverse().lighten(75));
entry_colors_.emplace_back(background_fade_color_.getInverse().lighten(50));
entry_colors_.emplace_back(background_fade_color_.getInverse().lighten(25));
entry_colors_.emplace_back(background_fade_color_.getInverse());
}
// Hace brillar los nombres de la tabla de records
void HiScoreTable::glowEntryNames()
{
const Color entry_color = getEntryColor(counter_ / 5);
for (const auto& entry_index : options.game.last_hi_score_entry)
{
if (entry_index != -1)
{
entry_names_.at(entry_index)->getTexture()->setColor(entry_color);
}
}
}

View File

@@ -47,6 +47,7 @@ private:
SDL_Rect view_area_; // Parte de la textura que se muestra en pantalla SDL_Rect view_area_; // Parte de la textura que se muestra en pantalla
FadeMode fade_mode_; // Modo de fade a utilizar FadeMode fade_mode_; // Modo de fade a utilizar
Color background_fade_color_; // Color de atenuación del fondo Color background_fade_color_; // Color de atenuación del fondo
std::vector<Color> entry_colors_; // Colores para destacar las entradas en la tabla
// Actualiza las variables // Actualiza las variables
void update(); void update();
@@ -84,6 +85,15 @@ private:
// Inicializa el fondo // Inicializa el fondo
void initBackground(); void initBackground();
// Obtiene un color del vector de colores de entradas
Color getEntryColor(int counter_);
// Inicializa los colores de las entradas
void iniEntryColors();
// Hace brillar los nombres de la tabla de records
void glowEntryNames();
public: public:
// Constructor // Constructor
HiScoreTable(); HiScoreTable();

View File

@@ -110,9 +110,11 @@ bool Input::checkInput(InputType input, bool repeat, InputDeviceToUse device, in
} }
if (gameControllerFound() && controller_index >= 0 && controller_index < num_gamepads_) if (gameControllerFound() && controller_index >= 0 && controller_index < num_gamepads_)
{
if ((device == InputDeviceToUse::CONTROLLER) || (device == InputDeviceToUse::ANY)) if ((device == InputDeviceToUse::CONTROLLER) || (device == InputDeviceToUse::ANY))
{ {
success_controller = checkAxisInput(input, controller_index); success_controller = checkAxisInput(input, controller_index, repeat);
if (!success_controller) if (!success_controller)
{ {
if (repeat) if (repeat)
@@ -144,6 +146,7 @@ bool Input::checkInput(InputType input, bool repeat, InputDeviceToUse device, in
} }
} }
} }
}
return (success_keyboard || success_controller); return (success_keyboard || success_controller);
} }
@@ -379,19 +382,53 @@ InputType Input::to_inputs_e(const std::string &name) const
} }
// Comprueba el eje del mando // Comprueba el eje del mando
bool Input::checkAxisInput(InputType input, int controller_index) const bool Input::checkAxisInput(InputType input, int controller_index, bool repeat)
{ {
// Umbral para considerar el eje como activo
const Sint16 threshold = 30000;
bool axis_active_now = false;
switch (input) switch (input)
{ {
case InputType::LEFT: case InputType::LEFT:
return SDL_GameControllerGetAxis(connected_controllers_[controller_index], SDL_CONTROLLER_AXIS_LEFTX) < -30000; axis_active_now = SDL_GameControllerGetAxis(connected_controllers_[controller_index], SDL_CONTROLLER_AXIS_LEFTX) < -threshold;
break;
case InputType::RIGHT: case InputType::RIGHT:
return SDL_GameControllerGetAxis(connected_controllers_[controller_index], SDL_CONTROLLER_AXIS_LEFTX) > 30000; axis_active_now = SDL_GameControllerGetAxis(connected_controllers_[controller_index], SDL_CONTROLLER_AXIS_LEFTX) > threshold;
break;
case InputType::UP: case InputType::UP:
return SDL_GameControllerGetAxis(connected_controllers_[controller_index], SDL_CONTROLLER_AXIS_LEFTY) < -30000; axis_active_now = SDL_GameControllerGetAxis(connected_controllers_[controller_index], SDL_CONTROLLER_AXIS_LEFTY) < -threshold;
break;
case InputType::DOWN: case InputType::DOWN:
return SDL_GameControllerGetAxis(connected_controllers_[controller_index], SDL_CONTROLLER_AXIS_LEFTY) > 30000; axis_active_now = SDL_GameControllerGetAxis(connected_controllers_[controller_index], SDL_CONTROLLER_AXIS_LEFTY) > threshold;
break;
default: default:
return false; return false;
} }
// Referencia al binding correspondiente
auto &binding = controller_bindings_.at(controller_index).at(static_cast<int>(input));
if (repeat)
{
// Si se permite repetir, simplemente devolvemos el estado actual
return axis_active_now;
}
else
{
// Si no se permite repetir, aplicamos la lógica de transición
if (axis_active_now && !binding.axis_active)
{
// Transición de inactivo a activo
binding.axis_active = true;
return true;
}
else if (!axis_active_now && binding.axis_active)
{
// Transición de activo a inactivo
binding.axis_active = false;
}
// Mantener el estado actual
return false;
}
} }

View File

@@ -81,10 +81,11 @@ private:
{ {
SDL_GameControllerButton button; // GameControllerButton asociado SDL_GameControllerButton button; // GameControllerButton asociado
bool active; // Indica si está activo bool active; // Indica si está activo
bool axis_active; // Estado del eje
// Constructor // Constructor
explicit ControllerBindings(SDL_GameControllerButton btn = SDL_CONTROLLER_BUTTON_INVALID, bool act = false) explicit ControllerBindings(SDL_GameControllerButton btn = SDL_CONTROLLER_BUTTON_INVALID, bool act = false, bool axis_act = false)
: button(btn), active(act) {} : button(btn), active(act), axis_active(axis_act) {}
}; };
// Variables // Variables
@@ -99,7 +100,7 @@ private:
std::string game_controller_db_path_; // Ruta al archivo gamecontrollerdb.txt std::string game_controller_db_path_; // Ruta al archivo gamecontrollerdb.txt
// Comprueba el eje del mando // Comprueba el eje del mando
bool checkAxisInput(InputType input, int controller_index = 0) const; bool checkAxisInput(InputType input, int controller_index, bool repeat);
// Constructor // Constructor
explicit Input(const std::string &game_controller_db_path); explicit Input(const std::string &game_controller_db_path);

View File

@@ -21,7 +21,7 @@
// Constructor // Constructor
Intro::Intro() Intro::Intro()
: texture_(Resource::get()->getTexture("intro.png")), : texture_(Resource::get()->getTexture("intro.png")),
text_(Resource::get()->getText("04b_25_var01")) text_(Resource::get()->getText("04b_25_metal"))
{ {
// Inicializa variables // Inicializa variables

View File

@@ -27,7 +27,7 @@ void ManageHiScoreTable::clear()
} }
// Añade un elemento a la tabla // Añade un elemento a la tabla
void ManageHiScoreTable::add(HiScoreEntry entry) int ManageHiScoreTable::add(const HiScoreEntry &entry)
{ {
// Añade la entrada a la tabla // Añade la entrada a la tabla
table_.push_back(entry); table_.push_back(entry);
@@ -35,8 +35,32 @@ void ManageHiScoreTable::add(HiScoreEntry entry)
// Ordena la tabla // Ordena la tabla
sort(); sort();
// Encontrar la posición del nuevo elemento
auto it = std::find_if(table_.begin(), table_.end(), [&](const HiScoreEntry &e)
{ return e.name == entry.name &&
e.score == entry.score &&
e.one_credit_complete == entry.one_credit_complete; });
int position = -1;
if (it != table_.end())
{
position = std::distance(table_.begin(), it);
}
// Deja solo las 10 primeras entradas // Deja solo las 10 primeras entradas
if (table_.size() > 10)
{
table_.resize(10); table_.resize(10);
// Si el nuevo elemento quedó fuera del top 10
if (position >= 10)
{
position = -1; // No entró en el top 10
}
}
// Devuelve la posición
return position;
} }
// Ordena la tabla // Ordena la tabla
@@ -50,52 +74,55 @@ void ManageHiScoreTable::sort()
std::sort(table_.begin(), table_.end(), scoreDescendingComparator); std::sort(table_.begin(), table_.end(), scoreDescendingComparator);
} }
// Carga la tabla con los datos de un fichero // Carga la tabla desde un fichero
bool ManageHiScoreTable::loadFromFile(const std::string &file_path) bool ManageHiScoreTable::loadFromFile(const std::string &file_path)
{ {
clear(); clear();
auto success = true; auto success = true;
auto file = SDL_RWFromFile(file_path.c_str(), "r+b"); auto file = SDL_RWFromFile(file_path.c_str(), "rb");
if (file) if (file)
{ {
std::cout << "Reading file: " << getFileName(file_path) << std::endl; table_.clear(); // Limpia la tabla actual
for (auto &entry : table_) // Lee el número de entradas en la tabla
int tableSize = 0;
SDL_RWread(file, &tableSize, sizeof(int), 1);
// Lee los datos de cada entrada
for (int i = 0; i < tableSize; ++i)
{ {
HiScoreEntry entry;
// Lee la puntuación
SDL_RWread(file, &entry.score, sizeof(int), 1);
// Lee el tamaño del nombre y luego el nombre
int nameSize = 0; int nameSize = 0;
SDL_RWread(file, &nameSize, sizeof(int), 1);
if (SDL_RWread(file, &entry.score, sizeof(int), 1) == 0)
{
success = false;
break;
}
if (SDL_RWread(file, &nameSize, sizeof(int), 1) == 0)
{
success = false;
break;
}
std::vector<char> nameBuffer(nameSize + 1); std::vector<char> nameBuffer(nameSize + 1);
if (SDL_RWread(file, nameBuffer.data(), sizeof(char) * nameSize, 1) == 0) SDL_RWread(file, nameBuffer.data(), nameSize, 1);
{ nameBuffer[nameSize] = '\0'; // Asegurar el fin de la cadena
success = false;
break;
}
nameBuffer[nameSize] = '\0';
entry.name = std::string(nameBuffer.data()); entry.name = std::string(nameBuffer.data());
// Lee el valor de one_credit_complete
int occValue = 0;
SDL_RWread(file, &occValue, sizeof(int), 1);
entry.one_credit_complete = (occValue != 0);
// Añade la entrada a la tabla
table_.push_back(entry);
} }
std::cout << "Reading file: " << getFileName(file_path) << std::endl;
SDL_RWclose(file); SDL_RWclose(file);
} }
else
if (!success)
{ {
clear(); std::cout << "Error: Unable to load " << getFileName(file_path) << " file! " << SDL_GetError() << std::endl;
success = false;
} }
return success; return success;
} }
@@ -107,21 +134,35 @@ bool ManageHiScoreTable::saveToFile(const std::string &file_path)
if (file) if (file)
{ {
// Guarda los datos // Guarda el número de entradas en la tabla
for (int i = 0; i < (int)table_.size(); ++i) int tableSize = static_cast<int>(table_.size());
SDL_RWwrite(file, &tableSize, sizeof(int), 1);
// Guarda los datos de cada entrada
for (int i = 0; i < tableSize; ++i)
{ {
SDL_RWwrite(file, &table_.at(i).score, sizeof(int), 1); const HiScoreEntry &entry = table_.at(i);
const int nameSize = (int)table_.at(i).name.size();
// Guarda la puntuación
SDL_RWwrite(file, &entry.score, sizeof(int), 1);
// Guarda el tamaño del nombre y luego el nombre
int nameSize = static_cast<int>(entry.name.size());
SDL_RWwrite(file, &nameSize, sizeof(int), 1); SDL_RWwrite(file, &nameSize, sizeof(int), 1);
SDL_RWwrite(file, table_.at(i).name.c_str(), nameSize, 1); SDL_RWwrite(file, entry.name.c_str(), nameSize, 1);
// Guarda el valor de one_credit_complete como un entero (0 o 1)
int occValue = entry.one_credit_complete ? 1 : 0;
SDL_RWwrite(file, &occValue, sizeof(int), 1);
} }
std::cout << "Writing file: " << getFileName(file_path).c_str() << std::endl; std::cout << "Writing file: " << getFileName(file_path) << std::endl;
SDL_RWclose(file); SDL_RWclose(file);
} }
else else
{ {
std::cout << "Error: Unable to save " << getFileName(file_path).c_str() << " file! " << SDL_GetError() << std::endl; std::cout << "Error: Unable to save " << getFileName(file_path) << " file! " << SDL_GetError() << std::endl;
success = false;
} }
return success; return success;
} }

View File

@@ -16,10 +16,11 @@ struct HiScoreEntry
{ {
std::string name; // Nombre std::string name; // Nombre
int score; // Puntuación int score; // Puntuación
bool one_credit_complete; // Indica si se ha conseguido 1CC
// Constructor // Constructor
explicit HiScoreEntry(const std::string &n = "", int s = 0) explicit HiScoreEntry(const std::string &n = "", int s = 0, bool occ = false)
: name(n), score(s) {} : name(n.substr(0, 6)), score(s), one_credit_complete(occ) {}
}; };
// Clase ManageHiScoreTable // Clase ManageHiScoreTable
@@ -44,7 +45,7 @@ public:
void clear(); void clear();
// Añade un elemento a la tabla // Añade un elemento a la tabla
void add(HiScoreEntry entry); int add(const HiScoreEntry& entry);
// Carga la tabla con los datos de un fichero // Carga la tabla con los datos de un fichero
bool loadFromFile(const std::string &file_path); bool loadFromFile(const std::string &file_path);

View File

@@ -44,6 +44,7 @@ void initOptions()
options.game.difficulty = GameDifficulty::NORMAL; options.game.difficulty = GameDifficulty::NORMAL;
options.game.language = lang::Code::ba_BA; options.game.language = lang::Code::ba_BA;
options.game.autofire = true; options.game.autofire = true;
options.game.clear_last_hi_score_entries();
// Opciones de control // Opciones de control
options.controllers.clear(); options.controllers.clear();

View File

@@ -66,8 +66,16 @@ struct OptionsGame
{ {
GameDifficulty difficulty; // Dificultad del juego GameDifficulty difficulty; // Dificultad del juego
lang::Code language; // Idioma usado en el juego lang::Code language; // Idioma usado en el juego
bool autofire; // Indica si el jugador ha de pulsar repetidamente para disparar o basta con mantener pulsado bool autofire; // Indicador de autofire
std::vector<HiScoreEntry> hi_score_table; // Tabla con las mejores puntuaciones std::vector<HiScoreEntry> hi_score_table; // Tabla de mejores puntuaciones
std::vector<int> last_hi_score_entry = { -1, -1 }; // Inicialización directa con dos elementos en -1
// Método para reiniciar las últimas entradas de puntuación
void clear_last_hi_score_entries()
{
last_hi_score_entry[0] = -1;
last_hi_score_entry[1] = -1;
}
}; };
// Estructura para los controles del juego // Estructura para los controles del juego

View File

@@ -65,8 +65,8 @@ public:
// Añade un recorrido // Añade un recorrido
void addPath(Path path, bool centered = false); void addPath(Path path, bool centered = false);
void addPath(std::vector<SDL_Point> spots, int waiting_counter); void addPath(std::vector<SDL_Point> spots, int waiting_counter = 0);
void addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easingFunction, int waiting_counter); void addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easingFunction, int waiting_counter = 0);
// Habilita el objeto // Habilita el objeto
void enable(); void enable();

View File

@@ -58,7 +58,7 @@ void Player::init()
score_ = 0; score_ = 0;
score_multiplier_ = 1.0f; score_multiplier_ = 1.0f;
cool_down_ = 10; cool_down_ = 10;
enter_name_->init(); enter_name_->init(last_enter_name_);
// Establece la posición del sprite // Establece la posición del sprite
player_sprite_->clear(); player_sprite_->clear();
@@ -148,6 +148,7 @@ void Player::setInputEnteringName(InputType input)
enter_name_->decIndex(); enter_name_->decIndex();
break; break;
case InputType::START: case InputType::START:
last_enter_name_ = getRecordName();
break; break;
default: default:
break; break;
@@ -449,6 +450,7 @@ void Player::update()
updateInvulnerable(); updateInvulnerable();
updateContinueCounter(); updateContinueCounter();
updateEnterNameCounter(); updateEnterNameCounter();
updateShowingName();
updateScoreboard(); updateScoreboard();
} }
@@ -474,7 +476,7 @@ void Player::updateScoreboard()
case PlayerState::ENTERING_NAME: case PlayerState::ENTERING_NAME:
case PlayerState::ENTERING_NAME_GAME_COMPLETED: case PlayerState::ENTERING_NAME_GAME_COMPLETED:
{ {
Scoreboard::get()->setRecordName(getScoreBoardPanel(), enter_name_->getName()); Scoreboard::get()->setRecordName(getScoreBoardPanel(), enter_name_->getCurrentName());
Scoreboard::get()->setSelectorPos(getScoreBoardPanel(), getRecordNamePos()); Scoreboard::get()->setSelectorPos(getScoreBoardPanel(), getRecordNamePos());
break; break;
} }
@@ -525,12 +527,19 @@ void Player::setPlayingState(PlayerState state)
setScoreboardMode(ScoreboardMode::ENTER_NAME); setScoreboardMode(ScoreboardMode::ENTER_NAME);
break; break;
} }
case PlayerState::SHOWING_NAME:
{
showing_name_ticks_ = SDL_GetTicks();
setScoreboardMode(ScoreboardMode::SHOW_NAME);
Scoreboard::get()->setRecordName(scoreboard_panel_, last_enter_name_);
break;
}
case PlayerState::DYING: case PlayerState::DYING:
{ {
// Activa la animación de morir // Activa la animación de morir
player_sprite_->setAccelY(0.2f); player_sprite_->setAccelY(0.2f);
player_sprite_->setVelY(-6.6f); player_sprite_->setVelY(-6.6f);
rand() % 2 == 0 ? player_sprite_->setVelX(3.3f) : player_sprite_->setVelX(-3.3f); (rand() % 2 == 0) ? player_sprite_->setVelX(3.3f) : player_sprite_->setVelX(-3.3f);
break; break;
} }
case PlayerState::DIED: case PlayerState::DIED:
@@ -546,6 +555,7 @@ void Player::setPlayingState(PlayerState state)
} }
case PlayerState::CELEBRATING: case PlayerState::CELEBRATING:
{ {
game_completed_ = true;
setScoreboardMode(ScoreboardMode::SCORE); setScoreboardMode(ScoreboardMode::SCORE);
break; break;
} }
@@ -711,6 +721,19 @@ void Player::updateEnterNameCounter()
} }
} }
// Actualiza el estado de SHOWING_NAME
void Player::updateShowingName()
{
if (playing_state_ == PlayerState::SHOWING_NAME)
{
constexpr int TICKS_SPEED = 5000;
if (SDL_GetTicks() - enter_name_ticks_ > TICKS_SPEED)
{
game_completed_ ? setPlayingState(PlayerState::LEAVING_SCREEN) : setPlayingState(PlayerState::CONTINUE);
}
}
}
// Decrementa el contador de continuar // Decrementa el contador de continuar
void Player::decContinueCounter() void Player::decContinueCounter()
{ {

View File

@@ -34,6 +34,7 @@ enum class PlayerState
CONTINUE, // Está con la cuenta atras para continuar CONTINUE, // Está con la cuenta atras para continuar
WAITING, // No está jugando pero puede entrar a jugar WAITING, // No está jugando pero puede entrar a jugar
ENTERING_NAME, // Introduciendo nombre ENTERING_NAME, // Introduciendo nombre
SHOWING_NAME, // Mostrando el nombre introducido
DYING, // El cadaver está volando por ahi DYING, // El cadaver está volando por ahi
DIED, // El cadaver ha desaparecido por el fondo DIED, // El cadaver ha desaparecido por el fondo
GAME_OVER, // No está jugando y no puede entrar a jugar GAME_OVER, // No está jugando y no puede entrar a jugar
@@ -92,7 +93,11 @@ private:
bool demo_; // Para que el jugador sepa si está en el modo demostración bool demo_; // Para que el jugador sepa si está en el modo demostración
int enter_name_counter_; // Contador para poner nombre int enter_name_counter_; // Contador para poner nombre
Uint32 enter_name_ticks_ = 0; // Variable para poder cambiar el contador de poner nombre en función del tiempo Uint32 enter_name_ticks_ = 0; // Variable para poder cambiar el contador de poner nombre en función del tiempo
Uint32 showing_name_ticks_ = 0; // Tiempo en el que se entra al estado SHOWING_NAME
int step_counter_ = 0; // Cuenta los pasos para los estados en los que camina automáticamente int step_counter_ = 0; // Cuenta los pasos para los estados en los que camina automáticamente
bool game_completed_ = false; // Indica si ha completado el juego
int credits_used_ = 1; // Indica el numero de veces que ha continuado
std::string last_enter_name_; // Ultimo nombre introducido en la tabla de puntuaciones
// Actualiza el circulo de colisión a la posición del jugador // Actualiza el circulo de colisión a la posición del jugador
void shiftColliders(); void shiftColliders();
@@ -109,6 +114,9 @@ private:
// Actualiza el contador de entrar nombre // Actualiza el contador de entrar nombre
void updateEnterNameCounter(); void updateEnterNameCounter();
// Actualiza el estado de SHOWING_NAME
void updateShowingName();
// Decrementa el contador de entrar nombre // Decrementa el contador de entrar nombre
void decEnterNameCounter(); void decEnterNameCounter();
@@ -224,12 +232,14 @@ public:
int getPosX() const { return static_cast<int>(pos_x_); } int getPosX() const { return static_cast<int>(pos_x_); }
int getPosY() const { return pos_y_; } int getPosY() const { return pos_y_; }
int getPowerUpCounter() const { return power_up_counter_; } int getPowerUpCounter() const { return power_up_counter_; }
std::string getRecordName() const { return enter_name_->getName(); } std::string getRecordName() const { return enter_name_->getFinalName(); }
int getScore() const { return score_; } int getScore() const { return score_; }
int getScoreBoardPanel() const { return scoreboard_panel_; } int getScoreBoardPanel() const { return scoreboard_panel_; }
int getWidth() const { return WIDTH_; } int getWidth() const { return WIDTH_; }
PlayerState getPlayingState() const { return playing_state_; } PlayerState getPlayingState() const { return playing_state_; }
std::string getName() const { return name_; } std::string getName() const { return name_; }
bool get1CC() const { return game_completed_ && credits_used_ == 1; }
bool getEnterNamePositionOverflow() const { return enter_name_->getPositionOverflow(); }
// Setters // Setters
void setController(int index) { controller_index_ = index; } void setController(int index) { controller_index_ = index; }
@@ -242,4 +252,5 @@ public:
void setScoreBoardPanel(int panel) { scoreboard_panel_ = panel; } void setScoreBoardPanel(int panel) { scoreboard_panel_ = panel; }
void setScoreMultiplier(float value) { score_multiplier_ = value; } void setScoreMultiplier(float value) { score_multiplier_ = value; }
void setWalkingState(PlayerState state) { walking_state_ = state; } void setWalkingState(PlayerState state) { walking_state_ = state; }
void addCredit() { ++credits_used_; }
}; };

View File

@@ -315,23 +315,35 @@ void Resource::createTextures()
} }
} }
// Crea los objetos de texto
void Resource::createText() void Resource::createText()
{ {
struct ResourceInfo
{
std::string key; // Identificador del recurso
std::string textureFile; // Nombre del archivo de textura
std::string textFile; // Nombre del archivo de texto
// Constructor para facilitar la creación de objetos ResourceInfo
ResourceInfo(const std::string &k, const std::string &tFile, const std::string &txtFile)
: key(k), textureFile(tFile), textFile(txtFile) {}
};
std::cout << "\n>> CREATING TEXT_OBJECTS" << std::endl; std::cout << "\n>> CREATING TEXT_OBJECTS" << std::endl;
std::vector<std::pair<std::string, std::string>> resources = { std::vector<ResourceInfo> resources = {
{"04b_25", "04b_25.png"}, {"04b_25", "04b_25.png", "04b_25.txt"},
{"04b_25_2x", "04b_25_2x.png"}, {"04b_25_2x", "04b_25_2x.png", "04b_25_2x.txt"},
{"04b_25_var01", "04b_25_var01.png"}, {"04b_25_metal", "04b_25_metal.png", "04b_25.txt"},
{"8bithud", "8bithud.png"}, {"04b_25_grey", "04b_25_grey.png", "04b_25.txt"},
{"nokia", "nokia.png"}, {"8bithud", "8bithud.png", "8bithud.txt"},
{"smb2", "smb2.gif"}}; {"smb2", "smb2.gif", "smb2.txt"}};
for (const auto &resource : resources) for (const auto &resource : resources)
{ {
texts_.emplace_back(ResourceText(resource.first, std::make_shared<Text>(getTexture(resource.second), getTextFile(resource.first + ".txt")))); texts_.emplace_back(ResourceText(resource.key, std::make_shared<Text>(
printWithDots("Text : ", resource.first, "[ DONE ]"); getTexture(resource.textureFile),
getTextFile(resource.textFile))));
printWithDots("Text : ", resource.key, "[ DONE ]");
} }
} }

View File

@@ -10,7 +10,8 @@
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "text.h" // Para Text #include "text.h" // Para Text
#include "enter_name.h" #include "enter_name.h" // Para NAME_LENGHT
#include <iostream>
// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado // [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado
Scoreboard *Scoreboard::scoreboard_ = nullptr; Scoreboard *Scoreboard::scoreboard_ = nullptr;
@@ -68,6 +69,9 @@ Scoreboard::Scoreboard()
// Rellena la textura de fondo // Rellena la textura de fondo
fillBackgroundTexture(); fillBackgroundTexture();
// Inicializa el vector de colores para el nombre
iniNameColors();
} }
Scoreboard::~Scoreboard() Scoreboard::~Scoreboard()
@@ -86,23 +90,23 @@ Scoreboard::~Scoreboard()
} }
} }
// Transforma un valor numérico en una cadena de 6 cifras // Transforma un valor numérico en una cadena de 7 cifras
std::string Scoreboard::updateScoreText(int num) std::string Scoreboard::updateScoreText(int num)
{ {
std::ostringstream oss; std::ostringstream oss;
oss << std::setw(8) << std::setfill('0') << num; oss << std::setw(7) << std::setfill('0') << num;
return oss.str(); return oss.str();
} }
// Actualiza el contador // Actualiza el contador
void Scoreboard::updateCounter() void Scoreboard::updateTimeCounter()
{ {
constexpr int TICKS_SPEED = 100; constexpr int TICKS_SPEED = 100;
if (SDL_GetTicks() - ticks_ > TICKS_SPEED) if (SDL_GetTicks() - ticks_ > TICKS_SPEED)
{ {
ticks_ = SDL_GetTicks(); ticks_ = SDL_GetTicks();
counter_++; ++time_counter_;
} }
} }
@@ -110,7 +114,8 @@ void Scoreboard::updateCounter()
void Scoreboard::update() void Scoreboard::update()
{ {
fillBackgroundTexture(); fillBackgroundTexture();
updateCounter(); updateTimeCounter();
++loop_counter_;
} }
// Pinta el marcador // Pinta el marcador
@@ -150,7 +155,7 @@ void Scoreboard::fillPanelTextures()
// Guarda a donde apunta actualmente el renderizador // Guarda a donde apunta actualmente el renderizador
auto temp = SDL_GetRenderTarget(renderer_); auto temp = SDL_GetRenderTarget(renderer_);
// Genera el contenidoi de cada panel_ // Genera el contenido de cada panel_
for (size_t i = 0; i < SCOREBOARD_MAX_PANELS; ++i) for (size_t i = 0; i < SCOREBOARD_MAX_PANELS; ++i)
{ {
// Cambia el destino del renderizador // Cambia el destino del renderizador
@@ -180,7 +185,7 @@ void Scoreboard::fillPanelTextures()
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y + 4, lang::getText(101)); text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y + 4, lang::getText(101));
// PRESS START TO PLAY // PRESS START TO PLAY
if (counter_ % 10 < 8) if (time_counter_ % 10 < 8)
{ {
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y - 2, lang::getText(103)); 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)); text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y - 2, lang::getText(104));
@@ -194,7 +199,7 @@ void Scoreboard::fillPanelTextures()
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y + 4, lang::getText(102)); text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y + 4, lang::getText(102));
// PRESS START TO PLAY // PRESS START TO PLAY
if (counter_ % 10 < 8) if (time_counter_ % 10 < 8)
{ {
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y - 2, lang::getText(103)); 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)); text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y - 2, lang::getText(104));
@@ -208,7 +213,7 @@ void Scoreboard::fillPanelTextures()
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y + 4, lang::getText(102)); text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y + 4, lang::getText(102));
// PLEASE WAIT // PLEASE WAIT
if (counter_ % 10 < 8) if (time_counter_ % 10 < 8)
{ {
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y - 2, lang::getText(114)); 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)); text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y - 2, lang::getText(115));
@@ -253,18 +258,45 @@ void Scoreboard::fillPanelTextures()
text_scoreboard_->writeCentered(slot4_2_.x, slot4_2_.y, updateScoreText(score_[i])); text_scoreboard_->writeCentered(slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]));
// ENTER NAME // ENTER NAME
{
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y, lang::getText(106)); 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_Rect rect = {enter_name_pos_.x, enter_name_pos_.y, 5, 7};
SDL_SetRenderDrawColor(renderer_, 0xFF, 0xFF, 0xEB, 255);
for (size_t j = 0; j < record_name_[i].size(); ++j) // Recorre todos los slots de letras del nombre
for (size_t j = 0; j < NAME_LENGHT; ++j)
{ {
if (j != selector_pos_[i] || counter_ % 3 == 0) // 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_RenderDrawLine(renderer_, rect.x, rect.y + rect.h, rect.x + rect.w, rect.y + rect.h); 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)); }
// 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; 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));
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y, record_name_[i], 1, getColorLikeKnightRider(name_colors_, loop_counter_ / 5));
break; break;
} }
case ScoreboardMode::GAME_COMPLETED: case ScoreboardMode::GAME_COMPLETED:
@@ -273,7 +305,7 @@ void Scoreboard::fillPanelTextures()
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y + 4, lang::getText(102)); text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y + 4, lang::getText(102));
// SCORE // SCORE
if (counter_ % 10 < 8) if (time_counter_ % 10 < 8)
{ {
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y - 2, lang::getText(120)); 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])); text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y - 2, updateScoreText(score_[i]));
@@ -319,27 +351,27 @@ void Scoreboard::fillBackgroundTexture()
void Scoreboard::recalculateAnchors() void Scoreboard::recalculateAnchors()
{ {
// Recalcula la posición y el tamaño de los paneles // Recalcula la posición y el tamaño de los paneles
const float panelWidth = (float)rect_.w / (float)SCOREBOARD_MAX_PANELS; const float panel_width = (float)rect_.w / (float)SCOREBOARD_MAX_PANELS;
for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i) for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i)
{ {
panel_[i].pos.x = roundf(panelWidth * i); panel_[i].pos.x = roundf(panel_width * i);
panel_[i].pos.y = 0; panel_[i].pos.y = 0;
panel_[i].pos.w = roundf(panelWidth * (i + 1)) - panel_[i].pos.x; panel_[i].pos.w = roundf(panel_width * (i + 1)) - panel_[i].pos.x;
panel_[i].pos.h = rect_.h; panel_[i].pos.h = rect_.h;
} }
// Constantes para definir las zonas del panel_: 4 filas y 1 columna // Constantes para definir las zonas del panel_: 4 filas y 1 columna
const int rowSize = rect_.h / 4; const int row_size = rect_.h / 4;
const int textHeight = 7; const int text_height = 7;
// Filas // Filas
const int row1 = (rowSize * 0) + (textHeight / 2); const int row1 = (row_size * 0) + (text_height / 2);
const int row2 = (rowSize * 1) + (textHeight / 2) - 1; const int row2 = (row_size * 1) + (text_height / 2) - 1;
const int row3 = (rowSize * 2) + (textHeight / 2) - 2; const int row3 = (row_size * 2) + (text_height / 2) - 2;
const int row4 = (rowSize * 3) + (textHeight / 2) - 3; const int row4 = (row_size * 3) + (text_height / 2) - 3;
// Columna // Columna
const int col = panelWidth / 2; const int col = panel_width / 2;
// Slots de 4 // Slots de 4
slot4_1_ = {col, row1}; slot4_1_ = {col, row1};
@@ -348,8 +380,8 @@ void Scoreboard::recalculateAnchors()
slot4_4_ = {col, row4}; slot4_4_ = {col, row4};
// Primer cuadrado para poner el nombre de record // Primer cuadrado para poner el nombre de record
const int enterNameLenght = NAME_LENGHT * 7; const int enter_name_lenght = text_scoreboard_->lenght(std::string(NAME_LENGHT, 'A'));
enter_name_pos_.x = (panelWidth - enterNameLenght) / 2; enter_name_pos_.x = col - (enter_name_lenght / 2);
enter_name_pos_.y = row4; enter_name_pos_.y = row4;
// Recoloca los sprites // Recoloca los sprites
@@ -403,3 +435,13 @@ void Scoreboard::renderSeparator()
SDL_SetRenderDrawColor(renderer_, separator_color.r, separator_color.g, separator_color.b, 255); SDL_SetRenderDrawColor(renderer_, separator_color.r, separator_color.g, separator_color.b, 255);
SDL_RenderDrawLine(renderer_, 0, 0, rect_.w, 0); SDL_RenderDrawLine(renderer_, 0, 0, rect_.w, 0);
} }
// Inicializa el vector de colores para el nombre
void Scoreboard::iniNameColors()
{
name_colors_.clear();
name_colors_.emplace_back(green_color.lighten(50));
name_colors_.emplace_back(green_color.lighten(25));
name_colors_.emplace_back(green_color);
name_colors_.emplace_back(green_color.darken(25));
}

View File

@@ -29,6 +29,7 @@ enum class ScoreboardMode : int
GAME_OVER, GAME_OVER,
DEMO, DEMO,
ENTER_NAME, ENTER_NAME,
SHOW_NAME,
GAME_COMPLETED, GAME_COMPLETED,
NUM_MODES, NUM_MODES,
}; };
@@ -72,7 +73,9 @@ private:
Color color_ = Color(); // Color del marcador Color color_ = Color(); // Color del marcador
SDL_Rect rect_ = {0, 0, 320, 40}; // Posición y dimensiones del marcador SDL_Rect rect_ = {0, 0, 320, 40}; // Posición y dimensiones del marcador
Uint32 ticks_ = SDL_GetTicks(); // Variable donde almacenar el valor de SDL_GetTiks() Uint32 ticks_ = SDL_GetTicks(); // Variable donde almacenar el valor de SDL_GetTiks()
int counter_ = 0; // Contador int time_counter_ = 0; // Contador de segundos
int loop_counter_ = 0; // Contador de bucle
std::vector<Color> name_colors_; // Colores para destacar el nombre una vez introducido
// Puntos predefinidos para colocar elementos en los paneles // Puntos predefinidos para colocar elementos en los paneles
SDL_Point slot4_1_, slot4_2_, slot4_3_, slot4_4_; SDL_Point slot4_1_, slot4_2_, slot4_3_, slot4_4_;
@@ -81,7 +84,7 @@ private:
// Recalcula las anclas de los elementos // Recalcula las anclas de los elementos
void recalculateAnchors(); void recalculateAnchors();
// Transforma un valor numérico en una cadena de 6 cifras // Transforma un valor numérico en una cadena de 7 cifras
std::string updateScoreText(int num); std::string updateScoreText(int num);
// Crea la textura de fondo // Crea la textura de fondo
@@ -97,11 +100,14 @@ private:
void fillBackgroundTexture(); void fillBackgroundTexture();
// Actualiza el contador // Actualiza el contador
void updateCounter(); void updateTimeCounter();
// Dibuja la linea que separa la zona de juego del marcador // Dibuja la linea que separa la zona de juego del marcador
void renderSeparator(); void renderSeparator();
// Inicializa el vector de colores para el nombre
void iniNameColors();
// [SINGLETON] Ahora el constructor y el destructor son privados // [SINGLETON] Ahora el constructor y el destructor son privados
// Constructor // Constructor

View File

@@ -394,10 +394,9 @@ void Screen::renderInfo()
// Contador de service_pressed_counter // Contador de service_pressed_counter
if (const int counter = globalInputs::service_pressed_counter; counter > 0) if (const int counter = globalInputs::service_pressed_counter; counter > 0)
{
dbg_print(0, 8, std::to_string(counter).c_str(), 255, 0, 255); dbg_print(0, 8, std::to_string(counter).c_str(), 255, 0, 255);
}
const std::string atten = attenuate_effect_ ? "ATTEN YES" : "ATTEN NO";
dbg_print(0, 16, atten.c_str(), 255, 0, 0);
} }
} }

View File

@@ -1,6 +1,7 @@
// IWYU pragma: no_include <bits/std_abs.h> // IWYU pragma: no_include <bits/std_abs.h>
#include "tabe.h" #include "tabe.h"
#include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL, SDL_FLIP_NONE #include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL, SDL_FLIP_NONE
#include <SDL2/SDL.h>
#include <stdlib.h> // Para rand, abs #include <stdlib.h> // Para rand, abs
#include <algorithm> // Para max #include <algorithm> // Para max
#include "jail_audio.h" // Para JA_PlaySound #include "jail_audio.h" // Para JA_PlaySound
@@ -10,7 +11,8 @@
// Constructor // Constructor
Tabe::Tabe() Tabe::Tabe()
: sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("tabe.png"), Resource::get()->getAnimation("tabe.ani"))) {} : sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("tabe.png"), Resource::get()->getAnimation("tabe.ani"))),
timer_(TabeTimer(2.5f, 4.0f)) {}
// Actualiza la lógica // Actualiza la lógica
void Tabe::update() void Tabe::update()
@@ -21,6 +23,11 @@ void Tabe::update()
move(); move();
updateState(); updateState();
} }
timer_.update();
if (timer_.should_spawn())
{
enable();
}
} }
// Dibuja el objeto // Dibuja el objeto
@@ -49,7 +56,7 @@ void Tabe::move()
{ {
if (x_ < min_x) if (x_ < min_x)
{ {
enabled_ = false; disable();
} }
if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_ && direction_ == TabeDirection::TO_THE_RIGHT) if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_ && direction_ == TabeDirection::TO_THE_RIGHT)
{ {
@@ -63,7 +70,7 @@ void Tabe::move()
{ {
if (x_ > max_x) if (x_ > max_x)
{ {
enabled_ = false; disable();
} }
if (x_ < param.game.game_area.rect.x && direction_ == TabeDirection::TO_THE_LEFT) if (x_ < param.game.game_area.rect.x && direction_ == TabeDirection::TO_THE_LEFT)
{ {
@@ -193,10 +200,25 @@ void Tabe::updateState()
// Intenta obtener el bonus // Intenta obtener el bonus
bool Tabe::tryToGetBonus() bool Tabe::tryToGetBonus()
{ {
if (has_bonus_ && rand() % std::max(1, 10 - number_of_hits_) == 0) if (has_bonus_ && rand() % std::max(1, 15 - number_of_hits_) == 0)
{ {
has_bonus_ = false; has_bonus_ = false;
return true; return true;
} }
return false; return false;
} }
// Actualiza el temporizador
void Tabe::updateTimer()
{
timer_.current_time = SDL_GetTicks();
timer_.delta_time = timer_.current_time - timer_.last_time;
timer_.last_time = timer_.current_time;
}
// Deshabilita el objeto
void Tabe::disable()
{
enabled_ = false;
timer_.reset();
}

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <SDL2/SDL_rect.h> // Para SDL_Rect #include <SDL2/SDL_rect.h> // Para SDL_Rect
#include <SDL2/SDL.h>
#include <memory> // Para unique_ptr #include <memory> // Para unique_ptr
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
@@ -16,6 +17,55 @@ enum class TabeState : int
HIT = 1, HIT = 1,
}; };
struct TabeTimer
{
Uint32 time_until_next_spawn; // Tiempo restante para la próxima aparición
Uint32 min_spawn_time; // Tiempo mínimo entre apariciones
Uint32 max_spawn_time; // Tiempo máximo entre apariciones
Uint32 current_time; // Tiempo actual
Uint32 delta_time; // Diferencia de tiempo desde la última actualización
Uint32 last_time; // Tiempo de la última actualización
// Constructor
TabeTimer(float minTime, float maxTime)
: min_spawn_time(minTime * 60000), max_spawn_time(maxTime * 60000)
{
current_time = SDL_GetTicks();
reset();
}
// Restablece el temporizador con un nuevo tiempo hasta la próxima aparición
void reset()
{
Uint32 range = max_spawn_time - min_spawn_time;
time_until_next_spawn = min_spawn_time + rand() % (range + 1);
last_time = SDL_GetTicks();
}
// Actualiza el temporizador, decrementando el tiempo hasta la próxima aparición
void update()
{
current_time = SDL_GetTicks();
delta_time = current_time - last_time;
last_time = current_time;
if (time_until_next_spawn > delta_time)
{
time_until_next_spawn -= delta_time;
}
else
{
time_until_next_spawn = 0;
}
}
// Indica si el temporizador ha finalizado
bool should_spawn() const
{
return time_until_next_spawn == 0;
}
};
// Clase Tabe // Clase Tabe
class Tabe class Tabe
{ {
@@ -41,6 +91,7 @@ private:
int hit_counter_ = 0; // Contador para el estado HIT int hit_counter_ = 0; // Contador para el estado HIT
int number_of_hits_ = 0; // Cantidad de disparos que ha recibido int number_of_hits_ = 0; // Cantidad de disparos que ha recibido
bool has_bonus_ = true; // Indica si el Tabe aun tiene el bonus para soltar bool has_bonus_ = true; // Indica si el Tabe aun tiene el bonus para soltar
TabeTimer timer_; // Temporizador para gestionar la aparición del Tabe
// Mueve el objeto // Mueve el objeto
void move(); void move();
@@ -54,6 +105,12 @@ private:
// Actualiza el estado // Actualiza el estado
void updateState(); void updateState();
// Actualiza el temporizador
void updateTimer();
// Deshabilita el objeto
void disable();
public: public:
// Constructor // Constructor
Tabe(); Tabe();

View File

@@ -13,17 +13,40 @@
Overrides overrides = Overrides(); Overrides overrides = Overrides();
// Colores // Colores
const Color bg_color = Color(0x27, 0x27, 0x36); const Color bg_color = Color(0X27, 0X27, 0X36);
const Color no_color = Color(0xFF, 0xFF, 0xFF); const Color no_color = Color(0XFF, 0XFF, 0XFF);
const Color shdw_txt_color = Color(0x43, 0x43, 0x4F); const Color shdw_txt_color = Color(0X43, 0X43, 0X4F);
const Color separator_color = Color(0x0D, 0x1A, 0x2B); const Color separator_color = Color(0X0D, 0X1A, 0X2B);
const Color scoreboard_easy_color = Color(0x4B, 0x69, 0x2F); const Color scoreboard_easy_color = Color(0X4B, 0X69, 0X2F);
const Color scoreboard_normal_color = Color(0x2E, 0x3F, 0x47); const Color scoreboard_normal_color = Color(0X2E, 0X3F, 0X47);
const Color scoreboard_hard_color = Color(0x76, 0x42, 0x8A); const Color scoreboard_hard_color = Color(0X76, 0X42, 0X8A);
const Color flash_color = Color(0xFF, 0xFF, 0xFF); const Color flash_color = Color(0XFF, 0XFF, 0XFF);
const Color fade_color = Color(0x27, 0x27, 0x36); const Color fade_color = Color(0X27, 0X27, 0X36);
const Color orange_color = Color(0xFF, 0x7A, 0x00); const Color orange_color = Color(0XFF, 0X7A, 0X00);
const Color orange_soft_color = Color(0xFF, 0xA0, 0x33); const Color orange_soft_color = Color(0XFF, 0XA0, 0X33);
const Color green_color = Color(0X5B, 0XEC, 0X95);
const Color blue_sky_color = Color(0X02, 0X88, 0XD1);
const Color pink_sky_color = Color(0XFF, 0X6B, 0X97);
const Color green_sky_color = Color(0X00, 0X79, 0X6B);
// Obtiene un color del vector de colores imitando al Coche Fantástico
Color getColorLikeKnightRider(const std::vector<Color> &colors, int counter_)
{
int cycle_length = colors.size() * 2 - 2;
size_t n = counter_ % cycle_length;
size_t index;
if (n < colors.size())
{
index = n; // Avanza: 0,1,2,3
}
else
{
index = 2 * (colors.size() - 1) - n; // Retrocede: 2,1
}
return colors[index];
}
// Calcula el cuadrado de la distancia entre dos puntos // Calcula el cuadrado de la distancia entre dos puntos
double distanceSquared(int x1, int y1, int x2, int y2) double distanceSquared(int x1, int y1, int x2, int y2)

View File

@@ -124,6 +124,9 @@ struct Zone
int third_quarter_y; // Anclaje al 75% del eje X int third_quarter_y; // Anclaje al 75% del eje X
}; };
// Obtiene un color del vector de colores imitando al Coche Fantástico
Color getColorLikeKnightRider(const std::vector<Color> &colors, int counter_);
// Calcula el cuadrado de la distancia entre dos puntos // Calcula el cuadrado de la distancia entre dos puntos
double distanceSquared(int x1, int y1, int x2, int y2); double distanceSquared(int x1, int y1, int x2, int y2);
@@ -204,3 +207,7 @@ extern const Color flash_color;
extern const Color fade_color; extern const Color fade_color;
extern const Color orange_color; extern const Color orange_color;
extern const Color orange_soft_color; extern const Color orange_soft_color;
extern const Color green_color;
extern const Color blue_sky_color;
extern const Color pink_sky_color;
extern const Color green_sky_color;