Compare commits

14 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
33 changed files with 653 additions and 480 deletions

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
data/font/04b_25_grey.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

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

@@ -68,6 +68,7 @@ Credits::~Credits()
SDL_DestroyTexture(text_texture_);
SDL_DestroyTexture(canvas_);
resetVolume();
JA_StopMusic();
}
// Bucle principal
@@ -477,7 +478,7 @@ void Credits::updateAllFades()
fade_out_->update();
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::options = section::Options::GAME_PLAY_1P;
#elif DEBUG
section::name = section::Name::INSTRUCTIONS;
section::name = section::Name::LOGO;
#else // NORMAL GAME
section::name = section::Name::LOGO;
section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
@@ -536,8 +536,6 @@ void Director::setFileList()
// Fuentes de texto
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/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_palette1.pal", AssetType::PALETTE);
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_2x.png", AssetType::BITMAP);
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
Asset::get()->add(prefix + "/data/lang/es_ES.txt", AssetType::LANG);

View File

@@ -1,93 +1,164 @@
#include "enter_name.h"
#include "utils.h"
#include <stddef.h> // Para size_t
#include <algorithm> // Para max, min
#include <cassert> // Para assert
#include <iostream>
// Constructor
EnterName::EnterName()
{
init();
}
: character_list_(" ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-+-*/=?¿<>!\"#$%&/()") {}
// Inicializa el objeto
void EnterName::init()
void EnterName::init(const std::string &name)
{
// Obtiene el puntero al nombre
name_ = "A";
// No se pasa ningún nombre
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
character_list_ = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-+-*/=?¿<>!\"#$%&/()";
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();
// Inicializa el vector de indices con el nombre y espacios
initCharacterIndex(name_);
}
// Incrementa la posición
void EnterName::incPosition()
{
position_++;
position_ = std::min(position_, NAME_LENGHT - 1);
checkIfPositionHasBeenUsed();
if (position_overflow_)
{
// 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
void EnterName::decPosition()
{
--position_;
position_ = std::max(position_, 0);
if (position_overflow_)
{
// Si estaba en overflow, lo desactivamos y mantenemos position_ en el máximo.
position_overflow_ = false;
position_ = NAME_LENGHT - 1;
}
else
{
if (position_ > 0)
{
--position_;
// 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
void EnterName::incIndex()
{
if (position_overflow_)
{
return;
}
++character_index_[position_];
if (character_index_[position_] >= num_characters_)
if (character_index_[position_] >= static_cast<int>(character_list_.size()))
{
character_index_[position_] = 0;
}
updateName();
updateNameFromCharacterIndex();
}
// Decrementa el índice
void EnterName::decIndex()
{
if (position_overflow_)
{
return;
}
--character_index_[position_];
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
void EnterName::updateName()
void EnterName::updateNameFromCharacterIndex()
{
name_.clear();
for (int i = 0; i < NAME_LENGHT; ++i)
{
name_.push_back(character_list_[character_index_[i]]);
}
name_ = trim(name_);
}
// 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)
{
character_index_[i] = 0;
position_has_been_used_[i] = false;
}
// 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));
position_has_been_used_[i] = true;
character_index_[i] = findIndex(name.at(i));
}
}
@@ -98,28 +169,4 @@ int EnterName::findIndex(char character) const
if (character == character_list_.at(i))
return i;
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
#include <string>
#include "utils.h"
constexpr int NAME_LENGHT = 6;
@@ -16,25 +17,21 @@ constexpr int NAME_LENGHT = 6;
class EnterName
{
private:
std::string character_list_; // Lista de todos los caracteres permitidos
std::string name_; // Nombre introducido
int position_; // Posición a editar del nombre
int num_characters_; // Cantidad de caracteres de la lista de caracteres
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
std::string character_list_; // Lista de todos los caracteres permitidos
std::string name_; // Nombre introducido
int position_ = 0; // Posición a editar del nombre
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
// Actualiza el nombre a partir de la lista de índices
void updateName();
void updateNameFromCharacterIndex();
// Actualiza la variable
void updateCharacterIndex();
void initCharacterIndex(const std::string &name);
// Encuentra el indice de un caracter en "characterList"
int findIndex(char character) const;
// Comprueba la posición y copia el caracter si es necesario
void checkIfPositionHasBeenUsed();
public:
// Constructor
EnterName();
@@ -43,7 +40,7 @@ public:
~EnterName() = default;
// Inicializa el objeto
void init();
void init(const std::string &name = "");
// Incrementa la posición
void incPosition();
@@ -57,9 +54,9 @@ public:
// Decrementa el índice
void decIndex();
// Obtiene el nombre
std::string getName() const;
// Obtiene la posición que se está editando
int getPosition() const;
// Getters
std::string getFinalName() const { return trim(name_.substr(0, position_)); }
std::string getCurrentName() const { return trim(name_); }
int getPosition() const { return position_; }
bool getPositionOverflow() const { return position_overflow_; }
};

View File

@@ -1370,11 +1370,11 @@ void Game::pause(bool value)
}
// Añade una puntuación a la tabla de records
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);
manager->add(entry);
options.game.last_hi_score_entry.at(player->getId() - 1) = manager->add(entry);
manager->saveToFile(asset_->get("score.bin"));
hi_score_.name = options.game.hi_score_table.front().name;
}
@@ -1627,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))
{
player->setPlayingState(PlayerState::PLAYING);
player->addCredit();
}
// Disminuye el contador de continuación si se presiona cualquier botón de disparo.
@@ -1634,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_RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index))
{
player->decContinueCounter();
if (player->getContinueCounter() < 7)
{
player->decContinueCounter();
}
}
}
@@ -1646,12 +1650,11 @@ void Game::handleNameInput(const std::shared_ptr<Player> &player)
input_->checkInput(InputType::FIRE_CENTER, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index) ||
input_->checkInput(InputType::FIRE_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);
addScoreToScoreBoard(player->getRecordName(), player->getScore());
const auto state = player->getPlayingState();
player->setPlayingState(state == PlayerState::ENTERING_NAME ? PlayerState::CONTINUE : PlayerState::LEAVING_SCREEN);
addScoreToScoreBoard(player);
player->setPlayingState(PlayerState::SHOWING_NAME);
}
else
{
@@ -1673,9 +1676,8 @@ void Game::handleNameInput(const std::shared_ptr<Player> &player)
else if (input_->checkInput(InputType::START, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index))
{
player->setInput(InputType::START);
addScoreToScoreBoard(player->getRecordName(), player->getScore());
const auto state = player->getPlayingState();
player->setPlayingState(state == PlayerState::ENTERING_NAME ? PlayerState::CONTINUE : PlayerState::LEAVING_SCREEN);
addScoreToScoreBoard(player);
player->setPlayingState(PlayerState::SHOWING_NAME);
}
}

