Compare commits

50 Commits

Author SHA1 Message Date
2cb22ed013 fix: els globos tenien un parell de setters mal asignats per culpa de buscar y reemplazar
fix: els globos verds s'inicialitzaven amb vy = 0 per gastar abs en lloc de fabs
fix: corregit un bug milenari que de sempre havia creat els balloons verds al popar al pare amb la meitat de velocitat en y. Lo que jo no se es com anava res. Supose que ara el joc serà un poc mes xungo. Quan rebotaven en el piso ja se'ls posava la velocitat bona (crec)
2024-10-20 22:58:15 +02:00
a3a583deb7 Precàrrega dels fitxers amb dades per al mode demostració 2024-10-20 21:23:04 +02:00
b263e0c4be Modificada la estructura on es guarden els datos de la demo 2024-10-20 20:43:03 +02:00
3bf61fc758 fix: no guardar el fitxer de puntuacions en el modo demo 2024-10-20 19:40:09 +02:00
2377815c02 Amb les textures en memoria i compartides ja no puc fer el trick de canvi de paleta per a la flama del segon jugador tal i com està plantejat el codi. Arreglat creant una segona textura 2024-10-20 19:38:28 +02:00
7434869894 Corregit un fallo amagat baix un ifdef ARCADE. Ja he posat que estiga definit per defecte pa que no torne a passar 2024-10-20 15:43:10 +02:00
848d61b5c0 He fet un "manolete" i he pasat a c++ i smartpointers la cárrega de surfaces desde gif. Sembla que no ha petat res
Precárrega i asignació de paletes a les textures
Ara si algú toca una paleta, que siga conscient que la textura es compartida durant tot el joc
2024-10-20 15:36:04 +02:00
cbc9b3f071 Eliminats els últimes defines i passats a enum class 2024-10-20 12:07:55 +02:00
8bca5095da Modificats, estructurats i ben formatats alguns missatges de consola
Canvis en els codis d'eixida del programa
2024-10-20 11:37:26 +02:00
a4b4e188cd Precàrrega de tots els recursos al inici del joc
8.000.000 de cherrypickings que he anat fent pel codi
2024-10-20 11:06:10 +02:00
f23dcae5b6 Creada la classe Resource
Afegida la musica i els sons a Resource
2024-10-19 10:07:14 +02:00
b879673bc2 Mes merdes que faltaven del merge 2024-10-18 17:10:06 +02:00
a8701dbebc Merge branch 'main' of https://gitea.sustancia.synology.me/JailDesigner/coffee_crisis_arcade_edition 2024-10-18 16:53:53 +02:00
afe835914e Revisada la carrega de recursos en game.cpp 2024-10-18 14:07:25 +02:00
808f1595e9 Treballant en la càrrega de animacions desde fitxers 2024-10-17 21:02:28 +02:00
8e8346b2ab Li he demanat a la IA que revente Game::checkInput() que aixo si que era un monstruo amb sombreret i pajarita 2024-10-17 20:05:26 +02:00
1da8f33a5e Llevats tots els ifdef VERBOSE i redirigit cout a null_stream 2024-10-17 19:31:44 +02:00
50a376e582 Comença a estar tot mes o menos be el desaguisao de les classes Sprite. Encara algunes animacions sembla que van massa ràpides 2024-10-17 19:26:39 +02:00
59de566c5b commit de acabar la jornada laboral 2024-10-17 13:57:41 +02:00
db884cb422 Commit de vesprà tirada a la brossa 2024-10-16 22:35:19 +02:00
5585f996cb A vore si el helper ja funciona com toca 2024-10-16 13:29:16 +02:00
24556eeaa8 Implementat contador per a posar el nom al acabar la partida 2024-10-16 09:18:22 +02:00
dbffda491f Retocat l'aspecte visual de les notificacions 2024-10-15 22:56:24 +02:00
53f5f3f8b0 Ja comprova la notificació d'eixir per diferenciarla de la resta
En ARCADE la notificació diferencia si vas a eixir o a apagar el sistema
2024-10-15 20:40:45 +02:00
e0faa0890e Afegides noves cadenes de text 2024-10-15 20:12:16 +02:00
de6508c37c Don Melitonitzada la classe Notifier e independitzada de la classe Screen
Ara es poden afegir codis a les notificacions per identificarles
2024-10-15 20:09:09 +02:00
e99c2c5265 fix: faltava el nom de la classe en shutdownSystem() 2024-10-15 18:58:10 +02:00
942924c65c Afegit codi per apagar el sistema al eixir del joc 2024-10-15 18:24:19 +02:00
089da99b5b Afegida la funció getNewPosition a la classe Screen per a respectar la posició de la finestra al canviarla de tamany 2024-10-15 18:12:16 +02:00
3fdd60c9e2 Treballant en els game_texts 2024-10-15 14:02:37 +02:00
3b9885ab03 Commit de Boromir 2024-10-14 22:33:45 +02:00
39a8c992e1 Ja duplica la ultima lletra al posar el nom 2024-10-14 17:12:07 +02:00
9825c7fb9b Pasaeta de include-what-you-use 2024-10-13 21:58:36 +02:00
d0a6e4c572 Afegits destructors virtuals en les classes Sprite 2024-10-13 21:23:15 +02:00
7c876e1d4d Acabat amb cppcheck
Arreglades les herencies de les classes Sprite
2024-10-13 21:00:33 +02:00
809c10048e Commit pa poder tornar a passar el cppcheck 2024-10-13 19:39:43 +02:00
babf02226c Mes recomanacions de cppcheck 2024-10-13 19:26:27 +02:00
46540ad7c3 Optimitzat el tema de comparacions i asignacions de strings buits. Mes que optimitzat, ara està mes mono 2024-10-13 14:25:05 +02:00
ba7c44ad06 Actualitzat Makefile 2024-10-13 14:24:15 +02:00
46b19ee82f Mes recomanacions de cppcheck aplicades
Abans de tocar unes cosetes de strings buits
2024-10-13 13:49:00 +02:00
b2122ac239 Eliminats fitxers que s'havien colat 2024-10-13 11:04:50 +02:00
c11a868289 Afegides recomanacions de cppcheck
Optimitzada la funció updateBalloonSpeed() i eliminades funcions sobrants o redundants
2024-10-13 11:03:50 +02:00
22d457285d Modificat .gitignore 2024-10-13 11:03:00 +02:00
b060f21696 Arreglades les herencies de Sprite
Abans de llevar mil coses que sobren i replantejar-se estes 4 classes
2024-10-13 10:01:07 +02:00
33ea8d90ca Acabat de renamar, encara que he descobert cosetes i tindré que fer altra pasaeta
Actualitzat stb_image.h a la última versió
2024-10-12 22:25:43 +02:00
cce14dba4d Mes renames. Mes ordre. 2024-10-12 12:03:19 +02:00
101e375fd3 Variables renombrades en input.cpp 2024-10-12 11:01:42 +02:00
4ef759772a game.cpp renombrat 2024-10-12 09:15:20 +02:00
07714aabc3 Abans de renombrar game.cpp 2024-10-12 07:26:41 +02:00
d50cf23721 Abans de renombrar player.cpp 2024-10-11 21:58:59 +02:00
113 changed files with 6567 additions and 6857 deletions

1
.gitignore vendored
View File

@@ -15,3 +15,4 @@ thumbs.db
*score.bin
coffee_crisis*
debug.txt
cppcheck-result*

View File

@@ -25,8 +25,8 @@ INCLUDES:= -I$(DIR_SOURCES)
ifeq ($(OS),Windows_NT)
FixPath = $(subst /,\,$1)
SOURCES := source/*.cpp
CXXFLAGS:= -std=c++14 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows
CXXFLAGS_DEBUG:= -std=c++14 -Wall -g
CXXFLAGS:= -std=c++20 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows
CXXFLAGS_DEBUG:= -std=c++20 -Wall -g
LDFLAGS := -lmingw32 -lws2_32 -lSDL2main -lSDL2 -lopengl32
RM = del /Q
MKD:= mkdir
@@ -34,8 +34,8 @@ else
FixPath = $1
SOURCES := $(shell find $(DIR_SOURCES) -name '*.cpp')
SOURCES := source/*.cpp
CXXFLAGS:= -std=c++14 -Wall -Os -ffunction-sections -fdata-sections
CXXFLAGS_DEBUG:= -std=c++14 -Wall -g
CXXFLAGS:= -std=c++20 -Wall -Os -ffunction-sections -fdata-sections
CXXFLAGS_DEBUG:= -std=c++20 -Wall -g
LDFLAGS := -lSDL2
RM = rm -f
MKD:= mkdir -p

View File

@@ -1,11 +1,12 @@
## GAME
game.item_size 20
game.width 320
game.height 240
game.play_area.rect.x 0
game.play_area.rect.y 0
game.play_area.rect.w 320
game.play_area.rect.h 200
game.item_size 20 # Tamaño de los items del juego
game.width 320 # Ancho de la resolucion nativa del juego
game.height 240 # Alto de la resolucion nativa del juego
game.play_area.rect.x 0 # Rectangulo con la posición de la zona de juego
game.play_area.rect.y 0 # Rectangulo con la posición de la zona de juego
game.play_area.rect.w 320 # Rectangulo con la posición de la zona de juego
game.play_area.rect.h 200 # Rectangulo con la posición de la zona de juego
game.enter_name_seconds 30 # Duración en segundos para introducir el nombre al finalizar la partida
## FADE
fade.num_squares_width 160

View File

@@ -1,11 +1,12 @@
## GAME
game.item_size 20
game.width 320
game.height 256
game.play_area.rect.x 0
game.play_area.rect.y 0
game.play_area.rect.w 320
game.play_area.rect.h 216
game.item_size 20 # Tamaño de los items del juego
game.width 320 # Ancho de la resolucion nativa del juego
game.height 256 # Alto de la resolucion nativa del juego
game.play_area.rect.x 0 # Rectangulo con la posición de la zona de juego
game.play_area.rect.y 0 # Rectangulo con la posición de la zona de juego
game.play_area.rect.w 320 # Rectangulo con la posición de la zona de juego
game.play_area.rect.h 216 # Rectangulo con la posición de la zona de juego
game.enter_name_seconds 30 # Duración en segundos para introducir el nombre al finalizar la partida
## FADE
fade.num_squares_width 160

View File

Before

Width:  |  Height:  |  Size: 84 B

After

Width:  |  Height:  |  Size: 84 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 935 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

View File

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 173 B

View File

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 772 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 929 B

View File

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 173 B

View File

Before

Width:  |  Height:  |  Size: 172 B

After

Width:  |  Height:  |  Size: 172 B

View File

Before

Width:  |  Height:  |  Size: 172 B

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 772 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 941 B

View File

Before

Width:  |  Height:  |  Size: 172 B

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 944 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 B

View File

@@ -281,7 +281,7 @@ MODE FORA DE LINEA
TAULER DE PUNTS
## 94 - NOTIFICACIONES
Torna a polsar per eixir ...
Torna a polsar per eixir
## 95 - DEFINE BUTTONS
Disparar cap a l'esquerra
@@ -344,4 +344,7 @@ Eixir
Per favor
## 115 - MARCADOR
espere
espere
## 116 - NOTIFICACIONES
Torna a polsar per apagar el sistema

View File

@@ -344,4 +344,7 @@ Exit
Please
## 115 - MARCADOR
wait
wait
## 116 - NOTIFICACIONES
Press again to shutdown system

View File

@@ -344,4 +344,7 @@ Salir
Por favor
## 115 - MARCADOR
espere
espere
## 94 - NOTIFICACIONES
Pulsa otra vez para apagar el sistema

View File

@@ -4,7 +4,7 @@ SOURCEPATH=../source/
for i in "$SOURCEPATH"/*.cpp
do
include-what-you-use -D DEBUG -D VERBOSE -std=c++14 -Wall "$i"
include-what-you-use -D DEBUG -D VERBOSE -std=c++20 -Wall "$i"
read -p "Presiona cualquier tecla para continuar..."
clear
done

View File

@@ -1,198 +1,60 @@
#include "animated_sprite.h"
#include <algorithm> // for copy
#include <fstream> // for basic_ostream, operator<<, basic_istream, basic...
#include <iostream> // for cout
#include <iterator> // for back_insert_iterator, back_inserter
#include <sstream> // for basic_stringstream
#include "texture.h" // for Texture
#include "utils.h"
// Carga la animación desde un fichero
AnimatedFile loadAnimationFromFile(std::shared_ptr<Texture> texture, std::string file_path)
// Carga las animaciones en un vector(Animations) desde un fichero
Animations loadAnimationsFromFile(const std::string &file_path)
{
// Inicializa variables
AnimatedFile af;
af.texture = texture;
auto frames_per_row = 0;
auto frame_width = 0;
auto frame_height = 0;
auto max_tiles = 0;
const std::string file_name = file_path.substr(file_path.find_last_of("\\/") + 1);
std::vector<std::string> buffer;
std::ifstream file(file_path);
if (!file)
{
std::cerr << "Error: Fichero no encontrado " << file_path << std::endl;
throw std::runtime_error("Fichero no encontrado: " + file_path);
}
std::string line;
printWithDots("Animation : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]");
// El fichero se puede abrir
if (file.good())
while (std::getline(file, line))
{
// Procesa el fichero linea a linea
#ifdef VERBOSE
std::cout << "Animation loaded: " << file_name << std::endl;
#endif
while (std::getline(file, line))
{
// Si la linea contiene el texto [animation] se realiza el proceso de carga de una animación
if (line == "[animation]")
{
Animation buffer;
buffer.counter = 0;
buffer.current_frame = 0;
buffer.completed = false;
do
{
std::getline(file, line);
// Encuentra la posición del caracter '='
int pos = line.find("=");
// Procesa las dos subcadenas
if (pos != (int)line.npos)
{
if (line.substr(0, pos) == "name")
{
buffer.name = line.substr(pos + 1, line.length());
}
else if (line.substr(0, pos) == "speed")
{
buffer.speed = std::stoi(line.substr(pos + 1, line.length()));
}
else if (line.substr(0, pos) == "loop")
{
buffer.loop = std::stoi(line.substr(pos + 1, line.length()));
}
else if (line.substr(0, pos) == "frames")
{
// Se introducen los valores separados por comas en un vector
std::stringstream ss(line.substr(pos + 1, line.length()));
std::string tmp;
SDL_Rect rect = {0, 0, frame_width, frame_height};
while (getline(ss, tmp, ','))
{
// Comprueba que el tile no sea mayor que el maximo indice permitido
const auto num_tile = std::stoi(tmp) > max_tiles ? 0 : std::stoi(tmp);
rect.x = (num_tile % frames_per_row) * frame_width;
rect.y = (num_tile / frames_per_row) * frame_height;
buffer.frames.push_back(rect);
}
}
else
{
#ifdef VERBOSE
std::cout << "Warning: file " << file_name.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
#endif
}
}
} while (line != "[/animation]");
// Añade la animación al vector de animaciones
af.animations.push_back(buffer);
}
// En caso contrario se parsea el fichero para buscar las variables y los valores
else
{
// Encuentra la posición del caracter '='
int pos = line.find("=");
// Procesa las dos subcadenas
if (pos != (int)line.npos)
{
if (line.substr(0, pos) == "frames_per_row")
{
frames_per_row = std::stoi(line.substr(pos + 1, line.length()));
}
else if (line.substr(0, pos) == "frame_width")
{
frame_width = std::stoi(line.substr(pos + 1, line.length()));
}
else if (line.substr(0, pos) == "frame_height")
{
frame_height = std::stoi(line.substr(pos + 1, line.length()));
}
else
{
#ifdef VERBOSE
std::cout << "Warning: file " << file_name.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
#endif
}
// Normaliza valores
if (frames_per_row == 0 && frame_width > 0)
{
frames_per_row = texture->getWidth() / frame_width;
}
if (max_tiles == 0 && frame_width > 0 && frame_height > 0)
{
const auto w = texture->getWidth() / frame_width;
const auto h = texture->getHeight() / frame_height;
max_tiles = w * h;
}
}
}
}
// Cierra el fichero
file.close();
}
// El fichero no se puede abrir
else
{
#ifdef VERBOSE
std::cout << "Warning: Unable to open " << file_name.c_str() << " file" << std::endl;
#endif
buffer.push_back(line);
}
return af;
return buffer;
}
// Constructor
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, std::string file, std::vector<std::string> *buffer)
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const std::string &file_path)
: MovingSprite(texture),
current_animation_(0)
{
// Copia los punteros
setTexture(texture);
// Carga las animaciones
if (file != "")
if (!file_path.empty())
{
AnimatedFile as = loadAnimationFromFile(texture, file);
// Copia los datos de las animaciones
for (auto animation : as.animations)
{
animations_.push_back(animation);
}
animations_ = loadFromFile(file_path);
}
}
else if (buffer)
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const Animations &animations)
: MovingSprite(texture),
current_animation_(0)
{
if (!animations.empty())
{
loadFromVector(buffer);
loadFromVector(animations);
}
// Inicializa variables
current_animation_ = 0;
}
// Constructor
AnimatedSprite::AnimatedSprite(AnimatedFile *animation)
{
// Copia los punteros
setTexture(animation->texture);
// Inicializa variables
current_animation_ = 0;
// Copia los datos de las animaciones
for (auto a : animation->animations)
{
animations_.push_back(a);
}
}
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture)
: MovingSprite(texture),
current_animation_(0) {}
// Destructor
AnimatedSprite::~AnimatedSprite()
@@ -201,11 +63,11 @@ AnimatedSprite::~AnimatedSprite()
}
// Obtiene el indice de la animación a partir del nombre
int AnimatedSprite::getIndex(std::string name)
int AnimatedSprite::getIndex(const std::string &name)
{
auto index = -1;
for (auto a : animations_)
for (const auto &a : animations_)
{
index++;
if (a.name == name)
@@ -213,16 +75,14 @@ int AnimatedSprite::getIndex(std::string name)
return index;
}
}
#ifdef VERBOSE
std::cout << "** Warning: could not find \"" << name.c_str() << "\" animation" << std::endl;
#endif
return -1;
}
// Calcula el frame correspondiente a la animación
void AnimatedSprite::animate()
{
if (!enabled_ || animations_[current_animation_].speed == 0)
if (animations_[current_animation_].speed == 0)
{
return;
}
@@ -280,13 +140,13 @@ void AnimatedSprite::setCurrentFrame(int num)
}
// Establece el valor del contador
void AnimatedSprite::setAnimationCounter(std::string name, int num)
void AnimatedSprite::setAnimationCounter(const std::string &name, int num)
{
animations_[getIndex(name)].counter = num;
}
// Establece la velocidad de una animación
void AnimatedSprite::setAnimationSpeed(std::string name, int speed)
void AnimatedSprite::setAnimationSpeed(const std::string &name, int speed)
{
animations_[getIndex(name)].counter = speed;
}
@@ -298,7 +158,7 @@ void AnimatedSprite::setAnimationSpeed(int index, int speed)
}
// Establece si la animación se reproduce en bucle
void AnimatedSprite::setAnimationLoop(std::string name, int loop)
void AnimatedSprite::setAnimationLoop(const std::string &name, int loop)
{
animations_[getIndex(name)].loop = loop;
}
@@ -310,7 +170,7 @@ void AnimatedSprite::setAnimationLoop(int index, int loop)
}
// Establece el valor de la variable
void AnimatedSprite::setAnimationCompleted(std::string name, bool value)
void AnimatedSprite::setAnimationCompleted(const std::string &name, bool value)
{
animations_[getIndex(name)].completed = value;
}
@@ -328,7 +188,7 @@ bool AnimatedSprite::animationIsCompleted()
}
// Devuelve el rectangulo de una animación y frame concreto
SDL_Rect AnimatedSprite::getAnimationClip(std::string name, Uint8 index)
SDL_Rect AnimatedSprite::getAnimationClip(const std::string &name, Uint8 index)
{
return animations_[getIndex(name)].frames[index];
}
@@ -339,8 +199,203 @@ SDL_Rect AnimatedSprite::getAnimationClip(int indexA, Uint8 indexF)
return animations_[indexA].frames[indexF];
}
// Establece la animacion actual
void AnimatedSprite::setCurrentAnimation(const std::string &name)
{
const auto new_animation = getIndex(name);
if (current_animation_ != new_animation)
{
current_animation_ = new_animation;
animations_[current_animation_].current_frame = 0;
animations_[current_animation_].counter = 0;
animations_[current_animation_].completed = false;
}
}
// Establece la animacion actual
void AnimatedSprite::setCurrentAnimation(int index)
{
const auto new_animation = index;
if (current_animation_ != new_animation)
{
current_animation_ = new_animation;
animations_[current_animation_].current_frame = 0;
animations_[current_animation_].counter = 0;
animations_[current_animation_].completed = false;
}
}
// Actualiza las variables del objeto
void AnimatedSprite::update()
{
animate();
MovingSprite::update();
}
// Establece el rectangulo para un frame de una animación
void AnimatedSprite::setAnimationFrames(Uint8 index_animation, Uint8 index_frame, int x, int y, int w, int h)
{
animations_[index_animation].frames.push_back({x, y, w, h});
}
// OLD - Establece el contador para todas las animaciones
void AnimatedSprite::setAnimationCounter(int value)
{
for (auto &a : animations_)
{
a.counter = value;
}
}
// Reinicia la animación
void AnimatedSprite::resetAnimation()
{
animations_[current_animation_].current_frame = 0;
animations_[current_animation_].counter = 0;
animations_[current_animation_].completed = false;
}
// Carga la animación desde un fichero
std::vector<Animation> AnimatedSprite::loadFromFile(const std::string &file_path)
{
// Inicializa variables
std::vector<Animation> animations;
auto frames_per_row = 0;
auto frame_width = 0;
auto frame_height = 0;
auto max_tiles = 0;
const std::string file_name = file_path.substr(file_path.find_last_of("\\/") + 1);
std::ifstream file(file_path);
std::string line;
// El fichero se puede abrir
if (file.good())
{
// Procesa el fichero linea a linea
std::cout << "Animation loaded: " << file_name << std::endl;
while (std::getline(file, line))
{
// Si la linea contiene el texto [animation] se realiza el proceso de carga de una animación
if (line == "[animation]")
{
Animation animation = Animation();
do
{
std::getline(file, line);
// Encuentra la posición del caracter '='
int pos = line.find("=");
// Procesa las dos subcadenas
if (pos != static_cast<int>(line.npos))
{
if (line.substr(0, pos) == "name")
{
animation.name = line.substr(pos + 1, line.length());
}
else if (line.substr(0, pos) == "speed")
{
animation.speed = std::stoi(line.substr(pos + 1, line.length()));
}
else if (line.substr(0, pos) == "loop")
{
animation.loop = std::stoi(line.substr(pos + 1, line.length()));
}
else if (line.substr(0, pos) == "frames")
{
// Se introducen los valores separados por comas en un vector
std::stringstream ss(line.substr(pos + 1, line.length()));
std::string tmp;
SDL_Rect rect = {0, 0, frame_width, frame_height};
while (getline(ss, tmp, ','))
{
// Comprueba que el tile no sea mayor que el maximo indice permitido
const auto num_tile = std::stoi(tmp) > max_tiles ? 0 : std::stoi(tmp);
rect.x = (num_tile % frames_per_row) * frame_width;
rect.y = (num_tile / frames_per_row) * frame_height;
animation.frames.push_back(rect);
}
}
else
{
std::cout << "Warning: file " << file_name.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
}
}
} while (line != "[/animation]");
// Añade la animación al vector de animaciones
animations.push_back(animation);
}
// En caso contrario se parsea el fichero para buscar las variables y los valores
else
{
// Encuentra la posición del caracter '='
int pos = line.find("=");
// Procesa las dos subcadenas
if (pos != (int)line.npos)
{
if (line.substr(0, pos) == "frames_per_row")
{
frames_per_row = std::stoi(line.substr(pos + 1, line.length()));
}
else if (line.substr(0, pos) == "frame_width")
{
frame_width = std::stoi(line.substr(pos + 1, line.length()));
}
else if (line.substr(0, pos) == "frame_height")
{
frame_height = std::stoi(line.substr(pos + 1, line.length()));
}
else
{
std::cout << "Warning: file " << file_name.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
}
// Normaliza valores
if (frames_per_row == 0 && frame_width > 0)
{
frames_per_row = texture_->getWidth() / frame_width;
}
if (max_tiles == 0 && frame_width > 0 && frame_height > 0)
{
const auto w = texture_->getWidth() / frame_width;
const auto h = texture_->getHeight() / frame_height;
max_tiles = w * h;
}
}
}
}
// Cierra el fichero
file.close();
}
// El fichero no se puede abrir
else
{
std::cout << "Warning: Unable to open " << file_name.c_str() << " file" << std::endl;
}
// Pone un valor por defecto
setWidth(frame_width);
setHeight(frame_height);
return animations;
}
// Carga la animación desde un vector
bool AnimatedSprite::loadFromVector(std::vector<std::string> *source)
bool AnimatedSprite::loadFromVector(const Animations &source)
{
// Inicializa variables
auto frames_per_row = 0;
@@ -354,44 +409,41 @@ bool AnimatedSprite::loadFromVector(std::vector<std::string> *source)
// Recorre todo el vector
auto index = 0;
while (index < (int)source->size())
while (index < (int)source.size())
{
// Lee desde el vector
line = source->at(index);
line = source.at(index);
// Si la linea contiene el texto [animation] se realiza el proceso de carga de una animación
if (line == "[animation]")
{
Animation buffer;
buffer.counter = 0;
buffer.current_frame = 0;
buffer.completed = false;
Animation animation = Animation();
do
{
// Aumenta el indice para leer la siguiente linea
index++;
line = source->at(index);
line = source.at(index);
// Encuentra la posición del caracter '='
int pos = line.find("=");
// Procesa las dos subcadenas
if (pos != (int)line.npos)
if (pos != static_cast<int>(line.npos))
{
if (line.substr(0, pos) == "name")
{
buffer.name = line.substr(pos + 1, line.length());
animation.name = line.substr(pos + 1, line.length());
}
else if (line.substr(0, pos) == "speed")
{
buffer.speed = std::stoi(line.substr(pos + 1, line.length()));
animation.speed = std::stoi(line.substr(pos + 1, line.length()));
}
else if (line.substr(0, pos) == "loop")
{
buffer.loop = std::stoi(line.substr(pos + 1, line.length()));
animation.loop = std::stoi(line.substr(pos + 1, line.length()));
}
else if (line.substr(0, pos) == "frames")
@@ -406,22 +458,20 @@ bool AnimatedSprite::loadFromVector(std::vector<std::string> *source)
const int num_tile = std::stoi(tmp) > max_tiles ? 0 : std::stoi(tmp);
rect.x = (num_tile % frames_per_row) * frame_width;
rect.y = (num_tile / frames_per_row) * frame_height;
buffer.frames.push_back(rect);
animation.frames.push_back(rect);
}
}
else
{
#ifdef VERBOSE
std::cout << "Warning: unknown parameter " << line.substr(0, pos).c_str() << std::endl;
#endif
success = false;
}
}
} while (line != "[/animation]");
// Añade la animación al vector de animaciones
animations_.push_back(buffer);
animations_.push_back(animation);
}
// En caso contrario se parsea el fichero para buscar las variables y los valores
@@ -450,9 +500,7 @@ bool AnimatedSprite::loadFromVector(std::vector<std::string> *source)
else
{
#ifdef VERBOSE
std::cout << "Warning: unknown parameter " << line.substr(0, pos).c_str() << std::endl;
#endif
success = false;
}
@@ -476,66 +524,8 @@ bool AnimatedSprite::loadFromVector(std::vector<std::string> *source)
}
// Pone un valor por defecto
setRect({0, 0, frame_width, frame_height});
setWidth(frame_width);
setHeight(frame_height);
return success;
}
// Establece la animacion actual
void AnimatedSprite::setCurrentAnimation(std::string name)
{
const auto new_animation = getIndex(name);
if (current_animation_ != new_animation)
{
current_animation_ = new_animation;
animations_[current_animation_].current_frame = 0;
animations_[current_animation_].counter = 0;
animations_[current_animation_].completed = false;
}
}
// Establece la animacion actual
void AnimatedSprite::setCurrentAnimation(int index)
{
const auto new_animation = index;
if (current_animation_ != new_animation)
{
current_animation_ = new_animation;
animations_[current_animation_].current_frame = 0;
animations_[current_animation_].counter = 0;
animations_[current_animation_].completed = false;
}
}
// Actualiza las variables del objeto
void AnimatedSprite::update()
{
if (enabled_)
{
animate();
MovingSprite::update();
}
}
// Establece el rectangulo para un frame de una animación
void AnimatedSprite::setAnimationFrames(Uint8 index_animation, Uint8 index_frame, int x, int y, int w, int h)
{
animations_[index_animation].frames.push_back({x, y, w, h});
}
// OLD - Establece el contador para todas las animaciones
void AnimatedSprite::setAnimationCounter(int value)
{
for (auto &a : animations_)
{
a.counter = value;
}
}
// Reinicia la animación
void AnimatedSprite::resetAnimation()
{
animations_[current_animation_].current_frame = 0;
animations_[current_animation_].counter = 0;
animations_[current_animation_].completed = false;
}

View File

@@ -2,11 +2,11 @@
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_stdinc.h> // for Uint8
#include <string> // for string, basic_string
#include <memory> // for shared_ptr
#include <string> // for string
#include <vector> // for vector
#include "moving_sprite.h" // for MovingSprite
#include "texture.h"
#include <memory>
class Texture;
struct Animation
{
@@ -17,35 +17,43 @@ struct Animation
bool completed; // Indica si ha finalizado la animación
int current_frame; // Frame actual
int counter; // Contador para las animaciones
Animation() : name(std::string()), speed(5), loop(0), completed(false), current_frame(0), counter(0) {}
};
struct AnimatedFile
{
std::vector<Animation> animations; // Vector con las diferentes animaciones
std::shared_ptr<Texture> texture; // Textura con los graficos para el sprite
};
using Animations = std::vector<std::string>;
// Carga la animación desde un fichero
AnimatedFile loadAnimationFromFile(std::shared_ptr<Texture> texture, std::string filePath);
// Carga las animaciones en un vector(Animations) desde un fichero
Animations loadAnimationsFromFile(const std::string &file_path);
class AnimatedSprite : public MovingSprite
{
private:
protected:
// Variables
std::vector<Animation> animations_; // Vector con las diferentes animaciones
int current_animation_; // Animacion activa
public:
// Constructor
AnimatedSprite(std::shared_ptr<Texture> texture = nullptr, std::string file = "", std::vector<std::string> *buffer = nullptr);
AnimatedSprite(AnimatedFile *animation);
// Destructor
~AnimatedSprite();
// Calcula el frame correspondiente a la animación actual
void animate();
// Carga la animación desde un fichero
std::vector<Animation> loadFromFile(const std::string &file_path);
// Carga la animación desde un vector
bool loadFromVector(const Animations &source);
public:
// Constructor
AnimatedSprite(std::shared_ptr<Texture> texture, const std::string &file_path);
AnimatedSprite(std::shared_ptr<Texture> texture, const Animations &animations);
explicit AnimatedSprite(std::shared_ptr<Texture> texture);
// Destructor
virtual ~AnimatedSprite();
// Actualiza las variables del objeto
void update() override;
// Obtiene el número de frames de la animación actual
int getNumFrames();
@@ -53,40 +61,34 @@ public:
void setCurrentFrame(int num);
// Establece el valor del contador
void setAnimationCounter(std::string name, int num);
void setAnimationCounter(const std::string &name, int num);
// Establece la velocidad de una animación
void setAnimationSpeed(std::string name, int speed);
void setAnimationSpeed(const std::string &name, int speed);
void setAnimationSpeed(int index, int speed);
// Establece el frame al que vuelve la animación al finalizar
void setAnimationLoop(std::string name, int loop);
void setAnimationLoop(const std::string &name, int loop);
void setAnimationLoop(int index, int loop);
// Establece el valor de la variable
void setAnimationCompleted(std::string name, bool value);
void setAnimationCompleted(const std::string &name, bool value);
void setAnimationCompleted(int index, bool value);
// Comprueba si ha terminado la animación
bool animationIsCompleted();
// Devuelve el rectangulo de una animación y frame concreto
SDL_Rect getAnimationClip(std::string name = "default", Uint8 index = 0);
SDL_Rect getAnimationClip(const std::string &name = "default", Uint8 index = 0);
SDL_Rect getAnimationClip(int indexA = 0, Uint8 indexF = 0);
// Obtiene el indice de la animación a partir del nombre
int getIndex(std::string name);
// Carga la animación desde un vector
bool loadFromVector(std::vector<std::string> *source);
int getIndex(const std::string &name);
// Establece la animacion actual
void setCurrentAnimation(std::string name = "default");
void setCurrentAnimation(const std::string &name = "default");
void setCurrentAnimation(int index = 0);
// Actualiza las variables del objeto
void update();
// OLD - Establece el rectangulo para un frame de una animación
void setAnimationFrames(Uint8 index_animation, Uint8 index_frame, int x, int y, int w, int h);

View File

@@ -1,39 +1,40 @@
#include "asset.h"
#include "utils.h"
#include <SDL2/SDL_rwops.h> // for SDL_RWFromFile, SDL_RWclose, SDL_RWops
#include <SDL2/SDL_stdinc.h> // for SDL_max
#include <stddef.h> // for size_t
#include <iostream> // for basic_ostream, operator<<, cout, endl
// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado
Asset *Asset::asset = nullptr;
Asset *Asset::asset_ = nullptr;
// [SINGLETON] Crearemos el objeto asset con esta función estática
void Asset::init(std::string executable_path)
void Asset::init(const std::string &executable_path)
{
Asset::asset = new Asset(executable_path);
Asset::asset_ = new Asset(executable_path);
}
// [SINGLETON] Destruiremos el objeto asset con esta función estática
void Asset::destroy()
{
delete Asset::asset;
delete Asset::asset_;
}
// [SINGLETON] Con este método obtenemos el objeto asset y podemos trabajar con él
Asset *Asset::get()
{
return Asset::asset;
return Asset::asset_;
}
// Constructor
Asset::Asset(std::string executable_path)
Asset::Asset(const std::string &executable_path)
: executable_path_(executable_path.substr(0, executable_path.find_last_of("\\/")))
{
executable_path_ = executable_path.substr(0, executable_path.find_last_of("\\/"));
longest_name_ = 0;
}
// Añade un elemento a la lista
void Asset::add(std::string file, AssetType type, bool required, bool absolute)
void Asset::add(const std::string &file, AssetType type, bool required, bool absolute)
{
AssetItem ai;
ai.file = absolute ? file : executable_path_ + file;
@@ -46,9 +47,9 @@ void Asset::add(std::string file, AssetType type, bool required, bool absolute)
}
// Devuelve el fichero de un elemento de la lista a partir de una cadena
std::string Asset::get(std::string text) const
std::string Asset::get(const std::string &text) const
{
for (auto f : file_list_)
for (const auto &f : file_list_)
{
const size_t last_index = f.file.find_last_of("/") + 1;
const std::string file = f.file.substr(last_index, std::string::npos);
@@ -59,9 +60,7 @@ std::string Asset::get(std::string text) const
}
}
#ifdef VERBOSE
std::cout << "Warning: file " << text.c_str() << " not found" << std::endl;
#endif
return "";
}
@@ -70,12 +69,10 @@ bool Asset::check() const
{
bool success = true;
#ifdef VERBOSE
std::cout << "\n** Checking files" << std::endl;
std::cout << "\n** CHECKING FILES" << std::endl;
std::cout << "Executable path is: " << executable_path_ << std::endl;
std::cout << "Sample filepath: " << file_list_.back().file << std::endl;
#endif
// std::cout << "Executable path is: " << executable_path_ << std::endl;
// std::cout << "Sample filepath: " << file_list_.back().file << std::endl;
// Comprueba la lista de ficheros clasificandolos por tipo
for (int type = 0; type < static_cast<int>(AssetType::MAX_ASSET_TYPE); ++type)
@@ -83,7 +80,7 @@ bool Asset::check() const
// Comprueba si hay ficheros de ese tipo
bool any = false;
for (auto f : file_list_)
for (const auto &f : file_list_)
{
if (f.required && f.type == static_cast<AssetType>(type))
{
@@ -94,53 +91,43 @@ bool Asset::check() const
// Si hay ficheros de ese tipo, comprueba si existen
if (any)
{
#ifdef VERBOSE
std::cout << "\n>> " << getTypeName(static_cast<AssetType>(type)).c_str() << " FILES" << std::endl;
#endif
for (auto f : file_list_)
for (const auto &f : file_list_)
{
if (f.required && f.type == static_cast<AssetType>(type))
{
success &= checkFile(f.file);
}
}
if (success)
std::cout << " All files are OK." << std::endl;
}
}
// Resultado
#ifdef VERBOSE
std::cout << (success ? "\n** All files OK.\n" : "\n** A file is missing. Exiting.\n") << std::endl;
#endif
// Resultado
std::cout << (success ? "\n** CHECKING FILES COMPLETED.\n" : "\n** CHECKING FILES FAILED.\n") << std::endl;
return success;
}
// Comprueba que existe un fichero
bool Asset::checkFile(std::string path) const
bool Asset::checkFile(const std::string &path) const
{
bool success = false;
std::string result = "ERROR";
auto success = false;
// Comprueba si existe el fichero
const std::string file_name = path.substr(path.find_last_of("\\/") + 1);
SDL_RWops *file = SDL_RWFromFile(path.c_str(), "rb");
auto file = SDL_RWFromFile(path.c_str(), "rb");
if (file != nullptr)
if (file)
{
result = "OK";
success = true;
SDL_RWclose(file);
}
#ifdef VERBOSE
std::cout.setf(std::ios::left, std::ios::adjustfield);
std::cout << "Checking file: ";
std::cout.width(longest_name_ + 2);
std::cout.fill('.');
std::cout << file_name + " ";
std::cout << " [" + result + "]" << std::endl;
#endif
const std::string file_name = path.substr(path.find_last_of("\\/") + 1);
if (!success)
printWithDots("Checking file : ", file_name, (success ? " [ OK ]" : " [ ERROR ]"));
return success;
}

View File

@@ -1,7 +1,7 @@
#pragma once
#include <string> // for string, basic_string
#include <vector> // for vector
#include <string> // for string, basic_string
#include <vector> // for vector
enum class AssetType : int
{
@@ -22,7 +22,7 @@ class Asset
{
private:
// [SINGLETON] Objeto asset privado para Don Melitón
static Asset *asset;
static Asset *asset_;
// Estructura para definir un item
struct AssetItem
@@ -34,25 +34,25 @@ private:
};
// Variables
int longest_name_; // Contiene la longitud del nombre de fichero mas largo
int longest_name_; // Contiene la longitud del nombre de fichero mas largo
std::vector<AssetItem> file_list_; // Listado con todas las rutas a los ficheros
std::string executable_path_; // Ruta al ejecutable
std::string executable_path_; // Ruta al ejecutable
// Comprueba que existe un fichero
bool checkFile(std::string executable_path) const;
bool checkFile(const std::string &path) const;
// Devuelve el nombre del tipo de recurso
std::string getTypeName(AssetType type) const;
// Constructor
Asset(std::string path);
explicit Asset(const std::string &executable_path);
// Destructor
~Asset() = default;
public:
// [SINGLETON] Crearemos el objeto screen con esta función estática
static void init(std::string path);
static void init(const std::string &executable_path);
// [SINGLETON] Destruiremos el objeto screen con esta función estática
static void destroy();
@@ -61,10 +61,10 @@ public:
static Asset *get();
// Añade un elemento a la lista
void add(std::string file, AssetType type, bool required = true, bool absolute = false);
void add(const std::string &file, AssetType type, bool required = true, bool absolute = false);
// Devuelve un elemento de la lista a partir de una cadena
std::string get(std::string text) const;
std::string get(const std::string &text) const;
// Comprueba que existen todos los elementos
bool check() const;

View File

@@ -1,79 +1,98 @@
#include "background.h"
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND
#include <SDL2/SDL_pixels.h> // for SDL_PIXELFORMAT_RGBA8888
#include <algorithm> // for max, min
#include <string> // for basic_string
#include <algorithm> // for clamp, max
#include "asset.h" // for Asset
#include "moving_sprite.h" // for MovingSprite
#include "param.h" // for param
#include "resource.h" // for Resource
#include "screen.h"
#include "sprite.h" // for Sprite
#include "texture.h" // for Texture
// Constructor
Background::Background(SDL_Renderer *renderer)
: renderer_(renderer)
Background::Background()
: renderer_(Screen::get()->getRenderer()),
buildings_texture_(Resource::get()->getTexture("game_buildings.png")),
top_clouds_texture_(Resource::get()->getTexture("game_clouds1.png")),
bottom_clouds_texture_(Resource::get()->getTexture("game_clouds2.png")),
grass_texture_(Resource::get()->getTexture("game_grass.png")),
gradients_texture_(Resource::get()->getTexture("game_sky_colors.png")),
gradient_number_(0),
alpha_(0),
clouds_speed_(0),
transition_(0),
counter_(0),
rect_({0, 0, gradients_texture_->getWidth() / 2, gradients_texture_->getHeight() / 2}),
src_rect_({0, 0, 320, 240}),
dst_rect_({0, 0, 320, 240}),
base_(rect_.h),
color_({param.background.attenuate_color.r, param.background.attenuate_color.g, param.background.attenuate_color.b}),
alpha_color_text_(param.background.attenuate_alpha),
alpha_color_text_temp_(param.background.attenuate_alpha)
{
// Carga las texturas
buildings_texture_ = std::make_shared<Texture>(renderer, Asset::get()->get("game_buildings.png"));
top_clouds_texture_ = std::make_shared<Texture>(renderer, Asset::get()->get("game_clouds1.png"));
bottom_clouds_texture_ = std::make_shared<Texture>(renderer, Asset::get()->get("game_clouds2.png"));
grass_texture_ = std::make_shared<Texture>(renderer, Asset::get()->get("game_grass.png"));
gradients_texture_ = std::make_shared<Texture>(renderer, Asset::get()->get("game_sky_colors.png"));
// Inicializa variables
gradient_number_ = 0;
alpha_ = 0;
clouds_speed_ = 0;
transition_ = 0;
counter_ = 0;
rect_ = {0, 0, gradients_texture_->getWidth() / 2, gradients_texture_->getHeight() / 2};
src_rect_ = {0, 0, 320, 240};
dst_rect_ = {0, 0, 320, 240};
base_ = rect_.h;
color_ = {param.background.attenuate_color.r, param.background.attenuate_color.g, param.background.attenuate_color.b};
alpha_color_text_ = alpha_color_text_temp_ = param.background.attenuate_alpha;
gradient_rect_[0] = {0, 0, rect_.w, rect_.h};
gradient_rect_[1] = {rect_.w, 0, rect_.w, rect_.h};
gradient_rect_[2] = {0, rect_.h, rect_.w, rect_.h};
gradient_rect_[3] = {rect_.w, rect_.h, rect_.w, rect_.h};
const int top_clouds_texture_height = top_clouds_texture_->getHeight() / 4;
const int bottom_clouds_texture_height = bottom_clouds_texture_->getHeight() / 4;
for (int i = 0; i < 4; ++i)
{
top_clouds_rect_[i] = {0, i * top_clouds_texture_height, top_clouds_texture_->getWidth(), top_clouds_texture_height};
bottom_clouds_rect_[i] = {0, i * bottom_clouds_texture_height, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_height};
gradient_rect_[0] = {0, 0, rect_.w, rect_.h};
gradient_rect_[1] = {rect_.w, 0, rect_.w, rect_.h};
gradient_rect_[2] = {0, rect_.h, rect_.w, rect_.h};
gradient_rect_[3] = {rect_.w, rect_.h, rect_.w, rect_.h};
const int top_clouds_texture_height = top_clouds_texture_->getHeight() / 4;
const int bottom_clouds_texture_height = bottom_clouds_texture_->getHeight() / 4;
for (int i = 0; i < 4; ++i)
{
top_clouds_rect_[i] = {0, i * top_clouds_texture_height, top_clouds_texture_->getWidth(), top_clouds_texture_height};
bottom_clouds_rect_[i] = {0, i * bottom_clouds_texture_height, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_height};
}
}
// Crea los sprites
const int top_clouds_y = base_ - 165;
const int bottom_clouds_y = base_ - 101;
constexpr float top_clouds_speed = 0.1f;
constexpr float bottom_clouds_speed = 0.05f;
top_clouds_sprite_a_ = std::make_unique<MovingSprite>(0, top_clouds_y, rect_.w, top_clouds_texture_->getHeight(), -top_clouds_speed, 0.0f, 0.0f, 0.0f, top_clouds_texture_);
top_clouds_sprite_b_ = std::make_unique<MovingSprite>(rect_.w, top_clouds_y, rect_.w, top_clouds_texture_->getHeight(), -top_clouds_speed, 0.0f, 0.0f, 0.0f, top_clouds_texture_);
{
const int top_clouds_y = base_ - 165;
const int bottom_clouds_y = base_ - 101;
bottom_clouds_sprite_a_ = std::make_unique<MovingSprite>(0, bottom_clouds_y, rect_.w, bottom_clouds_texture_->getHeight(), -bottom_clouds_speed, 0.0f, 0.0f, 0.0f, bottom_clouds_texture_);
bottom_clouds_sprite_b_ = std::make_unique<MovingSprite>(rect_.w, bottom_clouds_y, rect_.w, bottom_clouds_texture_->getHeight(), -bottom_clouds_speed, 0.0f, 0.0f, 0.0f, bottom_clouds_texture_);
top_clouds_sprite_a_ = std::make_unique<MovingSprite>(top_clouds_texture_, (SDL_Rect){0, top_clouds_y, rect_.w, top_clouds_texture_->getHeight()});
top_clouds_sprite_b_ = std::make_unique<MovingSprite>(top_clouds_texture_, (SDL_Rect){rect_.w, top_clouds_y, rect_.w, top_clouds_texture_->getHeight()});
buildings_sprite_ = std::make_unique<Sprite>(0, 0, buildings_texture_->getWidth(), buildings_texture_->getHeight(), buildings_texture_);
gradient_sprite_ = std::make_unique<Sprite>(0, 0, rect_.w, rect_.h, gradients_texture_);
grass_sprite_ = std::make_unique<Sprite>(0, 0, grass_texture_->getWidth(), grass_texture_->getHeight() / 2, grass_texture_);
bottom_clouds_sprite_a_ = std::make_unique<MovingSprite>(bottom_clouds_texture_, (SDL_Rect){0, bottom_clouds_y, rect_.w, bottom_clouds_texture_->getHeight()});
bottom_clouds_sprite_b_ = std::make_unique<MovingSprite>(bottom_clouds_texture_, (SDL_Rect){rect_.w, bottom_clouds_y, rect_.w, bottom_clouds_texture_->getHeight()});
buildings_sprite_ = std::make_unique<Sprite>(buildings_texture_, 0, 0, buildings_texture_->getWidth(), buildings_texture_->getHeight());
gradient_sprite_ = std::make_unique<Sprite>(gradients_texture_, 0, 0, rect_.w, rect_.h);
grass_sprite_ = std::make_unique<Sprite>(grass_texture_, 0, 0, grass_texture_->getWidth(), grass_texture_->getHeight() / 2);
}
// Inicializa objetos
top_clouds_sprite_a_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight());
top_clouds_sprite_b_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight());
bottom_clouds_sprite_a_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight());
bottom_clouds_sprite_b_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight());
buildings_sprite_->setPosY(base_ - buildings_sprite_->getHeight());
grass_sprite_->setPosY(base_ - grass_sprite_->getHeight());
{
constexpr float top_clouds_speed = 0.1f;
constexpr float bottom_clouds_speed = 0.05f;
top_clouds_sprite_a_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight());
top_clouds_sprite_a_->setVelX(-top_clouds_speed);
top_clouds_sprite_b_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight());
top_clouds_sprite_b_->setVelX(-top_clouds_speed);
bottom_clouds_sprite_a_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight());
bottom_clouds_sprite_a_->setVelX(-bottom_clouds_speed);
bottom_clouds_sprite_b_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight());
bottom_clouds_sprite_b_->setVelX(-bottom_clouds_speed);
buildings_sprite_->setY(base_ - buildings_sprite_->getHeight());
grass_sprite_->setY(base_ - grass_sprite_->getHeight());
}
// Crea la textura para componer el fondo
canvas_ = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h);
canvas_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h);
SDL_SetTextureBlendMode(canvas_, SDL_BLENDMODE_BLEND);
// Crea la textura para atenuar el fondo
color_texture_ = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h);
color_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h);
SDL_SetTextureBlendMode(color_texture_, SDL_BLENDMODE_BLEND);
setColor(color_);
SDL_SetTextureAlphaMod(color_texture_, alpha_color_text_);
@@ -102,20 +121,21 @@ void Background::update()
alpha_ = std::max((255 - (int)(255 * transition_)), 0);
// Incrementa el contador
counter_++;
++counter_;
// Compone todos los elementos del fondo en la textura
fillCanvas();
}
// Dibuja el gradiente de fondo
void Background::renderGradient()
{
// Dibuja el gradiente 2
// Dibuja el gradiente de detras
gradients_texture_->setAlpha(255);
gradient_sprite_->setSpriteClip(gradient_rect_[(gradient_number_ + 1) % 4]);
gradient_sprite_->render();
// Dibuja el gradiente 1 con una opacidad cada vez menor
// Dibuja el gradiente de delante con una opacidad cada vez menor
gradients_texture_->setAlpha(alpha_);
gradient_sprite_->setSpriteClip(gradient_rect_[gradient_number_]);
gradient_sprite_->render();
@@ -124,36 +144,36 @@ void Background::renderGradient()
// Dibuja las nubes de arriba
void Background::renderTopClouds()
{
// Dibuja el primer conjunto de nubes
// Dibuja el primer conjunto de nubes, las de detras
top_clouds_texture_->setAlpha(255);
top_clouds_sprite_a_->setSpriteClip(top_clouds_rect_[(gradient_number_ + 1) % 4]);
top_clouds_sprite_a_->render();
top_clouds_sprite_b_->setSpriteClip(top_clouds_rect_[(gradient_number_ + 1) % 4]);
top_clouds_sprite_a_->render();
top_clouds_sprite_b_->render();
// Dibuja el segundo conjunto de nubes
// Dibuja el segundo conjunto de nubes, las de delante
top_clouds_texture_->setAlpha(alpha_);
top_clouds_sprite_a_->setSpriteClip(top_clouds_rect_[gradient_number_]);
top_clouds_sprite_a_->render();
top_clouds_sprite_b_->setSpriteClip(top_clouds_rect_[gradient_number_]);
top_clouds_sprite_a_->render();
top_clouds_sprite_b_->render();
}
// Dibuja las nubes de abajo
void Background::renderBottomClouds()
{
// Dibuja el primer conjunto de nubes
// Dibuja el primer conjunto de nubes, las de detras
bottom_clouds_texture_->setAlpha(255);
bottom_clouds_sprite_a_->setSpriteClip(bottom_clouds_rect_[(gradient_number_ + 1) % 4]);
bottom_clouds_sprite_a_->render();
bottom_clouds_sprite_b_->setSpriteClip(bottom_clouds_rect_[(gradient_number_ + 1) % 4]);
bottom_clouds_sprite_a_->render();
bottom_clouds_sprite_b_->render();
// Dibuja el segundo conjunto de nubes
// Dibuja el segundo conjunto de nubes, las de delante
bottom_clouds_texture_->setAlpha(alpha_);
bottom_clouds_sprite_a_->setSpriteClip(bottom_clouds_rect_[gradient_number_]);
bottom_clouds_sprite_a_->render();
bottom_clouds_sprite_b_->setSpriteClip(bottom_clouds_rect_[gradient_number_]);
bottom_clouds_sprite_a_->render();
bottom_clouds_sprite_b_->render();
}
@@ -218,9 +238,7 @@ void Background::setGradientNumber(int value)
// Ajusta el valor de la variable
void Background::setTransition(float value)
{
value = std::min(value, 1.0f);
value = std::max(value, 0.0f);
transition_ = value;
transition_ = std::clamp(value, 0.0f, 1.0f);
}
// Establece la posición del objeto
@@ -266,13 +284,10 @@ void Background::setColor(Color color)
void Background::setAlpha(int alpha)
{
// Evita que se asignen valores fuera de rango
alpha_ = std::min(alpha, 255);
alpha_ = std::max(alpha, 0);
alpha_ = std::clamp(alpha, 0, 255);
// Guarda el valor actual
// Guarda el valor actual y establece el nuevo valor
alpha_color_text_temp_ = alpha_color_text_;
// Establece el nuevo valor
alpha_color_text_ = alpha_;
}
@@ -300,10 +315,10 @@ void Background::updateClouds()
bottom_clouds_sprite_b_->setVelX(clouds_speed_ / 2);
// Mueve las nubes
top_clouds_sprite_a_->move();
top_clouds_sprite_b_->move();
bottom_clouds_sprite_a_->move();
bottom_clouds_sprite_b_->move();
top_clouds_sprite_a_->update();
top_clouds_sprite_b_->update();
bottom_clouds_sprite_a_->update();
bottom_clouds_sprite_b_->update();
// Calcula el offset de las nubes
if (top_clouds_sprite_a_->getPosX() < -top_clouds_sprite_a_->getWidth())

View File

@@ -2,11 +2,11 @@
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_render.h> // for SDL_Renderer, SDL_Texture
#include <memory> // for unique_ptr, shared_ptr
#include "utils.h" // for Color
#include "moving_sprite.h"
#include "sprite.h"
#include "texture.h"
#include <memory>
class MovingSprite;
class Sprite;
class Texture;
/*
Esta clase es la encargada de dibujar el fondo que aparece durante la sección
@@ -107,7 +107,7 @@ private:
public:
// Constructor
Background(SDL_Renderer *renderer);
Background();
// Destructor
~Background();

View File

@@ -1,18 +1,31 @@
#include "balloon.h"
#include <math.h> // for abs
#include "animated_sprite.h" // for AnimatedSprite
#include <cmath> // for abs
#include "animated_sprite.h" // for SpriteAnimated
#include "moving_sprite.h" // for MovingSprite
#include "param.h" // for param
#include "sprite.h" // for Sprite
#include "texture.h" // for Texture
// Constructor
Balloon::Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16 creation_timer, std::shared_ptr<Texture> texture, std::vector<std::string> *animation)
: kind_(kind), speed_(speed)
Balloon::Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16 creation_timer, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation)
: sprite_(std::make_unique<AnimatedSprite>(texture, animation)),
pos_x_(x),
pos_y_(y),
vel_x_(vel_x),
being_created_(creation_timer > 0),
blinking_(false),
enabled_(true),
invulnerable_(creation_timer > 0),
stopped_(true),
visible_(true),
creation_counter_(creation_timer),
creation_counter_ini_(creation_timer),
stopped_counter_(0),
kind_(kind),
counter_(0),
travel_y_(1.0f),
speed_(speed)
{
sprite_ = std::make_unique<AnimatedSprite>(texture, "", animation);
enabled_ = true;
switch (kind_)
{
@@ -24,7 +37,6 @@ Balloon::Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16
power_ = 1;
// Inicializa los valores de velocidad y gravedad
vel_x_ = vel_x;
vel_y_ = 0;
max_vel_y_ = 3.0f;
gravity_ = param.balloon_1.grav;
@@ -46,7 +58,6 @@ Balloon::Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16
power_ = 3;
// Inicializa los valores de velocidad y gravedad
vel_x_ = vel_x;
vel_y_ = 0;
max_vel_y_ = 3.0f;
gravity_ = param.balloon_2.grav;
@@ -68,7 +79,6 @@ Balloon::Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16
power_ = 7;
// Inicializa los valores de velocidad y gravedad
vel_x_ = vel_x;
vel_y_ = 0;
max_vel_y_ = 3.0f;
gravity_ = param.balloon_3.grav;
@@ -90,7 +100,6 @@ Balloon::Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16
power_ = 15;
// Inicializa los valores de velocidad y gravedad
vel_x_ = vel_x;
vel_y_ = 0;
max_vel_y_ = 3.0f;
gravity_ = param.balloon_4.grav;
@@ -112,11 +121,10 @@ Balloon::Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16
power_ = 1;
// Inicializa los valores de velocidad y gravedad
vel_x_ = vel_x;
vel_y_ = abs(vel_x) * 2;
max_vel_y_ = abs(vel_x) * 2;
vel_y_ = fabs(vel_x_ * 2.0f);
max_vel_y_ = vel_y_;
gravity_ = 0.00f;
default_vel_y_ = abs(vel_x) * 2;
default_vel_y_ = vel_y_;
// Puntos que da el globo al ser destruido
score_ = BALLOON_SCORE_1;
@@ -134,11 +142,10 @@ Balloon::Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16
power_ = 3;
// Inicializa los valores de velocidad y gravedad
vel_x_ = vel_x;
vel_y_ = abs(vel_x) * 2;
max_vel_y_ = abs(vel_x) * 2;
vel_y_ = fabs(vel_x_ * 2.0f);
max_vel_y_ = vel_y_;
gravity_ = 0.00f;
default_vel_y_ = abs(vel_x) * 2;
default_vel_y_ = vel_y_;
// Puntos que da el globo al ser destruido
score_ = BALLOON_SCORE_2;
@@ -156,11 +163,10 @@ Balloon::Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16
power_ = 7;
// Inicializa los valores de velocidad y gravedad
vel_x_ = vel_x;
vel_y_ = abs(vel_x) * 2;
max_vel_y_ = abs(vel_x) * 2;
vel_y_ = fabs(vel_x_ * 2.0f);
max_vel_y_ = vel_y_;
gravity_ = 0.00f;
default_vel_y_ = abs(vel_x) * 2;
default_vel_y_ = vel_y_;
// Puntos que da el globo al ser destruido
score_ = BALLOON_SCORE_3;
@@ -178,11 +184,10 @@ Balloon::Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16
power_ = 15;
// Inicializa los valores de velocidad y gravedad
vel_x_ = vel_x;
vel_y_ = abs(vel_x) * 2;
max_vel_y_ = abs(vel_x) * 2;
vel_y_ = fabs(vel_x_ * 2.0f);
max_vel_y_ = vel_y_;
gravity_ = 0.00f;
default_vel_y_ = abs(vel_x) * 2;
default_vel_y_ = vel_y_;
// Puntos que da el globo al ser destruido
score_ = BALLOON_SCORE_4;
@@ -200,7 +205,6 @@ Balloon::Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16
power_ = 0;
// Inicializa los valores de velocidad y gravedad
vel_x_ = vel_x;
vel_y_ = 0;
max_vel_y_ = 3.0f;
gravity_ = param.balloon_4.grav;
@@ -213,7 +217,7 @@ Balloon::Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16
menace_ = 0;
// Añade rotación al sprite_
sprite_->setRotate(false);
sprite_->disableRotate();
sprite_->setRotateSpeed(0);
vel_x_ > 0.0f ? sprite_->setRotateAmount(2.0) : sprite_->setRotateAmount(-2.0);
@@ -223,10 +227,6 @@ Balloon::Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16
break;
}
// Posición inicial
pos_x_ = x;
pos_y_ = y;
// Valores para el efecto de rebote
bouncing_.enabled = false;
bouncing_.counter = 0;
@@ -238,36 +238,14 @@ Balloon::Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16
bouncing_.w = {1.10f, 1.05f, 1.00f, 0.95f, 0.90f, 0.95f, 1.00f, 1.02f, 1.05f, 1.02f};
bouncing_.h = {0.90f, 0.95f, 1.00f, 1.05f, 1.10f, 1.05f, 1.00f, 0.98f, 0.95f, 0.98f};
// Alto y ancho del sprite_
sprite_->setWidth(width_);
sprite_->setHeight(height_);
// Posición X,Y del sprite_
sprite_->setPosX((int)pos_x_);
sprite_->setPosY((int)pos_y_);
// Configura el sprite
sprite_->setPos({static_cast<int>(pos_x_), static_cast<int>(pos_y_), width_, height_});
// Tamaño del circulo de colisión
collider_.r = width_ / 2;
// Alinea el circulo de colisión con el objeto
updateColliders();
// Inicializa variables
stopped_ = true;
stopped_counter_ = 0;
blinking_ = false;
visible_ = true;
invulnerable_ = true;
being_created_ = true;
creation_counter_ = creation_timer;
creation_counter_ini_ = creation_timer;
// Actualiza valores
being_created_ = creation_counter_ == 0 ? false : true;
invulnerable_ = being_created_ == false ? false : true;
counter_ = 0;
travel_y_ = 1.0f;
}
// Centra el globo en la posición X
@@ -323,7 +301,7 @@ void Balloon::render()
if (kind_ == POWER_BALL && !isBeingCreated())
{
auto sp = std::make_unique<Sprite>(sprite_->getRect(), sprite_->getTexture());
auto sp = std::make_unique<Sprite>(sprite_->getTexture(), sprite_->getPosition());
sp->setSpriteClip(BALLOON_WIDTH_4, 0, BALLOON_WIDTH_4, BALLOON_WIDTH_4);
sp->render();
}
@@ -413,10 +391,6 @@ void Balloon::move()
// Aplica la gravedad al objeto sin pasarse de una velocidad máxima
vel_y_ += gravity_;
// Al parecer esta asignación se quedó sin hacer y ahora el juego no funciona
// correctamente si se aplica, así que se deja sin efecto
// vel_y_ = std::min(vel_y_, max_vel_y_);
}
// Actualiza la posición del sprite_
@@ -471,13 +445,13 @@ void Balloon::update()
{
if (enabled_)
{
sprite_->MovingSprite::update();
sprite_->update();
move();
updateAnimation();
updateColliders();
updateState();
updateBounce();
counter_++;
++counter_;
}
}
@@ -527,7 +501,7 @@ void Balloon::updateState()
setInvulnerable(false);
if (kind_ == POWER_BALL)
{
sprite_->setRotate(true);
sprite_->enableRotate();
}
}
}
@@ -537,7 +511,7 @@ void Balloon::updateState()
// Si es una powerball deja de rodar
if (kind_ == POWER_BALL)
{
sprite_->setRotate(false);
sprite_->disableRotate();
}
// Reduce el contador
@@ -553,7 +527,7 @@ void Balloon::updateState()
// Si es una powerball vuelve a rodar
if (kind_ == POWER_BALL)
{
sprite_->setRotate(true);
sprite_->enableRotate();
}
}
}
@@ -586,7 +560,7 @@ void Balloon::updateAnimation()
sprite_->setCurrentAnimation(normal_animation);
}
sprite_->animate();
sprite_->update();
}
// Comprueba si el globo está habilitado
@@ -626,15 +600,15 @@ int Balloon::getHeight() const
}
// Establece el valor de la variable
void Balloon::setVelY(float vel_y_)
void Balloon::setVelY(float vel_y)
{
this->vel_y_ = vel_y_;
vel_y_ = vel_y;
}
// Establece el valor de la variable
void Balloon::setSpeed(float speed_)
void Balloon::setSpeed(float speed)
{
this->speed_ = speed_;
speed_ = speed;
}
// Obtiene del valor de la variable

View File

@@ -1,12 +1,12 @@
#pragma once
#include <SDL2/SDL_stdinc.h> // for Uint8, Uint16, Uint32
#include <memory> // for shared_ptr, unique_ptr
#include <string> // for string
#include <vector> // for vector
#include <memory>
#include "utils.h" // for Circle
#include "animated_sprite.h"
#include "texture.h"
#include "animated_sprite.h" // for SpriteAnimated
#include "utils.h" // for Circle
class Texture;
// Cantidad de elementos del vector con los valores de la deformación del globo al rebotar
constexpr int MAX_BOUNCE = 10;
@@ -141,7 +141,7 @@ private:
public:
// Constructor
Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16 creation_timer, std::shared_ptr<Texture> texture, std::vector<std::string> *animation);
Balloon(float x, float y, Uint8 kind, float vel_x, float speed, Uint16 creation_timer, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation);
// Destructor
~Balloon() = default;

View File

@@ -0,0 +1,714 @@
#include "balloon_formations.h"
#include "balloon.h" // for BALLOON_VELX_NEGATIVE, BALLOON_VELX_POSITIVE
#include "param.h" // for param
#include "utils.h" // for ParamGame, Param, Zone, BLOCK
// Constructor
BalloonFormations::BalloonFormations()
{
initBalloonFormations();
initBalloonFormationPools();
initGameStages();
}
// Inicializa las formaciones enemigas
void BalloonFormations::initBalloonFormations()
{
constexpr int y4 = -BLOCK;
const int x4_0 = param.game.play_area.rect.x;
const int x4_100 = param.game.play_area.rect.w - BALLOON_WIDTH_4;
constexpr int y3 = -BLOCK;
const int x3_0 = param.game.play_area.rect.x;
const int x3_100 = param.game.play_area.rect.w - BALLOON_WIDTH_3;
constexpr int y2 = -BLOCK;
const int x2_0 = param.game.play_area.rect.x;
const int x2_100 = param.game.play_area.rect.w - BALLOON_WIDTH_2;
constexpr int y1 = -BLOCK;
const int x1_0 = param.game.play_area.rect.x;
const int x1_50 = param.game.play_area.center_x - (BALLOON_WIDTH_1 / 2);
const int x1_100 = param.game.play_area.rect.w - BALLOON_WIDTH_1;
// Inicializa a cero las variables
for (int i = 0; i < NUMBER_OF_BALLOON_FORMATIONS; i++)
{
balloon_formation_[i].number_of_balloons = 0;
for (int j = 0; j < MAX_NUMBER_OF_BALLOONS_IN_A_FORMATION; j++)
{
balloon_formation_[i].init[j] = BalloonFormationParams();
}
}
constexpr int CREATION_TIME = 300;
int inc_x = 0;
int inc_time = 0;
int j = 0;
// #00 - Dos enemigos BALLOON4 uno a cada extremo
j = 0;
balloon_formation_[j].number_of_balloons = 2;
inc_x = x4_100;
inc_time = 0;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x4_0 + (i * inc_x);
balloon_formation_[j].init[i].y = y4;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE * (((i % 2) * 2) - 1);
balloon_formation_[j].init[i].kind = BALLOON_4;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME + (inc_time * i);
}
// #01 - Dos enemigos BALLOON4 uno a cada cuarto. Ambos van hacia el centro
j = 1;
balloon_formation_[j].number_of_balloons = 2;
inc_x = param.game.play_area.center_x;
inc_time = 0;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = param.game.play_area.first_quarter_x - (BALLOON_WIDTH_4 / 2) + (i * inc_x);
balloon_formation_[j].init[i].y = y4;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE * (((i % 2) * 2) - 1);
balloon_formation_[j].init[i].kind = BALLOON_4;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME + (inc_time * i);
}
// #02 - Cuatro enemigos BALLOON2 uno detras del otro. A la izquierda y hacia el centro
j = 2;
balloon_formation_[j].number_of_balloons = 4;
inc_x = BALLOON_WIDTH_2 + 1;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x2_0 + (i * inc_x);
balloon_formation_[j].init[i].y = y2;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
balloon_formation_[j].init[i].kind = BALLOON_2;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #03 - Cuatro enemigos BALLOON2 uno detras del otro. A la derecha y hacia el centro
j = 3;
balloon_formation_[j].number_of_balloons = 4;
inc_x = BALLOON_WIDTH_2 + 1;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x2_100 - (i * inc_x);
balloon_formation_[j].init[i].y = y2;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
balloon_formation_[j].init[i].kind = BALLOON_2;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #04 - Tres enemigos BALLOON3. 0, 25, 50. Hacia la derecha
j = 4;
balloon_formation_[j].number_of_balloons = 3;
inc_x = BALLOON_WIDTH_3 * 2;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x3_0 + (i * inc_x);
balloon_formation_[j].init[i].y = y3;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
balloon_formation_[j].init[i].kind = BALLOON_3;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #05 - Tres enemigos BALLOON3. 50, 75, 100. Hacia la izquierda
j = 5;
balloon_formation_[j].number_of_balloons = 3;
inc_x = BALLOON_WIDTH_3 * 2;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x3_100 - (i * inc_x);
balloon_formation_[j].init[i].y = y3;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
balloon_formation_[j].init[i].kind = BALLOON_3;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #06 - Tres enemigos BALLOON3. 0, 0, 0. Hacia la derecha
j = 6;
balloon_formation_[j].number_of_balloons = 3;
inc_x = BALLOON_WIDTH_3 + 1;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x3_0 + (i * inc_x);
balloon_formation_[j].init[i].y = y3;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
balloon_formation_[j].init[i].kind = BALLOON_3;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #07 - Tres enemigos BALLOON3. 100, 100, 100. Hacia la izquierda
j = 7;
balloon_formation_[j].number_of_balloons = 3;
inc_x = BALLOON_WIDTH_3 + 1;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x3_100 - (i * inc_x);
balloon_formation_[j].init[i].y = y3;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
balloon_formation_[j].init[i].kind = BALLOON_3;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #08 - Seis enemigos BALLOON1. 0, 0, 0, 0, 0, 0. Hacia la derecha
j = 8;
balloon_formation_[j].number_of_balloons = 6;
inc_x = BALLOON_WIDTH_1 + 1;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x1_0 + (i * inc_x);
balloon_formation_[j].init[i].y = y1;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
balloon_formation_[j].init[i].kind = BALLOON_1;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #09 - Seis enemigos BALLOON1. 100, 100, 100, 100, 100, 100. Hacia la izquierda
j = 9;
balloon_formation_[j].number_of_balloons = 6;
inc_x = BALLOON_WIDTH_1 + 1;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x1_100 - (i * inc_x);
balloon_formation_[j].init[i].y = y1;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
balloon_formation_[j].init[i].kind = BALLOON_1;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #10 - Tres enemigos BALLOON4 seguidos desde la izquierda
j = 10;
balloon_formation_[j].number_of_balloons = 3;
inc_x = BALLOON_WIDTH_4 + 1;
inc_time = 15;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x4_0 + (i * inc_x);
balloon_formation_[j].init[i].y = y4;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
balloon_formation_[j].init[i].kind = BALLOON_4;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #11 - Tres enemigos BALLOON4 seguidos desde la derecha
j = 11;
balloon_formation_[j].number_of_balloons = 3;
inc_x = BALLOON_WIDTH_4 + 1;
inc_time = 15;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x4_100 - (i * inc_x);
balloon_formation_[j].init[i].y = y4;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
balloon_formation_[j].init[i].kind = BALLOON_4;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #12 - Seis enemigos BALLOON2 uno detras del otro. A la izquierda y hacia el centro
j = 12;
balloon_formation_[j].number_of_balloons = 6;
inc_x = BALLOON_WIDTH_2 + 1;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x2_0 + (i * inc_x);
balloon_formation_[j].init[i].y = y2;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
balloon_formation_[j].init[i].kind = BALLOON_2;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #13 - Seis enemigos BALLOON2 uno detras del otro. A la derecha y hacia el centro
j = 13;
balloon_formation_[j].number_of_balloons = 6;
inc_x = BALLOON_WIDTH_2 + 1;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x2_100 - (i * inc_x);
balloon_formation_[j].init[i].y = y2;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
balloon_formation_[j].init[i].kind = BALLOON_2;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #14 - Cinco enemigos BALLOON3. Hacia la derecha. Separados
j = 14;
balloon_formation_[j].number_of_balloons = 5;
inc_x = BALLOON_WIDTH_3 * 2;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x3_0 + (i * inc_x);
balloon_formation_[j].init[i].y = y3;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
balloon_formation_[j].init[i].kind = BALLOON_3;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #15 - Cinco enemigos BALLOON3. Hacia la izquierda. Separados
j = 15;
balloon_formation_[j].number_of_balloons = 5;
inc_x = BALLOON_WIDTH_3 * 2;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x3_100 - (i * inc_x);
balloon_formation_[j].init[i].y = y3;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
balloon_formation_[j].init[i].kind = BALLOON_3;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #16 - Cinco enemigos BALLOON3. Hacia la derecha. Juntos
j = 16;
balloon_formation_[j].number_of_balloons = 5;
inc_x = BALLOON_WIDTH_3 + 1;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x3_0 + (i * inc_x);
balloon_formation_[j].init[i].y = y3;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
balloon_formation_[j].init[i].kind = BALLOON_3;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #17 - Cinco enemigos BALLOON3. Hacia la izquierda. Juntos
j = 17;
balloon_formation_[j].number_of_balloons = 5;
inc_x = BALLOON_WIDTH_3 + 1;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x3_100 - (i * inc_x);
balloon_formation_[j].init[i].y = y3;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
balloon_formation_[j].init[i].kind = BALLOON_3;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #18 - Doce enemigos BALLOON1. Hacia la derecha. Juntos
j = 18;
balloon_formation_[j].number_of_balloons = 12;
inc_x = BALLOON_WIDTH_1 + 1;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x1_0 + (i * inc_x);
balloon_formation_[j].init[i].y = y1;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
balloon_formation_[j].init[i].kind = BALLOON_1;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #19 - Doce enemigos BALLOON1. Hacia la izquierda. Juntos
j = 19;
balloon_formation_[j].number_of_balloons = 12;
inc_x = BALLOON_WIDTH_1 + 1;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
balloon_formation_[j].init[i].x = x1_100 - (i * inc_x);
balloon_formation_[j].init[i].y = y1;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
balloon_formation_[j].init[i].kind = BALLOON_1;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME - (inc_time * i);
}
// #20 - Dos enemigos BALLOON4 seguidos desde la izquierda/derecha. Simetricos
j = 20;
balloon_formation_[j].number_of_balloons = 4;
inc_x = BALLOON_WIDTH_4 + 1;
inc_time = 0;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
const int half = balloon_formation_[j].number_of_balloons / 2;
if (i < half)
{
balloon_formation_[j].init[i].x = x4_0 + (i * inc_x);
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
}
else
{
balloon_formation_[j].init[i].x = x4_100 - ((i - half) * inc_x);
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
}
balloon_formation_[j].init[i].y = y4;
balloon_formation_[j].init[i].kind = BALLOON_4;
balloon_formation_[j].init[i].creation_counter = CREATION_TIME + (inc_time * i);
}
// #21 - Diez enemigos BALLOON2 uno detras del otro. Izquierda/derecha. Simetricos
j = 21;
balloon_formation_[j].number_of_balloons = 10;
inc_x = BALLOON_WIDTH_2 + 1;
inc_time = 3;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
const int half = balloon_formation_[j].number_of_balloons / 2;
if (i < half)
{
balloon_formation_[j].init[i].x = x2_0 + (i * inc_x);
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
balloon_formation_[j].init[i].creation_counter = (CREATION_TIME) - (inc_time * i);
}
else
{
balloon_formation_[j].init[i].x = x2_100 - ((i - half) * inc_x);
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
balloon_formation_[j].init[i].creation_counter = (CREATION_TIME) - (inc_time * (i - half));
}
balloon_formation_[j].init[i].y = y2;
balloon_formation_[j].init[i].kind = BALLOON_2;
}
// #22 - Diez enemigos BALLOON3. Hacia la derecha/izquierda. Separados. Simetricos
j = 22;
balloon_formation_[j].number_of_balloons = 10;
inc_x = BALLOON_WIDTH_3 * 2;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
const int half = balloon_formation_[j].number_of_balloons / 2;
if (i < half)
{
balloon_formation_[j].init[i].x = x3_0 + (i * inc_x);
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
balloon_formation_[j].init[i].creation_counter = (CREATION_TIME) - (inc_time * i);
}
else
{
balloon_formation_[j].init[i].x = x3_100 - ((i - half) * inc_x);
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
balloon_formation_[j].init[i].creation_counter = (CREATION_TIME) - (inc_time * (i - half));
}
balloon_formation_[j].init[i].y = y3;
balloon_formation_[j].init[i].kind = BALLOON_3;
}
// #23 - Diez enemigos BALLOON3. Hacia la derecha. Juntos. Simetricos
j = 23;
balloon_formation_[j].number_of_balloons = 10;
inc_x = BALLOON_WIDTH_3 + 1;
inc_time = 10;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
const int half = balloon_formation_[j].number_of_balloons / 2;
if (i < half)
{
balloon_formation_[j].init[i].x = x3_0 + (i * inc_x);
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
balloon_formation_[j].init[i].creation_counter = (CREATION_TIME) - (inc_time * i);
}
else
{
balloon_formation_[j].init[i].x = x3_100 - ((i - half) * inc_x);
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
balloon_formation_[j].init[i].creation_counter = (CREATION_TIME) - (inc_time * (i - half));
}
balloon_formation_[j].init[i].y = y3;
balloon_formation_[j].init[i].kind = BALLOON_3;
}
// #24 - Treinta enemigos BALLOON1. Del centro hacia los extremos. Juntos. Simetricos
j = 24;
balloon_formation_[j].number_of_balloons = 30;
inc_time = 5;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
const int half = balloon_formation_[j].number_of_balloons / 2;
if (i < half)
{
balloon_formation_[j].init[i].x = x1_50;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
balloon_formation_[j].init[i].creation_counter = (CREATION_TIME) + (inc_time * i);
}
else
{
balloon_formation_[j].init[i].x = x1_50;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
balloon_formation_[j].init[i].creation_counter = (CREATION_TIME) + (inc_time * (i - half));
}
balloon_formation_[j].init[i].y = y1;
balloon_formation_[j].init[i].kind = BALLOON_1;
}
// #25 - Treinta enemigos BALLOON1. Del centro hacia adentro. Juntos. Simetricos
j = 25;
balloon_formation_[j].number_of_balloons = 30;
inc_time = 5;
for (int i = 0; i < balloon_formation_[j].number_of_balloons; i++)
{
const int half = balloon_formation_[j].number_of_balloons / 2;
if (i < half)
{
balloon_formation_[j].init[i].x = x1_50 + 20;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
balloon_formation_[j].init[i].creation_counter = (CREATION_TIME) - (inc_time * i);
}
else
{
balloon_formation_[j].init[i].x = x1_50 - 20;
balloon_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
balloon_formation_[j].init[i].creation_counter = (CREATION_TIME) - (inc_time * (i - half));
}
balloon_formation_[j].init[i].y = y1;
balloon_formation_[j].init[i].kind = BALLOON_1;
}
// Crea las mismas formaciones pero con hexagonos a partir de la posición 50 del vector
for (int k = 0; k < j + 1; k++)
{
balloon_formation_[k + 50].number_of_balloons = balloon_formation_[k].number_of_balloons;
for (int i = 0; i < balloon_formation_[k + 50].number_of_balloons; i++)
{
balloon_formation_[k + 50].init[i].x = balloon_formation_[k].init[i].x;
balloon_formation_[k + 50].init[i].y = balloon_formation_[k].init[i].y;
balloon_formation_[k + 50].init[i].vel_x = balloon_formation_[k].init[i].vel_x;
balloon_formation_[k + 50].init[i].creation_counter = balloon_formation_[k].init[i].creation_counter;
balloon_formation_[k + 50].init[i].kind = balloon_formation_[k].init[i].kind + 4;
}
}
// TEST
balloon_formation_[99].number_of_balloons = 4;
balloon_formation_[99].init[0].x = 10;
balloon_formation_[99].init[0].y = y1;
balloon_formation_[99].init[0].vel_x = 0;
balloon_formation_[99].init[0].kind = BALLOON_1;
balloon_formation_[99].init[0].creation_counter = 200;
balloon_formation_[99].init[1].x = 50;
balloon_formation_[99].init[1].y = y1;
balloon_formation_[99].init[1].vel_x = 0;
balloon_formation_[99].init[1].kind = BALLOON_2;
balloon_formation_[99].init[1].creation_counter = 200;
balloon_formation_[99].init[2].x = 90;
balloon_formation_[99].init[2].y = y1;
balloon_formation_[99].init[2].vel_x = 0;
balloon_formation_[99].init[2].kind = BALLOON_3;
balloon_formation_[99].init[2].creation_counter = 200;
balloon_formation_[99].init[3].x = 140;
balloon_formation_[99].init[3].y = y1;
balloon_formation_[99].init[3].vel_x = 0;
balloon_formation_[99].init[3].kind = BALLOON_4;
balloon_formation_[99].init[3].creation_counter = 200;
}
// Inicializa los conjuntos de formaciones
void BalloonFormations::initBalloonFormationPools()
{
// EnemyPool #0
balloon_formation_pool_[0].set[0] = &balloon_formation_[0];
balloon_formation_pool_[0].set[1] = &balloon_formation_[1];
balloon_formation_pool_[0].set[2] = &balloon_formation_[2];
balloon_formation_pool_[0].set[3] = &balloon_formation_[3];
balloon_formation_pool_[0].set[4] = &balloon_formation_[4];
balloon_formation_pool_[0].set[5] = &balloon_formation_[5];
balloon_formation_pool_[0].set[6] = &balloon_formation_[6];
balloon_formation_pool_[0].set[7] = &balloon_formation_[7];
balloon_formation_pool_[0].set[8] = &balloon_formation_[8];
balloon_formation_pool_[0].set[9] = &balloon_formation_[9];
// EnemyPool #1
balloon_formation_pool_[1].set[0] = &balloon_formation_[10];
balloon_formation_pool_[1].set[1] = &balloon_formation_[11];
balloon_formation_pool_[1].set[2] = &balloon_formation_[12];
balloon_formation_pool_[1].set[3] = &balloon_formation_[13];
balloon_formation_pool_[1].set[4] = &balloon_formation_[14];
balloon_formation_pool_[1].set[5] = &balloon_formation_[15];
balloon_formation_pool_[1].set[6] = &balloon_formation_[16];
balloon_formation_pool_[1].set[7] = &balloon_formation_[17];
balloon_formation_pool_[1].set[8] = &balloon_formation_[18];
balloon_formation_pool_[1].set[9] = &balloon_formation_[19];
// EnemyPool #2
balloon_formation_pool_[2].set[0] = &balloon_formation_[0];
balloon_formation_pool_[2].set[1] = &balloon_formation_[1];
balloon_formation_pool_[2].set[2] = &balloon_formation_[2];
balloon_formation_pool_[2].set[3] = &balloon_formation_[3];
balloon_formation_pool_[2].set[4] = &balloon_formation_[4];
balloon_formation_pool_[2].set[5] = &balloon_formation_[55];
balloon_formation_pool_[2].set[6] = &balloon_formation_[56];
balloon_formation_pool_[2].set[7] = &balloon_formation_[57];
balloon_formation_pool_[2].set[8] = &balloon_formation_[58];
balloon_formation_pool_[2].set[9] = &balloon_formation_[59];
// EnemyPool #3
balloon_formation_pool_[3].set[0] = &balloon_formation_[50];
balloon_formation_pool_[3].set[1] = &balloon_formation_[51];
balloon_formation_pool_[3].set[2] = &balloon_formation_[52];
balloon_formation_pool_[3].set[3] = &balloon_formation_[53];
balloon_formation_pool_[3].set[4] = &balloon_formation_[54];
balloon_formation_pool_[3].set[5] = &balloon_formation_[5];
balloon_formation_pool_[3].set[6] = &balloon_formation_[6];
balloon_formation_pool_[3].set[7] = &balloon_formation_[7];
balloon_formation_pool_[3].set[8] = &balloon_formation_[8];
balloon_formation_pool_[3].set[9] = &balloon_formation_[9];
// EnemyPool #4
balloon_formation_pool_[4].set[0] = &balloon_formation_[60];
balloon_formation_pool_[4].set[1] = &balloon_formation_[61];
balloon_formation_pool_[4].set[2] = &balloon_formation_[62];
balloon_formation_pool_[4].set[3] = &balloon_formation_[63];
balloon_formation_pool_[4].set[4] = &balloon_formation_[64];
balloon_formation_pool_[4].set[5] = &balloon_formation_[65];
balloon_formation_pool_[4].set[6] = &balloon_formation_[66];
balloon_formation_pool_[4].set[7] = &balloon_formation_[67];
balloon_formation_pool_[4].set[8] = &balloon_formation_[68];
balloon_formation_pool_[4].set[9] = &balloon_formation_[69];
// EnemyPool #5
balloon_formation_pool_[5].set[0] = &balloon_formation_[10];
balloon_formation_pool_[5].set[1] = &balloon_formation_[61];
balloon_formation_pool_[5].set[2] = &balloon_formation_[12];
balloon_formation_pool_[5].set[3] = &balloon_formation_[63];
balloon_formation_pool_[5].set[4] = &balloon_formation_[14];
balloon_formation_pool_[5].set[5] = &balloon_formation_[65];
balloon_formation_pool_[5].set[6] = &balloon_formation_[16];
balloon_formation_pool_[5].set[7] = &balloon_formation_[67];
balloon_formation_pool_[5].set[8] = &balloon_formation_[18];
balloon_formation_pool_[5].set[9] = &balloon_formation_[69];
// EnemyPool #6
balloon_formation_pool_[6].set[0] = &balloon_formation_[60];
balloon_formation_pool_[6].set[1] = &balloon_formation_[11];
balloon_formation_pool_[6].set[2] = &balloon_formation_[62];
balloon_formation_pool_[6].set[3] = &balloon_formation_[13];
balloon_formation_pool_[6].set[4] = &balloon_formation_[64];
balloon_formation_pool_[6].set[5] = &balloon_formation_[15];
balloon_formation_pool_[6].set[6] = &balloon_formation_[66];
balloon_formation_pool_[6].set[7] = &balloon_formation_[17];
balloon_formation_pool_[6].set[8] = &balloon_formation_[68];
balloon_formation_pool_[6].set[9] = &balloon_formation_[19];
// EnemyPool #7
balloon_formation_pool_[7].set[0] = &balloon_formation_[20];
balloon_formation_pool_[7].set[1] = &balloon_formation_[21];
balloon_formation_pool_[7].set[2] = &balloon_formation_[22];
balloon_formation_pool_[7].set[3] = &balloon_formation_[23];
balloon_formation_pool_[7].set[4] = &balloon_formation_[24];
balloon_formation_pool_[7].set[5] = &balloon_formation_[65];
balloon_formation_pool_[7].set[6] = &balloon_formation_[66];
balloon_formation_pool_[7].set[7] = &balloon_formation_[67];
balloon_formation_pool_[7].set[8] = &balloon_formation_[68];
balloon_formation_pool_[7].set[9] = &balloon_formation_[69];
// EnemyPool #8
balloon_formation_pool_[8].set[0] = &balloon_formation_[70];
balloon_formation_pool_[8].set[1] = &balloon_formation_[71];
balloon_formation_pool_[8].set[2] = &balloon_formation_[72];
balloon_formation_pool_[8].set[3] = &balloon_formation_[73];
balloon_formation_pool_[8].set[4] = &balloon_formation_[74];
balloon_formation_pool_[8].set[5] = &balloon_formation_[15];
balloon_formation_pool_[8].set[6] = &balloon_formation_[16];
balloon_formation_pool_[8].set[7] = &balloon_formation_[17];
balloon_formation_pool_[8].set[8] = &balloon_formation_[18];
balloon_formation_pool_[8].set[9] = &balloon_formation_[19];
// EnemyPool #9
balloon_formation_pool_[9].set[0] = &balloon_formation_[20];
balloon_formation_pool_[9].set[1] = &balloon_formation_[21];
balloon_formation_pool_[9].set[2] = &balloon_formation_[22];
balloon_formation_pool_[9].set[3] = &balloon_formation_[23];
balloon_formation_pool_[9].set[4] = &balloon_formation_[24];
balloon_formation_pool_[9].set[5] = &balloon_formation_[70];
balloon_formation_pool_[9].set[6] = &balloon_formation_[71];
balloon_formation_pool_[9].set[7] = &balloon_formation_[72];
balloon_formation_pool_[9].set[8] = &balloon_formation_[73];
balloon_formation_pool_[9].set[9] = &balloon_formation_[74];
}
// Inicializa las fases del juego
void BalloonFormations::initGameStages()
{
// STAGE 1
stage_[0].number = 1;
stage_[0].power_to_complete = 200;
stage_[0].min_menace = 7 + (4 * 1);
stage_[0].max_menace = 7 + (4 * 3);
stage_[0].balloon_pool = &balloon_formation_pool_[0];
// STAGE 2
stage_[1].number = 2;
stage_[1].power_to_complete = 300;
stage_[1].min_menace = 7 + (4 * 2);
stage_[1].max_menace = 7 + (4 * 4);
stage_[1].balloon_pool = &balloon_formation_pool_[1];
// STAGE 3
stage_[2].number = 3;
stage_[2].power_to_complete = 600;
stage_[2].min_menace = 7 + (4 * 3);
stage_[2].max_menace = 7 + (4 * 5);
stage_[2].balloon_pool = &balloon_formation_pool_[2];
// STAGE 4
stage_[3].number = 4;
stage_[3].power_to_complete = 600;
stage_[3].min_menace = 7 + (4 * 3);
stage_[3].max_menace = 7 + (4 * 5);
stage_[3].balloon_pool = &balloon_formation_pool_[3];
// STAGE 5
stage_[4].number = 5;
stage_[4].power_to_complete = 600;
stage_[4].min_menace = 7 + (4 * 4);
stage_[4].max_menace = 7 + (4 * 6);
stage_[4].balloon_pool = &balloon_formation_pool_[4];
// STAGE 6
stage_[5].number = 6;
stage_[5].power_to_complete = 600;
stage_[5].min_menace = 7 + (4 * 4);
stage_[5].max_menace = 7 + (4 * 6);
stage_[5].balloon_pool = &balloon_formation_pool_[5];
// STAGE 7
stage_[6].number = 7;
stage_[6].power_to_complete = 650;
stage_[6].min_menace = 7 + (4 * 5);
stage_[6].max_menace = 7 + (4 * 7);
stage_[6].balloon_pool = &balloon_formation_pool_[6];
// STAGE 8
stage_[7].number = 8;
stage_[7].power_to_complete = 750;
stage_[7].min_menace = 7 + (4 * 5);
stage_[7].max_menace = 7 + (4 * 7);
stage_[7].balloon_pool = &balloon_formation_pool_[7];
// STAGE 9
stage_[8].number = 9;
stage_[8].power_to_complete = 850;
stage_[8].min_menace = 7 + (4 * 6);
stage_[8].max_menace = 7 + (4 * 8);
stage_[8].balloon_pool = &balloon_formation_pool_[8];
// STAGE 10
stage_[9].number = 10;
stage_[9].power_to_complete = 950;
stage_[9].min_menace = 7 + (4 * 7);
stage_[9].max_menace = 7 + (4 * 10);
stage_[9].balloon_pool = &balloon_formation_pool_[9];
}
// Devuelve una fase
Stage BalloonFormations::getStage(int index) const
{
return stage_[index];
}

View File

@@ -0,0 +1,67 @@
#pragma once
constexpr int NUMBER_OF_BALLOON_FORMATIONS = 100;
constexpr int MAX_NUMBER_OF_BALLOONS_IN_A_FORMATION = 50;
// Estructuras
struct BalloonFormationParams
{
int x = 0; // Posición en el eje X donde crear al enemigo
int y = 0; // Posición en el eje Y donde crear al enemigo
float vel_x = 0.0f; // Velocidad inicial en el eje X
int kind = 0; // Tipo de enemigo
int creation_counter = 0; // Temporizador para la creación del enemigo
// Constructor que inicializa todos los campos con valores proporcionados o predeterminados
BalloonFormationParams(int x_val = 0, int y_val = 0, float vel_x_val = 0.0f, int kind_val = 0, int creation_counter_val = 0)
: x(x_val), y(y_val), vel_x(vel_x_val), kind(kind_val), creation_counter(creation_counter_val) {}
};
struct BalloonFormationUnit // Contiene la información de una formación enemiga
{
int number_of_balloons; // Cantidad de enemigos que forman la formación
BalloonFormationParams init[MAX_NUMBER_OF_BALLOONS_IN_A_FORMATION]; // Vector con todas las inicializaciones de los enemigos de la formación
};
struct BalloonFormationPool
{
BalloonFormationUnit *set[10]; // Conjunto de formaciones de globos
};
struct Stage // Contiene todas las variables relacionadas con una fase
{
BalloonFormationPool *balloon_pool; // El conjunto de formaciones de globos de la fase
int power_to_complete; // Cantidad de poder que se necesita para completar la fase
int max_menace; // Umbral máximo de amenaza de la fase
int min_menace; // Umbral mínimo de amenaza de la fase
int number; // Número de fase
};
// Clase BalloonFormations, para gestionar las formaciones de globos
class BalloonFormations
{
private:
// Variables
Stage stage_[10]; // Variable con los datos de cada pantalla
BalloonFormationUnit balloon_formation_[NUMBER_OF_BALLOON_FORMATIONS]; // Vector con todas las formaciones enemigas
BalloonFormationPool balloon_formation_pool_[10]; // Variable con los diferentes conjuntos de formaciones enemigas
// Inicializa las formaciones enemigas
void initBalloonFormations();
// Inicializa los conjuntos de formaciones
void initBalloonFormationPools();
// Inicializa las fases del juego
void initGameStages();
public:
// Constructor
BalloonFormations();
// Destructor
~BalloonFormations() = default;
// Devuelve una fase
Stage getStage(int index) const;
};

View File

@@ -1,9 +1,9 @@
#include "bullet.h"
#include "param.h" // for param
#include "sprite.h" // for Sprite
#include <memory> // for std::unique_ptr
#include <memory> // for unique_ptr, make_unique, shared_ptr
#include "param.h" // for param
#include "sprite.h" // for Sprite
class Texture;
// Constantes evaluables en tiempo de compilación
constexpr int BULLET_WIDTH = 12;
constexpr int BULLET_HEIGHT = 12;
constexpr int BULLET_VELY = -3;
@@ -11,16 +11,23 @@ constexpr int BULLET_VELX_LEFT = -2;
constexpr int BULLET_VELX_RIGHT = 2;
// Constructor
Bullet::Bullet(int x, int y, BulletType kind_, bool poweredUp, int owner, SDL_Rect *play_area, std::shared_ptr<Texture> texture)
: pos_x_(x), pos_y_(y), width_(BULLET_WIDTH), height_(BULLET_HEIGHT), vel_x_(0), vel_y_(BULLET_VELY),
kind_(kind_), owner_(owner), play_area_(play_area)
Bullet::Bullet(int x, int y, BulletType kind, bool powered_up, int owner, SDL_Rect *play_area, std::shared_ptr<Texture> texture)
: sprite_(std::make_unique<Sprite>(texture, SDL_Rect{x, y, BULLET_WIDTH, BULLET_HEIGHT})),
pos_x_(x),
pos_y_(y),
width_(BULLET_WIDTH),
height_(BULLET_HEIGHT),
vel_x_(0),
vel_y_(BULLET_VELY),
kind_(kind),
owner_(owner),
play_area_(play_area)
{
vel_x_ = (kind_ == BulletType::LEFT) ? BULLET_VELX_LEFT : (kind_ == BulletType::RIGHT) ? BULLET_VELX_RIGHT
: 0;
auto sprite_offset = poweredUp ? 3 : 0;
auto kind_index = static_cast<int>(kind_);
sprite_ = std::make_unique<Sprite>(SDL_Rect{x, y, BULLET_WIDTH, BULLET_HEIGHT}, texture);
auto sprite_offset = powered_up ? 3 : 0;
auto kind_index = static_cast<int>(kind);
sprite_->setSpriteClip((kind_index + sprite_offset) * width_, 0, sprite_->getWidth(), sprite_->getHeight());
collider_.r = width_ / 2;
@@ -50,8 +57,8 @@ BulletMoveStatus Bullet::move()
return BulletMoveStatus::OUT;
}
sprite_->setPosX(pos_x_);
sprite_->setPosY(pos_y_);
sprite_->setX(pos_x_);
sprite_->setY(pos_y_);
shiftColliders();
return BulletMoveStatus::OK;
@@ -59,12 +66,12 @@ BulletMoveStatus Bullet::move()
bool Bullet::isEnabled() const
{
return kind_ != BulletType::NULL_TYPE;
return kind_ != BulletType::NONE;
}
void Bullet::disable()
{
kind_ = BulletType::NULL_TYPE;
kind_ = BulletType::NONE;
}
int Bullet::getPosX() const

View File

@@ -1,11 +1,11 @@
#pragma once
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_stdinc.h> // for Uint8
#include <memory> // for unique_ptr
#include "sprite.h" // for Sprite
#include "utils.h" // for Circle
#include "texture.h" // lines 9-9
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_stdinc.h> // for Uint8
#include <memory> // for shared_ptr, unique_ptr
#include "sprite.h" // for Sprite
#include "utils.h" // for Circle
class Texture;
// Enumeración para los diferentes tipos de balas
enum class BulletType
@@ -13,7 +13,7 @@ enum class BulletType
UP,
LEFT,
RIGHT,
NULL_TYPE
NONE
};
// Enumeración para los resultados del movimiento de la bala
@@ -27,18 +27,21 @@ enum class BulletMoveStatus : Uint8
class Bullet
{
private:
int pos_x_; // Posición en el eje X
int pos_y_; // Posición en el eje Y
Uint8 width_; // Ancho del objeto
Uint8 height_; // Alto del objeto
int vel_x_; // Velocidad en el eje X
int vel_y_; // Velocidad en el eje Y
BulletType kind_; // Tipo de objeto
int owner_; // Identificador del dueño del objeto
Circle collider_; // Círculo de colisión del objeto
SDL_Rect *play_area_; // Rectángulo con la zona de juego
std::unique_ptr<Sprite> sprite_; // Sprite con los gráficos y métodos de pintado
int pos_x_; // Posición en el eje X
int pos_y_; // Posición en el eje Y
Uint8 width_; // Ancho del objeto
Uint8 height_; // Alto del objeto
int vel_x_; // Velocidad en el eje X
int vel_y_; // Velocidad en el eje Y
BulletType kind_; // Tipo de objeto
int owner_; // Identificador del dueño del objeto
Circle collider_; // Círculo de colisión del objeto
SDL_Rect *play_area_; // Rectángulo con la zona de juego
void shiftColliders(); // Alinea el círculo de colisión con el objeto
public:

View File

@@ -1,8 +1,10 @@
#include "define_buttons.h"
#include <utility> // for move
#include "input.h" // for Input, InputType
#include "lang.h" // for getText
#include "options.h" // for options
#include "param.h" // for param
#include "section.h" // for name, SectionName, options, SectionOptions
#include "section.h" // for Name, Options, name, options
#include "text.h" // for Text
#include "utils.h" // for OptionsController, Options, Param, ParamGame
@@ -24,27 +26,27 @@ DefineButtons::DefineButtons(std::unique_ptr<Text> text_)
DefineButtonsButton button;
button.label = lang::getText(95);
button.input = input_fire_left;
button.input = InputType::FIRE_LEFT;
button.button = SDL_CONTROLLER_BUTTON_X;
buttons_.push_back(button);
button.label = lang::getText(96);
button.input = input_fire_center;
button.input = InputType::FIRE_CENTER;
button.button = SDL_CONTROLLER_BUTTON_Y;
buttons_.push_back(button);
button.label = lang::getText(97);
button.input = input_fire_right;
button.input = InputType::FIRE_RIGHT;
button.button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
buttons_.push_back(button);
button.label = lang::getText(98);
button.input = input_start;
button.input = InputType::START;
button.button = SDL_CONTROLLER_BUTTON_START;
buttons_.push_back(button);
button.label = lang::getText(99);
button.input = input_exit;
button.input = InputType::EXIT;
button.button = SDL_CONTROLLER_BUTTON_BACK;
buttons_.push_back(button);
@@ -104,7 +106,7 @@ void DefineButtons::checkInput()
case SDL_QUIT:
{
section::name = section::Name::QUIT;
section::options = section::Options::QUIT_NORMAL;
section::options = section::Options::QUIT_WITH_KEYBOARD;
break;
}
@@ -155,7 +157,7 @@ void DefineButtons::incIndexButton()
// Guarda los cambios en las opciones
saveBindingsToOptions();
input_->allActive(index_controller_);
// input_->allActive(index_controller_);
// Reinicia variables
index_button_ = 0;

View File

@@ -1,17 +1,18 @@
#pragma once
#include <SDL2/SDL_events.h> // for SDL_ControllerButtonEvent
#include <SDL2/SDL_gamecontroller.h> // for SDL_GameControllerButton
#include <string> // for string, basic_string
#include <vector> // for vector
#include "input.h" // for inputs_e
#include "text.h"
#include <memory>
#include <SDL2/SDL_events.h> // for SDL_ControllerButtonEvent
#include <SDL2/SDL_gamecontroller.h> // for SDL_GameControllerButton
#include <memory> // for shared_ptr, unique_ptr
#include <string> // for string
#include <vector> // for vector
class Input;
class Text;
enum class InputType : int;
struct DefineButtonsButton
{
std::string label; // Texto en pantalla para el botón
inputs_e input; // Input asociado
InputType input; // Input asociado
SDL_GameControllerButton button; // Botón del mando correspondiente
};
@@ -46,7 +47,7 @@ private:
public:
// Constructor
DefineButtons(std::unique_ptr<Text> text);
explicit DefineButtons(std::unique_ptr<Text> text);
// Destructor
~DefineButtons() = default;

View File

@@ -5,43 +5,47 @@
#include <SDL2/SDL_error.h> // for SDL_GetError
#include <SDL2/SDL_gamecontroller.h> // for SDL_CONTROLLER_BUTTON_B, SDL_CO...
#include <SDL2/SDL_hints.h> // for SDL_SetHint, SDL_HINT_RENDER_DR...
#include <SDL2/SDL_scancode.h> // for SDL_SCANCODE_DOWN, SDL_SCANCODE_E
#include <SDL2/SDL_stdinc.h> // for Uint32
#include <SDL2/SDL_scancode.h> // for SDL_SCANCODE_0, SDL_SCANCODE_DOWN
#include <SDL2/SDL_stdinc.h> // for SDL_bool, Uint32
#include <SDL2/SDL_timer.h> // for SDL_GetTicks
#include <errno.h> // for errno, EACCES, EEXIST, ENAMETOO...
#include <stdio.h> // for printf, perror, size_t
#include <cstdlib> // for system
#include <errno.h> // for errno, EEXIST, EACCES, ENAMETOO...
#include <stdio.h> // for printf, perror
#include <string.h> // for strcmp
#include <sys/stat.h> // for stat, mkdir, S_IRWXU
#include <sys/stat.h> // for mkdir, stat, S_IRWXU
#include <unistd.h> // for getuid
#include <cstdlib> // for exit, EXIT_FAILURE, rand, srand
#include <iostream> // for basic_ostream, operator<<, cout
#include <string> // for basic_string, operator+, allocator
#include "asset.h" // for Asset, assetType
#include <memory> // for make_unique, unique_ptr
#include <string> // for operator+, allocator, char_traits
#include "asset.h" // for Asset, AssetType
#include "dbgtxt.h" // for dbg_init
#include "game.h" // for Game, GAME_MODE_DEMO_OFF, GAME_...
#include "global_inputs.h"
#include "hiscore_table.h" // for HiScoreTable
#include "input.h" // for inputs_e, Input
#include "instructions.h" // for Instructions
#include "intro.h" // for Intro
#include "jail_audio.h" // for JA_DeleteMusic, JA_DeleteSound
#include "logo.h" // for Logo
#include "manage_hiscore_table.h" // for ManageHiScoreTable
#include "on_screen_help.h" // for OnScreenHelp
#include "options.h" // for options, loadOptionsFile, saveO...
#include "param.h" // for param, loadParamsFromFile
#include "screen.h" // for Screen
#include "section.h" // for SectionName, name, options, SectionOptions
#include "title.h" // for Title
#include "utils.h" // for MusicFile, SoundFile, opt...
#include <memory>
#include "global_inputs.h" // for init
#include "hiscore_table.h" // for HiScoreTable
#include "input.h" // for Input, InputType
#include "instructions.h" // for Instructions
#include "intro.h" // for Intro
#include "jail_audio.h" // for JA_LoadMusic, JA_LoadSound, JA_...
#include "lang.h" // for Code, loadFromFile
#include "logo.h" // for Logo
#include "manage_hiscore_table.h" // for ManageHiScoreTable
#include "notifier.h" // for Notifier
#include "on_screen_help.h" // for OnScreenHelp
#include "options.h" // for options, loadOptionsFile, saveO...
#include "param.h" // for param, loadParamsFromFile
#include "resource.h" //for Resource
#include "screen.h" // for Screen
#include "section.h" // for Name, name, Options, options
#include "title.h" // for Title
#include "utils.h" // for MusicFile, SoundFile, Options
#ifndef _WIN32
#include <pwd.h> // for getpwuid, passwd
#endif
// Constructor
Director::Director(int argc, char *argv[])
Director::Director(int argc, const char *argv[])
{
#ifdef RECORDING
section::name = section::Name::GAME;
@@ -52,6 +56,14 @@ Director::Director(int argc, char *argv[])
section::name = section::Name::LOGO;
#endif
#ifndef VERBOSE
// Deshabilita todos los std::cout
std::ostream null_stream(nullptr);
orig_buf = std::cout.rdbuf(null_stream.rdbuf());
#endif
std::cout << "Game start" << std::endl;
// Comprueba los parametros del programa
checkProgramArguments(argc, argv);
@@ -62,11 +74,8 @@ Director::Director(int argc, char *argv[])
// Crea el objeto que controla los ficheros de recursos
Asset::init(executable_path_);
// Si falta algún fichero no inicia el programa
if (!setFileList())
{
exit(EXIT_FAILURE);
}
// Crea el indice de ficheros
setFileList();
// Carga el fichero de configuración
loadOptionsFile(Asset::get()->get("config.txt"));
@@ -93,21 +102,20 @@ Director::Director(int argc, char *argv[])
dbg_init(renderer_);
// Crea los objetos
lang::loadFromFile(getLangFile((lang::lang_e)options.game.language));
Input::init(Asset::get()->get("gamecontrollerdb.txt"));
initInput();
lang::loadFromFile(getLangFile((lang::Code)options.game.language));
Screen::init(window_, renderer_);
Resource::init();
Input::init(Asset::get()->get("gamecontrollerdb.txt"));
bindInputs();
auto notifier_text = std::make_shared<Text>(Resource::get()->getTexture("8bithud.png"), Resource::get()->getTextFile("8bithud.txt"));
Notifier::init(std::string(), notifier_text, Asset::get()->get("notify.wav"));
OnScreenHelp::init();
// Carga los sonidos del juego
loadSounds();
// Carga las musicas del juego
loadMusics();
globalInputs::init();
}
@@ -116,85 +124,77 @@ Director::~Director()
saveOptionsFile(Asset::get()->get("config.txt"));
Asset::destroy();
Resource::destroy();
Input::destroy();
Screen::destroy();
Notifier::destroy();
OnScreenHelp::destroy();
sounds_.clear();
musics_.clear();
SDL_DestroyRenderer(renderer_);
SDL_DestroyWindow(window_);
SDL_Quit();
std::cout << "\nBye!" << std::endl;
}
/// Inicializa el objeto input
void Director::initInput()
// Asigna los botones y teclas al objeto Input
void Director::bindInputs()
{
// Establece si ha de mostrar mensajes
#ifdef VERBOSE
Input::get()->setVerbose(true);
#else
Input::get()->setVerbose(false);
#endif
// Busca si hay mandos conectados
Input::get()->discoverGameControllers();
// Teclado - Movimiento del jugador
Input::get()->bindKey(input_up, SDL_SCANCODE_UP);
Input::get()->bindKey(input_down, SDL_SCANCODE_DOWN);
Input::get()->bindKey(input_left, SDL_SCANCODE_LEFT);
Input::get()->bindKey(input_right, SDL_SCANCODE_RIGHT);
Input::get()->bindKey(InputType::UP, SDL_SCANCODE_UP);
Input::get()->bindKey(InputType::DOWN, SDL_SCANCODE_DOWN);
Input::get()->bindKey(InputType::LEFT, SDL_SCANCODE_LEFT);
Input::get()->bindKey(InputType::RIGHT, SDL_SCANCODE_RIGHT);
Input::get()->bindKey(input_fire_left, SDL_SCANCODE_Q);
Input::get()->bindKey(input_fire_center, SDL_SCANCODE_W);
Input::get()->bindKey(input_fire_right, SDL_SCANCODE_E);
Input::get()->bindKey(InputType::FIRE_LEFT, SDL_SCANCODE_Q);
Input::get()->bindKey(InputType::FIRE_CENTER, SDL_SCANCODE_W);
Input::get()->bindKey(InputType::FIRE_RIGHT, SDL_SCANCODE_E);
Input::get()->bindKey(input_start, SDL_SCANCODE_RETURN);
Input::get()->bindKey(InputType::START, SDL_SCANCODE_RETURN);
// Teclado - Control del programa
Input::get()->bindKey(input_service, SDL_SCANCODE_0);
Input::get()->bindKey(input_exit, SDL_SCANCODE_ESCAPE);
Input::get()->bindKey(input_pause, SDL_SCANCODE_P);
Input::get()->bindKey(input_window_dec_size, SDL_SCANCODE_F1);
Input::get()->bindKey(input_window_inc_size, SDL_SCANCODE_F2);
Input::get()->bindKey(input_window_fullscreen, SDL_SCANCODE_F3);
Input::get()->bindKey(input_video_shaders, SDL_SCANCODE_F4);
Input::get()->bindKey(input_mute, SDL_SCANCODE_F5);
Input::get()->bindKey(input_showinfo, SDL_SCANCODE_F6);
Input::get()->bindKey(input_reset, SDL_SCANCODE_F10);
Input::get()->bindKey(InputType::SERVICE, SDL_SCANCODE_0);
Input::get()->bindKey(InputType::EXIT, SDL_SCANCODE_ESCAPE);
Input::get()->bindKey(InputType::PAUSE, SDL_SCANCODE_P);
Input::get()->bindKey(InputType::WINDOW_DEC_SIZE, SDL_SCANCODE_F1);
Input::get()->bindKey(InputType::WINDOW_INC_SIZE, SDL_SCANCODE_F2);
Input::get()->bindKey(InputType::WINDOW_FULLSCREEN, SDL_SCANCODE_F3);
Input::get()->bindKey(InputType::VIDEO_SHADERS, SDL_SCANCODE_F4);
Input::get()->bindKey(InputType::MUTE, SDL_SCANCODE_F5);
Input::get()->bindKey(InputType::SHOWINFO, SDL_SCANCODE_F6);
Input::get()->bindKey(InputType::RESET, SDL_SCANCODE_F10);
// Asigna botones a inputs
const int numGamePads = Input::get()->getNumControllers();
for (int i = 0; i < numGamePads; ++i)
const int num_gamepads = Input::get()->getNumControllers();
for (int i = 0; i < num_gamepads; ++i)
{
// Mando - Movimiento del jugador
Input::get()->bindGameControllerButton(i, input_up, SDL_CONTROLLER_BUTTON_DPAD_UP);
Input::get()->bindGameControllerButton(i, input_down, SDL_CONTROLLER_BUTTON_DPAD_DOWN);
Input::get()->bindGameControllerButton(i, input_left, SDL_CONTROLLER_BUTTON_DPAD_LEFT);
Input::get()->bindGameControllerButton(i, input_right, SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
Input::get()->bindGameControllerButton(i, InputType::UP, SDL_CONTROLLER_BUTTON_DPAD_UP);
Input::get()->bindGameControllerButton(i, InputType::DOWN, SDL_CONTROLLER_BUTTON_DPAD_DOWN);
Input::get()->bindGameControllerButton(i, InputType::LEFT, SDL_CONTROLLER_BUTTON_DPAD_LEFT);
Input::get()->bindGameControllerButton(i, InputType::RIGHT, SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
Input::get()->bindGameControllerButton(i, input_fire_left, SDL_CONTROLLER_BUTTON_X);
Input::get()->bindGameControllerButton(i, input_fire_center, SDL_CONTROLLER_BUTTON_Y);
Input::get()->bindGameControllerButton(i, input_fire_right, SDL_CONTROLLER_BUTTON_B);
Input::get()->bindGameControllerButton(i, InputType::FIRE_LEFT, SDL_CONTROLLER_BUTTON_X);
Input::get()->bindGameControllerButton(i, InputType::FIRE_CENTER, SDL_CONTROLLER_BUTTON_Y);
Input::get()->bindGameControllerButton(i, InputType::FIRE_RIGHT, SDL_CONTROLLER_BUTTON_B);
Input::get()->bindGameControllerButton(i, input_start, SDL_CONTROLLER_BUTTON_START);
Input::get()->bindGameControllerButton(i, InputType::START, SDL_CONTROLLER_BUTTON_START);
// Mando - Control del programa
Input::get()->bindGameControllerButton(i, input_service, SDL_CONTROLLER_BUTTON_BACK);
Input::get()->bindGameControllerButton(i, input_exit, input_start);
Input::get()->bindGameControllerButton(i, input_pause, input_fire_right);
Input::get()->bindGameControllerButton(i, input_video_shaders, input_fire_left);
Input::get()->bindGameControllerButton(i, input_mute, input_left);
Input::get()->bindGameControllerButton(i, input_showinfo, input_right);
Input::get()->bindGameControllerButton(i, input_reset, input_fire_center);
Input::get()->bindGameControllerButton(i, input_config, input_down);
Input::get()->bindGameControllerButton(i, input_swap_controllers, input_up);
Input::get()->bindGameControllerButton(i, InputType::SERVICE, SDL_CONTROLLER_BUTTON_BACK);
Input::get()->bindGameControllerButton(i, InputType::EXIT, InputType::START);
Input::get()->bindGameControllerButton(i, InputType::PAUSE, InputType::FIRE_RIGHT);
Input::get()->bindGameControllerButton(i, InputType::VIDEO_SHADERS, InputType::FIRE_LEFT);
Input::get()->bindGameControllerButton(i, InputType::MUTE, InputType::LEFT);
Input::get()->bindGameControllerButton(i, InputType::SHOWINFO, InputType::RIGHT);
Input::get()->bindGameControllerButton(i, InputType::RESET, InputType::FIRE_CENTER);
Input::get()->bindGameControllerButton(i, InputType::CONFIG, InputType::DOWN);
Input::get()->bindGameControllerButton(i, InputType::SWAP_CONTROLLERS, InputType::UP);
}
// Mapea las asignaciones a los botones desde el archivo de configuración, si se da el caso
for (int i = 0; i < numGamePads; ++i)
for (int i = 0; i < num_gamepads; ++i)
for (int index = 0; index < (int)options.controller.size(); ++index)
if (Input::get()->getControllerName(i) == options.controller[index].name)
{
@@ -206,20 +206,20 @@ void Director::initInput()
}
// Asigna botones a inputs desde otros inputs
for (int i = 0; i < numGamePads; ++i)
for (int i = 0; i < num_gamepads; ++i)
{
Input::get()->bindGameControllerButton(i, input_exit, input_start);
Input::get()->bindGameControllerButton(i, input_reset, input_fire_center);
Input::get()->bindGameControllerButton(i, input_pause, input_fire_right);
Input::get()->bindGameControllerButton(i, input_video_shaders, input_fire_left);
Input::get()->bindGameControllerButton(i, input_mute, input_left);
Input::get()->bindGameControllerButton(i, input_showinfo, input_right);
Input::get()->bindGameControllerButton(i, input_config, input_down);
Input::get()->bindGameControllerButton(i, input_swap_controllers, input_up);
Input::get()->bindGameControllerButton(i, InputType::EXIT, InputType::START);
Input::get()->bindGameControllerButton(i, InputType::RESET, InputType::FIRE_CENTER);
Input::get()->bindGameControllerButton(i, InputType::PAUSE, InputType::FIRE_RIGHT);
Input::get()->bindGameControllerButton(i, InputType::VIDEO_SHADERS, InputType::FIRE_LEFT);
Input::get()->bindGameControllerButton(i, InputType::MUTE, InputType::LEFT);
Input::get()->bindGameControllerButton(i, InputType::SHOWINFO, InputType::RIGHT);
Input::get()->bindGameControllerButton(i, InputType::CONFIG, InputType::DOWN);
Input::get()->bindGameControllerButton(i, InputType::SWAP_CONTROLLERS, InputType::UP);
}
// Guarda las asignaciones de botones en las opciones
for (int i = 0; i < numGamePads; ++i)
for (int i = 0; i < num_gamepads; ++i)
{
options.controller[i].name = Input::get()->getControllerName(i);
for (int j = 0; j < (int)options.controller[i].inputs.size(); ++j)
@@ -248,9 +248,7 @@ bool Director::initSDL()
// Inicializa SDL
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
#ifdef VERBOSE
std::cout << "SDL could not initialize!\nSDL Error: " << SDL_GetError() << std::endl;
#endif
success = false;
}
else
@@ -258,7 +256,6 @@ bool Director::initSDL()
// Inicia el generador de numeros aleatorios
std::srand(static_cast<unsigned int>(SDL_GetTicks()));
#ifdef VERBOSE
// Muestra información de la pantalla
/*std::cout << "\nDisplay modes list:" << std::endl;
for (int i = 0; i < SDL_GetNumDisplayModes(0); ++i)
@@ -272,30 +269,23 @@ bool Director::initSDL()
SDL_GetCurrentDisplayMode(0, &DM);
std::cout << "\nCurrent display mode: " + std::to_string(DM.w) + "x" + std::to_string(DM.h) + " @ " + std::to_string(DM.refresh_rate) + "Hz" << std::endl;
std::cout << "Window resolution : " + std::to_string(param.game.width) + "x" + std::to_string(param.game.height) + " x" + std::to_string(options.video.window.size) << std::endl;
#endif
// Establece el filtro de la textura
if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, std::to_string(static_cast<int>(options.video.filter)).c_str()))
{
#ifdef VERBOSE
std::cout << "Warning: texture filtering not enabled!\n";
#endif
}
#ifndef NO_SHADERS
if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"))
{
#ifdef VERBOSE
std::cout << "Warning: opengl not enabled!\n";
#endif // VERBOSE
}
#endif // NO_SHADERS
// Crea la ventana
window_ = SDL_CreateWindow(WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, param.game.width * options.video.window.size, param.game.height * options.video.window.size, SDL_WINDOW_HIDDEN);
if (!window_)
{
#ifdef VERBOSE
std::cout << "Window could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
#endif
success = false;
}
else
@@ -304,7 +294,7 @@ bool Director::initSDL()
Uint32 flags = 0;
if (options.video.v_sync)
{
flags = flags | SDL_RENDERER_PRESENTVSYNC;
flags = SDL_RENDERER_PRESENTVSYNC;
}
#ifndef NO_SHADERS
// La aceleración se activa según el define
@@ -314,9 +304,7 @@ bool Director::initSDL()
if (!renderer_)
{
#ifdef VERBOSE
std::cout << "Renderer could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
#endif
success = false;
}
else
@@ -334,19 +322,17 @@ bool Director::initSDL()
}
}
#ifdef VERBOSE
std::cout << std::endl;
#endif
return success;
}
// Crea el indice de ficheros
bool Director::setFileList()
void Director::setFileList()
{
#ifdef MACOS_BUNDLE
const std::string prefix = "/../Resources";
#else
const std::string prefix = "";
const std::string prefix;
#endif
// Ficheros de configuración
@@ -385,94 +371,127 @@ bool Director::setFileList()
Asset::get()->add(prefix + "/data/shaders/crtpi.glsl", AssetType::DATA);
// Texturas
Asset::get()->add(prefix + "/data/gfx/controllers/controllers.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon1.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon1.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon2.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon2.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon3.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon3.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon4.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon4.ani", AssetType::ANIMATION);
{ // Controllers
Asset::get()->add(prefix + "/data/gfx/controllers/controllers.png", AssetType::BITMAP);
}
Asset::get()->add(prefix + "/data/gfx/balloon/explosion1.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion1.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion2.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion2.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion3.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion3.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion4.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion4.ani", AssetType::ANIMATION);
{ // Balloons
Asset::get()->add(prefix + "/data/gfx/balloon/balloon1.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon1.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon2.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon2.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon3.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon3.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon4.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/balloon4.ani", AssetType::ANIMATION);
}
Asset::get()->add(prefix + "/data/gfx/balloon/powerball.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/powerball.ani", AssetType::ANIMATION);
{ // Explosions
Asset::get()->add(prefix + "/data/gfx/balloon/explosion1.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion1.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion2.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion2.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion3.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion3.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion4.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/explosion4.ani", AssetType::ANIMATION);
}
Asset::get()->add(prefix + "/data/gfx/bullet/bullet.png", AssetType::BITMAP);
{ // Power Ball
Asset::get()->add(prefix + "/data/gfx/balloon/powerball.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/balloon/powerball.ani", AssetType::ANIMATION);
}
Asset::get()->add(prefix + "/data/gfx/game/game_buildings.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_clouds1.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_clouds2.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_grass.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_power_meter.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_sky_colors.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_text.png", AssetType::BITMAP);
{ // Bala
Asset::get()->add(prefix + "/data/gfx/bullet/bullet.png", AssetType::BITMAP);
}
Asset::get()->add(prefix + "/data/gfx/intro/intro.png", AssetType::BITMAP);
{ // Juego
Asset::get()->add(prefix + "/data/gfx/game/game_buildings.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_clouds1.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_clouds2.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_grass.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_power_meter.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_sky_colors.png", AssetType::BITMAP);
}
Asset::get()->add(prefix + "/data/gfx/logo/logo_jailgames.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/logo/logo_jailgames_mini.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/logo/logo_since_1998.png", AssetType::BITMAP);
{ // Game Text
Asset::get()->add(prefix + "/data/gfx/game_text/game_text_1000_points.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game_text/game_text_2500_points.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game_text/game_text_5000_points.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game_text/game_text_powerup.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game_text/game_text_one_hit.png", AssetType::BITMAP);
}
Asset::get()->add(prefix + "/data/gfx/item/item_points1_disk.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_points1_disk.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/item/item_points2_gavina.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_points2_gavina.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/item/item_points3_pacmar.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_points3_pacmar.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/item/item_clock.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_clock.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/item/item_coffee.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_coffee.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/item/item_coffee_machine.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_coffee_machine.ani", AssetType::ANIMATION);
{ // Intro
Asset::get()->add(prefix + "/data/gfx/intro/intro.png", AssetType::BITMAP);
}
Asset::get()->add(prefix + "/data/gfx/title/title_bg_tile.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/title/title_coffee.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/title/title_crisis.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/title/title_arcade_edition.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/title/title_dust.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/title/title_dust.ani", AssetType::ANIMATION);
{ // Logo
Asset::get()->add(prefix + "/data/gfx/logo/logo_jailgames.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/logo/logo_jailgames_mini.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/logo/logo_since_1998.png", AssetType::BITMAP);
}
Asset::get()->add(prefix + "/data/gfx/player/player1.gif", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/player/player1_pal1.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player1_pal2.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player1_pal3.gif", AssetType::PALETTE);
{ // Items
Asset::get()->add(prefix + "/data/gfx/item/item_points1_disk.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_points1_disk.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/item/item_points2_gavina.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_points2_gavina.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/item/item_points3_pacmar.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_points3_pacmar.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/item/item_clock.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_clock.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/item/item_coffee.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_coffee.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/item/item_coffee_machine.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_coffee_machine.ani", AssetType::ANIMATION);
}
Asset::get()->add(prefix + "/data/gfx/player/player2.gif", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/player/player2_pal1.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player2_pal2.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player2_pal3.gif", AssetType::PALETTE);
{ // Titulo
Asset::get()->add(prefix + "/data/gfx/title/title_bg_tile.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/title/title_coffee.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/title/title_crisis.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/title/title_arcade_edition.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/title/title_dust.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/title/title_dust.ani", AssetType::ANIMATION);
}
Asset::get()->add(prefix + "/data/gfx/player/player.ani", AssetType::ANIMATION);
{ // Jugador 1
Asset::get()->add(prefix + "/data/gfx/player/player1.gif", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/player/player1_one_coffee_palette.pal", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player1_two_coffee_palette.pal", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player1_all_white_palette.pal", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player1_power.png", AssetType::BITMAP);
}
Asset::get()->add(prefix + "/data/gfx/player/player_power.gif", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/player/player_power_pal.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player_power.ani", AssetType::ANIMATION);
{ // Jugador 2
Asset::get()->add(prefix + "/data/gfx/player/player2.gif", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/player/player2_one_coffee_palette.pal", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player2_two_coffee_palette.pal", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player2_all_white_palette.pal", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player2_power.png", AssetType::BITMAP);
}
{ // Animaciones del jugador
Asset::get()->add(prefix + "/data/gfx/player/player.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/player/player_power.ani", AssetType::ANIMATION);
}
// Fuentes de texto
Asset::get()->add(prefix + "/data/font/8bithud.png", AssetType::FONT);
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::FONT);
Asset::get()->add(prefix + "/data/font/nokia_big2.png", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/nokia.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/font/nokia_big2.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/font/nokia.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/nokia2.png", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/nokia2.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/font/nokia2.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/nokia_big2.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/smb2_big.png", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/smb2_big.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/font/smb2_big.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/smb2.gif", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/smb2_pal1.gif", AssetType::PALETTE);
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);
// Textos
@@ -480,25 +499,27 @@ bool Director::setFileList()
Asset::get()->add(prefix + "/data/lang/en_UK.txt", AssetType::LANG);
Asset::get()->add(prefix + "/data/lang/ba_BA.txt", AssetType::LANG);
return Asset::get()->check();
// Si falta algun fichero, sale del programa
if (!Asset::get()->check())
throw std::runtime_error("Falta algun fichero");
}
// Carga los parametros para configurar el juego
void Director::loadParams(std::string filepath)
void Director::loadParams(const std::string &file_path)
{
loadParamsFromFile(filepath);
loadParamsFromFile(file_path);
}
// Comprueba los parametros del programa
void Director::checkProgramArguments(int argc, char *argv[])
void Director::checkProgramArguments(int argc, const char *argv[])
{
// Establece la ruta del programa
executable_path_ = argv[0];
// Valores por defecto
param_file_argument_ = "";
param_file_argument_.clear();
// Comprueba el resto de parametros
// Comprueba el resto de parámetros
for (int i = 1; i < argc; ++i)
{
if (strcmp(argv[i], "--320x240") == 0)
@@ -509,7 +530,7 @@ void Director::checkProgramArguments(int argc, char *argv[])
}
// Crea la carpeta del sistema donde guardar datos
void Director::createSystemFolder(std::string folder)
void Director::createSystemFolder(const std::string &folder)
{
#ifdef _WIN32
system_folder_ = std::string(getenv("APPDATA")) + "/" + folder;
@@ -568,100 +589,57 @@ void Director::createSystemFolder(std::string folder)
}
}
// Carga los sonidos del juego
void Director::loadSounds()
{
// Obtiene la lista con las rutas a los ficheros de sonidos
std::vector<std::string> list = Asset::get()->getListByType(AssetType::SOUND);
sounds_.clear();
for (auto l : list)
{
const size_t lastIndex = l.find_last_of("/") + 1;
const std::string name = l.substr(lastIndex, std::string::npos);
SoundFile temp;
temp.name = name; // Añade el nombre del fichero
temp.file = JA_LoadSound(l.c_str()); // Carga el fichero de audio
sounds_.push_back(temp);
}
}
// Carga las musicas del juego
void Director::loadMusics()
{
// Obtiene la lista con las rutas a los ficheros musicales
std::vector<std::string> list = Asset::get()->getListByType(AssetType::MUSIC);
musics_.clear();
for (auto l : list)
{
const size_t lastIndex = l.find_last_of("/") + 1;
const std::string name = l.substr(lastIndex, std::string::npos);
MusicFile temp;
temp.name = name; // Añade el nombre del fichero
temp.file = JA_LoadMusic(l.c_str()); // Carga el fichero de audio
musics_.push_back(temp);
}
}
// Ejecuta la sección con el logo
void Director::runLogo()
{
auto logo = new Logo();
auto logo = std::make_unique<Logo>();
logo->run();
delete logo;
}
// Ejecuta la sección con la secuencia de introducción
void Director::runIntro()
{
auto intro = new Intro(getMusic(musics_, "intro.ogg"));
auto intro = std::make_unique<Intro>();
intro->run();
delete intro;
}
// Ejecuta la sección con el titulo del juego
// Ejecuta la sección con el título del juego
void Director::runTitle()
{
auto title = new Title(getMusic(musics_, "title.ogg"));
auto title = std::make_unique<Title>();
title->run();
delete title;
}
// Ejecuta la sección donde se juega al juego
void Director::runGame()
{
const auto playerID = section::options == section::Options::GAME_PLAY_1P ? 1 : 2;
constexpr auto currentStage = 0;
auto game = new Game(playerID, currentStage, GAME_MODE_DEMO_OFF, getMusic(musics_, "playing.ogg"));
const auto player_id = section::options == section::Options::GAME_PLAY_1P ? 1 : 2;
constexpr auto current_stage = 0;
auto game = std::make_unique<Game>(player_id, current_stage, GAME_MODE_DEMO_OFF);
game->run();
delete game;
}
// Ejecuta la sección donde se muestran las instrucciones
void Director::runInstructions()
{
auto instructions = new Instructions(getMusic(musics_, "title.ogg"));
auto instructions = std::make_unique<Instructions>();
instructions->run();
delete instructions;
}
// Ejecuta la sección donde se muestra la tabla de puntuaciones
void Director::runHiScoreTable()
{
auto hiScoreTable = new HiScoreTable(getMusic(musics_, "title.ogg"));
hiScoreTable->run();
delete hiScoreTable;
auto hi_score_table = std::make_unique<HiScoreTable>();
hi_score_table->run();
}
// Ejecuta el juego en modo demo
void Director::runDemoGame()
{
const auto playerID = (rand() % 2) + 1;
constexpr auto currentStage = 0;
auto game = new Game(playerID, currentStage, GAME_MODE_DEMO_ON, nullptr);
const auto player_id = (rand() % 2) + 1;
constexpr auto current_stage = 0;
auto game = std::make_unique<Game>(player_id, current_stage, GAME_MODE_DEMO_ON);
game->run();
delete game;
}
int Director::run()
@@ -708,24 +686,38 @@ int Director::run()
}
}
const int returnCode = section::options == section::Options::QUIT_NORMAL ? 0 : 1;
return returnCode;
#ifdef ARCADE
// Comprueba si ha de apagar el sistema
if (section::options == section::Options::QUIT_WITH_CONTROLLER)
shutdownSystem();
#endif
const auto return_code = (section::options == section::Options::QUIT_WITH_KEYBOARD) ? "with keyboard" : (section::options == section::Options::QUIT_WITH_CONTROLLER) ? "with controller"
: "from event";
std::cout << "\nGame end " << return_code << std::endl;
#ifndef VERBOSE
// Habilita de nuevo los std::cout
std::cout.rdbuf(orig_buf);
#endif
return (section::options == section::Options::QUIT_WITH_CONTROLLER) ? 1 : 0;
}
// Obtiene una fichero a partir de un lang_e
std::string Director::getLangFile(lang::lang_e lang)
// Obtiene una fichero a partir de un lang::Code
std::string Director::getLangFile(lang::Code code)
{
switch (lang)
switch (code)
{
case lang::ba_BA:
case lang::Code::ba_BA:
return Asset::get()->get("ba_BA.txt");
break;
case lang::es_ES:
case lang::Code::es_ES:
return Asset::get()->get("es_ES.txt");
break;
case lang::en_UK:
case lang::Code::en_UK:
return Asset::get()->get("en_UK.txt");
break;
@@ -734,4 +726,22 @@ std::string Director::getLangFile(lang::lang_e lang)
}
return Asset::get()->get("en_UK.txt");
}
// Apaga el sistema
void Director::shutdownSystem()
{
#ifdef _WIN32
// Apaga el sistema en Windows
system("shutdown /s /t 0");
#elif __APPLE__
// Apaga el sistema en macOS
system("sudo shutdown -h now");
#elif __linux__
// Apaga el sistema en Linux
system("shutdown -h now");
#else
// Sistema operativo no compatible
#error "Sistema operativo no soportado"
#endif
}

View File

@@ -2,10 +2,14 @@
#include <SDL2/SDL_render.h> // for SDL_Renderer
#include <SDL2/SDL_video.h> // for SDL_Window
#include <string> // for string, basic_string
#include <string> // for string
#include <vector> // for vector
#include "lang.h" // for lang_e
#include "utils.h" // for MusicFile, SoundFile
namespace lang
{
enum class Code : int;
}
struct ResourceMusic;
struct ResourceSound;
// Textos
constexpr char WINDOW_CAPTION[] = "Coffee Crisis Arcade Edition";
@@ -14,15 +18,14 @@ class Director
{
private:
// Objetos y punteros
SDL_Window *window_; // La ventana donde dibujamos
SDL_Renderer *renderer_; // El renderizador de la ventana
SDL_Window *window_; // La ventana donde dibujamos
SDL_Renderer *renderer_; // El renderizador de la ventana
std::streambuf *orig_buf; // Puntero al buffer de flujo original para restaurar std::cout
// Variables
std::string executable_path_; // Path del ejecutable
std::string system_folder_; // Carpeta del sistema donde guardar datos
std::string executable_path_; // Path del ejecutable
std::string system_folder_; // Carpeta del sistema donde guardar datos
std::string param_file_argument_; // Argumento para gestionar el fichero con los parametros del programa
std::vector<SoundFile> sounds_; // Vector con los sonidos
std::vector<MusicFile> musics_; // Vector con las musicas
// Inicializa jail_audio
void initJailAudio();
@@ -30,26 +33,20 @@ private:
// Arranca SDL y crea la ventana
bool initSDL();
// Inicializa el objeto input
void initInput();
// Asigna los botones y teclas al objeto Input
void bindInputs();
// Carga los parametros para configurar el juego
void loadParams(std::string file_path);
void loadParams(const std::string &file_path);
// Crea el indice de ficheros
bool setFileList();
// Carga los sonidos del juego
void loadSounds();
// Carga las musicas del juego
void loadMusics();
void setFileList();
// Comprueba los parametros del programa
void checkProgramArguments(int argc, char *argv[]);
void checkProgramArguments(int argc, const char *argv[]);
// Crea la carpeta del sistema donde guardar datos
void createSystemFolder(std::string folder);
void createSystemFolder(const std::string &folder);
// Ejecuta la sección con el logo
void runLogo();
@@ -72,12 +69,15 @@ private:
// Ejecuta el juego en modo demo
void runDemoGame();
// Obtiene una fichero a partir de un lang_e
std::string getLangFile(lang::lang_e lang);
// Obtiene una fichero a partir de un lang::Code
std::string getLangFile(lang::Code code);
// Apaga el sistema
void shutdownSystem();
public:
// Constructor
Director(int argc, char *argv[]);
Director(int argc, const char *argv[]);
// Destructor
~Director();

View File

@@ -1,720 +0,0 @@
#include "enemy_formations.h"
#include "balloon.h" // for BALLOON_VELX_NEGATIVE, BALLOON_VELX_POSITIVE
#include "param.h" // for param
#include "utils.h" // for ParamGame, Param, Zone, BLOCK
// Constructor
EnemyFormations::EnemyFormations()
{
initEnemyFormations();
initEnemyPools();
initGameStages();
}
// Inicializa las formaciones enemigas
void EnemyFormations::initEnemyFormations()
{
constexpr int y4 = -BLOCK;
const int x4_0 = param.game.play_area.rect.x;
const int x4_100 = param.game.play_area.rect.w - BALLOON_WIDTH_4;
constexpr int y3 = -BLOCK;
const int x3_0 = param.game.play_area.rect.x;
const int x3_100 = param.game.play_area.rect.w - BALLOON_WIDTH_3;
constexpr int y2 = -BLOCK;
const int x2_0 = param.game.play_area.rect.x;
const int x2_100 = param.game.play_area.rect.w - BALLOON_WIDTH_2;
constexpr int y1 = -BLOCK;
const int x1_0 = param.game.play_area.rect.x;
const int x1_50 = param.game.play_area.center_x - (BALLOON_WIDTH_1 / 2);
const int x1_100 = param.game.play_area.rect.w - BALLOON_WIDTH_1;
// Inicializa a cero las variables
for (int i = 0; i < NUMBER_OF_ENEMY_FORMATIONS; i++)
{
enemy_formation_[i].number_of_enemies = 0;
for (int j = 0; j < MAX_NUMBER_OF_ENEMIES_IN_A_FORMATION; j++)
{
enemy_formation_[i].init[j].x = 0;
enemy_formation_[i].init[j].y = 0;
enemy_formation_[i].init[j].vel_x = 0;
enemy_formation_[i].init[j].kind = 0;
enemy_formation_[i].init[j].creation_counter = 0;
}
}
const int creationTime = 300;
int incX = 0;
int incTime = 0;
int j = 0;
// #00 - Dos enemigos BALLOON4 uno a cada extremo
j = 0;
enemy_formation_[j].number_of_enemies = 2;
incX = x4_100;
incTime = 0;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x4_0 + (i * incX);
enemy_formation_[j].init[i].y = y4;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE * (((i % 2) * 2) - 1);
enemy_formation_[j].init[i].kind = BALLOON_4;
enemy_formation_[j].init[i].creation_counter = creationTime + (incTime * i);
}
// #01 - Dos enemigos BALLOON4 uno a cada cuarto. Ambos van hacia el centro
j = 1;
enemy_formation_[j].number_of_enemies = 2;
incX = param.game.play_area.center_x;
incTime = 0;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = param.game.play_area.first_quarter_x - (BALLOON_WIDTH_4 / 2) + (i * incX);
enemy_formation_[j].init[i].y = y4;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE * (((i % 2) * 2) - 1);
enemy_formation_[j].init[i].kind = BALLOON_4;
enemy_formation_[j].init[i].creation_counter = creationTime + (incTime * i);
}
// #02 - Cuatro enemigos BALLOON2 uno detras del otro. A la izquierda y hacia el centro
j = 2;
enemy_formation_[j].number_of_enemies = 4;
incX = BALLOON_WIDTH_2 + 1;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x2_0 + (i * incX);
enemy_formation_[j].init[i].y = y2;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
enemy_formation_[j].init[i].kind = BALLOON_2;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #03 - Cuatro enemigos BALLOON2 uno detras del otro. A la derecha y hacia el centro
j = 3;
enemy_formation_[j].number_of_enemies = 4;
incX = BALLOON_WIDTH_2 + 1;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x2_100 - (i * incX);
enemy_formation_[j].init[i].y = y2;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
enemy_formation_[j].init[i].kind = BALLOON_2;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #04 - Tres enemigos BALLOON3. 0, 25, 50. Hacia la derecha
j = 4;
enemy_formation_[j].number_of_enemies = 3;
incX = BALLOON_WIDTH_3 * 2;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x3_0 + (i * incX);
enemy_formation_[j].init[i].y = y3;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
enemy_formation_[j].init[i].kind = BALLOON_3;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #05 - Tres enemigos BALLOON3. 50, 75, 100. Hacia la izquierda
j = 5;
enemy_formation_[j].number_of_enemies = 3;
incX = BALLOON_WIDTH_3 * 2;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x3_100 - (i * incX);
enemy_formation_[j].init[i].y = y3;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
enemy_formation_[j].init[i].kind = BALLOON_3;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #06 - Tres enemigos BALLOON3. 0, 0, 0. Hacia la derecha
j = 6;
enemy_formation_[j].number_of_enemies = 3;
incX = BALLOON_WIDTH_3 + 1;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x3_0 + (i * incX);
enemy_formation_[j].init[i].y = y3;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
enemy_formation_[j].init[i].kind = BALLOON_3;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #07 - Tres enemigos BALLOON3. 100, 100, 100. Hacia la izquierda
j = 7;
enemy_formation_[j].number_of_enemies = 3;
incX = BALLOON_WIDTH_3 + 1;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x3_100 - (i * incX);
enemy_formation_[j].init[i].y = y3;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
enemy_formation_[j].init[i].kind = BALLOON_3;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #08 - Seis enemigos BALLOON1. 0, 0, 0, 0, 0, 0. Hacia la derecha
j = 8;
enemy_formation_[j].number_of_enemies = 6;
incX = BALLOON_WIDTH_1 + 1;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x1_0 + (i * incX);
enemy_formation_[j].init[i].y = y1;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
enemy_formation_[j].init[i].kind = BALLOON_1;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #09 - Seis enemigos BALLOON1. 100, 100, 100, 100, 100, 100. Hacia la izquierda
j = 9;
enemy_formation_[j].number_of_enemies = 6;
incX = BALLOON_WIDTH_1 + 1;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x1_100 - (i * incX);
enemy_formation_[j].init[i].y = y1;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
enemy_formation_[j].init[i].kind = BALLOON_1;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #10 - Tres enemigos BALLOON4 seguidos desde la izquierda
j = 10;
enemy_formation_[j].number_of_enemies = 3;
incX = BALLOON_WIDTH_4 + 1;
incTime = 15;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x4_0 + (i * incX);
enemy_formation_[j].init[i].y = y4;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
enemy_formation_[j].init[i].kind = BALLOON_4;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #11 - Tres enemigos BALLOON4 seguidos desde la derecha
j = 11;
enemy_formation_[j].number_of_enemies = 3;
incX = BALLOON_WIDTH_4 + 1;
incTime = 15;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x4_100 - (i * incX);
enemy_formation_[j].init[i].y = y4;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
enemy_formation_[j].init[i].kind = BALLOON_4;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #12 - Seis enemigos BALLOON2 uno detras del otro. A la izquierda y hacia el centro
j = 12;
enemy_formation_[j].number_of_enemies = 6;
incX = BALLOON_WIDTH_2 + 1;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x2_0 + (i * incX);
enemy_formation_[j].init[i].y = y2;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
enemy_formation_[j].init[i].kind = BALLOON_2;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #13 - Seis enemigos BALLOON2 uno detras del otro. A la derecha y hacia el centro
j = 13;
enemy_formation_[j].number_of_enemies = 6;
incX = BALLOON_WIDTH_2 + 1;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x2_100 - (i * incX);
enemy_formation_[j].init[i].y = y2;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
enemy_formation_[j].init[i].kind = BALLOON_2;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #14 - Cinco enemigos BALLOON3. Hacia la derecha. Separados
j = 14;
enemy_formation_[j].number_of_enemies = 5;
incX = BALLOON_WIDTH_3 * 2;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x3_0 + (i * incX);
enemy_formation_[j].init[i].y = y3;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
enemy_formation_[j].init[i].kind = BALLOON_3;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #15 - Cinco enemigos BALLOON3. Hacia la izquierda. Separados
j = 15;
enemy_formation_[j].number_of_enemies = 5;
incX = BALLOON_WIDTH_3 * 2;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x3_100 - (i * incX);
enemy_formation_[j].init[i].y = y3;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
enemy_formation_[j].init[i].kind = BALLOON_3;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #16 - Cinco enemigos BALLOON3. Hacia la derecha. Juntos
j = 16;
enemy_formation_[j].number_of_enemies = 5;
incX = BALLOON_WIDTH_3 + 1;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x3_0 + (i * incX);
enemy_formation_[j].init[i].y = y3;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
enemy_formation_[j].init[i].kind = BALLOON_3;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #17 - Cinco enemigos BALLOON3. Hacia la izquierda. Juntos
j = 17;
enemy_formation_[j].number_of_enemies = 5;
incX = BALLOON_WIDTH_3 + 1;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x3_100 - (i * incX);
enemy_formation_[j].init[i].y = y3;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
enemy_formation_[j].init[i].kind = BALLOON_3;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #18 - Doce enemigos BALLOON1. Hacia la derecha. Juntos
j = 18;
enemy_formation_[j].number_of_enemies = 12;
incX = BALLOON_WIDTH_1 + 1;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x1_0 + (i * incX);
enemy_formation_[j].init[i].y = y1;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
enemy_formation_[j].init[i].kind = BALLOON_1;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #19 - Doce enemigos BALLOON1. Hacia la izquierda. Juntos
j = 19;
enemy_formation_[j].number_of_enemies = 12;
incX = BALLOON_WIDTH_1 + 1;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
enemy_formation_[j].init[i].x = x1_100 - (i * incX);
enemy_formation_[j].init[i].y = y1;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
enemy_formation_[j].init[i].kind = BALLOON_1;
enemy_formation_[j].init[i].creation_counter = creationTime - (incTime * i);
}
// #20 - Dos enemigos BALLOON4 seguidos desde la izquierda/derecha. Simetricos
j = 20;
enemy_formation_[j].number_of_enemies = 4;
incX = BALLOON_WIDTH_4 + 1;
incTime = 0;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
const int half = enemy_formation_[j].number_of_enemies / 2;
if (i < half)
{
enemy_formation_[j].init[i].x = x4_0 + (i * incX);
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
}
else
{
enemy_formation_[j].init[i].x = x4_100 - ((i - half) * incX);
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
}
enemy_formation_[j].init[i].y = y4;
enemy_formation_[j].init[i].kind = BALLOON_4;
enemy_formation_[j].init[i].creation_counter = creationTime + (incTime * i);
}
// #21 - Diez enemigos BALLOON2 uno detras del otro. Izquierda/derecha. Simetricos
j = 21;
enemy_formation_[j].number_of_enemies = 10;
incX = BALLOON_WIDTH_2 + 1;
incTime = 3;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
const int half = enemy_formation_[j].number_of_enemies / 2;
if (i < half)
{
enemy_formation_[j].init[i].x = x2_0 + (i * incX);
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
enemy_formation_[j].init[i].creation_counter = (creationTime) - (incTime * i);
}
else
{
enemy_formation_[j].init[i].x = x2_100 - ((i - half) * incX);
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
enemy_formation_[j].init[i].creation_counter = (creationTime) - (incTime * (i - half));
}
enemy_formation_[j].init[i].y = y2;
enemy_formation_[j].init[i].kind = BALLOON_2;
}
// #22 - Diez enemigos BALLOON3. Hacia la derecha/izquierda. Separados. Simetricos
j = 22;
enemy_formation_[j].number_of_enemies = 10;
incX = BALLOON_WIDTH_3 * 2;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
const int half = enemy_formation_[j].number_of_enemies / 2;
if (i < half)
{
enemy_formation_[j].init[i].x = x3_0 + (i * incX);
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
enemy_formation_[j].init[i].creation_counter = (creationTime) - (incTime * i);
}
else
{
enemy_formation_[j].init[i].x = x3_100 - ((i - half) * incX);
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
enemy_formation_[j].init[i].creation_counter = (creationTime) - (incTime * (i - half));
}
enemy_formation_[j].init[i].y = y3;
enemy_formation_[j].init[i].kind = BALLOON_3;
}
// #23 - Diez enemigos BALLOON3. Hacia la derecha. Juntos. Simetricos
j = 23;
enemy_formation_[j].number_of_enemies = 10;
incX = BALLOON_WIDTH_3 + 1;
incTime = 10;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
const int half = enemy_formation_[j].number_of_enemies / 2;
if (i < half)
{
enemy_formation_[j].init[i].x = x3_0 + (i * incX);
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
enemy_formation_[j].init[i].creation_counter = (creationTime) - (incTime * i);
}
else
{
enemy_formation_[j].init[i].x = x3_100 - ((i - half) * incX);
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
enemy_formation_[j].init[i].creation_counter = (creationTime) - (incTime * (i - half));
}
enemy_formation_[j].init[i].y = y3;
enemy_formation_[j].init[i].kind = BALLOON_3;
}
// #24 - Treinta enemigos BALLOON1. Del centro hacia los extremos. Juntos. Simetricos
j = 24;
enemy_formation_[j].number_of_enemies = 30;
incX = 0;
incTime = 5;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
const int half = enemy_formation_[j].number_of_enemies / 2;
if (i < half)
{
enemy_formation_[j].init[i].x = x1_50;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
enemy_formation_[j].init[i].creation_counter = (creationTime) + (incTime * i);
}
else
{
enemy_formation_[j].init[i].x = x1_50;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
enemy_formation_[j].init[i].creation_counter = (creationTime) + (incTime * (i - half));
}
enemy_formation_[j].init[i].y = y1;
enemy_formation_[j].init[i].kind = BALLOON_1;
}
// #25 - Treinta enemigos BALLOON1. Del centro hacia adentro. Juntos. Simetricos
j = 25;
enemy_formation_[j].number_of_enemies = 30;
incX = BALLOON_WIDTH_1 + 1;
incTime = 5;
for (int i = 0; i < enemy_formation_[j].number_of_enemies; i++)
{
const int half = enemy_formation_[j].number_of_enemies / 2;
if (i < half)
{
enemy_formation_[j].init[i].x = x1_50 + 20;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_NEGATIVE;
enemy_formation_[j].init[i].creation_counter = (creationTime) - (incTime * i);
}
else
{
enemy_formation_[j].init[i].x = x1_50 - 20;
enemy_formation_[j].init[i].vel_x = BALLOON_VELX_POSITIVE;
enemy_formation_[j].init[i].creation_counter = (creationTime) - (incTime * (i - half));
}
enemy_formation_[j].init[i].y = y1;
enemy_formation_[j].init[i].kind = BALLOON_1;
}
// Crea las mismas formaciones pero con hexagonos a partir de la posición 50 del vector
for (int k = 0; k < j + 1; k++)
{
enemy_formation_[k + 50].number_of_enemies = enemy_formation_[k].number_of_enemies;
for (int i = 0; i < enemy_formation_[k + 50].number_of_enemies; i++)
{
enemy_formation_[k + 50].init[i].x = enemy_formation_[k].init[i].x;
enemy_formation_[k + 50].init[i].y = enemy_formation_[k].init[i].y;
enemy_formation_[k + 50].init[i].vel_x = enemy_formation_[k].init[i].vel_x;
enemy_formation_[k + 50].init[i].creation_counter = enemy_formation_[k].init[i].creation_counter;
enemy_formation_[k + 50].init[i].kind = enemy_formation_[k].init[i].kind + 4;
}
}
// TEST
enemy_formation_[99].number_of_enemies = 4;
enemy_formation_[99].init[0].x = 10;
enemy_formation_[99].init[0].y = y1;
enemy_formation_[99].init[0].vel_x = 0;
enemy_formation_[99].init[0].kind = BALLOON_1;
enemy_formation_[99].init[0].creation_counter = 200;
enemy_formation_[99].init[1].x = 50;
enemy_formation_[99].init[1].y = y1;
enemy_formation_[99].init[1].vel_x = 0;
enemy_formation_[99].init[1].kind = BALLOON_2;
enemy_formation_[99].init[1].creation_counter = 200;
enemy_formation_[99].init[2].x = 90;
enemy_formation_[99].init[2].y = y1;
enemy_formation_[99].init[2].vel_x = 0;
enemy_formation_[99].init[2].kind = BALLOON_3;
enemy_formation_[99].init[2].creation_counter = 200;
enemy_formation_[99].init[3].x = 140;
enemy_formation_[99].init[3].y = y1;
enemy_formation_[99].init[3].vel_x = 0;
enemy_formation_[99].init[3].kind = BALLOON_4;
enemy_formation_[99].init[3].creation_counter = 200;
}
// Inicializa los conjuntos de formaciones
void EnemyFormations::initEnemyPools()
{
// EnemyPool #0
enemy_pool_[0].set[0] = &enemy_formation_[0];
enemy_pool_[0].set[1] = &enemy_formation_[1];
enemy_pool_[0].set[2] = &enemy_formation_[2];
enemy_pool_[0].set[3] = &enemy_formation_[3];
enemy_pool_[0].set[4] = &enemy_formation_[4];
enemy_pool_[0].set[5] = &enemy_formation_[5];
enemy_pool_[0].set[6] = &enemy_formation_[6];
enemy_pool_[0].set[7] = &enemy_formation_[7];
enemy_pool_[0].set[8] = &enemy_formation_[8];
enemy_pool_[0].set[9] = &enemy_formation_[9];
// EnemyPool #1
enemy_pool_[1].set[0] = &enemy_formation_[10];
enemy_pool_[1].set[1] = &enemy_formation_[11];
enemy_pool_[1].set[2] = &enemy_formation_[12];
enemy_pool_[1].set[3] = &enemy_formation_[13];
enemy_pool_[1].set[4] = &enemy_formation_[14];
enemy_pool_[1].set[5] = &enemy_formation_[15];
enemy_pool_[1].set[6] = &enemy_formation_[16];
enemy_pool_[1].set[7] = &enemy_formation_[17];
enemy_pool_[1].set[8] = &enemy_formation_[18];
enemy_pool_[1].set[9] = &enemy_formation_[19];
// EnemyPool #2
enemy_pool_[2].set[0] = &enemy_formation_[0];
enemy_pool_[2].set[1] = &enemy_formation_[1];
enemy_pool_[2].set[2] = &enemy_formation_[2];
enemy_pool_[2].set[3] = &enemy_formation_[3];
enemy_pool_[2].set[4] = &enemy_formation_[4];
enemy_pool_[2].set[5] = &enemy_formation_[55];
enemy_pool_[2].set[6] = &enemy_formation_[56];
enemy_pool_[2].set[7] = &enemy_formation_[57];
enemy_pool_[2].set[8] = &enemy_formation_[58];
enemy_pool_[2].set[9] = &enemy_formation_[59];
// EnemyPool #3
enemy_pool_[3].set[0] = &enemy_formation_[50];
enemy_pool_[3].set[1] = &enemy_formation_[51];
enemy_pool_[3].set[2] = &enemy_formation_[52];
enemy_pool_[3].set[3] = &enemy_formation_[53];
enemy_pool_[3].set[4] = &enemy_formation_[54];
enemy_pool_[3].set[5] = &enemy_formation_[5];
enemy_pool_[3].set[6] = &enemy_formation_[6];
enemy_pool_[3].set[7] = &enemy_formation_[7];
enemy_pool_[3].set[8] = &enemy_formation_[8];
enemy_pool_[3].set[9] = &enemy_formation_[9];
// EnemyPool #4
enemy_pool_[4].set[0] = &enemy_formation_[60];
enemy_pool_[4].set[1] = &enemy_formation_[61];
enemy_pool_[4].set[2] = &enemy_formation_[62];
enemy_pool_[4].set[3] = &enemy_formation_[63];
enemy_pool_[4].set[4] = &enemy_formation_[64];
enemy_pool_[4].set[5] = &enemy_formation_[65];
enemy_pool_[4].set[6] = &enemy_formation_[66];
enemy_pool_[4].set[7] = &enemy_formation_[67];
enemy_pool_[4].set[8] = &enemy_formation_[68];
enemy_pool_[4].set[9] = &enemy_formation_[69];
// EnemyPool #5
enemy_pool_[5].set[0] = &enemy_formation_[10];
enemy_pool_[5].set[1] = &enemy_formation_[61];
enemy_pool_[5].set[2] = &enemy_formation_[12];
enemy_pool_[5].set[3] = &enemy_formation_[63];
enemy_pool_[5].set[4] = &enemy_formation_[14];
enemy_pool_[5].set[5] = &enemy_formation_[65];
enemy_pool_[5].set[6] = &enemy_formation_[16];
enemy_pool_[5].set[7] = &enemy_formation_[67];
enemy_pool_[5].set[8] = &enemy_formation_[18];
enemy_pool_[5].set[9] = &enemy_formation_[69];
// EnemyPool #6
enemy_pool_[6].set[0] = &enemy_formation_[60];
enemy_pool_[6].set[1] = &enemy_formation_[11];
enemy_pool_[6].set[2] = &enemy_formation_[62];
enemy_pool_[6].set[3] = &enemy_formation_[13];
enemy_pool_[6].set[4] = &enemy_formation_[64];
enemy_pool_[6].set[5] = &enemy_formation_[15];
enemy_pool_[6].set[6] = &enemy_formation_[66];
enemy_pool_[6].set[7] = &enemy_formation_[17];
enemy_pool_[6].set[8] = &enemy_formation_[68];
enemy_pool_[6].set[9] = &enemy_formation_[19];
// EnemyPool #7
enemy_pool_[7].set[0] = &enemy_formation_[20];
enemy_pool_[7].set[1] = &enemy_formation_[21];
enemy_pool_[7].set[2] = &enemy_formation_[22];
enemy_pool_[7].set[3] = &enemy_formation_[23];
enemy_pool_[7].set[4] = &enemy_formation_[24];
enemy_pool_[7].set[5] = &enemy_formation_[65];
enemy_pool_[7].set[6] = &enemy_formation_[66];
enemy_pool_[7].set[7] = &enemy_formation_[67];
enemy_pool_[7].set[8] = &enemy_formation_[68];
enemy_pool_[7].set[9] = &enemy_formation_[69];
// EnemyPool #8
enemy_pool_[8].set[0] = &enemy_formation_[70];
enemy_pool_[8].set[1] = &enemy_formation_[71];
enemy_pool_[8].set[2] = &enemy_formation_[72];
enemy_pool_[8].set[3] = &enemy_formation_[73];
enemy_pool_[8].set[4] = &enemy_formation_[74];
enemy_pool_[8].set[5] = &enemy_formation_[15];
enemy_pool_[8].set[6] = &enemy_formation_[16];
enemy_pool_[8].set[7] = &enemy_formation_[17];
enemy_pool_[8].set[8] = &enemy_formation_[18];
enemy_pool_[8].set[9] = &enemy_formation_[19];
// EnemyPool #9
enemy_pool_[9].set[0] = &enemy_formation_[20];
enemy_pool_[9].set[1] = &enemy_formation_[21];
enemy_pool_[9].set[2] = &enemy_formation_[22];
enemy_pool_[9].set[3] = &enemy_formation_[23];
enemy_pool_[9].set[4] = &enemy_formation_[24];
enemy_pool_[9].set[5] = &enemy_formation_[70];
enemy_pool_[9].set[6] = &enemy_formation_[71];
enemy_pool_[9].set[7] = &enemy_formation_[72];
enemy_pool_[9].set[8] = &enemy_formation_[73];
enemy_pool_[9].set[9] = &enemy_formation_[74];
}
// Inicializa las fases del juego
void EnemyFormations::initGameStages()
{
// STAGE 1
stage_[0].number = 1;
stage_[0].power_to_complete = 200;
stage_[0].min_menace = 7 + (4 * 1);
stage_[0].max_menace = 7 + (4 * 3);
stage_[0].enemy_pool = &enemy_pool_[0];
// STAGE 2
stage_[1].number = 2;
stage_[1].power_to_complete = 300;
stage_[1].min_menace = 7 + (4 * 2);
stage_[1].max_menace = 7 + (4 * 4);
stage_[1].enemy_pool = &enemy_pool_[1];
// STAGE 3
stage_[2].number = 3;
stage_[2].power_to_complete = 600;
stage_[2].min_menace = 7 + (4 * 3);
stage_[2].max_menace = 7 + (4 * 5);
stage_[2].enemy_pool = &enemy_pool_[2];
// STAGE 4
stage_[3].number = 4;
stage_[3].power_to_complete = 600;
stage_[3].min_menace = 7 + (4 * 3);
stage_[3].max_menace = 7 + (4 * 5);
stage_[3].enemy_pool = &enemy_pool_[3];
// STAGE 5
stage_[4].number = 5;
stage_[4].power_to_complete = 600;
stage_[4].min_menace = 7 + (4 * 4);
stage_[4].max_menace = 7 + (4 * 6);
stage_[4].enemy_pool = &enemy_pool_[4];
// STAGE 6
stage_[5].number = 6;
stage_[5].power_to_complete = 600;
stage_[5].min_menace = 7 + (4 * 4);
stage_[5].max_menace = 7 + (4 * 6);
stage_[5].enemy_pool = &enemy_pool_[5];
// STAGE 7
stage_[6].number = 7;
stage_[6].power_to_complete = 650;
stage_[6].min_menace = 7 + (4 * 5);
stage_[6].max_menace = 7 + (4 * 7);
stage_[6].enemy_pool = &enemy_pool_[6];
// STAGE 8
stage_[7].number = 8;
stage_[7].power_to_complete = 750;
stage_[7].min_menace = 7 + (4 * 5);
stage_[7].max_menace = 7 + (4 * 7);
stage_[7].enemy_pool = &enemy_pool_[7];
// STAGE 9
stage_[8].number = 9;
stage_[8].power_to_complete = 850;
stage_[8].min_menace = 7 + (4 * 6);
stage_[8].max_menace = 7 + (4 * 8);
stage_[8].enemy_pool = &enemy_pool_[8];
// STAGE 10
stage_[9].number = 10;
stage_[9].power_to_complete = 950;
stage_[9].min_menace = 7 + (4 * 7);
stage_[9].max_menace = 7 + (4 * 10);
stage_[9].enemy_pool = &enemy_pool_[9];
}
// Devuelve una fase
Stage EnemyFormations::getStage(int index) const
{
return stage_[index];
}

View File

@@ -1,63 +0,0 @@
#pragma once
constexpr int NUMBER_OF_ENEMY_FORMATIONS = 100;
constexpr int MAX_NUMBER_OF_ENEMIES_IN_A_FORMATION = 50;
// Estructuras
struct EnemyFormationInit
{
int x; // Posición en el eje X donde crear al enemigo
int y; // Posición en el eje Y donde crear al enemigo
float vel_x; // Velocidad inicial en el eje X
int kind; // Tipo de enemigo
int creation_counter; // Temporizador para la creación del enemigo
};
struct EnemyFormationUnit // Contiene la información de una formación enemiga
{
int number_of_enemies; // Cantidad de enemigos que forman la formación
EnemyFormationInit init[MAX_NUMBER_OF_ENEMIES_IN_A_FORMATION]; // Vector con todas las inicializaciones de los enemigos de la formación
};
struct EnemyFormationPool
{
EnemyFormationUnit *set[10]; // Conjunto de formaciones enemigas
};
struct Stage // Contiene todas las variables relacionadas con una fase
{
EnemyFormationPool *enemy_pool; // El conjunto de formaciones enemigas de la fase
int power_to_complete; // Cantidad de poder que se necesita para completar la fase
int max_menace; // Umbral máximo de amenaza de la fase
int min_menace; // Umbral mínimo de amenaza de la fase
int number; // Número de fase
};
// Clase EnemyFormations, para gestionar las formaciones enemigas
class EnemyFormations
{
private:
// Variables
Stage stage_[10]; // Variable con los datos de cada pantalla
EnemyFormationUnit enemy_formation_[NUMBER_OF_ENEMY_FORMATIONS]; // Vector con todas las formaciones enemigas
EnemyFormationPool enemy_pool_[10]; // Variable con los diferentes conjuntos de formaciones enemigas
// Inicializa las formaciones enemigas
void initEnemyFormations();
// Inicializa los conjuntos de formaciones
void initEnemyPools();
// Inicializa las fases del juego
void initGameStages();
public:
// Constructor
EnemyFormations();
// Destructor
~EnemyFormations() = default;
// Devuelve una fase
Stage getStage(int index) const;
};

View File

@@ -15,7 +15,7 @@ void EnterName::init()
// Inicia la lista de caracteres permitidos
character_list_ = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-+-*/=?¿<>!\"#$%&/()";
pos_ = 0;
position_ = 0;
num_characters_ = (int)character_list_.size();
// Pone la lista de indices para que refleje el nombre
@@ -26,26 +26,27 @@ void EnterName::init()
}
// Incrementa la posición
void EnterName::incPos()
void EnterName::incPosition()
{
pos_++;
pos_ = std::min(pos_, NAME_LENGHT - 1);
position_++;
position_ = std::min(position_, NAME_LENGHT - 1);
checkIfPositionHasBeenUsed();
}
// Decrementa la posición
void EnterName::decPos()
void EnterName::decPosition()
{
pos_--;
pos_ = std::max(pos_, 0);
position_--;
position_ = std::max(position_, 0);
}
// Incrementa el índice
void EnterName::incIndex()
{
++character_index_[pos_];
if (character_index_[pos_] >= num_characters_)
++character_index_[position_];
if (character_index_[position_] >= num_characters_)
{
character_index_[pos_] = 0;
character_index_[position_] = 0;
}
updateName();
}
@@ -53,15 +54,15 @@ void EnterName::incIndex()
// Decrementa el índice
void EnterName::decIndex()
{
--character_index_[pos_];
if (character_index_[pos_] < 0)
--character_index_[position_];
if (character_index_[position_] < 0)
{
character_index_[pos_] = num_characters_ - 1;
character_index_[position_] = num_characters_ - 1;
}
updateName();
}
// Actualiza la variable
// Actualiza el nombre a partir de la lista de índices
void EnterName::updateName()
{
name_.clear();
@@ -74,16 +75,18 @@ void EnterName::updateName()
// Actualiza la variable
void EnterName::updateCharacterIndex()
{
// Rellena de espacios
// Rellena de espacios y marca como no usados
for (int i = 0; i < NAME_LENGHT; ++i)
{
character_index_[i] = 0;
position_has_been_used_[i] = false;
}
// Coloca los índices en funcion de los caracteres que forman el nombre
for (int i = 0; i < (int)name_.size(); ++i)
{
character_index_[i] = findIndex(name_.at(i));
position_has_been_used_[i] = true;
}
}
@@ -107,7 +110,21 @@ std::string EnterName::getName() const
}
// Obtiene la posición que se está editando
int EnterName::getPos() const
int EnterName::getPosition() const
{
return pos_;
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

@@ -16,13 +16,14 @@ constexpr int NAME_LENGHT = 8;
class EnterName
{
private:
std::string character_list_; // Lista de todos los caracteres permitidos
std::string name_; // Nombre introducido
int pos_; // 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
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
// Actualiza la variable
// Actualiza el nombre a partir de la lista de índices
void updateName();
// Actualiza la variable
@@ -31,6 +32,9 @@ private:
// Encuentra el indice de un caracter en "characterList"
int findIndex(char character);
// Comprueba la posición y copia el caracter si es necesario
void checkIfPositionHasBeenUsed();
public:
// Constructor
EnterName();
@@ -42,10 +46,10 @@ public:
void init();
// Incrementa la posición
void incPos();
void incPosition();
// Decrementa la posición
void decPos();
void decPosition();
// Incrementa el índice
void incIndex();
@@ -57,5 +61,5 @@ public:
std::string getName() const;
// Obtiene la posición que se está editando
int getPos() const;
int getPosition() const;
};

View File

@@ -1,6 +1,7 @@
#include "explosions.h"
#include "animated_sprite.h" // for AnimatedSprite
class Texture;
#include <utility> // for move
#include "animated_sprite.h" // for SpriteAnimated
class Texture; // lines 3-3
// Constructor
Explosions::Explosions()
@@ -37,22 +38,17 @@ void Explosions::render()
}
// Añade texturas al objeto
void Explosions::addTexture(int size, std::shared_ptr<Texture> texture, std::vector<std::string> *animation)
void Explosions::addTexture(int size, std::shared_ptr<Texture> texture, std::vector<std::string> &animation)
{
ExplosionTexture temp;
temp.size = size;
temp.texture = texture;
temp.animation = animation;
textures_.push_back(temp);
textures_.emplace_back(ExplosionTexture(size, texture, animation));
}
// Añade una explosión
void Explosions::add(int x, int y, int size)
{
const int index = getIndexBySize(size);
auto sprite = std::make_unique<AnimatedSprite>(textures_[index].texture, "", textures_[index].animation);
sprite->setPos(x, y);
explosions_.push_back(std::move(sprite));
const auto index = getIndexBySize(size);
explosions_.emplace_back(std::make_unique<AnimatedSprite>(textures_[index].texture, textures_[index].animation));
explosions_.back()->setPos(x, y);
}
// Vacia el vector de elementos finalizados

View File

@@ -1,16 +1,20 @@
#pragma once
#include <memory> // for shared_ptr, unique_ptr
#include <string> // for string
#include <vector> // for vector
#include "animated_sprite.h"
#include <memory>
#include "texture.h"
class AnimatedSprite;
class Texture;
struct ExplosionTexture
{
std::shared_ptr<Texture> texture; // Textura para la explosión
std::vector<std::string> *animation; // Animación para la textura
int size; // Tamaño de la explosión
int size; // Tamaño de la explosión
std::shared_ptr<Texture> texture; // Textura para la explosión
std::vector<std::string> animation; // Animación para la textura
// Constructor
ExplosionTexture(int sz, std::shared_ptr<Texture> tex, std::vector<std::string> anim)
: size(sz), texture(tex), animation(anim) {}
};
// Clase explosions
@@ -41,7 +45,7 @@ public:
void render();
// Añade texturas al objeto
void addTexture(int size, std::shared_ptr<Texture> texture, std::vector<std::string> *animation);
void addTexture(int size, std::shared_ptr<Texture> texture, std::vector<std::string> &animation);
// Añade una explosión
void add(int x, int y, int size);

View File

@@ -4,11 +4,12 @@
#include <stdlib.h> // for rand
#include <algorithm> // for min, max
#include "param.h" // for param
#include "screen.h"
#include "utils.h" // for Param, ParamGame, ParamFade
// Constructor
Fade::Fade(SDL_Renderer *renderer_)
: renderer_(renderer_)
Fade::Fade()
: renderer_(Screen::get()->getRenderer())
{
// Crea la textura donde dibujar el fade
backbuffer_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);

View File

@@ -54,7 +54,7 @@ private:
public:
// Constructor
Fade(SDL_Renderer *renderer);
Fade();
// Destructor
~Fade();

File diff suppressed because it is too large Load Diff

View File

@@ -1,56 +1,37 @@
#pragma once
#include <SDL2/SDL_events.h> // for SDL_Event
#include <SDL2/SDL_render.h> // for SDL_Renderer, SDL_Texture
#include <SDL2/SDL_stdinc.h> // for Uint32
#include <memory> // for shared_ptr, unique_ptr
#include <string> // for string
#include <vector> // for vector
#include "section.h" // for SectionOptions
#include "balloon.h" // for Balloon
#include "player.h" // for Player
#include "utils.h" // for DemoKeys, Color, HiScoreEntry
#include <memory>
#include "asset.h" // lines 11-11
#include "background.h" // lines 12-12
#include "balloon.h" // lines 13-13
#include "bullet.h" // lines 14-14
#include "enemy_formations.h" // lines 15-15
#include "explosions.h" // lines 16-16
#include "fade.h" // lines 17-17
#include "input.h" // lines 18-18
#include "item.h" // lines 19-19
#include "player.h" // lines 20-20
#include "scoreboard.h" // lines 21-21
#include "screen.h" // lines 22-22
#include "smart_sprite.h" // lines 23-23
#include "text.h" // lines 24-24
#include "texture.h" // lines 24-24
enum class BulletType;
struct JA_Music_t; // lines 26-26
struct JA_Sound_t; // lines 27-27
class Asset;
class Background;
class BalloonFormations;
class Bullet;
class Explosions;
class Fade;
class Input;
class Item;
class Scoreboard;
class Screen;
class SmartSprite;
class Text;
class Texture;
enum class BulletType; // lines 26-26
struct JA_Music_t; // lines 27-27
struct JA_Sound_t; // lines 28-28
enum class ItemType;
#define GAME_MODE_DEMO_OFF false
#define GAME_MODE_DEMO_ON true
// Modo demo
constexpr bool GAME_MODE_DEMO_OFF = false;
constexpr bool GAME_MODE_DEMO_ON = true;
// Cantidad de elementos a escribir en los ficheros de datos
#define TOTAL_SCORE_DATA 3
#define TOTAL_DEMO_DATA 2000
// Contadores
#define STAGE_COUNTER 200
#define HELP_COUNTER 1000
#define GAME_COMPLETED_START_FADE 500
#define GAME_COMPLETED_END 700
// Porcentaje de aparición de los objetos
#define ITEM_POINTS_1_DISK_ODDS 10
#define ITEM_POINTS_2_GAVINA_ODDS 6
#define ITEM_POINTS_3_PACMAR_ODDS 3
#define ITEM_CLOCK_ODDS 5
#define ITEM_COFFEE_ODDS 5
#define ITEM_POWER_BALL_ODDS 0
#define ITEM_COFFEE_MACHINE_ODDS 4
// Valores para las variables asociadas a los objetos
#define TIME_STOPPED_COUNTER 300
constexpr int TOTAL_SCORE_DATA = 3;
/*
Esta clase gestiona un estado del programa. Se encarga de toda la parte en la
@@ -82,129 +63,115 @@ struct JA_Sound_t; // lines 27-27
class Game
{
private:
struct helper_t
// Estructuras
struct Helper
{
bool needCoffee; // Indica si se necesitan cafes
bool needCoffeeMachine; // Indica si se necesita PowerUp
bool needPowerBall; // Indica si se necesita una PowerBall
int counter; // Contador para no dar ayudas consecutivas
int itemPoints1Odds; // Probabilidad de aparición del objeto
int itemPoints2Odds; // Probabilidad de aparición del objeto
int itemPoints3Odds; // Probabilidad de aparición del objeto
int itemClockOdds; // Probabilidad de aparición del objeto
int itemCoffeeOdds; // Probabilidad de aparición del objeto
int itemCoffeeMachineOdds; // Probabilidad de aparición del objeto
bool need_coffee; // Indica si se necesitan cafes
bool need_coffee_machine; // Indica si se necesita PowerUp
bool need_power_ball; // Indica si se necesita una PowerBall
int counter; // Contador para no dar ayudas consecutivas
int item_disk_odds; // Probabilidad de aparición del objeto
int item_gavina_odds; // Probabilidad de aparición del objeto
int item_pacmar_odds; // Probabilidad de aparición del objeto
int item_clock_odds; // Probabilidad de aparición del objeto
int item_coffee_odds; // Probabilidad de aparición del objeto
int item_coffee_machine_odds; // Probabilidad de aparición del objeto
};
struct demo_t
{
bool enabled; // Indica si está activo el modo demo
bool recording; // Indica si está activado el modo para grabar la demo
int counter; // Contador para el modo demo
DemoKeys keys; // Variable con las pulsaciones de teclas del modo demo
DemoKeys dataFile[2][TOTAL_DEMO_DATA]; // Vector con diferentes sets de datos con los movimientos para la demo
};
// Constantes
// Contadores
static constexpr int STAGE_COUNTER_ = 200;
static constexpr int HELP_COUNTER_ = 1000;
static constexpr int GAME_COMPLETED_START_FADE_ = 500;
static constexpr int GAME_COMPLETED_END_ = 700;
static constexpr int GAME_OVER_COUNTER_ = 350;
static constexpr int TIME_STOPPED_COUNTER_ = 300;
static constexpr int TICKS_SPEED_ = 15;
// Porcentaje de aparición de los objetos
static constexpr int ITEM_POINTS_1_DISK_ODDS_ = 10;
static constexpr int ITEM_POINTS_2_GAVINA_ODDS_ = 6;
static constexpr int ITEM_POINTS_3_PACMAR_ODDS_ = 3;
static constexpr int ITEM_CLOCK_ODDS_ = 5;
static constexpr int ITEM_COFFEE_ODDS_ = 5;
static constexpr int ITEM_POWER_BALL_ODDS_ = 0;
static constexpr int ITEM_COFFEE_MACHINE_ODDS_ = 4;
// Objetos y punteros
SDL_Renderer *renderer; // El renderizador de la ventana
Screen *screen; // Objeto encargado de dibujar en pantalla
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
Input *input; // Manejador de entrada
Scoreboard *scoreboard; // Objeto para dibujar el marcador
SDL_Renderer *renderer_; // El renderizador de la ventana
Screen *screen_; // Objeto encargado de dibujar en pantalla
Asset *asset_; // Objeto que gestiona todos los ficheros de recursos
Input *input_; // Manejador de entrada
Scoreboard *scoreboard_; // Objeto para dibujar el marcador
std::unique_ptr<Background> background; // Objeto para dibujar el fondo del juego
std::unique_ptr<Explosions> explosions; // Objeto para dibujar explosiones
std::unique_ptr<EnemyFormations> enemyFormations; // Objeto para gestionar las oleadas enemigas
std::unique_ptr<Background> background_; // Objeto para dibujar el fondo del juego
std::unique_ptr<Explosions> explosions_; // Objeto para dibujar explosiones
std::unique_ptr<BalloonFormations> balloon_formations_; // Objeto para gestionar las oleadas enemigas
SDL_Texture *canvas; // Textura para dibujar la zona de juego
SDL_Texture *canvas_; // Textura para dibujar la zona de juego
std::vector<std::shared_ptr<Player>> players; // Vector con los jugadores
std::vector<std::shared_ptr<Balloon>> balloons; // Vector con los globos
std::vector<std::unique_ptr<Bullet>> bullets; // Vector con las balas
std::vector<std::unique_ptr<Item>> items; // Vector con los items
std::vector<SmartSprite *> smartSprites; // Vector con los smartsprites
std::vector<std::shared_ptr<Player>> players_; // Vector con los jugadores
std::vector<std::shared_ptr<Balloon>> balloons_; // Vector con los globos
std::vector<std::unique_ptr<Bullet>> bullets_; // Vector con las balas
std::vector<std::unique_ptr<Item>> items_; // Vector con los items
std::vector<std::unique_ptr<SmartSprite>> smart_sprites_; // Vector con los smartsprites
std::shared_ptr<Texture> bulletTexture; // Textura para las balas
std::vector<std::shared_ptr<Texture>> itemTextures; // Vector con las texturas de los items
std::vector<std::shared_ptr<Texture>> balloonTextures; // Vector con las texturas de los globos
std::vector<std::shared_ptr<Texture>> explosionsTextures; // Vector con las texturas de las explosiones
std::vector<std::shared_ptr<Texture>> player1Textures; // Vector con las texturas del jugador
std::vector<std::shared_ptr<Texture>> player2Textures; // Vector con las texturas del jugador
std::vector<std::vector<std::shared_ptr<Texture>>> playerTextures; // Vector con todas las texturas de los jugadores;
std::shared_ptr<Texture> bullet_texture_; // Textura para las balas
std::vector<std::shared_ptr<Texture>> item_textures_; // Vector con las texturas de los items
std::vector<std::shared_ptr<Texture>> balloon_textures_; // Vector con las texturas de los globos
std::vector<std::shared_ptr<Texture>> explosions_textures_; // Vector con las texturas de las explosiones
std::vector<std::vector<std::shared_ptr<Texture>>> player_textures_; // Vector con todas las texturas de los jugadores;
std::shared_ptr<Texture> gameTextTexture; // Textura para los sprites con textos
std::vector<std::shared_ptr<Texture>> game_text_textures_; // Vector con las texturas para los sprites con textos
std::vector<std::vector<std::string> *> itemAnimations; // Vector con las animaciones de los items
std::vector<std::vector<std::string> *> playerAnimations; // Vector con las animaciones del jugador
std::vector<std::vector<std::string> *> balloonAnimations; // Vector con las animaciones de los globos
std::vector<std::vector<std::string> *> explosionsAnimations; // Vector con las animaciones de las explosiones
std::vector<std::vector<std::string>> item_animations_; // Vector con las animaciones de los items
std::vector<std::vector<std::string>> player_animations_; // Vector con las animaciones del jugador
std::vector<std::vector<std::string>> balloon_animations_; // Vector con las animaciones de los globos
std::vector<std::vector<std::string>> explosions_animations_; // Vector con las animaciones de las explosiones
std::unique_ptr<Text> text; // Fuente para los textos del juego
std::unique_ptr<Text> textBig; // Fuente de texto grande
std::unique_ptr<Text> textNokia2; // Otra fuente de texto para mensajes
std::unique_ptr<Text> textNokiaBig2; // Y la versión en grande
std::unique_ptr<Text> text_; // Fuente para los textos del juego
std::unique_ptr<Text> text_big_; // Fuente de texto grande
std::unique_ptr<Text> text_nokia2_; // Otra fuente de texto para mensajes
std::unique_ptr<Text> text_nokia2_big_; // Y la versión en grande
std::unique_ptr<Fade> fade; // Objeto para renderizar fades
std::unique_ptr<SDL_Event> eventHandler; // Manejador de eventos
std::shared_ptr<SmartSprite> n1000Sprite; // Sprite con el texto 1.000
std::shared_ptr<SmartSprite> n2500Sprite; // Sprite con el texto 2.500
std::shared_ptr<SmartSprite> n5000Sprite; // Sprite con el texto 5.000
JA_Sound_t *balloonSound; // Sonido para la explosión del globo
JA_Sound_t *bulletSound; // Sonido para los disparos
JA_Sound_t *playerCollisionSound; // Sonido para la colisión del jugador con un enemigo
JA_Sound_t *hiScoreSound; // Sonido para cuando se alcanza la máxima puntuación
JA_Sound_t *itemDropSound; // Sonido para cuando se genera un item
JA_Sound_t *itemPickUpSound; // Sonido para cuando se recoge un item
JA_Sound_t *coffeeOutSound; // Sonido para cuando el jugador pierde el café al recibir un impacto
JA_Sound_t *stageChangeSound; // Sonido para cuando se cambia de fase
JA_Sound_t *bubble1Sound; // Sonido para cuando el jugador muere
JA_Sound_t *bubble2Sound; // Sonido para cuando el jugador muere
JA_Sound_t *bubble3Sound; // Sonido para cuando el jugador muere
JA_Sound_t *bubble4Sound; // Sonido para cuando el jugador muere
JA_Sound_t *clockSound; // Sonido para cuando se detiene el tiempo con el item reloj
JA_Sound_t *powerBallSound; // Sonido para cuando se explota una Power Ball
JA_Sound_t *coffeeMachineSound; // Sonido para cuando la máquina de café toca el suelo
JA_Music_t *music; // Musica de fondo
std::unique_ptr<Fade> fade_; // Objeto para renderizar fades
// Variables
Uint32 ticks; // Contador de ticks para ajustar la velocidad del programa
Uint32 ticksSpeed; // Velocidad a la que se repiten los bucles del programa
bool hiScoreAchieved; // Indica si se ha superado la puntuación máxima
HiScoreEntry hiScore; // Máxima puntuación y nombre de quien la ostenta
int currentStage; // Indica la fase actual
int stageBitmapCounter; // Contador para el tiempo visible del texto de Stage
float stageBitmapPath[STAGE_COUNTER]; // Vector con los puntos Y por donde se desplaza el texto
float getReadyBitmapPath[STAGE_COUNTER]; // Vector con los puntos X por donde se desplaza el texto
int gameOverCounter; // Contador para el estado de fin de partida
int menaceCurrent; // Nivel de amenaza actual
int menaceThreshold; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el número de globos
bool timeStopped; // Indica si el tiempo está detenido
int timeStoppedCounter; // Temporizador para llevar la cuenta del tiempo detenido
int counter; // Contador para el juego
int balloonsPopped; // Lleva la cuenta de los globos explotados
int lastEnemyDeploy; // Guarda cual ha sido la última formación desplegada para no repetir;
int enemyDeployCounter; // Cuando se lanza una formación, se le da un valor y no sale otra hasta que llegue a cero
float enemySpeed; // Velocidad a la que se mueven los enemigos
float defaultEnemySpeed; // Velocidad base de los enemigos, sin incrementar
helper_t helper; // Variable para gestionar las ayudas
bool powerBallEnabled; // Indica si hay una powerball ya activa
int powerBallCounter; // Contador de formaciones enemigas entre la aparicion de una PowerBall y otra
bool coffeeMachineEnabled; // Indica si hay una máquina de café en el terreno de juego
bool gameCompleted; // Indica si se ha completado la partida, llegando al final de la ultima pantalla
int gameCompletedCounter; // Contador para el tramo final, cuando se ha completado la partida y ya no aparecen más enemigos
GameDifficulty difficulty; // Dificultad del juego
float difficultyScoreMultiplier; // Multiplicador de puntos en función de la dificultad
Color difficultyColor; // Color asociado a la dificultad
int lastStageReached; // Contiene el número de la última pantalla que se ha alcanzado
demo_t demo; // Variable con todas las variables relacionadas con el modo demo
int totalPowerToCompleteGame; // La suma del poder necesario para completar todas las fases
bool paused; // Indica si el juego está pausado (no se deberia de poder utilizar en el modo arcade)
int currentPower; // Poder actual almacenado para completar la fase
Uint32 ticks_; // Contador de ticks para ajustar la velocidad del programa
bool hi_score_achieved_; // Indica si se ha superado la puntuación máxima
HiScoreEntry hi_score_; // Máxima puntuación y nombre de quien la ostenta
int current_stage_; // Indica la fase actual
int stage_bitmap_counter_; // Contador para el tiempo visible del texto de Stage
float stage_bitmap_path_[STAGE_COUNTER_]; // Vector con los puntos Y por donde se desplaza el texto
float get_ready_bitmap_path_[STAGE_COUNTER_]; // Vector con los puntos X por donde se desplaza el texto
int game_over_counter_; // Contador para el estado de fin de partida
int menace_current_; // Nivel de amenaza actual
int menace_threshold_; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el número de globos
bool time_stopped_; // Indica si el tiempo está detenido
int time_stopped_counter_; // Temporizador para llevar la cuenta del tiempo detenido
int counter_; // Contador para el juego
int balloons_popped_; // Lleva la cuenta de los globos explotados
int last_ballon_deploy_; // Guarda cual ha sido la última formación desplegada para no repetir;
int balloon_deploy_counter_; // Cuando se lanza una formación, se le da un valor y no sale otra hasta que llegue a cero
float balloon_speed_; // Velocidad a la que se mueven los enemigos
float default_balloon_speed_; // Velocidad base de los enemigos, sin incrementar
Helper helper_; // Variable para gestionar las ayudas
bool power_ball_enabled_; // Indica si hay una powerball ya activa
int power_ball_counter_; // Contador de formaciones enemigas entre la aparicion de una PowerBall y otra
bool coffee_machine_enabled_; // Indica si hay una máquina de café en el terreno de juego
bool game_completed_; // Indica si se ha completado la partida, llegando al final de la ultima pantalla
int game_completed_counter_; // Contador para el tramo final, cuando se ha completado la partida y ya no aparecen más enemigos
GameDifficulty difficulty_; // Dificultad del juego
float difficulty_score_multiplier_; // Multiplicador de puntos en función de la dificultad
Color difficulty_color_; // Color asociado a la dificultad
int last_stage_reached_; // Contiene el número de la última pantalla que se ha alcanzado
Demo demo_; // Variable con todas las variables relacionadas con el modo demo
int total_power_to_complete_game_; // La suma del poder necesario para completar todas las fases
bool paused_; // Indica si el juego está pausado (no se deberia de poder utilizar en el modo arcade)
int current_power_; // Poder actual almacenado para completar la fase
#ifdef DEBUG
bool autoPopBalloons; // Si es true, incrementa automaticamente los globos explotados
bool auto_pop_balloons_; // Si es true, incrementa automaticamente los globos explotados
#endif
// Actualiza el juego
@@ -217,7 +184,7 @@ private:
void checkEvents();
// Inicializa las variables necesarias para la sección 'Game'
void init(int playerID);
void init(int player_id);
// Carga los recursos necesarios para la sección 'Game'
void loadMedia();
@@ -225,14 +192,8 @@ private:
// Libera los recursos previamente cargados
void unloadMedia();
// Carga el fichero de datos para la demo
bool loadDemoFile(std::string filePath, DemoKeys (*dataFile)[TOTAL_DEMO_DATA]);
#ifdef RECORDING
// Guarda el fichero de datos para la demo
bool saveDemoFile(std::string filePath);
#endif
// Crea una formación de enemigos
void deployEnemyFormation();
void deployBalloonFormation();
// Aumenta el poder de la fase
void increaseStageCurrentPower(int power);
@@ -259,7 +220,7 @@ private:
void renderBalloons();
// Crea un globo nuevo en el vector de globos
std::shared_ptr<Balloon> createBalloon(float x, int y, int kind, float velx, float speed, int stoppedcounter);
std::shared_ptr<Balloon> createBalloon(float x, int y, int kind, float velx, float speed, int stopped_counter);
// Crea una PowerBall
void createPowerBall();
@@ -267,12 +228,6 @@ private:
// Establece la velocidad de los globos
void setBalloonSpeed(float speed);
// Incrementa la velocidad de los globos
void incBalloonSpeed();
// Decrementa la velocidad de los globos
void decBalloonSpeed();
// Actualiza la velocidad de los globos en funcion del poder acumulado de la fase
void updateBalloonSpeed();
@@ -282,9 +237,6 @@ private:
// Explosiona un globo. Lo destruye
void destroyBalloon(std::shared_ptr<Balloon> &balloon);
// Explosiona todos los globos
void popAllBalloons();
// Destruye todos los globos
void destroyAllBalloons();
@@ -294,9 +246,6 @@ private:
// Pone en marcha todos los globos
void startAllBalloons();
// Obtiene el número de globos activos
int countBalloons();
// Vacia el vector de globos
void freeBalloons();
@@ -316,7 +265,7 @@ private:
void renderBullets();
// Crea un objeto bala
void createBullet(int x, int y, BulletType kind, bool poweredUp, int owner);
void createBullet(int x, int y, BulletType kind, bool powered_up, int owner);
// Vacia el vector de balas
void freeBullets();
@@ -328,28 +277,28 @@ private:
void renderItems();
// Devuelve un item en función del azar
int dropItem();
ItemType dropItem();
// Crea un objeto item
void createItem(int kind, float x, float y);
void createItem(ItemType type, float x, float y);
// Vacia el vector de items
void freeItems();
// Crea un objeto SmartSprite
void createItemScoreSprite(int x, int y, std::shared_ptr<SmartSprite> sprite);
// Crea un objeto SpriteSmart
void createItemScoreSprite(int x, int y, std::shared_ptr<Texture> texture);
// Vacia el vector de smartsprites
void freeSmartSprites();
void freeSpriteSmarts();
// Crea un SmartSprite para arrojar el item café al recibir un impacto
// Crea un SpriteSmart para arrojar el item café al recibir un impacto
void throwCoffee(int x, int y);
// Actualiza los SmartSprites
void updateSmartSprites();
// Actualiza los SpriteSmarts
void updateSpriteSmarts();
// Pinta los SmartSprites activos
void renderSmartSprites();
// Pinta los SpriteSmarts activos
void renderSpriteSmarts();
// Acciones a realizar cuando el jugador muere
void killPlayer(std::shared_ptr<Player> &player);
@@ -373,7 +322,7 @@ private:
void incTimeStoppedCounter(int value);
// Actualiza la variable EnemyDeployCounter
void updateEnemyDeployCounter();
void updateBalloonDeployCounter();
// Actualiza y comprueba el valor de la variable
void updateTimeStoppedCounter();
@@ -384,9 +333,6 @@ private:
// Actualiza el fondo
void updateBackground();
// Gestiona la entrada durante el juego
void checkInput();
// Pinta diferentes mensajes en la pantalla
void renderMessages();
@@ -420,9 +366,6 @@ private:
// Comprueba si todos los jugadores han terminado de jugar
bool allPlayersAreNotPlaying();
// Carga las animaciones
void loadAnimations(std::string filePath, std::vector<std::string> *buffer);
// Elimina todos los objetos contenidos en vectores
void deleteAllVectorObjects();
@@ -442,10 +385,10 @@ private:
void checkMusicStatus();
// Añade una puntuación a la tabla de records
void addScoreToScoreBoard(std::string name, int score);
void addScoreToScoreBoard(const std::string &name, int score);
// Saca del estado de GAME OVER al jugador si el otro está activo
void checkAndUpdatePlayerStatus(int activePlayerIndex, int inactivePlayerIndex);
void checkAndUpdatePlayerStatus(int active_player_index, int inactive_player_index);
// Comprueba el estado de juego de los jugadores
void checkPlayersStatusPlaying();
@@ -456,9 +399,40 @@ private:
// Obtiene un controlador a partir del "id" del jugador
int getController(int playerId);
// Gestiona la entrada durante el juego
void checkInput();
// Verifica si alguno de los controladores ha solicitado una pausa y actualiza el estado de pausa del juego.
void checkPauseInput();
// Gestiona las entradas de los jugadores en el modo demo, incluyendo movimientos y disparos automáticos.
void handleDemoMode();
// Procesa las entradas para un jugador específico durante el modo demo.
// Incluye movimientos (izquierda, derecha, sin movimiento) y disparos automáticos.
void handleDemoPlayerInput(const std::shared_ptr<Player> &player, int index);
// Maneja el disparo de un jugador, incluyendo la creación de balas y la gestión del tiempo de espera entre disparos.
void handleFireInput(const std::shared_ptr<Player> &player, BulletType bulletType);
// Gestiona las entradas de todos los jugadores en el modo normal (fuera del modo demo).
void handlePlayersInput();
// Maneja las entradas de movimiento y disparo para un jugador en modo normal.
void handleNormalPlayerInput(const std::shared_ptr<Player> &player);
// Procesa las entradas de disparo del jugador, permitiendo disparos automáticos si está habilitado.
void handleFireInputs(const std::shared_ptr<Player> &player, bool autofire, int controllerIndex);
// Maneja la continuación del jugador cuando no está jugando, permitiendo que continúe si se pulsa el botón de inicio.
void handlePlayerContinue(const std::shared_ptr<Player> &player);
// Procesa las entradas para la introducción del nombre del jugador.
void handleNameInput(const std::shared_ptr<Player> &player);
public:
// Constructor
Game(int playerID, int currentStage, bool demo, JA_Music_t *music);
Game(int playerID, int current_stage, bool demo);
// Destructor
~Game();

View File

@@ -1,47 +1,40 @@
#include "game_logo.h"
#include <SDL2/SDL_render.h> // for SDL_FLIP_HORIZONTAL
#include <algorithm> // for max
#include <string> // for basic_string
#include "animated_sprite.h" // for AnimatedSprite
#include "animated_sprite.h" // for SpriteAnimated
#include "asset.h" // for Asset
#include "jail_audio.h" // for JA_DeleteSound, JA_LoadSound, JA_PlaySound
#include "jail_audio.h" // JA_PlaySound
#include "param.h" // for param
#include "resource.h" // for Resource
#include "screen.h" // for Screen
#include "smart_sprite.h" // for SmartSprite
#include "smart_sprite.h" // for SpriteSmart
#include "sprite.h" // for Sprite
#include "texture.h" // for Texture
#include "utils.h" // for Param, ParamGame, ParamTitle
// Constructor
GameLogo::GameLogo(int x, int y)
: x_(x), y_(y)
: dust_texture_(Resource::get()->getTexture("title_dust.png")),
coffee_texture_(Resource::get()->getTexture("title_coffee.png")),
crisis_texture_(Resource::get()->getTexture("title_crisis.png")),
arcade_edition_texture_(Resource::get()->getTexture("title_arcade_edition.png")),
dust_left_sprite_(std::make_unique<AnimatedSprite>(dust_texture_, Resource::get()->getAnimation("title_dust.ani"))),
dust_right_sprite_(std::make_unique<AnimatedSprite>(dust_texture_, Resource::get()->getAnimation("title_dust.ani"))),
coffee_sprite_(std::make_unique<SmartSprite>(coffee_texture_)),
crisis_sprite_(std::make_unique<SmartSprite>(crisis_texture_)),
arcade_edition_sprite_(std::make_unique<Sprite>(arcade_edition_texture_, (param.game.width - arcade_edition_texture_->getWidth()) / 2, param.title.arcade_edition_position, arcade_edition_texture_->getWidth(), arcade_edition_texture_->getHeight())),
x_(x),
y_(y)
{
// Crea los objetos
dust_texture_ = std::make_shared<Texture>(Screen::get()->getRenderer(), Asset::get()->get("title_dust.png"));
coffee_texture_ = std::make_shared<Texture>(Screen::get()->getRenderer(), Asset::get()->get("title_coffee.png"));
crisis_texture_ = std::make_shared<Texture>(Screen::get()->getRenderer(), Asset::get()->get("title_crisis.png"));
arcade_edition_texture_ = std::make_shared<Texture>(Screen::get()->getRenderer(), Asset::get()->get("title_arcade_edition.png"));
coffee_sprite_ = std::make_unique<SmartSprite>(coffee_texture_);
crisis_sprite_ = std::make_unique<SmartSprite>(crisis_texture_);
arcade_edition_sprite_ = std::make_unique<Sprite>((param.game.width - arcade_edition_texture_->getWidth()) / 2, param.title.arcade_edition_position, arcade_edition_texture_->getWidth(), arcade_edition_texture_->getHeight(), arcade_edition_texture_);
dust_left_sprite_ = std::make_unique<AnimatedSprite>(dust_texture_, Asset::get()->get("title_dust.ani"));
dust_right_sprite_ = std::make_unique<AnimatedSprite>(dust_texture_, Asset::get()->get("title_dust.ani"));
// Sonidos
crash_sound_ = JA_LoadSound(Asset::get()->get("title.wav").c_str());
// Inicializa las variables
init();
}
// Destructor
GameLogo::~GameLogo()
{
JA_DeleteSound(crash_sound_);
}
// Inicializa las variables
void GameLogo::init()
{
@@ -125,7 +118,9 @@ void GameLogo::render()
// Actualiza la lógica de la clase
void GameLogo::update()
{
if (status_ == Status::MOVING)
switch (status_)
{
case Status::MOVING:
{
coffee_sprite_->update();
crisis_sprite_->update();
@@ -136,11 +131,13 @@ void GameLogo::update()
status_ = Status::SHAKING;
// Reproduce el efecto sonoro
JA_PlaySound(crash_sound_);
JA_PlaySound(Resource::get()->getSound("title.wav"));
}
break;
}
else if (status_ == Status::SHAKING)
case Status::SHAKING:
{
// Agita el logo
if (shake_.remaining > 0)
@@ -167,12 +164,20 @@ void GameLogo::update()
dust_right_sprite_->update();
dust_left_sprite_->update();
break;
}
else if (status_ == Status::FINISHED)
case Status::FINISHED:
{
dust_right_sprite_->update();
dust_left_sprite_->update();
break;
}
default:
break;
}
}

View File

@@ -1,45 +1,23 @@
#pragma once
#include <SDL2/SDL_render.h> // for SDL_Renderer
#include <memory>
#include "texture.h"
#include <memory> // for unique_ptr, shared_ptr
#include "animated_sprite.h"
#include "smart_sprite.h"
#include "sprite.h"
struct JA_Sound_t;
class Sprite;
class Texture;
struct JA_Sound_t; // lines 10-10
// Clase GameLogo
class GameLogo
{
private:
// Objetos y punteros
std::shared_ptr<Texture> dust_texture_; // Textura con los graficos del polvo
std::shared_ptr<Texture> coffee_texture_; // Textura con los graficos de la palabra "COFFEE"
std::shared_ptr<Texture> crisis_texture_; // Textura con los graficos de la plabra "CRISIS"
std::shared_ptr<Texture> arcade_edition_texture_; // Textura con los graficos de "Arcade Edition"
std::unique_ptr<AnimatedSprite> dust_left_sprite_; // Sprite con la el polvo que aparece al colisionar el texto de la pantalla de titulo
std::unique_ptr<AnimatedSprite> dust_right_sprite_; // Sprite con la el polvo que aparece al colisionar el texto de la pantalla de titulo
std::unique_ptr<SmartSprite> coffee_sprite_; // Sprite con la palabra "COFFEE" para la pantalla de titulo
std::unique_ptr<SmartSprite> crisis_sprite_; // Sprite con la palabra "CRISIS" para la pantalla de titulo
std::unique_ptr<Sprite> arcade_edition_sprite_; // Sprite con los graficos de "Arcade Edition"
JA_Sound_t *crash_sound_; // Sonido con el impacto del título
// Variables
int x_; // Posición donde dibujar el logo
int y_; // Posición donde dibujar el logo
enum class Status
{
DISABLED,
MOVING,
SHAKING,
FINISHED,
} status_; // Estado en el que se encuentra la clase
};
struct Shake
{
@@ -49,7 +27,28 @@ private:
int lenght; // Cantidad de desplazamientos a realizar
int remaining; // Cantidad de desplazamientos pendientes a realizar
int origin; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
} shake_; // Estructura para generar el efecto de agitación
};
// Objetos y punteros
std::shared_ptr<Texture> dust_texture_; // Textura con los graficos del polvo
std::shared_ptr<Texture> coffee_texture_; // Textura con los graficos de la palabra "COFFEE"
std::shared_ptr<Texture> crisis_texture_; // Textura con los graficos de la plabra "CRISIS"
std::shared_ptr<Texture> arcade_edition_texture_; // Textura con los graficos de "Arcade Edition"
std::unique_ptr<AnimatedSprite> dust_left_sprite_; // Sprite con la el polvo que aparece al colisionar el texto de la pantalla de titulo
std::unique_ptr<AnimatedSprite> dust_right_sprite_; // Sprite con la el polvo que aparece al colisionar el texto de la pantalla de titulo
std::unique_ptr<SmartSprite> coffee_sprite_; // Sprite con la palabra "COFFEE" para la pantalla de titulo
std::unique_ptr<SmartSprite> crisis_sprite_; // Sprite con la palabra "CRISIS" para la pantalla de titulo
std::unique_ptr<Sprite> arcade_edition_sprite_; // Sprite con los graficos de "Arcade Edition"
// Variables
int x_; // Posición donde dibujar el logo
int y_; // Posición donde dibujar el logo
Status status_; // Estado en el que se encuentra la clase
Shake shake_; // Estructura para generar el efecto de agitación
// Inicializa las variables
void init();
@@ -62,7 +61,7 @@ public:
GameLogo(int x, int y);
// Destructor
~GameLogo();
~GameLogo() = default;
// Pinta la clase en pantalla
void render();

View File

@@ -3,6 +3,7 @@
#include "input.h" // for Input, inputs_e, INPUT_DO_NOT_ALLOW_REPEAT
#include "jail_audio.h" // for JA_EnableMusic, JA_EnableSound
#include "lang.h" // for getText
#include "notifier.h" // for Notifier
#include "options.h" // for options
#include "on_screen_help.h"
#include "screen.h" // for Screen
@@ -12,30 +13,37 @@
namespace globalInputs
{
// Variables
std::vector<int> servicePressedCounter;
std::vector<int> service_pressed_counter;
// Inicializa variables
void init()
{
const auto numInputs = Input::get()->getNumControllers() + 1;
servicePressedCounter.reserve(numInputs);
for (int i = 0; i < numInputs; ++i)
const auto num_inputs = Input::get()->getNumControllers() + 1;
service_pressed_counter.reserve(num_inputs);
for (int i = 0; i < num_inputs; ++i)
{
servicePressedCounter.push_back(0);
service_pressed_counter.push_back(0);
}
}
// Termina
void quit(section::Options code)
{
if (Screen::get()->notificationsAreActive())
const std::string exit_code = "QUIT";
auto code_found = stringInVector(Notifier::get()->getCodes(), exit_code);
if (code_found)
{
section::name = section::Name::QUIT;
section::options = code;
}
else
{
Screen::get()->showNotification(lang::getText(94));
#ifdef ARCADE
const int index = code == section::Options::QUIT_WITH_CONTROLLER ? 116 : 94;
Notifier::get()->showText(lang::getText(index), std::string(), -1, exit_code);
#else
Notifier::get()->showText(lang::getText(94), std::string(), -1, exit_code);
#endif
}
}
@@ -43,7 +51,7 @@ namespace globalInputs
void reset()
{
section::name = section::Name::INIT;
Screen::get()->showNotification("Reset");
Notifier::get()->showText("Reset");
}
// Activa o desactiva el audio
@@ -52,85 +60,85 @@ namespace globalInputs
options.audio.sound.enabled = options.audio.music.enabled = !options.audio.music.enabled;
JA_EnableMusic(options.audio.music.enabled);
JA_EnableSound(options.audio.sound.enabled);
Screen::get()->showNotification("Audio " + boolToOnOff(options.audio.music.enabled));
Notifier::get()->showText("Audio " + boolToOnOff(options.audio.music.enabled));
}
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
void check()
{
// Comprueba si se sale con el teclado
if (Input::get()->checkInput(input_exit, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
if (Input::get()->checkInput(InputType::EXIT, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
{
quit(section::Options::QUIT_NORMAL);
quit(section::Options::QUIT_WITH_KEYBOARD);
return;
}
// Comprueba si se va a resetear el juego
else if (Input::get()->checkInput(input_reset, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
else if (Input::get()->checkInput(InputType::RESET, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
{
reset();
return;
}
else if (Input::get()->checkInput(input_mute, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
else if (Input::get()->checkInput(InputType::MUTE, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
{
switchAudio();
return;
}
else if (Input::get()->checkInput(input_service, INPUT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
else if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
{
servicePressedCounter[0]++;
service_pressed_counter[0]++;
if (servicePressedCounter[0] >= 3000)
if (service_pressed_counter[0] >= 3000)
{
OnScreenHelp::get()->toggleState();
servicePressedCounter[0] = 0;
service_pressed_counter[0] = 0;
}
return;
}
else
{
servicePressedCounter[0] = 0;
service_pressed_counter[0] = 0;
}
for (int i = 0; i < Input::get()->getNumControllers(); ++i)
{
// Comprueba si se sale con el mando
if (Input::get()->checkModInput(input_service, input_exit, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i))
if (Input::get()->checkModInput(InputType::SERVICE, InputType::EXIT, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i))
{
quit(section::Options::QUIT_SHUTDOWN);
quit(section::Options::QUIT_WITH_CONTROLLER);
return;
}
// Comprueba si se va a resetear el juego
else if (Input::get()->checkModInput(input_service, input_reset, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i))
else if (Input::get()->checkModInput(InputType::SERVICE, InputType::RESET, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i))
{
reset();
return;
}
// Comprueba si se va a activar o desactivar el audio
else if (Input::get()->checkModInput(input_service, input_mute, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i))
else if (Input::get()->checkModInput(InputType::SERVICE, InputType::MUTE, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i))
{
switchAudio();
return;
}
if (Input::get()->checkInput(input_service, INPUT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i))
if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i))
{
servicePressedCounter[i + 1]++;
service_pressed_counter[i + 1]++;
if (servicePressedCounter[i + 1] >= 3000)
if (service_pressed_counter[i + 1] >= 3000)
{
OnScreenHelp::get()->toggleState();
servicePressedCounter[i + 1] = 0;
service_pressed_counter[i + 1] = 0;
}
return;
}
else
{
servicePressedCounter[i + 1] = 0;
service_pressed_counter[i + 1] = 0;
}
}
}

View File

@@ -1,7 +1,7 @@
#include <vector>
namespace globalInputs
{
extern std::vector<int> servicePressedCounter;
extern std::vector<int> service_pressed_counter;
// Inicializa variables
void init();

View File

@@ -1,5 +1,6 @@
#include "hiscore_table.h"
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND
#include <SDL2/SDL_events.h> // for SDL_PollEvent, SDL_Event, SDL_QUIT
#include <SDL2/SDL_pixels.h> // for SDL_PIXELFORMAT_RGBA8888
#include <SDL2/SDL_timer.h> // for SDL_GetTicks
#include <SDL2/SDL_video.h> // for SDL_WINDOWEVENT_SIZE_CHANGED
@@ -7,52 +8,45 @@
#include <vector> // for vector
#include "asset.h" // for Asset
#include "background.h" // for Background
#include "global_inputs.h" // for globalInputs::check
#include "fade.h" // for Fade, FadeMode, FadeType
#include "global_inputs.h" // for check
#include "input.h" // for Input
#include "jail_audio.h" // for JA_GetMusicState, JA_Music_state
#include "lang.h" // for getText
#include "options.h" // for options
#include "param.h" // for param
#include "resource.h" // for Resource
#include "screen.h" // for Screen
#include "text.h" // for Text, TEXT_CENTER, TEXT_SHADOW, TEXT_COLOR
#include "utils.h" // for Param, ParamGame, HiScoreEntry
#include "section.h" // for Name, name, Options, options
#include "text.h" // for Text, TEXT_CENTER, TEXT_SHADOW, TEXT...
#include "utils.h" // for Param, ParamGame, Color, HiScoreEntry
// Constructor
HiScoreTable::HiScoreTable(JA_Music_t *music)
: music(music)
HiScoreTable::HiScoreTable()
: renderer_(Screen::get()->getRenderer()),
backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
fade_(std::make_unique<Fade>()),
background_(std::make_unique<Background>()),
text_(std::make_unique<Text>(Resource::get()->getTexture("smb2.gif"), Resource::get()->getTextFile("smb2.txt"))),
counter_(0),
ticks_(0),
view_area_({0, 0, param.game.width, param.game.height}),
fade_mode_(FadeMode::IN)
{
// Copia punteros
renderer = Screen::get()->getRenderer();
// Objetos
eventHandler = std::make_unique<SDL_Event>();
fade = std::make_unique<Fade>(renderer);
background = std::make_unique<Background>(renderer);
text = std::make_unique<Text>(Asset::get()->get("smb2.gif"), Asset::get()->get("smb2.txt"), renderer);
// Crea un backbuffer para el renderizador
backbuffer = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);
SDL_SetTextureBlendMode(backbuffer, SDL_BLENDMODE_BLEND);
// Inicializa variables
// Inicializa el resto de variables
section::name = section::Name::HI_SCORE_TABLE;
ticks = 0;
ticksSpeed = 15;
counter = 0;
counterEnd = 800;
viewArea = {0, 0, param.game.width, param.game.height};
fadeMode = FadeMode::IN;
// Inicializa objetos
background->setPos(param.game.game_area.rect);
background->setCloudsSpeed(-0.1f);
background->setGradientNumber(1);
background->setTransition(0.8f);
fade->setColor(fade_color.r, fade_color.g, fade_color.b);
fade->setType(FadeType::RANDOM_SQUARE);
fade->setPost(param.fade.post_duration);
fade->setMode(fadeMode);
fade->activate();
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
background_->setPos(param.game.game_area.rect);
background_->setCloudsSpeed(-0.1f);
background_->setGradientNumber(1);
background_->setTransition(0.8f);
fade_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_->setType(FadeType::RANDOM_SQUARE);
fade_->setPost(param.fade.post_duration);
fade_->setMode(fade_mode_);
fade_->activate();
// Crea el contenido de la textura con la lista de puntuaciones
fillTexture();
@@ -61,45 +55,45 @@ HiScoreTable::HiScoreTable(JA_Music_t *music)
// Destructor
HiScoreTable::~HiScoreTable()
{
SDL_DestroyTexture(backbuffer);
SDL_DestroyTexture(backbuffer_);
}
// Actualiza las variables
void HiScoreTable::update()
{
// Actualiza las variables
if (SDL_GetTicks() - ticks > ticksSpeed)
if (SDL_GetTicks() - ticks_ > TICKS_SPEED_)
{
// Actualiza el contador de ticks
ticks = SDL_GetTicks();
ticks_ = SDL_GetTicks();
// Mantiene la música sonando
if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED))
{
JA_PlayMusic(music);
JA_PlayMusic(Resource::get()->getMusic("title.ogg"));
}
// Actualiza el objeto screen
Screen::get()->update();
// Actualiza el fondo
background->update();
background_->update();
// Gestiona el fade
updateFade();
// Gestiona el contador y sus eventos
counter++;
counter_++;
if (counter == 150)
if (counter_ == 150)
{
background->setColor({0, 0, 0});
background->setAlpha(96);
background_->setColor({0, 0, 0});
background_->setAlpha(96);
}
if (counter == counterEnd)
if (counter_ == COUNTER_END_)
{
fade->activate();
fade_->activate();
}
}
}
@@ -107,40 +101,40 @@ void HiScoreTable::update()
// Crea el contenido de la textura con la lista de puntuaciones
void HiScoreTable::fillTexture()
{
// hay 27 letras - 7 de puntos quedan 20 caracteres 20 - nameLenght 0 numDots
constexpr auto maxNames = 10;
constexpr auto spaceBetweenHeader = 32;
const auto spaceBetweenLines = text->getCharacterSize() * 2.0f;
const auto size = spaceBetweenHeader + spaceBetweenLines * (maxNames - 1) + text->getCharacterSize();
const auto firstLine = (param.game.height - size) / 2;
// hay 27 letras - 7 de puntos quedan 20 caracteres 20 - name_lenght 0 num_dots
constexpr auto max_names = 10;
constexpr auto space_between_header = 32;
const auto space_between_lines = text_->getCharacterSize() * 2.0f;
const auto size = space_between_header + space_between_lines * (max_names - 1) + text_->getCharacterSize();
const auto first_line = (param.game.height - size) / 2;
// Pinta en el backbuffer el texto y los sprites
auto temp = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, backbuffer);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
SDL_RenderClear(renderer_);
// Escribe el texto: Mejores puntuaciones
text->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, firstLine, lang::getText(42), 1, orange_color, 1, shdw_txt_color);
text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, first_line, lang::getText(42), 1, orange_color, 1, shdw_txt_color);
// Escribe los nombres de la tabla de puntuaciones
for (int i = 0; i < maxNames; ++i)
for (int i = 0; i < max_names; ++i)
{
const auto nameLenght = options.game.hi_score_table[i].name.length();
const auto name_lenght = options.game.hi_score_table[i].name.length();
const auto score = format(options.game.hi_score_table[i].score);
const auto scoreLenght = score.size();
const auto numDots = 25 - nameLenght - scoreLenght;
std::string dots = "";
for (int j = 0; j < (int)numDots; ++j)
const auto score_lenght = score.size();
const auto num_dots = 25 - name_lenght - score_lenght;
std::string dots;
for (int j = 0; j < (int)num_dots; ++j)
{
dots = dots + ".";
}
const auto line = options.game.hi_score_table[i].name + dots + score;
text->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, (i * spaceBetweenLines) + firstLine + spaceBetweenHeader, line, 1, orange_color, 1, shdw_txt_color);
text_->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, (i * space_between_lines) + first_line + space_between_header, line, 1, orange_color, 1, shdw_txt_color);
}
// Cambia el destino de renderizado
SDL_SetRenderTarget(renderer, temp);
SDL_SetRenderTarget(renderer_, temp);
}
// Pinta en pantalla
@@ -153,16 +147,16 @@ void HiScoreTable::render()
Screen::get()->clean(bg_color);
// Pinta el fondo
background->render();
background_->render();
// Establece la ventana del backbuffer
viewArea.y = std::max(0, param.game.height - counter + 100);
view_area_.y = std::max(0, param.game.height - counter_ + 100);
// Copia el backbuffer al renderizador
SDL_RenderCopy(renderer, backbuffer, nullptr, &viewArea);
SDL_RenderCopy(renderer_, backbuffer_, nullptr, &view_area_);
// Renderiza el fade
fade->render();
fade_->render();
// Vuelca el contenido del renderizador en pantalla
Screen::get()->blit();
@@ -171,7 +165,7 @@ void HiScoreTable::render()
// Recarga todas las texturas
void HiScoreTable::reloadTextures()
{
text->reLoadTexture();
text_->reLoadTexture();
fillTexture();
}
@@ -179,19 +173,21 @@ void HiScoreTable::reloadTextures()
void HiScoreTable::checkEvents()
{
// Comprueba los eventos que hay en la cola
while (SDL_PollEvent(eventHandler.get()) != 0)
SDL_Event event;
while (SDL_PollEvent(&event))
{
// Evento de salida de la aplicación
if (eventHandler->type == SDL_QUIT)
if (event.type == SDL_QUIT)
{
section::name = section::Name::QUIT;
section::options = section::Options::QUIT_FROM_EVENT;
break;
}
// Comprueba si se ha cambiado el tamaño de la ventana
else if (eventHandler->type == SDL_WINDOWEVENT)
else if (event.type == SDL_WINDOWEVENT)
{
if (eventHandler->window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
reloadTextures();
}
@@ -233,16 +229,16 @@ void HiScoreTable::run()
// Gestiona el fade
void HiScoreTable::updateFade()
{
fade->update();
fade_->update();
if (fade->hasEnded() && fadeMode == FadeMode::IN)
if (fade_->hasEnded() && fade_mode_ == FadeMode::IN)
{
fade->reset();
fadeMode = FadeMode::OUT;
fade->setMode(fadeMode);
fade_->reset();
fade_mode_ = FadeMode::OUT;
fade_->setMode(fade_mode_);
}
if (fade->hasEnded() && fadeMode == FadeMode::OUT)
if (fade_->hasEnded() && fade_mode_ == FadeMode::OUT)
{
section::name = section::Name::INSTRUCTIONS;
}
@@ -255,7 +251,7 @@ std::string HiScoreTable::format(int number)
const std::string score = std::to_string(number);
auto index = (int)score.size() - 1;
std::string result = "";
std::string result;
auto i = 0;
while (index >= 0)
{

View File

@@ -1,17 +1,14 @@
#pragma once
#include <SDL2/SDL_events.h> // for SDL_Event
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_render.h> // for SDL_Renderer, SDL_Texture
#include <SDL2/SDL_stdinc.h> // for Uint16, Uint32
#include <memory>
#include <string> // for string
#include "fade.h"
#include "section.h" // for SectionOptions
#include "background.h"
#include "text.h"
struct JA_Music_t;
#include <SDL2/SDL_stdinc.h> // for Uint16, Uint32, Uint8
#include <memory> // for unique_ptr
#include <string> // for string
class Background; // lines 8-8
class Fade; // lines 9-9
class Text; // lines 10-10
enum class FadeMode : Uint8; // lines 11-11
/*
Esta clase gestiona un estado del programa. Se encarga de mostrar la tabla con las puntuaciones
@@ -27,23 +24,23 @@ struct JA_Music_t;
class HiScoreTable
{
private:
// Objetos y punteros
SDL_Renderer *renderer; // El renderizador de la ventana
SDL_Texture *backbuffer; // Textura para usar como backbuffer
JA_Music_t *music; // Musica de fondo
// Constantes
static constexpr Uint16 COUNTER_END_ = 800; // Valor final para el contador
static constexpr Uint32 TICKS_SPEED_ = 15; // Velocidad a la que se repiten los bucles del programa
std::unique_ptr<Fade> fade; // Objeto para renderizar fades
std::unique_ptr<Background> background; // Objeto para dibujar el fondo del juego
std::unique_ptr<SDL_Event> eventHandler; // Manejador de eventos
std::unique_ptr<Text> text; // Objeto para escribir texto
// Objetos y punteros
SDL_Renderer *renderer_; // El renderizador de la ventana
SDL_Texture *backbuffer_; // Textura para usar como backbuffer
std::unique_ptr<Fade> fade_; // Objeto para renderizar fades
std::unique_ptr<Background> background_; // Objeto para dibujar el fondo del juego
std::unique_ptr<Text> text_; // Objeto para escribir texto
// Variables
Uint16 counter; // Contador
Uint16 counterEnd; // Valor final para el contador
Uint32 ticks; // Contador de ticks para ajustar la velocidad del programa
Uint32 ticksSpeed; // Velocidad a la que se repiten los bucles del programa
SDL_Rect viewArea; // Parte de la textura que se muestra en pantalla
FadeMode fadeMode; // Modo de fade a utilizar
Uint16 counter_; // 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
// Actualiza las variables
void update();
@@ -71,7 +68,7 @@ private:
public:
// Constructor
HiScoreTable(JA_Music_t *music);
HiScoreTable();
// Destructor
~HiScoreTable();

View File

@@ -6,122 +6,106 @@
#include <iostream> // for basic_ostream, operator<<, cout, basi...
// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado
Input *Input::input = nullptr;
Input *Input::input_ = nullptr;
// [SINGLETON] Crearemos el objeto input con esta función estática
void Input::init(std::string dbPath)
void Input::init(const std::string &game_controller_db_path)
{
Input::input = new Input(dbPath);
Input::input_ = new Input(game_controller_db_path);
}
// [SINGLETON] Destruiremos el objeto input con esta función estática
void Input::destroy()
{
delete Input::input;
delete Input::input_;
}
// [SINGLETON] Con este método obtenemos el objeto input y podemos trabajar con él
Input *Input::get()
{
return Input::input;
return Input::input_;
}
// Constructor
Input::Input(std::string dbPath)
: dbPath(dbPath)
Input::Input(const std::string &game_controller_db_path)
: game_controller_db_path_(game_controller_db_path),
enabled_(true)
{
// Inicializa variables
verbose = false;
enabled = true;
// Busca si hay mandos conectados
discoverGameControllers();
// Inicializa las vectores
keyBindings_t kb;
KeyBindings kb;
kb.scancode = 0;
kb.active = false;
keyBindings.resize(input_number_of_inputs, kb);
key_bindings_.resize(static_cast<int>(InputType::NUMBER_OF_INPUTS), kb);
GameControllerBindings_t gcb;
ControllerBindings gcb;
gcb.button = SDL_CONTROLLER_BUTTON_INVALID;
gcb.active = false;
gameControllerBindings.resize(numGamepads);
for (int i = 0; i < numGamepads; ++i)
controller_bindings_.resize(num_gamepads_);
for (int i = 0; i < num_gamepads_; ++i)
{
gameControllerBindings[i].resize(input_number_of_inputs, gcb);
controller_bindings_[i].resize(static_cast<int>(InputType::NUMBER_OF_INPUTS), gcb);
}
// Listado de los inputs usados para jugar, excluyendo botones para la interfaz
gameInputs.clear();
gameInputs.push_back(input_fire_left);
gameInputs.push_back(input_fire_center);
gameInputs.push_back(input_fire_right);
gameInputs.push_back(input_up);
gameInputs.push_back(input_down);
gameInputs.push_back(input_left);
gameInputs.push_back(input_right);
game_inputs_.clear();
game_inputs_.push_back(InputType::FIRE_LEFT);
game_inputs_.push_back(InputType::FIRE_CENTER);
game_inputs_.push_back(InputType::FIRE_RIGHT);
game_inputs_.push_back(InputType::UP);
game_inputs_.push_back(InputType::DOWN);
game_inputs_.push_back(InputType::LEFT);
game_inputs_.push_back(InputType::RIGHT);
// Listado de los inputs para jugar que utilizan botones, ni palancas ni crucetas
buttonInputs.clear();
buttonInputs.push_back(input_fire_left);
buttonInputs.push_back(input_fire_center);
buttonInputs.push_back(input_fire_right);
buttonInputs.push_back(input_start);
}
// Destructor
Input::~Input()
{
}
// Actualiza el estado del objeto
void Input::update()
{
if (disabledUntil == d_keyPressed && !checkAnyInput())
{
enable();
}
button_inputs_.clear();
button_inputs_.push_back(InputType::FIRE_LEFT);
button_inputs_.push_back(InputType::FIRE_CENTER);
button_inputs_.push_back(InputType::FIRE_RIGHT);
button_inputs_.push_back(InputType::START);
}
// Asigna inputs a teclas
void Input::bindKey(inputs_e input, SDL_Scancode code)
void Input::bindKey(InputType input, SDL_Scancode code)
{
keyBindings[input].scancode = code;
key_bindings_[static_cast<int>(input)].scancode = code;
}
// Asigna inputs a botones del mando
void Input::bindGameControllerButton(int index, inputs_e input, SDL_GameControllerButton button)
void Input::bindGameControllerButton(int controller_index, InputType input, SDL_GameControllerButton button)
{
if (index < numGamepads)
if (controller_index < num_gamepads_)
{
gameControllerBindings[index][input].button = button;
controller_bindings_[controller_index][static_cast<int>(input)].button = button;
}
}
// Asigna inputs a botones del mando
void Input::bindGameControllerButton(int index, inputs_e inputTarget, inputs_e inputSource)
void Input::bindGameControllerButton(int controller_index, InputType input_target, InputType input_source)
{
if (index < numGamepads)
if (controller_index < num_gamepads_)
{
gameControllerBindings[index][inputTarget].button = gameControllerBindings[index][inputSource].button;
controller_bindings_[controller_index][static_cast<int>(input_target)].button = controller_bindings_[controller_index][static_cast<int>(input_source)].button;
}
}
// Comprueba si un input esta activo
bool Input::checkInput(inputs_e input, bool repeat, int device, int index)
bool Input::checkInput(InputType input, bool repeat, int device, int controller_index)
{
if (!enabled)
if (!enabled_)
{
return false;
}
bool successKeyboard = false;
bool successGameController = false;
bool success_keyboard = false;
bool success_controller = false;
const int input_index = static_cast<int>(input);
if (device == INPUT_USE_ANY)
{
index = 0;
controller_index = 0;
}
if (device == INPUT_USE_KEYBOARD || device == INPUT_USE_ANY)
@@ -130,108 +114,109 @@ bool Input::checkInput(inputs_e input, bool repeat, int device, int index)
if (repeat)
{
if (keyStates[keyBindings[input].scancode] != 0)
if (keyStates[key_bindings_[input_index].scancode] != 0)
{
successKeyboard = true;
success_keyboard = true;
}
else
{
successKeyboard = false;
success_keyboard = false;
}
}
else
{
if (!keyBindings[input].active)
if (!key_bindings_[input_index].active)
{
if (keyStates[keyBindings[input].scancode] != 0)
if (keyStates[key_bindings_[input_index].scancode] != 0)
{
keyBindings[input].active = true;
successKeyboard = true;
key_bindings_[input_index].active = true;
success_keyboard = true;
}
else
{
successKeyboard = false;
success_keyboard = false;
}
}
else
{
if (keyStates[keyBindings[input].scancode] == 0)
if (keyStates[key_bindings_[input_index].scancode] == 0)
{
keyBindings[input].active = false;
successKeyboard = false;
key_bindings_[input_index].active = false;
success_keyboard = false;
}
else
{
successKeyboard = false;
success_keyboard = false;
}
}
}
}
if (gameControllerFound() && index < numGamepads)
if (gameControllerFound() && controller_index < num_gamepads_)
if ((device == INPUT_USE_GAMECONTROLLER) || (device == INPUT_USE_ANY))
{
successGameController = checkAxisInput(input, index);
if (!successGameController)
success_controller = checkAxisInput(input, controller_index);
if (!success_controller)
{
if (repeat)
{
if (SDL_GameControllerGetButton(connectedControllers[index], gameControllerBindings[index][input].button) != 0)
if (SDL_GameControllerGetButton(connected_controllers_[controller_index], controller_bindings_[controller_index][input_index].button) != 0)
{
successGameController = true;
success_controller = true;
}
else
{
successGameController = false;
success_controller = false;
}
}
else
{
if (!gameControllerBindings[index][input].active)
if (!controller_bindings_[controller_index][input_index].active)
{
if (SDL_GameControllerGetButton(connectedControllers[index], gameControllerBindings[index][input].button) != 0)
if (SDL_GameControllerGetButton(connected_controllers_[controller_index], controller_bindings_[controller_index][input_index].button) != 0)
{
gameControllerBindings[index][input].active = true;
successGameController = true;
controller_bindings_[controller_index][input_index].active = true;
success_controller = true;
}
else
{
successGameController = false;
success_controller = false;
}
}
else
{
if (SDL_GameControllerGetButton(connectedControllers[index], gameControllerBindings[index][input].button) == 0)
if (SDL_GameControllerGetButton(connected_controllers_[controller_index], controller_bindings_[controller_index][input_index].button) == 0)
{
gameControllerBindings[index][input].active = false;
successGameController = false;
controller_bindings_[controller_index][input_index].active = false;
success_controller = false;
}
else
{
successGameController = false;
success_controller = false;
}
}
}
}
}
return (successKeyboard || successGameController);
return (success_keyboard || success_controller);
}
// Comprueba si un input con modificador esta activo
bool Input::checkModInput(inputs_e inputMod, inputs_e input, bool repeat, int device, int index)
bool Input::checkModInput(InputType input_mod, InputType input, bool repeat, int device, int controller_index)
{
if (!enabled || index >= numGamepads || !checkInput(inputMod, INPUT_ALLOW_REPEAT, device, index))
if (!enabled_ || controller_index >= num_gamepads_ || !checkInput(input_mod, INPUT_ALLOW_REPEAT, device, controller_index))
{
return false;
}
bool successKeyboard = false;
bool successGameController = false;
bool success_keyboard = false;
bool success_controller = false;
const int input_index = static_cast<int>(input);
if (device == INPUT_USE_ANY)
{
index = 0;
controller_index = 0;
}
if (device == INPUT_USE_KEYBOARD || device == INPUT_USE_ANY)
@@ -240,111 +225,111 @@ bool Input::checkModInput(inputs_e inputMod, inputs_e input, bool repeat, int de
if (repeat)
{
if (keyStates[keyBindings[input].scancode] != 0)
if (keyStates[key_bindings_[input_index].scancode] != 0)
{
successKeyboard = true;
success_keyboard = true;
}
else
{
successKeyboard = false;
success_keyboard = false;
}
}
else
{
if (!keyBindings[input].active)
if (!key_bindings_[input_index].active)
{
if (keyStates[keyBindings[input].scancode] != 0)
if (keyStates[key_bindings_[input_index].scancode] != 0)
{
keyBindings[input].active = true;
successKeyboard = true;
key_bindings_[input_index].active = true;
success_keyboard = true;
}
else
{
successKeyboard = false;
success_keyboard = false;
}
}
else
{
if (keyStates[keyBindings[input].scancode] == 0)
if (keyStates[key_bindings_[input_index].scancode] == 0)
{
keyBindings[input].active = false;
successKeyboard = false;
key_bindings_[input_index].active = false;
success_keyboard = false;
}
else
{
successKeyboard = false;
success_keyboard = false;
}
}
}
}
if (gameControllerFound() && index < numGamepads)
if (gameControllerFound() && controller_index < num_gamepads_)
if ((device == INPUT_USE_GAMECONTROLLER) || (device == INPUT_USE_ANY))
{
successGameController = checkAxisInput(input, index);
if (!successGameController)
success_controller = checkAxisInput(input, controller_index);
if (!success_controller)
{
if (repeat)
{
if (SDL_GameControllerGetButton(connectedControllers[index], gameControllerBindings[index][input].button) != 0)
if (SDL_GameControllerGetButton(connected_controllers_[controller_index], controller_bindings_[controller_index][input_index].button) != 0)
{
successGameController = true;
success_controller = true;
}
else
{
successGameController = false;
success_controller = false;
}
}
else
{
if (!gameControllerBindings[index][input].active)
if (!controller_bindings_[controller_index][input_index].active)
{
if (SDL_GameControllerGetButton(connectedControllers[index], gameControllerBindings[index][input].button) != 0)
if (SDL_GameControllerGetButton(connected_controllers_[controller_index], controller_bindings_[controller_index][input_index].button) != 0)
{
gameControllerBindings[index][input].active = true;
successGameController = true;
controller_bindings_[controller_index][input_index].active = true;
success_controller = true;
}
else
{
successGameController = false;
success_controller = false;
}
}
else
{
if (SDL_GameControllerGetButton(connectedControllers[index], gameControllerBindings[index][input].button) == 0)
if (SDL_GameControllerGetButton(connected_controllers_[controller_index], controller_bindings_[controller_index][input_index].button) == 0)
{
gameControllerBindings[index][input].active = false;
successGameController = false;
controller_bindings_[controller_index][input_index].active = false;
success_controller = false;
}
else
{
successGameController = false;
success_controller = false;
}
}
}
}
}
return (successKeyboard || successGameController);
return (success_keyboard || success_controller);
}
// Comprueba si hay almenos un input activo
bool Input::checkAnyInput(int device, int index)
bool Input::checkAnyInput(int device, int controller_index)
{
if (device == INPUT_USE_ANY)
{
index = 0;
controller_index = 0;
}
if (device == INPUT_USE_KEYBOARD || device == INPUT_USE_ANY)
{
const Uint8 *mKeystates = SDL_GetKeyboardState(nullptr);
for (int i = 0; i < (int)keyBindings.size(); ++i)
for (int i = 0; i < (int)key_bindings_.size(); ++i)
{
if (mKeystates[keyBindings[i].scancode] != 0 && !keyBindings[i].active)
if (mKeystates[key_bindings_[i].scancode] != 0 && !key_bindings_[i].active)
{
keyBindings[i].active = true;
key_bindings_[i].active = true;
return true;
}
}
@@ -354,11 +339,11 @@ bool Input::checkAnyInput(int device, int index)
{
if (device == INPUT_USE_GAMECONTROLLER || device == INPUT_USE_ANY)
{
for (int i = 0; i < (int)gameControllerBindings.size(); ++i)
for (int i = 0; i < (int)controller_bindings_.size(); ++i)
{
if (SDL_GameControllerGetButton(connectedControllers[index], gameControllerBindings[index][i].button) != 0 && !gameControllerBindings[index][i].active)
if (SDL_GameControllerGetButton(connected_controllers_[controller_index], controller_bindings_[controller_index][i].button) != 0 && !controller_bindings_[controller_index][i].active)
{
gameControllerBindings[index][i].active = true;
controller_bindings_[controller_index][i].active = true;
return true;
}
}
@@ -372,13 +357,13 @@ bool Input::checkAnyInput(int device, int index)
int Input::checkAnyButtonPressed(bool repeat)
{
// Si está pulsado el botón de servicio, ningún botón se puede considerar pulsado
if (checkInput(input_service, INPUT_ALLOW_REPEAT, INPUT_USE_ANY))
if (checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, INPUT_USE_ANY))
{
return 0;
}
// Solo comprueba los botones definidos previamente
for (auto bi : buttonInputs)
for (auto bi : button_inputs_)
{
// Comprueba el teclado
if (checkInput(bi, repeat, INPUT_USE_KEYBOARD))
@@ -387,7 +372,7 @@ int Input::checkAnyButtonPressed(bool repeat)
}
// Comprueba los mandos
for (int i = 0; i < numGamepads; ++i)
for (int i = 0; i < num_gamepads_; ++i)
{
if (checkInput(bi, repeat, INPUT_USE_GAMECONTROLLER, i))
{
@@ -409,57 +394,51 @@ bool Input::discoverGameControllers()
SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
}
if (SDL_GameControllerAddMappingsFromFile(dbPath.c_str()) < 0)
if (SDL_GameControllerAddMappingsFromFile(game_controller_db_path_.c_str()) < 0)
{
if (verbose)
{
std::cout << "Error, could not load " << dbPath.c_str() << " file: " << SDL_GetError() << std::endl;
std::cout << "Error, could not load " << game_controller_db_path_.c_str() << " file: " << SDL_GetError() << std::endl;
}
}
numJoysticks = SDL_NumJoysticks();
numGamepads = 0;
num_joysticks_ = SDL_NumJoysticks();
num_gamepads_ = 0;
// Cuenta el número de mandos
joysticks.clear();
for (int i = 0; i < numJoysticks; ++i)
joysticks_.clear();
for (int i = 0; i < num_joysticks_; ++i)
{
SDL_Joystick *joy = SDL_JoystickOpen(i);
joysticks.push_back(joy);
joysticks_.push_back(joy);
if (SDL_IsGameController(i))
{
numGamepads++;
num_gamepads_++;
}
}
if (verbose)
{
std::cout << "\nChecking for game controllers...\n";
std::cout << numJoysticks << " joysticks found, " << numGamepads << " are gamepads\n";
}
std::cout << "\n** LOOKING FOR GAME CONTROLLERS" << std::endl;
// std::cout << " " << num_joysticks_ << " joysticks found" << std::endl;
std::cout << "Gamepads found: " << num_gamepads_ << std::endl;
if (numGamepads > 0)
if (num_gamepads_ > 0)
{
found = true;
for (int i = 0; i < numGamepads; i++)
for (int i = 0; i < num_gamepads_; i++)
{
// Abre el mando y lo añade a la lista
SDL_GameController *pad = SDL_GameControllerOpen(i);
auto pad = SDL_GameControllerOpen(i);
if (SDL_GameControllerGetAttached(pad) == 1)
{
connectedControllers.push_back(pad);
const std::string separator(" #");
std::string name = SDL_GameControllerNameForIndex(i);
if (verbose)
connected_controllers_.push_back(pad);
const std::string name = SDL_GameControllerNameForIndex(i);
{
std::cout << name << std::endl;
std::cout << "#" << i << ": " << name << std::endl;
}
controllerNames.push_back(name);
controller_names_.push_back(name);
}
else
{
if (verbose)
{
std::cout << "SDL_GetError() = " << SDL_GetError() << std::endl;
}
@@ -469,53 +448,35 @@ bool Input::discoverGameControllers()
SDL_GameControllerEventState(SDL_ENABLE);
}
std::cout << "\n** FINISHED LOOKING FOR GAME CONTROLLERS" << std::endl;
return found;
}
// Comprueba si hay algun mando conectado
bool Input::gameControllerFound()
{
return numGamepads > 0 ? true : false;
return num_gamepads_ > 0 ? true : false;
}
// Obten el nombre de un mando de juego
std::string Input::getControllerName(int index) const
std::string Input::getControllerName(int controller_index) const
{
return numGamepads > 0 ? controllerNames[index] : "";
return num_gamepads_ > 0 ? controller_names_[controller_index] : "";
}
// Obten el número de mandos conectados
int Input::getNumControllers() const
{
return numGamepads;
}
// Establece si ha de mostrar mensajes
void Input::setVerbose(bool value)
{
verbose = value;
}
// Deshabilita las entradas durante un periodo de tiempo
void Input::disableUntil(i_disable_e value)
{
disabledUntil = value;
enabled = false;
}
// Hablita las entradas
void Input::enable()
{
enabled = true;
disabledUntil = d_notDisabled;
return num_gamepads_;
}
// Obtiene el indice del controlador a partir de un event.id
int Input::getJoyIndex(int id) const
{
for (int i = 0; i < numJoysticks; ++i)
for (int i = 0; i < num_joysticks_; ++i)
{
if (SDL_JoystickInstanceID(joysticks[i]) == id)
if (SDL_JoystickInstanceID(joysticks_[i]) == id)
{
return i;
}
@@ -524,7 +485,7 @@ int Input::getJoyIndex(int id) const
}
// Muestra por consola los controles asignados
void Input::printBindings(int device, int index) const
void Input::printBindings(int device, int controller_index) const
{
if (device == INPUT_USE_ANY || device == INPUT_USE_KEYBOARD)
{
@@ -533,35 +494,35 @@ void Input::printBindings(int device, int index) const
if (device == INPUT_USE_GAMECONTROLLER)
{
if (index >= numGamepads)
if (controller_index >= num_gamepads_)
{
return;
}
// Muestra el nombre del mando
std::cout << "\n"
<< controllerNames[index] << std::endl;
<< controller_names_[controller_index] << std::endl;
// Muestra los botones asignados
for (auto bi : buttonInputs)
for (auto bi : button_inputs_)
{
std::cout << to_string(bi) << " : " << gameControllerBindings[index][bi].button << std::endl;
std::cout << to_string(bi) << " : " << controller_bindings_[controller_index][static_cast<int>(bi)].button << std::endl;
}
}
}
// Obtiene el SDL_GameControllerButton asignado a un input
SDL_GameControllerButton Input::getControllerBinding(int index, inputs_e input) const
SDL_GameControllerButton Input::getControllerBinding(int controller_index, InputType input) const
{
return gameControllerBindings[index][input].button;
return controller_bindings_[controller_index][static_cast<int>(input)].button;
}
// Obtiene el indice a partir del nombre del mando
int Input::getIndexByName(std::string name) const
int Input::getIndexByName(const std::string &name) const
{
for (int i = 0; i < numGamepads; ++i)
for (int i = 0; i < num_gamepads_; ++i)
{
if (controllerNames[i] == name)
if (controller_names_[i] == name)
{
return i;
}
@@ -569,30 +530,30 @@ int Input::getIndexByName(std::string name) const
return -1;
}
// Convierte un inputs_e a std::string
std::string Input::to_string(inputs_e input) const
// Convierte un InputType a std::string
std::string Input::to_string(InputType input) const
{
if (input == input_fire_left)
if (input == InputType::FIRE_LEFT)
{
return "input_fire_left";
}
if (input == input_fire_center)
if (input == InputType::FIRE_CENTER)
{
return "input_fire_center";
}
if (input == input_fire_right)
if (input == InputType::FIRE_RIGHT)
{
return "input_fire_right";
}
if (input == input_start)
if (input == InputType::START)
{
return "input_start";
}
if (input == input_service)
if (input == InputType::SERVICE)
{
return "input_service";
}
@@ -600,76 +561,67 @@ std::string Input::to_string(inputs_e input) const
return "";
}
// Convierte un std::string a inputs_e
inputs_e Input::to_inputs_e(std::string name) const
// Convierte un std::string a InputType
InputType Input::to_inputs_e(const std::string &name) const
{
if (name == "input_fire_left")
{
return input_fire_left;
return InputType::FIRE_LEFT;
}
if (name == "input_fire_center")
{
return input_fire_center;
return InputType::FIRE_CENTER;
}
if (name == "input_fire_right")
{
return input_fire_right;
return InputType::FIRE_RIGHT;
}
if (name == "input_start")
{
return input_start;
return InputType::START;
}
if (name == "input_service")
{
return input_service;
return InputType::SERVICE;
}
return input_null;
}
// Activa todos los inputs. Sirve para evitar inputs sin repeticiones pero que ya vienen pulsados cuando checkInput no estaba monitorizando
void Input::allActive(int index)
{
for (int i = 0; i < (int)buttonInputs.size(); ++i)
{
gameControllerBindings[index][i].active = true;
}
return InputType::NONE;
}
// Comprueba el eje del mando
bool Input::checkAxisInput(inputs_e input, int index) const
bool Input::checkAxisInput(InputType input, int controller_index) const
{
bool success = false;
switch (input)
{
case input_left:
if (SDL_GameControllerGetAxis(connectedControllers[index], SDL_CONTROLLER_AXIS_LEFTX) < -30000)
case InputType::LEFT:
if (SDL_GameControllerGetAxis(connected_controllers_[controller_index], SDL_CONTROLLER_AXIS_LEFTX) < -30000)
{
success = true;
}
break;
case input_right:
if (SDL_GameControllerGetAxis(connectedControllers[index], SDL_CONTROLLER_AXIS_LEFTX) > 30000)
case InputType::RIGHT:
if (SDL_GameControllerGetAxis(connected_controllers_[controller_index], SDL_CONTROLLER_AXIS_LEFTX) > 30000)
{
success = true;
}
break;
case input_up:
if (SDL_GameControllerGetAxis(connectedControllers[index], SDL_CONTROLLER_AXIS_LEFTY) < -30000)
case InputType::UP:
if (SDL_GameControllerGetAxis(connected_controllers_[controller_index], SDL_CONTROLLER_AXIS_LEFTY) < -30000)
{
success = true;
}
break;
case input_down:
if (SDL_GameControllerGetAxis(connectedControllers[index], SDL_CONTROLLER_AXIS_LEFTY) > 30000)
case InputType::DOWN:
if (SDL_GameControllerGetAxis(connected_controllers_[controller_index], SDL_CONTROLLER_AXIS_LEFTY) > 30000)
{
success = true;
}

View File

@@ -1,11 +1,11 @@
#pragma once
#include <SDL2/SDL_gamecontroller.h> // for SDL_GameControllerButton, SDL_G...
#include <SDL2/SDL_joystick.h> // for SDL_Joystick
#include <SDL2/SDL_scancode.h> // for SDL_Scancode
#include <SDL2/SDL_stdinc.h> // for Uint8
#include <string> // for string, basic_string
#include <vector> // for vector
#include <SDL2/SDL_gamecontroller.h> // for SDL_GameControllerButton, SDL_G...
#include <SDL2/SDL_joystick.h> // for SDL_Joystick
#include <SDL2/SDL_scancode.h> // for SDL_Scancode
#include <SDL2/SDL_stdinc.h> // for Uint8
#include <string> // for string, basic_string
#include <vector> // for vector
/*
connectedControllers es un vector donde estan todos los mandos encontrados [0 .. n]
@@ -16,98 +16,89 @@ device contiene el tipo de dispositivo a comprobar:
INPUT_USE_ANY mirará tanto el teclado como el PRIMER controlador
*/
enum inputs_e
enum class InputType : int
{
// Inputs de movimiento
input_up,
input_down,
input_left,
input_right,
UP,
DOWN,
LEFT,
RIGHT,
// Inputs personalizados
input_fire_left,
input_fire_center,
input_fire_right,
input_start,
FIRE_LEFT,
FIRE_CENTER,
FIRE_RIGHT,
START,
// Inputs de control
input_exit,
input_pause,
input_service,
input_window_fullscreen,
input_window_inc_size,
input_window_dec_size,
input_video_shaders,
input_reset,
input_mute,
input_showinfo,
input_config,
input_swap_controllers,
EXIT,
PAUSE,
SERVICE,
WINDOW_FULLSCREEN,
WINDOW_INC_SIZE,
WINDOW_DEC_SIZE,
VIDEO_SHADERS,
RESET,
MUTE,
SHOWINFO,
CONFIG,
SWAP_CONTROLLERS,
// Input obligatorio
input_null,
input_number_of_inputs,
NONE,
NUMBER_OF_INPUTS,
};
#define INPUT_ALLOW_REPEAT true
#define INPUT_DO_NOT_ALLOW_REPEAT false
constexpr bool INPUT_ALLOW_REPEAT = true;
constexpr bool INPUT_DO_NOT_ALLOW_REPEAT = false;
#define INPUT_USE_KEYBOARD 0
#define INPUT_USE_GAMECONTROLLER 1
#define INPUT_USE_ANY 2
enum i_disable_e
{
d_notDisabled,
d_forever,
d_keyPressed
};
constexpr int INPUT_USE_KEYBOARD = 0;
constexpr int INPUT_USE_GAMECONTROLLER = 1;
constexpr int INPUT_USE_ANY = 2;
class Input
{
private:
// [SINGLETON] Objeto screen privado para Don Melitón
static Input *input;
static Input *input_;
struct keyBindings_t
struct KeyBindings
{
Uint8 scancode; // Scancode asociado
bool active; // Indica si está activo
};
struct GameControllerBindings_t
struct ControllerBindings
{
SDL_GameControllerButton button; // GameControllerButton asociado
bool active; // Indica si está activo
};
// Variables
std::vector<SDL_GameController *> connectedControllers; // Vector con todos los mandos conectados
std::vector<SDL_Joystick *> joysticks; // Vector con todos los joysticks conectados
std::vector<keyBindings_t> keyBindings; // Vector con las teclas asociadas a los inputs predefinidos
std::vector<std::vector<GameControllerBindings_t>> gameControllerBindings; // Vector con los botones asociadas a los inputs predefinidos para cada mando
std::vector<std::string> controllerNames; // Vector con los nombres de los mandos
std::vector<inputs_e> gameInputs; // Inputs usados para jugar, normalmente direcciones y botones
std::vector<inputs_e> buttonInputs; // Inputs asignados al jugador y a botones, excluyendo direcciones
int numJoysticks; // Número de joysticks conectados
int numGamepads; // Número de mandos conectados
std::string dbPath; // Ruta al archivo gamecontrollerdb.txt
bool verbose; // Indica si ha de mostrar mensajes
i_disable_e disabledUntil; // Tiempo que esta deshabilitado
bool enabled; // Indica si está habilitado
std::vector<SDL_GameController *> connected_controllers_; // Vector con todos los mandos conectados
std::vector<SDL_Joystick *> joysticks_; // Vector con todos los joysticks conectados
std::vector<KeyBindings> key_bindings_; // Vector con las teclas asociadas a los inputs predefinidos
std::vector<std::vector<ControllerBindings>> controller_bindings_; // Vector con los botones asociadas a los inputs predefinidos para cada mando
std::vector<std::string> controller_names_; // Vector con los nombres de los mandos
std::vector<InputType> game_inputs_; // Inputs usados para jugar, normalmente direcciones y botones
std::vector<InputType> button_inputs_; // Inputs asignados al jugador y a botones, excluyendo direcciones
int num_joysticks_; // Número de joysticks conectados
int num_gamepads_; // Número de mandos conectados
std::string game_controller_db_path_; // Ruta al archivo gamecontrollerdb.txt
bool enabled_; // Indica si está habilitado
// Comprueba el eje del mando
bool checkAxisInput(inputs_e input, int index = 0) const;
bool checkAxisInput(InputType input, int controller_index = 0) const;
// Constructor
Input(std::string dbPath);
explicit Input(const std::string &game_controller_db_path);
// Destructor
~Input();
~Input() = default;
public:
// [SINGLETON] Crearemos el objeto screen con esta función estática
static void init(std::string dbPath);
static void init(const std::string &game_controller_db_path);
// [SINGLETON] Destruiremos el objeto screen con esta función estática
static void destroy();
@@ -115,24 +106,21 @@ public:
// [SINGLETON] Con este método obtenemos el objeto screen y podemos trabajar con él
static Input *get();
// Actualiza el estado del objeto
void update();
// Asigna inputs a teclas
void bindKey(inputs_e input, SDL_Scancode code);
void bindKey(InputType input, SDL_Scancode code);
// Asigna inputs a botones del mando
void bindGameControllerButton(int index, inputs_e input, SDL_GameControllerButton button);
void bindGameControllerButton(int index, inputs_e inputTarget, inputs_e inputSource);
void bindGameControllerButton(int controller_index, InputType input, SDL_GameControllerButton button);
void bindGameControllerButton(int controller_index, InputType inputTarget, InputType inputSource);
// Comprueba si un input esta activo
bool checkInput(inputs_e input, bool repeat = true, int device = INPUT_USE_ANY, int index = 0);
bool checkInput(InputType input, bool repeat = true, int device = INPUT_USE_ANY, int controller_index = 0);
// Comprueba si un input con modificador esta activo
bool checkModInput(inputs_e inputMod, inputs_e input, bool repeat = true, int device = INPUT_USE_ANY, int index = 0);
bool checkModInput(InputType input_mod, InputType input, bool repeat = true, int device = INPUT_USE_ANY, int controller_index = 0);
// Comprueba si hay almenos un input activo
bool checkAnyInput(int device = INPUT_USE_ANY, int index = 0);
bool checkAnyInput(int device = INPUT_USE_ANY, int controller_index = 0);
// Comprueba si hay algún botón pulsado
int checkAnyButtonPressed(bool repeat = INPUT_DO_NOT_ALLOW_REPEAT);
@@ -147,35 +135,23 @@ public:
int getNumControllers() const;
// Obten el nombre de un mando de juego
std::string getControllerName(int index) const;
// Establece si ha de mostrar mensajes
void setVerbose(bool value);
// Deshabilita las entradas durante un periodo de tiempo
void disableUntil(i_disable_e value);
// Hablita las entradas
void enable();
std::string getControllerName(int controller_index) const;
// Obtiene el indice del controlador a partir de un event.id
int getJoyIndex(int id) const;
// Muestra por consola los controles asignados
void printBindings(int device = INPUT_USE_KEYBOARD, int index = 0) const;
void printBindings(int device = INPUT_USE_KEYBOARD, int controller_index = 0) const;
// Obtiene el SDL_GameControllerButton asignado a un input
SDL_GameControllerButton getControllerBinding(int index, inputs_e input) const;
SDL_GameControllerButton getControllerBinding(int controller_index, InputType input) const;
// Convierte un inputs_e a std::string
std::string to_string(inputs_e input) const;
// Convierte un InputType a std::string
std::string to_string(InputType input) const;
// Convierte un std::string a inputs_e
inputs_e to_inputs_e(std::string name) const;
// Convierte un std::string a InputType
InputType to_inputs_e(const std::string &name) const;
// Obtiene el indice a partir del nombre del mando
int getIndexByName(std::string name) const;
// Activa todos los inputs. Sirve para evitar inputs sin repeticiones pero que ya vienen pulsados cuando checkInput no estaba monitorizando
void allActive(int index);
int getIndexByName(const std::string &name) const;
};

View File

@@ -1,63 +1,63 @@
#include "instructions.h"
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND
#include <SDL2/SDL_events.h> // for SDL_PollEvent, SDL_Event, SDL_QUIT
#include <SDL2/SDL_pixels.h> // for SDL_PIXELFORMAT_RGBA8888
#include <SDL2/SDL_timer.h> // for SDL_GetTicks
#include <SDL2/SDL_video.h> // for SDL_WINDOWEVENT_SIZE_CHANGED
#include <algorithm> // for max
#include <string> // for basic_string
#include <utility> // for move
#include "asset.h" // for Asset
#include "fade.h" // for Fade, FadeType::FULLSCREEN, FadeMode::IN
#include "global_inputs.h" // for globalInputs::check
#include "fade.h" // for Fade, FadeMode, FadeType
#include "global_inputs.h" // for check
#include "input.h" // for Input
#include "jail_audio.h" // for JA_GetMusicState, JA_Music_state
#include "lang.h" // for getText
#include "param.h" // for param
#include "resource.h" // for Resource
#include "screen.h" // for Screen
#include "section.h" // for name, SectionName, options, SectionOptions
#include "section.h" // for Name, name, Options, options
#include "sprite.h" // for Sprite
#include "text.h" // for Text, TEXT_CENTER, TEXT_COLOR, TEXT_SHADOW
#include "text.h" // for Text, TEXT_CENTER, TEXT_COLOR, TEXT_...
#include "texture.h" // for Texture
#include "tiled_bg.h" // for Tiledbg, TILED_MODE_STATIC
#include "utils.h" // for Param, ParamGame, Color, shdwT...
struct JA_Music_t;
#include "tiled_bg.h" // for TiledBG, TILED_MODE_STATIC
#include "utils.h" // for Param, ParamGame, Color, shdw_txt_color
struct JA_Music_t; // lines 22-22
// Constructor
Instructions::Instructions(JA_Music_t *music)
: music(music)
Instructions::Instructions()
{
// Copia los punteros
renderer = Screen::get()->getRenderer();
renderer_ = Screen::get()->getRenderer();
// Crea objetos
eventHandler = std::make_unique<SDL_Event>();
text = std::make_unique<Text>(Asset::get()->get("smb2.gif"), Asset::get()->get("smb2.txt"), renderer);
tiledbg = std::make_unique<Tiledbg>(Asset::get()->get("title_bg_tile.png"), (SDL_Rect){0, 0, param.game.width, param.game.height}, TILED_MODE_STATIC);
fade = std::make_unique<Fade>(renderer);
text_ = std::make_unique<Text>(Resource::get()->getTexture("smb2.gif"), Resource::get()->getTextFile("smb2.txt"));
tiled_bg_ = std::make_unique<TiledBG>((SDL_Rect){0, 0, param.game.width, param.game.height}, TiledBGMode::STATIC);
fade_ = std::make_unique<Fade>();
// Crea un backbuffer para el renderizador
backbuffer = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);
SDL_SetTextureBlendMode(backbuffer, SDL_BLENDMODE_BLEND);
backbuffer_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
// Crea una textura para el texto fijo
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);
SDL_SetTextureBlendMode(texture_, SDL_BLENDMODE_BLEND);
// Inicializa variables
section::name = section::Name::INSTRUCTIONS;
ticks = 0;
ticksSpeed = 15;
counter = 0;
counterEnd = 700;
view = {0, 0, param.game.width, param.game.height};
spritePos = {0, 0};
itemSpace = 2;
ticks_ = 0;
ticks_speed_ = 15;
counter_ = 0;
counter_end_ = 700;
view_ = {0, 0, param.game.width, param.game.height};
sprite_pos_ = {0, 0};
item_space_ = 2;
// Inicializa objetos
fade->setColor(fade_color.r, fade_color.g, fade_color.b);
fade->setType(FadeType::FULLSCREEN);
fade->setPost(param.fade.post_duration);
fade->setMode(FadeMode::IN);
fade->activate();
fade_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_->setType(FadeType::FULLSCREEN);
fade_->setPost(param.fade.post_duration);
fade_->setMode(FadeMode::IN);
fade_->activate();
// Rellena la textura de texto
fillTexture();
@@ -69,187 +69,178 @@ Instructions::Instructions(JA_Music_t *music)
// Destructor
Instructions::~Instructions()
{
itemTextures.clear();
sprites.clear();
item_textures_.clear();
sprites_.clear();
SDL_DestroyTexture(backbuffer);
SDL_DestroyTexture(texture);
SDL_DestroyTexture(backbuffer_);
SDL_DestroyTexture(texture_);
}
// Inicializa los sprites de los items
void Instructions::iniSprites()
{
// Inicializa las texturas
auto item1 = std::make_shared<Texture>(renderer, Asset::get()->get("item_points1_disk.png"));
itemTextures.push_back(item1);
auto item2 = std::make_shared<Texture>(renderer, Asset::get()->get("item_points2_gavina.png"));
itemTextures.push_back(item2);
auto item3 = std::make_shared<Texture>(renderer, Asset::get()->get("item_points3_pacmar.png"));
itemTextures.push_back(item3);
auto item4 = std::make_shared<Texture>(renderer, Asset::get()->get("item_clock.png"));
itemTextures.push_back(item4);
auto item5 = std::make_shared<Texture>(renderer, Asset::get()->get("item_coffee.png"));
itemTextures.push_back(item5);
item_textures_.emplace_back(Resource::get()->getTexture("item_points1_disk.png"));
item_textures_.emplace_back(Resource::get()->getTexture("item_points2_gavina.png"));
item_textures_.emplace_back(Resource::get()->getTexture("item_points3_pacmar.png"));
item_textures_.emplace_back(Resource::get()->getTexture("item_clock.png"));
item_textures_.emplace_back(Resource::get()->getTexture("item_coffee.png"));
// Inicializa los sprites
for (int i = 0; i < (int)itemTextures.size(); ++i)
for (int i = 0; i < (int)item_textures_.size(); ++i)
{
auto sprite = std::make_unique<Sprite>(0, 0, param.game.item_size, param.game.item_size, itemTextures[i]);
sprite->setPos((SDL_Point){spritePos.x, spritePos.y + ((param.game.item_size + itemSpace) * i)});
sprites.push_back(std::move(sprite));
auto sprite = std::make_unique<Sprite>(item_textures_[i], 0, 0, param.game.item_size, param.game.item_size);
sprite->setPosition((SDL_Point){sprite_pos_.x, sprite_pos_.y + ((param.game.item_size + item_space_) * i)});
sprites_.push_back(std::move(sprite));
}
}
// Actualiza los sprites
void Instructions::updateSprites()
{
SDL_Rect srcRect = {0, 0, param.game.item_size, param.game.item_size};
SDL_Rect src_rect = {0, 0, param.game.item_size, param.game.item_size};
// Disquito
srcRect.y = param.game.item_size * (((counter + 12) / 36) % 2);
sprites[0]->setSpriteClip(srcRect);
src_rect.y = param.game.item_size * (((counter_ + 12) / 36) % 2);
sprites_[0]->setSpriteClip(src_rect);
// Gavineixon
srcRect.y = param.game.item_size * (((counter + 9) / 36) % 2);
sprites[1]->setSpriteClip(srcRect);
// Gavina
src_rect.y = param.game.item_size * (((counter_ + 9) / 36) % 2);
sprites_[1]->setSpriteClip(src_rect);
// Pacmar
srcRect.y = param.game.item_size * (((counter + 6) / 36) % 2);
sprites[2]->setSpriteClip(srcRect);
src_rect.y = param.game.item_size * (((counter_ + 6) / 36) % 2);
sprites_[2]->setSpriteClip(src_rect);
// Time Stopper
srcRect.y = param.game.item_size * (((counter + 3) / 36) % 2);
sprites[3]->setSpriteClip(srcRect);
src_rect.y = param.game.item_size * (((counter_ + 3) / 36) % 2);
sprites_[3]->setSpriteClip(src_rect);
// Coffee
srcRect.y = param.game.item_size * (((counter + 0) / 36) % 2);
sprites[4]->setSpriteClip(srcRect);
src_rect.y = param.game.item_size * (((counter_ + 0) / 36) % 2);
sprites_[4]->setSpriteClip(src_rect);
}
// Rellena la textura de texto
void Instructions::fillTexture()
{
const int despX = param.game.item_size + 8;
const int desp_x = param.game.item_size + 8;
// Modifica el renderizador para pintar en la textura
SDL_Texture *temp = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, texture);
auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, texture_);
// Limpia la textura
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
SDL_RenderClear(renderer_);
// Constantes
const int numLines = 4;
const int numItemLines = 4;
const int numPostHeaders = 2;
const int numPreHeaders = 1;
constexpr int num_lines = 4;
constexpr int num_item_lines = 4;
constexpr int num_post_headers = 2;
constexpr int num_pre_headers = 1;
const int spacePostHeader = 20;
const int spacePreHeader = 28;
const int spaceBetweenLines = text->getCharacterSize() * 1.5f;
const int spaceBetweenItemLines = param.game.item_size + itemSpace;
const int spaceNewParagraph = spaceBetweenLines * 0.5f;
constexpr int space_post_header = 20;
constexpr int space_pre_header = 28;
const int space_between_lines = text_->getCharacterSize() * 1.5f;
const int space_between_item_lines = param.game.item_size + item_space_;
const int space_new_paragraph = space_between_lines * 0.5f;
const int size = (numLines * spaceBetweenLines) + (numItemLines * spaceBetweenItemLines) + (numPostHeaders * spacePostHeader) + (numPreHeaders * spacePreHeader) + (spaceNewParagraph);
const int firstLine = (param.game.height - size) / 2;
const int size = (num_lines * space_between_lines) + (num_item_lines * space_between_item_lines) + (num_post_headers * space_post_header) + (num_pre_headers * space_pre_header) + (space_new_paragraph);
const int first_line = (param.game.height - size) / 2;
// Calcula cual es el texto más largo de las descripciones de los items
int lenght = 0;
for (int i = 17; i <= 21; ++i)
{
const int l = text->lenght(lang::getText(i));
const int l = text_->lenght(lang::getText(i));
lenght = l > lenght ? l : lenght;
}
const int anchorItem = (param.game.width - (lenght + despX)) / 2;
const int anchor_item = (param.game.width - (lenght + desp_x)) / 2;
// Escribe el texto de las instrucciones
text->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, firstLine, lang::getText(11), 1, orange_color, 1, shdw_txt_color);
text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, first_line, lang::getText(11), 1, orange_color, 1, shdw_txt_color);
const int anchor1 = firstLine + spacePostHeader;
text->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + spaceBetweenLines * 0, lang::getText(12), 1, no_color, 1, shdw_txt_color);
text->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + spaceBetweenLines * 1, lang::getText(13), 1, no_color, 1, shdw_txt_color);
text->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + spaceNewParagraph + spaceBetweenLines * 2, lang::getText(14), 1, no_color, 1, shdw_txt_color);
text->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + spaceNewParagraph + spaceBetweenLines * 3, lang::getText(15), 1, no_color, 1, shdw_txt_color);
const int anchor1 = first_line + space_post_header;
text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_between_lines * 0, lang::getText(12), 1, no_color, 1, shdw_txt_color);
text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_between_lines * 1, lang::getText(13), 1, no_color, 1, shdw_txt_color);
text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_new_paragraph + space_between_lines * 2, lang::getText(14), 1, no_color, 1, shdw_txt_color);
text_->writeDX(TEXT_CENTER | TEXT_COLOR | TEXT_SHADOW, param.game.game_area.center_x, anchor1 + space_new_paragraph + space_between_lines * 3, lang::getText(15), 1, no_color, 1, shdw_txt_color);
// Escribe el texto de los objetos y sus puntos
const int anchor2 = anchor1 + spacePreHeader + spaceNewParagraph + spaceBetweenLines * 3;
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 anchor2 = anchor1 + space_pre_header + space_new_paragraph + space_between_lines * 3;
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 + spacePostHeader;
const int anchor3 = anchor2 + space_post_header;
// const int anchor4 = anchor3 + ((param.game.item_size + text->getCharacterSize()) / 2);
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 0, lang::getText(17), shdw_txt_color);
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 1, lang::getText(18), shdw_txt_color);
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 2, lang::getText(19), shdw_txt_color);
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 3, lang::getText(20), shdw_txt_color);
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 4, lang::getText(21), 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 * 2, lang::getText(19), shdw_txt_color);
text_->writeShadowed(anchor_item + desp_x, anchor3 + space_between_item_lines * 3, lang::getText(20), shdw_txt_color);
text_->writeShadowed(anchor_item + desp_x, anchor3 + space_between_item_lines * 4, lang::getText(21), shdw_txt_color);
// Deja el renderizador como estaba
SDL_SetRenderTarget(renderer, temp);
SDL_SetRenderTarget(renderer_, temp);
// Da valor a la variable
spritePos.x = anchorItem;
spritePos.y = anchor3 - ((param.game.item_size - text->getCharacterSize()) / 2);
sprite_pos_.x = anchor_item;
sprite_pos_.y = anchor3 - ((param.game.item_size - text_->getCharacterSize()) / 2);
}
// Rellena el backbuffer
void Instructions::fillBackbuffer()
{
// Modifica el renderizador para pintar en la textura
SDL_Texture *temp = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, backbuffer);
auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_);
// Limpia la textura
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
SDL_RenderClear(renderer_);
// Coloca el texto de fondo
SDL_RenderCopy(renderer, texture, nullptr, nullptr);
SDL_RenderCopy(renderer_, texture_, nullptr, nullptr);
// Dibuja los sprites
for (auto &sprite : sprites)
for (auto &sprite : sprites_)
{
sprite->render();
}
// Deja el renderizador como estaba
SDL_SetRenderTarget(renderer, temp);
SDL_SetRenderTarget(renderer_, temp);
}
// Actualiza las variables
void Instructions::update()
{
// Actualiza las variables
if (SDL_GetTicks() - ticks > ticksSpeed)
if (SDL_GetTicks() - ticks_ > ticks_speed_)
{
// Actualiza el contador de ticks
ticks = SDL_GetTicks();
ticks_ = SDL_GetTicks();
// Mantiene la música sonando
if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED))
JA_PlayMusic(music);
JA_PlayMusic(Resource::get()->getMusic("title.ogg"));
// Actualiza el objeto screen
Screen::get()->update();
// Incrementa el contador
counter++;
counter_++;
// Actualiza los sprites
updateSprites();
// Actualiza el mosaico de fondo
tiledbg->update();
tiled_bg_->update();
// Actualiza el objeto "fade"
fade->update();
fade_->update();
// Comprueba si el contador ha llegado al final
if (counter == counterEnd)
if (counter_ == counter_end_)
{
section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1;
@@ -270,15 +261,15 @@ void Instructions::render()
Screen::get()->clean(bg_color);
// Dibuja el mosacico de fondo
tiledbg->render();
tiled_bg_->render();
// Establece la ventana del backbuffer
view.y = std::max(0, param.game.height - counter + 100);
view_.y = std::max(0, param.game.height - counter_ + 100);
// Copia la textura y el backbuffer al renderizador
SDL_RenderCopy(renderer, backbuffer, nullptr, &view);
SDL_RenderCopy(renderer_, backbuffer_, nullptr, &view_);
fade->render();
fade_->render();
// Vuelca el contenido del renderizador en pantalla
Screen::get()->blit();
@@ -287,11 +278,11 @@ void Instructions::render()
// Recarga todas las texturas
void Instructions::reloadTextures()
{
for (auto &tex : itemTextures)
for (auto &texture : item_textures_)
{
tex->reLoad();
texture->reLoad();
}
text->reLoadTexture();
text_->reLoadTexture();
fillTexture();
}
@@ -299,19 +290,21 @@ void Instructions::reloadTextures()
void Instructions::checkEvents()
{
// Comprueba los eventos que hay en la cola
while (SDL_PollEvent(eventHandler.get()) != 0)
SDL_Event event;
while (SDL_PollEvent(&event))
{
// Evento de salida de la aplicación
if (eventHandler->type == SDL_QUIT)
if (event.type == SDL_QUIT)
{
section::name = section::Name::QUIT;
section::options = section::Options::QUIT_FROM_EVENT;
break;
}
// Comprueba si se ha cambiado el tamaño de la ventana
else if (eventHandler->type == SDL_WINDOWEVENT)
else if (event.type == SDL_WINDOWEVENT)
{
if (eventHandler->window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
reloadTextures();
}

View File

@@ -1,17 +1,16 @@
#pragma once
#include <SDL2/SDL_events.h> // for SDL_Event
#include <SDL2/SDL_rect.h> // for SDL_Point, SDL_Rect
#include <SDL2/SDL_render.h> // for SDL_Texture, SDL_Renderer
#include <SDL2/SDL_stdinc.h> // for Uint32
#include <memory> // for unique_ptr, shared_ptr
#include <vector> // for vector
#include <memory>
#include "fade.h"
#include "sprite.h"
#include "text.h"
#include "texture.h"
#include "tiled_bg.h"
struct JA_Music_t;
class Fade;
class Sprite;
class Text;
class Texture;
class TiledBG;
struct JA_Music_t; // lines 14-14
/*
Esta clase gestiona un estado del programa. Se encarga de poner en pantalla
@@ -31,26 +30,24 @@ class Instructions
{
private:
// Objetos y punteros
std::vector<std::shared_ptr<Texture>> itemTextures; // Vector con las texturas de los items
std::vector<std::unique_ptr<Sprite>> sprites; // Vector con los sprites de los items
std::unique_ptr<SDL_Event> eventHandler; // Manejador de eventos
std::unique_ptr<Text> text; // Objeto para escribir texto
std::unique_ptr<Tiledbg> tiledbg; // Objeto para dibujar el mosaico animado de fondo
std::unique_ptr<Fade> fade; // Objeto para renderizar fades
std::vector<std::shared_ptr<Texture>> item_textures_; // Vector con las texturas de los items
std::vector<std::unique_ptr<Sprite>> sprites_; // Vector con los sprites de los items
std::unique_ptr<Text> text_; // Objeto para escribir texto
std::unique_ptr<TiledBG> tiled_bg_; // Objeto para dibujar el mosaico animado de fondo
std::unique_ptr<Fade> fade_; // Objeto para renderizar fades
SDL_Renderer *renderer; // El renderizador de la ventana
JA_Music_t *music; // Musica de fondo
SDL_Texture *texture; // Textura fija con el texto
SDL_Texture *backbuffer; // Textura para usar como backbuffer
SDL_Renderer *renderer_; // El renderizador de la ventana
SDL_Texture *texture_; // Textura fija con el texto
SDL_Texture *backbuffer_; // Textura para usar como backbuffer
// Variables
int counter; // Contador
int counterEnd; // Valor final para el contador
Uint32 ticks; // Contador de ticks para ajustar la velocidad del programa
Uint32 ticksSpeed; // Velocidad a la que se repiten los bucles del programa
SDL_Rect view; // Vista del backbuffer que se va amostrar por pantalla
SDL_Point spritePos; // Posición del primer sprite
int itemSpace; // Espacio entre los items
int counter_; // Contador
int counter_end_; // Valor final para el contador
Uint32 ticks_; // Contador de ticks para ajustar la velocidad del programa
Uint32 ticks_speed_; // Velocidad a la que se repiten los bucles del programa
SDL_Rect view_; // Vista del backbuffer que se va amostrar por pantalla
SDL_Point sprite_pos_; // Posición del primer sprite
int item_space_; // Espacio entre los items
// Actualiza las variables
void update();
@@ -81,7 +78,7 @@ private:
public:
// Constructor
Instructions(JA_Music_t *music);
Instructions();
// Destructor
~Instructions();

View File

@@ -1,153 +1,150 @@
#include "intro.h"
#include <SDL2/SDL_render.h> // for SDL_Renderer
#include <SDL2/SDL_events.h> // for SDL_PollEvent, SDL_Event, SDL_QUIT, SDL...
#include <SDL2/SDL_timer.h> // for SDL_GetTicks
#include <SDL2/SDL_video.h> // for SDL_WINDOWEVENT_SIZE_CHANGED
#include <string> // for basic_string
#include <utility> // for move
#include "asset.h" // for Asset
#include "global_inputs.h" // for globalInputs::check
#include "global_inputs.h" // for check
#include "input.h" // for Input
#include "jail_audio.h" // for JA_StopMusic, JA_PlayMusic
#include "lang.h" // for getText
#include "param.h" // for param
#include "resource.h" // for Resource
#include "screen.h" // for Screen
#include "section.h" // for name, SectionName, options, SectionOptions
#include "smart_sprite.h" // for SmartSprite
#include "section.h" // for Name, name, Options, options
#include "smart_sprite.h" // for SpriteSmart
#include "text.h" // for Text
#include "texture.h" // for Texture
#include "utils.h" // for ParamGame, Param, Zone, BLOCK
#include "utils.h" // for Param, ParamGame, Zone, BLOCK, Color
#include "writer.h" // for Writer
struct JA_Music_t;
struct JA_Music_t; // lines 19-19
// Constructor
Intro::Intro(JA_Music_t *music)
: music(music)
Intro::Intro()
{
// Copia los punteros
auto renderer = Screen::get()->getRenderer();
// Reserva memoria para los objetos
texture = std::make_shared<Texture>(renderer, Asset::get()->get("intro.png"));
text = std::make_shared<Text>(Asset::get()->get("nokia.png"), Asset::get()->get("nokia.txt"), renderer);
texture_ = Resource::get()->getTexture("intro.png");
text_ = std::make_shared<Text>(Resource::get()->getTexture("nokia.png"), Resource::get()->getTextFile("nokia.txt"));
// Inicializa variables
section::name = section::Name::INTRO;
section::options = section::Options::NONE;
ticks = 0;
ticksSpeed = 15;
scene = 1;
ticks_ = 0;
ticks_speed_ = 15;
scene_ = 1;
// Inicializa los bitmaps de la intro
constexpr int totalBitmaps = 6;
for (int i = 0; i < totalBitmaps; ++i)
{
auto ss = std::make_unique<SmartSprite>(texture);
auto ss = std::make_unique<SmartSprite>(texture_);
ss->setWidth(128);
ss->setHeight(96);
ss->setFinishedCounter(20);
ss->setDestX(param.game.game_area.center_x - 64);
ss->setDestY(param.game.game_area.first_quarter_y - 24);
bitmaps.push_back(std::move(ss));
bitmaps_.push_back(std::move(ss));
}
bitmaps[0]->setPosX(-128);
bitmaps[0]->setPosY(param.game.game_area.first_quarter_y - 24);
bitmaps[0]->setVelX(0.0f);
bitmaps[0]->setVelY(0.0f);
bitmaps[0]->setAccelX(0.6f);
bitmaps[0]->setAccelY(0.0f);
bitmaps[0]->setSpriteClip(0, 0, 128, 96);
bitmaps_[0]->setPosX(-128);
bitmaps_[0]->setPosY(param.game.game_area.first_quarter_y - 24);
bitmaps_[0]->setVelX(0.0f);
bitmaps_[0]->setVelY(0.0f);
bitmaps_[0]->setAccelX(0.6f);
bitmaps_[0]->setAccelY(0.0f);
bitmaps_[0]->setSpriteClip(0, 0, 128, 96);
bitmaps[1]->setPosX(param.game.width);
bitmaps[1]->setPosY(param.game.game_area.first_quarter_y - 24);
bitmaps[1]->setVelX(-1.0f);
bitmaps[1]->setVelY(0.0f);
bitmaps[1]->setAccelX(-0.3f);
bitmaps[1]->setAccelY(0.0f);
bitmaps[1]->setSpriteClip(128, 0, 128, 96);
bitmaps_[1]->setPosX(param.game.width);
bitmaps_[1]->setPosY(param.game.game_area.first_quarter_y - 24);
bitmaps_[1]->setVelX(-1.0f);
bitmaps_[1]->setVelY(0.0f);
bitmaps_[1]->setAccelX(-0.3f);
bitmaps_[1]->setAccelY(0.0f);
bitmaps_[1]->setSpriteClip(128, 0, 128, 96);
bitmaps[2]->setPosX(param.game.game_area.center_x - 64);
bitmaps[2]->setPosY(-96);
bitmaps[2]->setVelX(0.0f);
bitmaps[2]->setVelY(3.0f);
bitmaps[2]->setAccelX(0.1f);
bitmaps[2]->setAccelY(0.3f);
bitmaps[2]->setSpriteClip(0, 96, 128, 96);
bitmaps[2]->setFinishedCounter(250);
bitmaps_[2]->setPosX(param.game.game_area.center_x - 64);
bitmaps_[2]->setPosY(-96);
bitmaps_[2]->setVelX(0.0f);
bitmaps_[2]->setVelY(3.0f);
bitmaps_[2]->setAccelX(0.1f);
bitmaps_[2]->setAccelY(0.3f);
bitmaps_[2]->setSpriteClip(0, 96, 128, 96);
bitmaps_[2]->setFinishedCounter(250);
bitmaps[3]->setPosX(param.game.game_area.center_x - 64);
bitmaps[3]->setPosY(param.game.height);
bitmaps[3]->setVelX(0.0f);
bitmaps[3]->setVelY(-0.7f);
bitmaps[3]->setAccelX(0.0f);
bitmaps[3]->setAccelY(0.0f);
bitmaps[3]->setSpriteClip(128, 96, 128, 96);
bitmaps_[3]->setPosX(param.game.game_area.center_x - 64);
bitmaps_[3]->setPosY(param.game.height);
bitmaps_[3]->setVelX(0.0f);
bitmaps_[3]->setVelY(-0.7f);
bitmaps_[3]->setAccelX(0.0f);
bitmaps_[3]->setAccelY(0.0f);
bitmaps_[3]->setSpriteClip(128, 96, 128, 96);
bitmaps[4]->setPosX(param.game.game_area.center_x - 64);
bitmaps[4]->setPosY(-96);
bitmaps[4]->setVelX(0.0f);
bitmaps[4]->setVelY(3.0f);
bitmaps[4]->setAccelX(0.1f);
bitmaps[4]->setAccelY(0.3f);
bitmaps[4]->setSpriteClip(0, 192, 128, 96);
bitmaps_[4]->setPosX(param.game.game_area.center_x - 64);
bitmaps_[4]->setPosY(-96);
bitmaps_[4]->setVelX(0.0f);
bitmaps_[4]->setVelY(3.0f);
bitmaps_[4]->setAccelX(0.1f);
bitmaps_[4]->setAccelY(0.3f);
bitmaps_[4]->setSpriteClip(0, 192, 128, 96);
bitmaps[5]->setPosX(param.game.width);
bitmaps[5]->setPosY(param.game.game_area.first_quarter_y - 24);
bitmaps[5]->setVelX(-0.7f);
bitmaps[5]->setVelY(0.0f);
bitmaps[5]->setAccelX(0.0f);
bitmaps[5]->setAccelY(0.0f);
bitmaps[5]->setSpriteClip(128, 192, 128, 96);
bitmaps_[5]->setPosX(param.game.width);
bitmaps_[5]->setPosY(param.game.game_area.first_quarter_y - 24);
bitmaps_[5]->setVelX(-0.7f);
bitmaps_[5]->setVelY(0.0f);
bitmaps_[5]->setAccelX(0.0f);
bitmaps_[5]->setAccelY(0.0f);
bitmaps_[5]->setSpriteClip(128, 192, 128, 96);
// Inicializa los textos de la intro
constexpr int totalTexts = 9;
for (int i = 0; i < totalTexts; ++i)
{
auto w = std::make_unique<Writer>(text);
auto w = std::make_unique<Writer>(text_);
w->setPosX(BLOCK * 0);
w->setPosY(param.game.height - (BLOCK * 6));
w->setKerning(-1);
w->setEnabled(false);
w->setFinishedCounter(180);
texts.push_back(std::move(w));
texts_.push_back(std::move(w));
}
// Un dia qualsevol de l'any 2000
texts[0]->setCaption(lang::getText(27));
texts[0]->setSpeed(8);
texts_[0]->setCaption(lang::getText(27));
texts_[0]->setSpeed(8);
// Tot esta tranquil a la UPV
texts[1]->setCaption(lang::getText(28));
texts[1]->setSpeed(8);
texts_[1]->setCaption(lang::getText(28));
texts_[1]->setSpeed(8);
// Fins que un desaprensiu...
texts[2]->setCaption(lang::getText(29));
texts[2]->setSpeed(12);
texts_[2]->setCaption(lang::getText(29));
texts_[2]->setSpeed(12);
// HEY! ME ANE A FERME UN CORTAET...
texts[3]->setCaption(lang::getText(30));
texts[3]->setSpeed(8);
texts_[3]->setCaption(lang::getText(30));
texts_[3]->setSpeed(8);
// UAAAAAAAAAAAAA!!!
texts[4]->setCaption(lang::getText(31));
texts[4]->setSpeed(1);
texts_[4]->setCaption(lang::getText(31));
texts_[4]->setSpeed(1);
// Espera un moment...
texts[5]->setCaption(lang::getText(32));
texts[5]->setSpeed(16);
texts_[5]->setCaption(lang::getText(32));
texts_[5]->setSpeed(16);
// Si resulta que no tinc solt!
texts[6]->setCaption(lang::getText(33));
texts[6]->setSpeed(2);
texts_[6]->setCaption(lang::getText(33));
texts_[6]->setSpeed(2);
// MERDA DE MAQUINA!
texts[7]->setCaption(lang::getText(34));
texts[7]->setSpeed(3);
texts_[7]->setCaption(lang::getText(34));
texts_[7]->setSpeed(3);
// Blop... blop... blop...
texts[8]->setCaption(lang::getText(35));
texts[8]->setSpeed(16);
texts_[8]->setCaption(lang::getText(35));
texts_[8]->setSpeed(16);
for (auto &text : texts)
for (auto &text : texts_)
{
text->center(param.game.game_area.center_x);
}
@@ -156,8 +153,8 @@ Intro::Intro(JA_Music_t *music)
// Recarga todas las texturas
void Intro::reloadTextures()
{
texture->reLoad();
text->reLoadTexture();
texture_->reLoad();
text_->reLoadTexture();
}
// Comprueba los eventos
@@ -173,6 +170,7 @@ void Intro::checkEvents()
case SDL_QUIT:
{
section::name = section::Name::QUIT;
section::options = section::Options::QUIT_FROM_EVENT;
break;
}
@@ -213,153 +211,158 @@ void Intro::checkInput()
// Actualiza las escenas de la intro
void Intro::updateScenes()
{
switch (scene)
switch (scene_)
{
case 1:
// Primera imagen - UPV
if (!bitmaps[0]->hasFinished())
{ // Primera imagen - UPV
if (!bitmaps_[0]->hasFinished())
{
bitmaps[0]->setEnabled(true);
bitmaps_[0]->setEnabled(true);
}
// Primer texto de la primera imagen
if (bitmaps[0]->hasFinished() && !texts[0]->hasFinished())
if (bitmaps_[0]->hasFinished() && !texts_[0]->hasFinished())
{
texts[0]->setEnabled(true);
texts_[0]->setEnabled(true);
}
// Segundo texto de la primera imagen
if (texts[0]->hasFinished() && !texts[1]->hasFinished())
if (texts_[0]->hasFinished() && !texts_[1]->hasFinished())
{
texts[0]->setEnabled(false);
texts[1]->setEnabled(true);
texts_[0]->setEnabled(false);
texts_[1]->setEnabled(true);
}
// Tercer texto de la primera imagen
if (texts[1]->hasFinished() && !texts[2]->hasFinished())
if (texts_[1]->hasFinished() && !texts_[2]->hasFinished())
{
texts[1]->setEnabled(false);
texts[2]->setEnabled(true);
texts_[1]->setEnabled(false);
texts_[2]->setEnabled(true);
}
// Fin de la primera escena
if (texts[2]->hasFinished())
if (texts_[2]->hasFinished())
{
bitmaps[0]->setEnabled(false);
texts[2]->setEnabled(false);
scene++;
bitmaps_[0]->setEnabled(false);
texts_[2]->setEnabled(false);
scene_++;
}
break;
}
case 2:
// Segunda imagen - Máquina
if (!bitmaps[1]->hasFinished())
{ // Segunda imagen - Máquina
if (!bitmaps_[1]->hasFinished())
{
bitmaps[1]->setEnabled(true);
bitmaps_[1]->setEnabled(true);
}
// Primer texto de la segunda imagen
if (bitmaps[1]->hasFinished() && !texts[3]->hasFinished())
if (bitmaps_[1]->hasFinished() && !texts_[3]->hasFinished())
{
texts[3]->setEnabled(true);
texts_[3]->setEnabled(true);
}
// Fin de la segunda escena
if (texts[3]->hasFinished())
if (texts_[3]->hasFinished())
{
bitmaps[1]->setEnabled(false);
texts[3]->setEnabled(false);
scene++;
bitmaps_[1]->setEnabled(false);
texts_[3]->setEnabled(false);
scene_++;
}
break;
}
case 3:
// Tercera imagen junto con primer texto - GRITO
if (!bitmaps[2]->hasFinished() && !texts[4]->hasFinished())
{ // Tercera imagen junto con primer texto - GRITO
if (!bitmaps_[2]->hasFinished() && !texts_[4]->hasFinished())
{
bitmaps[2]->setEnabled(true);
texts[4]->setEnabled(true);
bitmaps_[2]->setEnabled(true);
texts_[4]->setEnabled(true);
}
// Fin de la tercera escena
if (bitmaps[2]->hasFinished() && texts[4]->hasFinished())
if (bitmaps_[2]->hasFinished() && texts_[4]->hasFinished())
{
bitmaps[2]->setEnabled(false);
texts[4]->setEnabled(false);
scene++;
bitmaps_[2]->setEnabled(false);
texts_[4]->setEnabled(false);
scene_++;
}
break;
}
case 4:
// Cuarta imagen junto con primer texto - Reflexión
if (!bitmaps[3]->hasFinished() && !texts[5]->hasFinished())
{ // Cuarta imagen junto con primer texto - Reflexión
if (!bitmaps_[3]->hasFinished() && !texts_[5]->hasFinished())
{
bitmaps[3]->setEnabled(true);
texts[5]->setEnabled(true);
bitmaps_[3]->setEnabled(true);
texts_[5]->setEnabled(true);
}
// Segundo texto de la cuarta imagen
if (texts[5]->hasFinished() && !texts[6]->hasFinished())
if (texts_[5]->hasFinished() && !texts_[6]->hasFinished())
{
texts[5]->setEnabled(false);
texts[6]->setEnabled(true);
texts_[5]->setEnabled(false);
texts_[6]->setEnabled(true);
}
// Fin de la cuarta escena
if (bitmaps[3]->hasFinished() && texts[6]->hasFinished())
if (bitmaps_[3]->hasFinished() && texts_[6]->hasFinished())
{
bitmaps[3]->setEnabled(false);
texts[6]->setEnabled(false);
scene++;
bitmaps_[3]->setEnabled(false);
texts_[6]->setEnabled(false);
scene_++;
}
break;
}
case 5:
// Quinta imagen - Patada
if (!bitmaps[4]->hasFinished())
{ // Quinta imagen - Patada
if (!bitmaps_[4]->hasFinished())
{
bitmaps[4]->setEnabled(true);
bitmaps_[4]->setEnabled(true);
}
// Primer texto de la quinta imagen
if (bitmaps[4]->hasFinished() && !texts[7]->hasFinished())
if (bitmaps_[4]->hasFinished() && !texts_[7]->hasFinished())
{
texts[7]->setEnabled(true);
texts_[7]->setEnabled(true);
}
// Fin de la quinta escena
if (bitmaps[4]->hasFinished() && texts[7]->hasFinished())
if (bitmaps_[4]->hasFinished() && texts_[7]->hasFinished())
{
bitmaps[4]->setEnabled(false);
texts[7]->setEnabled(false);
scene++;
bitmaps_[4]->setEnabled(false);
texts_[7]->setEnabled(false);
scene_++;
}
break;
}
case 6:
// Sexta imagen junto con texto - Globos de café
if (!bitmaps[5]->hasFinished() && !texts[8]->hasFinished())
{ // Sexta imagen junto con texto - Globos de café
if (!bitmaps_[5]->hasFinished() && !texts_[8]->hasFinished())
{
bitmaps[5]->setEnabled(true);
texts[8]->setEnabled(true);
bitmaps_[5]->setEnabled(true);
texts_[8]->setEnabled(true);
}
// Acaba el último texto
if (bitmaps[5]->hasFinished() && texts[8]->hasFinished())
if (bitmaps_[5]->hasFinished() && texts_[8]->hasFinished())
{
bitmaps[5]->setEnabled(false);
texts[8]->setEnabled(false);
bitmaps_[5]->setEnabled(false);
texts_[8]->setEnabled(false);
JA_StopMusic();
section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1;
}
break;
}
default:
break;
@@ -369,21 +372,21 @@ void Intro::updateScenes()
// Actualiza las variables del objeto
void Intro::update()
{
if (SDL_GetTicks() - ticks > ticksSpeed)
if (SDL_GetTicks() - ticks_ > ticks_speed_)
{
// Actualiza el contador de ticks
ticks = SDL_GetTicks();
ticks_ = SDL_GetTicks();
// Actualiza el objeto screen
Screen::get()->update();
// Actualiza los objetos
for (auto &bitmap : bitmaps)
for (auto &bitmap : bitmaps_)
{
bitmap->update();
}
for (auto &text : texts)
for (auto &text : texts_)
{
text->update();
}
@@ -403,12 +406,12 @@ void Intro::render()
Screen::get()->clean(bg_color);
// Dibuja los objetos
for (auto &bitmap : bitmaps)
for (const auto &bitmap : bitmaps_)
{
bitmap->render();
}
for (auto &text : texts)
for (const auto &text : texts_)
{
text->render();
}
@@ -420,7 +423,7 @@ void Intro::render()
// Bucle principal
void Intro::run()
{
JA_PlayMusic(music, 0);
JA_PlayMusic(Resource::get()->getMusic("intro.ogg"), 0);
while (section::name == section::Name::INTRO)
{

View File

@@ -1,14 +1,13 @@
#pragma once
#include <SDL2/SDL_events.h> // for SDL_Event
#include <SDL2/SDL_stdinc.h> // for Uint32, Uint8
#include <memory> // for unique_ptr, shared_ptr
#include <vector> // for vector
#include <memory>
#include "smart_sprite.h"
#include "texture.h"
#include "text.h"
#include "writer.h"
struct JA_Music_t;
#include "smart_sprite.h" // for SpriteSmart
#include "writer.h" // for Writer
class Text;
class Texture;
struct JA_Music_t; // lines 11-11
/*
Esta clase gestiona un estado del programa. Se encarga de mostrar la secuencia
@@ -20,17 +19,16 @@ class Intro
{
private:
// Objetos
std::shared_ptr<Texture> texture; // Textura con los graficos
std::shared_ptr<Text> text; // Textos de la intro
std::shared_ptr<Texture> texture_; // Textura con los graficos
std::shared_ptr<Text> text_; // Textos de la intro
std::vector<std::unique_ptr<SmartSprite>> bitmaps; // Vector con los sprites inteligentes para los dibujos de la intro
std::vector<std::unique_ptr<Writer>> texts; // Textos de la intro
std::vector<std::unique_ptr<SmartSprite>> bitmaps_; // Vector con los sprites inteligentes para los dibujos de la intro
std::vector<std::unique_ptr<Writer>> texts_; // Textos de la intro
// Variables
Uint32 ticks; // Contador de ticks para ajustar la velocidad del programa
Uint8 ticksSpeed; // Velocidad a la que se repiten los bucles del programa
JA_Music_t *music; // Musica para la intro
int scene; // Indica que escena está activa
Uint32 ticks_; // Contador de ticks para ajustar la velocidad del programa
Uint8 ticks_speed_; // Velocidad a la que se repiten los bucles del programa
int scene_; // Indica que escena está activa
// Actualiza las variables del objeto
void update();
@@ -52,7 +50,7 @@ private:
public:
// Constructor
Intro(JA_Music_t *music);
Intro();
// Destructor
~Intro() = default;

View File

@@ -1,65 +1,64 @@
#include "item.h"
#include <stdlib.h> // for rand
#include "animated_sprite.h" // for AnimatedSprite
#include "animated_sprite.h" // for SpriteAnimated
#include "param.h" // for param
class Texture;
// Constructor
Item::Item(int kind, float x, float y, SDL_Rect *playArea, std::shared_ptr<Texture> texture, std::vector<std::string> *animation)
: kind(kind), playArea(playArea)
Item::Item(ItemType type, float x, float y, SDL_Rect *play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation)
: sprite_(std::make_unique<AnimatedSprite>(texture, animation)),
accel_x_(0.0f),
floor_collision_(false),
type_(type),
enabled_(true),
play_area_(play_area),
time_to_live_(600)
{
sprite = std::make_unique<AnimatedSprite>(texture, "", animation);
enabled = true;
timeToLive = 600;
accelX = 0.0f;
floorCollision = false;
if (kind == ITEM_COFFEE_MACHINE)
if (type == ItemType::COFFEE_MACHINE)
{
width = 28;
height = 37;
posX = (((int)x + (playArea->w / 2)) % (playArea->w - width - 5)) + 2;
posY = -height;
velX = 0.0f;
velY = -0.1f;
accelY = 0.1f;
collider.r = 10;
width_ = 28;
height_ = 37;
pos_x_ = (((int)x + (play_area->w / 2)) % (play_area->w - width_ - 5)) + 2;
pos_y_ = -height_;
vel_x_ = 0.0f;
vel_y_ = -0.1f;
accel_y_ = 0.1f;
collider_.r = 10;
}
else
{
width = 20;
height = 20;
posX = x;
posY = y;
velX = -1.0f + ((rand() % 5) * 0.5f);
velY = -4.0f;
accelY = 0.2f;
collider.r = width / 2;
width_ = 20;
height_ = 20;
pos_x_ = x;
pos_y_ = y;
vel_x_ = -1.0f + ((rand() % 5) * 0.5f);
vel_y_ = -4.0f;
accel_y_ = 0.2f;
collider_.r = width_ / 2;
}
sprite->setPosX(posX);
sprite->setPosY(posY);
sprite_->setPosX(pos_x_);
sprite_->setPosY(pos_y_);
shiftColliders();
}
// Centra el objeto en la posición X
void Item::allignTo(int x)
{
posX = float(x - (width / 2));
pos_x_ = float(x - (width_ / 2));
if (posX < param.game.play_area.rect.x)
if (pos_x_ < param.game.play_area.rect.x)
{
posX = param.game.play_area.rect.x + 1;
pos_x_ = param.game.play_area.rect.x + 1;
}
else if ((posX + width) > playArea->w)
else if ((pos_x_ + width_) > play_area_->w)
{
posX = float(playArea->w - width - 1);
pos_x_ = float(play_area_->w - width_ - 1);
}
// Posición X,Y del sprite
sprite->setPosX(int(posX));
sprite->setPosY(int(posY));
sprite_->setPosX(int(pos_x_));
sprite_->setPosY(int(pos_y_));
// Alinea el circulo de colisión con el objeto
shiftColliders();
@@ -68,15 +67,15 @@ void Item::allignTo(int x)
// Pinta el objeto en la pantalla
void Item::render()
{
if (enabled)
if (enabled_)
{
if (timeToLive > 200)
if (time_to_live_ > 200)
{
sprite->render();
sprite_->render();
}
else if (timeToLive % 20 > 10)
else if (time_to_live_ % 20 > 10)
{
sprite->render();
sprite_->render();
}
}
}
@@ -84,68 +83,68 @@ void Item::render()
// Actualiza la posición y estados del objeto
void Item::move()
{
floorCollision = false;
floor_collision_ = false;
// Calcula la nueva posición
posX += velX;
posY += velY;
pos_x_ += vel_x_;
pos_y_ += vel_y_;
// Aplica las aceleraciones a la velocidad
velX += accelX;
velY += accelY;
vel_x_ += accel_x_;
vel_y_ += accel_y_;
// Si queda fuera de pantalla, corregimos su posición y cambiamos su sentido
if ((posX < param.game.play_area.rect.x) || (posX + width > playArea->w))
if ((pos_x_ < param.game.play_area.rect.x) || (pos_x_ + width_ > play_area_->w))
{
// Corregir posición
posX -= velX;
pos_x_ -= vel_x_;
// Invertir sentido
velX = -velX;
vel_x_ = -vel_x_;
}
// Si se sale por arriba rebota (excepto la maquina de café)
if ((posY < param.game.play_area.rect.y) && !(kind == ITEM_COFFEE_MACHINE))
if ((pos_y_ < param.game.play_area.rect.y) && !(type_ == ItemType::COFFEE_MACHINE))
{
// Corrige
posY = param.game.play_area.rect.y;
pos_y_ = param.game.play_area.rect.y;
// Invierte el sentido
velY = -velY;
vel_y_ = -vel_y_;
}
// Si el objeto se sale por la parte inferior
if (posY + height > playArea->h)
if (pos_y_ + height_ > play_area_->h)
{
// Detiene el objeto
velY = 0;
velX = 0;
accelX = 0;
accelY = 0;
posY = playArea->h - height;
if (kind == ITEM_COFFEE_MACHINE)
vel_y_ = 0;
vel_x_ = 0;
accel_x_ = 0;
accel_y_ = 0;
pos_y_ = play_area_->h - height_;
if (type_ == ItemType::COFFEE_MACHINE)
{
floorCollision = true;
floor_collision_ = true;
}
}
// Actualiza la posición del sprite
sprite->setPosX(int(posX));
sprite->setPosY(int(posY));
sprite_->setPosX(int(pos_x_));
sprite_->setPosY(int(pos_y_));
shiftColliders();
}
// Pone a cero todos los valores del objeto
void Item::disable()
{
enabled = false;
enabled_ = false;
}
// Actualiza el objeto a su posicion, animación y controla los contadores
void Item::update()
{
move();
sprite->animate();
sprite_->update();
updateTimeToLive();
checkTimeToLive();
}
@@ -153,70 +152,70 @@ void Item::update()
// Actualiza el contador
void Item::updateTimeToLive()
{
if (timeToLive > 0)
if (time_to_live_ > 0)
{
timeToLive--;
time_to_live_--;
}
}
// Comprueba si el objeto sigue vivo
void Item::checkTimeToLive()
{
if (timeToLive == 0)
if (time_to_live_ == 0)
disable();
}
// Obtiene del valor de la variable
float Item::getPosX()
{
return posX;
return pos_x_;
}
// Obtiene del valor de la variable
float Item::getPosY()
{
return posY;
return pos_y_;
}
// Obtiene del valor de la variable
int Item::getWidth()
{
return width;
return width_;
}
// Obtiene del valor de la variable
int Item::getHeight()
{
return height;
return height_;
}
// Obtiene del valor de la variable
int Item::getClass()
ItemType Item::getType()
{
return kind;
return type_;
}
// Obtiene el valor de la variable
bool Item::isEnabled()
{
return enabled;
return enabled_;
}
// Obtiene el circulo de colisión
Circle &Item::getCollider()
{
return collider;
return collider_;
}
// Alinea el circulo de colisión con la posición del objeto
void Item::shiftColliders()
{
collider.x = int(posX + (width / 2));
collider.y = int(posY + (height / 2));
collider_.x = int(pos_x_ + (width_ / 2));
collider_.y = int(pos_y_ + (height_ / 2));
}
// Informa si el objeto ha colisionado con el suelo
bool Item::isOnFloor()
{
return floorCollision;
return floor_collision_;
}

View File

@@ -2,43 +2,47 @@
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_stdinc.h> // for Uint16
#include <memory> // for shared_ptr, unique_ptr
#include <string> // for string
#include <vector> // for vector
#include <memory>
#include "utils.h" // for Circle
#include "animated_sprite.h"
#include "texture.h"
#include "animated_sprite.h" // for SpriteAnimated
#include "utils.h" // for Circle
class Texture;
// Tipos de objetos
#define ITEM_POINTS_1_DISK 1
#define ITEM_POINTS_2_GAVINA 2
#define ITEM_POINTS_3_PACMAR 3
#define ITEM_CLOCK 4
#define ITEM_COFFEE 5
#define ITEM_COFFEE_MACHINE 6
#define ITEM_NULL 7
enum class ItemType : int
{
DISK = 1,
GAVINA = 2,
PACMAR = 3,
CLOCK = 4,
COFFEE = 5,
COFFEE_MACHINE = 6,
NONE = 7,
};
// Clase Item
class Item
{
private:
// Objetos y punteros
std::unique_ptr<AnimatedSprite> sprite; // Sprite con los graficos del objeto
std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los graficos del objeto
// Variables
float posX; // Posición X del objeto
float posY; // Posición Y del objeto
int width; // Ancho del objeto
int height; // Alto del objeto
float velX; // Velocidad en el eje X
float velY; // Velocidad en el eje Y
float accelX; // Aceleración en el eje X
float accelY; // Aceleración en el eje Y
bool floorCollision; // Indica si el objeto colisiona con el suelo
int kind; // Especifica el tipo de objeto que es
bool enabled; // Especifica si el objeto está habilitado
Circle collider; // Circulo de colisión del objeto
SDL_Rect *playArea; // Rectangulo con la zona de juego
float pos_x_; // Posición X del objeto
float pos_y_; // Posición Y del objeto
int width_; // Ancho del objeto
int height_; // Alto del objeto
float vel_x_; // Velocidad en el eje X
float vel_y_; // Velocidad en el eje Y
float accel_x_; // Aceleración en el eje X
float accel_y_; // Aceleración en el eje Y
bool floor_collision_; // Indica si el objeto colisiona con el suelo
ItemType type_; // Especifica el tipo de objeto que es
bool enabled_; // Especifica si el objeto está habilitado
Circle collider_; // Circulo de colisión del objeto
SDL_Rect *play_area_; // Rectangulo con la zona de juego
Uint16 time_to_live_; // Temporizador con el tiempo que el objeto está presente
// Alinea el circulo de colisión con la posición del objeto
void shiftColliders();
@@ -46,11 +50,15 @@ private:
// Actualiza la posición y estados del objeto
void move();
public:
Uint16 timeToLive; // Temporizador con el tiempo que el objeto está presente
// Actualiza el contador
void updateTimeToLive();
// Comprueba si el objeto sigue vivo
void checkTimeToLive();
public:
// Constructor
Item(int kind, float x, float y, SDL_Rect *playArea, std::shared_ptr<Texture> texture, std::vector<std::string> *animation);
Item(ItemType type, float x, float y, SDL_Rect *play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation);
// Destructor
~Item() = default;
@@ -67,12 +75,6 @@ public:
// Actualiza al objeto a su posicion, animación y controla los contadores
void update();
// Actualiza el contador
void updateTimeToLive();
// Comprueba si el objeto sigue vivo
void checkTimeToLive();
// Obtiene del valor de la variable
float getPosX();
@@ -86,7 +88,7 @@ public:
int getHeight();
// Obtiene del valor de la variable
int getClass();
ItemType getType();
// Obtiene el valor de la variable
bool isEnabled();

View File

@@ -129,7 +129,7 @@ JA_Music_t *JA_LoadMusic(const char* filename) {
void JA_PlayMusic(JA_Music_t *music, const int loop)
{
if (!JA_musicEnabled) return;
if (!JA_musicEnabled || !music) return;
if (current_music != NULL) {
current_music->pos = 0;
@@ -223,7 +223,7 @@ JA_Sound_t *JA_LoadSound(const char* filename) {
int JA_PlaySound(JA_Sound_t *sound, const int loop)
{
if (!JA_soundEnabled) return 0;
if (!JA_soundEnabled || !sound) return 0;
int channel = 0;
while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; }

View File

@@ -1,166 +0,0 @@
#ifdef JA_USESDLMIXER
#include "jail_audio.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_mixer.h>
#include <stdio.h>
struct JA_Sound_t {}; // Dummy structs
struct JA_Music_t {};
int JA_freq {48000};
SDL_AudioFormat JA_format {AUDIO_S16};
Uint8 JA_channels {2};
int JA_musicVolume = 128;
int JA_soundVolume = 64;
bool JA_musicEnabled = true;
bool JA_soundEnabled = true;
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels) {
JA_freq = freq;
JA_format = format;
JA_channels = channels;
Mix_OpenAudio(JA_freq, JA_format, JA_channels, 1024);
}
void JA_Quit() {
Mix_CloseAudio();
}
JA_Music_t *JA_LoadMusic(const char* filename) {
return (JA_Music_t*)Mix_LoadMUS(filename);
}
void JA_PlayMusic(JA_Music_t *music, const int loop)
{
if (!JA_musicEnabled) return;
Mix_PlayMusic((Mix_Music*)music, loop);
Mix_VolumeMusic(JA_musicVolume);
}
void JA_PauseMusic()
{
if (!JA_musicEnabled) return;
Mix_PauseMusic();
}
void JA_ResumeMusic()
{
if (!JA_musicEnabled) return;
Mix_ResumeMusic();
}
void JA_StopMusic()
{
if (!JA_musicEnabled) return;
Mix_HaltMusic();
}
JA_Music_state JA_GetMusicState()
{
if (!JA_musicEnabled) return JA_MUSIC_DISABLED;
if (Mix_PausedMusic()) {
return JA_MUSIC_PAUSED;
} else if (Mix_PlayingMusic()) {
return JA_MUSIC_PLAYING;
} else {
return JA_MUSIC_STOPPED;
}
}
void JA_DeleteMusic(JA_Music_t *music)
{
Mix_FreeMusic((Mix_Music*)music);
}
int JA_SetMusicVolume(int volume)
{
JA_musicVolume = volume;
Mix_VolumeMusic(JA_musicVolume);
return JA_musicVolume;
}
void JA_EnableMusic(const bool value)
{
if (Mix_PlayingMusic()) Mix_HaltMusic();
JA_musicEnabled = value;
}
JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length)
{
return NULL;
}
JA_Sound_t *JA_LoadSound(const char* filename) {
JA_Sound_t *sound = (JA_Sound_t*)Mix_LoadWAV(filename);
return sound;
}
int JA_PlaySound(JA_Sound_t *sound, const int loop) {
if (!JA_soundEnabled) return -1;
const int channel = Mix_PlayChannel(-1, (Mix_Chunk*)sound, loop);
Mix_Volume(-1, JA_soundVolume);
return channel;
}
void JA_DeleteSound(JA_Sound_t *sound)
{
Mix_FreeChunk((Mix_Chunk*)sound);
}
void JA_PauseChannel(const int channel)
{
if (!JA_soundEnabled) return;
Mix_Pause(channel);
}
void JA_ResumeChannel(const int channel)
{
if (!JA_soundEnabled) return;
Mix_Resume(channel);
}
void JA_StopChannel(const int channel)
{
if (!JA_soundEnabled) return;
Mix_HaltChannel(channel);
}
JA_Channel_state JA_GetChannelState(const int channel)
{
if (!JA_soundEnabled) return JA_SOUND_DISABLED;
if (Mix_Paused(channel)) {
return JA_CHANNEL_PAUSED;
} else if (Mix_Playing(channel)) {
return JA_CHANNEL_PLAYING;
} else {
return JA_CHANNEL_FREE;
}
}
int JA_SetSoundVolume(int volume)
{
JA_musicVolume = volume;
Mix_Volume(-1, JA_musicVolume);
return JA_musicVolume;
}
void JA_EnableSound(const bool value)
{
Mix_HaltChannel(-1);
JA_soundEnabled = value;
}
int JA_SetVolume(int volume)
{
JA_SetSoundVolume(volume);
return JA_SetMusicVolume(volume);
}
#endif

View File

@@ -7,13 +7,13 @@ namespace lang
std::vector<std::string> texts; // Vector con los textos
// Inicializa los textos del juego en el idioma seleccionado
bool loadFromFile(std::string filePath)
bool loadFromFile(std::string file_path)
{
texts.clear();
bool success = false;
std::ifstream rfile(filePath);
std::ifstream rfile(file_path);
if (rfile.is_open() && rfile.good())
{
success = true;

View File

@@ -4,7 +4,7 @@
namespace lang
{
enum lang_e
enum class Code : int
{
es_ES = 0,
ba_BA = 1,
@@ -12,7 +12,7 @@ namespace lang
};
// Inicializa los textos del juego en el idioma seleccionado
bool loadFromFile(std::string filePath);
bool loadFromFile(std::string file_path);
// Obtiene la cadena de texto del indice
std::string getText(int index);

View File

@@ -1,73 +1,65 @@
#include "logo.h"
#include <SDL2/SDL_events.h> // for SDL_PollEvent, SDL_Event, SDL_QUIT, SDL...
#include <SDL2/SDL_render.h> // for SDL_Renderer
#include <SDL2/SDL_timer.h> // for SDL_GetTicks
#include <SDL2/SDL_video.h> // for SDL_WINDOWEVENT_SIZE_CHANGED
#include <string> // for basic_string
#include <utility> // for move
#include "asset.h" // for Asset
#include "global_inputs.h" // for globalInputs::check
#include "global_inputs.h" // for check
#include "input.h" // for Input
#include "jail_audio.h" // for JA_StopMusic
#include "param.h" // for param
#include "resource.h" // for Resource
#include "screen.h" // for Screen
#include "section.h" // for name, SectionName, options, SectionOptions
#include "section.h" // for Name, name, Options, options
#include "sprite.h" // for Sprite
#include "texture.h" // for Texture
// Constructor
Logo::Logo()
: since_texture_(Resource::get()->getTexture("logo_since_1998.png")),
since_sprite_(std::make_unique<Sprite>(since_texture_)),
jail_texture_(Resource::get()->getTexture("logo_jailgames.png"))
{
// Copia la dirección de los objetos
SDL_Renderer *renderer = Screen::get()->getRenderer();
// Reserva memoria para los punteros
jailTexture = std::make_shared<Texture>(renderer, Asset::get()->get("logo_jailgames.png"));
sinceTexture = std::make_shared<Texture>(renderer, Asset::get()->get("logo_since_1998.png"));
sinceSprite = std::make_unique<Sprite>((param.game.width - sinceTexture->getWidth()) / 2, 83 + jailTexture->getHeight() + 5, sinceTexture->getWidth(), sinceTexture->getHeight(), sinceTexture);
// Inicializa variables
counter = 0;
counter_ = 0;
section::name = section::Name::LOGO;
ticks = 0;
ticksSpeed = 15;
showSinceSprite_cm = 70;
initFade_cm = 300;
endLogo_cm = 400;
postLogoDuration = 20;
speed = 8;
dest.x = param.game.game_area.center_x - jailTexture->getWidth() / 2;
dest.y = param.game.game_area.center_y - jailTexture->getHeight() / 2;
sinceSprite->setPosY(dest.y + jailTexture->getHeight() + 5);
sinceSprite->setSpriteClip(0, 0, sinceTexture->getWidth(), sinceTexture->getHeight());
sinceSprite->setEnabled(false);
sinceTexture->setColor(0x00, 0x00, 0x00); // Esto en linux no hace nada ??
ticks_ = 0;
dest_.x = param.game.game_area.center_x - jail_texture_->getWidth() / 2;
dest_.y = param.game.game_area.center_y - jail_texture_->getHeight() / 2;
since_sprite_->setPosition({(param.game.width - since_texture_->getWidth()) / 2, 83 + jail_texture_->getHeight() + 5, since_texture_->getWidth(), since_texture_->getHeight()});
since_sprite_->setY(dest_.y + jail_texture_->getHeight() + 5);
since_sprite_->setSpriteClip(0, 0, since_texture_->getWidth(), since_texture_->getHeight());
since_texture_->setColor(0x00, 0x00, 0x00); // Esto en linux no hace nada ??
// Crea los sprites de cada linea
for (int i = 0; i < jailTexture->getHeight(); ++i)
for (int i = 0; i < jail_texture_->getHeight(); ++i)
{
auto temp = std::make_unique<Sprite>(0, i, jailTexture->getWidth(), 1, jailTexture);
temp->setSpriteClip(0, i, jailTexture->getWidth(), 1);
const int posX = (i % 2 == 0) ? param.game.width + (i * 3) : -jailTexture->getWidth() - (i * 3);
temp->setPosX(posX);
temp->setPosY(dest.y + i);
jailSprite.push_back(std::move(temp));
auto temp = std::make_unique<Sprite>(jail_texture_, 0, i, jail_texture_->getWidth(), 1);
temp->setSpriteClip(0, i, jail_texture_->getWidth(), 1);
const int posX = (i % 2 == 0) ? param.game.width + (i * 3) : -jail_texture_->getWidth() - (i * 3);
temp->setX(posX);
temp->setY(dest_.y + i);
jail_sprite_.push_back(std::move(temp));
}
// Inicializa el vector de colores
color.push_back({0x00, 0x00, 0x00}); // Black
color.push_back({0x00, 0x00, 0xd8}); // Blue
color.push_back({0xd8, 0x00, 0x00}); // Red
color.push_back({0xd8, 0x00, 0xd8}); // Magenta
color.push_back({0x00, 0xd8, 0x00}); // Green
color.push_back({0x00, 0xd8, 0xd8}); // Cyan
color.push_back({0xd8, 0xd8, 0x00}); // Yellow
color.push_back({0xFF, 0xFF, 0xFF}); // Bright white
color_.push_back({0x00, 0x00, 0x00}); // Black
color_.push_back({0x00, 0x00, 0xd8}); // Blue
color_.push_back({0xd8, 0x00, 0x00}); // Red
color_.push_back({0xd8, 0x00, 0xd8}); // Magenta
color_.push_back({0x00, 0xd8, 0x00}); // Green
color_.push_back({0x00, 0xd8, 0xd8}); // Cyan
color_.push_back({0xd8, 0xd8, 0x00}); // Yellow
color_.push_back({0xFF, 0xFF, 0xFF}); // Bright white
}
// Recarga todas las texturas
void Logo::reloadTextures()
{
jailTexture->reLoad();
sinceTexture->reLoad();
jail_texture_->reLoad();
since_texture_->reLoad();
}
// Comprueba el manejador de eventos
@@ -81,6 +73,7 @@ void Logo::checkEvents()
if (event.type == SDL_QUIT)
{
section::name = section::Name::QUIT;
section::options = section::Options::QUIT_FROM_EVENT;
break;
}
@@ -117,26 +110,26 @@ void Logo::checkInput()
// Gestiona el logo de JAILGAME
void Logo::updateJAILGAMES()
{
if (counter > 30)
if (counter_ > 30)
{
for (int i = 0; i < (int)jailSprite.size(); ++i)
for (int i = 0; i < (int)jail_sprite_.size(); ++i)
{
if (jailSprite[i]->getPosX() != dest.x)
if (jail_sprite_[i]->getX() != dest_.x)
{
if (i % 2 == 0)
{
jailSprite[i]->incPosX(-speed);
if (jailSprite[i]->getPosX() < dest.x)
jail_sprite_[i]->incX(-SPEED);
if (jail_sprite_[i]->getX() < dest_.x)
{
jailSprite[i]->setPosX(dest.x);
jail_sprite_[i]->setX(dest_.x);
}
}
else
{
jailSprite[i]->incPosX(speed);
if (jailSprite[i]->getPosX() > dest.x)
jail_sprite_[i]->incX(SPEED);
if (jail_sprite_[i]->getX() > dest_.x)
{
jailSprite[i]->setPosX(dest.x);
jail_sprite_[i]->setX(dest_.x);
}
}
}
@@ -152,19 +145,19 @@ void Logo::updateTextureColors()
// Manejo de 'sinceTexture'
for (int i = 0; i <= 7; ++i)
{
if (counter == showSinceSprite_cm + inc * i)
if (counter_ == SHOW_SINCE_SPRITE_COUNTER_MARK + inc * i)
{
sinceTexture->setColor(color[i].r, color[i].g, color[i].b);
since_texture_->setColor(color_[i].r, color_[i].g, color_[i].b);
}
}
// Manejo de 'jailTexture' y 'sinceTexture' en el fade
for (int i = 0; i <= 6; ++i)
{
if (counter == initFade_cm + inc * i)
if (counter_ == INIT_FADE_COUNTER_MARK + inc * i)
{
jailTexture->setColor(color[6 - i].r, color[6 - i].g, color[6 - i].b);
sinceTexture->setColor(color[6 - i].r, color[6 - i].g, color[6 - i].b);
jail_texture_->setColor(color_[6 - i].r, color_[6 - i].g, color_[6 - i].b);
since_texture_->setColor(color_[6 - i].r, color_[6 - i].g, color_[6 - i].b);
}
}
}
@@ -173,10 +166,10 @@ void Logo::updateTextureColors()
void Logo::update()
{
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
if (SDL_GetTicks() - ticks > ticksSpeed)
if (SDL_GetTicks() - ticks_ > TICKS_SPEED)
{
// Actualiza el contador de ticks
ticks = SDL_GetTicks();
ticks_ = SDL_GetTicks();
// Actualiza el objeto screen
Screen::get()->update();
@@ -191,19 +184,13 @@ void Logo::update()
updateTextureColors();
// Gestiona el contador y sus eventos
counter++;
counter_++;
// Comprueba si ha terminado el logo
if (counter == endLogo_cm + postLogoDuration)
if (counter_ == END_LOGO_COUNTER_MARK + POST_LOGO_DURATION)
{
section::name = section::Name::INTRO;
}
// Comprueba si se ha de mostrar el sprite
else if (counter == showSinceSprite_cm)
{
sinceSprite->setEnabled(true);
}
}
}
@@ -217,11 +204,15 @@ void Logo::render()
Screen::get()->clean();
// Dibuja los sprites
for (auto &sprite : jailSprite)
for (auto &sprite : jail_sprite_)
{
sprite->render();
}
sinceSprite->render();
if (counter_ >= SHOW_SINCE_SPRITE_COUNTER_MARK)
{
since_sprite_->render();
}
// Vuelca el contenido del renderizador en pantalla
Screen::get()->blit();

View File

@@ -1,13 +1,12 @@
#pragma once
#include <SDL2/SDL_events.h> // for SDL_Event
#include <SDL2/SDL_rect.h> // for SDL_Point
#include <SDL2/SDL_stdinc.h> // for Uint32
#include <vector> // for vector
#include <memory>
#include "utils.h" // for Color
#include "sprite.h"
#include "texture.h"
#include <SDL2/SDL_rect.h> // for SDL_Point
#include <SDL2/SDL_stdinc.h> // for Uint32
#include <memory> // for unique_ptr, shared_ptr
#include <vector> // for vector
#include "sprite.h" // for Sprite
#include "utils.h" // for Color
class Texture;
/*
Esta clase gestiona un estado del programa. Se encarga de dibujar por pantalla el
@@ -21,23 +20,25 @@
class Logo
{
private:
// Constantes
static constexpr Uint32 TICKS_SPEED = 15; // Velocidad a la que se repiten los bucles del programa
static constexpr int SHOW_SINCE_SPRITE_COUNTER_MARK = 70; // Tiempo del contador en el que empieza a verse el sprite de "SINCE 1998"
static constexpr int INIT_FADE_COUNTER_MARK = 300; // Tiempo del contador cuando inicia el fade a negro
static constexpr int END_LOGO_COUNTER_MARK = 400; // Tiempo del contador para terminar el logo
static constexpr int POST_LOGO_DURATION = 20; // Tiempo que dura el logo con el fade al maximo
static constexpr int SPEED = 8; // Velocidad de desplazamiento de cada linea
// Objetos y punteros
std::shared_ptr<Texture> sinceTexture; // Textura con los graficos "Since 1998"
std::unique_ptr<Sprite> sinceSprite; // Sprite para manejar la sinceTexture
std::shared_ptr<Texture> jailTexture; // Textura con los graficos "JAILGAMES"
std::vector<std::unique_ptr<Sprite>> jailSprite; // Vector con los sprites de cada linea que forman el bitmap JAILGAMES
std::shared_ptr<Texture> since_texture_; // Textura con los graficos "Since 1998"
std::unique_ptr<Sprite> since_sprite_; // Sprite para manejar la sinceTexture
std::shared_ptr<Texture> jail_texture_; // Textura con los graficos "JAILGAMES"
std::vector<std::unique_ptr<Sprite>> jail_sprite_; // Vector con los sprites de cada linea que forman el bitmap JAILGAMES
// Variables
std::vector<Color> color; // Vector con los colores para el fade
int counter; // Contador
Uint32 ticks; // Contador de ticks para ajustar la velocidad del programa
Uint32 ticksSpeed; // Velocidad a la que se repiten los bucles del programa
int showSinceSprite_cm; // Tiempo del contador en el que empieza a verse el sprite de "SINCE 1998"
int initFade_cm; // Tiempo del contador cuando inicia el fade a negro
int endLogo_cm; // Tiempo del contador para terminar el logo
int postLogoDuration; // Tiempo que dura el logo con el fade al maximo
int speed; // Velocidad de desplazamiento de cada linea
SDL_Point dest; // Posición X donde dibujar el logo
std::vector<Color> color_; // Vector con los colores para el fade
int counter_; // Contador
Uint32 ticks_; // Contador de ticks para ajustar la velocidad del programa
SDL_Point dest_; // Posición X donde dibujar el logo
// Actualiza las variables
void update();

View File

@@ -7,25 +7,15 @@ Actualizando a la versión "Arcade Edition" en 08/05/2024
*/
#include <iostream> // for basic_ostream, char_traits, operator<<, cout
#include <string> // for basic_string, operator<<, string
#include <iostream> // for char_traits, basic_ostream, operator<<, cout
#include <memory> // for make_unique, unique_ptr
#include "director.h" // for Director
int main(int argc, char *argv[])
{
std::cout << "Game start" << std::endl;
// Crea el objeto Director
auto director = std::make_unique<Director>(argc, const_cast<const char **>(argv));
// Crea el objeto Director
Director *director = new Director(argc, argv);
// Bucle principal
const auto exit = director->run();
// Destruye el objeto Director
delete director;
const auto endType = exit == 0 ? "keyboard" : "controller";
std::cout << "\nGame end with " << endType << std::endl;
return exit;
// Bucle principal
return director->run();
}

View File

@@ -8,40 +8,40 @@
// Constructor
ManageHiScoreTable::ManageHiScoreTable(std::vector<HiScoreEntry> *table)
: table(table) {}
: table_(table) {}
// Resetea la tabla a los valores por defecto
void ManageHiScoreTable::clear()
{
// Limpia la tabla
table->clear();
table_->clear();
// Añade 10 entradas predefinidas
table->push_back({"Bry", 1000000});
table->push_back({"Usufondo", 500000});
table->push_back({"G.Lucas", 100000});
table->push_back({"P.Delgat", 50000});
table->push_back({"P.Arrabalera", 10000});
table->push_back({"Pelechano", 5000});
table->push_back({"Sahuquillo", 1000});
table->push_back({"Bacteriol", 500});
table->push_back({"Pepe", 200});
table->push_back({"Rosita", 100});
table_->push_back({"Bry", 1000000});
table_->push_back({"Usufondo", 500000});
table_->push_back({"G.Lucas", 100000});
table_->push_back({"P.Delgat", 50000});
table_->push_back({"P.Arrabalera", 10000});
table_->push_back({"Pelechano", 5000});
table_->push_back({"Sahuquillo", 1000});
table_->push_back({"Bacteriol", 500});
table_->push_back({"Pepe", 200});
table_->push_back({"Rosita", 100});
}
// Añade un elemento a la tabla
void ManageHiScoreTable::add(HiScoreEntry entry)
{
// Añade la entrada a la tabla
table->push_back(entry);
table_->push_back(entry);
// Ordena la tabla
sort();
// Deja solo las 10 primeras entradas
if ((int)table->size() > 10)
if (static_cast<int>(table_->size()) > 10)
{
table->resize(10);
table_->resize(10);
}
}
@@ -50,31 +50,29 @@ void ManageHiScoreTable::sort()
{
struct
{
bool operator()(HiScoreEntry a, HiScoreEntry b) const { return a.score > b.score; }
} customLess;
bool operator()(const HiScoreEntry &a, const HiScoreEntry &b) const { return a.score > b.score; }
} custom_less;
std::sort(table->begin(), table->end(), customLess);
std::sort(table_->begin(), table_->end(), custom_less);
}
// Carga la tabla con los datos de un fichero
bool ManageHiScoreTable::loadFromFile(std::string filePath)
bool ManageHiScoreTable::loadFromFile(const std::string &file_path)
{
clear();
bool success = true;
const std::string filename = filePath.substr(filePath.find_last_of("\\/") + 1);
SDL_RWops *file = SDL_RWFromFile(filePath.c_str(), "r+b");
auto success = true;
auto file = SDL_RWFromFile(file_path.c_str(), "r+b");
if (file)
{
#ifdef DEBUG
std::cout << "Reading file: " << filename.c_str() << std::endl;
#endif
for (int i = 0; i < (int)table->size(); ++i)
const std::string file_name = file_path.substr(file_path.find_last_of("\\/") + 1);
std::cout << "Reading file: " << file_name.c_str() << std::endl;
for (int i = 0; i < (int)table_->size(); ++i)
{
int nameSize = 0;
if (SDL_RWread(file, &table->at(i).score, sizeof(int), 1) == 0)
if (SDL_RWread(file, &table_->at(i).score, sizeof(int), 1) == 0)
{
success = false;
break;
@@ -86,7 +84,7 @@ bool ManageHiScoreTable::loadFromFile(std::string filePath)
break;
}
char *name = (char *)malloc(nameSize + 1);
char *name = static_cast<char *>(malloc(nameSize + 1));
if (SDL_RWread(file, name, sizeof(char) * nameSize, 1) == 0)
{
success = false;
@@ -96,7 +94,7 @@ bool ManageHiScoreTable::loadFromFile(std::string filePath)
else
{
name[nameSize] = 0;
table->at(i).name = name;
table_->at(i).name = name;
free(name);
}
}
@@ -113,34 +111,30 @@ bool ManageHiScoreTable::loadFromFile(std::string filePath)
}
// Guarda la tabla en un fichero
bool ManageHiScoreTable::saveToFile(std::string filePath)
bool ManageHiScoreTable::saveToFile(const std::string &file_path)
{
bool success = true;
const std::string fileName = filePath.substr(filePath.find_last_of("\\/") + 1);
SDL_RWops *file = SDL_RWFromFile(filePath.c_str(), "w+b");
const std::string file_name = file_path.substr(file_path.find_last_of("\\/") + 1);
auto success = true;
auto file = SDL_RWFromFile(file_path.c_str(), "w+b");
if (file)
{
// Guarda los datos
for (int i = 0; i < (int)table->size(); ++i)
for (int i = 0; i < (int)table_->size(); ++i)
{
SDL_RWwrite(file, &table->at(i).score, sizeof(int), 1);
const int nameSize = (int)table->at(i).name.size();
SDL_RWwrite(file, &table_->at(i).score, sizeof(int), 1);
const int nameSize = (int)table_->at(i).name.size();
SDL_RWwrite(file, &nameSize, sizeof(int), 1);
SDL_RWwrite(file, table->at(i).name.c_str(), nameSize, 1);
SDL_RWwrite(file, table_->at(i).name.c_str(), nameSize, 1);
}
#ifdef DEBUG
std::cout << "Writing file: " << fileName.c_str() << std::endl;
#endif
std::cout << "Writing file: " << file_name.c_str() << std::endl;
// Cierra el fichero
SDL_RWclose(file);
}
else
{
#ifdef DEBUG
std::cout << "Error: Unable to save " << fileName.c_str() << " file! " << SDL_GetError() << std::endl;
#endif
std::cout << "Error: Unable to save " << file_name.c_str() << " file! " << SDL_GetError() << std::endl;
}
return success;
}

View File

@@ -17,14 +17,14 @@ class ManageHiScoreTable
{
private:
// Variables
std::vector<HiScoreEntry> *table; // Tabla con los records
std::vector<HiScoreEntry> *table_; // Tabla con los records
// Ordena la tabla
void sort();
public:
// Constructor
ManageHiScoreTable(std::vector<HiScoreEntry> *table);
explicit ManageHiScoreTable(std::vector<HiScoreEntry> *table);
// Destructor
~ManageHiScoreTable() = default;
@@ -36,8 +36,8 @@ public:
void add(HiScoreEntry entry);
// Carga la tabla con los datos de un fichero
bool loadFromFile(std::string filePath);
bool loadFromFile(const std::string &file_path);
// Guarda la tabla en un fichero
bool saveToFile(std::string filePath);
bool saveToFile(const std::string &file_path);
};

View File

@@ -2,33 +2,44 @@
#include "texture.h" // for Texture
// Constructor
MovingSprite::MovingSprite(float x, float y, int w, int h, float vx, float vy, float ax, float ay, std::shared_ptr<Texture> texture)
: Sprite((int)x, (int)y, w, h, texture), x_(x), y_(y), vx_(vx), vy_(vy), ax_(ax), ay_(ay)
{
// Establece el zoom W,H del sprite
zoomW_ = 1;
zoomH_ = 1;
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_Rect pos, Rotate rotate, float zoom_w, float zoom_h, SDL_RendererFlip flip)
: Sprite(texture, pos),
x_(pos.x),
y_(pos.y),
vx_(0.0f),
vy_(0.0f),
ax_(0.0f),
ay_(0.0f),
rotate_(rotate),
zoom_w_(zoom_w),
zoom_h_(zoom_h),
flip_(flip) {}
// Establece el angulo con el que se dibujará
angle_ = (double)0;
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_Rect pos)
: Sprite(texture, pos),
x_(pos.x),
y_(pos.y),
vx_(0.0f),
vy_(0.0f),
ax_(0.0f),
ay_(0.0f),
rotate_(Rotate()),
zoom_w_(1.0f),
zoom_h_(1.0f),
flip_(SDL_FLIP_NONE) {}
// Establece los valores de rotacion
rotateEnabled_ = false;
rotateSpeed_ = 0;
rotateAmount_ = (double)0;
// Contador interno
counter_ = 0;
// Establece el rectangulo de donde coger la imagen
spriteClip_ = {0, 0, w_, h_};
// Establece el centro de rotación
center_ = nullptr;
// Establece el tipo de volteado
currentFlip_ = SDL_FLIP_NONE;
};
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture)
: Sprite(texture),
x_(0.0f),
y_(0.0f),
vx_(0.0f),
vy_(0.0f),
ax_(0.0f),
ay_(0.0f),
rotate_(Rotate()),
zoom_w_(1.0f),
zoom_h_(1.0f),
flip_(SDL_FLIP_NONE) { Sprite::clear(); }
// Reinicia todas las variables
void MovingSprite::clear()
@@ -42,17 +53,14 @@ void MovingSprite::clear()
ax_ = 0.0f; // Aceleración en el eje X. Variación de la velocidad
ay_ = 0.0f; // Aceleración en el eje Y. Variación de la velocidad
zoomW_ = 1.0f; // Zoom aplicado a la anchura
zoomH_ = 1.0f; // Zoom aplicado a la altura
rotate_ = Rotate(); // Inicializa la estructura
angle_ = 0.0; // Angulo para dibujarlo
rotateEnabled_ = false; // Indica si ha de rotar
center_ = nullptr; // Centro de rotación
rotateSpeed_ = 0; // Velocidad de giro
rotateAmount_ = 0.0; // Cantidad de grados a girar en cada iteración
counter_ = 0; // Contador interno
zoom_w_ = 1.0f; // Zoom aplicado a la anchura
zoom_h_ = 1.0f; // Zoom aplicado a la altura
currentFlip_ = SDL_FLIP_NONE; // Establece como se ha de voltear el sprite
flip_ = SDL_FLIP_NONE; // Establece como se ha de voltear el sprite
Sprite::clear();
}
// Mueve el sprite
@@ -63,17 +71,142 @@ void MovingSprite::move()
vx_ += ax_;
vy_ += ay_;
pos_.x = static_cast<int>(x_);
pos_.y = static_cast<int>(y_);
}
// Actualiza las variables internas del objeto
void MovingSprite::update()
{
move();
rotate();
}
// Muestra el sprite por pantalla
void MovingSprite::render()
{
if (enabled_)
texture_->render(pos_.x, pos_.y, &sprite_clip_, zoom_w_, zoom_h_, rotate_.angle, rotate_.center, flip_);
}
// Obtiene el valor de la variable
float MovingSprite::getZoomW() const
{
return zoom_w_;
}
// Obtiene el valor de la variable
float MovingSprite::getZoomH() const
{
return zoom_h_;
}
// Obtiene el valor de la variable
double MovingSprite::getAngle() const
{
return rotate_.angle;
}
// Establece el valor de la variable
void MovingSprite::setZoomW(float value)
{
zoom_w_ = value;
}
// Establece el valor de la variable
void MovingSprite::setZoomH(float value)
{
zoom_h_ = value;
}
// Establece el valor de la variable
void MovingSprite::setAngle(double value)
{
rotate_.angle = value;
}
// Incrementa el valor del ángulo
void MovingSprite::updateAngle()
{
rotate_.angle += rotate_.amount;
}
// Obtiene el valor de la variable
bool MovingSprite::isRotating() const
{
return rotate_.enabled;
}
// Obtiene el valor de la variable
int MovingSprite::getRotateSpeed() const
{
return rotate_.speed;
}
// Establece la rotacion
void MovingSprite::rotate()
{
if (rotate_.enabled)
{
texture_->render((int)x_, (int)y_, &spriteClip_, zoomW_, zoomH_, angle_, center_, currentFlip_);
++rotate_.counter;
if (rotate_.counter % rotate_.speed == 0)
{
updateAngle();
rotate_.counter = 0;
}
}
}
// Establece el valor de la variable
void MovingSprite::enableRotate()
{
rotate_.enabled = true;
rotate_.counter = 0;
}
// Establece el valor de la variable
void MovingSprite::disableRotate()
{
rotate_.enabled = false;
rotate_.counter = 0;
}
// Establece el valor de la variable
void MovingSprite::setRotateSpeed(int value)
{
rotate_.speed = std::max(1, value);
}
// Establece el valor de la variable
void MovingSprite::setRotateAmount(double value)
{
rotate_.amount = value;
}
// Cambia el sentido de la rotación
void MovingSprite::switchRotate()
{
rotate_.amount *= -1;
}
// Establece el valor de la variable
void MovingSprite::setFlip(SDL_RendererFlip flip)
{
flip_ = flip;
}
// Gira el sprite horizontalmente
void MovingSprite::flip()
{
flip_ = (flip_ == SDL_FLIP_HORIZONTAL) ? SDL_FLIP_NONE : SDL_FLIP_HORIZONTAL;
}
// Obtiene el valor de la variable
SDL_RendererFlip MovingSprite::getFlip()
{
return flip_;
}
// Obtiene el valor de la variable
float MovingSprite::getPosX() const
{
@@ -110,31 +243,13 @@ float MovingSprite::getAccelY() const
return ay_;
}
// Obtiene el valor de la variable
float MovingSprite::getZoomW() const
{
return zoomW_;
}
// Obtiene el valor de la variable
float MovingSprite::getZoomH() const
{
return zoomH_;
}
// Obtiene el valor de la variable
double MovingSprite::getAngle() const
{
return angle_;
}
// Establece la posición y_ el tamaño del objeto
void MovingSprite::setRect(SDL_Rect rect)
void MovingSprite::setPos(SDL_Rect rect)
{
x_ = (float)rect.x;
y_ = (float)rect.y;
w_ = rect.w;
h_ = rect.h;
x_ = static_cast<float>(rect.x);
y_ = static_cast<float>(rect.y);
pos_ = rect;
}
// Establece el valor de las variables
@@ -142,18 +257,23 @@ void MovingSprite::setPos(float x, float y)
{
x_ = x;
y_ = y;
pos_.x = static_cast<int>(x_);
pos_.y = static_cast<int>(y_);
}
// Establece el valor de la variable
void MovingSprite::setPosX(float value)
{
x_ = value;
pos_.x = static_cast<int>(x_);
}
// Establece el valor de la variable
void MovingSprite::setPosY(float value)
{
y_ = value;
pos_.y = static_cast<int>(y_);
}
// Establece el valor de la variable
@@ -178,124 +298,4 @@ void MovingSprite::setAccelX(float value)
void MovingSprite::setAccelY(float value)
{
ay_ = value;
}
// Establece el valor de la variable
void MovingSprite::setZoomW(float value)
{
zoomW_ = value;
}
// Establece el valor de la variable
void MovingSprite::setZoomH(float value)
{
zoomH_ = value;
}
// Establece el valor de la variable
void MovingSprite::setAngle(double value)
{
angle_ = value;
}
// Incrementa el valor de la variable
void MovingSprite::incAngle(double value)
{
angle_ += value;
}
// Decrementa el valor de la variable
void MovingSprite::decAngle(double value)
{
angle_ -= value;
}
// Obtiene el valor de la variable
bool MovingSprite::getRotate() const
{
return rotateEnabled_;
}
// Obtiene el valor de la variable
Uint16 MovingSprite::getRotateSpeed() const
{
return rotateSpeed_;
}
// Establece la rotacion
void MovingSprite::rotate()
{
if (rotateEnabled_)
{
if (counter_ % rotateSpeed_ == 0)
{
incAngle(rotateAmount_);
}
}
}
// Establece el valor de la variable
void MovingSprite::setRotate(bool value)
{
rotateEnabled_ = value;
}
// Establece el valor de la variable
void MovingSprite::setRotateSpeed(int value)
{
rotateSpeed_ = (value < 1) ? 1 : value;
}
// Establece el valor de la variable
void MovingSprite::setRotateAmount(double value)
{
rotateAmount_ = value;
}
// Establece el valor de la variable
void MovingSprite::disableRotate()
{
rotateEnabled_ = false;
angle_ = (double)0;
}
// Actualiza las variables internas del objeto
void MovingSprite::update()
{
if (enabled_)
{
move();
rotate();
++counter_ %= 60000;
}
}
// Cambia el sentido de la rotación
void MovingSprite::switchRotate()
{
rotateAmount_ *= -1;
}
// Establece el valor de la variable
void MovingSprite::setFlip(SDL_RendererFlip flip)
{
currentFlip_ = flip;
}
// Gira el sprite horizontalmente
void MovingSprite::flip()
{
currentFlip_ = (currentFlip_ == SDL_FLIP_HORIZONTAL) ? SDL_FLIP_NONE : SDL_FLIP_HORIZONTAL;
}
// Obtiene el valor de la variable
SDL_RendererFlip MovingSprite::getFlip()
{
return currentFlip_;
}
// Devuelve el rectangulo donde está el sprite
SDL_Rect MovingSprite::getRect()
{
return (SDL_Rect){(int)x_, (int)y_, w_, h_};
}

View File

@@ -1,15 +1,28 @@
#pragma once
#include <SDL2/SDL_rect.h> // for SDL_Rect, SDL_Point
#include <SDL2/SDL_render.h> // for SDL_RendererFlip
#include <SDL2/SDL_stdinc.h> // for Uint16
#include <memory>
#include "sprite.h" // for Sprite
#include "texture.h"
#include <SDL2/SDL_rect.h> // for SDL_Rect, SDL_Point
#include <SDL2/SDL_render.h> // for SDL_RendererFlip
#include <SDL2/SDL_stdinc.h> // for Uint16
#include <memory> // for shared_ptr
#include "sprite.h" // for Sprite
class Texture;
// Clase MovingSprite. Añade posicion y velocidad en punto flotante
// Clase MovingSprite. Añade movimiento y efectos de rotación, zoom y flip al sprite
class MovingSprite : public Sprite
{
public:
struct Rotate
{
bool enabled; // Indica si ha de rotar
int counter; // Contador
int speed; // Velocidad de giro
double angle; // Angulo para dibujarlo
float amount; // Cantidad de grados a girar en cada iteración
SDL_Point *center; // Centro de rotación
Rotate() : enabled(false), counter(0), speed(0), angle(0.0), amount(0.0f), center(nullptr) {}
};
protected:
float x_; // Posición en el eje X
float y_; // Posición en el eje Y
@@ -20,20 +33,13 @@ protected:
float ax_; // Aceleración en el eje X. Variación de la velocidad
float ay_; // Aceleración en el eje Y. Variación de la velocidad
float zoomW_; // Zoom aplicado a la anchura
float zoomH_; // Zoom aplicado a la altura
Rotate rotate_; // Variables usada para controlar la rotación del sprite
float zoom_w_; // Zoom aplicado a la anchura
float zoom_h_; // Zoom aplicado a la altura
SDL_RendererFlip flip_; // Indica como se voltea el sprite
double angle_; // Angulo para dibujarlo
bool rotateEnabled_; // Indica si ha de rotar
int rotateSpeed_; // Velocidad de giro
double rotateAmount_; // Cantidad de grados a girar en cada iteración
int counter_; // Contador interno
SDL_Point *center_; // Centro de rotación
SDL_RendererFlip currentFlip_; // Indica como se voltea el sprite
public:
// Constructor
MovingSprite(float x = 0, float y = 0, int w = 0, int h = 0, float velx = 0, float vely = 0, float accelx = 0, float accely = 0, std::shared_ptr<Texture> texture = nullptr);
// Incrementa el valor del ángulo
void updateAngle();
// Mueve el sprite
void move();
@@ -41,53 +47,46 @@ public:
// Rota el sprite
void rotate();
// Actualiza las variables internas del objeto
void update();
public:
// Constructor
MovingSprite(std::shared_ptr<Texture> texture, SDL_Rect pos, MovingSprite::Rotate rotate, float zoom_w, float zoom_h, SDL_RendererFlip flip);
MovingSprite(std::shared_ptr<Texture> texture, SDL_Rect pos);
explicit MovingSprite(std::shared_ptr<Texture> texture);
// Reinicia todas las variables
void clear();
// Destructor
~MovingSprite() = default;
// Actualiza las variables internas del objeto
virtual void update();
// Reinicia todas las variables a cero
void clear() override;
// Muestra el sprite por pantalla
void render();
void render() override;
// Obten el valor de la variable
// Obtiene la variable
float getPosX() const;
float getPosY() const;
// Obten el valor de la variable
float getVelX() const;
float getVelY() const;
// Obten el valor de la variable
float getAccelX() const;
float getAccelY() const;
// Establece la variable
void setVelX(float value);
void setVelY(float value);
void setAccelX(float value);
void setAccelY(float value);
// Obten el valor de la variable
float getZoomW() const;
float getZoomH() const;
// Obten el valor de la variable
bool isRotating() const;
double getAngle() const;
bool getRotate() const;
Uint16 getRotateSpeed() const;
// Establece la posición y el tamaño del objeto
void setRect(SDL_Rect rect);
// Establece el valor de las variables
void setPos(float x, float y);
// Establece el valor de la variable
void setPosX(float value);
void setPosY(float value);
// Establece el valor de la variable
void setVelX(float value);
void setVelY(float value);
// Establece el valor de la variable
void setAccelX(float value);
void setAccelY(float value);
int getRotateSpeed() const;
// Establece el valor de la variable
void setZoomW(float value);
@@ -95,17 +94,15 @@ public:
// Establece el valor de la variable
void setAngle(double vaue);
void incAngle(double value);
void decAngle(double value);
// Activa o desactiva el efecto derotación
void enableRotate();
void disableRotate();
// Establece el valor de la variable
void setRotate(bool value);
void setRotateSpeed(int value);
void setRotateAmount(double value);
// Quita el efecto de rotación y deja el sprite en su angulo inicial.
void disableRotate();
// Cambia el sentido de la rotación
void switchRotate();
@@ -118,6 +115,15 @@ public:
// Obtiene el valor de la variable
SDL_RendererFlip getFlip();
// Devuelve el rectangulo donde está el sprite
SDL_Rect getRect();
// Establece la posición y_ el tamaño del objeto
void setPos(SDL_Rect rect);
// Establece el valor de las variables
void setPos(float x, float y);
// Establece el valor de la variable
void setPosX(float value);
// Establece el valor de la variable
void setPosY(float value);
};

344
source/notifier.cpp Normal file
View File

@@ -0,0 +1,344 @@
#include "notifier.h"
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND
#include <SDL2/SDL_pixels.h> // for SDL_PIXELFORMAT_RGBA8888
#include <string> // for string
#include "jail_audio.h" // for JA_DeleteSound, JA_LoadSound, JA_Pla...
#include "param.h" // for param
#include "resource.h" // for Resource
#include "screen.h" // for Screen
#include "sprite.h" // for Sprite
#include "text.h" // for Text
#include "texture.h" // for Texture
// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado
Notifier *Notifier::notifier_ = nullptr;
// [SINGLETON] Crearemos el objeto screen con esta función estática
void Notifier::init(std::string icon_file, std::shared_ptr<Text> text, const std::string &sound_file)
{
Notifier::notifier_ = new Notifier(icon_file, text, sound_file);
}
// [SINGLETON] Destruiremos el objeto screen con esta función estática
void Notifier::destroy()
{
delete Notifier::notifier_;
}
// [SINGLETON] Con este método obtenemos el objeto screen y podemos trabajar con él
Notifier *Notifier::get()
{
return Notifier::notifier_;
}
// Constructor
Notifier::Notifier(std::string icon_file, std::shared_ptr<Text> text, const std::string &sound_file)
: renderer_(Screen::get()->getRenderer()),
text_(text),
bg_color_(param.notification.color),
wait_time_(150),
stack_(false),
sound_(JA_LoadSound(sound_file.c_str()))
{
// Inicializa variables
has_icons_ = !icon_file.empty();
// Crea objetos
icon_texture_ = has_icons_ ? std::make_unique<Texture>(renderer_, icon_file) : nullptr;
}
// Destructor
Notifier::~Notifier()
{
// Libera la memoria de los objetos
JA_DeleteSound(sound_);
notifications_.clear();
}
// Dibuja las notificaciones por pantalla
void Notifier::render()
{
for (int i = (int)notifications_.size() - 1; i >= 0; --i)
{
notifications_[i].sprite->render();
}
}
// Actualiza el estado de las notificaiones
void Notifier::update()
{
for (int i = 0; i < (int)notifications_.size(); ++i)
{
// Si la notificación anterior está "saliendo", no hagas nada
if (i > 0)
{
if (notifications_[i - 1].status == NotificationStatus::RISING)
{
break;
}
}
notifications_[i].counter++;
// Hace sonar la notificación en el primer frame
if (notifications_[i].counter == 1)
{
if (param.notification.sound)
{
if (notifications_[i].status == NotificationStatus::RISING)
{ // Reproduce el sonido de la notificación
JA_PlaySound(sound_);
}
}
}
// Comprueba los estados
if (notifications_[i].status == NotificationStatus::RISING)
{
const float step = ((float)notifications_[i].counter / notifications_[i].travel_dist);
const int alpha = 255 * step;
if (param.notification.pos_v == NotifyPosition::TOP)
{
notifications_[i].rect.y++;
}
else
{
notifications_[i].rect.y--;
}
notifications_[i].texture->setAlpha(alpha);
if (notifications_[i].rect.y == notifications_[i].y)
{
notifications_[i].status = NotificationStatus::STAY;
notifications_[i].texture->setAlpha(255);
notifications_[i].counter = 0;
}
}
else if (notifications_[i].status == NotificationStatus::STAY)
{
if (notifications_[i].counter == wait_time_)
{
notifications_[i].status = NotificationStatus::VANISHING;
notifications_[i].counter = 0;
}
}
else if (notifications_[i].status == NotificationStatus::VANISHING)
{
const float step = (notifications_[i].counter / (float)notifications_[i].travel_dist);
const int alpha = 255 * (1 - step);
if (param.notification.pos_v == NotifyPosition::TOP)
{
notifications_[i].rect.y--;
}
else
{
notifications_[i].rect.y++;
}
notifications_[i].texture->setAlpha(alpha);
if (notifications_[i].rect.y == notifications_[i].y - notifications_[i].travel_dist)
{
notifications_[i].status = NotificationStatus::FINISHED;
}
}
notifications_[i].sprite->setPosition(notifications_[i].rect);
}
clearFinishedNotifications();
}
// Elimina las notificaciones finalizadas
void Notifier::clearFinishedNotifications()
{
for (int i = (int)notifications_.size() - 1; i >= 0; --i)
{
if (notifications_[i].status == NotificationStatus::FINISHED)
{
notifications_.erase(notifications_.begin() + i);
}
}
}
void Notifier::showText(std::string text1, std::string text2, int icon, std::string code)
{
// Cuenta el número de textos a mostrar
const int num_texts = !text1.empty() + !text2.empty();
// Si no hay texto, acaba
if (num_texts == 0)
{
return;
}
// Si solo hay un texto, lo coloca en la primera variable
if (num_texts == 1)
{
text1 += text2;
text2.clear();
}
// Si las notificaciones no se apilan, elimina las anteriores
if (!stack_)
{
clearNotifications();
}
// Inicializa variables
constexpr auto icon_size = 16;
constexpr auto padding_out = 1;
const auto padding_in_h = text_->getCharacterSize();
const auto padding_in_v = text_->getCharacterSize() / 2;
const auto icon_space = icon >= 0 ? icon_size + padding_in_h : 0;
const std::string txt = text1.length() > text2.length() ? text1 : text2;
const auto width = text_->lenght(txt) + (padding_in_h * 2) + icon_space;
const auto height = (text_->getCharacterSize() * num_texts) + (padding_in_v * 2);
const auto shape = NotificationShape::SQUARED;
// Posición horizontal
auto desp_h = 0;
if (param.notification.pos_h == NotifyPosition::LEFT)
{
desp_h = padding_out;
}
else if (param.notification.pos_h == NotifyPosition::MIDDLE)
{
desp_h = ((param.game.width / 2) - (width / 2));
}
else
{
desp_h = param.game.width - width - padding_out;
}
// Posición vertical
const int desp_v = (param.notification.pos_v == NotifyPosition::TOP) ? padding_out : (param.game.height - height - padding_out);
// Offset
const auto travel_dist = height + padding_out;
auto offset = 0;
if (param.notification.pos_v == NotifyPosition::TOP)
{
offset = (int)notifications_.size() > 0 ? notifications_.back().y + travel_dist : desp_v;
}
else
{
offset = (int)notifications_.size() > 0 ? notifications_.back().y - travel_dist : desp_v;
}
// Crea la notificacion
Notification n;
// Inicializa variables
n.code = code;
n.y = offset;
n.travel_dist = travel_dist;
n.counter = 0;
n.status = NotificationStatus::RISING;
n.text1 = text1;
n.text2 = text2;
n.shape = shape;
auto y_pos = offset + (param.notification.pos_v == NotifyPosition::TOP ? -travel_dist : travel_dist);
n.rect = {desp_h, y_pos, width, height};
// Crea la textura
n.texture = std::make_shared<Texture>(renderer_);
n.texture->createBlank(width, height, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET);
n.texture->setBlendMode(SDL_BLENDMODE_BLEND);
// Prepara para dibujar en la textura
n.texture->setAsRenderTarget(renderer_);
// Dibuja el fondo de la notificación
SDL_SetRenderDrawColor(renderer_, bg_color_.r, bg_color_.g, bg_color_.b, 255);
SDL_Rect rect;
if (shape == NotificationShape::ROUNDED)
{
rect = {4, 0, width - (4 * 2), height};
SDL_RenderFillRect(renderer_, &rect);
rect = {4 / 2, 1, width - 4, height - 2};
SDL_RenderFillRect(renderer_, &rect);
rect = {1, 4 / 2, width - 2, height - 4};
SDL_RenderFillRect(renderer_, &rect);
rect = {0, 4, width, height - (4 * 2)};
SDL_RenderFillRect(renderer_, &rect);
}
else if (shape == NotificationShape::SQUARED)
{
SDL_RenderClear(renderer_);
}
// Dibuja el icono de la notificación
if (has_icons_ && icon >= 0 && num_texts == 2)
{
auto sp = std::make_unique<Sprite>(icon_texture_, (SDL_Rect){0, 0, icon_size, icon_size});
sp->setPosition({padding_in_h, padding_in_v, icon_size, icon_size});
sp->setSpriteClip({icon_size * (icon % 10), icon_size * (icon / 10), icon_size, icon_size});
sp->render();
}
// Escribe el texto de la notificación
Color color = {255, 255, 255};
if (num_texts == 2)
{ // Dos lineas de texto
text_->writeColored(padding_in_h + icon_space, padding_in_v, text1, color);
text_->writeColored(padding_in_h + icon_space, padding_in_v + text_->getCharacterSize() + 1, text2, color);
}
else
{ // Una linea de texto
text_->writeColored(padding_in_h + icon_space, padding_in_v, text1, color);
}
// Deja de dibujar en la textura
SDL_SetRenderTarget(renderer_, nullptr);
// Crea el sprite de la notificación
n.sprite = std::make_shared<Sprite>(n.texture, n.rect);
// Deja la notificación invisible
n.texture->setAlpha(0);
// Añade la notificación a la lista
notifications_.push_back(n);
}
// Indica si hay notificaciones activas
bool Notifier::isActive()
{
if ((int)notifications_.size() > 0)
{
return true;
}
return false;
}
// Finaliza y elimnina todas las notificaciones activas
void Notifier::clearNotifications()
{
for (int i = 0; i < (int)notifications_.size(); ++i)
{
notifications_[i].status = NotificationStatus::FINISHED;
}
clearFinishedNotifications();
}
// Obtiene los códigos de las notificaciones
std::vector<std::string> Notifier::getCodes()
{
std::vector<std::string> codes;
for (int i = 0; i < (int)notifications_.size(); ++i)
{
codes.push_back(notifications_[i].code);
}
return codes;
}

121
source/notifier.h Normal file
View File

@@ -0,0 +1,121 @@
#pragma once
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_render.h> // for SDL_Renderer
#include <memory> // for shared_ptr, unique_ptr
#include <string> // for string, basic_string
#include <vector> // for vector
#include "utils.h" // for Color
class Sprite;
class Text;
class Texture;
struct JA_Sound_t; // lines 12-12
class Notifier
{
private:
// [SINGLETON] Objeto notifier privado para Don Melitón
static Notifier *notifier_;
enum class NotificationStatus
{
RISING,
STAY,
VANISHING,
FINISHED,
};
enum class NotificationPosition
{
UPPER_LEFT,
UPPER_CENTER,
UPPER_RIGHT,
MIDDLE_LEFT,
MIDDLE_RIGHT,
BOTTOM_LEFT,
BOTTOM_CENTER,
BOTTOM_RIGHT,
};
enum class NotificationShape
{
ROUNDED,
SQUARED,
};
struct Notification
{
std::shared_ptr<Texture> texture;
std::shared_ptr<Sprite> sprite;
std::string text1;
std::string text2;
int counter;
NotificationStatus status;
NotificationPosition position;
NotificationShape shape;
SDL_Rect rect;
int y;
int travel_dist;
std::string code; // Permite asignar un código a la notificación
};
// Objetos y punteros
SDL_Renderer *renderer_; // El renderizador de la ventana
std::shared_ptr<Texture> icon_texture_; // Textura para los iconos de las notificaciones
std::shared_ptr<Text> text_; // Objeto para dibujar texto
// Variables
Color bg_color_; // Color de fondo de las notificaciones
int wait_time_; // Tiempo que se ve la notificación
std::vector<Notification> notifications_; // La lista de notificaciones activas
bool stack_; // Indica si las notificaciones se apilan
bool has_icons_; // Indica si el notificador tiene textura para iconos
JA_Sound_t *sound_; // Sonido a reproducir cuando suena la notificación
// Elimina las notificaciones finalizadas
void clearFinishedNotifications();
// Finaliza y elimnina todas las notificaciones activas
void clearNotifications();
// [SINGLETON] Ahora el constructor y el destructor son privados, para no poder crear objetos notifier desde fuera
// Constructor
Notifier(std::string icon_file, std::shared_ptr<Text> text, const std::string &sound_file);
// Destructor
~Notifier();
public:
// [SINGLETON] Crearemos el objeto notifier con esta función estática
static void init(std::string icon_file, std::shared_ptr<Text> text, const std::string &sound_file);
// [SINGLETON] Destruiremos el objeto notifier con esta función estática
static void destroy();
// [SINGLETON] Con este método obtenemos el objeto notifier y podemos trabajar con él
static Notifier *get();
// Dibuja las notificaciones por pantalla
void render();
// Actualiza el estado de las notificaiones
void update();
/**
* @brief Muestra una notificación de texto por pantalla.
*
* @param text1 Primer texto opcional para mostrar (valor predeterminado: cadena vacía).
* @param text2 Segundo texto opcional para mostrar (valor predeterminado: cadena vacía).
* @param icon Icono opcional para mostrar (valor predeterminado: -1).
* @param code Permite asignar un código a la notificación (valor predeterminado: cadena vacía).
*/
void showText(std::string text1 = std::string(), std::string text2 = std::string(), int icon = -1, std::string code = std::string());
// Indica si hay notificaciones activas
bool isActive();
// Obtiene los códigos de las notificaciones
std::vector<std::string> getCodes();
};

View File

@@ -1,312 +0,0 @@
#include "notify.h"
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND
#include <SDL2/SDL_pixels.h> // for SDL_PIXELFORMAT_RGBA8888
#include <string> // for basic_string, char_traits, string
#include "jail_audio.h" // for JA_DeleteSound, JA_LoadSound, JA_Pla...
#include "options.h" // for options
#include "param.h"
#include "sprite.h" // for Sprite
#include "text.h" // for Text
#include "texture.h" // for Texture
// Constructor
Notify::Notify(SDL_Renderer *renderer, std::string iconFile, std::string bitmapFile, std::string textFile, std::string soundFile)
: renderer(renderer)
{
// Inicializa variables
bgColor = param.notification.color;
waitTime = 150;
stack = false;
hasIcons = iconFile == "" ? false : true;
// Crea objetos
if (hasIcons)
{
iconTexture = std::make_unique<Texture>(renderer, iconFile);
}
text = std::make_unique<Text>(bitmapFile, textFile, renderer);
sound = JA_LoadSound(soundFile.c_str());
}
// Destructor
Notify::~Notify()
{
// Libera la memoria de los objetos
JA_DeleteSound(sound);
notifications.clear();
}
// Dibuja las notificaciones por pantalla
void Notify::render()
{
for (int i = (int)notifications.size() - 1; i >= 0; --i)
{
notifications[i].sprite->render();
}
}
// Actualiza el estado de las notificaiones
void Notify::update()
{
for (int i = 0; i < (int)notifications.size(); ++i)
{
// Si la notificación anterior está "saliendo", no hagas nada
if (i > 0)
{
if (notifications[i - 1].status == NotificationStatus::RISING)
{
break;
}
}
notifications[i].counter++;
// Hace sonar la notificación en el primer frame
if (notifications[i].counter == 1)
{
if (param.notification.sound)
{
if (notifications[i].status == NotificationStatus::RISING)
{ // Reproduce el sonido de la notificación
JA_PlaySound(sound);
}
}
}
// Comprueba los estados
if (notifications[i].status == NotificationStatus::RISING)
{
const float step = ((float)notifications[i].counter / notifications[i].travelDist);
const int alpha = 255 * step;
if (param.notification.pos_v == NotifyPosition::TOP)
{
notifications[i].rect.y++;
}
else
{
notifications[i].rect.y--;
}
notifications[i].texture->setAlpha(alpha);
if (notifications[i].rect.y == notifications[i].y)
{
notifications[i].status = NotificationStatus::STAY;
notifications[i].texture->setAlpha(255);
notifications[i].counter = 0;
}
}
else if (notifications[i].status == NotificationStatus::STAY)
{
if (notifications[i].counter == waitTime)
{
notifications[i].status = NotificationStatus::VANISHING;
notifications[i].counter = 0;
}
}
else if (notifications[i].status == NotificationStatus::VANISHING)
{
const float step = (notifications[i].counter / (float)notifications[i].travelDist);
const int alpha = 255 * (1 - step);
if (param.notification.pos_v == NotifyPosition::TOP)
{
notifications[i].rect.y--;
}
else
{
notifications[i].rect.y++;
}
notifications[i].texture->setAlpha(alpha);
if (notifications[i].rect.y == notifications[i].y - notifications[i].travelDist)
{
notifications[i].status = NotificationStatus::FINISHED;
}
}
notifications[i].sprite->setPos(notifications[i].rect);
}
clearFinishedNotifications();
}
// Elimina las notificaciones finalizadas
void Notify::clearFinishedNotifications()
{
for (int i = (int)notifications.size() - 1; i >= 0; --i)
{
if (notifications[i].status == NotificationStatus::FINISHED)
{
notifications.erase(notifications.begin() + i);
}
}
}
// Muestra una notificación de texto por pantalla;
void Notify::showText(std::string text1, std::string text2, int icon)
{
// Cuenta el número de textos a mostrar
const int numTexts = (text1 != "") + (text2 != "");
// Si no hay texto, acaba
if (numTexts == 0)
{
return;
}
// Si solo hay un texto, lo coloca en la primera variable
else if (numTexts == 1)
{
text1 = text1 + text2;
text2 = "";
}
// Si las notificaciones no se apilan, elimina las anteriores
if (!stack)
{
clearNotifications();
}
// Inicializa variables
constexpr auto iconSize = 16;
constexpr auto paddingOut = 1;
const auto paddingIn = text->getCharacterSize() / 2;
const auto iconSpace = icon >= 0 ? iconSize + paddingIn : 0;
const std::string txt = text1.length() > text2.length() ? text1 : text2;
const auto width = text->lenght(txt) + (paddingIn * 2) + iconSpace;
const auto height = (text->getCharacterSize() * numTexts) + (paddingIn * 2);
const auto shape = NotificationShape::SQUARED;
// Posición horizontal
auto despH = 0;
if (param.notification.pos_h == NotifyPosition::LEFT)
{
despH = paddingOut;
}
else if (param.notification.pos_h == NotifyPosition::MIDDLE)
{
despH = ((param.game.width / 2) - (width / 2));
}
else
{
despH = param.game.width - width - paddingOut;
}
// Posición vertical
const int despV = (param.notification.pos_v == NotifyPosition::TOP) ? paddingOut : (param.game.height - height - paddingOut);
// Offset
const auto travelDist = height + paddingOut;
auto offset = 0;
if (param.notification.pos_v == NotifyPosition::TOP)
{
offset = (int)notifications.size() > 0 ? notifications.back().y + travelDist : despV;
}
else
{
offset = (int)notifications.size() > 0 ? notifications.back().y - travelDist : despV;
}
// Crea la notificacion
Notification n;
// Inicializa variables
n.y = offset;
n.travelDist = travelDist;
n.counter = 0;
n.status = NotificationStatus::RISING;
n.text1 = text1;
n.text2 = text2;
n.shape = shape;
auto yPos = offset + (param.notification.pos_v == NotifyPosition::TOP ? -travelDist : travelDist);
n.rect = {despH, yPos, width, height};
// Crea la textura
n.texture = std::make_shared<Texture>(renderer);
n.texture->createBlank(width, height, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET);
n.texture->setBlendMode(SDL_BLENDMODE_BLEND);
// Prepara para dibujar en la textura
n.texture->setAsRenderTarget(renderer);
// Dibuja el fondo de la notificación
SDL_SetRenderDrawColor(renderer, bgColor.r, bgColor.g, bgColor.b, 255);
SDL_Rect rect;
if (shape == NotificationShape::ROUNDED)
{
rect = {4, 0, width - (4 * 2), height};
SDL_RenderFillRect(renderer, &rect);
rect = {4 / 2, 1, width - 4, height - 2};
SDL_RenderFillRect(renderer, &rect);
rect = {1, 4 / 2, width - 2, height - 4};
SDL_RenderFillRect(renderer, &rect);
rect = {0, 4, width, height - (4 * 2)};
SDL_RenderFillRect(renderer, &rect);
}
else if (shape == NotificationShape::SQUARED)
{
SDL_RenderClear(renderer);
}
// Dibuja el icono de la notificación
if (hasIcons && icon >= 0 && numTexts == 2)
{
auto sp = std::make_unique<Sprite>((SDL_Rect){0, 0, iconSize, iconSize}, iconTexture);
sp->setPos({paddingIn, paddingIn, iconSize, iconSize});
sp->setSpriteClip({iconSize * (icon % 10), iconSize * (icon / 10), iconSize, iconSize});
sp->render();
}
// Escribe el texto de la notificación
Color color = {255, 255, 255};
if (numTexts == 2)
{ // Dos lineas de texto
text->writeColored(paddingIn + iconSpace, paddingIn, text1, color);
text->writeColored(paddingIn + iconSpace, paddingIn + text->getCharacterSize() + 1, text2, color);
}
else
{ // Una linea de texto
text->writeColored(paddingIn + iconSpace, paddingIn, text1, color);
}
// Deja de dibujar en la textura
SDL_SetRenderTarget(renderer, nullptr);
// Crea el sprite de la notificación
n.sprite = std::make_shared<Sprite>(n.rect, n.texture);
// Deja la notificación invisible
n.texture->setAlpha(0);
// Añade la notificación a la lista
notifications.push_back(n);
}
// Indica si hay notificaciones activas
bool Notify::active()
{
if ((int)notifications.size() > 0)
{
return true;
}
return false;
}
// Finaliza y elimnina todas las notificaciones activas
void Notify::clearNotifications()
{
for (int i = 0; i < (int)notifications.size(); ++i)
{
notifications[i].status = NotificationStatus::FINISHED;
}
clearFinishedNotifications();
}

View File

@@ -1,96 +0,0 @@
#pragma once
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_render.h> // for SDL_Renderer
#include <string> // for basic_string, string
#include <vector> // for vector
#include <memory>
#include "utils.h" // for Color
#include "text.h"
#include "texture.h"
#include "sprite.h"
struct JA_Sound_t;
class Notify
{
private:
enum class NotificationStatus
{
RISING,
STAY,
VANISHING,
FINISHED,
};
enum class NotificationPosition
{
UPPER_LEFT,
UPPER_CENTER,
UPPER_RIGHT,
MIDDLE_LEFT,
MIDDLE_RIGHT,
BOTTOM_LEFT,
BOTTOM_CENTER,
BOTTOM_RIGHT,
};
enum class NotificationShape
{
ROUNDED,
SQUARED,
};
struct Notification
{
std::shared_ptr<Texture> texture;
std::shared_ptr<Sprite> sprite;
std::string text1;
std::string text2;
int counter;
NotificationStatus status;
NotificationPosition position;
NotificationShape shape;
SDL_Rect rect;
int y;
int travelDist;
};
// Objetos y punteros
SDL_Renderer *renderer; // El renderizador de la ventana
std::shared_ptr<Texture> iconTexture; // Textura para los iconos de las notificaciones
std::unique_ptr<Text> text; // Objeto para dibujar texto
// Variables
Color bgColor; // Color de fondo de las notificaciones
int waitTime; // Tiempo que se ve la notificación
std::vector<Notification> notifications; // La lista de notificaciones activas
JA_Sound_t *sound; // Sonido a reproducir cuando suena la notificación
bool stack; // Indica si las notificaciones se apilan
bool hasIcons; // Indica si el notificador tiene textura para iconos
// Elimina las notificaciones finalizadas
void clearFinishedNotifications();
// Finaliza y elimnina todas las notificaciones activas
void clearNotifications();
public:
// Constructor
Notify(SDL_Renderer *renderer, std::string iconFile, std::string bitmapFile, std::string textFile, std::string soundFile);
// Destructor
~Notify();
// Dibuja las notificaciones por pantalla
void render();
// Actualiza el estado de las notificaiones
void update();
// Muestra una notificación de texto por pantalla;
void showText(std::string text1 = "", std::string text2 = "", int icon = -1);
// Indica si hay notificaciones activas
bool active();
};

View File

@@ -1,16 +1,16 @@
#include "on_screen_help.h"
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND
#include <SDL2/SDL_pixels.h> // for SDL_PIXELFORMAT_RGBA8888
#include <memory> // for make_unique, unique_ptr
#include <string> // for basic_string
#include <memory> // for make_unique, make_shared, unique_ptr
#include "asset.h" // for Asset
#include "lang.h" // for getText
#include "param.h" // for param
#include "resource.h" // for Resource
#include "screen.h" // for Screen
#include "sprite.h" // for Sprite
#include "text.h" // for Text
#include "texture.h" // for Texture
#include "utils.h" // for easeInOutSine, ParamGame, Param
#include "utils.h" // for easeInOutSine, Param, ParamGame
// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado
OnScreenHelp *OnScreenHelp::onScreenHelp = nullptr;
@@ -96,13 +96,13 @@ void OnScreenHelp::fillTexture()
SDL_SetRenderTarget(Screen::get()->getRenderer(), texture);
// Crea el objeto para el texto
auto text = std::make_unique<Text>(Asset::get()->get("8bithud.png"), Asset::get()->get("8bithud.txt"), Screen::get()->getRenderer());
auto text = std::make_unique<Text>(Resource::get()->getTexture("8bithud.png"), Resource::get()->getTextFile("8bithud.txt"));
// Crea la textura con los gráficos
auto controllersTexture = std::make_shared<Texture>(Screen::get()->getRenderer(), Asset::get()->get("controllers.png"));
auto controllersTexture = Resource::get()->getTexture("controllers.png");
// Crea el sprite para dibujar los gráficos
auto sprite = std::make_unique<Sprite>((SDL_Rect){0, 0, 16, 16}, controllersTexture);
auto sprite = std::make_unique<Sprite>(controllersTexture, (SDL_Rect){0, 0, 16, 16});
// Borra la textura
SDL_SetRenderDrawColor(Screen::get()->getRenderer(), 0, 0, 0, 0);
@@ -171,7 +171,7 @@ void OnScreenHelp::toggleState()
// Calcula la longitud en pixels del texto más largo
auto OnScreenHelp::getLargestStringSize() -> int const
{
auto text = std::make_unique<Text>(Asset::get()->get("8bithud.png"), Asset::get()->get("8bithud.txt"), Screen::get()->getRenderer());
auto text = std::make_unique<Text>(Resource::get()->getTexture("8bithud.png"), Resource::get()->getTextFile("8bithud.txt"));
auto size = 0;
for (int i = 107; i <= 113; ++i)
@@ -187,7 +187,7 @@ auto OnScreenHelp::getLargestStringSize() -> int const
void OnScreenHelp::renderButton(Sprite *sprite, Text *text, const SDL_Rect &buttonClip, const SDL_Rect &buttonPos, int textId)
{
sprite->setSpriteClip(buttonClip);
sprite->setPos(buttonPos);
sprite->setPosition(buttonPos);
sprite->render();
text->write(buttonPos.x + DESP.x, buttonPos.y + DESP.y, lang::getText(textId));
}

View File

@@ -1,11 +1,10 @@
#pragma once
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_render.h> // for SDL_Texture
#include <vector> // for vector
#include <memory>
#include "sprite.h" // lines 10-10
#include "text.h"
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_render.h> // for SDL_Texture
#include <vector> // for vector
class Sprite;
class Text;
enum class OnScreenHelpStatus
{

View File

@@ -13,7 +13,7 @@
Options options;
// Declaraciones
bool setOptions(std::string var, std::string value);
bool setOptions(const std::string &var, const std::string &value);
// Inicializa las opciones del programa
void initOptions()
@@ -39,7 +39,7 @@ void initOptions()
// Opciones de juego
options.game.difficulty = GameDifficulty::NORMAL;
options.game.language = lang::ba_BA;
options.game.language = lang::Code::ba_BA;
options.game.autofire = true;
// Opciones de control
@@ -57,11 +57,11 @@ void initOptions()
// Inputs que se guardan en las opciones y, por tanto, a disco
c.inputs.clear();
c.inputs.push_back(input_fire_left);
c.inputs.push_back(input_fire_center);
c.inputs.push_back(input_fire_right);
c.inputs.push_back(input_start);
c.inputs.push_back(input_service);
c.inputs.push_back(InputType::FIRE_LEFT);
c.inputs.push_back(InputType::FIRE_CENTER);
c.inputs.push_back(InputType::FIRE_RIGHT);
c.inputs.push_back(InputType::START);
c.inputs.push_back(InputType::SERVICE);
// Botones asociados a los inputs anteriores
c.buttons.clear();
@@ -93,9 +93,7 @@ bool loadOptionsFile(std::string file_path)
if (file.good())
{
// Procesa el fichero linea a linea
#ifdef VERBOSE
std::cout << "Reading file: " << file_name << std::endl;
#endif
std::string line;
while (std::getline(file, line))
{
@@ -107,10 +105,8 @@ bool loadOptionsFile(std::string file_path)
// Procesa las dos subcadenas
if (!setOptions(line.substr(0, pos), line.substr(pos + 1, line.length())))
{
#ifdef VERBOSE
std::cout << "Warning: file " << file_name << std::endl;
std::cout << "Unknown parameter " << line.substr(0, pos).c_str() << std::endl;
#endif
success = false;
}
}
@@ -139,9 +135,9 @@ bool loadOptionsFile(std::string file_path)
options.video.window.size = 3;
}
if (options.game.language < 0 || options.game.language > 2)
if (options.game.language != lang::Code::en_UK && options.game.language != lang::Code::ba_BA && options.game.language != lang::Code::es_ES)
{
options.game.language = lang::en_UK;
options.game.language = lang::Code::en_UK;
}
return success;
@@ -155,15 +151,11 @@ bool saveOptionsFile(std::string file_path)
if (!file.good())
{
#ifdef VERBOSE
std::cout << file_name << " can't be opened" << std::endl;
#endif
return false;
}
#ifdef VERBOSE
std::cout << "Writing file: " << file_name << std::endl;
#endif
// Opciones de video
const auto value_video_mode_winow = std::to_string(static_cast<int>(ScreenVideoMode::WINDOW));
@@ -207,7 +199,7 @@ bool saveOptionsFile(std::string file_path)
file << "## game.difficulty [" << value_difficulty_easy << ": easy, " << value_difficulty_normal << ": normal, " << value_difficulty_hard << ": hard]\n";
file << "\n";
file << "game.language=" + std::to_string(options.game.language) + "\n";
file << "game.language=" + std::to_string(static_cast<int>(options.game.language)) + "\n";
file << "game.difficulty=" + std::to_string(static_cast<int>(options.game.difficulty)) + "\n";
file << "game.autofire=" + boolToString(options.game.autofire) + "\n";
@@ -240,10 +232,10 @@ bool saveOptionsFile(std::string file_path)
}
// Asigna variables a partir de dos cadenas
bool setOptions(std::string var, std::string value)
bool setOptions(const std::string &var, const std::string &value)
{
// Indicador de éxito en la asignación
bool success = true;
auto success = true;
// Opciones de video
if (var == "video.mode")
@@ -304,7 +296,7 @@ bool setOptions(std::string var, std::string value)
// Opciones de juego
else if (var == "game.language")
{
options.game.language = std::stoi(value);
options.game.language = static_cast<lang::Code>(std::stoi(value));
}
else if (var == "game.difficulty")
@@ -389,7 +381,7 @@ bool setOptions(std::string var, std::string value)
}
// Lineas vacias o que empiezan por comentario
else if (var == "" || var.substr(0, 1) == "#")
else if (var.empty() || var.starts_with("#"))
{
}

View File

@@ -1,12 +1,15 @@
#include "param.h"
#include <fstream> // for char_traits, basic_ostream, basic_ifstream, basi...
#include <iostream> // for cout
#include "utils.h" // for Param, ParamGame, Zone, ParamBalloon
#include <sstream>
#include <string>
#include <stdexcept>
#include "utils.h" // for Param, ParamGame, Zone, ParamBalloon
Param param;
// Asigna variables a partir de dos cadenas
bool setParams(std::string var, std::string value);
bool setParams(const std::string &var, const std::string &value);
// Calcula variables a partir de otras variables
void precalculateZones();
@@ -40,7 +43,7 @@ void initParam()
param.title.title_c_c_position = 11;
// BACKGROUND
param.background.attenuate_color = {255, 255, 255};
param.background.attenuate_color = (Color){255, 255, 255};
param.background.attenuate_alpha = 32;
// BALLOONS
@@ -52,110 +55,62 @@ void initParam()
param.balloon_3.grav = 0.10f;
param.balloon_4.vel = 4.95f;
param.balloon_4.grav = 0.10f;
// NOTIFICATION
param.notification.pos_v = NotifyPosition::TOP;
param.notification.pos_h = NotifyPosition::LEFT;
param.notification.sound = false;
param.notification.color.r = 48;
param.notification.color.g = 48;
param.notification.color.b = 48;
}
// Establece valores para los parametros a partir de un fichero de texto
void loadParamsFromFile(std::string filePath)
void loadParamsFromFile(const std::string &file_path)
{
// Pone valores por defecto a las variables
// Inicializa los parámetros con valores por defecto
initParam();
// Variables para manejar el fichero
std::ifstream file(filePath);
std::string line;
std::string param1;
std::string param2;
// Si el fichero se puede abrir
if (file.good())
// Abre el archivo
std::ifstream file(file_path);
if (!file.is_open())
{
#ifdef VERBOSE
const std::string filename = filePath.substr(filePath.find_last_of("\\/") + 1);
std::cout << "Reading file: " << filename << std::endl;
#endif
// Procesa cada linea del fichero
while (std::getline(file, line))
std::cerr << "Error: No se pudo abrir el archivo " << file_path << std::endl;
throw std::runtime_error("No se pudo abrir el archivo: " + file_path);
}
const std::string file_name = file_path.substr(file_path.find_last_of("\\/") + 1);
std::cout << "Reading file: " << file_name << std::endl;
std::string line, param1, param2;
while (std::getline(file, line))
{
// Elimina comentarios
auto comment_pos = line.find('#');
if (comment_pos != std::string::npos)
{
// Reinicia variables
param1 = "";
param2 = "";
// Elimina los comentarios
line = line.substr(0, line.find("#"));
// Ignora los espacios en blanco
int pos = 0;
while (pos < (int)line.size() && (int)line[pos] <= 32)
{
pos++;
}
// Si no ha llegado al final de la linea, es que hay algo escrito (no es una linea vacía)
if (pos < (int)line.size())
{
// Elimina el espacio en blanco
line = line.substr(pos, std::string::npos);
// Se queda con todo lo que no sean espacios en blanco
pos = 1;
while (pos <= (int)line.size() && (int)line[pos] > 32)
{
pos++;
}
// Si llega al final de la linea, falta la segunda palabra
if (pos < (int)line.size())
{
// Se queda con la primera palabra
param1 = line.substr(0, pos);
// Y recorta la linea
line = line.substr(pos, std::string::npos);
// Ignora los espacios en blanco
pos = 0;
while (pos <= (int)line.size() && (int)line[pos] <= 32)
{
pos++;
}
// Si llega al final de la linea, falta la segunda palabra
if (pos < (int)line.size())
{
// Elimina el espacio en blanco
line = line.substr(pos, std::string::npos);
// Ignora los espacios en blanco
pos = 1;
while (pos <= (int)line.size() && (int)line[pos] > 32)
{
pos++;
}
// Se queda con la segunda palabra
param2 = line.substr(0, pos);
}
}
}
setParams(param1, param2);
line.resize(comment_pos);
}
// Cierra el fichero
file.close();
// Usa un stream para separar palabras
std::istringstream iss(line);
if (iss >> param1 >> param2)
{
setParams(param1, param2);
}
}
#ifdef VERBOSE
else
std::cout << "Failed to load file: " << filePath << std::endl;
#endif
// Cierra el archivo
file.close();
// Realiza cálculos adicionales después de cargar los parámetros
precalculateZones();
}
// Asigna variables a partir de dos cadenas
bool setParams(std::string var, std::string value)
bool setParams(const std::string &var, const std::string &value)
{
// Indicador de éxito en la asignación
bool success = true;
auto success = true;
// GAME
if (var == "game.width")
@@ -193,6 +148,11 @@ bool setParams(std::string var, std::string value)
param.game.play_area.rect.h = std::stoi(value);
}
else if (var == "game.enter_name_seconds")
{
param.game.enter_name_seconds = std::stoi(value);
}
// FADE
else if (var == "fade.num_squares_width")
{

View File

@@ -6,4 +6,4 @@ struct Param;
extern Param param;
// Establece valores para los parametros a partir de un fichero de texto
void loadParamsFromFile(std::string file_path);
void loadParamsFromFile(const std::string &file_path);

View File

@@ -3,7 +3,7 @@
#include <SDL2/SDL_timer.h> // for SDL_GetTicks
#include <stdlib.h> // for rand
#include <algorithm> // for max, min
#include "animated_sprite.h" // for AnimatedSprite
#include "animated_sprite.h" // for SpriteAnimated
#include "input.h" // for inputs_e
#include "param.h" // for param
#include "texture.h" // for Texture
@@ -11,32 +11,31 @@
#include "options.h"
// Constructor
Player::Player(int id, float x, int y, bool demo, SDL_Rect *playArea, std::vector<std::shared_ptr<Texture>> texture, std::vector<std::vector<std::string> *> animations)
Player::Player(int id, float x, int y, bool demo, SDL_Rect *play_area, std::vector<std::shared_ptr<Texture>> texture, const std::vector<std::vector<std::string>> &animations)
: player_sprite_(std::make_unique<AnimatedSprite>(texture[0], animations[0])),
power_sprite_(std::make_unique<AnimatedSprite>(texture[1], animations[1])),
enter_name_(std::make_unique<EnterName>()),
play_area_(play_area),
id_(id),
pos_x_(x),
pos_y_(y),
default_pos_x_(x),
default_pos_y_(y),
status_playing_(PlayerStatus::WAITING),
scoreboard_panel_(0),
name_(std::string()),
controller_index_(0),
demo_(demo)
{
// Reserva memoria para los objetos
playerSprite = std::make_unique<AnimatedSprite>(texture[0], "", animations[0]);
powerSprite = std::make_unique<AnimatedSprite>(texture[1], "", animations[1]);
powerSprite->getTexture()->setAlpha(224);
enterName = std::make_unique<EnterName>();
// Rectangulo con la zona de juego
this->playArea = playArea;
// Establece la posición inicial del jugador
defaultPosX = posX = x;
defaultPosY = posY = y;
power_sprite_->getTexture()->setAlpha(224);
// Establece los offsets para el sprite de PowerUp
powerUpDespX = (powerSprite->getWidth() - playerSprite->getWidth()) / 2;
powerSprite->setPosY(y - (powerSprite->getHeight() - playerSprite->getHeight()));
power_up_desp_x_ = (power_sprite_->getWidth() - player_sprite_->getWidth()) / 2;
power_sprite_->setPosY(y - (power_sprite_->getHeight() - player_sprite_->getHeight()));
// Inicializa variables
this->id = id;
this->demo = demo;
statusPlaying = PlayerStatus::WAITING;
scoreBoardPanel = 0;
name = "";
setRecordName(enterName->getName());
setRecordName(enter_name_->getName());
init();
}
@@ -44,50 +43,57 @@ Player::Player(int id, float x, int y, bool demo, SDL_Rect *playArea, std::vecto
void Player::init()
{
// Inicializa variables de estado
posX = defaultPosX;
posY = defaultPosY;
statusWalking = PlayerStatus::WALKING_STOP;
statusFiring = PlayerStatus::FIRING_NO;
invulnerable = true;
invulnerableCounter = PLAYER_INVULNERABLE_COUNTER;
powerUp = false;
powerUpCounter = PLAYER_POWERUP_COUNTER;
extraHit = false;
coffees = 0;
input = true;
continueTicks = 0;
continueCounter = 20;
width = 30;
height = 30;
collider.r = 9;
pos_x_ = default_pos_x_;
pos_y_ = default_pos_y_;
status_walking_ = PlayerStatus::WALKING_STOP;
status_firing_ = PlayerStatus::FIRING_NO;
invulnerable_ = true;
invulnerable_counter_ = PLAYER_INVULNERABLE_COUNTER;
power_up_ = false;
power_up_counter_ = PLAYER_POWERUP_COUNTER;
extra_hit_ = false;
coffees_ = 0;
input_ = true;
continue_ticks_ = 0;
continue_counter_ = 10;
enter_name_ticks_ = 0;
enter_name_counter_ = param.game.enter_name_seconds;
width_ = 30;
height_ = 30;
collider_.r = 9;
shiftColliders();
velX = 0;
velY = 0;
baseSpeed = 1.5;
score = 0;
scoreMultiplier = 1.0f;
cooldown = 10;
vel_x_ = 0;
vel_y_ = 0;
base_speed_ = 1.5;
score_ = 0;
score_multiplier_ = 1.0f;
cooldown_ = 10;
// Establece la posición del sprite
playerSprite->setPosX(posX);
playerSprite->setPosY(posY);
player_sprite_->clear();
player_sprite_->setPosX(pos_x_);
player_sprite_->setPosY(pos_y_);
// Selecciona un frame para pintar
playerSprite->setCurrentAnimation("stand");
player_sprite_->setCurrentAnimation("stand");
}
// Actua en consecuencia de la entrada recibida
void Player::setInput(int input)
void Player::setInput(InputType input)
{
switch (statusPlaying)
switch (status_playing_)
{
case PlayerStatus::PLAYING:
{
setInputPlaying(input);
break;
}
case PlayerStatus::ENTERING_NAME:
{
setInputEnteringName(input);
break;
}
default:
break;
@@ -95,68 +101,80 @@ void Player::setInput(int input)
}
// Procesa inputs para cuando está jugando
void Player::setInputPlaying(int input)
void Player::setInputPlaying(InputType input)
{
switch (input)
{
case input_left:
velX = -baseSpeed;
case InputType::LEFT:
{
vel_x_ = -base_speed_;
setWalkingStatus(PlayerStatus::WALKING_LEFT);
break;
}
case input_right:
velX = baseSpeed;
case InputType::RIGHT:
{
vel_x_ = base_speed_;
setWalkingStatus(PlayerStatus::WALKING_RIGHT);
break;
}
case input_fire_center:
case InputType::FIRE_CENTER:
{
setFiringStatus(PlayerStatus::FIRING_UP);
break;
}
case input_fire_left:
case InputType::FIRE_LEFT:
{
setFiringStatus(PlayerStatus::FIRING_LEFT);
break;
}
case input_fire_right:
case InputType::FIRE_RIGHT:
{
setFiringStatus(PlayerStatus::FIRING_RIGHT);
break;
}
default:
velX = 0;
{
vel_x_ = 0;
setWalkingStatus(PlayerStatus::WALKING_STOP);
break;
}
}
}
// Procesa inputs para cuando está introduciendo el nombre
void Player::setInputEnteringName(int input)
void Player::setInputEnteringName(InputType input)
{
switch (input)
{
case input_left:
enterName->decPos();
case InputType::LEFT:
enter_name_->decPosition();
break;
case input_right:
enterName->incPos();
case InputType::RIGHT:
enter_name_->incPosition();
break;
case input_up:
enterName->incIndex();
case InputType::UP:
enter_name_->incIndex();
break;
case input_down:
enterName->decIndex();
case InputType::DOWN:
enter_name_->decIndex();
break;
case input_start:
setRecordName(enterName->getName());
case InputType::START:
setRecordName(enter_name_->getName());
break;
default:
break;
}
setRecordName(enterName->getName());
setRecordName(enter_name_->getName());
}
// Mueve el jugador a la posición y animación que le corresponde
@@ -165,38 +183,38 @@ void Player::move()
if (isPlaying())
{
// Mueve el jugador a derecha o izquierda
posX += velX;
pos_x_ += vel_x_;
// Si el jugador abandona el area de juego por los laterales
if ((posX < param.game.play_area.rect.x - 5) || (posX + width > playArea->w + 5))
if ((pos_x_ < param.game.play_area.rect.x - 5) || (pos_x_ + width_ > play_area_->w + 5))
{
// Restaura su posición
posX -= velX;
pos_x_ -= vel_x_;
}
// Actualiza la posición del sprite
playerSprite->setPosX(getPosX());
playerSprite->setPosY(posY);
player_sprite_->setPosX(getPosX());
player_sprite_->setPosY(pos_y_);
powerSprite->setPosX(getPosX() - powerUpDespX);
power_sprite_->setPosX(getPosX() - power_up_desp_x_);
}
else if (isDying())
{
playerSprite->update();
player_sprite_->update();
// Si el cadaver abandona el area de juego por los laterales
if ((playerSprite->getPosX() < param.game.play_area.rect.x) || (playerSprite->getPosX() + width > playArea->w))
if ((player_sprite_->getPosX() < param.game.play_area.rect.x) || (player_sprite_->getPosX() + width_ > play_area_->w))
{
// Restaura su posición
const float vx = playerSprite->getVelX();
playerSprite->setPosX(playerSprite->getPosX() - vx);
const float vx = player_sprite_->getVelX();
player_sprite_->setPosX(player_sprite_->getPosX() - vx);
// Rebota
playerSprite->setVelX(-vx);
player_sprite_->setVelX(-vx);
}
// Si el cadaver abandona el area de juego por abajo
if (playerSprite->getPosY() > param.game.play_area.rect.h)
if (player_sprite_->getPosY() > param.game.play_area.rect.h)
{
setStatusPlaying(PlayerStatus::DIED);
}
@@ -206,122 +224,114 @@ void Player::move()
// Pinta el jugador en pantalla
void Player::render()
{
if (powerUp && isPlaying())
if (power_up_ && isPlaying())
{
if (powerUpCounter > (PLAYER_POWERUP_COUNTER / 4) || powerUpCounter % 20 > 4)
if (power_up_counter_ > (PLAYER_POWERUP_COUNTER / 4) || power_up_counter_ % 20 > 4)
{
powerSprite->render();
power_sprite_->render();
}
}
if (isRenderable())
playerSprite->render();
player_sprite_->render();
}
// Establece el estado del jugador cuando camina
void Player::setWalkingStatus(PlayerStatus status)
{
// Si cambiamos de estado, reiniciamos la animación
if (statusWalking != status)
{
statusWalking = status;
}
status_walking_ = status;
}
// Establece el estado del jugador cuando dispara
void Player::setFiringStatus(PlayerStatus status)
{
// Si cambiamos de estado, reiniciamos la animación
if (statusFiring != status)
{
statusFiring = status;
}
status_firing_ = status;
}
// Establece la animación correspondiente al estado
void Player::setAnimation()
{
// Crea cadenas de texto para componer el nombre de la animación
const std::string aWalking = statusWalking == PlayerStatus::WALKING_STOP ? "stand" : "walk";
const std::string aFiring = statusFiring == PlayerStatus::FIRING_UP ? "centershoot" : "sideshoot";
const std::string a_walking = status_walking_ == PlayerStatus::WALKING_STOP ? "stand" : "walk";
const std::string a_firing = status_firing_ == PlayerStatus::FIRING_UP ? "centershoot" : "sideshoot";
const SDL_RendererFlip flipWalk = statusWalking == PlayerStatus::WALKING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
const SDL_RendererFlip flipFire = statusFiring == PlayerStatus::FIRING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
const SDL_RendererFlip flip_walk = status_walking_ == PlayerStatus::WALKING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
const SDL_RendererFlip flip_fire = status_firing_ == PlayerStatus::FIRING_RIGHT ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE;
// Establece la animación a partir de las cadenas
if (isPlaying())
{
if (statusFiring == PlayerStatus::FIRING_NO)
if (status_firing_ == PlayerStatus::FIRING_NO)
{ // No esta disparando
playerSprite->setCurrentAnimation(aWalking);
playerSprite->setFlip(flipWalk);
player_sprite_->setCurrentAnimation(a_walking);
player_sprite_->setFlip(flip_walk);
}
else
{ // Está disparando
playerSprite->setCurrentAnimation(aWalking + "-" + aFiring);
player_sprite_->setCurrentAnimation(a_walking + "-" + a_firing);
// Si dispara de lado, invierte el sprite segun hacia donde dispara
// Si dispara recto, invierte el sprite segun hacia donde camina
aFiring == "centershoot" ? playerSprite->setFlip(flipWalk) : playerSprite->setFlip(flipFire);
a_firing == "centershoot" ? player_sprite_->setFlip(flip_walk) : player_sprite_->setFlip(flip_fire);
}
}
else
{
playerSprite->setCurrentAnimation("death");
player_sprite_->setCurrentAnimation("death");
}
// Actualiza las animaciones de los sprites
playerSprite->animate();
player_sprite_->update();
// powerSprite->setFlip(flipWalk);
powerSprite->animate();
// powerSprite->setFlip(flip_walk);
power_sprite_->update();
}
// Obtiene el valor de la variable
int Player::getPosX() const
{
return int(posX);
return int(pos_x_);
}
// Obtiene el valor de la variable
int Player::getPosY() const
{
return posY;
return pos_y_;
}
// Obtiene el valor de la variable
int Player::getWidth() const
{
return width;
return width_;
}
// Obtiene el valor de la variable
int Player::getHeight() const
{
return height;
return height_;
}
// Indica si el jugador puede disparar
bool Player::canFire() const
{
// Si el contador a llegado a cero, podemos disparar. En caso contrario decrementamos el contador
return cooldown > 0 ? false : true;
return cooldown_ > 0 ? false : true;
}
// Establece el valor de la variable
void Player::setFireCooldown(int time)
{
cooldown = time;
cooldown_ = time;
}
// Actualiza el valor de la variable
void Player::updateCooldown()
{
if (cooldown > 0)
if (cooldown_ > 0)
{
cooldown--;
if (powerUp)
cooldown_--;
if (power_up_)
{
cooldown--;
cooldown_--;
}
}
else
@@ -337,22 +347,23 @@ void Player::update()
setAnimation();
shiftColliders();
updateCooldown();
updatePowerUpCounter();
updatePowerUp();
updateInvulnerable();
updateContinueCounter();
updateEnterNameCounter();
updateScoreboard();
}
// Obtiene la puntuación del jugador
int Player::getScore() const
{
return score;
return score_;
}
// Asigna un valor a la puntuación del jugador
void Player::setScore(int score)
{
this->score = score;
score_ = score;
}
// Incrementa la puntuación del jugador
@@ -360,56 +371,56 @@ void Player::addScore(int score)
{
if (isPlaying())
{
this->score += score;
score_ += score;
}
}
// Indica si el jugador está jugando
bool Player::isPlaying() const
{
return statusPlaying == PlayerStatus::PLAYING;
return status_playing_ == PlayerStatus::PLAYING;
}
// Indica si el jugador está continuando
bool Player::isContinue() const
{
return statusPlaying == PlayerStatus::CONTINUE;
return status_playing_ == PlayerStatus::CONTINUE;
}
// Indica si el jugador está esperando
bool Player::isWaiting() const
{
return statusPlaying == PlayerStatus::WAITING;
return status_playing_ == PlayerStatus::WAITING;
}
// Indica si el jugador está introduciendo su nombre
bool Player::isEnteringName() const
{
return statusPlaying == PlayerStatus::ENTERING_NAME;
return status_playing_ == PlayerStatus::ENTERING_NAME;
}
// Indica si el jugador está muriendose
bool Player::isDying() const
{
return statusPlaying == PlayerStatus::DYING;
return status_playing_ == PlayerStatus::DYING;
}
// Indica si el jugador ha terminado de morir
bool Player::hasDied() const
{
return statusPlaying == PlayerStatus::DIED;
return status_playing_ == PlayerStatus::DIED;
}
// Indica si el jugador ya ha terminado de jugar
bool Player::isGameOver() const
{
return statusPlaying == PlayerStatus::GAME_OVER;
return status_playing_ == PlayerStatus::GAME_OVER;
}
// Actualiza el panel del marcador
void Player::updateScoreboard()
{
switch (statusPlaying)
switch (status_playing_)
{
case PlayerStatus::CONTINUE:
@@ -433,7 +444,7 @@ void Player::updateScoreboard()
// Cambia el modo del marcador
void Player::setScoreboardMode(ScoreboardMode mode)
{
if (!demo)
if (!demo_)
{
Scoreboard::get()->setMode(getScoreBoardPanel(), mode);
}
@@ -442,13 +453,13 @@ void Player::setScoreboardMode(ScoreboardMode mode)
// Establece el estado del jugador en el juego
void Player::setStatusPlaying(PlayerStatus value)
{
statusPlaying = value;
status_playing_ = value;
switch (statusPlaying)
switch (status_playing_)
{
case PlayerStatus::PLAYING:
{
statusPlaying = PlayerStatus::PLAYING;
status_playing_ = PlayerStatus::PLAYING;
init();
setScoreboardMode(ScoreboardMode::SCORE);
break;
@@ -457,9 +468,9 @@ void Player::setStatusPlaying(PlayerStatus value)
case PlayerStatus::CONTINUE:
{
// Inicializa el contador de continuar
continueTicks = SDL_GetTicks();
continueCounter = 9;
enterName->init();
continue_ticks_ = SDL_GetTicks();
continue_counter_ = 9;
enter_name_->init();
setScoreboardMode(ScoreboardMode::CONTINUE);
break;
}
@@ -479,16 +490,16 @@ void Player::setStatusPlaying(PlayerStatus value)
case PlayerStatus::DYING:
{
// Activa la animación de morir
playerSprite->setAccelY(0.2f);
playerSprite->setVelY(-6.6f);
rand() % 2 == 0 ? playerSprite->setVelX(3.3f) : playerSprite->setVelX(-3.3f);
player_sprite_->setAccelY(0.2f);
player_sprite_->setVelY(-6.6f);
rand() % 2 == 0 ? player_sprite_->setVelX(3.3f) : player_sprite_->setVelX(-3.3f);
break;
}
case PlayerStatus::DIED:
{
const auto nextPlayerStatus = IsEligibleForHighScore() ? PlayerStatus::ENTERING_NAME : PlayerStatus::CONTINUE;
demo ? setStatusPlaying(PlayerStatus::WAITING) : setStatusPlaying(nextPlayerStatus);
demo_ ? setStatusPlaying(PlayerStatus::WAITING) : setStatusPlaying(nextPlayerStatus);
break;
}
@@ -506,74 +517,74 @@ void Player::setStatusPlaying(PlayerStatus value)
// Obtiene el estado del jugador en el juego
PlayerStatus Player::getStatusPlaying() const
{
return statusPlaying;
return status_playing_;
}
// Obtiene el valor de la variable
float Player::getScoreMultiplier() const
{
return scoreMultiplier;
return score_multiplier_;
}
// Establece el valor de la variable
void Player::setScoreMultiplier(float value)
{
scoreMultiplier = value;
score_multiplier_ = value;
}
// Aumenta el valor de la variable hasta un máximo
void Player::incScoreMultiplier()
{
scoreMultiplier += 0.1f;
scoreMultiplier = std::min(scoreMultiplier, 5.0f);
score_multiplier_ += 0.1f;
score_multiplier_ = std::min(score_multiplier_, 5.0f);
}
// Decrementa el valor de la variable hasta un mínimo
void Player::decScoreMultiplier()
{
scoreMultiplier -= 0.1f;
scoreMultiplier = std::max(scoreMultiplier, 1.0f);
score_multiplier_ -= 0.1f;
score_multiplier_ = std::max(score_multiplier_, 1.0f);
}
// Obtiene el valor de la variable
bool Player::isInvulnerable() const
{
return invulnerable;
return invulnerable_;
}
// Establece el valor del estado
void Player::setInvulnerable(bool value)
{
invulnerable = value;
invulnerableCounter = invulnerable ? PLAYER_INVULNERABLE_COUNTER : 0;
invulnerable_ = value;
invulnerable_counter_ = invulnerable_ ? PLAYER_INVULNERABLE_COUNTER : 0;
}
// Obtiene el valor de la variable
int Player::getInvulnerableCounter() const
{
return invulnerableCounter;
return invulnerable_counter_;
}
// Establece el valor de la variable
void Player::setInvulnerableCounter(int value)
{
invulnerableCounter = value;
invulnerable_counter_ = value;
}
// Monitoriza el estado
void Player::updateInvulnerable()
{
if (invulnerable)
if (invulnerable_)
{
if (invulnerableCounter > 0)
if (invulnerable_counter_ > 0)
{
invulnerableCounter--;
invulnerableCounter % 8 > 3 ? playerSprite->getTexture()->setPalette(coffees) : playerSprite->getTexture()->setPalette(3);
--invulnerable_counter_;
invulnerable_counter_ % 8 > 3 ? player_sprite_->getTexture()->setPalette(coffees_) : player_sprite_->getTexture()->setPalette(3);
}
else
{
setInvulnerable(false);
playerSprite->getTexture()->setPalette(coffees);
player_sprite_->getTexture()->setPalette(coffees_);
}
}
}
@@ -581,183 +592,205 @@ void Player::updateInvulnerable()
// Obtiene el valor de la variable
bool Player::isPowerUp() const
{
return powerUp;
return power_up_;
}
// Establece el valor de la variable
void Player::setPowerUp()
{
powerUp = true;
powerUpCounter = PLAYER_POWERUP_COUNTER;
power_up_ = true;
power_up_counter_ = PLAYER_POWERUP_COUNTER;
}
// Obtiene el valor de la variable
int Player::getPowerUpCounter() const
{
return powerUpCounter;
return power_up_counter_;
}
// Establece el valor de la variable
void Player::setPowerUpCounter(int value)
{
powerUpCounter = value;
power_up_counter_ = value;
}
// Actualiza el valor de la variable
void Player::updatePowerUpCounter()
void Player::updatePowerUp()
{
if ((powerUpCounter > 0) && (powerUp))
if (power_up_)
{
powerUpCounter--;
}
else
{
powerUp = false;
// powerUpCounter = PLAYER_POWERUP_COUNTER;
--power_up_counter_;
power_up_ = power_up_counter_ > 0;
}
}
// Obtiene el valor de la variable
bool Player::hasExtraHit() const
{
return extraHit;
return extra_hit_;
}
// Concede un toque extra al jugador
void Player::giveExtraHit()
{
extraHit = true;
if (coffees < 2)
extra_hit_ = true;
if (coffees_ < 2)
{
coffees++;
playerSprite->getTexture()->setPalette(coffees);
coffees_++;
player_sprite_->getTexture()->setPalette(coffees_);
}
}
// Quita el toque extra al jugador
void Player::removeExtraHit()
{
if (coffees > 0)
if (coffees_ > 0)
{
coffees--;
coffees_--;
setInvulnerable(true);
playerSprite->getTexture()->setPalette(coffees);
player_sprite_->getTexture()->setPalette(coffees_);
}
extraHit = coffees == 0 ? false : true;
extra_hit_ = coffees_ == 0 ? false : true;
}
// Habilita la entrada de ordenes
void Player::enableInput()
{
input = true;
input_ = true;
}
// Deshabilita la entrada de ordenes
void Player::disableInput()
{
input = false;
input_ = false;
}
// Devuelve el número de cafes actuales
int Player::getCoffees() const
{
return coffees;
return coffees_;
}
// Obtiene el circulo de colisión
Circle &Player::getCollider()
{
return collider;
return collider_;
}
// Actualiza el circulo de colisión a la posición del jugador
void Player::shiftColliders()
{
collider.x = int(posX + (width / 2));
collider.y = int(posY + (height / 2));
collider_.x = int(pos_x_ + (width_ / 2));
collider_.y = int(pos_y_ + (height_ / 2));
}
// Pone las texturas del jugador
void Player::setPlayerTextures(std::vector<std::shared_ptr<Texture>> texture)
void Player::setPlayerTextures(const std::vector<std::shared_ptr<Texture>> &texture)
{
playerSprite->setTexture(texture[0]);
powerSprite->setTexture(texture[1]);
player_sprite_->setTexture(texture[0]);
power_sprite_->setTexture(texture[1]);
}
// Obtiene el valor de la variable
int Player::getContinueCounter() const
{
return continueCounter;
return continue_counter_;
}
// Actualiza el contador de continue
void Player::updateContinueCounter()
{
if (statusPlaying == PlayerStatus::CONTINUE)
if (status_playing_ == PlayerStatus::CONTINUE)
{
const Uint32 ticksSpeed = 1000;
constexpr Uint32 ticks_speed = 1000;
if (SDL_GetTicks() - continueTicks > ticksSpeed)
if (SDL_GetTicks() - continue_ticks_ > ticks_speed)
{
decContinueCounter();
}
}
}
// Actualiza el contador de entrar nombre
void Player::updateEnterNameCounter()
{
if (status_playing_ == PlayerStatus::ENTERING_NAME)
{
constexpr Uint32 ticks_speed = 1000;
if (SDL_GetTicks() - enter_name_ticks_ > ticks_speed)
{
decEnterNameCounter();
}
}
}
// Le asigna un panel en el marcador al jugador
void Player::setScoreBoardPanel(int panel)
{
scoreBoardPanel = panel;
scoreboard_panel_ = panel;
}
// Obtiene el valor de la variable
int Player::getScoreBoardPanel() const
{
return scoreBoardPanel;
return scoreboard_panel_;
}
// Decrementa el contador de continuar
void Player::decContinueCounter()
{
continueTicks = SDL_GetTicks();
continueCounter--;
if (continueCounter < 0)
continue_ticks_ = SDL_GetTicks();
--continue_counter_;
if (continue_counter_ < 0)
{
setStatusPlaying(PlayerStatus::GAME_OVER);
}
}
// Establece el nombre del jugador
void Player::setName(std::string name)
// Decrementa el contador de entrar nombre
void Player::decEnterNameCounter()
{
this->name = name;
enter_name_ticks_ = SDL_GetTicks();
--enter_name_counter_;
if (enter_name_counter_ < 0)
{
enter_name_counter_ = param.game.enter_name_seconds;
setStatusPlaying(PlayerStatus::CONTINUE);
}
}
// Establece el nombre del jugador
void Player::setName(const std::string &name)
{
name_ = name;
}
// Establece el nombre del jugador para la tabla de mejores puntuaciones
void Player::setRecordName(std::string recordName)
void Player::setRecordName(const std::string &record_name)
{
this->recordName = recordName.substr(0, 8);
record_name_ = record_name.substr(0, 8);
}
// Obtiene el nombre del jugador
std::string Player::getName() const
{
return name;
return name_;
}
// Obtiene el nombre del jugador para la tabla de mejores puntuaciones
std::string Player::getRecordName() const
{
return recordName;
return record_name_;
}
// Obtiene la posici´´on que se está editando del nombre del jugador para la tabla de mejores puntuaciones
int Player::getRecordNamePos() const
{
if (enterName)
if (enter_name_)
{
return enterName->getPos();
return enter_name_->getPosition();
}
return 0;
@@ -766,19 +799,19 @@ int Player::getRecordNamePos() const
// Establece el mando que usará para ser controlado
void Player::setController(int index)
{
controllerIndex = index;
controller_index_ = index;
}
// Obtiene el mando que usa para ser controlado
int Player::getController() const
{
return controllerIndex;
return controller_index_;
}
// Obtiene el "id" del jugador
int Player::getId() const
{
return id;
return id_;
}
// Indica si el jugador se puede dibujar
@@ -790,5 +823,5 @@ bool Player::isRenderable() const
// Comprueba si la puntuación entra en la tabla de mejores puntuaciones
bool Player::IsEligibleForHighScore()
{
return score > options.game.hi_score_table.back().score;
return score_ > options.game.hi_score_table.back().score;
}

View File

@@ -2,14 +2,16 @@
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_stdinc.h> // for Uint32
#include <memory> // for unique_ptr
#include <string> // for string, basic_string
#include <memory> // for unique_ptr, shared_ptr
#include <string> // for string
#include <vector> // for vector
#include "animated_sprite.h" // for AnimatedSprite
#include "animated_sprite.h" // for SpriteAnimated
#include "smart_sprite.h" // for SpriteAnimated
#include "enter_name.h" // for EnterName
#include "utils.h" // for Circle
#include "texture.h" // lines 12-12
enum class ScoreboardMode;
class Texture;
enum class InputType : int;
enum class ScoreboardMode; // lines 12-12
// Estados del jugador
enum class PlayerStatus
@@ -41,44 +43,46 @@ class Player
{
private:
// Objetos y punteros
std::unique_ptr<AnimatedSprite> playerSprite; // Sprite para dibujar el jugador
std::unique_ptr<AnimatedSprite> powerSprite; // Sprite para dibujar el aura del jugador con el poder a tope
std::unique_ptr<EnterName> enterName; // Clase utilizada para introducir el nombre
SDL_Rect *playArea; // Rectangulo con la zona de juego
std::unique_ptr<AnimatedSprite> player_sprite_; // Sprite para dibujar el jugador
std::unique_ptr<AnimatedSprite> power_sprite_; // Sprite para dibujar el aura del jugador con el poder a tope
std::unique_ptr<EnterName> enter_name_; // Clase utilizada para introducir el nombre
SDL_Rect *play_area_; // Rectangulo con la zona de juego
// Variables
int id; // Numero de identificación para el jugador
float posX; // Posicion en el eje X
int posY; // Posicion en el eje Y
float defaultPosX; // Posición inicial para el jugador
int defaultPosY; // Posición inicial para el jugador
int width; // Anchura
int height; // Altura
float velX; // Cantidad de pixeles a desplazarse en el eje X
int velY; // Cantidad de pixeles a desplazarse en el eje Y
float baseSpeed; // Velocidad base del jugador
int cooldown; // Contador durante el cual no puede disparar
int score; // Puntos del jugador
float scoreMultiplier; // Multiplicador de puntos
PlayerStatus statusWalking; // Estado del jugador al moverse
PlayerStatus statusFiring; // Estado del jugador al disparar
PlayerStatus statusPlaying; // Estado del jugador en el juego
bool invulnerable; // Indica si el jugador es invulnerable
int invulnerableCounter; // Contador para la invulnerabilidad
bool extraHit; // Indica si el jugador tiene un toque extra
int coffees; // Indica cuantos cafes lleva acumulados
bool powerUp; // Indica si el jugador tiene activo el modo PowerUp
int powerUpCounter; // Temporizador para el modo PowerUp
int powerUpDespX; // Desplazamiento del sprite de PowerUp respecto al sprite del jugador
bool input; // Indica si puede recibir ordenes de entrada
Circle collider; // Circulo de colisión del jugador
int continueCounter; // Contador para poder continuar
Uint32 continueTicks; // Variable para poder cambiar el contador de continue en función del tiempo
int scoreBoardPanel; // Panel del marcador asociado al jugador
std::string name; // Nombre del jugador
std::string recordName; // Nombre del jugador para l atabla de mejores puntuaciones
int controllerIndex; // Indice del array de mandos que utilizará para moverse
bool demo; // Para que el jugador sepa si está en el modo demostración
int id_; // Numero de identificación para el jugador. Player1 = 1, Player2 = 2
float pos_x_; // Posicion en el eje X
int pos_y_; // Posicion en el eje Y
float default_pos_x_; // Posición inicial para el jugador
int default_pos_y_; // Posición inicial para el jugador
int width_; // Anchura
int height_; // Altura
float vel_x_; // Cantidad de pixeles a desplazarse en el eje X
int vel_y_; // Cantidad de pixeles a desplazarse en el eje Y
float base_speed_; // Velocidad base del jugador
int cooldown_; // Contador durante el cual no puede disparar
int score_; // Puntos del jugador
float score_multiplier_; // Multiplicador de puntos
PlayerStatus status_walking_; // Estado del jugador al moverse
PlayerStatus status_firing_; // Estado del jugador al disparar
PlayerStatus status_playing_; // Estado del jugador en el juego
bool invulnerable_; // Indica si el jugador es invulnerable
int invulnerable_counter_; // Contador para la invulnerabilidad
bool extra_hit_; // Indica si el jugador tiene un toque extra
int coffees_; // Indica cuantos cafes lleva acumulados
bool power_up_; // Indica si el jugador tiene activo el modo PowerUp
int power_up_counter_; // Temporizador para el modo PowerUp
int power_up_desp_x_; // Desplazamiento del sprite de PowerUp respecto al sprite del jugador
bool input_; // Indica si puede recibir ordenes de entrada
Circle collider_; // Circulo de colisión del jugador
int continue_counter_; // Contador para poder continuar
Uint32 continue_ticks_; // Variable para poder cambiar el contador de continue en función del tiempo
int scoreboard_panel_; // Panel del marcador asociado al jugador
std::string name_; // Nombre del jugador
std::string record_name_; // Nombre del jugador para la tabla de mejores puntuaciones
int controller_index_; // Indice del array de mandos que utilizará para moverse
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_; // Variable para poder cambiar el contador de poner nombre en función del tiempo
// Actualiza el circulo de colisión a la posición del jugador
void shiftColliders();
@@ -89,6 +93,12 @@ private:
// Actualiza el contador de continue
void updateContinueCounter();
// Actualiza el contador de entrar nombre
void updateEnterNameCounter();
// Decrementa el contador de entrar nombre
void decEnterNameCounter();
// Indica si el jugador se puede dibujar
bool isRenderable() const;
@@ -103,7 +113,7 @@ private:
public:
// Constructor
Player(int id, float x, int y, bool demo, SDL_Rect *playArea, std::vector<std::shared_ptr<Texture>> texture, std::vector<std::vector<std::string> *> animations);
Player(int id, float x, int y, bool demo, SDL_Rect *play_area, std::vector<std::shared_ptr<Texture>> texture, const std::vector<std::vector<std::string>> &animations);
// Destructor
~Player() = default;
@@ -118,16 +128,16 @@ public:
void render();
// Pone las texturas del jugador
void setPlayerTextures(std::vector<std::shared_ptr<Texture>> texture);
void setPlayerTextures(const std::vector<std::shared_ptr<Texture>> &texture);
// Actua en consecuencia de la entrada recibida
void setInput(int input);
void setInput(InputType input);
// Procesa inputs para cuando está jugando
void setInputPlaying(int input);
void setInputPlaying(InputType input);
// Procesa inputs para cuando está introduciendo el nombre
void setInputEnteringName(int input);
void setInputEnteringName(InputType input);
// Mueve el jugador a la posición y animación que le corresponde
void move();
@@ -235,7 +245,7 @@ public:
void setPowerUpCounter(int value);
// Actualiza el valor de la variable
void updatePowerUpCounter();
void updatePowerUp();
// Obtiene el valor de la variable
bool hasExtraHit() const;
@@ -271,10 +281,10 @@ public:
void decContinueCounter();
// Establece el nombre del jugador
void setName(std::string name);
void setName(const std::string &name);
// Establece el nombre del jugador para la tabla de mejores puntuaciones
void setRecordName(std::string recordName);
void setRecordName(const std::string &record_name);
// Obtiene el nombre del jugador
std::string getName() const;

256
source/resource.cpp Normal file
View File

@@ -0,0 +1,256 @@
#include <iostream>
#include "resource.h"
#include "asset.h"
#include "screen.h"
// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado
Resource *Resource::resource_ = nullptr;
// [SINGLETON] Crearemos el objeto screen con esta función estática
void Resource::init()
{
Resource::resource_ = new Resource();
}
// [SINGLETON] Destruiremos el objeto screen con esta función estática
void Resource::destroy()
{
delete Resource::resource_;
}
// [SINGLETON] Con este método obtenemos el objeto screen y podemos trabajar con él
Resource *Resource::get()
{
return Resource::resource_;
}
// Constructor
Resource::Resource()
{
std::cout << "** LOADING RESOURCES" << std::endl;
loadSounds();
loadMusics();
loadTextures();
loadTextFiles();
loadAnimations();
loadDemoData();
addPalettes();
std::cout << "\n** RESOURCES LOADED" << std::endl;
}
// Destructor
Resource::~Resource()
{
sounds_.clear();
musics_.clear();
textures_.clear();
text_files_.clear();
animations_.clear();
}
// Obtiene el sonido a partir de un nombre
JA_Sound_t *Resource::getSound(const std::string &name)
{
for (const auto &s : sounds_)
{
if (s.name == name)
{
return s.sound;
}
}
std::cerr << "Error: Sonido no encontrado " << name << std::endl;
throw std::runtime_error("Sonido no encontrado: " + name);
}
// Obtiene la música a partir de un nombre
JA_Music_t *Resource::getMusic(const std::string &name)
{
for (const auto &m : musics_)
{
if (m.name == name)
{
return m.music;
}
}
std::cerr << "Error: Música no encontrada " << name << std::endl;
throw std::runtime_error("Música no encontrada: " + name);
}
// Obtiene la textura a partir de un nombre
std::shared_ptr<Texture> Resource::getTexture(const std::string &name)
{
for (const auto &t : textures_)
{
if (t.name == name)
{
return t.texture;
}
}
std::cerr << "Error: Imagen no encontrada " << name << std::endl;
throw std::runtime_error("Imagen no encontrada: " + name);
}
// Obtiene el fichero de texto a partir de un nombre
std::shared_ptr<TextFile> Resource::getTextFile(const std::string &name)
{
for (const auto &t : text_files_)
{
if (t.name == name)
{
return t.text_file;
}
}
std::cerr << "Error: TextFile no encontrado " << name << std::endl;
throw std::runtime_error("TextFile no encontrado: " + name);
}
// Obtiene la animación a partir de un nombre
Animations &Resource::getAnimation(const std::string &name)
{
for (auto &a : animations_)
{
if (a.name == name)
{
return a.animation;
}
}
std::cerr << "Error: Animación no encontrada " << name << std::endl;
throw std::runtime_error("Animación no encontrada: " + name);
}
// Obtiene el fichero con los datos para el modo demostración a partir de un çindice
DemoData &Resource::getDemoData(int index)
{
return demos_.at(index);
}
// Carga los sonidos
void Resource::loadSounds()
{
std::cout << "\n>> SOUND FILES" << std::endl;
// Obtiene la lista con las rutas a los ficheros de sonidos
auto list = Asset::get()->getListByType(AssetType::SOUND);
sounds_.clear();
for (const auto &l : list)
{
// Encuentra el último índice de '/'
auto last_index = l.find_last_of('/') + 1;
// Obtiene la subcadena desde el último '/'
auto name = l.substr(last_index);
sounds_.emplace_back(ResourceSound(name, JA_LoadSound(l.c_str())));
printWithDots("Sound : ", name, "[ LOADED ]");
}
}
// Carga las musicas
void Resource::loadMusics()
{
std::cout << "\n>> MUSIC FILES" << std::endl;
// Obtiene la lista con las rutas a los ficheros musicales
auto list = Asset::get()->getListByType(AssetType::MUSIC);
musics_.clear();
for (const auto &l : list)
{
// Encuentra el último índice de '/'
auto last_index = l.find_last_of('/') + 1;
// Obtiene la subcadena desde el último '/'
auto name = l.substr(last_index);
musics_.emplace_back(ResourceMusic(name, JA_LoadMusic(l.c_str())));
printWithDots("Music : ", name, "[ LOADED ]");
}
}
// Carga las texturas
void Resource::loadTextures()
{
std::cout << "\n>> TEXTURES" << std::endl;
// Obtiene la lista con las rutas a los ficheros png
auto list = Asset::get()->getListByType(AssetType::BITMAP);
textures_.clear();
for (const auto &l : list)
{
// Encuentra el último índice de '/'
auto last_index = l.find_last_of('/') + 1;
// Obtiene la subcadena desde el último '/'
auto name = l.substr(last_index);
textures_.emplace_back(ResourceTexture(name, std::make_shared<Texture>(Screen::get()->getRenderer(), l)));
}
}
// Carga los ficheros de texto
void Resource::loadTextFiles()
{
std::cout << "\n>> TEXT FILES" << std::endl;
// Obtiene la lista con las rutas a los ficheros png
auto list = Asset::get()->getListByType(AssetType::FONT);
text_files_.clear();
for (const auto &l : list)
{
// Encuentra el último índice de '/'
auto last_index = l.find_last_of('/') + 1;
// Obtiene la subcadena desde el último '/'
auto name = l.substr(last_index);
text_files_.emplace_back(ResourceTextFile(name, loadTextFile(l)));
}
}
// Carga las animaciones
void Resource::loadAnimations()
{
std::cout << "\n>> ANIMATIONS" << std::endl;
// Obtiene la lista con las rutas a los ficheros ani
auto list = Asset::get()->getListByType(AssetType::ANIMATION);
animations_.clear();
for (const auto &l : list)
{
// Encuentra el último índice de '/'
auto last_index = l.find_last_of('/') + 1;
// Obtiene la subcadena desde el último '/'
auto name = l.substr(last_index);
animations_.emplace_back(ResourceAnimation(name, loadAnimationsFromFile(l)));
}
}
// Carga los datos para el modo demostración
void Resource::loadDemoData()
{
std::cout << "\n>> DEMO_FILES" << std::endl;
demos_.emplace_back(loadDemoDataFromFile(Asset::get()->get("demo1.bin")));
demos_.emplace_back(loadDemoDataFromFile(Asset::get()->get("demo2.bin")));
}
// Añade paletas a las texturas
void Resource::addPalettes()
{
// Jugador 1
std::cout << "\n>> PALETTES" << std::endl;
getTexture("player1.gif")->addPaletteFromFile(Asset::get()->get("player1_one_coffee_palette.pal"));
getTexture("player1.gif")->addPaletteFromFile(Asset::get()->get("player1_two_coffee_palette.pal"));
getTexture("player1.gif")->addPaletteFromFile(Asset::get()->get("player1_all_white_palette.pal"));
// Jugador 2
getTexture("player2.gif")->addPaletteFromFile(Asset::get()->get("player2_one_coffee_palette.pal"));
getTexture("player2.gif")->addPaletteFromFile(Asset::get()->get("player2_two_coffee_palette.pal"));
getTexture("player2.gif")->addPaletteFromFile(Asset::get()->get("player2_all_white_palette.pal"));
// Fuentes
getTexture("smb2.gif")->addPaletteFromFile(Asset::get()->get("smb2_palette1.pal"));
}

137
source/resource.h Normal file
View File

@@ -0,0 +1,137 @@
#pragma once
#include <SDL2/SDL.h>
#include <vector>
#include <memory>
#include <string>
#include "jail_audio.h"
#include "texture.h"
#include "text.h"
#include "utils.h"
#include "animated_sprite.h"
// Estructura para almacenar ficheros de sonido y su nombre
struct ResourceSound
{
std::string name; // Nombre del sonido
JA_Sound_t *sound; // Objeto con el sonido
// Constructor
ResourceSound(const std::string &name, JA_Sound_t *sound)
: name(name), sound(sound) {}
};
// Estructura para almacenar ficheros musicales y su nombre
struct ResourceMusic
{
std::string name; // Nombre de la musica
JA_Music_t *music; // Objeto con la música
// Constructor
ResourceMusic(const std::string &name, JA_Music_t *music)
: name(name), music(music) {}
};
// Estructura para almacenar objetos Texture y su nombre
struct ResourceTexture
{
std::string name; // Nombre de la textura
std::shared_ptr<Texture> texture; // Objeto con la textura
// Constructor
ResourceTexture(const std::string &name, std::shared_ptr<Texture> texture)
: name(name), texture(texture) {}
};
// Estructura para almacenar ficheros TextFile y su nombre
struct ResourceTextFile
{
std::string name; // Nombre del fichero
std::shared_ptr<TextFile> text_file; // Objeto con los descriptores de la fuente de texto
// Constructor
ResourceTextFile(const std::string &name, std::shared_ptr<TextFile> text_file)
: name(name), text_file(text_file) {}
};
// Estructura para almacenar ficheros animaciones y su nombre
struct ResourceAnimation
{
std::string name; // Nombre del fichero
Animations animation; // Objeto con las animaciones
// Constructor
ResourceAnimation(const std::string &name, Animations animation)
: name(name), animation(animation) {}
};
class Resource
{
private:
// [SINGLETON] Objeto resource privado para Don Melitón
static Resource *resource_;
std::vector<ResourceSound> sounds_; // Vector con los sonidos
std::vector<ResourceMusic> musics_; // Vector con las musicas
std::vector<ResourceTexture> textures_; // Vector con las musicas
std::vector<ResourceTextFile> text_files_; // Vector con los ficheros de texto
std::vector<ResourceAnimation> animations_; // Vector con las animaciones
std::vector<DemoData> demos_; // Vector con los ficheros de datos para el modo demostración
// Carga los sonidos
void loadSounds();
// Carga las musicas
void loadMusics();
// Carga las texturas
void loadTextures();
// Carga los ficheros de texto
void loadTextFiles();
// Carga las animaciones
void loadAnimations();
// Carga los datos para el modo demostración
void loadDemoData();
// Añade paletas a las texturas
void addPalettes();
// [SINGLETON] Ahora el constructor y el destructor son privados, para no poder crear objetos resource desde fuera
// Constructor
Resource();
// Destructor
~Resource();
public:
// [SINGLETON] Crearemos el objeto resource con esta función estática
static void init();
// [SINGLETON] Destruiremos el objeto resource con esta función estática
static void destroy();
// [SINGLETON] Con este método obtenemos el objeto resource y podemos trabajar con él
static Resource *get();
// Obtiene el sonido a partir de un nombre
JA_Sound_t *getSound(const std::string &name);
// Obtiene la música a partir de un nombre
JA_Music_t *getMusic(const std::string &name);
// Obtiene la textura a partir de un nombre
std::shared_ptr<Texture> getTexture(const std::string &name);
// Obtiene el fichero de texto a partir de un nombre
std::shared_ptr<TextFile> getTextFile(const std::string &name);
// Obtiene la animación a partir de un nombre
Animations &getAnimation(const std::string &name);
// Obtiene el fichero con los datos para el modo demostración a partir de un çindice
DemoData &getDemoData(int index);
};

View File

@@ -5,74 +5,73 @@
#include <math.h> // for roundf
#include <iomanip>
#include <sstream>
#include "asset.h" // for Asset
#include "lang.h" // for getText
#include "asset.h" // for Asset
#include "lang.h" // for getText
#include "resource.h" // for Resource
#include "screen.h"
#include "sprite.h" // for Sprite
#include "text.h" // for Text
#include "texture.h" // for Texture
// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado
Scoreboard *Scoreboard::scoreboard = nullptr;
Scoreboard *Scoreboard::scoreboard_ = nullptr;
// [SINGLETON] Crearemos el objeto scoreboard con esta función estática
void Scoreboard::init(SDL_Renderer *renderer)
// [SINGLETON] Crearemos el objeto score_board con esta función estática
void Scoreboard::init()
{
Scoreboard::scoreboard = new Scoreboard(renderer);
Scoreboard::scoreboard_ = new Scoreboard();
}
// [SINGLETON] Destruiremos el objeto scoreboard con esta función estática
// [SINGLETON] Destruiremos el objeto score_board con esta función estática
void Scoreboard::destroy()
{
delete Scoreboard::scoreboard;
delete Scoreboard::scoreboard_;
}
// [SINGLETON] Con este método obtenemos el objeto scoreboard y podemos trabajar con él
// [SINGLETON] Con este método obtenemos el objeto score_board y podemos trabajar con él
Scoreboard *Scoreboard::get()
{
return Scoreboard::scoreboard;
return Scoreboard::scoreboard_;
}
// Constructor
Scoreboard::Scoreboard(SDL_Renderer *renderer)
: renderer(renderer)
{
// Inicializa punteros
gamePowerMeterTexture = nullptr;
powerMeterSprite = nullptr;
textScoreBoard = nullptr;
Scoreboard::Scoreboard()
: renderer_(Screen::get()->getRenderer()),
game_power_meter_texture_(Resource::get()->getTexture("game_power_meter.png")),
power_meter_sprite_(std::make_unique<Sprite>(game_power_meter_texture_)),
text_scoreboard_(std::make_unique<Text>(Resource::get()->getTexture("8bithud.png"), Resource::get()->getTextFile("8bithud.txt"))),
stage_(1),
hi_score_(0),
power_(0),
hi_score_name_(std::string()),
color_({0, 0, 0}),
rect_({0, 0, 320, 40}),
ticks_(SDL_GetTicks()),
counter_(0)
{
// Inicializa variables
stage = 1;
for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i)
{
name[i] = "";
recordName[i] = "";
selectorPos[i] = 0;
score[i] = 0;
mult[i] = 0;
continueCounter[i] = 0;
name_[i].clear();
record_name_[i].clear();
selector_pos_[i] = 0;
score_[i] = 0;
mult_[i] = 0;
continue_counter_[i] = 0;
}
hiScore = 0;
power = 0;
hiScoreName = "";
color = {0, 0, 0};
rect = {0, 0, 320, 40};
panel[SCOREBOARD_LEFT_PANEL].mode = ScoreboardMode::SCORE;
panel[SCOREBOARD_RIGHT_PANEL].mode = ScoreboardMode::SCORE;
panel[SCOREBOARD_CENTER_PANEL].mode = ScoreboardMode::STAGE_INFO;
ticks = SDL_GetTicks();
counter = 0;
panel_[SCOREBOARD_LEFT_PANEL].mode = ScoreboardMode::SCORE;
panel_[SCOREBOARD_RIGHT_PANEL].mode = ScoreboardMode::SCORE;
panel_[SCOREBOARD_CENTER_PANEL].mode = ScoreboardMode::STAGE_INFO;
// Recalcula las anclas de los elementos
recalculateAnchors();
// Crea objetos
gamePowerMeterTexture = std::make_shared<Texture>(renderer, Asset::get()->get("game_power_meter.png"));
powerMeterSprite = std::make_unique<Sprite>(slot4_2.x - 20, slot4_2.y, 40, 7, gamePowerMeterTexture);
textScoreBoard = std::make_unique<Text>(Asset::get()->get("8bithud.png"), Asset::get()->get("8bithud.txt"), renderer);
power_meter_sprite_->setPosition({slot4_2_.x - 20, slot4_2_.y, 40, 7});
// Crea la textura de fondo
background = nullptr;
background_ = nullptr;
createBackgroundTexture();
// Crea las texturas de los paneles
@@ -84,12 +83,12 @@ Scoreboard::Scoreboard(SDL_Renderer *renderer)
Scoreboard::~Scoreboard()
{
if (background)
if (background_)
{
SDL_DestroyTexture(background);
SDL_DestroyTexture(background_);
}
for (auto texture : panelTexture)
for (auto texture : panel_texture_)
{
if (texture)
{
@@ -109,10 +108,10 @@ std::string Scoreboard::updateScoreText(int num)
// Actualiza el contador
void Scoreboard::updateCounter()
{
if (SDL_GetTicks() - ticks > SCOREBOARD_TICK_SPEED)
if (SDL_GetTicks() - ticks_ > SCOREBOARD_TICK_SPEED_)
{
ticks = SDL_GetTicks();
counter++;
ticks_ = SDL_GetTicks();
counter_++;
}
}
@@ -126,80 +125,80 @@ void Scoreboard::update()
// Pinta el marcador
void Scoreboard::render()
{
SDL_RenderCopy(renderer, background, nullptr, &rect);
SDL_RenderCopy(renderer_, background_, nullptr, &rect_);
}
// Establece el valor de la variable
void Scoreboard::setName(int panel, std::string name)
void Scoreboard::setName(int panel_, const std::string &name_)
{
this->name[panel] = name;
this->name_[panel_] = name_;
}
// Establece el valor de la variable
void Scoreboard::setRecordName(int panel, std::string recordName)
void Scoreboard::setRecordName(int panel_, const std::string &record_name_)
{
this->recordName[panel] = recordName;
this->record_name_[panel_] = record_name_;
}
// Establece el valor de la variable
void Scoreboard::setSelectorPos(int panel, int pos)
void Scoreboard::setSelectorPos(int panel_, int pos)
{
selectorPos[panel] = pos;
selector_pos_[panel_] = pos;
}
// Establece el valor de la variable
void Scoreboard::setScore(int panel, int score)
void Scoreboard::setScore(int panel_, int score_)
{
this->score[panel] = score;
this->score_[panel_] = score_;
}
// Establece el valor de la variable
void Scoreboard::setMult(int panel, float mult)
void Scoreboard::setMult(int panel_, float mult_)
{
this->mult[panel] = mult;
this->mult_[panel_] = mult_;
}
// Establece el valor de la variable
void Scoreboard::setContinue(int panel, int value)
void Scoreboard::setContinue(int panel_, int value)
{
continueCounter[panel] = value;
continue_counter_[panel_] = value;
}
// Establece el valor de la variable
void Scoreboard::setStage(int stage)
void Scoreboard::setStage(int stage_)
{
this->stage = stage;
this->stage_ = stage_;
}
// Establece el valor de la variable
void Scoreboard::setHiScore(int hiScore)
void Scoreboard::setHiScore(int hi_score_)
{
this->hiScore = hiScore;
this->hi_score_ = hi_score_;
}
// Establece el valor de la variable
void Scoreboard::setPower(float power)
void Scoreboard::setPower(float power_)
{
this->power = power;
this->power_ = power_;
}
// Establece el valor de la variable
void Scoreboard::setHiScoreName(std::string name)
void Scoreboard::setHiScoreName(const std::string &name_)
{
hiScoreName = name;
hi_score_name_ = name_;
}
// Establece el valor de la variable
void Scoreboard::setColor(Color color)
void Scoreboard::setColor(Color color_)
{
this->color = color;
this->color_ = color_;
fillBackgroundTexture();
}
// Establece el valor de la variable
void Scoreboard::setPos(SDL_Rect rect)
void Scoreboard::setPos(SDL_Rect rect_)
{
this->rect = rect;
this->rect_ = rect_;
// Recalcula las anclas de los elementos
recalculateAnchors();
@@ -218,42 +217,42 @@ void Scoreboard::setPos(SDL_Rect rect)
void Scoreboard::fillPanelTextures()
{
// Guarda a donde apunta actualmente el renderizador
SDL_Texture *temp = SDL_GetRenderTarget(renderer);
SDL_Texture *temp = SDL_GetRenderTarget(renderer_);
// Genera el contenidoi de cada panel
// Genera el contenidoi de cada panel_
for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i)
{
// Cambia el destino del renderizador
SDL_SetRenderTarget(renderer, panelTexture[i]);
SDL_SetRenderTarget(renderer_, panel_texture_[i]);
// Dibuja el fondo de la textura
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
SDL_RenderClear(renderer_);
switch (panel[i].mode)
switch (panel_[i].mode)
{
case ScoreboardMode::SCORE:
{
// SCORE
textScoreBoard->writeCentered(slot4_1.x, slot4_1.y, name[i]);
textScoreBoard->writeCentered(slot4_2.x, slot4_2.y, updateScoreText(score[i]));
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y, name_[i]);
text_scoreboard_->writeCentered(slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]));
// MULT
textScoreBoard->writeCentered(slot4_3.x, slot4_3.y, lang::getText(55));
textScoreBoard->writeCentered(slot4_4.x, slot4_4.y, std::to_string(mult[i]).substr(0, 3));
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y, lang::getText(55));
text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y, std::to_string(mult_[i]).substr(0, 3));
break;
}
case ScoreboardMode::DEMO:
{
// DEMO MODE
textScoreBoard->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
if (counter % 10 < 8)
if (counter_ % 10 < 8)
{
textScoreBoard->writeCentered(slot4_3.x, slot4_3.y - 2, lang::getText(103));
textScoreBoard->writeCentered(slot4_4.x, slot4_4.y - 2, lang::getText(104));
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y - 2, lang::getText(103));
text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y - 2, lang::getText(104));
}
break;
}
@@ -261,13 +260,13 @@ void Scoreboard::fillPanelTextures()
case ScoreboardMode::WAITING:
{
// GAME OVER
textScoreBoard->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
if (counter % 10 < 8)
if (counter_ % 10 < 8)
{
textScoreBoard->writeCentered(slot4_3.x, slot4_3.y - 2, lang::getText(103));
textScoreBoard->writeCentered(slot4_4.x, slot4_4.y - 2, lang::getText(104));
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y - 2, lang::getText(103));
text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y - 2, lang::getText(104));
}
break;
}
@@ -275,13 +274,13 @@ void Scoreboard::fillPanelTextures()
case ScoreboardMode::GAME_OVER:
{
// GAME OVER
textScoreBoard->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
if (counter % 10 < 8)
if (counter_ % 10 < 8)
{
textScoreBoard->writeCentered(slot4_3.x, slot4_3.y - 2, lang::getText(114));
textScoreBoard->writeCentered(slot4_4.x, slot4_4.y - 2, lang::getText(115));
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y - 2, lang::getText(114));
text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y - 2, lang::getText(115));
}
break;
}
@@ -289,56 +288,56 @@ void Scoreboard::fillPanelTextures()
case ScoreboardMode::STAGE_INFO:
{
// STAGE
textScoreBoard->writeCentered(slot4_1.x, slot4_1.y, lang::getText(57) + std::to_string(stage));
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y, lang::getText(57) + std::to_string(stage_));
// POWERMETER
powerMeterSprite->setSpriteClip(0, 0, 40, 7);
powerMeterSprite->render();
powerMeterSprite->setSpriteClip(40, 0, int(power * 40.0f), 7);
powerMeterSprite->render();
power_meter_sprite_->setSpriteClip(0, 0, 40, 7);
power_meter_sprite_->render();
power_meter_sprite_->setSpriteClip(40, 0, int(power_ * 40.0f), 7);
power_meter_sprite_->render();
// HI-SCORE
textScoreBoard->writeCentered(slot4_3.x, slot4_3.y, lang::getText(56));
textScoreBoard->writeCentered(slot4_4.x, slot4_4.y, hiScoreName + " - " + updateScoreText(hiScore));
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y, lang::getText(56));
text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y, hi_score_name_ + " - " + updateScoreText(hi_score_));
break;
}
case ScoreboardMode::CONTINUE:
{
// SCORE
textScoreBoard->writeCentered(slot4_1.x, slot4_1.y, name[i]);
textScoreBoard->writeCentered(slot4_2.x, slot4_2.y, updateScoreText(score[i]));
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y, name_[i]);
text_scoreboard_->writeCentered(slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]));
// CONTINUE
textScoreBoard->writeCentered(slot4_3.x, slot4_3.y, lang::getText(105));
textScoreBoard->writeCentered(slot4_4.x, slot4_4.y, std::to_string(continueCounter[i]));
text_scoreboard_->writeCentered(slot4_3_.x, slot4_3_.y, lang::getText(105));
text_scoreboard_->writeCentered(slot4_4_.x, slot4_4_.y, std::to_string(continue_counter_[i]));
break;
}
case ScoreboardMode::ENTER_NAME:
{
// SCORE
textScoreBoard->writeCentered(slot4_1.x, slot4_1.y, name[i]);
textScoreBoard->writeCentered(slot4_2.x, slot4_2.y, updateScoreText(score[i]));
text_scoreboard_->writeCentered(slot4_1_.x, slot4_1_.y, name_[i]);
text_scoreboard_->writeCentered(slot4_2_.x, slot4_2_.y, updateScoreText(score_[i]));
// ENTER NAME
textScoreBoard->writeCentered(slot4_3.x, slot4_3.y, lang::getText(106));
SDL_Rect rect = {enterNamePos.x, enterNamePos.y, 5, 7};
SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xEB, 255);
for (int j = 0; j < (int)recordName[i].size(); ++j)
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 (int j = 0; j < (int)record_name_[i].size(); ++j)
{
if (j == selectorPos[i])
if (j == selector_pos_[i])
{ // La letra seleccionada se pinta de forma intermitente
if (counter % 3 > 0)
if (counter_ % 3 > 0)
{
SDL_RenderDrawLine(renderer, rect.x, rect.y + rect.h, rect.x + rect.w, rect.y + rect.h);
textScoreBoard->write(rect.x, rect.y, recordName[i].substr(j, 1));
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));
}
}
else
{
SDL_RenderDrawLine(renderer, rect.x, rect.y + rect.h, rect.x + rect.w, rect.y + rect.h);
textScoreBoard->write(rect.x, rect.y, recordName[i].substr(j, 1));
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));
}
rect.x += 7;
}
@@ -351,7 +350,7 @@ void Scoreboard::fillPanelTextures()
}
// Deja el renderizador apuntando donde estaba
SDL_SetRenderTarget(renderer, temp);
SDL_SetRenderTarget(renderer_, temp);
}
// Rellena la textura de fondo
@@ -361,41 +360,41 @@ void Scoreboard::fillBackgroundTexture()
fillPanelTextures();
// Cambia el destino del renderizador
SDL_Texture *temp = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, background);
SDL_Texture *temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, background_);
// Dibuja el fondo del marcador
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, 255);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer_, color_.r, color_.g, color_.b, 255);
SDL_RenderClear(renderer_);
// Copia las texturas de los paneles
for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i)
{
SDL_RenderCopy(renderer, panelTexture[i], nullptr, &panel[i].pos);
SDL_RenderCopy(renderer_, panel_texture_[i], nullptr, &panel_[i].pos);
}
// Dibuja la linea que separa la zona de juego del marcador
renderSeparator();
// Deja el renderizador apuntando donde estaba
SDL_SetRenderTarget(renderer, temp);
SDL_SetRenderTarget(renderer_, temp);
}
// Recalcula las anclas de los elementos
void Scoreboard::recalculateAnchors()
{
// Recalcula la posición y el tamaño de los paneles
const float panelWidth = (float)rect.w / (float)SCOREBOARD_MAX_PANELS;
const float panelWidth = (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.y = 0;
panel[i].pos.w = roundf(panelWidth * (i + 1)) - panel[i].pos.x;
panel[i].pos.h = rect.h;
panel_[i].pos.x = roundf(panelWidth * i);
panel_[i].pos.y = 0;
panel_[i].pos.w = roundf(panelWidth * (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;
// Constantes para definir las zonas del panel_: 4 filas y 1 columna
const int rowSize = rect_.h / 4;
const int textHeight = 7;
// Filas
@@ -408,63 +407,63 @@ void Scoreboard::recalculateAnchors()
const int col = panelWidth / 2;
// Slots de 4
slot4_1 = {col, row1};
slot4_2 = {col, row2};
slot4_3 = {col, row3};
slot4_4 = {col, row4};
slot4_1_ = {col, row1};
slot4_2_ = {col, row2};
slot4_3_ = {col, row3};
slot4_4_ = {col, row4};
// Primer cuadrado para poner el nombre de record
const int enterNameLenght = 8 * 7;
enterNamePos.x = (panelWidth - enterNameLenght) / 2;
enterNamePos.y = row4;
enter_name_pos_.x = (panelWidth - enterNameLenght) / 2;
enter_name_pos_.y = row4;
// Recoloca los sprites
if (powerMeterSprite)
if (power_meter_sprite_)
{
powerMeterSprite->setPosX(slot4_2.x - 20);
powerMeterSprite->setPosY(slot4_2.y);
power_meter_sprite_->setX(slot4_2_.x - 20);
power_meter_sprite_->setY(slot4_2_.y);
}
}
// Establece el modo del marcador
void Scoreboard::setMode(int index, ScoreboardMode mode)
{
panel[index].mode = mode;
panel_[index].mode = mode;
}
// Crea la textura de fondo
void Scoreboard::createBackgroundTexture()
{
// Elimina la textura en caso de existir
if (background)
if (background_)
{
SDL_DestroyTexture(background);
SDL_DestroyTexture(background_);
}
// Recrea la textura de fondo
background = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect.w, rect.h);
SDL_SetTextureBlendMode(background, SDL_BLENDMODE_BLEND);
background_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h);
SDL_SetTextureBlendMode(background_, SDL_BLENDMODE_BLEND);
}
// Crea las texturas de los paneles
void Scoreboard::createPanelTextures()
{
// Elimina las texturas en caso de existir
for (auto texture : panelTexture)
for (auto texture : panel_texture_)
{
if (texture != nullptr)
{
SDL_DestroyTexture(texture);
}
}
panelTexture.clear();
panel_texture_.clear();
// Crea las texturas para cada panel
// Crea las texturas para cada panel_
for (int i = 0; i < SCOREBOARD_MAX_PANELS; ++i)
{
SDL_Texture *tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, panel[i].pos.w, panel[i].pos.h);
SDL_Texture *tex = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, panel_[i].pos.w, panel_[i].pos.h);
SDL_SetTextureBlendMode(tex, SDL_BLENDMODE_BLEND);
panelTexture.push_back(tex);
panel_texture_.push_back(tex);
}
}
@@ -472,6 +471,6 @@ void Scoreboard::createPanelTextures()
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);
SDL_SetRenderDrawColor(renderer_, separator_color.r, separator_color.g, separator_color.b, 255);
SDL_RenderDrawLine(renderer_, 0, 0, rect_.w, 0);
}

View File

@@ -3,23 +3,22 @@
#include <SDL2/SDL_rect.h> // for SDL_Point, SDL_Rect
#include <SDL2/SDL_render.h> // for SDL_Renderer, SDL_Texture
#include <SDL2/SDL_stdinc.h> // for Uint32
#include <memory> // for unique_ptr
#include <string> // for string, basic_string
#include <memory> // for unique_ptr, shared_ptr
#include <string> // for string
#include <vector> // for vector
#include "utils.h" // for Color
#include "sprite.h" // lines 11-11
#include "text.h" // lines 12-12
#include "texture.h" // lines 13-13
class Sprite;
class Text;
class Texture;
// Defines
constexpr int SCOREBOARD_LEFT_PANEL = 0;
constexpr int SCOREBOARD_CENTER_PANEL = 1;
constexpr int SCOREBOARD_RIGHT_PANEL = 2;
constexpr int SCOREBOARD_MAX_PANELS = 3;
constexpr int SCOREBOARD_TICK_SPEED = 100;
// Enums
enum class ScoreboardMode
enum class ScoreboardMode : int
{
SCORE,
STAGE_INFO,
@@ -32,7 +31,7 @@ enum class ScoreboardMode
};
// Structs
struct panel_t
struct Panel
{
ScoreboardMode mode; // Modo en el que se encuentra el panel
SDL_Rect pos; // Posición donde dibujar el panel dentro del marcador
@@ -42,39 +41,42 @@ struct panel_t
class Scoreboard
{
private:
// Constantes
static constexpr int SCOREBOARD_TICK_SPEED_ = 100;
// [SINGLETON] Objeto scoreboard privado para Don Melitón
static Scoreboard *scoreboard;
static Scoreboard *scoreboard_;
// Objetos y punteros
SDL_Renderer *renderer; // El renderizador de la ventana
SDL_Renderer *renderer_; // El renderizador de la ventana
std::shared_ptr<Texture> gamePowerMeterTexture; // Textura con el marcador de poder de la fase
std::unique_ptr<Sprite> powerMeterSprite; // Sprite para el medidor de poder de la fase
std::unique_ptr<Text> textScoreBoard; // Fuente para el marcador del juego
std::shared_ptr<Texture> game_power_meter_texture_; // Textura con el marcador de poder de la fase
std::unique_ptr<Sprite> power_meter_sprite_; // Sprite para el medidor de poder de la fase
std::unique_ptr<Text> text_scoreboard_; // Fuente para el marcador del juego
SDL_Texture *background; // Textura para dibujar el marcador
std::vector<SDL_Texture *> panelTexture; // Texturas para dibujar cada panel;
SDL_Texture *background_; // Textura para dibujar el marcador
std::vector<SDL_Texture *> panel_texture_; // Texturas para dibujar cada panel
// Variables
int stage; // Número de fase actual
std::string name[SCOREBOARD_MAX_PANELS]; // Nom de cada jugador
std::string recordName[SCOREBOARD_MAX_PANELS]; // Nombre introducido para la tabla de records
int selectorPos[SCOREBOARD_MAX_PANELS]; // Posición del selector de letra para introducir el nombre
int score[SCOREBOARD_MAX_PANELS]; // Puntuación de los jugadores
float mult[SCOREBOARD_MAX_PANELS]; // Multiplicador de los jugadores
int continueCounter[SCOREBOARD_MAX_PANELS]; // Tiempo para continuar de los jugadores
int hiScore; // Máxima puntuación
float power; // Poder actual de la fase
std::string hiScoreName; // Nombre del jugador con la máxima puntuación
Color color; // Color del marcador
SDL_Rect rect; // Posición y dimensiones del marcador
panel_t panel[SCOREBOARD_MAX_PANELS]; // Lista con todos los paneles del marcador
Uint32 ticks; // Variable donde almacenar el valor de SDL_GetTiks()
int counter; // Contador
std::string name_[SCOREBOARD_MAX_PANELS]; // Nom de cada jugador
std::string record_name_[SCOREBOARD_MAX_PANELS]; // Nombre introducido para la tabla de records
int selector_pos_[SCOREBOARD_MAX_PANELS]; // Posición del selector de letra para introducir el nombre
int score_[SCOREBOARD_MAX_PANELS]; // Puntuación de los jugadores
float mult_[SCOREBOARD_MAX_PANELS]; // Multiplicador de los jugadores
int continue_counter_[SCOREBOARD_MAX_PANELS]; // Tiempo para continuar de los jugadores
Panel panel_[SCOREBOARD_MAX_PANELS]; // Lista con todos los paneles del marcador
int stage_; // Número de fase actual
int hi_score_; // Máxima puntuación
float power_; // Poder actual de la fase
std::string hi_score_name_; // Nombre del jugador con la máxima puntuación
Color color_; // Color del marcador
SDL_Rect rect_; // Posición y dimensiones del marcador
Uint32 ticks_; // Variable donde almacenar el valor de SDL_GetTiks()
int counter_; // Contador
// Puntos predefinidos para colocar elementos en los paneles
SDL_Point slot4_1, slot4_2, slot4_3, slot4_4;
SDL_Point enterNamePos;
SDL_Point slot4_1_, slot4_2_, slot4_3_, slot4_4_;
SDL_Point enter_name_pos_;
// Recalcula las anclas de los elementos
void recalculateAnchors();
@@ -103,14 +105,14 @@ private:
// [SINGLETON] Ahora el constructor y el destructor son privados
// Constructor
Scoreboard(SDL_Renderer *renderer);
Scoreboard();
// Destructor
~Scoreboard();
public:
// [SINGLETON] Crearemos el objeto scoreboard con esta función estática
static void init(SDL_Renderer *renderer);
static void init();
// [SINGLETON] Destruiremos el objeto scoreboard con esta función estática
static void destroy();
@@ -125,10 +127,10 @@ public:
void render();
// Establece el valor de la variable
void setName(int panel, std::string name);
void setName(int panel, const std::string &name);
// Establece el valor de la variable
void setRecordName(int panel, std::string recordName);
void setRecordName(int panel, const std::string &record_name);
// Establece el valor de la variable
void setSelectorPos(int panel, int pos);
@@ -146,13 +148,13 @@ public:
void setStage(int stage);
// Establece el valor de la variable
void setHiScore(int hiScore);
void setHiScore(int hi_score);
// Establece el valor de la variable
void setPower(float power);
// Establece el valor de la variable
void setHiScoreName(std::string name);
void setHiScoreName(const std::string &name);
// Establece el valor de la variable
void setColor(Color color);

View File

@@ -12,7 +12,7 @@
#include "dbgtxt.h" // for dbg_print
#include "global_inputs.h" // for servicePressedCounter
#include "input.h" // for Input, inputs_e, INPUT_DO_NOT_ALLOW_REPEAT
#include "notify.h" // for Notify
#include "notifier.h" // for Notify
#include "on_screen_help.h" // for OnScreenHelp
#include "options.h" // for options
#include "param.h" // for param
@@ -22,105 +22,96 @@
#endif
// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado
Screen *Screen::screen = nullptr;
Screen *Screen::screen_ = nullptr;
// [SINGLETON] Crearemos el objeto screen con esta función estática
void Screen::init(SDL_Window *window, SDL_Renderer *renderer)
{
Screen::screen = new Screen(window, renderer);
Screen::screen_ = new Screen(window, renderer);
}
// [SINGLETON] Destruiremos el objeto screen con esta función estática
void Screen::destroy()
{
delete Screen::screen;
delete Screen::screen_;
}
// [SINGLETON] Con este método obtenemos el objeto screen y podemos trabajar con él
Screen *Screen::get()
{
return Screen::screen;
return Screen::screen_;
}
// Constructor
Screen::Screen(SDL_Window *window, SDL_Renderer *renderer)
: window(window), renderer(renderer)
{
// Copia punteros
input = Input::get();
asset = Asset::get();
: window_(window),
renderer_(renderer),
// Inicializa variables
srcrect = {0, 0, param.game.width, param.game.height};
dstrect = {0, 0, param.game.width, param.game.height};
borderColor = {0, 0, 0};
flashEffect.enabled = false;
flashEffect.counter = 0;
flashEffect.lenght = 0;
flashEffect.color = {0xFF, 0xFF, 0xFF};
shakeEffect.enabled = false;
shakeEffect.desp = 2;
shakeEffect.delay = 3;
shakeEffect.counter = 0;
shakeEffect.lenght = 8;
shakeEffect.remaining = 0;
shakeEffect.originalPos = 0;
shakeEffect.originalWidth = param.game.width;
attenuateEffect = false;
fpsTicks = 0;
fpsCounter = 0;
fps = 0;
game_canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
shader_canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
src_rect_({0, 0, param.game.width, param.game.height}),
dst_rect_({0, 0, param.game.width, param.game.height}),
border_color_({0x00, 0x00, 0x00}),
attenuate_effect_(false),
fps_ticks_(0),
fps_counter_(0),
fps_(0),
#ifdef DEBUG
showInfo = true;
show_info_(true)
#else
showInfo = false;
show_info_(false)
#endif
{
// Inicializa variables
flash_effect_.enabled = false;
flash_effect_.counter = 0;
flash_effect_.lenght = 0;
flash_effect_.color = {0xFF, 0xFF, 0xFF};
shake_effect_.enabled = false;
shake_effect_.desp = 2;
shake_effect_.delay = 3;
shake_effect_.counter = 0;
shake_effect_.lenght = 8;
shake_effect_.remaining = 0;
shake_effect_.originalPos = 0;
shake_effect_.originalWidth = param.game.width;
SDL_DisplayMode DM;
SDL_GetCurrentDisplayMode(0, &DM);
infoResolution = std::to_string(DM.w) + " X " + std::to_string(DM.h) + " AT " + std::to_string(DM.refresh_rate) + " HZ";
// Crea los objetos
notify = std::make_unique<Notify>(renderer, "", asset->get("8bithud.png"), asset->get("8bithud.txt"), asset->get("notify.wav"));
// Define el color del borde para el modo de pantalla completa
borderColor = {0x00, 0x00, 0x00};
// Crea las textura donde se dibujan los graficos del juego
gameCanvas = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);
shaderCanvas = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);
info_resolution_ = std::to_string(DM.w) + " X " + std::to_string(DM.h) + " AT " + std::to_string(DM.refresh_rate) + " HZ";
// Establece el modo de video
setVideoMode(options.video.mode);
// Muestra la ventana
SDL_ShowWindow(window);
SDL_ShowWindow(window_);
}
// Destructor
Screen::~Screen()
{
SDL_DestroyTexture(gameCanvas);
SDL_DestroyTexture(shaderCanvas);
SDL_DestroyTexture(game_canvas_);
SDL_DestroyTexture(shader_canvas_);
}
// Limpia la pantalla
void Screen::clean(Color color)
{
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, 0xFF);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer_, color.r, color.g, color.b, 0xFF);
SDL_RenderClear(renderer_);
}
// Prepara para empezar a dibujar en la textura de juego
void Screen::start()
{
SDL_SetRenderTarget(renderer, gameCanvas);
SDL_SetRenderTarget(renderer_, game_canvas_);
}
// Vuelca el contenido del renderizador en pantalla
void Screen::blit()
{
// Actualiza el contador de FPS
fpsCounter++;
fps_counter_++;
// Actualiza y dibuja el efecto de flash en la pantalla
doFlash();
@@ -135,51 +126,51 @@ void Screen::blit()
displayInfo();
// Muestra las notificaciones
notify->render();
Notifier::get()->render();
#ifdef NO_SHADERS
// Vuelve a dejar el renderizador en modo normal
SDL_SetRenderTarget(renderer, nullptr);
SDL_SetRenderTarget(renderer_, nullptr);
// Borra el contenido previo
SDL_SetRenderDrawColor(renderer, borderColor.r, borderColor.g, borderColor.b, 0xFF);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer_, border_color_.r, border_color_.g, border_color_.b, 0xFF);
SDL_RenderClear(renderer_);
// Copia la textura de juego en el renderizador en la posición adecuada
if (shakeEffect.enabled)
SDL_RenderCopy(renderer, gameCanvas, nullptr, nullptr);
SDL_RenderCopy(renderer, gameCanvas, &srcrect, &dstrect);
if (shake_effect_.enabled)
SDL_RenderCopy(renderer_, game_canvas_, nullptr, nullptr);
SDL_RenderCopy(renderer_, game_canvas_, &src_rect_, &dst_rect_);
// Muestra por pantalla el renderizador
SDL_RenderPresent(renderer);
SDL_RenderPresent(renderer_);
#else
if (options.video.shaders)
{
SDL_SetRenderTarget(renderer, shaderCanvas);
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(renderer);
if (shakeEffect.enabled)
SDL_RenderCopy(renderer, gameCanvas, nullptr, nullptr);
SDL_RenderCopy(renderer, gameCanvas, &srcrect, &dstrect);
SDL_SetRenderTarget(renderer, nullptr);
SDL_SetRenderTarget(renderer_, shader_canvas_);
SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(renderer_);
if (shake_effect_.enabled)
SDL_RenderCopy(renderer_, game_canvas_, nullptr, nullptr);
SDL_RenderCopy(renderer_, game_canvas_, &src_rect_, &dst_rect_);
SDL_SetRenderTarget(renderer_, nullptr);
shader::render();
}
else
{
// Vuelve a dejar el renderizador en modo normal
SDL_SetRenderTarget(renderer, nullptr);
SDL_SetRenderTarget(renderer_, nullptr);
// Borra el render
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(renderer_);
// Copia la textura de juego en el renderizador en la posición adecuada
if (shakeEffect.enabled)
SDL_RenderCopy(renderer, gameCanvas, nullptr, nullptr);
SDL_RenderCopy(renderer, gameCanvas, &srcrect, &dstrect);
if (shake_effect_.enabled)
SDL_RenderCopy(renderer_, game_canvas_, nullptr, nullptr);
SDL_RenderCopy(renderer_, game_canvas_, &src_rect_, &dst_rect_);
// Muestra por pantalla el renderizador
SDL_RenderPresent(renderer);
SDL_RenderPresent(renderer_);
}
#endif
}
@@ -187,9 +178,10 @@ void Screen::blit()
// Establece el modo de video
void Screen::setVideoMode(ScreenVideoMode videoMode)
{
options.video.mode = videoMode;
#ifdef ARCADE
options.video.mode = ScreenVideoMode::WINDOW;
#else
options.video.mode = videoMode;
#endif
switch (options.video.mode)
@@ -197,7 +189,7 @@ void Screen::setVideoMode(ScreenVideoMode videoMode)
case ScreenVideoMode::WINDOW:
{
// Cambia a modo de ventana
SDL_SetWindowFullscreen(window, 0);
SDL_SetWindowFullscreen(window_, 0);
#ifdef ARCADE
// Oculta el puntero
@@ -207,8 +199,9 @@ void Screen::setVideoMode(ScreenVideoMode videoMode)
SDL_ShowCursor(SDL_ENABLE);
#endif
// Modifica el tamaño de la ventana
SDL_SetWindowSize(window, param.game.width * options.video.window.size, param.game.height * options.video.window.size);
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
SDL_Point pos = getNewPosition();
SDL_SetWindowSize(window_, param.game.width * options.video.window.size, param.game.height * options.video.window.size);
SDL_SetWindowPosition(window_, pos.x, pos.y);
break;
}
@@ -217,7 +210,7 @@ void Screen::setVideoMode(ScreenVideoMode videoMode)
case ScreenVideoMode::FULLSCREEN:
{
// Aplica el modo de video
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
SDL_SetWindowFullscreen(window_, SDL_WINDOW_FULLSCREEN_DESKTOP);
// Oculta el puntero
SDL_ShowCursor(SDL_DISABLE);
@@ -233,10 +226,10 @@ void Screen::setVideoMode(ScreenVideoMode videoMode)
if (options.video.shaders)
{
#ifndef NO_SHADERS
std::ifstream f(asset->get("crtpi.glsl").c_str());
std::ifstream f(Asset::get()->get("crtpi.glsl").c_str());
std::string source((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
shader::init(window, shaderCanvas, source.c_str());
shader::init(window_, shader_canvas_, source.c_str());
#endif
}
}
@@ -274,20 +267,20 @@ void Screen::incWindowSize()
// Cambia el color del borde
void Screen::setBorderColor(Color color)
{
borderColor = color;
border_color_ = color;
}
// Cambia el tipo de mezcla
void Screen::setBlendMode(SDL_BlendMode blendMode)
{
SDL_SetRenderDrawBlendMode(renderer, blendMode);
SDL_SetRenderDrawBlendMode(renderer_, blendMode);
}
// Actualiza la lógica de la clase
void Screen::update()
{
updateShake();
notify->update();
updateShakeEffect();
Notifier::get()->update();
updateFPS();
OnScreenHelp::get()->update();
}
@@ -297,35 +290,35 @@ void Screen::checkInput()
{
#ifndef ARCADE
// Comprueba el teclado para cambiar entre pantalla completa y ventana
if (input->checkInput(input_window_fullscreen, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
if (Input::get()->checkInput(InputType::WINDOW_FULLSCREEN, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
{
switchVideoMode();
const std::string mode = options.video.mode == ScreenVideoMode::WINDOW ? "Window" : "Fullscreen";
showNotification(mode + " mode");
Notifier::get()->showText(mode + " mode");
return;
}
// Comprueba el teclado para decrementar el tamaño de la ventana
if (input->checkInput(input_window_dec_size, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
if (Input::get()->checkInput(InputType::WINDOW_DEC_SIZE, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
{
decWindowSize();
const std::string size = std::to_string(options.video.window.size);
showNotification("Window size x" + size);
Notifier::get()->showText("Window size x" + size);
return;
}
// Comprueba el teclado para incrementar el tamaño de la ventana
if (input->checkInput(input_window_inc_size, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
if (Input::get()->checkInput(InputType::WINDOW_INC_SIZE, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
{
incWindowSize();
const std::string size = std::to_string(options.video.window.size);
showNotification("Window size x" + size);
Notifier::get()->showText("Window size x" + size);
return;
}
#endif
// Comprueba el teclado para activar o desactivar los shaders
if (input->checkInput(input_video_shaders, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
if (Input::get()->checkInput(InputType::VIDEO_SHADERS, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
{
switchShaders();
return;
@@ -333,26 +326,26 @@ void Screen::checkInput()
#ifdef DEBUG
// Comprueba el teclado para mostrar la información de debug
if (input->checkInput(input_showinfo, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
if (Input::get()->checkInput(InputType::SHOWINFO, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
{
showInfo = !showInfo;
show_info_ = !show_info_;
return;
}
#endif
for (int i = 0; i < input->getNumControllers(); ++i)
for (int i = 0; i < Input::get()->getNumControllers(); ++i)
{
// Comprueba los mandos para activar o desactivar los shaders
if (input->checkModInput(input_service, input_video_shaders, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i))
if (Input::get()->checkModInput(InputType::SERVICE, InputType::VIDEO_SHADERS, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i))
{
switchShaders();
return;
}
// Comprueba los mandos para mostrar la información de debug
if (input->checkModInput(input_service, input_showinfo, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i))
if (Input::get()->checkModInput(InputType::SERVICE, InputType::SHOWINFO, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i))
{
showInfo = !showInfo;
show_info_ = !show_info_;
return;
}
}
@@ -362,43 +355,43 @@ void Screen::checkInput()
void Screen::shake()
{
// Si no hay un shake effect activo, se guarda una copia de los valores actuales antes de modificarlos
if (!shakeEffect.enabled)
if (!shake_effect_.enabled)
{
shakeEffect.enabled = true;
shakeEffect.originalPos = srcrect.x;
shakeEffect.originalWidth = srcrect.w;
srcrect.w -= shakeEffect.desp;
dstrect.w = srcrect.w;
shake_effect_.enabled = true;
shake_effect_.originalPos = src_rect_.x;
shake_effect_.originalWidth = src_rect_.w;
src_rect_.w -= shake_effect_.desp;
dst_rect_.w = src_rect_.w;
}
// Si ya hay un shake effect en marcha no se pilla el origen, solo se renuevan los contadores
shakeEffect.remaining = shakeEffect.lenght;
shakeEffect.counter = shakeEffect.delay;
shake_effect_.remaining = shake_effect_.lenght;
shake_effect_.counter = shake_effect_.delay;
}
// Actualiza la logica para agitar la pantalla
void Screen::updateShake()
void Screen::updateShakeEffect()
{
if (shakeEffect.enabled)
if (shake_effect_.enabled)
{
if (shakeEffect.counter > 0)
if (shake_effect_.counter > 0)
{
shakeEffect.counter--;
shake_effect_.counter--;
}
else
{
shakeEffect.counter = shakeEffect.delay;
const auto srcdesp = shakeEffect.remaining % 2 == 0 ? 0 : shakeEffect.desp;
const auto dstdesp = shakeEffect.remaining % 2 == 1 ? 0 : shakeEffect.desp;
srcrect.x = shakeEffect.originalPos + srcdesp;
dstrect.x = shakeEffect.originalPos + dstdesp;
shakeEffect.remaining--;
shakeEffect.enabled = shakeEffect.remaining == -1 ? false : true;
if (!shakeEffect.enabled)
shake_effect_.counter = shake_effect_.delay;
const auto srcdesp = shake_effect_.remaining % 2 == 0 ? 0 : shake_effect_.desp;
const auto dstdesp = shake_effect_.remaining % 2 == 1 ? 0 : shake_effect_.desp;
src_rect_.x = shake_effect_.originalPos + srcdesp;
dst_rect_.x = shake_effect_.originalPos + dstdesp;
shake_effect_.remaining--;
shake_effect_.enabled = shake_effect_.remaining == -1 ? false : true;
if (!shake_effect_.enabled)
{
srcrect.x = shakeEffect.originalPos;
srcrect.w = shakeEffect.originalWidth;
dstrect = srcrect;
src_rect_.x = shake_effect_.originalPos;
src_rect_.w = shake_effect_.originalWidth;
dst_rect_ = src_rect_;
}
}
}
@@ -407,39 +400,39 @@ void Screen::updateShake()
// Pone la pantalla de color
void Screen::flash(Color color, int lenght)
{
flashEffect.enabled = true;
flashEffect.counter = 0;
flashEffect.lenght = lenght;
flashEffect.color = color;
flash_effect_.enabled = true;
flash_effect_.counter = 0;
flash_effect_.lenght = lenght;
flash_effect_.color = color;
}
// Actualiza y dibuja el efecto de flash en la pantalla
void Screen::doFlash()
{
if (flashEffect.enabled)
if (flash_effect_.enabled)
{
// Dibuja el color del flash en la textura
SDL_Texture *temp = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, gameCanvas);
SDL_SetRenderDrawColor(renderer, flashEffect.color.r, flashEffect.color.g, flashEffect.color.b, 0xFF);
SDL_RenderClear(renderer);
SDL_SetRenderTarget(renderer, temp);
SDL_Texture *temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, game_canvas_);
SDL_SetRenderDrawColor(renderer_, flash_effect_.color.r, flash_effect_.color.g, flash_effect_.color.b, 0xFF);
SDL_RenderClear(renderer_);
SDL_SetRenderTarget(renderer_, temp);
// Actualiza la lógica del efecto
flashEffect.counter < flashEffect.lenght ? flashEffect.counter++ : flashEffect.enabled = false;
flash_effect_.counter < flash_effect_.lenght ? flash_effect_.counter++ : flash_effect_.enabled = false;
}
}
// Atenua la pantalla
void Screen::doAttenuate()
{
if (attenuateEffect)
if (attenuate_effect_)
{
SDL_Texture *temp = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, gameCanvas);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 64);
SDL_RenderFillRect(renderer, nullptr);
SDL_SetRenderTarget(renderer, temp);
SDL_Texture *temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, game_canvas_);
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 64);
SDL_RenderFillRect(renderer_, nullptr);
SDL_SetRenderTarget(renderer_, temp);
}
}
@@ -449,56 +442,80 @@ void Screen::switchShaders()
options.video.shaders = !options.video.shaders;
setVideoMode(options.video.mode);
const std::string value = options.video.shaders ? "on" : "off";
showNotification("Shaders " + value);
Notifier::get()->showText("Shaders " + value);
}
// Atenua la pantalla
void Screen::attenuate(bool value)
{
attenuateEffect = value;
}
// Muestra una notificación de texto por pantalla;
void Screen::showNotification(std::string text1, std::string text2, int icon)
{
notify->showText(text1, text2, icon);
attenuate_effect_ = value;
}
// Obtiene el puntero al renderizador
SDL_Renderer *Screen::getRenderer()
{
return renderer;
return renderer_;
}
// Calcula los frames por segundo
void Screen::updateFPS()
{
if (SDL_GetTicks() - fpsTicks > 1000)
if (SDL_GetTicks() - fps_ticks_ > 1000)
{
fpsTicks = SDL_GetTicks();
fps = fpsCounter;
fpsCounter = 0;
fps_ticks_ = SDL_GetTicks();
fps_ = fps_counter_;
fps_counter_ = 0;
}
}
// Muestra información por pantalla
void Screen::displayInfo()
{
if (showInfo)
if (show_info_)
{
// FPS
const std::string fpstext = std::to_string(fps) + " FPS";
const std::string fpstext = std::to_string(fps_) + " FPS";
dbg_print(param.game.width - fpstext.length() * 8, 0, fpstext.c_str(), 255, 255, 0);
// Resolution
dbg_print(0, 0, infoResolution.c_str(), 255, 255, 0);
dbg_print(0, 0, info_resolution_.c_str(), 255, 255, 0);
dbg_print(0, 8, std::to_string(globalInputs::servicePressedCounter[0]).c_str(), 255, 255, 0);
dbg_print(0, 8, std::to_string(globalInputs::service_pressed_counter[0]).c_str(), 255, 255, 0);
}
}
// Indica si hay alguna notificación activa en pantalla
bool Screen::notificationsAreActive()
// Calcula la nueva posición de la ventana a partir de la antigua al cambiarla de tamaño
SDL_Point Screen::getNewPosition()
{
return notify->active();
// Obtiene la posición actual de la ventana
SDL_Point current_position;
SDL_GetWindowPosition(window_, &current_position.x, &current_position.y);
// Obtiene las dimensiones actuales de la ventana
int current_width, current_height;
SDL_GetWindowSize(window_, &current_width, &current_height);
// Obtiene las dimesiones que tendrá la ventana
const int new_width = param.game.width * options.video.window.size;
const int new_height = param.game.height * options.video.window.size;
// Obtiene el centro de la ventana actual
SDL_Point center;
center.x = current_position.x + current_width / 2;
center.y = current_position.y + current_height / 2;
// Calcula la nueva posición a partir del centro y las nuevas diemsiones
SDL_Point new_pos;
new_pos.x = center.x - new_width / 2;
new_pos.y = center.y - new_height / 2;
// Obtiene las dimensiones del escritorio
SDL_DisplayMode DM;
SDL_GetCurrentDisplayMode(0, &DM);
// Evita que la ventana quede fuera del escritorio
new_pos.x = std::clamp(new_pos.x, 30, DM.w - new_width);
new_pos.y = std::clamp(new_pos.y, 30, DM.h - new_height);
return new_pos;
}

View File

@@ -8,17 +8,14 @@
#include <string> // for basic_string, string
#include "utils.h" // for Color
#include <memory>
class Asset;
class Input;
class Notify;
enum class ScreenFilter
enum class ScreenFilter : int
{
NEAREST = 0,
LINEAL = 1,
};
enum class ScreenVideoMode
enum class ScreenVideoMode : int
{
WINDOW = 0,
FULLSCREEN = 1,
@@ -28,29 +25,26 @@ class Screen
{
private:
// [SINGLETON] Objeto screen privado para Don Melitón
static Screen *screen;
static Screen *screen_;
// Objetos y punteros
SDL_Window *window; // Ventana de la aplicación
SDL_Renderer *renderer; // El renderizador de la ventana
Asset *asset; // Objeto con el listado de recursos
Input *input; // Objeto para leer las entradas de teclado o mando
std::unique_ptr<Notify> notify; // Pinta notificaciones en pantalla
SDL_Texture *gameCanvas; // Textura donde se dibuja todo antes de volcarse al renderizador
SDL_Texture *shaderCanvas; // Textura para pasarle al shader desde gameCanvas
SDL_Window *window_; // Ventana de la aplicación
SDL_Renderer *renderer_; // El renderizador de la ventana
SDL_Texture *game_canvas_; // Textura donde se dibuja todo antes de volcarse al renderizador
SDL_Texture *shader_canvas_; // Textura para pasarle al shader desde gameCanvas
// Variables
SDL_Rect srcrect; // Coordenadas de donde va a pillar la textura del juego para dibujarla
SDL_Rect dstrect; // Coordenadas donde se va a dibujar la textura del juego sobre la pantalla o ventana
Color borderColor; // Color del borde añadido a la textura de juego para rellenar la pantalla
bool attenuateEffect; // Indica si la pantalla ha de estar atenuada
Uint32 fpsTicks; // Ticks para contar los frames por segundo
int fpsCounter; // Contador de frames por segundo
int fps; // Frames calculados en el último segundo
bool showInfo; // Indica si ha de mostrar/ocultar la información de la pantalla
std::string infoResolution; // Texto con la informacion de la pantalla
SDL_Rect src_rect_; // Coordenadas de donde va a pillar la textura del juego para dibujarla
SDL_Rect dst_rect_; // Coordenadas donde se va a dibujar la textura del juego sobre la pantalla o ventana
Color border_color_; // Color del borde añadido a la textura de juego para rellenar la pantalla
bool attenuate_effect_; // Indica si la pantalla ha de estar atenuada
Uint32 fps_ticks_; // Ticks para contar los frames por segundo
int fps_counter_; // Contador de frames por segundo
int fps_; // Frames calculados en el último segundo
bool show_info_; // Indica si ha de mostrar/ocultar la información de la pantalla
std::string info_resolution_; // Texto con la informacion de la pantalla
struct effect_t
struct FlashEffect
{
bool enabled; // Indica si el efecto está activo
int counter; // Contador para el efecto
@@ -58,10 +52,7 @@ private:
Color color; // Color del efecto
};
// Variables - Efectos
effect_t flashEffect; // Variable para gestionar el efecto de flash
struct shake_t
struct ShakeEffect
{
int desp; // Pixels de desplazamiento para agitar la pantalla en el eje x
int delay; // Retraso entre cada desplazamiento de la pantalla al agitarse
@@ -71,10 +62,14 @@ private:
int originalPos; // Posición inicial de la pantalla para dejarla igual tras el desplazamiento
int originalWidth; // Anchura inicial de la pantalla para dejarla igual tras el desplazamiento
bool enabled; // Indica si el efecto está activo
} shakeEffect;
};
// Variables - Efectos
FlashEffect flash_effect_; // Variable para gestionar el efecto de flash
ShakeEffect shake_effect_; // Variable para gestionar el efecto de agitar la pantalla
// Actualiza la logica para agitar la pantalla
void updateShake();
void updateShakeEffect();
// Actualiza y dibuja el efecto de flash en la pantalla
void doFlash();
@@ -88,6 +83,9 @@ private:
// Muestra información por pantalla
void displayInfo();
// Calcula la nueva posición de la ventana a partir de la antigua al cambiarla de tamaño
SDL_Point getNewPosition();
// [SINGLETON] Ahora el constructor y el destructor son privados, para no poder crear objetos screen desde fuera
// Constructor
@@ -122,7 +120,7 @@ public:
void blit();
// Establece el modo de video
void setVideoMode(ScreenVideoMode videoMode);
void setVideoMode(ScreenVideoMode video_mode);
// Camibia entre pantalla completa y ventana
void switchVideoMode();
@@ -140,7 +138,7 @@ public:
void setBorderColor(Color color);
// Cambia el tipo de mezcla
void setBlendMode(SDL_BlendMode blendMode);
void setBlendMode(SDL_BlendMode blend_mode);
// Agita la pantalla
void shake();
@@ -154,12 +152,6 @@ public:
// Atenua la pantalla
void attenuate(bool value);
// Muestra una notificación de texto por pantalla;
void showNotification(std::string text1 = "", std::string text2 = "", int icon = -1);
// Indica si hay alguna notificación activa en pantalla
bool notificationsAreActive();
// Obtiene el puntero al renderizador
SDL_Renderer *getRenderer();
};

View File

@@ -23,9 +23,10 @@ namespace section
GAME_PLAY_2P = 1,
TITLE_1 = 2,
TITLE_2 = 3,
QUIT_NORMAL = 4,
QUIT_SHUTDOWN = 5,
NONE = 6,
QUIT_WITH_KEYBOARD = 4,
QUIT_WITH_CONTROLLER = 5,
QUIT_FROM_EVENT = 6,
NONE = 7,
};
extern Name name;

View File

@@ -1,23 +1,19 @@
#include "smart_sprite.h"
#include "moving_sprite.h" // for MovingSprite
class Texture;
// Constructor
SmartSprite::SmartSprite(std::shared_ptr<Texture> texture)
: AnimatedSprite(texture)
{
// Copia punteros
setTexture(texture);
init();
}
// Inicializa el objeto
void SmartSprite::init()
{
finishedCounter_ = 0;
onDestination_ = false;
destX_ = 0;
destY_ = 0;
finished_counter_ = 0;
on_destination_ = false;
dest_x_ = dest_y_ = 0;
finished_ = false;
enabled_ = false;
}
@@ -36,31 +32,31 @@ void SmartSprite::update()
// Establece el valor de la variable
void SmartSprite::setFinishedCounter(int value)
{
finishedCounter_ = value;
finished_counter_ = value;
}
// Establece el valor de la variable
void SmartSprite::setDestX(int x)
{
destX_ = x;
dest_x_ = x;
}
// Establece el valor de la variable
void SmartSprite::setDestY(int y)
{
destY_ = y;
dest_y_ = y;
}
// Obtiene el valor de la variable
int SmartSprite::getDestX() const
{
return destX_;
return dest_x_;
}
// Obtiene el valor de la variable
int SmartSprite::getDestY() const
{
return destY_;
return dest_y_;
}
// Comprueba el movimiento
@@ -70,10 +66,10 @@ void SmartSprite::checkMove()
if (getAccelX() > 0 || getVelX() > 0)
{
// Comprueba si ha llegado al destino
if (getPosX() > destX_)
if (getPosX() > dest_x_)
{
// Lo coloca en posición
setPosX(destX_);
setPosX(dest_x_);
// Lo detiene
setVelX(0.0f);
@@ -84,10 +80,10 @@ void SmartSprite::checkMove()
else if (getAccelX() < 0 || getVelX() < 0)
{
// Comprueba si ha llegado al destino
if (getPosX() < destX_)
if (getPosX() < dest_x_)
{
// Lo coloca en posición
setPosX(destX_);
setPosX(dest_x_);
// Lo detiene
setVelX(0.0f);
@@ -99,10 +95,10 @@ void SmartSprite::checkMove()
if (getAccelY() > 0 || getVelY() > 0)
{
// Comprueba si ha llegado al destino
if (getPosY() > destY_)
if (getPosY() > dest_y_)
{
// Lo coloca en posición
setPosY(destY_);
setPosY(dest_y_);
// Lo detiene
setVelY(0.0f);
@@ -113,10 +109,10 @@ void SmartSprite::checkMove()
else if (getAccelY() < 0 || getVelY() < 0)
{
// Comprueba si ha llegado al destino
if (getPosY() < destY_)
if (getPosY() < dest_y_)
{
// Lo coloca en posición
setPosY(destY_);
setPosY(dest_y_);
// Lo detiene
setVelY(0.0f);
@@ -129,17 +125,17 @@ void SmartSprite::checkMove()
void SmartSprite::checkFinished()
{
// Comprueba si ha llegado a su destino
onDestination_ = (getPosX() == destX_ && getPosY() == destY_) ? true : false;
on_destination_ = (getPosX() == dest_x_ && getPosY() == dest_y_);
if (onDestination_)
if (on_destination_)
{
if (finishedCounter_ == 0)
if (finished_counter_ == 0)
{
finished_ = true;
}
else
{
--finishedCounter_;
--finished_counter_;
}
}
}
@@ -147,11 +143,16 @@ void SmartSprite::checkFinished()
// Obtiene el valor de la variable
bool SmartSprite::isOnDestination() const
{
return onDestination_;
return on_destination_;
}
// Obtiene el valor de la variable
bool SmartSprite::hasFinished() const
{
return finished_;
}
void SmartSprite::setEnabled(bool value)
{
enabled_ = value;
}

View File

@@ -1,29 +1,30 @@
#pragma once
#include "animated_sprite.h" // for AnimatedSprite
#include "texture.h"
#include <memory>
#include <memory> // for shared_ptr
#include "animated_sprite.h" // for SpriteAnimated
class Texture;
// Clase SmartSprite
// Clase SpriteSmart
class SmartSprite : public AnimatedSprite
{
private:
// Variables
bool onDestination_; // Indica si está en el destino
int destX_; // Posicion de destino en el eje X
int destY_; // Posicion de destino en el eje Y
int finishedCounter_; // Contador para deshabilitarlo
bool finished_; // Indica si ya ha terminado
// Comprueba el movimiento
void checkMove();
bool on_destination_; // Indica si está en el destino
int dest_x_; // Posicion de destino en el eje X
int dest_y_; // Posicion de destino en el eje Y
int finished_counter_; // Contador para deshabilitarlo
bool finished_; // Indica si ya ha terminado
bool enabled_; // Indica si el objeto está habilitado
// Comprueba si ha terminado
void checkFinished();
// Comprueba el movimiento
void checkMove();
public:
// Constructor
SmartSprite(std::shared_ptr<Texture> texture);
explicit SmartSprite(std::shared_ptr<Texture> texture);
// Destructor
~SmartSprite() = default;
@@ -32,7 +33,7 @@ public:
void init();
// Actualiza la posición y comprueba si ha llegado a su destino
void update();
void update() override;
// Establece el valor de la variable
void setFinishedCounter(int value);
@@ -54,4 +55,6 @@ public:
// Obtiene el valor de la variable
bool hasFinished() const;
void setEnabled(bool value);
};

View File

@@ -1,122 +1,111 @@
#include "sprite.h"
// Constructor
Sprite::Sprite(int x, int y, int w, int h, std::shared_ptr<Texture> texture)
: x_(x), y_(y), w_(w), h_(h), texture_(texture)
{
// Establece el rectangulo de donde coger la imagen
spriteClip_ = {0, 0, w, h};
Sprite::Sprite(std::shared_ptr<Texture> texture, int x, int y, int w, int h)
: texture_(texture),
pos_((SDL_Rect){x, y, w, h}),
sprite_clip_((SDL_Rect){0, 0, pos_.w, pos_.h}) {}
// Inicializa variables
enabled_ = true;
}
Sprite::Sprite(std::shared_ptr<Texture> texture, SDL_Rect rect)
: texture_(texture),
pos_(rect),
sprite_clip_((SDL_Rect){0, 0, pos_.w, pos_.h}) {}
Sprite::Sprite(SDL_Rect rect, std::shared_ptr<Texture> texture)
: x_(rect.x), y_(rect.y), w_(rect.w), h_(rect.h), texture_(texture)
{
// Establece el rectangulo de donde coger la imagen
spriteClip_ = {0, 0, w_, h_};
// Inicializa variables
enabled_ = true;
}
Sprite::Sprite(std::shared_ptr<Texture> texture)
: texture_(texture),
pos_({0, 0, texture_->getWidth(), texture_->getHeight()}),
sprite_clip_(pos_) {}
// Muestra el sprite por pantalla
void Sprite::render()
{
if (enabled_)
{
texture_->render(x_, y_, &spriteClip_);
}
texture_->render(pos_.x, pos_.y, &sprite_clip_);
}
// Obten el valor de la variable
int Sprite::getPosX() const
int Sprite::getX() const
{
return x_;
return pos_.x;
}
// Obten el valor de la variable
int Sprite::getPosY() const
int Sprite::getY() const
{
return y_;
return pos_.y;
}
// Obten el valor de la variable
int Sprite::getWidth() const
{
return w_;
return pos_.w;
}
// Obten el valor de la variable
int Sprite::getHeight() const
{
return h_;
return pos_.h;
}
// Establece la posición del objeto
void Sprite::setPos(int x, int y)
void Sprite::setPosition(int x, int y)
{
x_ = x;
y_ = y;
pos_.x = x;
pos_.y = y;
}
// Establece la posición del objeto
void Sprite::setPos(SDL_Point p)
void Sprite::setPosition(SDL_Point p)
{
x_ = p.x;
y_ = p.y;
pos_.x = p.x;
pos_.y = p.y;
}
// Establece la posición del objeto
void Sprite::setPos(SDL_Rect r)
void Sprite::setPosition(SDL_Rect r)
{
x_ = r.x;
y_ = r.y;
w_ = r.w;
h_ = r.h;
pos_ = r;
}
// Establece el valor de la variable
void Sprite::setPosX(int x)
void Sprite::setX(int x)
{
x_ = x;
pos_.x = x;
}
// Establece el valor de la variable
void Sprite::setPosY(int y)
void Sprite::setY(int y)
{
y_ = y;
pos_.y = y;
}
// Establece el valor de la variable
void Sprite::setWidth(int w)
{
w_ = w;
pos_.w = w;
}
// Establece el valor de la variable
void Sprite::setHeight(int h)
{
h_ = h;
pos_.h = h;
}
// Obten el valor de la variable
SDL_Rect Sprite::getSpriteClip() const
{
return spriteClip_;
return sprite_clip_;
}
// Establece el valor de la variable
void Sprite::setSpriteClip(SDL_Rect rect)
{
spriteClip_ = rect;
sprite_clip_ = rect;
}
// Establece el valor de la variable
void Sprite::setSpriteClip(int x, int y, int w, int h)
{
spriteClip_ = (SDL_Rect){x, y, w, h};
sprite_clip_ = (SDL_Rect){x, y, w, h};
}
// Obten el valor de la variable
@@ -131,32 +120,27 @@ void Sprite::setTexture(std::shared_ptr<Texture> texture)
texture_ = texture;
}
// Establece el valor de la variable
void Sprite::setEnabled(bool value)
{
enabled_ = value;
}
// Comprueba si el objeto está habilitado
bool Sprite::isEnabled() const
{
return enabled_;
}
// Devuelve el rectangulo donde está el sprite
SDL_Rect Sprite::getRect() const
SDL_Rect Sprite::getPosition() const
{
return (SDL_Rect){x_, y_, w_, h_};
return pos_;
}
// Incrementa el valor de la variable
void Sprite::incPosX(int value)
void Sprite::incX(int value)
{
x_ += value;
pos_.x += value;
}
// Incrementa el valor de la variable
void Sprite::incPosY(int value)
void Sprite::incY(int value)
{
y_ += value;
pos_.y += value;
}
// Reinicia las variables a cero
void Sprite::clear()
{
pos_ = {0, 0, 0, 0};
sprite_clip_ = {0, 0, 0, 0};
}

View File

@@ -8,50 +8,49 @@
class Sprite
{
protected:
int x_; // Posición en el eje X donde dibujar el sprite
int y_; // Posición en el eje Y donde dibujar el sprite
int w_; // Ancho del sprite
int h_; // Alto del sprite
// Variables
std::shared_ptr<Texture> texture_; // Textura donde estan todos los dibujos del sprite
SDL_Rect spriteClip_; // Rectangulo de origen de la textura que se dibujará en pantalla
bool enabled_; // Indica si el sprite esta habilitado
SDL_Rect pos_; // Posición y tamaño donde dibujar el sprite
SDL_Rect sprite_clip_; // Rectangulo de origen de la textura que se dibujará en pantalla
public:
// Constructor
Sprite(int x = 0, int y = 0, int w = 0, int h = 0, std::shared_ptr<Texture> texture = nullptr);
Sprite(SDL_Rect rect, std::shared_ptr<Texture> texture = nullptr);
Sprite(std::shared_ptr<Texture>, int x, int y, int w, int h);
Sprite(std::shared_ptr<Texture>, SDL_Rect rect);
explicit Sprite(std::shared_ptr<Texture>);
// Destructor
~Sprite() = default;
// Muestra el sprite por pantalla
void render();
virtual void render();
// Reinicia las variables a cero
virtual void clear();
// Obten el valor de la variable
int getPosX() const;
int getPosY() const;
int getX() const;
int getY() const;
int getWidth() const;
int getHeight() const;
// Establece la posición del objeto
void setPos(int x, int y);
void setPos(SDL_Point p);
void setPos(SDL_Rect r);
// Devuelve el rectangulo donde está el sprite
SDL_Rect getRect() const;
SDL_Rect getPosition() const;
// Establece el valor de la variable
void setPosX(int x);
void setPosY(int y);
void setX(int x);
void setY(int y);
void setWidth(int w);
void setHeight(int h);
// Establece la posición del objeto
void setPosition(int x, int y);
void setPosition(SDL_Point p);
void setPosition(SDL_Rect r);
// Incrementa el valor de la variable
void incPosX(int value);
void incPosY(int value);
void incX(int value);
void incY(int value);
// Obten el valor de la variable
SDL_Rect getSpriteClip() const;
@@ -65,11 +64,4 @@ public:
// Establece el valor de la variable
void setTexture(std::shared_ptr<Texture> texture);
// Establece el valor de la variable
void setEnabled(bool value);
// Comprueba si el objeto está habilitado
bool isEnabled() const;
};

Some files were not shown because too many files have changed in this diff Show More