Compare commits

16 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
b01763b749 Dels credits ja passa a la tabla de puntuacions 2025-01-26 21:15:13 +01:00
59b9f61d69 Font nova per a la intro 2025-01-26 21:05:43 +01:00
b9f194a2b1 Afegit efecte d'eixida a les instruccions 2025-01-26 20:16:43 +01:00
59936f13eb Arreglos estetics i de colorets en hiscore_table.cpp 2025-01-26 17:48:10 +01:00
38 changed files with 948 additions and 527 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

BIN
data/font/04b_25_grey.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
data/font/04b_25_metal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

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

@@ -32,7 +32,7 @@ IDIOMA
[ CANCELAR ] [ CANCELAR ]
## 11 - INSTRUCCIONES ## 11 - INSTRUCCIONES
OBJECTIU Objectiu
## 12 - INSTRUCCIONES ## 12 - INSTRUCCIONES
HAS D'EXPLOTAR HAS D'EXPLOTAR
@@ -47,7 +47,7 @@ LA DIFICULTAT AUGMENTA
A MESURA QUE VAS PUNTUANT A MESURA QUE VAS PUNTUANT
## 16 - INSTRUCCIONES ## 16 - INSTRUCCIONES
OBJECTES Objectes
## 17 - INSTRUCCIONES ## 17 - INSTRUCCIONES
1.000 PUNTS 1.000 PUNTS

View File

@@ -68,6 +68,7 @@ Credits::~Credits()
SDL_DestroyTexture(text_texture_); SDL_DestroyTexture(text_texture_);
SDL_DestroyTexture(canvas_); SDL_DestroyTexture(canvas_);
resetVolume(); resetVolume();
JA_StopMusic();
} }
// Bucle principal // Bucle principal
@@ -477,7 +478,7 @@ void Credits::updateAllFades()
fade_out_->update(); fade_out_->update();
if (fade_out_->hasEnded()) if (fade_out_->hasEnded())
{ {
section::name = section::Name::LOGO; section::name = section::Name::HI_SCORE_TABLE;
} }
} }

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::HI_SCORE_TABLE; 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,6 +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_metal.png", AssetType::BITMAP);
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
name_ = "A"; if (name == "")
{
name_ = "A";
position_ = 0;
position_overflow_ = false;
}
// Se pasa un nombre
else
{
name_ = name;
position_ = name_.length();
position_overflow_ = position_ >= NAME_LENGHT ? true : false;
}
// Inicia la lista de caracteres permitidos // Inicializa el vector de indices con el nombre y espacios
character_list_ = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-+-*/=?¿<>!\"#$%&/()"; initCharacterIndex(name_);
position_ = 0;
num_characters_ = static_cast<int>(character_list_.size());
// Pone la lista de indices para que refleje el nombre
updateCharacterIndex();
// 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()
{ {
--position_; if (position_overflow_)
position_ = std::max(position_, 0); {
// 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_;
// 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;
} }
} }
@@ -98,28 +169,4 @@ int EnterName::findIndex(char character) const
if (character == character_list_.at(i)) if (character == character_list_.at(i))
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;
@@ -16,25 +17,21 @@ constexpr int NAME_LENGHT = 6;
class EnterName 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