View File

@@ -311,7 +311,7 @@ private:
void pause(bool value);
// 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
void checkAndUpdatePlayerStatus(int active_player_index, int inactive_player_index);

View File

@@ -44,6 +44,7 @@ HiScoreTable::HiScoreTable()
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
initFade();
initBackground();
iniEntryColors();
createSprites();
}
@@ -51,6 +52,7 @@ HiScoreTable::HiScoreTable()
HiScoreTable::~HiScoreTable()
{
SDL_DestroyTexture(backbuffer_);
options.game.clear_last_hi_score_entries();
}
// Actualiza las variables
@@ -258,7 +260,7 @@ std::string HiScoreTable::format(int number)
// Crea los sprites con los textos
void HiScoreTable::createSprites()
{
auto header_text = Resource::get()->getText("04b_25");
auto header_text = Resource::get()->getText("04b_25_grey");
auto entry_text = Resource::get()->getText("smb2");
// Obtiene el tamaño de la textura
@@ -266,9 +268,9 @@ void HiScoreTable::createSprites()
int 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 space_between_header = 32;
const int space_between_header = entry_text->getCharacterSize() * 4;
const int space_between_lines = entry_text->getCharacterSize() * 2;
const int size = space_between_header + space_between_lines * (max_names - 1) + entry_text->getCharacterSize();
const int first_line = (param.game.height - size) / 2;
@@ -279,45 +281,39 @@ void HiScoreTable::createSprites()
// Crea los sprites para las entradas en la tabla de puntuaciones
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)
{
const auto table_position = (i + 1 >= 10) ? format(i + 1) + ". " : " " + format(i + 1) + ". ";
const auto table_position = format(i + 1) + ". ";
const auto score = format(options.game.hi_score_table.at(i).score);
const auto num_dots = 25 - table_position.size() - options.game.hi_score_table.at(i).name.size() - score.size();
const auto num_dots = entry_lenght - options.game.hi_score_table.at(i).name.size() - score.size();
const auto one_cc = options.game.hi_score_table.at(i).one_credit_complete ? " }" : "";
std::string dots;
for (int j = 0; j < (int)num_dots; ++j)
{
dots = dots + ".";
}
const auto line = table_position + options.game.hi_score_table.at(i).name + dots + score;
const auto line = table_position + options.game.hi_score_table.at(i).name + dots + score + one_cc;
entry_names_.emplace_back(std::make_shared<PathSprite>(entry_text->writeDXToTexture(TEXT_SHADOW, line, 1, orange_color, 1, shdw_txt_color)));
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)
{
case 0: // Ambos lados alternativamente
{
if (i % 2 == 0)
{
entry_names_.back()->addPath(
-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()->addPath(-entry_names_.back()->getWidth(), pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
entry_names_.back()->setPosition(-entry_names_.back()->getWidth(), 0);
}
else
{
entry_names_.back()->addPath(
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()->addPath(backbuffer_width, pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
entry_names_.back()->setPosition(backbuffer_width, 0);
}
break;
@@ -325,42 +321,21 @@ void HiScoreTable::createSprites()
case 1: // Entran por la izquierda
{
entry_names_.back()->addPath(
-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()->addPath(-entry_names_.back()->getWidth(), pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
entry_names_.back()->setPosition(-entry_names_.back()->getWidth(), 0);
break;
}
case 2: // Entran por la derecha
{
entry_names_.back()->addPath(
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()->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,
(i * space_between_lines) + first_line + space_between_header,
PathType::VERTICAL,
(backbuffer_width - entry_names_.back()->getWidth()) / 2,
80,
easeOutQuint,
0);
entry_names_.back()->addPath(backbuffer_height, pos_y, PathType::VERTICAL, pos_x, steps, easeOutQuint);
entry_names_.back()->setPosition(0, backbuffer_height);
}
@@ -391,6 +366,8 @@ void HiScoreTable::updateSprites()
{
entry->update();
}
glowEntryNames();
}
// Inicializa el fade
@@ -410,7 +387,6 @@ void HiScoreTable::initBackground()
background_->setCloudsSpeed(-0.1f);
const int lucky = rand() % 3;
//const int lucky = 2;
switch (lucky)
{
case 0: // Fondo verde
@@ -418,8 +394,8 @@ void HiScoreTable::initBackground()
background_->setGradientNumber(2);
background_->setTransition(0.0f);
background_->setSunProgression(1.0f);
background_->setMoonProgression(0.4f);
background_fade_color_ = Color(0x00, 0x79, 0x6b);
background_->setMoonProgression(0.0f);
background_fade_color_ = green_sky_color;
break;
}
@@ -429,7 +405,7 @@ void HiScoreTable::initBackground()
background_->setTransition(0.0f);
background_->setSunProgression(0.65f);
background_->setMoonProgression(0.0f);
background_fade_color_ = Color(0xff, 0x6b, 0x97);
background_fade_color_ = pink_sky_color;
break;
}
@@ -439,11 +415,53 @@ void HiScoreTable::initBackground()
background_->setTransition(0.0f);
background_->setSunProgression(0.0f);
background_->setMoonProgression(0.0f);
background_fade_color_ = Color(0x02, 0x88, 0xd1);
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

@@ -7,8 +7,8 @@
#include <string> // Para string
#include <vector> // Para vector
#include "utils.h"
class Background; // lines 10-10
class Fade; // lines 11-11
class Background; // lines 10-10
class Fade; // lines 11-11
class PathSprite;
class Sprite;
enum class FadeMode : Uint8; // lines 13-13
@@ -42,11 +42,12 @@ private:
std::vector<Path> paths_; // Vector con los recorridos precalculados
// Variables
Uint16 counter_ = 0; // Contador
Uint32 ticks_; // Contador de ticks para ajustar la velocidad del programa
SDL_Rect view_area_; // Parte de la textura que se muestra en pantalla
FadeMode fade_mode_; // Modo de fade a utilizar
Color background_fade_color_; // Color de atenuación del fondo
Uint16 counter_ = 0; // Contador
Uint32 ticks_; // Contador de ticks para ajustar la velocidad del programa
SDL_Rect view_area_; // Parte de la textura que se muestra en pantalla
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
void update();
@@ -84,6 +85,15 @@ private:
// 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:
// Constructor
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 ((device == InputDeviceToUse::CONTROLLER) || (device == InputDeviceToUse::ANY))
{
success_controller = checkAxisInput(input, controller_index);
success_controller = checkAxisInput(input, controller_index, repeat);
if (!success_controller)
{
if (repeat)
@@ -144,6 +146,7 @@ bool Input::checkInput(InputType input, bool repeat, InputDeviceToUse device, in
}
}
}
}
return (success_keyboard || success_controller);
}
@@ -379,19 +382,53 @@ InputType Input::to_inputs_e(const std::string &name) const
}
// 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)
{
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:
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:
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:
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:
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
bool active; // Indica si está activo
bool axis_active; // Estado del eje
// Constructor
explicit ControllerBindings(SDL_GameControllerButton btn = SDL_CONTROLLER_BUTTON_INVALID, bool act = false)
: button(btn), active(act) {}
explicit ControllerBindings(SDL_GameControllerButton btn = SDL_CONTROLLER_BUTTON_INVALID, bool act = false, bool axis_act = false)
: button(btn), active(act), axis_active(axis_act) {}
};
// Variables
@@ -99,7 +100,7 @@ private:
std::string game_controller_db_path_; // Ruta al archivo gamecontrollerdb.txt
// Comprueba el eje del mando
bool checkAxisInput(InputType input, int controller_index = 0) const;
bool checkAxisInput(InputType input, int controller_index, bool repeat);
// Constructor
explicit Input(const std::string &game_controller_db_path);

View File

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

View File

@@ -27,7 +27,7 @@ void ManageHiScoreTable::clear()
}
// 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
table_.push_back(entry);
@@ -35,8 +35,32 @@ void ManageHiScoreTable::add(HiScoreEntry entry)
// Ordena la tabla
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
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
@@ -50,52 +74,55 @@ void ManageHiScoreTable::sort()
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)
{
clear();
auto success = true;
auto file = SDL_RWFromFile(file_path.c_str(), "r+b");
auto file = SDL_RWFromFile(file_path.c_str(), "rb");
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;
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;
}
SDL_RWread(file, &nameSize, sizeof(int), 1);
std::vector<char> nameBuffer(nameSize + 1);
if (SDL_RWread(file, nameBuffer.data(), sizeof(char) * nameSize, 1) == 0)
{
success = false;
break;
}
nameBuffer[nameSize] = '\0';
SDL_RWread(file, nameBuffer.data(), nameSize, 1);
nameBuffer[nameSize] = '\0'; // Asegurar el fin de la cadena
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);
}
if (!success)
else
{
clear();
std::cout << "Error: Unable to load " << getFileName(file_path) << " file! " << SDL_GetError() << std::endl;
success = false;
}
return success;
}
@@ -107,21 +134,35 @@ bool ManageHiScoreTable::saveToFile(const std::string &file_path)
if (file)
{
// Guarda los datos
for (int i = 0; i < (int)table_.size(); ++i)
// Guarda el número de entradas en la tabla
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 int nameSize = (int)table_.at(i).name.size();
const HiScoreEntry &entry = table_.at(i);
// 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, 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);
}
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;
}

View File

@@ -14,12 +14,13 @@
// Estructura para las entradas de la tabla de recirds
struct HiScoreEntry
{
std::string name; // Nombre
int score; // Puntuación
std::string name; // Nombre
int score; // Puntuación
bool one_credit_complete; // Indica si se ha conseguido 1CC
// Constructor
explicit HiScoreEntry(const std::string &n = "", int s = 0)
: name(n), score(s) {}
// Constructor
explicit HiScoreEntry(const std::string &n = "", int s = 0, bool occ = false)
: name(n.substr(0, 6)), score(s), one_credit_complete(occ) {}
};
// Clase ManageHiScoreTable
@@ -44,7 +45,7 @@ public:
void clear();
// 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
bool loadFromFile(const std::string &file_path);

View File

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

View File

@@ -64,10 +64,18 @@ struct OptionsAudio
// Estructura para las opciones del juego
struct OptionsGame
{
GameDifficulty difficulty; // Dificultad del 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
std::vector<HiScoreEntry> hi_score_table; // Tabla con las mejores puntuaciones
GameDifficulty difficulty; // Dificultad del juego
lang::Code language; // Idioma usado en el juego
bool autofire; // Indicador de autofire
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

View File

@@ -65,8 +65,8 @@ public:
// Añade un recorrido
void addPath(Path path, bool centered = false);
void addPath(std::vector<SDL_Point> spots, 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);
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 = 0);
// Habilita el objeto
void enable();