@@ -283,6 +283,13 @@ void Game::updateStage()
createMessage(paths, text->writeToTexture(caption, 1, -4)); createMessage(paths, text->writeToTexture(caption, 1, -4));
} }
} }
// Modifica el color de fondo al llegar a la Fase 10
if (Stage::number == 9)
{
background_->setColor(Color(0xdd, 0x19, 0x1d).darken());
background_->setAlpha(96);
}
} }
} }
@@ -365,6 +372,7 @@ void Game::updateGameStateCompleted()
balloon_manager_->destroyAllBalloons(); // Destruye a todos los globos balloon_manager_->destroyAllBalloons(); // Destruye a todos los globos
destroyAllItems(); // Destruye todos los items destroyAllItems(); // Destruye todos los items
Stage::power = 0; // Vuelve a dejar el poder a cero, por lo que hubiera podido subir al destruir todos los globos Stage::power = 0; // Vuelve a dejar el poder a cero, por lo que hubiera podido subir al destruir todos los globos
background_->setAlpha(0); // Elimina el tono rojo de las últimas pantallas
} }
// Comienza las celebraciones // Comienza las celebraciones
@@ -1261,7 +1269,8 @@ void Game::checkEvents()
{ {
auto_pop_balloons_ = !auto_pop_balloons_; auto_pop_balloons_ = !auto_pop_balloons_;
Notifier::get()->showText({"auto advance: " + boolToString(auto_pop_balloons_)}); Notifier::get()->showText({"auto advance: " + boolToString(auto_pop_balloons_)});
balloon_manager_->destroyAllBalloons(); if (auto_pop_balloons_)
balloon_manager_->destroyAllBalloons();
balloon_manager_->setDeployBalloons(!auto_pop_balloons_); balloon_manager_->setDeployBalloons(!auto_pop_balloons_);
break; break;
} }
@@ -1361,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;
} }
@@ -1618,6 +1627,7 @@ 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.
@@ -1625,7 +1635,10 @@ void Game::handlePlayerContinue(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))
{ {
player->decContinueCounter(); if (player->getContinueCounter() < 7)
{
player->decContinueCounter();
}
} }
} }
@@ -1637,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
{ {
@@ -1664,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

@@ -4,23 +4,28 @@
#include <SDL2/SDL_pixels.h> // Para SDL_PIXELFORMAT_RGBA8888 #include <SDL2/SDL_pixels.h> // Para SDL_PIXELFORMAT_RGBA8888
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks #include <SDL2/SDL_timer.h> // Para SDL_GetTicks
#include <SDL2/SDL_video.h> // Para SDL_WINDOWEVENT_SIZE_CHANGED #include <SDL2/SDL_video.h> // Para SDL_WINDOWEVENT_SIZE_CHANGED
#include <stdlib.h> // Para rand
#include <algorithm> // Para max #include <algorithm> // Para max
#include <functional> // Para function
#include <vector> // Para vector #include <vector> // Para vector
#include "background.h" // Para Background #include "background.h" // Para Background
#include "fade.h" // Para Fade, FadeMode, FadeType #include "fade.h" // Para Fade, FadeMode, FadeType
#include "global_inputs.h" // Para check #include "global_inputs.h" // Para check, update
#include "input.h" // Para Input #include "input.h" // Para Input
#include "jail_audio.h" // Para JA_GetMusicState, JA_Music_state #include "jail_audio.h" // Para JA_GetMusicState, JA_Music_state
#include "lang.h" // Para getText #include "lang.h" // Para getText
#include "manage_hiscore_table.h" // Para HiScoreEntry #include "manage_hiscore_table.h" // Para HiScoreEntry
#include "mouse.h" // Para handleEvent
#include "options.h" // Para Options, OptionsGame, options #include "options.h" // Para Options, OptionsGame, options
#include "param.h" // Para Param, param, ParamGame, ParamFade #include "param.h" // Para Param, param, ParamGame, ParamFade
#include "path_sprite.h" // Para PathSprite, Path, PathType
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "section.h" // Para Name, name, Options, options #include "section.h" // Para Name, name, Options, options, Attr...
#include "text.h" // Para Text, TEXT_CENTER, TEXT_SHADOW #include "sprite.h" // Para Sprite
#include "utils.h" // Para Color, Zone, fade_color, orange_color #include "text.h" // Para Text, TEXT_COLOR, TEXT_SHADOW
#include "mouse.h" #include "texture.h" // Para Texture
#include "utils.h" // Para Color, easeOutQuint, fade_color
// Constructor // Constructor
HiScoreTable::HiScoreTable() HiScoreTable::HiScoreTable()
@@ -28,30 +33,18 @@ HiScoreTable::HiScoreTable()
backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
fade_(std::make_unique<Fade>()), fade_(std::make_unique<Fade>()),
background_(std::make_unique<Background>()), background_(std::make_unique<Background>()),
text_(Resource::get()->getText("smb2")),
counter_(0), counter_(0),
ticks_(0), ticks_(0),
view_area_({0, 0, param.game.width, param.game.height}), view_area_({0, 0, param.game.width, param.game.height}),
fade_mode_(FadeMode::IN) fade_mode_(FadeMode::IN),
background_fade_color_(Color(0, 0, 0))
{ {
// Inicializa el resto de variables // Inicializa el resto
section::name = section::Name::HI_SCORE_TABLE; section::name = section::Name::HI_SCORE_TABLE;
// Inicializa objetos
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
background_->setPos(param.game.game_area.rect); initFade();
background_->setCloudsSpeed(-0.1f); initBackground();
background_->setGradientNumber(1); iniEntryColors();
background_->setTransition(0.8f);
background_->setSunProgression(1.0f);
background_->setMoonProgression(0.6f);
fade_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_->setType(FadeType::RANDOM_SQUARE);
fade_->setPostDuration(param.fade.post_duration);
fade_->setMode(fade_mode_);
fade_->activate();
// Crea los sprites con los textos
createSprites(); createSprites();
} }
@@ -59,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
@@ -97,7 +91,7 @@ void HiScoreTable::update()
if (counter_ == 150) if (counter_ == 150)
{ {
background_->setColor(Color(0, 0, 0)); background_->setColor(background_fade_color_.darken());
background_->setAlpha(96); background_->setAlpha(96);
} }
@@ -161,8 +155,6 @@ void HiScoreTable::render()
// Recarga todas las texturas // Recarga todas las texturas
void HiScoreTable::reloadTextures() void HiScoreTable::reloadTextures()
{ {
text_->reLoadTexture();
fillTexture();
} }
// Comprueba los eventos // Comprueba los eventos
@@ -268,85 +260,96 @@ 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_grey");
auto entry_text = Resource::get()->getText("smb2");
// Obtiene el tamaño de la textura // Obtiene el tamaño de la textura
int backbuffer_width; int backbuffer_width;
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 = text_->getCharacterSize() * 2; const int space_between_lines = entry_text->getCharacterSize() * 2;
const int size = space_between_header + space_between_lines * (max_names - 1) + 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;
// Crea el sprite para el texto de cabecera // Crea el sprite para el texto de cabecera
header_ = std::make_unique<Sprite>(text_->writeDXToTexture(TEXT_COLOR | TEXT_SHADOW, lang::getText(42), 1, orange_color, 1, shdw_txt_color)); header_ = std::make_unique<Sprite>(header_text->writeDXToTexture(TEXT_COLOR, lang::getText(42), -2, background_fade_color_.getInverse().lighten(25)));
header_->setPosition(param.game.game_area.center_x - (header_->getWidth() / 2), first_line); header_->setPosition(param.game.game_area.center_x - (header_->getWidth() / 2), first_line);
// 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 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 name_lenght = options.game.hi_score_table.at(i).name.length(); 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 score_lenght = score.size(); const auto num_dots = entry_lenght - options.game.hi_score_table.at(i).name.size() - score.size();
const auto num_dots = 25 - name_lenght - score_lenght; 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 = 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>(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)));
if (false) 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)
{ {
if (i % 1 == 0) case 0: // Ambos lados alternativamente
{
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;
} }
if (true) 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);
backbuffer_height, entry_names_.back()->setPosition(-entry_names_.back()->getWidth(), 0);
(i * space_between_lines) + first_line + space_between_header, break;
PathType::VERTICAL, }
(backbuffer_width - entry_names_.back()->getWidth()) / 2,
80, case 2: // Entran por la derecha
easeOutQuint, {
0); entry_names_.back()->addPath(backbuffer_width, pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
entry_names_.back()->setPosition(backbuffer_width, 0);
break;
}
case 3: // Entran desde la parte inferior
{
entry_names_.back()->addPath(backbuffer_height, pos_y, PathType::VERTICAL, pos_x, steps, easeOutQuint);
entry_names_.back()->setPosition(0, backbuffer_height); entry_names_.back()->setPosition(0, backbuffer_height);
} }
default:
break;
}
} }
} }
// Actualiza las posiciones de los sprites de texto // Actualiza las posiciones de los sprites de texto
void HiScoreTable::updateSprites() void HiScoreTable::updateSprites()
{ {
constexpr int init_counter = 220; constexpr int init_counter = 190;
const int counter_between_entries = text_->getCharacterSize() * 2; const int counter_between_entries = 16;
if (counter_ >= init_counter) if (counter_ >= init_counter)
{ {
const int counter2 = counter_ - init_counter; const int counter2 = counter_ - init_counter;
@@ -363,4 +366,102 @@ void HiScoreTable::updateSprites()
{ {
entry->update(); entry->update();
} }
}
glowEntryNames();
}
// Inicializa el fade
void HiScoreTable::initFade()
{
fade_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_->setType(FadeType::RANDOM_SQUARE);
fade_->setPostDuration(param.fade.post_duration);
fade_->setMode(fade_mode_);
fade_->activate();
}
// Inicializa el fondo
void HiScoreTable::initBackground()
{
background_->setPos(param.game.game_area.rect);
background_->setCloudsSpeed(-0.1f);
const int lucky = rand() % 3;
switch (lucky)
{
case 0: // Fondo verde
{
background_->setGradientNumber(2);
background_->setTransition(0.0f);
background_->setSunProgression(1.0f);
background_->setMoonProgression(0.0f);
background_fade_color_ = green_sky_color;
break;
}
case 1: // Fondo naranja
{
background_->setGradientNumber(1);
background_->setTransition(0.0f);
background_->setSunProgression(0.65f);
background_->setMoonProgression(0.0f);
background_fade_color_ = pink_sky_color;
break;
}
case 2: // Fondo azul
{
background_->setGradientNumber(0);
background_->setTransition(0.0f);
background_->setSunProgression(0.0f);
background_->setMoonProgression(0.0f);
background_fade_color_ = blue_sky_color;
break;
}
default:
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

@@ -1,16 +1,18 @@
#pragma once #pragma once
#include <SDL2/SDL_rect.h> // para SDL_Rect #include <SDL2/SDL_rect.h> // Para SDL_Rect
#include <SDL2/SDL_render.h> // para SDL_Renderer, SDL_Texture #include <SDL2/SDL_render.h> // Para SDL_Renderer, SDL_Texture
#include <SDL2/SDL_stdinc.h> // para Uint16, Uint32, Uint8 #include <SDL2/SDL_stdinc.h> // Para Uint16, Uint32, Uint8
#include <memory> // para unique_ptr #include <memory> // Para unique_ptr, shared_ptr
#include <string> // para string #include <string> // Para string
#include "sprite.h" #include <vector> // Para vector
#include "path_sprite.h" #include "utils.h"
class Background; // lines 8-8 class Background; // lines 10-10
class Fade; // lines 9-9 class Fade; // lines 11-11
class Text; // lines 10-10 class PathSprite;
enum class FadeMode : Uint8; // lines 11-11 class Sprite;
enum class FadeMode : Uint8; // lines 13-13
struct Path;
/* /*
Esta clase gestiona un estado del programa. Se encarga de mostrar la tabla con las puntuaciones Esta clase gestiona un estado del programa. Se encarga de mostrar la tabla con las puntuaciones
@@ -35,16 +37,17 @@ private:
std::unique_ptr<Fade> fade_; // Objeto para renderizar fades std::unique_ptr<Fade> fade_; // Objeto para renderizar fades
std::unique_ptr<Background> background_; // Objeto para dibujar el fondo del juego std::unique_ptr<Background> background_; // Objeto para dibujar el fondo del juego
std::shared_ptr<Text> text_; // Objeto para escribir texto
std::unique_ptr<Sprite> header_; // Sprite con la cabecera del texto std::unique_ptr<Sprite> header_; // Sprite con la cabecera del texto
std::vector<std::shared_ptr<PathSprite>> entry_names_; // Lista con los spritres de cada uno de los nombres de la tabla de records std::vector<std::shared_ptr<PathSprite>> entry_names_; // Lista con los spritres de cada uno de los nombres de la tabla de records
std::vector<Path> paths_; // Vector con los recorridos precalculados std::vector<Path> paths_; // Vector con los recorridos precalculados
// Variables // Variables
Uint16 counter_; // Contador Uint16 counter_ = 0; // Contador
Uint32 ticks_; // Contador de ticks para ajustar la velocidad del programa Uint32 ticks_; // Contador de ticks para ajustar la velocidad del programa
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
std::vector<Color> entry_colors_; // Colores para destacar las entradas en la tabla
// Actualiza las variables // Actualiza las variables
void update(); void update();
@@ -76,6 +79,21 @@ private:
// Actualiza las posiciones de los sprites de texto // Actualiza las posiciones de los sprites de texto
void updateSprites(); void updateSprites();
// Inicializa el fade
void initFade();
// Inicializa el fondo
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

@@ -22,6 +22,10 @@
#include "utils.h" // Para Color, shdw_txt_color, Zone, no_color #include "utils.h" // Para Color, shdw_txt_color, Zone, no_color
#include "mouse.h" #include "mouse.h"
#include <SDL2/SDL.h>
#include <vector>
#include <cmath>
// Constructor // Constructor
Instructions::Instructions() Instructions::Instructions()
: renderer_(Screen::get()->getRenderer()), : renderer_(Screen::get()->getRenderer()),
@@ -46,6 +50,9 @@ Instructions::Instructions()
fade_->setMode(FadeMode::IN); fade_->setMode(FadeMode::IN);
fade_->activate(); fade_->activate();
// Inicializa las líneas con un retraso progresivo de 50 ms
lines_ = initializeLines(256);
// Rellena la textura de texto // Rellena la textura de texto
fillTexture(); fillTexture();
@@ -159,7 +166,6 @@ void Instructions::fillTexture()
text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor2, lang::getText(16), 1, orange_color, 1, shdw_txt_color); text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor2, lang::getText(16), 1, orange_color, 1, shdw_txt_color);
const int anchor3 = anchor2 + space_post_header; const int anchor3 = anchor2 + space_post_header;
// const int anchor4 = anchor3 + ((param.game.item_size + text->getCharacterSize()) / 2);
text_->writeShadowed(anchor_item + desp_x, anchor3 + space_between_item_lines * 0, lang::getText(17), shdw_txt_color); text_->writeShadowed(anchor_item + desp_x, anchor3 + space_between_item_lines * 0, lang::getText(17), shdw_txt_color);
text_->writeShadowed(anchor_item + desp_x, anchor3 + space_between_item_lines * 1, lang::getText(18), shdw_txt_color); text_->writeShadowed(anchor_item + desp_x, anchor3 + space_between_item_lines * 1, lang::getText(18), shdw_txt_color);
text_->writeShadowed(anchor_item + desp_x, anchor3 + space_between_item_lines * 2, lang::getText(19), shdw_txt_color); text_->writeShadowed(anchor_item + desp_x, anchor3 + space_between_item_lines * 2, lang::getText(19), shdw_txt_color);
@@ -226,14 +232,36 @@ void Instructions::update()
// Actualiza los sprites // Actualiza los sprites
updateSprites(); updateSprites();
// Establece la ventana del backbuffer
view_.y = std::max(0, param.game.height - counter_ + 100);
// Verifica si view_.y == 0 y gestiona el temporizador
if (view_.y == 0)
{
if (!start_delay_triggered_)
{
// Activa el temporizador si no ha sido activado
start_delay_triggered_ = true;
start_delay_time_ = SDL_GetTicks();
}
else if (SDL_GetTicks() - start_delay_time_ >= 4000)
{
// Han pasado tres segundos, mover líneas
all_lines_off_screen_ = moveLines(lines_, 320, 1.0f, 5);
}
}
// Actualiza el mosaico de fondo // Actualiza el mosaico de fondo
tiled_bg_->update(); tiled_bg_->update();
// Actualiza el objeto "fade" // Actualiza el objeto "fade"
fade_->update(); fade_->update();
// Rellena el backbuffer
fillBackbuffer();
// Comprueba si el contador ha llegado al final // Comprueba si el contador ha llegado al final
if (counter_ == counter_end_) if (all_lines_off_screen_)
{ {
section::name = section::Name::TITLE; section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1; section::options = section::Options::TITLE_1;
@@ -244,9 +272,6 @@ void Instructions::update()
// Pinta en pantalla // Pinta en pantalla
void Instructions::render() void Instructions::render()
{ {
// Rellena el backbuffer
fillBackbuffer();
// Prepara para empezar a dibujar en la textura de juego // Prepara para empezar a dibujar en la textura de juego
Screen::get()->start(); Screen::get()->start();
@@ -256,11 +281,11 @@ void Instructions::render()
// Dibuja el mosacico de fondo // Dibuja el mosacico de fondo
tiled_bg_->render(); tiled_bg_->render();
// Establece la ventana del backbuffer
view_.y = std::max(0, param.game.height - counter_ + 100);
// Copia la textura y el backbuffer al renderizador // Copia la textura y el backbuffer al renderizador
SDL_RenderCopy(renderer_, backbuffer_, nullptr, &view_); if (view_.y == 0)
renderLines(renderer_, backbuffer_, lines_);
else
SDL_RenderCopy(renderer_, backbuffer_, nullptr, &view_);
fade_->render(); fade_->render();
@@ -335,4 +360,61 @@ void Instructions::run()
checkEvents(); // Tiene que ir antes del render checkEvents(); // Tiene que ir antes del render
render(); render();
} }
}
// Método para inicializar las líneas
std::vector<Line> Instructions::initializeLines(int height)
{
std::vector<Line> lines;
for (int y = 0; y < height; y++)
{
int direction = (y % 2 == 0) ? -1 : 1; // Pares a la izquierda, impares a la derecha
lines.emplace_back(y, 0.0f, direction);
}
return lines;
}
// Método para mover las líneas con suavizado
bool Instructions::moveLines(std::vector<Line> &lines, int width, float duration, Uint32 startDelay)
{
Uint32 currentTime = SDL_GetTicks();
bool allLinesOffScreen = true;
for (auto &line : lines)
{
// Establecer startTime en el primer cuadro de animación
if (line.startTime == 0)
{
line.startTime = currentTime + line.y * startDelay;
}
float elapsedTime = (currentTime - line.startTime) / 1000.0f; // Convertir a segundos
if (elapsedTime < 0)
{
allLinesOffScreen = false; // Si aún no se debe mover esta línea, no están todas fuera de pantalla
continue;
}
if (elapsedTime >= duration)
{
continue; // Si la línea ha salido de los límites, no la muevas más
}
float t = elapsedTime / duration;
float smoothFactor = easeInOutQuint(t);
line.x = line.direction * smoothFactor * width;
allLinesOffScreen = false; // Si alguna línea aún se está moviendo, no están todas fuera de pantalla
}
return allLinesOffScreen;
}
// Método para renderizar las líneas
void Instructions::renderLines(SDL_Renderer *renderer, SDL_Texture *texture, const std::vector<Line> &lines)
{
for (const auto &line : lines)
{
SDL_Rect srcRect = {0, line.y, 320, 1};
SDL_Rect dstRect = {static_cast<int>(line.x), line.y, 320, 1};
SDL_RenderCopy(renderer, texture, &srcRect, &dstRect);
}
} }

View File

@@ -24,6 +24,19 @@ class TiledBG; // lines 12-12
por la pantalla sobre el mosaico de fondo (gestionado por el correspondiente objeto) por la pantalla sobre el mosaico de fondo (gestionado por el correspondiente objeto)
*/ */
// Estructura para almacenar información de línea
struct Line
{
int y; // Coordenada Y de la línea
float x; // Coordenada X inicial (usamos float para mayor precisión en el suavizado)
int direction; // Dirección de movimiento: -1 para izquierda, 1 para derecha
Uint32 startTime; // Tiempo de inicio del movimiento
// Constructor de Line
Line(int y, float x, int direction)
: y(y), x(x), direction(direction), startTime(0) {}
};
// Clase Instructions // Clase Instructions
class Instructions class Instructions
{ {
@@ -40,12 +53,15 @@ private:
std::unique_ptr<Fade> fade_; // Objeto para renderizar fades std::unique_ptr<Fade> fade_; // Objeto para renderizar fades
// Variables // Variables
int counter_ = 0; // Contador int counter_ = 0; // Contador para manejar el progreso en la pantalla de instrucciones
int counter_end_ = 700; // Valor final para el contador Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa SDL_Rect view_; // Vista del backbuffer que se va a mostrar por pantalla
SDL_Rect view_; // Vista del backbuffer que se va amostrar por pantalla SDL_Point sprite_pos_ = {0, 0}; // Posición del primer sprite en la lista
SDL_Point sprite_pos_ = {0, 0}; // Posición del primer sprite int item_space_ = 2; // Espacio entre los items en pantalla
int item_space_ = 2; // Espacio entre los items std::vector<Line> lines_; // Vector que contiene las líneas animadas en la pantalla
bool all_lines_off_screen_ = false; // Indica si todas las líneas han salido de la pantalla
Uint32 start_delay_time_ = 0; // Tiempo de inicio del retraso para mover las líneas
bool start_delay_triggered_ = false; // Bandera para determinar si el retraso ha comenzado
// Actualiza las variables // Actualiza las variables
void update(); void update();
@@ -74,6 +90,15 @@ private:
// Recarga todas las texturas // Recarga todas las texturas
void reloadTextures(); void reloadTextures();
// Método para inicializar las líneas
std::vector<Line> initializeLines(int height);
// Método para mover las líneas
bool moveLines(std::vector<Line> &lines, int width, float duration, Uint32 startDelay);
// Método para renderizar las líneas
void renderLines(SDL_Renderer *renderer, SDL_Texture *texture, const std::vector<Line> &lines);
public: public:
// Constructor // Constructor
Instructions(); Instructions();

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("nokia")) text_(Resource::get()->getText("04b_25_metal"))
{ {
// Inicializa variables // Inicializa variables
@@ -97,7 +97,7 @@ Intro::Intro()
auto w = std::make_unique<Writer>(text_); auto w = std::make_unique<Writer>(text_);
w->setPosX(BLOCK * 0); w->setPosX(BLOCK * 0);
w->setPosY(param.game.height - (BLOCK * 6)); w->setPosY(param.game.height - (BLOCK * 6));
w->setKerning(-1); w->setKerning(-2);
w->setEnabled(false); w->setEnabled(false);
w->setFinishedCounter(180); w->setFinishedCounter(180);
texts_.push_back(std::move(w)); texts_.push_back(std::move(w));

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
table_.resize(10); if (table_.size() > 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

@@ -14,12 +14,13 @@
// Estructura para las entradas de la tabla de recirds // Estructura para las entradas de la tabla de recirds
struct HiScoreEntry 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

@@ -64,10 +64,18 @@ struct OptionsAudio
// Estructura para las opciones del juego // Estructura para las opciones del juego
struct OptionsGame 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,22 +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"},
{"8bithud", "8bithud.png"}, {"04b_25_metal", "04b_25_metal.png", "04b_25.txt"},
{"nokia", "nokia.png"}, {"04b_25_grey", "04b_25_grey.png", "04b_25.txt"},
{"smb2", "smb2.gif"}}; {"8bithud", "8bithud.png", "8bithud.txt"},
{"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,27 +258,54 @@ 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));
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)
{ {
if (j != selector_pos_[i] || counter_ % 3 == 0) 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};
// Recorre todos los slots de letras del nombre
for (size_t j = 0; j < NAME_LENGHT; ++j)
{ {
SDL_RenderDrawLine(renderer_, rect.x, rect.y + rect.h, rect.x + rect.w, rect.y + rect.h); // Selecciona el color
text_scoreboard_->write(rect.x, rect.y, record_name_[i].substr(j, 1)); 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);
}
// 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; 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;
}
case ScoreboardMode::GAME_COMPLETED: case ScoreboardMode::GAME_COMPLETED:
{ {
// GAME OVER // GAME OVER
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
@@ -402,4 +434,14 @@ void Scoreboard::renderSeparator()
// Dibuja la linea que separa el marcador de la zona de juego // 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_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

@@ -325,11 +325,11 @@ void Screen::renderShake()
// Crea una textura temporal // Crea una textura temporal
auto temp_texture = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height); auto temp_texture = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);
// Vuelca game_canvas_ a la textura temporal // Vuelca game_canvas_ a la textura temporal
SDL_SetRenderTarget(renderer_, temp_texture); SDL_SetRenderTarget(renderer_, temp_texture);
SDL_RenderCopy(renderer_, game_canvas_, nullptr, nullptr); SDL_RenderCopy(renderer_, game_canvas_, nullptr, nullptr);
// Vuelca textura temporal a game_canvas_ // Vuelca textura temporal a game_canvas_
SDL_SetRenderTarget(renderer_, game_canvas_); SDL_SetRenderTarget(renderer_, game_canvas_);
SDL_RenderCopy(renderer_, temp_texture, &src_rect_, &dst_rect_); SDL_RenderCopy(renderer_, temp_texture, &src_rect_, &dst_rect_);
@@ -339,7 +339,7 @@ void Screen::renderShake()
// Restaura el renderizador de destino original // Restaura el renderizador de destino original
SDL_SetRenderTarget(renderer_, current_target); SDL_SetRenderTarget(renderer_, current_target);
} }
} }
// Activa / desactiva los shaders // Activa / desactiva los shaders
@@ -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,15 +1,18 @@
// 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 <stdlib.h> // Para rand, abs #include <SDL2/SDL.h>
#include "jail_audio.h" // Para JA_PlaySound #include <stdlib.h> // Para rand, abs
#include "param.h" // Para Param, ParamGame, param #include <algorithm> // Para max
#include "resource.h" // Para Resource #include "jail_audio.h" // Para JA_PlaySound
#include "utils.h" // Para Zone #include "param.h" // Para Param, ParamGame, param
#include "resource.h" // Para Resource
#include "utils.h" // Para Zone
// 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()
@@ -20,6 +23,11 @@ void Tabe::update()
move(); move();
updateState(); updateState();
} }
timer_.update();
if (timer_.should_spawn())
{
enable();
}
} }
// Dibuja el objeto // Dibuja el objeto
@@ -48,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)
{ {
@@ -62,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)
{ {
@@ -192,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,7 +1,9 @@
#pragma once #pragma once
#include "animated_sprite.h" #include <SDL2/SDL_rect.h> // Para SDL_Rect
#include <memory> #include <SDL2/SDL.h>
#include <memory> // Para unique_ptr
#include "animated_sprite.h" // Para AnimatedSprite
enum class TabeDirection : int enum class TabeDirection : int
{ {
@@ -15,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
{ {
@@ -40,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();
@@ -53,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

@@ -178,7 +178,7 @@ std::shared_ptr<Texture> Text::writeDXToTexture(Uint8 flags, const std::string &
{ {
auto renderer = Screen::get()->getRenderer(); auto renderer = Screen::get()->getRenderer();
auto texture = std::make_shared<Texture>(renderer); auto texture = std::make_shared<Texture>(renderer);
auto width = Text::lenght(text, kerning); auto width = Text::lenght(text, kerning) + shadow_distance;
auto height = box_height_ + shadow_distance; auto height = box_height_ + shadow_distance;
auto temp = SDL_GetRenderTarget(renderer); auto temp = SDL_GetRenderTarget(renderer);
texture->createBlank(width, height, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET); texture->createBlank(width, height, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET);

View File

@@ -164,6 +164,10 @@ void Texture::setColor(Uint8 red, Uint8 green, Uint8 blue)
{ {
SDL_SetTextureColorMod(texture_, red, green, blue); SDL_SetTextureColorMod(texture_, red, green, blue);
} }
void Texture::setColor(Color color)
{
SDL_SetTextureColorMod(texture_, color.r, color.g, color.b);
}
// Establece el blending // Establece el blending
void Texture::setBlendMode(SDL_BlendMode blending) void Texture::setBlendMode(SDL_BlendMode blending)

View File

@@ -1,13 +1,14 @@
#pragma once #pragma once
#include <SDL2/SDL_blendmode.h> // para SDL_BlendMode #include <SDL2/SDL_blendmode.h> // Para SDL_BlendMode
#include <SDL2/SDL_pixels.h> // para SDL_PIXELFORMAT_RGBA8888, SDL_PixelF... #include <SDL2/SDL_pixels.h> // Para SDL_PIXELFORMAT_RGBA8888, SDL_PixelF...
#include <SDL2/SDL_rect.h> // para SDL_Point, SDL_Rect #include <SDL2/SDL_rect.h> // Para SDL_Point, SDL_Rect
#include <SDL2/SDL_render.h> // para SDL_Renderer, SDL_FLIP_NONE, SDL_TEX... #include <SDL2/SDL_render.h> // Para SDL_Renderer, SDL_FLIP_NONE, SDL_TEX...
#include <SDL2/SDL_stdinc.h> // para Uint8, Uint32, Uint16 #include <SDL2/SDL_stdinc.h> // Para Uint8, Uint16, Uint32
#include <string> // para string, basic_string #include <memory> // Para shared_ptr
#include <vector> // para vector #include <string> // Para string
#include <memory> #include <vector> // Para vector
struct Color;
// Definiciones de tipos // Definiciones de tipos
struct Surface struct Surface
@@ -65,6 +66,7 @@ public:
// Establece el color para la modulacion // Establece el color para la modulacion
void setColor(Uint8 red, Uint8 green, Uint8 blue); void setColor(Uint8 red, Uint8 green, Uint8 blue);
void setColor(Color color);
// Establece el blending // Establece el blending
void setBlendMode(SDL_BlendMode blending); void setBlendMode(SDL_BlendMode blending);

View File

@@ -13,16 +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 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)
@@ -212,6 +236,12 @@ double easeInOutSine(double t)
return -0.5 * (std::cos(M_PI * t) - 1); return -0.5 * (std::cos(M_PI * t) - 1);
} }
// Función de suavizado
double easeInOut(double t)
{
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
}
// Comprueba si una vector contiene una cadena // Comprueba si una vector contiene una cadena
bool stringInVector(const std::vector<std::string> &vec, const std::string &str) bool stringInVector(const std::vector<std::string> &vec, const std::string &str)
{ {

View File

@@ -44,6 +44,30 @@ struct Color
Uint8 r, g, b; Uint8 r, g, b;
constexpr Color() : r(0), g(0), b(0) {} constexpr Color() : r(0), g(0), b(0) {}
explicit constexpr Color(int red, int green, int blue) : r(red), g(green), b(blue) {} explicit constexpr Color(int red, int green, int blue) : r(red), g(green), b(blue) {}
// Método para obtener el color inverso
constexpr Color getInverse() const
{
return Color(255 - r, 255 - g, 255 - b);
}
// Método para aclarar el color
Color lighten(int amount = 50) const
{
return Color(
std::min(255, r + amount),
std::min(255, g + amount),
std::min(255, b + amount));
}
// Método para oscurecer el color
Color darken(int amount = 50) const
{
return Color(
std::max(0, r - amount),
std::max(0, g - amount),
std::max(0, b - amount));
}
}; };
// Posiciones de las notificaciones // Posiciones de las notificaciones
@@ -100,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);
@@ -146,6 +173,7 @@ double easeInOutQuint(double t);
double easeInQuad(double t); double easeInQuad(double t);
double easeOutQuad(double t); double easeOutQuad(double t);
double easeInOutSine(double t); double easeInOutSine(double t);
double easeInOut(double t);
// Comprueba si una vector contiene una cadena // Comprueba si una vector contiene una cadena
bool stringInVector(const std::vector<std::string> &vec, const std::string &str); bool stringInVector(const std::vector<std::string> &vec, const std::string &str);
@@ -177,4 +205,9 @@ extern const Color scoreboard_normal_color;
extern const Color scoreboard_hard_color; extern const Color scoreboard_hard_color;
extern const Color flash_color; 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 green_color;
extern const Color blue_sky_color;
extern const Color pink_sky_color;
extern const Color green_sky_color;