View File

@@ -58,7 +58,7 @@ void Player::init()
score_ = 0;
score_multiplier_ = 1.0f;
cool_down_ = 10;
enter_name_->init();
enter_name_->init(last_enter_name_);
// Establece la posición del sprite
player_sprite_->clear();
@@ -148,6 +148,7 @@ void Player::setInputEnteringName(InputType input)
enter_name_->decIndex();
break;
case InputType::START:
last_enter_name_ = getRecordName();
break;
default:
break;
@@ -449,6 +450,7 @@ void Player::update()
updateInvulnerable();
updateContinueCounter();
updateEnterNameCounter();
updateShowingName();
updateScoreboard();
}
@@ -474,7 +476,7 @@ void Player::updateScoreboard()
case PlayerState::ENTERING_NAME:
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());
break;
}
@@ -525,12 +527,19 @@ void Player::setPlayingState(PlayerState state)
setScoreboardMode(ScoreboardMode::ENTER_NAME);
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:
{
// Activa la animación de morir
player_sprite_->setAccelY(0.2f);
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;
}
case PlayerState::DIED:
@@ -546,6 +555,7 @@ void Player::setPlayingState(PlayerState state)
}
case PlayerState::CELEBRATING:
{
game_completed_ = true;
setScoreboardMode(ScoreboardMode::SCORE);
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
void Player::decContinueCounter()
{

View File

@@ -34,6 +34,7 @@ enum class PlayerState
CONTINUE, // Está con la cuenta atras para continuar
WAITING, // No está jugando pero puede entrar a jugar
ENTERING_NAME, // Introduciendo nombre
SHOWING_NAME, // Mostrando el nombre introducido
DYING, // El cadaver está volando por ahi
DIED, // El cadaver ha desaparecido por el fondo
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
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 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
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
void shiftColliders();
@@ -109,6 +114,9 @@ private:
// Actualiza el contador de entrar nombre
void updateEnterNameCounter();
// Actualiza el estado de SHOWING_NAME
void updateShowingName();
// Decrementa el contador de entrar nombre
void decEnterNameCounter();
@@ -224,12 +232,14 @@ public:
int getPosX() const { return static_cast<int>(pos_x_); }
int getPosY() const { return pos_y_; }
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 getScoreBoardPanel() const { return scoreboard_panel_; }
int getWidth() const { return WIDTH_; }
PlayerState getPlayingState() const { return playing_state_; }
std::string getName() const { return name_; }
bool get1CC() const { return game_completed_ && credits_used_ == 1; }
bool getEnterNamePositionOverflow() const { return enter_name_->getPositionOverflow(); }
// Setters
void setController(int index) { controller_index_ = index; }
@@ -242,4 +252,5 @@ public:
void setScoreBoardPanel(int panel) { scoreboard_panel_ = panel; }
void setScoreMultiplier(float value) { score_multiplier_ = value; }
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()
{
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::vector<std::pair<std::string, std::string>> resources = {
{"04b_25", "04b_25.png"},
{"04b_25_2x", "04b_25_2x.png"},
{"8bithud", "8bithud.png"},
{"nokia", "nokia.png"},
{"smb2", "smb2.gif"}};
std::vector<ResourceInfo> resources = {
{"04b_25", "04b_25.png", "04b_25.txt"},
{"04b_25_2x", "04b_25_2x.png", "04b_25_2x.txt"},
{"04b_25_metal", "04b_25_metal.png", "04b_25.txt"},
{"04b_25_grey", "04b_25_grey.png", "04b_25.txt"},
{"8bithud", "8bithud.png", "8bithud.txt"},
{"smb2", "smb2.gif", "smb2.txt"}};
for (const auto &resource : resources)
{
texts_.emplace_back(ResourceText(resource.first, std::make_shared<Text>(getTexture(resource.second), getTextFile(resource.first + ".txt"))));
printWithDots("Text : ", resource.first, "[ DONE ]");
texts_.emplace_back(ResourceText(resource.key, std::make_shared<Text>(
getTexture(resource.textureFile),
getTextFile(resource.textFile))));
printWithDots("Text : ", resource.key, "[ DONE ]");
}
}

View File

@@ -10,7 +10,8 @@
#include "screen.h" // Para Screen
#include "sprite.h" // Para Sprite
#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
Scoreboard *Scoreboard::scoreboard_ = nullptr;
@@ -68,6 +69,9 @@ Scoreboard::Scoreboard()
// Rellena la textura de fondo
fillBackgroundTexture();
// Inicializa el vector de colores para el nombre
iniNameColors();
}
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::ostringstream oss;
oss << std::setw(8) << std::setfill('0') << num;
oss << std::setw(7) << std::setfill('0') << num;
return oss.str();
}
// Actualiza el contador
void Scoreboard::updateCounter()
void Scoreboard::updateTimeCounter()
{
constexpr int TICKS_SPEED = 100;
if (SDL_GetTicks() - ticks_ > TICKS_SPEED)
{
ticks_ = SDL_GetTicks();
counter_++;
++time_counter_;
}
}
@@ -110,7 +114,8 @@ void Scoreboard::updateCounter()
void Scoreboard::update()
{
fillBackgroundTexture();
updateCounter();
updateTimeCounter();
++loop_counter_;
}
// Pinta el marcador
@@ -150,7 +155,7 @@ void Scoreboard::fillPanelTextures()
// Guarda a donde apunta actualmente el renderizador
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)
{
// 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));
// 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_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));
// 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_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));
// 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_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]));
// 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);
text_scoreboard_->write(rect.x, rect.y, record_name_[i].substr(j, 1));
// Selecciona el color
const Color color = j < selector_pos_[i] ? orange_soft_color.lighten() : Color(0xFF, 0xFF, 0xEB);
if (j != selector_pos_[i] || time_counter_ % 3 == 0)
{
// Dibuja la linea
if (j >= selector_pos_[i])
{
SDL_SetRenderDrawColor(renderer_, color.r, color.g, color.b, 255);
SDL_RenderDrawLine(renderer_, rect.x, rect.y + rect.h, rect.x + rect.w, rect.y + rect.h);
}
// Dibuja la letra
if (j < record_name_->size())
{
text_scoreboard_->writeColored(rect.x, rect.y, record_name_[i].substr(j, 1), color);
}
}
rect.x += 7;
}
rect.x += 7;
}
break;
}
case ScoreboardMode::SHOW_NAME:
{
// SCORE
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y, name_[i]);
text_scoreboard_->writeCentered(slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]));
// NAME
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y, lang::getText(106));
text_scoreboard_->writeDX(TEXT_CENTER | TEXT_COLOR, slot4_4_.x, slot4_4_.y, record_name_[i], 1, getColorLikeKnightRider(name_colors_, loop_counter_ / 5));
break;
}
case ScoreboardMode::GAME_COMPLETED:
{
// GAME OVER
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y + 4, lang::getText(102));
// 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_4_.x, slot4_4_.y - 2, updateScoreText(score_[i]));
@@ -319,27 +351,27 @@ void Scoreboard::fillBackgroundTexture()
void Scoreboard::recalculateAnchors()
{
// 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)
{
panel_[i].pos.x = roundf(panelWidth * i);
panel_[i].pos.x = roundf(panel_width * i);
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;
}
// Constantes para definir las zonas del panel_: 4 filas y 1 columna
const int rowSize = rect_.h / 4;
const int textHeight = 7;
const int row_size = rect_.h / 4;
const int text_height = 7;
// Filas
const int row1 = (rowSize * 0) + (textHeight / 2);
const int row2 = (rowSize * 1) + (textHeight / 2) - 1;
const int row3 = (rowSize * 2) + (textHeight / 2) - 2;
const int row4 = (rowSize * 3) + (textHeight / 2) - 3;
const int row1 = (row_size * 0) + (text_height / 2);
const int row2 = (row_size * 1) + (text_height / 2) - 1;
const int row3 = (row_size * 2) + (text_height / 2) - 2;
const int row4 = (row_size * 3) + (text_height / 2) - 3;
// Columna
const int col = panelWidth / 2;
const int col = panel_width / 2;
// Slots de 4
slot4_1_ = {col, row1};
@@ -348,8 +380,8 @@ void Scoreboard::recalculateAnchors()
slot4_4_ = {col, row4};
// Primer cuadrado para poner el nombre de record
const int enterNameLenght = NAME_LENGHT * 7;
enter_name_pos_.x = (panelWidth - enterNameLenght) / 2;
const int enter_name_lenght = text_scoreboard_->lenght(std::string(NAME_LENGHT, 'A'));
enter_name_pos_.x = col - (enter_name_lenght / 2);
enter_name_pos_.y = row4;
// Recoloca los sprites
@@ -402,4 +434,14 @@ void Scoreboard::renderSeparator()
// Dibuja la linea que separa el marcador de la zona de juego
SDL_SetRenderDrawColor(renderer_, separator_color.r, separator_color.g, separator_color.b, 255);
SDL_RenderDrawLine(renderer_, 0, 0, rect_.w, 0);
}
// 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,
DEMO,
ENTER_NAME,
SHOW_NAME,
GAME_COMPLETED,
NUM_MODES,
};
@@ -72,7 +73,9 @@ private:
Color color_ = Color(); // Color 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()
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
SDL_Point slot4_1_, slot4_2_, slot4_3_, slot4_4_;
@@ -81,7 +84,7 @@ private:
// Recalcula las anclas de los elementos
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);
// Crea la textura de fondo
@@ -97,11 +100,14 @@ private:
void fillBackgroundTexture();
// Actualiza el contador
void updateCounter();
void updateTimeCounter();
// Dibuja la linea que separa la zona de juego del marcador
void renderSeparator();
// Inicializa el vector de colores para el nombre
void iniNameColors();
// [SINGLETON] Ahora el constructor y el destructor son privados
// Constructor

View File

@@ -325,11 +325,11 @@ void Screen::renderShake()
// Crea una textura temporal
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
SDL_SetRenderTarget(renderer_, temp_texture);
SDL_RenderCopy(renderer_, game_canvas_, nullptr, nullptr);
// Vuelca textura temporal a game_canvas_
SDL_SetRenderTarget(renderer_, game_canvas_);
SDL_RenderCopy(renderer_, temp_texture, &src_rect_, &dst_rect_);
@@ -339,7 +339,7 @@ void Screen::renderShake()
// Restaura el renderizador de destino original
SDL_SetRenderTarget(renderer_, current_target);
}
}
}
// Activa / desactiva los shaders
@@ -394,10 +394,9 @@ void Screen::renderInfo()
// Contador de service_pressed_counter
if (const int counter = globalInputs::service_pressed_counter; counter > 0)
{
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,16 +1,18 @@
// IWYU pragma: no_include <bits/std_abs.h>
#include "tabe.h"
#include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL, SDL_FLIP_NONE
#include <stdlib.h> // Para rand, abs
#include <algorithm> // Para max
#include "jail_audio.h" // Para JA_PlaySound
#include "param.h" // Para Param, ParamGame, param
#include "resource.h" // Para Resource
#include "utils.h" // Para Zone
#include <SDL2/SDL.h>
#include <stdlib.h> // Para rand, abs
#include <algorithm> // Para max
#include "jail_audio.h" // Para JA_PlaySound
#include "param.h" // Para Param, ParamGame, param
#include "resource.h" // Para Resource
#include "utils.h" // Para Zone
// Constructor
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
void Tabe::update()
@@ -21,6 +23,11 @@ void Tabe::update()
move();
updateState();
}
timer_.update();
if (timer_.should_spawn())
{
enable();
}
}
// Dibuja el objeto
@@ -49,7 +56,7 @@ void Tabe::move()
{
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)
{
@@ -63,7 +70,7 @@ void Tabe::move()
{
if (x_ > max_x)
{
enabled_ = false;
disable();
}
if (x_ < param.game.game_area.rect.x && direction_ == TabeDirection::TO_THE_LEFT)
{
@@ -193,10 +200,25 @@ void Tabe::updateState()
// Intenta obtener el bonus
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;
return true;
}
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,8 +1,9 @@
#pragma once
#include <SDL2/SDL_rect.h> // Para SDL_Rect
#include <memory> // Para unique_ptr
#include "animated_sprite.h" // Para AnimatedSprite
#include <SDL2/SDL_rect.h> // Para SDL_Rect
#include <SDL2/SDL.h>
#include <memory> // Para unique_ptr
#include "animated_sprite.h" // Para AnimatedSprite
enum class TabeDirection : int
{
@@ -16,6 +17,55 @@ enum class TabeState : int
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
class Tabe
{
@@ -41,6 +91,7 @@ private:
int hit_counter_ = 0; // Contador para el estado HIT
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
TabeTimer timer_; // Temporizador para gestionar la aparición del Tabe
// Mueve el objeto
void move();
@@ -54,6 +105,12 @@ private:
// Actualiza el estado
void updateState();
// Actualiza el temporizador
void updateTimer();
// Deshabilita el objeto
void disable();
public:
// Constructor
Tabe();

View File

@@ -13,17 +13,40 @@
Overrides overrides = Overrides();
// Colores
const Color bg_color = Color(0x27, 0x27, 0x36);
const Color no_color = Color(0xFF, 0xFF, 0xFF);
const Color shdw_txt_color = Color(0x43, 0x43, 0x4F);
const Color separator_color = Color(0x0D, 0x1A, 0x2B);
const Color scoreboard_easy_color = Color(0x4B, 0x69, 0x2F);
const Color scoreboard_normal_color = Color(0x2E, 0x3F, 0x47);
const Color scoreboard_hard_color = Color(0x76, 0x42, 0x8A);
const Color flash_color = Color(0xFF, 0xFF, 0xFF);
const Color fade_color = Color(0x27, 0x27, 0x36);
const Color orange_color = Color(0xFF, 0x7A, 0x00);
const Color orange_soft_color = Color(0xFF, 0xA0, 0x33);
const Color bg_color = Color(0X27, 0X27, 0X36);
const Color no_color = Color(0XFF, 0XFF, 0XFF);
const Color shdw_txt_color = Color(0X43, 0X43, 0X4F);
const Color separator_color = Color(0X0D, 0X1A, 0X2B);
const Color scoreboard_easy_color = Color(0X4B, 0X69, 0X2F);
const Color scoreboard_normal_color = Color(0X2E, 0X3F, 0X47);
const Color scoreboard_hard_color = Color(0X76, 0X42, 0X8A);
const Color flash_color = Color(0XFF, 0XFF, 0XFF);
const Color fade_color = Color(0X27, 0X27, 0X36);
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
double distanceSquared(int x1, int y1, int x2, int y2)

View File

@@ -124,6 +124,9 @@ struct Zone
int third_quarter_y; // Anclaje al 75% del eje X
};
// 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
double distanceSquared(int x1, int y1, int x2, int y2);
@@ -203,4 +206,8 @@ extern const Color scoreboard_hard_color;
extern const Color flash_color;
extern const Color fade_color;
extern const Color orange_color;
extern const Color orange_soft_color;
extern const Color orange_soft_color;
extern const Color green_color;
extern const Color blue_sky_color;
extern const Color pink_sky_color;
extern const Color green_sky_color;