Compare commits

96 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
3a6950f3a4 Menudo puto lio de renamar coses, a vore si tot va quedant al lloc que els structs i els enums estan revolant i duplicats per tots llocs 2024-10-11 20:12:50 +02:00
a9ca23138d Continuem estandaritzant noms 2024-10-11 13:54:43 +02:00
e1fa1d2102 Canviades certes opcions a parametres i afegides noves opcions 2024-10-11 09:03:57 +02:00
117b80bdfc idem 2024-10-10 20:59:39 +02:00
d6c3c89872 Estandaritzant noms segons convencions 2024-10-10 20:27:31 +02:00
9e5f41644e Açò ja no hi ha Cristo que ho pete 2024-10-10 13:48:53 +02:00
fc8fdc5fe5 Llevats uns punterets que sobraven en director.cpp 2024-10-10 09:23:16 +02:00
6fe294c59d Pos ja compila pero no es veu una puta merda ... 2024-10-10 08:06:36 +02:00
3fa5b227ae commit de anar a dormir 2024-10-09 23:01:44 +02:00
f2fa216b0d Commit pa que Mon arregle el codi mentre em dutxe 2024-10-09 21:48:01 +02:00
3c1dcad3ab Commit de anar al llit amb el portatil 2024-10-08 23:15:55 +02:00
bd3aa0bb06 Arreglos varios al codi 2024-10-08 22:38:58 +02:00
3e3d764b25 Commitet pa gastar el Cppcheck 2024-10-08 20:32:24 +02:00
c00f4326ae Commit de "guardar partida" 2024-10-08 18:07:54 +02:00
9ce0f16d33 Arreglats els constructors de Text 2024-10-08 18:07:44 +02:00
06a4f439c1 Posant make_uniques, s'ha quedat tot enmerdat per culpa d'un struct 2024-10-08 13:53:24 +02:00
9d41d14d68 Actualitzats els scripts de valgrind 2024-10-07 20:11:08 +02:00
0d0e49316f Afegit scripts a linux-utils 2024-10-07 18:44:18 +02:00
bf945ef14b Corregits 8.000.000 de segmentation faults en intro.cpp 2024-10-07 18:37:08 +02:00
0330fe6b74 Make uniques en intro.cpp 2024-10-07 17:28:34 +02:00
6305a67c84 Actualitzat .gitignore 2024-10-07 17:28:22 +02:00
5f18189269 Actualizado Makefile 2024-10-07 12:32:53 +02:00
7ebefd7b54 Les enum class passen a estar totes amb la inicial en majuscula 2024-10-07 12:30:46 +02:00
cffa4c3c92 Commitet pa valgrind, he aprofitat i posat mes make_unique i enum class 2024-10-07 10:49:29 +02:00
4f0ea9dcf2 Make_unique en title.cpp 2024-10-07 08:22:51 +02:00
b1f936a791 Pasaeta de include-what-you-use abans que es desmadre tot 2024-10-06 22:43:28 +02:00
1c0554d4df Actualitzat script check-includes.sh 2024-10-06 22:43:00 +02:00
8ba77d7d5d Demanada ajuda a la IA pa que m'arregle un poc la meua merda: Para optimizar este código y evitar duplicar la lógica para cada jugador, podemos extraer el código común en una función reutilizable. Así, reducimos la repetición y mejoramos la legibilidad. 2024-10-06 21:07:26 +02:00
6515ec6c7b Els panels dels marcadors ja passen a game over sense pasar per waiting un frame gracies a una parafernalia que he montat 2024-10-06 21:02:49 +02:00
b979c0f2b8 Mes textos 2024-10-06 21:02:12 +02:00
a95e5077e3 Els panels del marcador ara canvien de mode a petició i no a cada frame 2024-10-06 20:19:43 +02:00
6ea6f85e3e Nous textos 2024-10-06 20:14:37 +02:00
fe6e63e39f fix: la classe Screen ja ha recuperat un poc del lustro que tenia
shake effect ja no està fet "the torerous menner"
shake effect ja va amb shaders
2024-10-06 18:57:47 +02:00
afe092c742 Muntat a c++14 per a make_unique
Mes autos, const i constexpr perl codi
Ara la classe Screen es un poc pitjor
2024-10-06 14:58:00 +02:00
25a2753b13 Canviats defines per constexpr i enum class
Canviats punters a unique_ptr
Afegit const a alguns metodes de classse
fix: el segon jugador no podia unirse a la partida
new: Quan els dos jugadors han decidit no continuar, ja no poden continuar i el marcador així ho reflectix
fix: al posar el nom per segona vegada en la mateixa partida, no es reseteja la posició del selector
fix: el fade venetian no netejava la textura i de vegades eixien gràfics corruptes
fix: ara grava a disco cada vegada que es posa nom al morir
2024-10-05 23:53:42 +02:00
ee721ff573 debug 2024-10-03 19:35:58 +02:00
c07fd62037 Corregit bug en el text a l'hora d'intercanviar els mandos. Apareixia el nom del mando que te guardat a la configuració pero no estava connectat 2024-10-03 19:26:32 +02:00
fb74733f2c Correcció de textos 2024-10-03 18:16:20 +02:00
468bd0950c Modificat controllers.png 2024-10-03 18:13:48 +02:00
938e4ad011 La targeta d'ajuda ja ix amb els mandos i s'ha de deixar apretat el botó 2024-10-03 17:37:33 +02:00
71bd3bed52 Eliminades variables sobrants en director.cpp 2024-10-03 17:02:40 +02:00
5ebc58dd01 La tarjeta d'ajuda ja entra i ix amb animacions suavitzades 2024-10-02 18:03:20 +02:00
9b3e549876 Añadidas funciones de suavizado a utils.cpp 2024-10-02 18:00:21 +02:00
abc8a0b632 La tarjeta d'ajuda ix pero no s'amaga 2024-10-02 13:56:43 +02:00
3a84ea792c Ja dibuixa la tarjeta amb la ajuda per als botons de servei 2024-10-01 20:58:05 +02:00
3cabd5c675 Nous textos 2024-10-01 19:07:25 +02:00
136 changed files with 9716 additions and 10307 deletions

2
.gitignore vendored
View File

@@ -14,3 +14,5 @@ thumbs.db
*config.bin
*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++11 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows
CXXFLAGS_DEBUG:= -std=c++11 -Wall
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++11 -Wall -Os -ffunction-sections -fdata-sections
CXXFLAGS_DEBUG:= -std=c++11 -Wall
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,19 +1,20 @@
## GAME
game.itemSize 20
game.width 320
game.height 240
game.playArea.rect.x 0
game.playArea.rect.y 0
game.playArea.rect.w 320
game.playArea.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.numSquaresWidth 160
fade.numSquaresHeight 120
fade.randomSquaresDelay 1
fade.randomSquaresMult 500
fade.postDuration 80
fade.venetianSize 16
fade.num_squares_width 160
fade.num_squares_height 120
fade.random_squares_delay 1
fade.random_squares_mult 500
fade.post_duration 80
fade.venetian_size 16
## SCOREBOARD
scoreboard.x 0
@@ -22,23 +23,31 @@ scoreboard.w 320
scoreboard.h 40
## TITLE
title.pressStartPosition 170
title.titleDuration 800
title.arcadeEditionPosition 123
title.titleCCPosition 80
title.press_start_position 170
title.title_duration 800
title.arcade_edition_position 123
title.title_c_c_position 80
## BACKGROUND
background.attenuateColor.r 255
background.attenuateColor.g 255
background.attenuateColor.b 255
background.attenuateAlpha 0
background.attenuate_color.r 255
background.attenuate_color.g 255
background.attenuate_color.b 255
background.attenuate_alpha 0
## BALLOONS
balloon1.vel 2.75f
balloon1.grav 0.09f
balloon2.vel 3.70f
balloon2.grav 0.10f
balloon3.vel 4.70f
balloon3.grav 0.10f
balloon4.vel 5.45f
balloon4.grav 0.10f
balloon_1.vel 2.75f
balloon_1.grav 0.09f
balloon_2.vel 3.70f
balloon_2.grav 0.10f
balloon_3.vel 4.70f
balloon_3.grav 0.10f
balloon_4.vel 5.45f
balloon_4.grav 0.10f
## NOTIFICATION
notification.pos_v TOP
notification.pos_h LEFT
notification.sound false
notification.color.r 48
notification.color.g 48
notification.color.b 48

View File

@@ -1,19 +1,20 @@
## GAME
game.itemSize 20
game.width 320
game.height 256
game.playArea.rect.x 0
game.playArea.rect.y 0
game.playArea.rect.w 320
game.playArea.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.numSquaresWidth 160
fade.numSquaresHeight 128
fade.randomSquaresDelay 1
fade.randomSquaresMult 500
fade.postDuration 80
fade.venetianSize 16
fade.num_squares_width 160
fade.num_squares_height 128
fade.random_squares_delay 1
fade.random_squares_mult 500
fade.post_duration 80
fade.venetian_size 16
## SCOREBOARD
scoreboard.x 0
@@ -22,23 +23,31 @@ scoreboard.w 320
scoreboard.h 40
## TITLE
title.pressStartPosition 180
title.titleDuration 800
title.arcadeEditionPosition 123
title.titleCCPosition 80
title.press_start_position 180
title.title_duration 800
title.arcade_edition_position 123
title.title_c_c_position 80
## BACKGROUND
background.attenuateColor.r 255
background.attenuateColor.g 255
background.attenuateColor.b 255
background.attenuateAlpha 0
background.attenuate_color.r 255
background.attenuate_color.g 255
background.attenuate_color.b 255
background.attenuate_alpha 0
## BALLOONS
balloon1.vel 2.75f
balloon1.grav 0.09f
balloon2.vel 3.70f
balloon2.grav 0.10f
balloon3.vel 4.70f
balloon3.grav 0.10f
balloon4.vel 5.45f
balloon4.grav 0.10f
balloon_1.vel 2.75f
balloon_1.grav 0.09f
balloon_2.vel 3.70f
balloon_2.grav 0.10f
balloon_3.vel 4.70f
balloon_3.grav 0.10f
balloon_4.vel 5.45f
balloon_4.grav 0.10f
## NOTIFICATION
notification.pos_v TOP
notification.pos_h LEFT
notification.sound false
notification.color.r 48
notification.color.g 48
notification.color.b 48

View File

Before

Width:  |  Height:  |  Size: 84 B

After

Width:  |  Height:  |  Size: 84 B

View File

@@ -1,5 +1,5 @@
frameWidth=10
frameHeight=10
frame_width=10
frame_height=10
[animation]
name=orange

View File

@@ -1,5 +1,5 @@
frameWidth=16
frameHeight=16
frame_width=16
frame_height=16
[animation]
name=orange

View File

@@ -1,5 +1,5 @@
frameWidth=26
frameHeight=26
frame_width=26
frame_height=26
[animation]
name=orange

View File

@@ -1,5 +1,5 @@
frameWidth=48
frameHeight=48
frame_width=48
frame_height=48
[animation]
name=orange

View File

@@ -1,5 +1,5 @@
frameWidth=10
frameHeight=10
frame_width=10
frame_height=10
[animation]
name=default

View File

@@ -1,5 +1,5 @@
frameWidth=16
frameHeight=16
frame_width=16
frame_height=16
[animation]
name=default

View File

@@ -1,5 +1,5 @@
frameWidth=26
frameHeight=26
frame_width=26
frame_height=26
[animation]
name=default

View File

@@ -1,5 +1,5 @@
frameWidth=46
frameHeight=46
frame_width=46
frame_height=46
[animation]
name=default

View File

@@ -1,5 +1,5 @@
frameWidth=46
frameHeight=46
frame_width=46
frame_height=46
[animation]
name=powerball

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 799 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

@@ -1,5 +1,5 @@
frameWidth=20
frameHeight=20
frame_width=20
frame_height=20
[animation]
name=default

View File

@@ -1,5 +1,5 @@
frameWidth=20
frameHeight=20
frame_width=20
frame_height=20
[animation]
name=default

View File

@@ -1,5 +1,5 @@
frameWidth=28
frameHeight=37
frame_width=28
frame_height=37
[animation]
name=default

View File

@@ -1,5 +1,5 @@
frameWidth=20
frameHeight=20
frame_width=20
frame_height=20
[animation]
name=default

View File

@@ -1,5 +1,5 @@
frameWidth=20
frameHeight=20
frame_width=20
frame_height=20
[animation]
name=default

View File

@@ -1,5 +1,5 @@
frameWidth=20
frameHeight=20
frame_width=20
frame_height=20
[animation]
name=default

View File

@@ -1,5 +1,5 @@
frameWidth=30
frameHeight=30
frame_width=30
frame_height=30
[animation]
name=walk

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

View File

@@ -1,5 +1,5 @@
frameWidth=39
frameHeight=44
frame_width=39
frame_height=44
[animation]
name=default

Binary file not shown.

Before

Width:  |  Height:  |  Size: 944 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 B

View File

@@ -1,5 +1,5 @@
frameWidth=16
frameHeight=16
frame_width=16
frame_height=16
[animation]
name=default

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
@@ -317,4 +317,34 @@ per jugar
Continuar?
## 106 - MARCADOR
Posa el nom
Posa el nom
## 107 - AJUDA
Intercanviar mandos
## 108 - AJUDA
Configuracio
## 109 - AJUDA
Alternar el audio
## 110 - AJUDA
Filtres
## 111 - AJUDA
Reiniciar
## 112 - AJUDA
Pausar
## 113 - AJUDA
Eixir
## 114 - MARCADOR
Per favor
## 115 - MARCADOR
espere
## 116 - NOTIFICACIONES
Torna a polsar per apagar el sistema

View File

@@ -317,4 +317,34 @@ to play
Continue?
## 106 - MARCADOR
Enter name
Enter name
## 107 - AJUDA
Swap Controllers
## 108 - AJUDA
Configuration
## 109 - AJUDA
Toggle audio
## 110 - AJUDA
Shaders
## 111 - AJUDA
Reset
## 112 - AJUDA
Pause
## 113 - AJUDA
Exit
## 114 - MARCADOR
Please
## 115 - MARCADOR
wait
## 116 - NOTIFICACIONES
Press again to shutdown system

View File

@@ -317,4 +317,34 @@ para jugar
Continuar?
## 106 - MARCADOR
Pon tu nombre
Pon tu nombre
## 107 - AJUDA
Intercambiar mandos
## 108 - AJUDA
Configuracion
## 109 - AJUDA
Alternar el audio
## 110 - AJUDA
Filtros
## 111 - AJUDA
Reiniciar
## 112 - AJUDA
Pausar
## 113 - AJUDA
Salir
## 114 - MARCADOR
Por favor
## 115 - MARCADOR
espere
## 94 - NOTIFICACIONES
Pulsa otra vez para apagar el sistema

View File

@@ -4,5 +4,7 @@ SOURCEPATH=../source/
for i in "$SOURCEPATH"/*.cpp
do
include-what-you-use -D DEBUG -D VERBOSE -std=c++11 -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

@@ -0,0 +1,3 @@
#!/bin/bash
valgrind --suppressions=valgrind_exceptions --leak-check=full ~/coffee_crisis_arcade_edition/coffee_crisis_arcade_edition_debug > ~/coffee_crisis_arcade_edition/debug.txt 2>&1

View File

@@ -0,0 +1,12 @@
{
ignore_unversioned_libs
Memcheck:Leak
...
obj:*/lib*/lib*.so
}
{
ignore_versioned_libs
Memcheck:Leak
...
obj:*/lib*/lib*.so.*
}

View File

@@ -1,213 +1,73 @@
#include "animated_sprite.h"
#include <fstream> // for basic_ostream, operator<<, basic_istream, basic...
#include <iostream> // for cout
#include <sstream> // for basic_stringstream
#include "texture.h" // for Texture
#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
animatedSprite_t loadAnimationFromFile(Texture *texture, std::string filePath, bool verbose)
// Carga las animaciones en un vector(Animations) desde un fichero
Animations loadAnimationsFromFile(const std::string &file_path)
{
// Inicializa variables
animatedSprite_t as;
as.texture = texture;
int framesPerRow = 0;
int frameWidth = 0;
int frameHeight = 0;
int maxTiles = 0;
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);
}
const std::string filename = filePath.substr(filePath.find_last_of("\\/") + 1);
std::ifstream file(filePath);
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
if (verbose)
{
std::cout << "Animation loaded: " << filename << 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_t buffer;
buffer.counter = 0;
buffer.currentFrame = 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, frameWidth, frameHeight};
while (getline(ss, tmp, ','))
{
// Comprueba que el tile no sea mayor que el maximo indice permitido
const int numTile = std::stoi(tmp) > maxTiles ? 0 : std::stoi(tmp);
rect.x = (numTile % framesPerRow) * frameWidth;
rect.y = (numTile / framesPerRow) * frameHeight;
buffer.frames.push_back(rect);
}
}
else
{
std::cout << "Warning: file " << filename.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
as.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) == "framesPerRow")
{
framesPerRow = std::stoi(line.substr(pos + 1, line.length()));
}
else if (line.substr(0, pos) == "frameWidth")
{
frameWidth = std::stoi(line.substr(pos + 1, line.length()));
}
else if (line.substr(0, pos) == "frameHeight")
{
frameHeight = std::stoi(line.substr(pos + 1, line.length()));
}
else
{
std::cout << "Warning: file " << filename.c_str() << "\n, unknown parameter \"" << line.substr(0, pos).c_str() << "\"" << std::endl;
}
// Normaliza valores
if (framesPerRow == 0 && frameWidth > 0)
{
framesPerRow = texture->getWidth() / frameWidth;
}
if (maxTiles == 0 && frameWidth > 0 && frameHeight > 0)
{
const int w = texture->getWidth() / frameWidth;
const int h = texture->getHeight() / frameHeight;
maxTiles = w * h;
}
}
}
}
// Cierra el fichero
file.close();
}
// El fichero no se puede abrir
else
{
if (verbose)
{
std::cout << "Warning: Unable to open " << filename.c_str() << " file" << std::endl;
}
buffer.push_back(line);
}
return as;
return buffer;
}
// Constructor
AnimatedSprite::AnimatedSprite(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())
{
animatedSprite_t as = loadAnimationFromFile(texture, file);
// Copia los datos de las animaciones
for (auto animation : as.animations)
{
this->animation.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
currentAnimation = 0;
}
// Constructor
AnimatedSprite::AnimatedSprite(animatedSprite_t *animation)
{
// Copia los punteros
setTexture(animation->texture);
// Inicializa variables
currentAnimation = 0;
// Copia los datos de las animaciones
for (auto a : animation->animations)
{
this->animation.push_back(a);
}
}
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture)
: MovingSprite(texture),
current_animation_(0) {}
// Destructor
AnimatedSprite::~AnimatedSprite()
{
for (auto &a : animation)
{
a.frames.clear();
}
animation.clear();
animations_.clear();
}
// Obtiene el indice de la animación a partir del nombre
int AnimatedSprite::getIndex(std::string name)
int AnimatedSprite::getIndex(const std::string &name)
{
int index = -1;
auto index = -1;
for (auto a : animation)
for (const auto &a : animations_)
{
index++;
if (a.name == name)
@@ -215,293 +75,153 @@ int AnimatedSprite::getIndex(std::string name)
return index;
}
}
std::cout << "** Warning: could not find \"" << name.c_str() << "\" animation" << std::endl;
return -1;
}
// Calcula el frame correspondiente a la animación
void AnimatedSprite::animate()
{
if (!enabled || animation[currentAnimation].speed == 0)
if (animations_[current_animation_].speed == 0)
{
return;
}
// Calcula el frame actual a partir del contador
animation[currentAnimation].currentFrame = animation[currentAnimation].counter / animation[currentAnimation].speed;
animations_[current_animation_].current_frame = animations_[current_animation_].counter / animations_[current_animation_].speed;
// Si alcanza el final de la animación, reinicia el contador de la animación
// en función de la variable loop y coloca el nuevo frame
if (animation[currentAnimation].currentFrame >= (int)animation[currentAnimation].frames.size())
if (animations_[current_animation_].current_frame >= (int)animations_[current_animation_].frames.size())
{
if (animation[currentAnimation].loop == -1)
if (animations_[current_animation_].loop == -1)
{ // Si no hay loop, deja el último frame
animation[currentAnimation].currentFrame = animation[currentAnimation].frames.size();
animation[currentAnimation].completed = true;
animations_[current_animation_].current_frame = animations_[current_animation_].frames.size();
animations_[current_animation_].completed = true;
}
else
{ // Si hay loop, vuelve al frame indicado
animation[currentAnimation].counter = 0;
animation[currentAnimation].currentFrame = animation[currentAnimation].loop;
animations_[current_animation_].counter = 0;
animations_[current_animation_].current_frame = animations_[current_animation_].loop;
}
}
// En caso contrario
else
{
// Escoge el frame correspondiente de la animación
setSpriteClip(animation[currentAnimation].frames[animation[currentAnimation].currentFrame]);
setSpriteClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]);
// Incrementa el contador de la animacion
animation[currentAnimation].counter++;
animations_[current_animation_].counter++;
}
}
// Obtiene el número de frames de la animación actual
int AnimatedSprite::getNumFrames()
{
return (int)animation[currentAnimation].frames.size();
return (int)animations_[current_animation_].frames.size();
}
// Establece el frame actual de la animación
void AnimatedSprite::setCurrentFrame(int num)
{
// Descarta valores fuera de rango
if (num >= (int)animation[currentAnimation].frames.size())
if (num >= (int)animations_[current_animation_].frames.size())
{
num = 0;
}
// Cambia el valor de la variable
animation[currentAnimation].currentFrame = num;
animation[currentAnimation].counter = 0;
animations_[current_animation_].current_frame = num;
animations_[current_animation_].counter = 0;
// Escoge el frame correspondiente de la animación
setSpriteClip(animation[currentAnimation].frames[animation[currentAnimation].currentFrame]);
setSpriteClip(animations_[current_animation_].frames[animations_[current_animation_].current_frame]);
}
// Establece el valor del contador
void AnimatedSprite::setAnimationCounter(std::string name, int num)
void AnimatedSprite::setAnimationCounter(const std::string &name, int num)
{
animation[getIndex(name)].counter = 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)
{
animation[getIndex(name)].counter = speed;
animations_[getIndex(name)].counter = speed;
}
// Establece la velocidad de una animación
void AnimatedSprite::setAnimationSpeed(int index, int speed)
{
animation[index].counter = speed;
animations_[index].counter = 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)
{
animation[getIndex(name)].loop = loop;
animations_[getIndex(name)].loop = loop;
}
// Establece si la animación se reproduce en bucle
void AnimatedSprite::setAnimationLoop(int index, int loop)
{
animation[index].loop = loop;
animations_[index].loop = loop;
}
// Establece el valor de la variable
void AnimatedSprite::setAnimationCompleted(std::string name, bool value)
void AnimatedSprite::setAnimationCompleted(const std::string &name, bool value)
{
animation[getIndex(name)].completed = value;
animations_[getIndex(name)].completed = value;
}
// OLD - Establece el valor de la variable
void AnimatedSprite::setAnimationCompleted(int index, bool value)
{
animation[index].completed = value;
animations_[index].completed = value;
}
// Comprueba si ha terminado la animación
bool AnimatedSprite::animationIsCompleted()
{
return animation[currentAnimation].completed;
return animations_[current_animation_].completed;
}
// 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 animation[getIndex(name)].frames[index];
return animations_[getIndex(name)].frames[index];
}
// Devuelve el rectangulo de una animación y frame concreto
SDL_Rect AnimatedSprite::getAnimationClip(int indexA, Uint8 indexF)
{
return animation[indexA].frames[indexF];
}
// Carga la animación desde un vector
bool AnimatedSprite::loadFromVector(std::vector<std::string> *source)
{
// Inicializa variables
int framesPerRow = 0;
int frameWidth = 0;
int frameHeight = 0;
int maxTiles = 0;
// Indicador de éxito en el proceso
bool success = true;
std::string line;
// Recorre todo el vector
int index = 0;
while (index < (int)source->size())
{
// Lee desde el vector
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_t buffer;
buffer.counter = 0;
buffer.currentFrame = 0;
buffer.completed = false;
do
{
// Aumenta el indice para leer la siguiente linea
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 (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, frameWidth, frameHeight};
while (getline(ss, tmp, ','))
{
// Comprueba que el tile no sea mayor que el maximo indice permitido
const int numTile = std::stoi(tmp) > maxTiles ? 0 : std::stoi(tmp);
rect.x = (numTile % framesPerRow) * frameWidth;
rect.y = (numTile / framesPerRow) * frameHeight;
buffer.frames.push_back(rect);
}
}
else
{
std::cout << "Warning: unknown parameter " << line.substr(0, pos).c_str() << std::endl;
success = false;
}
}
} while (line != "[/animation]");
// Añade la animación al vector de animaciones
animation.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) == "framesPerRow")
{
framesPerRow = std::stoi(line.substr(pos + 1, line.length()));
}
else if (line.substr(0, pos) == "frameWidth")
{
frameWidth = std::stoi(line.substr(pos + 1, line.length()));
}
else if (line.substr(0, pos) == "frameHeight")
{
frameHeight = std::stoi(line.substr(pos + 1, line.length()));
}
else
{
std::cout << "Warning: unknown parameter " << line.substr(0, pos).c_str() << std::endl;
success = false;
}
// Normaliza valores
if (framesPerRow == 0 && frameWidth > 0)
{
framesPerRow = texture->getWidth() / frameWidth;
}
if (maxTiles == 0 && frameWidth > 0 && frameHeight > 0)
{
const int w = texture->getWidth() / frameWidth;
const int h = texture->getHeight() / frameHeight;
maxTiles = w * h;
}
}
}
// Una vez procesada la linea, aumenta el indice para pasar a la siguiente
index++;
}
// Pone un valor por defecto
setRect({0, 0, frameWidth, frameHeight});
return success;
return animations_[indexA].frames[indexF];
}
// Establece la animacion actual
void AnimatedSprite::setCurrentAnimation(std::string name)
void AnimatedSprite::setCurrentAnimation(const std::string &name)
{
const int newAnimation = getIndex(name);
if (currentAnimation != newAnimation)
const auto new_animation = getIndex(name);
if (current_animation_ != new_animation)
{
currentAnimation = newAnimation;
animation[currentAnimation].currentFrame = 0;
animation[currentAnimation].counter = 0;
animation[currentAnimation].completed = false;
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 int newAnimation = index;
if (currentAnimation != newAnimation)
const auto new_animation = index;
if (current_animation_ != new_animation)
{
currentAnimation = newAnimation;
animation[currentAnimation].currentFrame = 0;
animation[currentAnimation].counter = 0;
animation[currentAnimation].completed = false;
current_animation_ = new_animation;
animations_[current_animation_].current_frame = 0;
animations_[current_animation_].counter = 0;
animations_[current_animation_].completed = false;
}
}
@@ -515,13 +235,13 @@ void AnimatedSprite::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)
{
animation[index_animation].frames.push_back({x, y, w, 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 : animation)
for (auto &a : animations_)
{
a.counter = value;
}
@@ -530,7 +250,282 @@ void AnimatedSprite::setAnimationCounter(int value)
// Reinicia la animación
void AnimatedSprite::resetAnimation()
{
animation[currentAnimation].currentFrame = 0;
animation[currentAnimation].counter = 0;
animation[currentAnimation].completed = false;
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(const Animations &source)
{
// Inicializa variables
auto frames_per_row = 0;
auto frame_width = 0;
auto frame_height = 0;
auto max_tiles = 0;
// Indicador de éxito en el proceso
auto success = true;
std::string line;
// Recorre todo el vector
auto index = 0;
while (index < (int)source.size())
{
// Lee desde el vector
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 animation = Animation();
do
{
// Aumenta el indice para leer la siguiente linea
index++;
line = source.at(index);
// 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 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;
animation.frames.push_back(rect);
}
}
else
{
std::cout << "Warning: unknown parameter " << line.substr(0, pos).c_str() << std::endl;
success = false;
}
}
} 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: unknown parameter " << line.substr(0, pos).c_str() << std::endl;
success = false;
}
// 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 int w = texture_->getWidth() / frame_width;
const int h = texture_->getHeight() / frame_height;
max_tiles = w * h;
}
}
}
// Una vez procesada la linea, aumenta el indice para pasar a la siguiente
index++;
}
// Pone un valor por defecto
setWidth(frame_width);
setHeight(frame_height);
return success;
}

View File

@@ -1,50 +1,59 @@
#pragma once
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_stdinc.h> // for Uint8
#include <string> // for string, basic_string
#include <vector> // for vector
#include "moving_sprite.h" // for MovingSprite
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_stdinc.h> // for Uint8
#include <memory> // for shared_ptr
#include <string> // for string
#include <vector> // for vector
#include "moving_sprite.h" // for MovingSprite
class Texture;
struct animation_t
struct Animation
{
std::string name; // Nombre de la animacion
std::vector<SDL_Rect> frames; // Cada uno de los frames que componen la animación
int speed; // Velocidad de la animación
int loop; // Indica a que frame vuelve la animación al terminar. -1 para que no vuelva
bool completed; // Indica si ha finalizado la animación
int currentFrame; // Frame actual
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 animatedSprite_t
{
std::vector<animation_t> animations; // Vector con las diferentes animaciones
Texture *texture; // Textura con los graficos para el sprite
};
using Animations = std::vector<std::string>;
// Carga la animación desde un fichero
animatedSprite_t loadAnimationFromFile(Texture *texture, std::string filePath, bool verbose = false);
// 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_t> animation; // Vector con las diferentes animaciones
int currentAnimation; // Animacion activa
public:
// Constructor
AnimatedSprite(Texture *texture = nullptr, std::string file = "", std::vector<std::string> *buffer = nullptr);
AnimatedSprite(animatedSprite_t *animation);
// Destructor
~AnimatedSprite();
std::vector<Animation> animations_; // Vector con las diferentes animaciones
int current_animation_; // Animacion activa
// 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();
@@ -52,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,68 +1,58 @@
#include "asset.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
#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 executablePath)
void Asset::init(const std::string &executable_path)
{
Asset::asset = new Asset(executablePath);
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 executablePath)
Asset::Asset(const std::string &executable_path)
: executable_path_(executable_path.substr(0, executable_path.find_last_of("\\/")))
{
this->executablePath = executablePath.substr(0, executablePath.find_last_of("\\/"));
longestName = 0;
#ifdef VERBOSE
verbose = true;
#else
verbose = false;
#endif
}
// Destructor
Asset::~Asset()
{
longest_name_ = 0;
}
// Añade un elemento a la lista
void Asset::add(std::string file, enum assetType type, bool required, bool absolute)
void Asset::add(const std::string &file, AssetType type, bool required, bool absolute)
{
item_t temp;
temp.file = absolute ? file : executablePath + file;
temp.type = type;
temp.required = required;
fileList.push_back(temp);
AssetItem ai;
ai.file = absolute ? file : executable_path_ + file;
ai.type = type;
ai.required = required;
file_list_.push_back(ai);
const std::string filename = file.substr(file.find_last_of("\\/") + 1);
longestName = SDL_max(longestName, filename.size());
const std::string file_name = file.substr(file.find_last_of("\\/") + 1);
longest_name_ = SDL_max(longest_name_, file_name.size());
}
// Devuelve el fichero de un elemento de la lista a partir de una cadena
std::string Asset::get(std::string text)
std::string Asset::get(const std::string &text) const
{
for (auto f : fileList)
for (const auto &f : file_list_)
{
const size_t lastIndex = f.file.find_last_of("/") + 1;
const std::string file = f.file.substr(lastIndex, std::string::npos);
const size_t last_index = f.file.find_last_of("/") + 1;
const std::string file = f.file.substr(last_index, std::string::npos);
if (file == text)
{
@@ -70,35 +60,29 @@ std::string Asset::get(std::string text)
}
}
if (verbose)
{
std::cout << "Warning: file " << text.c_str() << " not found" << std::endl;
}
std::cout << "Warning: file " << text.c_str() << " not found" << std::endl;
return "";
}
// Comprueba que existen todos los elementos
bool Asset::check()
bool Asset::check() const
{
bool success = true;
if (verbose)
{
std::cout << "\n** Checking files" << std::endl;
std::cout << "\n** CHECKING FILES" << std::endl;
std::cout << "Executable path is: " << executablePath << std::endl;
std::cout << "Sample filepath: " << fileList.back().file << std::endl;
}
// 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 < t_maxAssetType; ++type)
for (int type = 0; type < static_cast<int>(AssetType::MAX_ASSET_TYPE); ++type)
{
// Comprueba si hay ficheros de ese tipo
bool any = false;
for (auto f : fileList)
for (const auto &f : file_list_)
{
if ((f.required) && (f.type == type))
if (f.required && f.type == static_cast<AssetType>(type))
{
any = true;
}
@@ -107,107 +91,85 @@ bool Asset::check()
// Si hay ficheros de ese tipo, comprueba si existen
if (any)
{
if (verbose)
{
std::cout << "\n>> " << getTypeName(type).c_str() << " FILES" << std::endl;
}
std::cout << "\n>> " << getTypeName(static_cast<AssetType>(type)).c_str() << " FILES" << std::endl;
for (auto f : fileList)
for (const auto &f : file_list_)
{
if ((f.required) && (f.type == type))
if (f.required && f.type == static_cast<AssetType>(type))
{
success &= checkFile(f.file);
}
}
if (success)
std::cout << " All files are OK." << std::endl;
}
}
// Resultado
if (verbose)
{
if (success)
{
std::cout << "\n** All files OK.\n"
<< std::endl;
}
else
{
std::cout << "\n** A file is missing. Exiting.\n"
<< std::endl;
}
}
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)
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 filename = 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);
}
if (verbose)
{
std::cout.setf(std::ios::left, std::ios::adjustfield);
std::cout << "Checking file: ";
std::cout.width(longestName + 2);
std::cout.fill('.');
std::cout << filename + " ";
std::cout << " [" + result + "]" << std::endl;
}
const std::string file_name = path.substr(path.find_last_of("\\/") + 1);
if (!success)
printWithDots("Checking file : ", file_name, (success ? " [ OK ]" : " [ ERROR ]"));
return success;
}
// Devuelve el nombre del tipo de recurso
std::string Asset::getTypeName(int type)
std::string Asset::getTypeName(AssetType type) const
{
switch (type)
{
case t_bitmap:
case AssetType::BITMAP:
return "BITMAP";
break;
case t_music:
case AssetType::MUSIC:
return "MUSIC";
break;
case t_sound:
case AssetType::SOUND:
return "SOUND";
break;
case t_font:
case AssetType::FONT:
return "FONT";
break;
case t_lang:
case AssetType::LANG:
return "LANG";
break;
case t_data:
case AssetType::DATA:
return "DATA";
break;
case t_animation:
case AssetType::ANIMATION:
return "ANIMATION";
break;
case t_palette:
case AssetType::PALETTE:
return "PALETTE";
break;
case t_item:
case AssetType::ITEM:
return "ITEM";
break;
@@ -217,18 +179,12 @@ std::string Asset::getTypeName(int type)
}
}
// Establece si ha de mostrar texto por pantalla
void Asset::setVerbose(bool value)
{
verbose = value;
}
// Devuelve la lista de recursos de un tipo
std::vector<std::string> Asset::getListByType(assetType type)
std::vector<std::string> Asset::getListByType(AssetType type) const
{
std::vector<std::string> list;
for (auto f : fileList)
for (auto f : file_list_)
{
if (f.type == type)
{

View File

@@ -1,20 +1,20 @@
#pragma once
#include <string> // for string, basic_string
#include <vector> // for vector
#include <string> // for string, basic_string
#include <vector> // for vector
enum assetType
enum class AssetType : int
{
t_bitmap,
t_music,
t_sound,
t_font,
t_lang,
t_data,
t_animation,
t_palette,
t_item,
t_maxAssetType
BITMAP,
MUSIC,
SOUND,
FONT,
LANG,
DATA,
ANIMATION,
PALETTE,
ITEM,
MAX_ASSET_TYPE,
};
// Clase Asset
@@ -22,38 +22,37 @@ class Asset
{
private:
// [SINGLETON] Objeto asset privado para Don Melitón
static Asset *asset;
static Asset *asset_;
// Estructura para definir un item
struct item_t
struct AssetItem
{
std::string file; // Ruta del fichero desde la raiz del directorio
enum assetType type; // Indica el tipo de recurso
enum AssetType type; // Indica el tipo de recurso
bool required; // Indica si es un fichero que debe de existir
// bool absolute; // Indica si la ruta que se ha proporcionado es una ruta absoluta
};
// Variables
int longestName; // Contiene la longitud del nombre de fichero mas largo
std::vector<item_t> fileList; // Listado con todas las rutas a los ficheros
std::string executablePath; // Ruta al ejecutable
bool verbose; // Indica si ha de mostrar información por pantalla
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
// Comprueba que existe un fichero
bool checkFile(std::string executablePath);
bool checkFile(const std::string &path) const;
// Devuelve el nombre del tipo de recurso
std::string getTypeName(int type);
std::string getTypeName(AssetType type) const;
// Constructor
Asset(std::string path);
explicit Asset(const std::string &executable_path);
// Destructor
~Asset();
~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();
@@ -62,17 +61,14 @@ public:
static Asset *get();
// Añade un elemento a la lista
void add(std::string file, enum 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);
std::string get(const std::string &text) const;
// Comprueba que existen todos los elementos
bool check();
// Establece si ha de mostrar texto por pantalla
void setVerbose(bool value);
bool check() const;
// Devuelve la lista de recursos de un tipo
std::vector<std::string> getListByType(assetType type);
std::vector<std::string> getListByType(AssetType type) const;
};

View File

@@ -1,187 +1,188 @@
#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 "asset.h" // for Asset
#include "moving_sprite.h" // for MovingSprite
#include "param.h" // for param
#include "sprite.h" // for Sprite
#include "texture.h" // for Texture
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND
#include <SDL2/SDL_pixels.h> // for SDL_PIXELFORMAT_RGBA8888
#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)
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)
{
// Copia los punteros
this->renderer = renderer;
asset = Asset::get();
// Carga las texturas
buildingsTexture = new Texture(renderer, asset->get("game_buildings.png"));
topCloudsTexture = new Texture(renderer, asset->get("game_clouds1.png"));
bottomCloudsTexture = new Texture(renderer, asset->get("game_clouds2.png"));
grassTexture = new Texture(renderer, asset->get("game_grass.png"));
gradientsTexture = new Texture(renderer, asset->get("game_sky_colors.png"));
// Inicializa variables
gradientNumber = 0;
alpha = 0;
cloudsSpeed = 0;
transition = 0;
counter = 0;
rect = {0, 0, gradientsTexture->getWidth() / 2, gradientsTexture->getHeight() / 2};
srcRect = {0, 0, 320, 240};
dstRect = {0, 0, 320, 240};
base = rect.h;
color = {param.background.attenuateColor.r, param.background.attenuateColor.g, param.background.attenuateColor.b};
alphaColorText = alphaColorTextTemp = param.background.attenuateAlpha;
gradientRect[0] = {0, 0, rect.w, rect.h};
gradientRect[1] = {rect.w, 0, rect.w, rect.h};
gradientRect[2] = {0, rect.h, rect.w, rect.h};
gradientRect[3] = {rect.w, rect.h, rect.w, rect.h};
const int topCloudsTextureHeight = topCloudsTexture->getHeight() / 4;
const int bottomCloudsTextureHeight = bottomCloudsTexture->getHeight() / 4;
for (int i = 0; i < 4; ++i)
{
topCloudsRect[i] = {0, i * topCloudsTextureHeight, topCloudsTexture->getWidth(), topCloudsTextureHeight};
bottomCloudsRect[i] = {0, i * bottomCloudsTextureHeight, bottomCloudsTexture->getWidth(), bottomCloudsTextureHeight};
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 topClouds_y = base - 165;
const int bottomClouds_y = base - 101;
const float topCloudsSpeed = 0.1f;
const float bottomCloudsSpeed = 0.05f;
topCloudsSprite_A = new MovingSprite(0, topClouds_y, rect.w, topCloudsTexture->getHeight(), -topCloudsSpeed, 0.0f, 0.0f, 0.0f, topCloudsTexture);
topCloudsSprite_B = new MovingSprite(rect.w, topClouds_y, rect.w, topCloudsTexture->getHeight(), -topCloudsSpeed, 0.0f, 0.0f, 0.0f, topCloudsTexture);
{
const int top_clouds_y = base_ - 165;
const int bottom_clouds_y = base_ - 101;
bottomCloudsSprite_A = new MovingSprite(0, bottomClouds_y, rect.w, bottomCloudsTexture->getHeight(), -bottomCloudsSpeed, 0.0f, 0.0f, 0.0f, bottomCloudsTexture);
bottomCloudsSprite_B = new MovingSprite(rect.w, bottomClouds_y, rect.w, bottomCloudsTexture->getHeight(), -bottomCloudsSpeed, 0.0f, 0.0f, 0.0f, bottomCloudsTexture);
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()});
buildingsSprite = new Sprite(0, 0, buildingsTexture->getWidth(), buildingsTexture->getHeight(), buildingsTexture);
gradientSprite = new Sprite(0, 0, rect.w, rect.h, gradientsTexture);
grassSprite = new Sprite(0, 0, grassTexture->getWidth(), grassTexture->getHeight() / 2, grassTexture);
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
topCloudsSprite_A->setSpriteClip(0, 0, topCloudsTexture->getWidth(), topCloudsTexture->getHeight());
topCloudsSprite_B->setSpriteClip(0, 0, topCloudsTexture->getWidth(), topCloudsTexture->getHeight());
bottomCloudsSprite_A->setSpriteClip(0, 0, bottomCloudsTexture->getWidth(), bottomCloudsTexture->getHeight());
bottomCloudsSprite_B->setSpriteClip(0, 0, bottomCloudsTexture->getWidth(), bottomCloudsTexture->getHeight());
buildingsSprite->setPosY(base - buildingsSprite->getHeight());
grassSprite->setPosY(base - grassSprite->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);
SDL_SetTextureBlendMode(canvas, SDL_BLENDMODE_BLEND);
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
colorTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect.w, rect.h);
SDL_SetTextureBlendMode(colorTexture, SDL_BLENDMODE_BLEND);
setColor(color);
SDL_SetTextureAlphaMod(colorTexture, alphaColorText);
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_);
}
// Destructor
Background::~Background()
{
delete buildingsTexture;
delete topCloudsTexture;
delete bottomCloudsTexture;
delete grassTexture;
delete gradientsTexture;
delete topCloudsSprite_A;
delete topCloudsSprite_B;
delete bottomCloudsSprite_A;
delete bottomCloudsSprite_B;
delete buildingsSprite;
delete gradientSprite;
delete grassSprite;
SDL_DestroyTexture(canvas);
SDL_DestroyTexture(colorTexture);
SDL_DestroyTexture(canvas_);
SDL_DestroyTexture(color_texture_);
}
// Actualiza la lógica del objeto
void Background::update()
{
// Actualiza el valor de alpha
// Actualiza el valor de alpha_
updateAlphaColorText();
// Actualiza las nubes
updateClouds();
// Calcula el frame de la hierba
grassSprite->setSpriteClip(0, (10 * (counter / 20 % 2)), 320, 10);
grass_sprite_->setSpriteClip(0, (10 * (counter_ / 20 % 2)), 320, 10);
// Calcula el valor de alpha
alpha = std::max((255 - (int)(255 * transition)), 0);
// Calcula el valor de alpha_
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
gradientsTexture->setAlpha(255);
gradientSprite->setSpriteClip(gradientRect[(gradientNumber + 1) % 4]);
gradientSprite->render();
// 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
gradientsTexture->setAlpha(alpha);
gradientSprite->setSpriteClip(gradientRect[gradientNumber]);
gradientSprite->render();
// 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();
}
// Dibuja las nubes de arriba
void Background::renderTopClouds()
{
// Dibuja el primer conjunto de nubes
topCloudsTexture->setAlpha(255);
topCloudsSprite_A->setSpriteClip(topCloudsRect[(gradientNumber + 1) % 4]);
topCloudsSprite_A->render();
topCloudsSprite_B->setSpriteClip(topCloudsRect[(gradientNumber + 1) % 4]);
topCloudsSprite_B->render();
// 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_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
topCloudsTexture->setAlpha(alpha);
topCloudsSprite_A->setSpriteClip(topCloudsRect[gradientNumber]);
topCloudsSprite_A->render();
topCloudsSprite_B->setSpriteClip(topCloudsRect[gradientNumber]);
topCloudsSprite_B->render();
// 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_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
bottomCloudsTexture->setAlpha(255);
bottomCloudsSprite_A->setSpriteClip(bottomCloudsRect[(gradientNumber + 1) % 4]);
bottomCloudsSprite_A->render();
bottomCloudsSprite_B->setSpriteClip(bottomCloudsRect[(gradientNumber + 1) % 4]);
bottomCloudsSprite_B->render();
// 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_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
bottomCloudsTexture->setAlpha(alpha);
bottomCloudsSprite_A->setSpriteClip(bottomCloudsRect[gradientNumber]);
bottomCloudsSprite_A->render();
bottomCloudsSprite_B->setSpriteClip(bottomCloudsRect[gradientNumber]);
bottomCloudsSprite_B->render();
// 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_b_->setSpriteClip(bottom_clouds_rect_[gradient_number_]);
bottom_clouds_sprite_a_->render();
bottom_clouds_sprite_b_->render();
}
// Compone todos los elementos del fondo en la textura
void Background::fillCanvas()
{
// Cambia el destino del renderizador
SDL_Texture *temp = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, canvas);
auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, canvas_);
// Dibuja el gradiente de fondo
renderGradient();
@@ -193,119 +194,114 @@ void Background::fillCanvas()
renderBottomClouds();
// Dibuja los edificios
buildingsSprite->render();
buildings_sprite_->render();
// Dibuja la hierba
grassSprite->render();
grass_sprite_->render();
// Deja el renderizador apuntando donde estaba
SDL_SetRenderTarget(renderer, temp);
SDL_SetRenderTarget(renderer_, temp);
}
// Dibuja el objeto
void Background::render()
{
// Fondo
SDL_RenderCopy(renderer, canvas, &srcRect, &dstRect);
SDL_RenderCopy(renderer_, canvas_, &src_rect_, &dst_rect_);
// Atenuación
SDL_RenderCopy(renderer, colorTexture, &srcRect, &dstRect);
SDL_RenderCopy(renderer_, color_texture_, &src_rect_, &dst_rect_);
}
// Vuelve a cargar las texturas
void Background::reloadTextures()
{
buildingsTexture->reLoad();
topCloudsTexture->reLoad();
bottomCloudsTexture->reLoad();
grassTexture->reLoad();
gradientsTexture->reLoad();
buildings_texture_->reLoad();
top_clouds_texture_->reLoad();
bottom_clouds_texture_->reLoad();
grass_texture_->reLoad();
gradients_texture_->reLoad();
}
// Ajusta el valor de la variable
void Background::setCloudsSpeed(float value)
{
cloudsSpeed = value;
clouds_speed_ = value;
}
// Ajusta el valor de la variable
void Background::setGradientNumber(int value)
{
gradientNumber = value % 4;
gradient_number_ = value % 4;
}
// 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
void Background::setPos(SDL_Rect pos)
{
this->dstRect = pos;
dst_rect_ = pos;
// Si cambian las medidas del destino, hay que cambiar las del origen para evitar deformar la imagen
this->srcRect.x = 0;
this->srcRect.y = rect.h - pos.h;
this->srcRect.w = pos.w;
this->srcRect.h = pos.h;
src_rect_.x = 0;
src_rect_.y = rect_.h - pos.h;
src_rect_.w = pos.w;
src_rect_.h = pos.h;
}
// Ajusta el valor de la variable
void Background::setSrcRect(SDL_Rect value)
{
srcRect = value;
src_rect_ = value;
}
// Ajusta el valor de la variable
void Background::setDstRect(SDL_Rect value)
{
dstRect = value;
dst_rect_ = value;
}
// Establece el color de atenuación
void Background::setColor(color_t color)
// Establece el color_ de atenuación
void Background::setColor(Color color)
{
this->color = color;
color_ = color;
// Colorea la textura
SDL_Texture *temp = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, colorTexture);
auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, color_texture_);
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_);
SDL_SetRenderTarget(renderer, temp);
SDL_SetRenderTarget(renderer_, temp);
}
// Establece la transparencia de la atenuación
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
alphaColorTextTemp = alphaColorText;
// Establece el nuevo valor
alphaColorText = alpha;
// Guarda el valor actual y establece el nuevo valor
alpha_color_text_temp_ = alpha_color_text_;
alpha_color_text_ = alpha_;
}
// Actualiza el valor de alpha
// Actualiza el valor de alpha_
void Background::updateAlphaColorText()
{
if (alphaColorText == alphaColorTextTemp)
if (alpha_color_text_ == alpha_color_text_temp_)
{
return;
}
else
{
alphaColorText > alphaColorTextTemp ? alphaColorTextTemp++ : alphaColorTextTemp--;
SDL_SetTextureAlphaMod(colorTexture, alphaColorTextTemp);
alpha_color_text_ > alpha_color_text_temp_ ? ++alpha_color_text_temp_ : --alpha_color_text_temp_;
SDL_SetTextureAlphaMod(color_texture_, alpha_color_text_temp_);
}
}
@@ -313,35 +309,35 @@ void Background::updateAlphaColorText()
void Background::updateClouds()
{
// Aplica la velocidad calculada a las nubes
topCloudsSprite_A->setVelX(cloudsSpeed);
topCloudsSprite_B->setVelX(cloudsSpeed);
bottomCloudsSprite_A->setVelX(cloudsSpeed / 2);
bottomCloudsSprite_B->setVelX(cloudsSpeed / 2);
top_clouds_sprite_a_->setVelX(clouds_speed_);
top_clouds_sprite_b_->setVelX(clouds_speed_);
bottom_clouds_sprite_a_->setVelX(clouds_speed_ / 2);
bottom_clouds_sprite_b_->setVelX(clouds_speed_ / 2);
// Mueve las nubes
topCloudsSprite_A->move();
topCloudsSprite_B->move();
bottomCloudsSprite_A->move();
bottomCloudsSprite_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 (topCloudsSprite_A->getPosX() < -topCloudsSprite_A->getWidth())
if (top_clouds_sprite_a_->getPosX() < -top_clouds_sprite_a_->getWidth())
{
topCloudsSprite_A->setPosX(topCloudsSprite_A->getWidth());
top_clouds_sprite_a_->setPosX(top_clouds_sprite_a_->getWidth());
}
if (topCloudsSprite_B->getPosX() < -topCloudsSprite_B->getWidth())
if (top_clouds_sprite_b_->getPosX() < -top_clouds_sprite_b_->getWidth())
{
topCloudsSprite_B->setPosX(topCloudsSprite_B->getWidth());
top_clouds_sprite_b_->setPosX(top_clouds_sprite_b_->getWidth());
}
if (bottomCloudsSprite_A->getPosX() < -bottomCloudsSprite_A->getWidth())
if (bottom_clouds_sprite_a_->getPosX() < -bottom_clouds_sprite_a_->getWidth())
{
bottomCloudsSprite_A->setPosX(bottomCloudsSprite_A->getWidth());
bottom_clouds_sprite_a_->setPosX(bottom_clouds_sprite_a_->getWidth());
}
if (bottomCloudsSprite_B->getPosX() < -bottomCloudsSprite_B->getWidth())
if (bottom_clouds_sprite_b_->getPosX() < -bottom_clouds_sprite_b_->getWidth())
{
bottomCloudsSprite_B->setPosX(bottomCloudsSprite_B->getWidth());
bottom_clouds_sprite_b_->setPosX(bottom_clouds_sprite_b_->getWidth());
}
}

View File

@@ -1,9 +1,9 @@
#pragma once
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_render.h> // for SDL_Renderer, SDL_Texture
#include "utils.h" // for color_t
class Asset;
#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
class MovingSprite;
class Sprite;
class Texture;
@@ -38,7 +38,7 @@ class Texture;
- setDstRecr(SDL_Rect value)
Rectangulo de destino donde se mostrará el rectángulo antrior. Automaticamente modifica srcRect para coincidor en tamaño con el destino.
- setColor(color_t color)
- setColor(Color color)
Establece el color de la textura de superposición
- setAlpha(int alpha)
@@ -50,43 +50,42 @@ class Background
{
private:
// Objetos y punteros
SDL_Renderer *renderer; // El renderizador de la ventana
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
SDL_Renderer *renderer_; // El renderizador de la ventana
Texture *buildingsTexture; // Textura con los edificios de fondo
Texture *topCloudsTexture; // Textura con las nubes de fondo
Texture *bottomCloudsTexture; // Textura con las nubes de fondo
Texture *grassTexture; // Textura con la hierba del suelo
Texture *gradientsTexture; // Textura con los diferentes colores de fondo del juego
std::shared_ptr<Texture> buildings_texture_; // Textura con los edificios de fondo
std::shared_ptr<Texture> top_clouds_texture_; // Textura con las nubes de fondo
std::shared_ptr<Texture> bottom_clouds_texture_; // Textura con las nubes de fondo
std::shared_ptr<Texture> grass_texture_; // Textura con la hierba del suelo
std::shared_ptr<Texture> gradients_texture_; // Textura con los diferentes colores de fondo del juego
MovingSprite *topCloudsSprite_A; // Sprite para las nubes superiores
MovingSprite *topCloudsSprite_B; // Sprite para las nubes superiores
MovingSprite *bottomCloudsSprite_A; // Sprite para las nubes inferiores
MovingSprite *bottomCloudsSprite_B; // Sprite para las nubes inferiores
std::unique_ptr<MovingSprite> top_clouds_sprite_a_; // Sprite para las nubes superiores
std::unique_ptr<MovingSprite> top_clouds_sprite_b_; // Sprite para las nubes superiores
std::unique_ptr<MovingSprite> bottom_clouds_sprite_a_; // Sprite para las nubes inferiores
std::unique_ptr<MovingSprite> bottom_clouds_sprite_b_; // Sprite para las nubes inferiores
Sprite *buildingsSprite; // Sprite con los edificios de fondo
Sprite *gradientSprite; // Sprite con los graficos del degradado de color de fondo
Sprite *grassSprite; // Sprite para la hierba
std::unique_ptr<Sprite> buildings_sprite_; // Sprite con los edificios de fondo
std::unique_ptr<Sprite> gradient_sprite_; // Sprite con los graficos del degradado de color de fondo
std::unique_ptr<Sprite> grass_sprite_; // Sprite para la hierba
SDL_Texture *canvas; // Textura para componer el fondo
SDL_Texture *colorTexture; // Textura para atenuar el fondo
SDL_Texture *canvas_; // Textura para componer el fondo
SDL_Texture *color_texture_; // Textura para atenuar el fondo
// Variables
SDL_Rect gradientRect[4]; // Vector con las coordenadas de los 4 degradados para el cielo
SDL_Rect topCloudsRect[4]; // Vector con las coordenadas de los 4 nubes de arriba
SDL_Rect bottomCloudsRect[4]; // Vector con las coordenadas de los 4 nubes de abajo
int gradientNumber; // Indica el número de degradado de fondo que se va a dibujar
int alpha; // Transparencia entre los dos degradados
float cloudsSpeed; // Velocidad a la que se desplazan las nubes
float transition; // Nivel de transición del fondo 0..1
int counter; // Contador interno
SDL_Rect rect; // Tamaño del objeto fondo
SDL_Rect srcRect; // Parte del objeto fondo que se va a dibujará en pantalla
SDL_Rect dstRect; // Posición donde dibujar la parte del objeto fondo que se dibujará en pantalla
int base; // Linea de fondo coincidente con el area inferior de la zona de juego
color_t color; // Color para atenuar el fondo
int alphaColorText; // Alpha para atenuar el fondo
int alphaColorTextTemp; // Valor temporal para hacer la transición de alpha
SDL_Rect gradient_rect_[4]; // Vector con las coordenadas de los 4 degradados para el cielo
SDL_Rect top_clouds_rect_[4]; // Vector con las coordenadas de los 4 nubes de arriba
SDL_Rect bottom_clouds_rect_[4]; // Vector con las coordenadas de los 4 nubes de abajo
int gradient_number_; // Indica el número de degradado de fondo que se va a dibujar
int alpha_; // Transparencia entre los dos degradados
float clouds_speed_; // Velocidad a la que se desplazan las nubes
float transition_; // Nivel de transición del fondo 0..1
int counter_; // Contador interno
SDL_Rect rect_; // Tamaño del objeto fondo
SDL_Rect src_rect_; // Parte del objeto fondo que se va a dibujará en pantalla
SDL_Rect dst_rect_; // Posición donde dibujar la parte del objeto fondo que se dibujará en pantalla
int base_; // Linea de fondo coincidente con el area inferior de la zona de juego
Color color_; // Color para atenuar el fondo
int alpha_color_text_; // Alpha para atenuar el fondo
int alpha_color_text_temp_; // Valor temporal para hacer la transición de alpha
// Dibuja el gradiente de fondo
void renderGradient();
@@ -108,7 +107,7 @@ private:
public:
// Constructor
Background(SDL_Renderer *renderer);
Background();
// Destructor
~Background();
@@ -141,7 +140,7 @@ public:
void setDstRect(SDL_Rect value);
// Establece el color de atenuación
void setColor(color_t color);
void setColor(Color color);
// Establece la transparencia de la atenuación
void setAlpha(int alpha);

File diff suppressed because it is too large Load Diff

View File

@@ -1,77 +1,78 @@
#pragma once
#include <SDL2/SDL_stdinc.h> // for Uint8, Uint16, Uint32
#include <string> // for string
#include <vector> // for vector
#include "utils.h" // for circle_t
class AnimatedSprite;
#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 "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
#define MAX_BOUNCE 10
constexpr int MAX_BOUNCE = 10;
// Tipos de globo
#define BALLOON_1 1
#define BALLOON_2 2
#define BALLOON_3 3
#define BALLOON_4 4
#define HEXAGON_1 5
#define HEXAGON_2 6
#define HEXAGON_3 7
#define HEXAGON_4 8
#define POWER_BALL 9
constexpr int BALLOON_1 = 1;
constexpr int BALLOON_2 = 2;
constexpr int BALLOON_3 = 3;
constexpr int BALLOON_4 = 4;
constexpr int HEXAGON_1 = 5;
constexpr int HEXAGON_2 = 6;
constexpr int HEXAGON_3 = 7;
constexpr int HEXAGON_4 = 8;
constexpr int POWER_BALL = 9;
// Puntos de globo
#define BALLOON_SCORE_1 50
#define BALLOON_SCORE_2 100
#define BALLOON_SCORE_3 200
#define BALLOON_SCORE_4 400
constexpr int BALLOON_SCORE_1 = 50;
constexpr int BALLOON_SCORE_2 = 100;
constexpr int BALLOON_SCORE_3 = 200;
constexpr int BALLOON_SCORE_4 = 400;
// Tamaños de globo
#define BALLOON_SIZE_1 1
#define BALLOON_SIZE_2 2
#define BALLOON_SIZE_3 3
#define BALLOON_SIZE_4 4
constexpr int BALLOON_SIZE_1 = 1;
constexpr int BALLOON_SIZE_2 = 2;
constexpr int BALLOON_SIZE_3 = 3;
constexpr int BALLOON_SIZE_4 = 4;
// Clases de globo
#define BALLOON_CLASS 0
#define HEXAGON_CLASS 1
constexpr int BALLOON_CLASS = 0;
constexpr int HEXAGON_CLASS = 1;
// Velocidad del globo
#define BALLOON_VELX_POSITIVE 0.7f
#define BALLOON_VELX_NEGATIVE -0.7f
constexpr float BALLOON_VELX_POSITIVE = 0.7f;
constexpr float BALLOON_VELX_NEGATIVE = -0.7f;
// Indice para las animaciones de los globos
#define BALLOON_MOVING_ANIMATION 0
#define BALLOON_POP_ANIMATION 1
#define BALLOON_BORN_ANIMATION 2
constexpr int BALLOON_MOVING_ANIMATION = 0;
constexpr int BALLOON_POP_ANIMATION = 1;
constexpr int BALLOON_BORN_ANIMATION = 2;
// Cantidad posible de globos
#define MAX_BALLOONS 100
constexpr int MAX_BALLOONS = 100;
// Velocidades a las que se mueven los globos
#define BALLOON_SPEED_1 0.60f
#define BALLOON_SPEED_2 0.70f
#define BALLOON_SPEED_3 0.80f
#define BALLOON_SPEED_4 0.90f
#define BALLOON_SPEED_5 1.00f
constexpr float BALLOON_SPEED_1 = 0.60f;
constexpr float BALLOON_SPEED_2 = 0.70f;
constexpr float BALLOON_SPEED_3 = 0.80f;
constexpr float BALLOON_SPEED_4 = 0.90f;
constexpr float BALLOON_SPEED_5 = 1.00f;
// Tamaño de los globos
#define BALLOON_WIDTH_1 10
#define BALLOON_WIDTH_2 16
#define BALLOON_WIDTH_3 26
#define BALLOON_WIDTH_4 46
constexpr int BALLOON_WIDTH_1 = 10;
constexpr int BALLOON_WIDTH_2 = 16;
constexpr int BALLOON_WIDTH_3 = 26;
constexpr int BALLOON_WIDTH_4 = 46;
// PowerBall
#define POWERBALL_SCREENPOWER_MINIMUM 10
#define POWERBALL_COUNTER 8
constexpr int POWERBALL_SCREENPOWER_MINIMUM = 10;
constexpr int POWERBALL_COUNTER = 8;
// Clase Balloon
class Balloon
{
private:
// Estructura para las variables para el efecto de los rebotes
struct bouncing
struct Bouncing
{
bool enabled; // Si el efecto está activo
Uint8 counter; // Countador para el efecto
@@ -85,37 +86,37 @@ private:
};
// Objetos y punteros
AnimatedSprite *sprite; // Sprite del objeto globo
std::unique_ptr<AnimatedSprite> sprite_; // Sprite del objeto globo
// Variables
float posX; // Posición en el eje X
float posY; // Posición en el eje Y
Uint8 width; // Ancho
Uint8 height; // Alto
float velX; // Velocidad en el eje X. Cantidad de pixeles a desplazarse
float velY; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse
float gravity; // Aceleración en el eje Y. Modifica la velocidad
float defaultVelY; // Velocidad inicial que tienen al rebotar contra el suelo
float maxVelY; // Máxima velocidad que puede alcanzar el objeto en el eje Y
bool beingCreated; // Indica si el globo se está creando
bool blinking; // Indica si el globo está intermitente
bool enabled; // Indica si el globo esta activo
bool invulnerable; // Indica si el globo es invulnerable
bool stopped; // Indica si el globo está parado
bool visible; // Indica si el globo es visible
circle_t collider; // Circulo de colisión del objeto
Uint16 creationCounter; // Temporizador para controlar el estado "creandose"
Uint16 creationCounterIni; // Valor inicial para el temporizador para controlar el estado "creandose"
Uint16 score; // Puntos que da el globo al ser destruido
Uint16 stoppedCounter; // Contador para controlar el estado "parado"
Uint8 kind; // Tipo de globo
Uint8 menace; // Cantidad de amenaza que genera el globo
Uint32 counter; // Contador interno
float travelY; // Distancia que ha de recorrer el globo en el eje Y antes de que se le aplique la gravedad
float speed; // Velocidad a la que se mueven los globos
Uint8 size; // Tamaño del globo
Uint8 power; // Cantidad de poder que alberga el globo
bouncing bouncing; // Contiene las variables para el efecto de rebote
float pos_x_; // Posición en el eje X
float pos_y_; // Posición en el eje Y
Uint8 width_; // Ancho
Uint8 height_; // Alto
float vel_x_; // Velocidad en el eje X. Cantidad de pixeles a desplazarse
float vel_y_; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse
float gravity_; // Aceleración en el eje Y. Modifica la velocidad
float default_vel_y_; // Velocidad inicial que tienen al rebotar contra el suelo
float max_vel_y_; // Máxima velocidad que puede alcanzar el objeto en el eje Y
bool being_created_; // Indica si el globo se está creando
bool blinking_; // Indica si el globo está intermitente
bool enabled_; // Indica si el globo esta activo
bool invulnerable_; // Indica si el globo es invulnerable
bool stopped_; // Indica si el globo está parado
bool visible_; // Indica si el globo es visible
Circle collider_; // Circulo de colisión del objeto
Uint16 creation_counter_; // Temporizador para controlar el estado "creandose"
Uint16 creation_counter_ini_; // Valor inicial para el temporizador para controlar el estado "creandose"
Uint16 score_; // Puntos que da el globo al ser destruido
Uint16 stopped_counter_; // Contador para controlar el estado "parado"
Uint8 kind_; // Tipo de globo
Uint8 menace_; // Cantidad de amenaza que genera el globo
Uint32 counter_; // Contador interno
float travel_y_; // Distancia que ha de recorrer el globo en el eje Y antes de que se le aplique la gravedad
float speed_; // Velocidad a la que se mueven los globos
Uint8 size_; // Tamaño del globo
Uint8 power_; // Cantidad de poder que alberga el globo
Bouncing bouncing_; // Contiene las variables para el efecto de rebote
// Alinea el circulo de colisión con la posición del objeto globo
void updateColliders();
@@ -140,10 +141,10 @@ private:
public:
// Constructor
Balloon(float x, float y, Uint8 kind, float velx, float speed, Uint16 creationtimer, 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();
~Balloon() = default;
// Centra el globo en la posición X
void allignTo(int x);
@@ -164,86 +165,86 @@ public:
void update();
// Comprueba si el globo está habilitado
bool isEnabled();
bool isEnabled() const;
// Obtiene del valor de la variable
float getPosX();
float getPosX() const;
// Obtiene del valor de la variable
float getPosY();
float getPosY() const;
// Obtiene del valor de la variable
float getVelY();
float getVelY() const;
// Obtiene del valor de la variable
int getWidth();
int getWidth() const;
// Obtiene del valor de la variable
int getHeight();
int getHeight() const;
// Establece el valor de la variable
void setVelY(float velY);
void setVelY(float vel_y);
// Establece el valor de la variable
void setSpeed(float speed);
// Obtiene del valor de la variable
int getKind();
int getKind() const;
// Obtiene del valor de la variable
Uint8 getSize();
Uint8 getSize() const;
// Obtiene la clase a la que pertenece el globo
Uint8 getClass();
Uint8 getClass() const;
// Establece el valor de la variable
void setStop(bool value);
// Obtiene del valor de la variable
bool isStopped();
bool isStopped() const;
// Establece el valor de la variable
void setBlink(bool value);
// Obtiene del valor de la variable
bool isBlinking();
bool isBlinking() const;
// Establece el valor de la variable
void setVisible(bool value);
// Obtiene del valor de la variable
bool isVisible();
bool isVisible() const;
// Establece el valor de la variable
void setInvulnerable(bool value);
// Obtiene del valor de la variable
bool isInvulnerable();
bool isInvulnerable() const;
// Obtiene del valor de la variable
bool isBeingCreated();
bool isBeingCreated() const;
// Establece el valor de la variable
void setStoppedTimer(Uint16 time);
// Obtiene del valor de la variable
Uint16 getStoppedTimer();
Uint16 getStoppedTimer() const;
// Obtiene del valor de la variable
Uint16 getScore();
Uint16 getScore() const;
// Obtiene el circulo de colisión
circle_t &getCollider();
Circle &getCollider();
// Obtiene le valor de la variable
Uint8 getMenace();
Uint8 getMenace() const;
// Obtiene le valor de la variable
Uint8 getPower();
Uint8 getPower() const;
// Indica si el globo se puede explotar
bool canBePopped();
bool canBePopped() const;
// Indica si el globo se puede destruir
bool canBeDestroyed();
bool canBeDestroyed() const;
};

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,47 +11,54 @@ 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 *playArea, Texture *texture)
: posX(x), posY(y), width(BULLET_WIDTH), height(BULLET_HEIGHT), velX(0), velY(BULLET_VELY),
kind(kind), owner(owner), playArea(playArea),
sprite(std::unique_ptr<Sprite>(new Sprite(SDL_Rect{x, y, BULLET_WIDTH, BULLET_HEIGHT}, texture))) // Crear manualmente el std::unique_ptr
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)
{
velX = (kind == BulletType::LEFT) ? BULLET_VELX_LEFT : (kind == BulletType::RIGHT) ? BULLET_VELX_RIGHT
: 0;
vel_x_ = (kind_ == BulletType::LEFT) ? BULLET_VELX_LEFT : (kind_ == BulletType::RIGHT) ? BULLET_VELX_RIGHT
: 0;
auto spriteOffset = poweredUp ? 3 : 0;
auto kindIndex = static_cast<int>(kind);
sprite->setSpriteClip((kindIndex + spriteOffset) * width, 0, sprite->getWidth(), sprite->getHeight());
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;
collider_.r = width_ / 2;
shiftColliders();
}
// Implementación de render (llama al render del sprite)
// Implementación de render (llama al render del sprite_)
void Bullet::render()
{
sprite->render();
sprite_->render();
}
// Implementación del movimiento usando BulletMoveStatus
BulletMoveStatus Bullet::move()
{
posX += velX;
if (posX < param.game.playArea.rect.x - width || posX > playArea->w)
pos_x_ += vel_x_;
if (pos_x_ < param.game.play_area.rect.x - width_ || pos_x_ > play_area_->w)
{
disable();
return BulletMoveStatus::OUT;
}
posY += velY;
if (posY < param.game.playArea.rect.y - height)
pos_y_ += vel_y_;
if (pos_y_ < param.game.play_area.rect.y - height_)
{
disable();
return BulletMoveStatus::OUT;
}
sprite->setPosX(posX);
sprite->setPosY(posY);
sprite_->setX(pos_x_);
sprite_->setY(pos_y_);
shiftColliders();
return BulletMoveStatus::OK;
@@ -59,56 +66,56 @@ 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
{
return posX;
return pos_x_;
}
int Bullet::getPosY() const
{
return posY;
return pos_y_;
}
void Bullet::setPosX(int x)
{
posX = x;
pos_x_ = x;
}
void Bullet::setPosY(int y)
{
posY = y;
pos_y_ = y;
}
int Bullet::getVelY() const
{
return velY;
return vel_y_;
}
BulletType Bullet::getKind() const
{
return kind;
return kind_;
}
int Bullet::getOwner() const
{
return owner;
return owner_;
}
circle_t &Bullet::getCollider()
Circle &Bullet::getCollider()
{
return collider;
return collider_;
}
void Bullet::shiftColliders()
{
collider.x = posX + collider.r;
collider.y = posY + collider.r;
collider_.x = pos_x_ + collider_.r;
collider_.y = pos_y_ + collider_.r;
}

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_t
class Texture; // 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,36 +27,53 @@ enum class BulletMoveStatus : Uint8
class Bullet
{
private:
int posX; // Posición en el eje X
int posY; // Posición en el eje Y
Uint8 width; // Ancho del objeto
Uint8 height; // Alto del objeto
int velX; // Velocidad en el eje X
int velY; // Velocidad en el eje Y
BulletType kind; // Tipo de objeto
int owner; // Identificador del dueño del objeto
circle_t collider; // Círculo de colisión del objeto
SDL_Rect *playArea; // Rectángulo con la zona de juego
std::unique_ptr<Sprite> sprite; // Sprite con los gráficos y métodos de pintado
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:
Bullet(int x, int y, BulletType kind, bool poweredUp, int owner, SDL_Rect *playArea, Texture *texture);
// Constructor
Bullet(int x, int y, BulletType kind, bool powered_up, int owner, SDL_Rect *play_area, std::shared_ptr<Texture> texture);
// Destructor
~Bullet() = default;
void render(); // Pinta el objeto en pantalla
BulletMoveStatus move(); // Actualiza la posición y estado del objeto
// Pinta el objeto en pantalla
void render();
bool isEnabled() const; // Comprueba si el objeto está habilitado
void disable(); // Deshabilita el objeto
// Actualiza la posición y estado del objeto
BulletMoveStatus move();
// Comprueba si el objeto está habilitado
bool isEnabled() const;
// Deshabilita el objeto
void disable();
// Obtiene la posición
int getPosX() const;
int getPosY() const;
// Establece la posición
void setPosX(int x);
void setPosY(int y);
// Obtiene parámetros
int getVelY() const;
BulletType getKind() const;
int getOwner() const;
circle_t &getCollider();
Circle &getCollider();
};

View File

@@ -1,128 +1,123 @@
#include "define_buttons.h"
#include "lang.h" // for getText
#include "options.h" // for options
#include "param.h" // for param
#include "section.h" // for name, name_e, options, options_e
#include "text.h" // for Text
#include "utils.h" // for op_controller_t, options_t, param_t, paramGame_t
#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, Options, name, options
#include "text.h" // for Text
#include "utils.h" // for OptionsController, Options, Param, ParamGame
// Constructor
DefineButtons::DefineButtons(Text *text)
DefineButtons::DefineButtons(std::unique_ptr<Text> text_)
: text_(std::move(text_))
{
// Copia punteros a los objetos
input = Input::get();
this->text = text;
input_ = Input::get();
// Inicializa variables
enabled = false;
x = param.game.width / 2;
y = param.title.pressStartPosition;
indexController = 0;
indexButton = 0;
enabled_ = false;
x_ = param.game.width / 2;
y_ = param.title.press_start_position;
index_controller_ = 0;
index_button_ = 0;
buttons.clear();
db_button_t button;
buttons_.clear();
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);
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);
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);
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);
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);
buttons_.push_back(button);
for (int i = 0; i < input->getNumControllers(); ++i)
{
controllerNames.push_back(input->getControllerName(i));
}
}
// Destructor
DefineButtons::~DefineButtons()
{
}
// Actualiza las variables del objeto
void DefineButtons::update()
{
if (enabled)
for (int i = 0; i < input_->getNumControllers(); ++i)
{
controller_names_.push_back(input_->getControllerName(i));
}
}
// Dibuja el objeto en pantalla
void DefineButtons::render()
{
if (enabled)
if (enabled_)
{
text->writeCentered(x, y - 10, lang::getText(100) + std::to_string(options.controller[indexController].playerId));
text->writeCentered(x, y, controllerNames[indexController]);
text->writeCentered(x, y + 10, buttons[indexButton].label);
text_->writeCentered(x_, y_ - 10, lang::getText(100) + std::to_string(options.controller[index_controller_].player_id));
text_->writeCentered(x_, y_, controller_names_[index_controller_]);
text_->writeCentered(x_, y_ + 10, buttons_[index_button_].label);
}
}
// Comprueba el botón que se ha pulsado
void DefineButtons::doControllerButtonDown(SDL_ControllerButtonEvent *event)
{
int i = input->getJoyIndex(event->which);
int i = input_->getJoyIndex(event->which);
// Solo pillamos botones del mando que toca
if (i != indexController)
if (i != index_controller_)
{
return;
}
buttons[indexButton].button = (SDL_GameControllerButton)event->button;
buttons_[index_button_].button = (SDL_GameControllerButton)event->button;
incIndexButton();
}
// Asigna los botones definidos al input
// Asigna los botones definidos al input_
void DefineButtons::bindButtons()
{
for (int i = 0; i < (int)buttons.size(); ++i)
for (int i = 0; i < (int)buttons_.size(); ++i)
{
input->bindGameControllerButton(indexController, buttons[i].input, buttons[i].button);
input_->bindGameControllerButton(index_controller_, buttons_[i].input, buttons_[i].button);
}
}
// Comprueba las entradas
void DefineButtons::checkInput()
{
if (enabled)
if (enabled_)
{
SDL_Event event;
// Comprueba los eventos que hay en la cola
while (SDL_PollEvent(&event))
{
// Evento de salida de la aplicación
if (event.type == SDL_QUIT)
switch (event.type)
{
section::name = section::NAME_QUIT;
section::options = section::OPTIONS_QUIT_NORMAL;
case SDL_QUIT:
{
section::name = section::Name::QUIT;
section::options = section::Options::QUIT_WITH_KEYBOARD;
break;
}
if (event.type == SDL_CONTROLLERBUTTONDOWN)
case SDL_CONTROLLERBUTTONDOWN:
{
doControllerButtonDown(&event.cbutton);
break;
}
default:
break;
}
}
}
@@ -131,11 +126,11 @@ void DefineButtons::checkInput()
// Habilita el objeto
bool DefineButtons::enable(int index)
{
if (index < input->getNumControllers())
if (index < input_->getNumControllers())
{
enabled = true;
indexController = index;
indexButton = 0;
enabled_ = true;
index_controller_ = index;
index_button_ = 0;
return true;
}
@@ -145,29 +140,29 @@ bool DefineButtons::enable(int index)
// Comprueba si está habilitado
bool DefineButtons::isEnabled()
{
return enabled;
return enabled_;
}
// Incrementa el indice de los botones
void DefineButtons::incIndexButton()
{
indexButton++;
index_button_++;
// Comprueba si ha finalizado
if (indexButton == (int)buttons.size())
if (index_button_ == (int)buttons_.size())
{
// Asigna los botones definidos al input
// Asigna los botones definidos al input_
bindButtons();
// Guarda los cambios en las opciones
saveBindingsToOptions();
input->allActive(indexController);
// input_->allActive(index_controller_);
// Reinicia variables
indexButton = 0;
indexController = 0;
enabled = false;
index_button_ = 0;
index_controller_ = 0;
enabled_ = false;
}
}
@@ -175,17 +170,17 @@ void DefineButtons::incIndexButton()
void DefineButtons::saveBindingsToOptions()
{
// Modifica las opciones para colocar los valores asignados
options.controller[indexController].name = input->getControllerName(indexController);
for (int j = 0; j < (int)options.controller[indexController].inputs.size(); ++j)
options.controller[index_controller_].name = input_->getControllerName(index_controller_);
for (int j = 0; j < (int)options.controller[index_controller_].inputs.size(); ++j)
{
options.controller[indexController].buttons[j] = input->getControllerBinding(indexController, options.controller[indexController].inputs[j]);
options.controller[index_controller_].buttons[j] = input_->getControllerBinding(index_controller_, options.controller[index_controller_].inputs[j]);
}
}
// Intercambia los jugadores asignados a los dos primeros mandos
void DefineButtons::swapControllers()
{
const int temp = options.controller[0].playerId;
options.controller[0].playerId = options.controller[1].playerId;
options.controller[1].playerId = temp;
const int temp = options.controller[0].player_id;
options.controller[0].player_id = options.controller[1].player_id;
options.controller[1].player_id = temp;
}

View File

@@ -2,15 +2,17 @@
#include <SDL2/SDL_events.h> // for SDL_ControllerButtonEvent
#include <SDL2/SDL_gamecontroller.h> // for SDL_GameControllerButton
#include <string> // for string, basic_string
#include <memory> // for shared_ptr, unique_ptr
#include <string> // for string
#include <vector> // for vector
#include "input.h" // for inputs_e
class Input;
class Text;
enum class InputType : int;
struct db_button_t
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
};
@@ -19,17 +21,17 @@ class DefineButtons
{
private:
// Objetos
Input *input; // Objeto pata gestionar la entrada
Text *text; // Objeto para escribir texto
Input *input_; // Objeto pata gestionar la entrada
std::shared_ptr<Text> text_; // Objeto para escribir texto
// Variables
bool enabled; // Indica si el objeto está habilitado
int x; // Posición donde dibujar el texto
int y; // Posición donde dibujar el texto
std::vector<db_button_t> buttons; // Vector con las nuevas definiciones de botones/acciones
int indexController; // Indice del controlador a reasignar
int indexButton; // Indice para saber qué bot´çon se está definiendo
std::vector<std::string> controllerNames; // Nombres de los mandos
bool enabled_; // Indica si el objeto está habilitado
int x_; // Posición donde dibujar el texto
int y_; // Posición donde dibujar el texto
std::vector<DefineButtonsButton> buttons_; // Vector con las nuevas definiciones de botones/acciones
int index_controller_; // Indice del controlador a reasignar
int index_button_; // Indice para saber qué bot´çon se está definiendo
std::vector<std::string> controller_names_; // Nombres de los mandos
// Incrementa el indice de los botones
void incIndexButton();
@@ -45,13 +47,10 @@ private:
public:
// Constructor
DefineButtons(Text *text);
explicit DefineButtons(std::unique_ptr<Text> text);
// Destructor
~DefineButtons();
// Actualiza las variables del objeto
void update();
~DefineButtons() = default;
// Dibuja el objeto en pantalla
void render();

File diff suppressed because it is too large Load Diff

View File

@@ -1,47 +1,31 @@
#pragma once
#include <SDL2/SDL_render.h> // for SDL_Renderer
#include <SDL2/SDL_video.h> // for SDL_Window
#include <string> // for string, basic_string
#include <vector> // for vector
#include "lang.h" // for lang_e
#include "utils.h" // for music_file_t, sound_file_t
class Asset;
class Game;
class HiScoreTable;
class Input;
class Instructions;
class Intro;
class Logo;
class Screen;
class Title;
#include <SDL2/SDL_render.h> // for SDL_Renderer
#include <SDL2/SDL_video.h> // for SDL_Window
#include <string> // for string
#include <vector> // for vector
namespace lang
{
enum class Code : int;
}
struct ResourceMusic;
struct ResourceSound;
// Textos
#define WINDOW_CAPTION "Coffee Crisis Arcade Edition"
constexpr char WINDOW_CAPTION[] = "Coffee Crisis Arcade Edition";
class Director
{
private:
// Objetos y punteros
SDL_Window *window; // La ventana donde dibujamos
SDL_Renderer *renderer; // El renderizador de la ventana
Screen *screen; // Objeto encargado de dibujar en pantalla
Logo *logo; // Objeto para la sección del logo
Intro *intro; // Objeto para la sección de la intro
Title *title; // Objeto para la sección del titulo y el menu de opciones
Game *game; // Objeto para la sección del juego
Instructions *instructions; // Objeto para la sección de las instrucciones
HiScoreTable *hiScoreTable; // Objeto para mostrar las mejores puntuaciones online
Game *demoGame; // Objeto para lanzar la demo del juego
Input *input; // Objeto Input para gestionar las entradas
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
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 executablePath; // Path del ejecutable
std::string systemFolder; // Carpeta del sistema donde guardar datos
std::string paramFileArgument; // Argumento para gestionar el fichero con los parametros del programa
std::vector<sound_file_t> sounds; // Vector con los sonidos
std::vector<music_file_t> musics; // Vector con las musicas
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
// Inicializa jail_audio
void initJailAudio();
@@ -49,32 +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 filepath);
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();
// Libera la memoria usada por los sonidos del juego
void deleteSounds();
// Libera la memoria usada por las músicas del juego
void deleteMusics();
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();
@@ -97,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,725 +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_t, param_t, zone_t, BLOCK
// Constructor
EnemyFormations::EnemyFormations()
{
initEnemyFormations();
initEnemyPools();
initGameStages();
}
// Destructor
EnemyFormations::~EnemyFormations()
{
}
// Inicializa las formaciones enemigas
void EnemyFormations::initEnemyFormations()
{
const int y4 = - BLOCK;
const int x4_0 = param.game.playArea.rect.x;
const int x4_100 = param.game.playArea.rect.w - BALLOON_WIDTH_4;
const int y3 = - BLOCK;
const int x3_0 = param.game.playArea.rect.x;
const int x3_100 = param.game.playArea.rect.w - BALLOON_WIDTH_3;
const int y2 = - BLOCK;
const int x2_0 = param.game.playArea.rect.x;
const int x2_100 = param.game.playArea.rect.w - BALLOON_WIDTH_2;
const int y1 = - BLOCK;
const int x1_0 = param.game.playArea.rect.x;
const int x1_50 = param.game.playArea.centerX - (BALLOON_WIDTH_1 / 2);
const int x1_100 = param.game.playArea.rect.w - BALLOON_WIDTH_1;
// Inicializa a cero las variables
for (int i = 0; i < NUMBER_OF_ENEMY_FORMATIONS; i++)
{
enemyFormation[i].numberOfEnemies = 0;
for (int j = 0; j < MAX_NUMBER_OF_ENEMIES_IN_A_FORMATION; j++)
{
enemyFormation[i].init[j].x = 0;
enemyFormation[i].init[j].y = 0;
enemyFormation[i].init[j].velX = 0;
enemyFormation[i].init[j].kind = 0;
enemyFormation[i].init[j].creationCounter = 0;
}
}
const int creationTime = 300;
int incX = 0;
int incTime = 0;
int j = 0;
// #00 - Dos enemigos BALLOON4 uno a cada extremo
j = 0;
enemyFormation[j].numberOfEnemies = 2;
incX = x4_100;
incTime = 0;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x4_0 + (i * incX);
enemyFormation[j].init[i].y = y4;
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE * (((i % 2) * 2) - 1);
enemyFormation[j].init[i].kind = BALLOON_4;
enemyFormation[j].init[i].creationCounter = creationTime + (incTime * i);
}
// #01 - Dos enemigos BALLOON4 uno a cada cuarto. Ambos van hacia el centro
j = 1;
enemyFormation[j].numberOfEnemies = 2;
incX = param.game.playArea.centerX;
incTime = 0;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = param.game.playArea.firstQuarterX - (BALLOON_WIDTH_4 / 2) + (i * incX);
enemyFormation[j].init[i].y = y4;
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE * (((i % 2) * 2) - 1);
enemyFormation[j].init[i].kind = BALLOON_4;
enemyFormation[j].init[i].creationCounter = creationTime + (incTime * i);
}
// #02 - Cuatro enemigos BALLOON2 uno detras del otro. A la izquierda y hacia el centro
j = 2;
enemyFormation[j].numberOfEnemies = 4;
incX = BALLOON_WIDTH_2 + 1;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x2_0 + (i * incX);
enemyFormation[j].init[i].y = y2;
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
enemyFormation[j].init[i].kind = BALLOON_2;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #03 - Cuatro enemigos BALLOON2 uno detras del otro. A la derecha y hacia el centro
j = 3;
enemyFormation[j].numberOfEnemies = 4;
incX = BALLOON_WIDTH_2 + 1;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x2_100 - (i * incX);
enemyFormation[j].init[i].y = y2;
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
enemyFormation[j].init[i].kind = BALLOON_2;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #04 - Tres enemigos BALLOON3. 0, 25, 50. Hacia la derecha
j = 4;
enemyFormation[j].numberOfEnemies = 3;
incX = BALLOON_WIDTH_3 * 2;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x3_0 + (i * incX);
enemyFormation[j].init[i].y = y3;
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
enemyFormation[j].init[i].kind = BALLOON_3;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #05 - Tres enemigos BALLOON3. 50, 75, 100. Hacia la izquierda
j = 5;
enemyFormation[j].numberOfEnemies = 3;
incX = BALLOON_WIDTH_3 * 2;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x3_100 - (i * incX);
enemyFormation[j].init[i].y = y3;
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
enemyFormation[j].init[i].kind = BALLOON_3;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #06 - Tres enemigos BALLOON3. 0, 0, 0. Hacia la derecha
j = 6;
enemyFormation[j].numberOfEnemies = 3;
incX = BALLOON_WIDTH_3 + 1;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x3_0 + (i * incX);
enemyFormation[j].init[i].y = y3;
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
enemyFormation[j].init[i].kind = BALLOON_3;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #07 - Tres enemigos BALLOON3. 100, 100, 100. Hacia la izquierda
j = 7;
enemyFormation[j].numberOfEnemies = 3;
incX = BALLOON_WIDTH_3 + 1;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x3_100 - (i * incX);
enemyFormation[j].init[i].y = y3;
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
enemyFormation[j].init[i].kind = BALLOON_3;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #08 - Seis enemigos BALLOON1. 0, 0, 0, 0, 0, 0. Hacia la derecha
j = 8;
enemyFormation[j].numberOfEnemies = 6;
incX = BALLOON_WIDTH_1 + 1;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x1_0 + (i * incX);
enemyFormation[j].init[i].y = y1;
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
enemyFormation[j].init[i].kind = BALLOON_1;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #09 - Seis enemigos BALLOON1. 100, 100, 100, 100, 100, 100. Hacia la izquierda
j = 9;
enemyFormation[j].numberOfEnemies = 6;
incX = BALLOON_WIDTH_1 + 1;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x1_100 - (i * incX);
enemyFormation[j].init[i].y = y1;
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
enemyFormation[j].init[i].kind = BALLOON_1;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #10 - Tres enemigos BALLOON4 seguidos desde la izquierda
j = 10;
enemyFormation[j].numberOfEnemies = 3;
incX = BALLOON_WIDTH_4 + 1;
incTime = 15;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x4_0 + (i * incX);
enemyFormation[j].init[i].y = y4;
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
enemyFormation[j].init[i].kind = BALLOON_4;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #11 - Tres enemigos BALLOON4 seguidos desde la derecha
j = 11;
enemyFormation[j].numberOfEnemies = 3;
incX = BALLOON_WIDTH_4 + 1;
incTime = 15;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x4_100 - (i * incX);
enemyFormation[j].init[i].y = y4;
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
enemyFormation[j].init[i].kind = BALLOON_4;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #12 - Seis enemigos BALLOON2 uno detras del otro. A la izquierda y hacia el centro
j = 12;
enemyFormation[j].numberOfEnemies = 6;
incX = BALLOON_WIDTH_2 + 1;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x2_0 + (i * incX);
enemyFormation[j].init[i].y = y2;
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
enemyFormation[j].init[i].kind = BALLOON_2;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #13 - Seis enemigos BALLOON2 uno detras del otro. A la derecha y hacia el centro
j = 13;
enemyFormation[j].numberOfEnemies = 6;
incX = BALLOON_WIDTH_2 + 1;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x2_100 - (i * incX);
enemyFormation[j].init[i].y = y2;
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
enemyFormation[j].init[i].kind = BALLOON_2;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #14 - Cinco enemigos BALLOON3. Hacia la derecha. Separados
j = 14;
enemyFormation[j].numberOfEnemies = 5;
incX = BALLOON_WIDTH_3 * 2;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x3_0 + (i * incX);
enemyFormation[j].init[i].y = y3;
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
enemyFormation[j].init[i].kind = BALLOON_3;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #15 - Cinco enemigos BALLOON3. Hacia la izquierda. Separados
j = 15;
enemyFormation[j].numberOfEnemies = 5;
incX = BALLOON_WIDTH_3 * 2;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x3_100 - (i * incX);
enemyFormation[j].init[i].y = y3;
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
enemyFormation[j].init[i].kind = BALLOON_3;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #16 - Cinco enemigos BALLOON3. Hacia la derecha. Juntos
j = 16;
enemyFormation[j].numberOfEnemies = 5;
incX = BALLOON_WIDTH_3 + 1;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x3_0 + (i * incX);
enemyFormation[j].init[i].y = y3;
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
enemyFormation[j].init[i].kind = BALLOON_3;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #17 - Cinco enemigos BALLOON3. Hacia la izquierda. Juntos
j = 17;
enemyFormation[j].numberOfEnemies = 5;
incX = BALLOON_WIDTH_3 + 1;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x3_100 - (i * incX);
enemyFormation[j].init[i].y = y3;
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
enemyFormation[j].init[i].kind = BALLOON_3;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #18 - Doce enemigos BALLOON1. Hacia la derecha. Juntos
j = 18;
enemyFormation[j].numberOfEnemies = 12;
incX = BALLOON_WIDTH_1 + 1;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x1_0 + (i * incX);
enemyFormation[j].init[i].y = y1;
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
enemyFormation[j].init[i].kind = BALLOON_1;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #19 - Doce enemigos BALLOON1. Hacia la izquierda. Juntos
j = 19;
enemyFormation[j].numberOfEnemies = 12;
incX = BALLOON_WIDTH_1 + 1;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
enemyFormation[j].init[i].x = x1_100 - (i * incX);
enemyFormation[j].init[i].y = y1;
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
enemyFormation[j].init[i].kind = BALLOON_1;
enemyFormation[j].init[i].creationCounter = creationTime - (incTime * i);
}
// #20 - Dos enemigos BALLOON4 seguidos desde la izquierda/derecha. Simetricos
j = 20;
enemyFormation[j].numberOfEnemies = 4;
incX = BALLOON_WIDTH_4 + 1;
incTime = 0;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
const int half = enemyFormation[j].numberOfEnemies / 2;
if (i < half)
{
enemyFormation[j].init[i].x = x4_0 + (i * incX);
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
}
else
{
enemyFormation[j].init[i].x = x4_100 - ((i - half) * incX);
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
}
enemyFormation[j].init[i].y = y4;
enemyFormation[j].init[i].kind = BALLOON_4;
enemyFormation[j].init[i].creationCounter = creationTime + (incTime * i);
}
// #21 - Diez enemigos BALLOON2 uno detras del otro. Izquierda/derecha. Simetricos
j = 21;
enemyFormation[j].numberOfEnemies = 10;
incX = BALLOON_WIDTH_2 + 1;
incTime = 3;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
const int half = enemyFormation[j].numberOfEnemies / 2;
if (i < half)
{
enemyFormation[j].init[i].x = x2_0 + (i * incX);
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
}
else
{
enemyFormation[j].init[i].x = x2_100 - ((i - half) * incX);
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
}
enemyFormation[j].init[i].y = y2;
enemyFormation[j].init[i].kind = BALLOON_2;
}
// #22 - Diez enemigos BALLOON3. Hacia la derecha/izquierda. Separados. Simetricos
j = 22;
enemyFormation[j].numberOfEnemies = 10;
incX = BALLOON_WIDTH_3 * 2;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
const int half = enemyFormation[j].numberOfEnemies / 2;
if (i < half)
{
enemyFormation[j].init[i].x = x3_0 + (i * incX);
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
}
else
{
enemyFormation[j].init[i].x = x3_100 - ((i - half) * incX);
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
}
enemyFormation[j].init[i].y = y3;
enemyFormation[j].init[i].kind = BALLOON_3;
}
// #23 - Diez enemigos BALLOON3. Hacia la derecha. Juntos. Simetricos
j = 23;
enemyFormation[j].numberOfEnemies = 10;
incX = BALLOON_WIDTH_3 + 1;
incTime = 10;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
const int half = enemyFormation[j].numberOfEnemies / 2;
if (i < half)
{
enemyFormation[j].init[i].x = x3_0 + (i * incX);
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
}
else
{
enemyFormation[j].init[i].x = x3_100 - ((i - half) * incX);
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
}
enemyFormation[j].init[i].y = y3;
enemyFormation[j].init[i].kind = BALLOON_3;
}
// #24 - Treinta enemigos BALLOON1. Del centro hacia los extremos. Juntos. Simetricos
j = 24;
enemyFormation[j].numberOfEnemies = 30;
incX = 0;
incTime = 5;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
const int half = enemyFormation[j].numberOfEnemies / 2;
if (i < half)
{
enemyFormation[j].init[i].x = x1_50;
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
enemyFormation[j].init[i].creationCounter = (creationTime) + (incTime * i);
}
else
{
enemyFormation[j].init[i].x = x1_50;
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
enemyFormation[j].init[i].creationCounter = (creationTime) + (incTime * (i - half));
}
enemyFormation[j].init[i].y = y1;
enemyFormation[j].init[i].kind = BALLOON_1;
}
// #25 - Treinta enemigos BALLOON1. Del centro hacia adentro. Juntos. Simetricos
j = 25;
enemyFormation[j].numberOfEnemies = 30;
incX = BALLOON_WIDTH_1 + 1;
incTime = 5;
for (int i = 0; i < enemyFormation[j].numberOfEnemies; i++)
{
const int half = enemyFormation[j].numberOfEnemies / 2;
if (i < half)
{
enemyFormation[j].init[i].x = x1_50 + 20;
enemyFormation[j].init[i].velX = BALLOON_VELX_NEGATIVE;
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * i);
}
else
{
enemyFormation[j].init[i].x = x1_50 - 20;
enemyFormation[j].init[i].velX = BALLOON_VELX_POSITIVE;
enemyFormation[j].init[i].creationCounter = (creationTime) - (incTime * (i - half));
}
enemyFormation[j].init[i].y = y1;
enemyFormation[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++)
{
enemyFormation[k + 50].numberOfEnemies = enemyFormation[k].numberOfEnemies;
for (int i = 0; i < enemyFormation[k + 50].numberOfEnemies; i++)
{
enemyFormation[k + 50].init[i].x = enemyFormation[k].init[i].x;
enemyFormation[k + 50].init[i].y = enemyFormation[k].init[i].y;
enemyFormation[k + 50].init[i].velX = enemyFormation[k].init[i].velX;
enemyFormation[k + 50].init[i].creationCounter = enemyFormation[k].init[i].creationCounter;
enemyFormation[k + 50].init[i].kind = enemyFormation[k].init[i].kind + 4;
}
}
// TEST
enemyFormation[99].numberOfEnemies = 4;
enemyFormation[99].init[0].x = 10;
enemyFormation[99].init[0].y = y1;
enemyFormation[99].init[0].velX = 0;
enemyFormation[99].init[0].kind = BALLOON_1;
enemyFormation[99].init[0].creationCounter = 200;
enemyFormation[99].init[1].x = 50;
enemyFormation[99].init[1].y = y1;
enemyFormation[99].init[1].velX = 0;
enemyFormation[99].init[1].kind = BALLOON_2;
enemyFormation[99].init[1].creationCounter = 200;
enemyFormation[99].init[2].x = 90;
enemyFormation[99].init[2].y = y1;
enemyFormation[99].init[2].velX = 0;
enemyFormation[99].init[2].kind = BALLOON_3;
enemyFormation[99].init[2].creationCounter = 200;
enemyFormation[99].init[3].x = 140;
enemyFormation[99].init[3].y = y1;
enemyFormation[99].init[3].velX = 0;
enemyFormation[99].init[3].kind = BALLOON_4;
enemyFormation[99].init[3].creationCounter = 200;
}
// Inicializa los conjuntos de formaciones
void EnemyFormations::initEnemyPools()
{
// EnemyPool #0
enemyPool[0].set[0] = &enemyFormation[0];
enemyPool[0].set[1] = &enemyFormation[1];
enemyPool[0].set[2] = &enemyFormation[2];
enemyPool[0].set[3] = &enemyFormation[3];
enemyPool[0].set[4] = &enemyFormation[4];
enemyPool[0].set[5] = &enemyFormation[5];
enemyPool[0].set[6] = &enemyFormation[6];
enemyPool[0].set[7] = &enemyFormation[7];
enemyPool[0].set[8] = &enemyFormation[8];
enemyPool[0].set[9] = &enemyFormation[9];
// EnemyPool #1
enemyPool[1].set[0] = &enemyFormation[10];
enemyPool[1].set[1] = &enemyFormation[11];
enemyPool[1].set[2] = &enemyFormation[12];
enemyPool[1].set[3] = &enemyFormation[13];
enemyPool[1].set[4] = &enemyFormation[14];
enemyPool[1].set[5] = &enemyFormation[15];
enemyPool[1].set[6] = &enemyFormation[16];
enemyPool[1].set[7] = &enemyFormation[17];
enemyPool[1].set[8] = &enemyFormation[18];
enemyPool[1].set[9] = &enemyFormation[19];
// EnemyPool #2
enemyPool[2].set[0] = &enemyFormation[0];
enemyPool[2].set[1] = &enemyFormation[1];
enemyPool[2].set[2] = &enemyFormation[2];
enemyPool[2].set[3] = &enemyFormation[3];
enemyPool[2].set[4] = &enemyFormation[4];
enemyPool[2].set[5] = &enemyFormation[55];
enemyPool[2].set[6] = &enemyFormation[56];
enemyPool[2].set[7] = &enemyFormation[57];
enemyPool[2].set[8] = &enemyFormation[58];
enemyPool[2].set[9] = &enemyFormation[59];
// EnemyPool #3
enemyPool[3].set[0] = &enemyFormation[50];
enemyPool[3].set[1] = &enemyFormation[51];
enemyPool[3].set[2] = &enemyFormation[52];
enemyPool[3].set[3] = &enemyFormation[53];
enemyPool[3].set[4] = &enemyFormation[54];
enemyPool[3].set[5] = &enemyFormation[5];
enemyPool[3].set[6] = &enemyFormation[6];
enemyPool[3].set[7] = &enemyFormation[7];
enemyPool[3].set[8] = &enemyFormation[8];
enemyPool[3].set[9] = &enemyFormation[9];
// EnemyPool #4
enemyPool[4].set[0] = &enemyFormation[60];
enemyPool[4].set[1] = &enemyFormation[61];
enemyPool[4].set[2] = &enemyFormation[62];
enemyPool[4].set[3] = &enemyFormation[63];
enemyPool[4].set[4] = &enemyFormation[64];
enemyPool[4].set[5] = &enemyFormation[65];
enemyPool[4].set[6] = &enemyFormation[66];
enemyPool[4].set[7] = &enemyFormation[67];
enemyPool[4].set[8] = &enemyFormation[68];
enemyPool[4].set[9] = &enemyFormation[69];
// EnemyPool #5
enemyPool[5].set[0] = &enemyFormation[10];
enemyPool[5].set[1] = &enemyFormation[61];
enemyPool[5].set[2] = &enemyFormation[12];
enemyPool[5].set[3] = &enemyFormation[63];
enemyPool[5].set[4] = &enemyFormation[14];
enemyPool[5].set[5] = &enemyFormation[65];
enemyPool[5].set[6] = &enemyFormation[16];
enemyPool[5].set[7] = &enemyFormation[67];
enemyPool[5].set[8] = &enemyFormation[18];
enemyPool[5].set[9] = &enemyFormation[69];
// EnemyPool #6
enemyPool[6].set[0] = &enemyFormation[60];
enemyPool[6].set[1] = &enemyFormation[11];
enemyPool[6].set[2] = &enemyFormation[62];
enemyPool[6].set[3] = &enemyFormation[13];
enemyPool[6].set[4] = &enemyFormation[64];
enemyPool[6].set[5] = &enemyFormation[15];
enemyPool[6].set[6] = &enemyFormation[66];
enemyPool[6].set[7] = &enemyFormation[17];
enemyPool[6].set[8] = &enemyFormation[68];
enemyPool[6].set[9] = &enemyFormation[19];
// EnemyPool #7
enemyPool[7].set[0] = &enemyFormation[20];
enemyPool[7].set[1] = &enemyFormation[21];
enemyPool[7].set[2] = &enemyFormation[22];
enemyPool[7].set[3] = &enemyFormation[23];
enemyPool[7].set[4] = &enemyFormation[24];
enemyPool[7].set[5] = &enemyFormation[65];
enemyPool[7].set[6] = &enemyFormation[66];
enemyPool[7].set[7] = &enemyFormation[67];
enemyPool[7].set[8] = &enemyFormation[68];
enemyPool[7].set[9] = &enemyFormation[69];
// EnemyPool #8
enemyPool[8].set[0] = &enemyFormation[70];
enemyPool[8].set[1] = &enemyFormation[71];
enemyPool[8].set[2] = &enemyFormation[72];
enemyPool[8].set[3] = &enemyFormation[73];
enemyPool[8].set[4] = &enemyFormation[74];
enemyPool[8].set[5] = &enemyFormation[15];
enemyPool[8].set[6] = &enemyFormation[16];
enemyPool[8].set[7] = &enemyFormation[17];
enemyPool[8].set[8] = &enemyFormation[18];
enemyPool[8].set[9] = &enemyFormation[19];
// EnemyPool #9
enemyPool[9].set[0] = &enemyFormation[20];
enemyPool[9].set[1] = &enemyFormation[21];
enemyPool[9].set[2] = &enemyFormation[22];
enemyPool[9].set[3] = &enemyFormation[23];
enemyPool[9].set[4] = &enemyFormation[24];
enemyPool[9].set[5] = &enemyFormation[70];
enemyPool[9].set[6] = &enemyFormation[71];
enemyPool[9].set[7] = &enemyFormation[72];
enemyPool[9].set[8] = &enemyFormation[73];
enemyPool[9].set[9] = &enemyFormation[74];
}
// Inicializa las fases del juego
void EnemyFormations::initGameStages()
{
// STAGE 1
stage[0].number = 1;
stage[0].powerToComplete = 200;
stage[0].minMenace = 7 + (4 * 1);
stage[0].maxMenace = 7 + (4 * 3);
stage[0].enemyPool = &enemyPool[0];
// STAGE 2
stage[1].number = 2;
stage[1].powerToComplete = 300;
stage[1].minMenace = 7 + (4 * 2);
stage[1].maxMenace = 7 + (4 * 4);
stage[1].enemyPool = &enemyPool[1];
// STAGE 3
stage[2].number = 3;
stage[2].powerToComplete = 600;
stage[2].minMenace = 7 + (4 * 3);
stage[2].maxMenace = 7 + (4 * 5);
stage[2].enemyPool = &enemyPool[2];
// STAGE 4
stage[3].number = 4;
stage[3].powerToComplete = 600;
stage[3].minMenace = 7 + (4 * 3);
stage[3].maxMenace = 7 + (4 * 5);
stage[3].enemyPool = &enemyPool[3];
// STAGE 5
stage[4].number = 5;
stage[4].powerToComplete = 600;
stage[4].minMenace = 7 + (4 * 4);
stage[4].maxMenace = 7 + (4 * 6);
stage[4].enemyPool = &enemyPool[4];
// STAGE 6
stage[5].number = 6;
stage[5].powerToComplete = 600;
stage[5].minMenace = 7 + (4 * 4);
stage[5].maxMenace = 7 + (4 * 6);
stage[5].enemyPool = &enemyPool[5];
// STAGE 7
stage[6].number = 7;
stage[6].powerToComplete = 650;
stage[6].minMenace = 7 + (4 * 5);
stage[6].maxMenace = 7 + (4 * 7);
stage[6].enemyPool = &enemyPool[6];
// STAGE 8
stage[7].number = 8;
stage[7].powerToComplete = 750;
stage[7].minMenace = 7 + (4 * 5);
stage[7].maxMenace = 7 + (4 * 7);
stage[7].enemyPool = &enemyPool[7];
// STAGE 9
stage[8].number = 9;
stage[8].powerToComplete = 850;
stage[8].minMenace = 7 + (4 * 6);
stage[8].maxMenace = 7 + (4 * 8);
stage[8].enemyPool = &enemyPool[8];
// STAGE 10
stage[9].number = 10;
stage[9].powerToComplete = 950;
stage[9].minMenace = 7 + (4 * 7);
stage[9].maxMenace = 7 + (4 * 10);
stage[9].enemyPool = &enemyPool[9];
}
// Devuelve una fase
stage_t EnemyFormations::getStage(int index)
{
return stage[index];
}

View File

@@ -1,63 +0,0 @@
#pragma once
#define NUMBER_OF_ENEMY_FORMATIONS 100
#define MAX_NUMBER_OF_ENEMIES_IN_A_FORMATION 50
// Estructuras
struct enemyInits_t
{
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 velX; // Velocidad inicial en el eje X
int kind; // Tipo de enemigo
int creationCounter; // Temporizador para la creación del enemigo
};
struct enemyFormation_t // Contiene la información de una formación enemiga
{
int numberOfEnemies; // Cantidad de enemigos que forman la formación
enemyInits_t init[MAX_NUMBER_OF_ENEMIES_IN_A_FORMATION]; // Vector con todas las inicializaciones de los enemigos de la formación
};
struct enemyPool_t
{
enemyFormation_t *set[10]; // Conjunto de formaciones enemigas
};
struct stage_t // Contiene todas las variables relacionadas con una fase
{
enemyPool_t *enemyPool; // El conjunto de formaciones enemigas de la fase
int powerToComplete; // Cantidad de poder que se necesita para completar la fase
int maxMenace; // Umbral máximo de amenaza de la fase
int minMenace; // 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_t stage[10]; // Variable con los datos de cada pantalla
enemyFormation_t enemyFormation[NUMBER_OF_ENEMY_FORMATIONS]; // Vector con todas las formaciones enemigas
enemyPool_t enemyPool[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();
// Devuelve una fase
stage_t getStage(int index);
};

View File

@@ -3,15 +3,20 @@
// Constructor
EnterName::EnterName()
{
init();
}
// Inicializa el objeto
void EnterName::init()
{
// Obtiene el puntero al nombre
name = "A";
name_ = "A";
// Inicia la lista de caracteres permitidos
// characterList = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
characterList = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-+-*/=?¿<>!\"#$%&/()";
pos = 0;
numCharacters = (int)characterList.size();
character_list_ = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-+-*/=?¿<>!\"#$%&/()";
position_ = 0;
num_characters_ = (int)character_list_.size();
// Pone la lista de indices para que refleje el nombre
updateCharacterIndex();
@@ -20,32 +25,28 @@ EnterName::EnterName()
updateName();
}
// Destructor
EnterName::~EnterName()
{
}
// 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()
{
++characterIndex[pos];
if (characterIndex[pos] >= numCharacters)
++character_index_[position_];
if (character_index_[position_] >= num_characters_)
{
characterIndex[pos] = 0;
character_index_[position_] = 0;
}
updateName();
}
@@ -53,46 +54,48 @@ void EnterName::incIndex()
// Decrementa el índice
void EnterName::decIndex()
{
--characterIndex[pos];
if (characterIndex[pos] < 0)
--character_index_[position_];
if (character_index_[position_] < 0)
{
characterIndex[pos] = numCharacters - 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();
name_.clear();
for (int i = 0; i < NAME_LENGHT; ++i)
{
name.push_back(characterList[characterIndex[i]]);
name_.push_back(character_list_[character_index_[i]]);
}
}
// 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)
{
characterIndex[i] = 0;
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)
for (int i = 0; i < (int)name_.size(); ++i)
{
characterIndex[i] = findIndex(name.at(i));
character_index_[i] = findIndex(name_.at(i));
position_has_been_used_[i] = true;
}
}
// Encuentra el indice de un caracter en "characterList"
// Encuentra el indice de un caracter en "character_list_"
int EnterName::findIndex(char character)
{
for (int i = 0; i < (int)characterList.size(); ++i)
for (int i = 0; i < (int)character_list_.size(); ++i)
{
if (character == characterList[i])
if (character == character_list_[i])
{
return i;
}
@@ -101,13 +104,27 @@ int EnterName::findIndex(char character)
}
// Obtiene el nombre
std::string EnterName::getName()
std::string EnterName::getName() const
{
return name;
return name_;
}
// Obtiene la posición que se está editando
int EnterName::getPos()
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

@@ -2,7 +2,7 @@
#include <string>
#define NAME_LENGHT 8
constexpr int NAME_LENGHT = 8;
/*
Un array, "characterList", contiene la lista de caracteres
@@ -16,13 +16,14 @@
class EnterName
{
private:
std::string characterList; // Lista de todos los caracteres permitidos
std::string name; // Nombre introducido
int pos; // Posición a editar del nombre
int numCharacters; // Cantidad de caracteres de la lista de caracteres
int characterIndex[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,18 +32,24 @@ 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();
// Destructor
~EnterName();
~EnterName() = default;
// Inicializa el objeto
void init();
// Incrementa la posición
void incPos();
void incPosition();
// Decrementa la posición
void decPos();
void decPosition();
// Incrementa el índice
void incIndex();
@@ -51,8 +58,8 @@ public:
void decIndex();
// Obtiene el nombre
std::string getName();
std::string getName() const;
// Obtiene la posición que se está editando
int getPos();
int getPosition() const;
};

View File

@@ -1,30 +1,25 @@
#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()
{
textures.clear();
explosions.clear();
textures_.clear();
explosions_.clear();
}
// Destructor
Explosions::~Explosions()
{
for (auto explosion : explosions)
{
if (explosion)
{
delete explosion;
}
}
explosions_.clear();
}
// Actualiza la lógica de la clase
void Explosions::update()
{
for (auto explosion : explosions)
for (auto &explosion : explosions_)
{
explosion->update();
}
@@ -36,42 +31,36 @@ void Explosions::update()
// Dibuja el objeto en pantalla
void Explosions::render()
{
for (auto explosion : explosions)
for (auto &explosion : explosions_)
{
explosion->render();
}
}
// Añade texturas al objetp
void Explosions::addTexture(int size, Texture *texture, std::vector<std::string> *animation)
// Añade texturas al objeto
void Explosions::addTexture(int size, std::shared_ptr<Texture> texture, std::vector<std::string> &animation)
{
explosion_texture_t 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);
AnimatedSprite *sprite = new AnimatedSprite(textures[index].texture, "", textures[index].animation);
sprite->setPos(x, y);
explosions.push_back(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
void Explosions::freeExplosions()
{
if (explosions.empty() == false)
if (explosions_.empty() == false)
{
for (int i = explosions.size() - 1; i >= 0; --i)
for (int i = explosions_.size() - 1; i >= 0; --i)
{
if (explosions[i]->animationIsCompleted())
if (explosions_[i]->animationIsCompleted())
{
delete explosions[i];
explosions.erase(explosions.begin() + i);
explosions_.erase(explosions_.begin() + i);
}
}
}
@@ -80,9 +69,9 @@ void Explosions::freeExplosions()
// Busca una textura a partir del tamaño
int Explosions::getIndexBySize(int size)
{
for (int i = 0; i < (int)textures.size();++i)
for (int i = 0; i < (int)textures_.size(); ++i)
{
if (size == textures[i].size)
if (size == textures_[i].size)
{
return i;
}

View File

@@ -1,15 +1,20 @@
#pragma once
#include <string> // for string
#include <vector> // for vector
#include <memory> // for shared_ptr, unique_ptr
#include <string> // for string
#include <vector> // for vector
class AnimatedSprite;
class Texture;
struct explosion_texture_t
struct ExplosionTexture
{
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
@@ -17,8 +22,8 @@ class Explosions
{
private:
// Variables
std::vector<explosion_texture_t> textures; // Vector con las texturas a utilizar
std::vector<AnimatedSprite *> explosions; // Lista con todas las explosiones
std::vector<ExplosionTexture> textures_; // Vector con las texturas a utilizar
std::vector<std::unique_ptr<AnimatedSprite>> explosions_; // Lista con todas las explosiones
// Vacia el vector de elementos finalizados
void freeExplosions();
@@ -39,8 +44,8 @@ public:
// Dibuja el objeto en pantalla
void render();
// Añade texturas al objetp
void addTexture(int size, Texture *texture, std::vector<std::string> *animation);
// Añade texturas al objeto
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

@@ -1,20 +1,19 @@
#include "fade.h"
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND, SDL_BLENDMODE_NONE
#include <SDL2/SDL_pixels.h> // for SDL_PIXELFORMAT_RGBA8888
#include <stdlib.h> // for rand
#include <algorithm> // for min, max
#include "param.h" // for param
#include "utils.h" // for param_t, paramGame_t, paramFade_t
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND, SDL_BLENDMODE_NONE
#include <SDL2/SDL_pixels.h> // for SDL_PIXELFORMAT_RGBA8888
#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)
Fade::Fade()
: renderer_(Screen::get()->getRenderer())
{
// Copia punteros y objetos
this->renderer = renderer;
// Crea la textura donde dibujar el fade
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);
// Inicializa las variables
init();
@@ -23,179 +22,177 @@ Fade::Fade(SDL_Renderer *renderer)
// Destructor
Fade::~Fade()
{
SDL_DestroyTexture(backbuffer);
backbuffer = nullptr;
SDL_DestroyTexture(backbuffer_);
backbuffer_ = nullptr;
}
// Inicializa las variables
void Fade::init()
{
type = FADE_CENTER;
mode = FADE_OUT;
enabled = false;
finished = false;
counter = 0;
r = 0;
g = 0;
b = 0;
postDuration = 20;
postCounter = 0;
numSquaresWidth = param.fade.numSquaresWidth;
numSquaresHeight = param.fade.numSquaresHeight;
fadeRandomSquaresDelay = param.fade.randomSquaresDelay;
fadeRandomSquaresMult = param.fade.randomSquaresMult;
type_ = FadeType::CENTER;
mode_ = FadeMode::OUT;
enabled_ = false;
finished_ = false;
counter_ = 0;
r_ = 0;
g_ = 0;
b_ = 0;
a_ = 0;
post_duration_ = 20;
post_counter_ = 0;
num_squares_width_ = param.fade.num_squares_width;
num_squares_height_ = param.fade.num_squares_height;
fade_random_squares_delay_ = param.fade.random_squares_delay;
fade_random_squares_mult_ = param.fade.random_squares_mult;
}
// Resetea algunas variables para volver a hacer el fade sin perder ciertos parametros
void Fade::reset()
{
enabled = false;
finished = false;
counter = 0;
enabled_ = false;
finished_ = false;
counter_ = 0;
}
// Pinta una transición en pantalla
void Fade::render()
{
if (enabled || finished)
if (enabled_ || finished_)
{
SDL_RenderCopy(renderer, backbuffer, nullptr, nullptr);
SDL_RenderCopy(renderer_, backbuffer_, nullptr, nullptr);
}
}
// Actualiza las variables internas
void Fade::update()
{
if (enabled)
if (enabled_)
{
switch (type)
switch (type_)
{
case FADE_FULLSCREEN:
case FadeType::FULLSCREEN:
{
// Modifica la transparencia de la
if (mode == FADE_OUT)
a = std::min(counter * 4, 255);
else
a = 255 - std::min(counter * 4, 255);
// Modifica la transparencia
a_ = mode_ == FadeMode::OUT ? std::min(counter_ * 4, 255) : 255 - std::min(counter_ * 4, 255);
SDL_SetTextureAlphaMod(backbuffer, a);
SDL_SetTextureAlphaMod(backbuffer_, a_);
// Comprueba si ha terminado
if (counter >= 255 / 4)
if (counter_ >= 255 / 4)
{
finished = true;
finished_ = true;
}
break;
}
case FADE_CENTER:
case FadeType::CENTER:
{
// Dibuja sobre el backbuffer
SDL_Texture *temp = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, backbuffer);
// Dibuja sobre el backbuffer_
auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_SetRenderDrawColor(renderer, r, g, b, a);
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
for (int i = 0; i < counter; i++)
for (int i = 0; i < counter_; i++)
{
rect1.h = rect2.h = i * 4;
rect2.y = param.game.height - (i * 4);
rect1_.h = rect2_.h = i * 4;
rect2_.y = param.game.height - (i * 4);
SDL_RenderFillRect(renderer, &rect1);
SDL_RenderFillRect(renderer, &rect2);
SDL_RenderFillRect(renderer_, &rect1_);
SDL_RenderFillRect(renderer_, &rect2_);
}
// Deja el renderizador como estaba
SDL_SetRenderTarget(renderer, temp);
SDL_SetRenderTarget(renderer_, temp);
// Comprueba si ha terminado
if ((counter * 4) > param.game.height)
if ((counter_ * 4) > param.game.height)
{
finished = true;
a = 255;
finished_ = true;
a_ = 255;
}
break;
}
case FADE_RANDOM_SQUARE:
case FadeType::RANDOM_SQUARE:
{
if (counter % fadeRandomSquaresDelay == 0)
if (counter_ % fade_random_squares_delay_ == 0)
{
// Dibuja sobre el backbuffer
SDL_Texture *temp = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, backbuffer);
// Dibuja sobre el backbuffer_
auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(renderer, r, g, b, a);
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
// Dibuja el cuadrado correspondiente
const int index = std::min(counter / fadeRandomSquaresDelay, (numSquaresWidth * numSquaresHeight) - 1);
for (int i = 0; i < fadeRandomSquaresMult; ++i)
const int index = std::min(counter_ / fade_random_squares_delay_, (num_squares_width_ * num_squares_height_) - 1);
for (int i = 0; i < fade_random_squares_mult_; ++i)
{
const int index2 = std::min(index * fadeRandomSquaresMult + i, (int)square.size() - 1);
SDL_RenderFillRect(renderer, &square[index2]);
const int index2 = std::min(index * fade_random_squares_mult_ + i, (int)square_.size() - 1);
SDL_RenderFillRect(renderer_, &square_[index2]);
}
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND);
// Deja el renderizador como estaba
SDL_SetRenderTarget(renderer, temp);
SDL_SetRenderTarget(renderer_, temp);
}
// Comprueba si ha terminado
if (counter * fadeRandomSquaresMult / fadeRandomSquaresDelay >= numSquaresWidth * numSquaresHeight)
if (counter_ * fade_random_squares_mult_ / fade_random_squares_delay_ >= num_squares_width_ * num_squares_height_)
{
finished = true;
finished_ = true;
}
break;
}
case FADE_VENETIAN:
case FadeType::VENETIAN:
{
// Counter debe ir de 0 a 150
if (square.back().h < param.fade.venetianSize)
if (square_.back().h < param.fade.venetian_size)
{
// Dibuja sobre el backbuffer
SDL_Texture *temp = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, backbuffer);
// Dibuja sobre el backbuffer_
auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_SetRenderDrawColor(renderer, r, g, b, a);
for (auto rect : square)
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
for (auto rect : square_)
{
SDL_RenderFillRect(renderer, &rect);
SDL_RenderFillRect(renderer_, &rect);
}
// Deja el renderizador como estaba
SDL_SetRenderTarget(renderer, temp);
SDL_SetRenderTarget(renderer_, temp);
const Uint8 h = counter / 3;
for (int i = 0; i < (int)square.size(); ++i)
const auto h = counter_ / 3;
for (int i = 0; i < (int)square_.size(); ++i)
{
// A partir del segundo rectangulo se pinta en función del anterior
i == 0 ? square[i].h = h : square[i].h = std::max(square[i - 1].h - 3, 0);
square_[i].h = i == 0 ? h : std::max(square_[i - 1].h - 3, 0);
}
}
else
{
finished = true;
finished_ = true;
}
break;
}
}
if (finished)
if (finished_)
{
// Actualiza el contador
postCounter == postDuration ? enabled = false : postCounter++;
post_counter_ == post_duration_ ? enabled_ = false : post_counter_++;
// Deja el backbuffer todo del mismo color
cleanBackbuffer(r, g, b, a);
// Deja el backbuffer_ todo del mismo color
cleanBackbuffer(r_, g_, b_, a_);
}
counter++;
counter_++;
}
}
@@ -203,84 +200,85 @@ void Fade::update()
void Fade::activate()
{
// Si ya está habilitado, no hay que volverlo a activar
if (enabled)
if (enabled_)
{
return;
}
enabled = true;
finished = false;
counter = 0;
postCounter = 0;
enabled_ = true;
finished_ = false;
counter_ = 0;
post_counter_ = 0;
switch (type)
switch (type_)
{
case FADE_FULLSCREEN:
case FadeType::FULLSCREEN:
{
// Pinta el backbuffer de color sólido
cleanBackbuffer(r, g, b, 255);
// Pinta el backbuffer_ de color sólido
cleanBackbuffer(r_, g_, b_, 255);
break;
}
case FADE_CENTER:
case FadeType::CENTER:
{
rect1 = {0, 0, param.game.width, 0};
rect2 = {0, 0, param.game.width, 0};
a = 64;
rect1_ = {0, 0, param.game.width, 0};
rect2_ = {0, 0, param.game.width, 0};
a_ = 64;
break;
}
case FADE_RANDOM_SQUARE:
case FadeType::RANDOM_SQUARE:
{
rect1 = {0, 0, param.game.width / numSquaresWidth, param.game.height / numSquaresHeight};
square.clear();
rect1_ = {0, 0, param.game.width / num_squares_width_, param.game.height / num_squares_height_};
square_.clear();
// Añade los cuadrados al vector
for (int i = 0; i < numSquaresWidth * numSquaresHeight; ++i)
for (int i = 0; i < num_squares_width_ * num_squares_height_; ++i)
{
rect1.x = (i % numSquaresWidth) * rect1.w;
rect1.y = (i / numSquaresWidth) * rect1.h;
square.push_back(rect1);
rect1_.x = (i % num_squares_width_) * rect1_.w;
rect1_.y = (i / num_squares_width_) * rect1_.h;
square_.push_back(rect1_);
}
// Desordena el vector de cuadrados
int num = numSquaresWidth * numSquaresHeight;
auto num = num_squares_width_ * num_squares_height_;
while (num > 1)
{
int num_arreu = rand() % num;
SDL_Rect temp = square[num_arreu];
square[num_arreu] = square[num - 1];
square[num - 1] = temp;
auto num_arreu = rand() % num;
SDL_Rect temp = square_[num_arreu];
square_[num_arreu] = square_[num - 1];
square_[num - 1] = temp;
num--;
}
// Limpia la textura
SDL_Texture *temp = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, backbuffer);
a = mode == FADE_OUT ? 0 : 255;
SDL_SetRenderDrawColor(renderer, r, g, b, a);
SDL_RenderClear(renderer);
SDL_SetRenderTarget(renderer, temp);
auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_);
a_ = mode_ == FadeMode::OUT ? 0 : 255;
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
SDL_RenderClear(renderer_);
SDL_SetRenderTarget(renderer_, temp);
// Deja el color listo para usar
a = mode == FADE_OUT ? 255 : 0;
a_ = mode_ == FadeMode::OUT ? 255 : 0;
break;
}
case FADE_VENETIAN:
case FadeType::VENETIAN:
{
rect1 = {0, 0, param.game.width, 0};
square.clear();
a = 255;
cleanBackbuffer(0, 0, 0, 0);
rect1_ = {0, 0, param.game.width, 0};
square_.clear();
a_ = 255;
// Añade los cuadrados al vector
const int max = param.game.height / param.fade.venetianSize;
const int max = param.game.height / param.fade.venetian_size;
for (int i = 0; i < max; ++i)
{
rect1.y = i * param.fade.venetianSize;
square.push_back(rect1);
rect1_.y = i * param.fade.venetian_size;
square_.push_back(rect1_);
}
break;
@@ -289,55 +287,55 @@ void Fade::activate()
}
// Comprueba si está activo
bool Fade::isEnabled()
bool Fade::isEnabled() const
{
return enabled;
return enabled_;
}
// Comprueba si ha terminado la transicion
bool Fade::hasEnded()
bool Fade::hasEnded() const
{
// Ha terminado cuando ha finalizado la transición y se ha deshabilitado
return !enabled && finished;
return !enabled_ && finished_;
}
// Establece el tipo de fade
void Fade::setType(Uint8 type)
void Fade::setType(FadeType type)
{
this->type = type;
type_ = type;
}
// Establece el modo de fade
void Fade::setMode(Uint8 mode)
void Fade::setMode(FadeMode mode)
{
this->mode = mode;
mode_ = mode;
}
// Establece el color del fade
void Fade::setColor(Uint8 r, Uint8 g, Uint8 b)
{
this->r = r;
this->g = g;
this->b = b;
r_ = r;
g_ = g;
b_ = b;
}
// Establece la duración posterior
void Fade::setPost(int value)
{
postDuration = value;
post_duration_ = value;
}
// Limpia el backbuffer
void Fade::cleanBackbuffer(int r, int g, int b, int a)
void Fade::cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
// Dibujamos sobre el backbuffer
SDL_Texture *temp = SDL_GetRenderTarget(renderer);
SDL_SetRenderTarget(renderer, backbuffer);
// Dibujamos sobre el backbuffer_
auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_);
// Pintamos la textura con el color del fade
SDL_SetRenderDrawColor(renderer, r, g, b, a);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer_, r, g, b, a);
SDL_RenderClear(renderer_);
// Vuelve a dejar el renderizador como estaba
SDL_SetRenderTarget(renderer, temp);
SDL_SetRenderTarget(renderer_, temp);
}

View File

@@ -1,54 +1,60 @@
#pragma once
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_render.h> // for SDL_Renderer, SDL_Texture
#include <SDL2/SDL_stdinc.h> // for Uint8, Uint16
#include <vector> // for vector
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_render.h> // for SDL_Renderer, SDL_Texture
#include <SDL2/SDL_stdinc.h> // for Uint8, Uint16
#include <vector> // for vector
// Tipos de fundido
#define FADE_FULLSCREEN 0
#define FADE_CENTER 1
#define FADE_RANDOM_SQUARE 2
#define FADE_VENETIAN 3
enum class FadeType : Uint8
{
FULLSCREEN = 0,
CENTER = 1,
RANDOM_SQUARE = 2,
VENETIAN = 3,
};
// Modos de fundido
#define FADE_IN 0
#define FADE_OUT 1
enum class FadeMode : Uint8
{
IN = 0,
OUT = 1,
};
// Clase Fade
class Fade
{
private:
// Objetos y punteros
SDL_Renderer *renderer; // El renderizador de la ventana
SDL_Texture *backbuffer; // Textura para usar como backbuffer con SDL_TEXTUREACCESS_TARGET
SDL_Renderer *renderer_; // El renderizador de la ventana
SDL_Texture *backbuffer_; // Textura para usar como backbuffer con SDL_TEXTUREACCESS_TARGET
// Variables
Uint8 type; // Tipo de fade a realizar
Uint8 mode; // Modo de fade a realizar
Uint16 counter; // Contador interno
bool enabled; // Indica si el fade está activo
bool finished; // Indica si ha terminado la transición
Uint8 r, g, b, a; // Colores para el fade
SDL_Rect rect1; // Rectangulo usado para crear los efectos de transición
SDL_Rect rect2; // Rectangulo usado para crear los efectos de transición
int numSquaresWidth; // Cantidad total de cuadraditos en horizontal para el FADE_RANDOM_SQUARE
int numSquaresHeight; // Cantidad total de cuadraditos en vertical para el FADE_RANDOM_SQUARE
std::vector<SDL_Rect> square; // Vector con los indices de los cuadrados para el FADE_RANDOM_SQUARE
int fadeRandomSquaresDelay; // Duración entre cada pintado de cuadrados
int fadeRandomSquaresMult; // Cantidad de cuadrados que se pintaran cada vez
int postDuration; // Duración posterior del fade tras finalizar
int postCounter; // Contador para la duración posterior
FadeType type_; // Tipo de fade a realizar
FadeMode mode_; // Modo de fade a realizar
Uint16 counter_; // Contador interno
bool enabled_; // Indica si el fade está activo
bool finished_; // Indica si ha terminado la transición
Uint8 r_, g_, b_, a_; // Colores para el fade
SDL_Rect rect1_; // Rectangulo usado para crear los efectos de transición
SDL_Rect rect2_; // Rectangulo usado para crear los efectos de transición
int num_squares_width_; // Cantidad total de cuadraditos en horizontal para el FadeType::RANDOM_SQUARE
int num_squares_height_; // Cantidad total de cuadraditos en vertical para el FadeType::RANDOM_SQUARE
std::vector<SDL_Rect> square_; // Vector con los indices de los cuadrados para el FadeType::RANDOM_SQUARE
int fade_random_squares_delay_; // Duración entre cada pintado de cuadrados
int fade_random_squares_mult_; // Cantidad de cuadrados que se pintaran cada vez
int post_duration_; // Duración posterior del fade tras finalizar
int post_counter_; // Contador para la duración posterior
// Inicializa las variables
void init();
// Limpia el backbuffer
void cleanBackbuffer(int r, int g, int b, int a);
void cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a);
public:
// Constructor
Fade(SDL_Renderer *renderer);
Fade();
// Destructor
~Fade();
@@ -66,16 +72,16 @@ public:
void activate();
// Comprueba si ha terminado la transicion
bool hasEnded();
bool hasEnded() const;
// Comprueba si está activo
bool isEnabled();
bool isEnabled() const;
// Establece el tipo de fade
void setType(Uint8 type);
void setType(FadeType type);
// Establece el modo de fade
void setMode(Uint8 mode);
void setMode(FadeMode mode);
// Establece el color del fade
void setColor(Uint8 r, Uint8 g, Uint8 b);

File diff suppressed because it is too large Load Diff

View File

@@ -1,55 +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 options_e
#include "utils.h" // for demoKeys_t, color_t, hiScoreEntry_t
class Asset; // lines 11-11
class Background; // lines 12-12
class Balloon; // lines 13-13
class Bullet; // lines 14-14
class EnemyFormations; // lines 15-15
class Explosions; // lines 16-16
class Fade; // lines 17-17
class Input; // lines 18-18
class Item; // lines 19-19
class Player; // lines 20-20
class Scoreboard; // lines 21-21
class Screen; // lines 22-22
class SmartSprite; // lines 23-23
class Text; // lines 24-24
class Texture; // lines 25-25
enum class BulletType;
struct JA_Music_t; // lines 26-26
struct JA_Sound_t; // lines 27-27
#include "balloon.h" // for Balloon
#include "player.h" // for Player
#include "utils.h" // for DemoKeys, Color, HiScoreEntry
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
@@ -81,127 +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_t keys; // Variable con las pulsaciones de teclas del modo demo
demoKeys_t 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
Background *background; // Objeto para dibujar el fondo del juego
Explosions *explosions; // Objeto para dibujar explosiones
EnemyFormations *enemyFormations; // Objeto para gestionar las oleadas enemigas
SDL_Texture *canvas; // Textura para dibujar la zona de juego
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::vector<Player *> players; // Vector con los jugadores
std::vector<Balloon *> balloons; // Vector con los globos
std::vector<Bullet *> bullets; // Vector con las balas
std::vector<Item *> items; // Vector con los items
std::vector<SmartSprite *> smartSprites; // Vector con los smartsprites
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
Texture *bulletTexture; // Textura para las balas
std::vector<Texture *> itemTextures; // Vector con las texturas de los items
std::vector<Texture *> balloonTextures; // Vector con las texturas de los globos
std::vector<Texture *> explosionsTextures; // Vector con las texturas de las explosiones
std::vector<Texture *> player1Textures; // Vector con las texturas del jugador
std::vector<Texture *> player2Textures; // Vector con las texturas del jugador
std::vector<std::vector<Texture *>> playerTextures; // Vector con todas las texturas de los jugadores;
SDL_Texture *canvas_; // Textura para dibujar la zona de juego
Texture *gameTextTexture; // Textura para los sprites con textos
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::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::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;
Text *text; // Fuente para los textos del juego
Text *textBig; // Fuente de texto grande
Text *textNokia2; // Otra fuente de texto para mensajes
Text *textNokiaBig2; // Y la versión en grande
std::vector<std::shared_ptr<Texture>> game_text_textures_; // Vector con las texturas para los sprites con textos
Fade *fade; // Objeto para renderizar fades
SDL_Event *eventHandler; // Manejador de eventos
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
SmartSprite *n1000Sprite; // Sprite con el texto 1.000
SmartSprite *n2500Sprite; // Sprite con el texto 2.500
SmartSprite *n5000Sprite; // Sprite con el texto 5.000
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
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_t 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
int difficulty; // Dificultad del juego
float difficultyScoreMultiplier; // Multiplicador de puntos en función de la dificultad
color_t 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
@@ -214,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();
@@ -222,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_t (*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);
@@ -256,7 +220,7 @@ private:
void renderBalloons();
// Crea un globo nuevo en el vector de globos
int 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();
@@ -264,23 +228,14 @@ 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();
// Explosiona un globo. Lo destruye y crea otros dos si es el caso
void popBalloon(Balloon *balloon);
void popBalloon(std::shared_ptr<Balloon> balloon);
// Explosiona un globo. Lo destruye
void destroyBalloon(Balloon *balloon);
// Explosiona todos los globos
void popAllBalloons();
void destroyBalloon(std::shared_ptr<Balloon> &balloon);
// Destruye todos los globos
void destroyAllBalloons();
@@ -291,17 +246,14 @@ 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();
// Comprueba la colisión entre el jugador y los globos activos
bool checkPlayerBalloonCollision(Player *player);
bool checkPlayerBalloonCollision(std::shared_ptr<Player> &player);
// Comprueba la colisión entre el jugador y los items
void checkPlayerItemCollision(Player *player);
void checkPlayerItemCollision(std::shared_ptr<Player> &player);
// Comprueba la colisión entre las balas y los globos
void checkBulletBalloonCollision();
@@ -313,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();
@@ -325,43 +277,43 @@ 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, 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(Player *player);
void killPlayer(std::shared_ptr<Player> &player);
// Calcula y establece el valor de amenaza en funcion de los globos activos
void evaluateAndSetMenace();
// Obtiene el valor de la variable
int getMenace();
int getMenace() const;
// Establece el valor de la variable
void setTimeStopped(bool value);
// Obtiene el valor de la variable
bool isTimeStopped();
bool isTimeStopped() const;
// Establece el valor de la variable
void setTimeStoppedCounter(int value);
@@ -370,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();
@@ -381,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();
@@ -409,14 +358,14 @@ private:
void updateHelper();
// Comprueba si todos los jugadores han terminado de jugar
bool allPlayersAreWaiting();
bool allPlayersAreWaitingOrGameOver();
// Comprueba si todos los jugadores han terminado de jugar
bool allPlayersAreGameOver();
// 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();
@@ -436,26 +385,54 @@ 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);
// Comprueba si la puntuación entra en la tabla de mejores puntuaciones
bool IsEligibleForHighScore(int score);
// Saca del estado de GAME OVER al jugador si el otro está activo
void checkAndUpdatePlayerStatus(int active_player_index, int inactive_player_index);
// Comprueba el estado de juego de los jugadores
void checkPlayersStatusPlaying();
// Obtiene un jugador a partir de su "id"
Player *getPlayer(int id);
std::shared_ptr<Player> getPlayer(int id);
// Obtiene un controlador a partir del "id" del jugador
int getController(int playerId);
// Termina
void quit(section::options_e code);
// 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,194 +1,183 @@
#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_t, paramGame_t, paramTitle_t
#include "utils.h" // for Param, ParamGame, ParamTitle
// Constructor
GameLogo::GameLogo(int x, int 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)
{
// Copia los punteros
screen = Screen::get();
renderer = screen->getRenderer();
asset = Asset::get();
this->x = x;
this->y = y;
// Crea los objetos
dustTexture = new Texture(renderer, asset->get("title_dust.png"));
coffeeTexture = new Texture(renderer, asset->get("title_coffee.png"));
crisisTexture = new Texture(renderer, asset->get("title_crisis.png"));
arcadeEditionTexture = new Texture(renderer, asset->get("title_arcade_edition.png"));
coffeeBitmap = new SmartSprite(coffeeTexture);
crisisBitmap = new SmartSprite(crisisTexture);
arcadeEditionBitmap = new Sprite((param.game.width - arcadeEditionTexture->getWidth()) / 2, param.title.arcadeEditionPosition, arcadeEditionTexture->getWidth(), arcadeEditionTexture->getHeight(), arcadeEditionTexture);
dustBitmapL = new AnimatedSprite(dustTexture, asset->get("title_dust.ani"));
dustBitmapR = new AnimatedSprite(dustTexture, asset->get("title_dust.ani"));
// Sonidos
crashSound = JA_LoadSound(asset->get("title.wav").c_str());
// Inicializa las variables
init();
}
// Destructor
GameLogo::~GameLogo()
{
delete dustTexture;
delete coffeeTexture;
delete crisisTexture;
delete arcadeEditionTexture;
delete coffeeBitmap;
delete crisisBitmap;
delete arcadeEditionBitmap;
delete dustBitmapL;
delete dustBitmapR;
JA_DeleteSound(crashSound);
}
// Inicializa las variables
void GameLogo::init()
{
const int xp = x - coffeeBitmap->getWidth() / 2;
const int desp = getInitialVerticalDesp();
const auto xp = x_ - coffee_sprite_->getWidth() / 2;
const auto desp = getInitialVerticalDesp();
// Variables
status = disabled;
shake.desp = 1;
shake.delay = 2;
shake.lenght = 8;
shake.remaining = shake.lenght;
shake.counter = shake.delay;
shake.origin = xp;
status_ = Status::DISABLED;
shake_.desp = 1;
shake_.delay = 2;
shake_.lenght = 8;
shake_.remaining = shake_.lenght;
shake_.counter = shake_.delay;
shake_.origin = xp;
// Inicializa el bitmap de 'Coffee'
coffeeBitmap->init();
coffeeBitmap->setPosX(xp);
coffeeBitmap->setPosY(y - coffeeTexture->getHeight() - desp);
coffeeBitmap->setWidth(coffeeTexture->getWidth());
coffeeBitmap->setHeight(coffeeTexture->getHeight());
coffeeBitmap->setVelX(0.0f);
coffeeBitmap->setVelY(2.5f);
coffeeBitmap->setAccelX(0.0f);
coffeeBitmap->setAccelY(0.1f);
coffeeBitmap->setSpriteClip(0, 0, coffeeTexture->getWidth(), coffeeTexture->getHeight());
coffeeBitmap->setEnabled(true);
coffeeBitmap->setEnabledCounter(0);
coffeeBitmap->setDestX(xp);
coffeeBitmap->setDestY(y - coffeeTexture->getHeight());
coffee_sprite_->init();
coffee_sprite_->setPosX(xp);
coffee_sprite_->setPosY(y_ - coffee_texture_->getHeight() - desp);
coffee_sprite_->setWidth(coffee_texture_->getWidth());
coffee_sprite_->setHeight(coffee_texture_->getHeight());
coffee_sprite_->setVelX(0.0f);
coffee_sprite_->setVelY(2.5f);
coffee_sprite_->setAccelX(0.0f);
coffee_sprite_->setAccelY(0.1f);
coffee_sprite_->setSpriteClip(0, 0, coffee_texture_->getWidth(), coffee_texture_->getHeight());
coffee_sprite_->setEnabled(true);
coffee_sprite_->setFinishedCounter(0);
coffee_sprite_->setDestX(xp);
coffee_sprite_->setDestY(y_ - coffee_texture_->getHeight());
// Inicializa el bitmap de 'Crisis'
crisisBitmap->init();
crisisBitmap->setPosX(xp + 15);
crisisBitmap->setPosY(y + desp);
crisisBitmap->setWidth(crisisTexture->getWidth());
crisisBitmap->setHeight(crisisTexture->getHeight());
crisisBitmap->setVelX(0.0f);
crisisBitmap->setVelY(-2.5f);
crisisBitmap->setAccelX(0.0f);
crisisBitmap->setAccelY(-0.1f);
crisisBitmap->setSpriteClip(0, 0, crisisTexture->getWidth(), crisisTexture->getHeight());
crisisBitmap->setEnabled(true);
crisisBitmap->setEnabledCounter(0);
crisisBitmap->setDestX(xp + 15);
crisisBitmap->setDestY(y);
crisis_sprite_->init();
crisis_sprite_->setPosX(xp + 15);
crisis_sprite_->setPosY(y_ + desp);
crisis_sprite_->setWidth(crisis_texture_->getWidth());
crisis_sprite_->setHeight(crisis_texture_->getHeight());
crisis_sprite_->setVelX(0.0f);
crisis_sprite_->setVelY(-2.5f);
crisis_sprite_->setAccelX(0.0f);
crisis_sprite_->setAccelY(-0.1f);
crisis_sprite_->setSpriteClip(0, 0, crisis_texture_->getWidth(), crisis_texture_->getHeight());
crisis_sprite_->setEnabled(true);
crisis_sprite_->setFinishedCounter(0);
crisis_sprite_->setDestX(xp + 15);
crisis_sprite_->setDestY(y_);
// Inicializa el bitmap de 'DustRight'
dustBitmapR->resetAnimation();
dustBitmapR->setPosX(coffeeBitmap->getPosX() + coffeeBitmap->getWidth());
dustBitmapR->setPosY(y);
dustBitmapR->setWidth(16);
dustBitmapR->setHeight(16);
dustBitmapR->setFlip(SDL_FLIP_HORIZONTAL);
dust_right_sprite_->resetAnimation();
dust_right_sprite_->setPosX(coffee_sprite_->getPosX() + coffee_sprite_->getWidth());
dust_right_sprite_->setPosY(y_);
dust_right_sprite_->setWidth(16);
dust_right_sprite_->setHeight(16);
dust_right_sprite_->setFlip(SDL_FLIP_HORIZONTAL);
// Inicializa el bitmap de 'DustLeft'
dustBitmapL->resetAnimation();
dustBitmapL->setPosX(coffeeBitmap->getPosX() - 16);
dustBitmapL->setPosY(y);
dustBitmapL->setWidth(16);
dustBitmapL->setHeight(16);
dust_left_sprite_->resetAnimation();
dust_left_sprite_->setPosX(coffee_sprite_->getPosX() - 16);
dust_left_sprite_->setPosY(y_);
dust_left_sprite_->setWidth(16);
dust_left_sprite_->setHeight(16);
}
// Pinta la clase en pantalla
void GameLogo::render()
{
// Dibuja el logo
coffeeBitmap->render();
crisisBitmap->render();
coffee_sprite_->render();
crisis_sprite_->render();
if (status == finished)
arcadeEditionBitmap->render();
if (status_ == Status::FINISHED)
{
arcade_edition_sprite_->render();
}
// Dibuja el polvillo del logo
dustBitmapR->render();
dustBitmapL->render();
dust_right_sprite_->render();
dust_left_sprite_->render();
}
// Actualiza la lógica de la clase
void GameLogo::update()
{
if (status == moving)
switch (status_)
{
coffeeBitmap->update();
crisisBitmap->update();
case Status::MOVING:
{
coffee_sprite_->update();
crisis_sprite_->update();
// Si los objetos han llegado a su destino, cambiamos de Sección
if (coffeeBitmap->hasFinished() && crisisBitmap->hasFinished())
if (coffee_sprite_->hasFinished() && crisis_sprite_->hasFinished())
{
status = shaking;
// Pantallazo blanco
//screen->flash(flashColor, 10);
status_ = Status::SHAKING;
// Reproduce el efecto sonoro
JA_PlaySound(crashSound);
JA_PlaySound(Resource::get()->getSound("title.wav"));
}
break;
}
else if (status == shaking)
case Status::SHAKING:
{
// Agita el logo
if (shake.remaining > 0)
if (shake_.remaining > 0)
{
if (shake.counter > 0)
if (shake_.counter > 0)
{
shake.counter--;
shake_.counter--;
}
else
{
shake.counter = shake.delay;
const int desp = shake.remaining % 2 == 0 ? shake.desp * (-1) : shake.desp;
coffeeBitmap->setPosX(shake.origin + desp);
crisisBitmap->setPosX(shake.origin + desp + 15);
shake.remaining--;
shake_.counter = shake_.delay;
const auto desp = shake_.remaining % 2 == 0 ? shake_.desp * (-1) : shake_.desp;
coffee_sprite_->setPosX(shake_.origin + desp);
crisis_sprite_->setPosX(shake_.origin + desp + 15);
shake_.remaining--;
}
}
else
{
coffeeBitmap->setPosX(shake.origin);
crisisBitmap->setPosX(shake.origin + 15);
status = finished;
coffee_sprite_->setPosX(shake_.origin);
crisis_sprite_->setPosX(shake_.origin + 15);
status_ = Status::FINISHED;
}
dustBitmapR->update();
dustBitmapL->update();
dust_right_sprite_->update();
dust_left_sprite_->update();
break;
}
else if (status == finished)
case Status::FINISHED:
{
dustBitmapR->update();
dustBitmapL->update();
dust_right_sprite_->update();
dust_left_sprite_->update();
break;
}
default:
break;
}
}
@@ -196,28 +185,28 @@ void GameLogo::update()
void GameLogo::enable()
{
init();
status = moving;
status_ = Status::MOVING;
}
// Indica si ha terminado la animación
bool GameLogo::hasFinished()
bool GameLogo::hasFinished() const
{
return (status == finished);
return status_ == Status::FINISHED;
}
// Recarga las texturas
void GameLogo::reLoad()
{
dustTexture->reLoad();
coffeeTexture->reLoad();
crisisTexture->reLoad();
dust_texture_->reLoad();
coffee_texture_->reLoad();
crisis_texture_->reLoad();
}
// Calcula el desplazamiento vertical inicial
int GameLogo::getInitialVerticalDesp()
{
int despUp = y;
int despDown = param.game.height - y;
auto desp_up = y_;
auto desp_down = param.game.height - y_;
return std::max(despUp, despDown);
return std::max(desp_up, desp_down);
}

View File

@@ -1,51 +1,25 @@
#pragma once
#include <SDL2/SDL_render.h> // for SDL_Renderer
class AnimatedSprite;
class Asset;
class Screen;
class SmartSprite;
#include <memory> // for unique_ptr, shared_ptr
#include "animated_sprite.h"
#include "smart_sprite.h"
class Sprite;
class Texture;
struct JA_Sound_t;
struct JA_Sound_t; // lines 10-10
// Clase GameLogo
class GameLogo
{
private:
// 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
Texture *dustTexture; // Textura con los graficos del polvo
Texture *coffeeTexture; // Textura con los graficos de la palabra "COFFEE"
Texture *crisisTexture; // Textura con los graficos de la plabra "CRISIS"
Texture *arcadeEditionTexture; // Textura con los graficos de "Arcade Edition"
AnimatedSprite *dustBitmapL; // Sprite con la el polvo que aparece al colisionar el texto de la pantalla de titulo
AnimatedSprite *dustBitmapR; // Sprite con la el polvo que aparece al colisionar el texto de la pantalla de titulo
SmartSprite *coffeeBitmap; // Sprite con la palabra "COFFEE" para la pantalla de titulo
SmartSprite *crisisBitmap; // Sprite con la palabra "CRISIS" para la pantalla de titulo
Sprite *arcadeEditionBitmap; // Sprite con los graficos de "Arcade Edition"
JA_Sound_t *crashSound; // 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 status_e
enum class Status
{
disabled,
moving,
shaking,
finished
} status; // Estado en el que se encuentra la clase
DISABLED,
MOVING,
SHAKING,
FINISHED,
};
struct shake_t
struct Shake
{
int desp; // Pixels de desplazamiento para agitar la pantalla en el eje x
int delay; // Retraso entre cada desplazamiento de la pantalla al agitarse
@@ -53,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();
@@ -66,7 +61,7 @@ public:
GameLogo(int x, int y);
// Destructor
~GameLogo();
~GameLogo() = default;
// Pinta la clase en pantalla
void render();
@@ -78,7 +73,7 @@ public:
void enable();
// Indica si ha terminado la animación
bool hasFinished();
bool hasFinished() const;
// Recarga las texturas
void reLoad();

View File

@@ -1,87 +1,145 @@
#include "global_inputs.h"
#include <string> // for basic_string, operator+
#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 "options.h" // for options
#include "screen.h" // for Screen
#include "section.h" // for options_e, name, name_e, options
#include "utils.h" // for op_audio_t, options_t, op_music_t, boolToOnOff
#include <string> // for basic_string, operator+
#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
#include "section.h" // for SectionOptions, name, SectionName, options
#include "utils.h" // for OptionsAudio, Options, OptionsMusic, boolToOnOff
// Termina
void quit(section::options_e code)
namespace globalInputs
{
if (Screen::get()->notificationsAreActive())
{
section::name = section::NAME_QUIT;
section::options = code;
}
else
{
Screen::get()->showNotification(lang::getText(94));
}
}
// Variables
std::vector<int> service_pressed_counter;
// Reinicia
void reset()
{
section::name = section::NAME_INIT;
Screen::get()->showNotification("Reset");
}
// Activa o desactiva el audio
void switchAudio()
{
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));
}
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
void checkGlobalInputs()
{
// Comprueba si se sale con el teclado
if (Input::get()->checkInput(input_exit, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
// Inicializa variables
void init()
{
quit(section::OPTIONS_QUIT_NORMAL);
return;
}
// Comprueba si se va a resetear el juego
else if (Input::get()->checkInput(input_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))
{
switchAudio();
return;
}
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))
const auto num_inputs = Input::get()->getNumControllers() + 1;
service_pressed_counter.reserve(num_inputs);
for (int i = 0; i < num_inputs; ++i)
{
quit(section::OPTIONS_QUIT_SHUTDOWN);
service_pressed_counter.push_back(0);
}
}
// Termina
void quit(section::Options code)
{
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
{
#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
}
}
// Reinicia
void reset()
{
section::name = section::Name::INIT;
Notifier::get()->showText("Reset");
}
// Activa o desactiva el audio
void switchAudio()
{
options.audio.sound.enabled = options.audio.music.enabled = !options.audio.music.enabled;
JA_EnableMusic(options.audio.music.enabled);
JA_EnableSound(options.audio.sound.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(InputType::EXIT, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
{
quit(section::Options::QUIT_WITH_KEYBOARD);
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()->checkInput(InputType::RESET, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
{
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()->checkInput(InputType::MUTE, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
{
switchAudio();
return;
}
else if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, INPUT_USE_KEYBOARD))
{
service_pressed_counter[0]++;
if (service_pressed_counter[0] >= 3000)
{
OnScreenHelp::get()->toggleState();
service_pressed_counter[0] = 0;
}
return;
}
else
{
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(InputType::SERVICE, InputType::EXIT, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i))
{
quit(section::Options::QUIT_WITH_CONTROLLER);
return;
}
// Comprueba si se va a resetear el juego
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(InputType::SERVICE, InputType::MUTE, INPUT_DO_NOT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i))
{
switchAudio();
return;
}
if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, INPUT_USE_GAMECONTROLLER, i))
{
service_pressed_counter[i + 1]++;
if (service_pressed_counter[i + 1] >= 3000)
{
OnScreenHelp::get()->toggleState();
service_pressed_counter[i + 1] = 0;
}
return;
}
else
{
service_pressed_counter[i + 1] = 0;
}
}
}
}

View File

@@ -1,2 +1,11 @@
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
void checkGlobalInputs();
#include <vector>
namespace globalInputs
{
extern std::vector<int> service_pressed_counter;
// Inicializa variables
void init();
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
void check();
}

View File

@@ -1,62 +1,52 @@
#include "hiscore_table.h"
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND
#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 <vector> // for vector
#include "asset.h" // for Asset
#include "background.h" // for Background
#include "fade.h" // for Fade, FADE_IN, FADE_OUT, FADE_RANDOM...
#include "global_inputs.h" // for checkGlobalInputs
#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 "screen.h" // for Screen
#include "text.h" // for Text, TXT_CENTER, TXT_SHADOW, TXT_COLOR
#include "utils.h" // for param_t, paramGame_t, hiScoreEntry_t
#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 <vector> // for vector
#include "asset.h" // for Asset
#include "background.h" // for Background
#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 "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)
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
this->music = music;
asset = Asset::get();
input = Input::get();
screen = Screen::get();
renderer = screen->getRenderer();
// Objetos
eventHandler = new SDL_Event();
fade = new Fade(renderer);
background = new Background(renderer);
text = new Text(asset->get("smb2.gif"), asset->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
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 = FADE_IN;
// Inicializa el resto de variables
section::name = section::Name::HI_SCORE_TABLE;
// Inicializa objetos
background->setPos(param.game.gameArea.rect);
background->setCloudsSpeed(-0.1f);
background->setGradientNumber(1);
background->setTransition(0.8f);
fade->setColor(fadeColor.r, fadeColor.g, fadeColor.b);
fade->setType(FADE_RANDOM_SQUARE);
fade->setPost(param.fade.postDuration);
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();
@@ -65,47 +55,45 @@ HiScoreTable::HiScoreTable(JA_Music_t *music)
// Destructor
HiScoreTable::~HiScoreTable()
{
delete text;
delete eventHandler;
delete background;
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->update();
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();
}
}
}
@@ -113,70 +101,71 @@ 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
const int maxNames = 10;
const int spaceBetweenHeader = 32;
const int spaceBetweenLines = text->getCharacterSize() * 2.0f;
const int size = spaceBetweenHeader + spaceBetweenLines * (maxNames - 1) + text->getCharacterSize();
const int 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
SDL_Texture *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(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param.game.gameArea.centerX, firstLine, lang::getText(42), 1, orangeColor, 1, shdwTxtColor);
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 int nameLenght = options.game.hiScoreTable[i].name.length();
const std::string score = format(options.game.hiScoreTable[i].score);
const int scoreLenght = score.size();
const int numDots = 25 - nameLenght - scoreLenght;
std::string dots = "";
for (int j = 0; j < numDots; ++j)
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 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 std::string line = options.game.hiScoreTable[i].name + dots + score;
text->writeDX(TXT_CENTER | TXT_SHADOW, param.game.gameArea.centerX, (i * spaceBetweenLines) + firstLine + spaceBetweenHeader, line, 1, orangeColor, 1, shdwTxtColor);
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 * 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
void HiScoreTable::render()
{
// Prepara para empezar a dibujar en la textura de juego
screen->start();
Screen::get()->start();
// Limpia la pantalla
screen->clean(bgColor);
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_);
fade->render();
// Renderiza el fade
fade_->render();
// Vuelca el contenido del renderizador en pantalla
screen->blit();
Screen::get()->blit();
}
// Recarga todas las texturas
void HiScoreTable::reloadTextures()
{
text->reLoadTexture();
text_->reLoadTexture();
fillTexture();
}
@@ -184,19 +173,21 @@ void HiScoreTable::reloadTextures()
void HiScoreTable::checkEvents()
{
// Comprueba los eventos que hay en la cola
while (SDL_PollEvent(eventHandler) != 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::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();
}
@@ -208,25 +199,25 @@ void HiScoreTable::checkEvents()
void HiScoreTable::checkInput()
{
// Comprueba si se ha pulsado cualquier botón (de los usados para jugar)
if (input->checkAnyButtonPressed())
if (Input::get()->checkAnyButtonPressed())
{
JA_StopMusic();
section::name = section::NAME_TITLE;
section::options = section::OPTIONS_TITLE_1;
section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1;
return;
}
// Comprueba el input para el resto de objetos
screen->checkInput();
Screen::get()->checkInput();
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
checkGlobalInputs();
globalInputs::check();
}
// Bucle para la pantalla de instrucciones
void HiScoreTable::run()
{
while (section::name == section::NAME_HI_SCORE_TABLE)
while (section::name == section::Name::HI_SCORE_TABLE)
{
checkInput();
update();
@@ -235,62 +226,21 @@ void HiScoreTable::run()
}
}
// Transforma un valor numérico en una cadena de 6 cifras
std::string HiScoreTable::scoreToString(int num)
{
if ((num >= 0) && (num <= 9))
{
return ("000000" + std::to_string(num));
}
if ((num >= 10) && (num <= 99))
{
return ("00000" + std::to_string(num));
}
if ((num >= 100) && (num <= 999))
{
return ("0000" + std::to_string(num));
}
if ((num >= 1000) && (num <= 9999))
{
return ("000" + std::to_string(num));
}
if ((num >= 010000) && (num <= 99999))
{
return ("00" + std::to_string(num));
}
if ((num >= 100000) && (num <= 999999))
{
return ("0" + std::to_string(num));
}
if ((num >= 1000000) && (num <= 9999999))
{
return (std::to_string(num));
}
return (std::to_string(num));
}
// Gestiona el fade
void HiScoreTable::updateFade()
{
fade->update();
fade_->update();
if (fade->hasEnded() && fadeMode == FADE_IN)
if (fade_->hasEnded() && fade_mode_ == FadeMode::IN)
{
fade->reset();
fadeMode = FADE_OUT;
fade->setMode(fadeMode);
fade_->reset();
fade_mode_ = FadeMode::OUT;
fade_->setMode(fade_mode_);
}
if (fade->hasEnded() && fadeMode == FADE_OUT)
if (fade_->hasEnded() && fade_mode_ == FadeMode::OUT)
{
section::name = section::NAME_INSTRUCTIONS;
section::name = section::Name::INSTRUCTIONS;
}
}
@@ -300,9 +250,9 @@ std::string HiScoreTable::format(int number)
const std::string separator = ".";
const std::string score = std::to_string(number);
int index = (int)score.size() - 1;
std::string result = "";
int i = 0;
auto index = (int)score.size() - 1;
std::string result;
auto i = 0;
while (index >= 0)
{
result = score.at(index) + result;

View File

@@ -1,18 +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 <string> // for string
#include "section.h" // for options_e
class Asset;
class Background;
class Fade;
class Input;
class Screen;
class Text;
struct JA_Music_t;
#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, 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
@@ -28,25 +24,23 @@ struct JA_Music_t;
class HiScoreTable
{
private:
// 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
// Objetos y punteros
SDL_Renderer *renderer; // El renderizador de la ventana
Screen *screen; // Objeto encargado de dibujar en pantalla
SDL_Event *eventHandler; // Manejador de eventos
SDL_Texture *backbuffer; // Textura para usar como backbuffer
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
Input *input; // Objeto pata gestionar la entrada
Background *background; // Objeto para dibujar el fondo del juego
Fade *fade; // Objeto para renderizar fades
Text *text; // Objeto para escribir texto
JA_Music_t *music; // Musica de fondo
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
int 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();
@@ -63,9 +57,6 @@ private:
// Convierte un entero a un string con separadores de miles
std::string format(int number);
// Transforma un valor numérico en una cadena de 6 cifras
std::string scoreToString(int num);
// Crea el contenido de la textura con la lista de puntuaciones
void fillTexture();
@@ -75,12 +66,9 @@ private:
// Gestiona el fade
void updateFade();
// Termina
void quit(section::options_e code);
public:
// Constructor
HiScoreTable(JA_Music_t *music);
HiScoreTable();
// Destructor
~HiScoreTable();

View File

@@ -1,130 +1,111 @@
#include "input.h"
#include <SDL2/SDL.h> // for SDL_INIT_GAMECONTROLLER, SDL_InitSubS...
#include <SDL2/SDL_error.h> // for SDL_GetError
#include <SDL2/SDL_events.h> // for SDL_ENABLE
#include <SDL2/SDL_keyboard.h> // for SDL_GetKeyboardState
#include <iostream> // for basic_ostream, operator<<, cout, basi...
#include <SDL2/SDL.h> // for SDL_INIT_GAMECONTROLLER, SDL_InitSubS...
#include <SDL2/SDL_error.h> // for SDL_GetError
#include <SDL2/SDL_events.h> // for SDL_ENABLE
#include <SDL2/SDL_keyboard.h> // for SDL_GetKeyboardState
#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 file)
void Input::init(const std::string &game_controller_db_path)
{
Input::input = new Input(file);
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 file)
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;
// Fichero gamecontrollerdb.txt
dbPath = file;
// 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)
@@ -133,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)
@@ -243,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;
}
}
@@ -357,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;
}
}
@@ -375,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))
@@ -390,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))
{
@@ -412,59 +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);
// name.resize(25);
// name = name + separator + std::to_string(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;
}
@@ -474,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)
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()
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)
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;
}
@@ -529,7 +485,7 @@ int Input::getJoyIndex(int id)
}
// Muestra por consola los controles asignados
void Input::printBindings(int device, int index)
void Input::printBindings(int device, int controller_index) const
{
if (device == INPUT_USE_ANY || device == INPUT_USE_KEYBOARD)
{
@@ -538,35 +494,35 @@ void Input::printBindings(int device, int index)
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)
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)
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;
}
@@ -574,30 +530,30 @@ int Input::getIndexByName(std::string name)
return -1;
}
// Convierte un inputs_e a std::string
std::string Input::to_string(inputs_e input)
// 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";
}
@@ -605,76 +561,67 @@ std::string Input::to_string(inputs_e input)
return "";
}
// Convierte un std::string a inputs_e
inputs_e Input::to_inputs_e(std::string name)
// 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)
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);
bool checkAxisInput(InputType input, int controller_index = 0) const;
// Constructor
Input(std::string file);
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 file);
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);
@@ -144,38 +132,26 @@ public:
bool gameControllerFound();
// Obten el número de mandos conectados
int getNumControllers();
int getNumControllers() const;
// Obten el nombre de un mando de juego
std::string getControllerName(int index);
// 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);
int getJoyIndex(int id) const;
// Muestra por consola los controles asignados
void printBindings(int device = INPUT_USE_KEYBOARD, int index = 0);
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);
SDL_GameControllerButton getControllerBinding(int controller_index, InputType input) const;
// Convierte un inputs_e a std::string
std::string to_string(inputs_e input);
// 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);
// 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);
// 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,66 +1,63 @@
#include "instructions.h"
#include <SDL2/SDL_blendmode.h> // for SDL_BLENDMODE_BLEND
#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 "asset.h" // for Asset
#include "fade.h" // for Fade, FADE_FULLSCREEN, FADE_IN
#include "global_inputs.h" // for checkGlobalInputs
#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 "screen.h" // for Screen
#include "section.h" // for name, name_e, options, options_e
#include "sprite.h" // for Sprite
#include "text.h" // for Text, TXT_CENTER, TXT_COLOR, TXT_SHADOW
#include "texture.h" // for Texture
#include "tiled_bg.h" // for Tiledbg, TILED_MODE_STATIC
#include "utils.h" // for param_t, paramGame_t, color_t, shdwT...
struct JA_Music_t;
#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 <utility> // for move
#include "asset.h" // for Asset
#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, name, Options, options
#include "sprite.h" // for Sprite
#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, shdw_txt_color
struct JA_Music_t; // lines 22-22
// Constructor
Instructions::Instructions(JA_Music_t *music)
Instructions::Instructions()
{
// Copia los punteros
this->music = music;
input = Input::get();
screen = Screen::get();
asset = Asset::get();
renderer = screen->getRenderer();
renderer_ = Screen::get()->getRenderer();
// Crea objetos
eventHandler = new SDL_Event();
text = new Text(asset->get("smb2.gif"), asset->get("smb2.txt"), renderer);
tiledbg = new Tiledbg(asset->get("title_bg_tile.png"), {0, 0, param.game.width, param.game.height}, TILED_MODE_STATIC);
fade = new 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;
section::name = section::Name::INSTRUCTIONS;
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(fadeColor.r, fadeColor.g, fadeColor.b);
fade->setType(FADE_FULLSCREEN);
fade->setPost(param.fade.postDuration);
fade->setMode(FADE_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();
@@ -72,205 +69,181 @@ Instructions::Instructions(JA_Music_t *music)
// Destructor
Instructions::~Instructions()
{
for (auto texture : itemTextures)
{
texture->unload();
delete texture;
}
itemTextures.clear();
item_textures_.clear();
sprites_.clear();
for (auto sprite : sprites)
{
delete sprite;
}
sprites.clear();
delete eventHandler;
delete text;
delete tiledbg;
delete fade;
SDL_DestroyTexture(backbuffer);
SDL_DestroyTexture(texture);
SDL_DestroyTexture(backbuffer_);
SDL_DestroyTexture(texture_);
}
// Inicializa los sprites de los items
void Instructions::iniSprites()
{
// Inicializa las texturas
Texture *item1 = new Texture(renderer, asset->get("item_points1_disk.png"));
itemTextures.push_back(item1);
Texture *item2 = new Texture(renderer, asset->get("item_points2_gavina.png"));
itemTextures.push_back(item2);
Texture *item3 = new Texture(renderer, asset->get("item_points3_pacmar.png"));
itemTextures.push_back(item3);
Texture *item4 = new Texture(renderer, asset->get("item_clock.png"));
itemTextures.push_back(item4);
Texture *item5 = new Texture(renderer, asset->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)
{
Sprite *sprite = new Sprite(0, 0, param.game.itemSize, param.game.itemSize, itemTextures[i]);
sprite->setPos((SDL_Point){spritePos.x, spritePos.y + ((param.game.itemSize + itemSpace) * i)});
sprites.push_back(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.itemSize, param.game.itemSize};
SDL_Rect src_rect = {0, 0, param.game.item_size, param.game.item_size};
// Disquito
srcRect.y = param.game.itemSize * (((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.itemSize * (((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.itemSize * (((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.itemSize * (((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.itemSize * (((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.itemSize + 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.itemSize + 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(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param.game.gameArea.centerX, firstLine, lang::getText(11), 1, orangeColor, 1, shdwTxtColor);
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(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param.game.gameArea.centerX, anchor1 + spaceBetweenLines * 0, lang::getText(12), 1, noColor, 1, shdwTxtColor);
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param.game.gameArea.centerX, anchor1 + spaceBetweenLines * 1, lang::getText(13), 1, noColor, 1, shdwTxtColor);
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param.game.gameArea.centerX, anchor1 + spaceNewParagraph + spaceBetweenLines * 2, lang::getText(14), 1, noColor, 1, shdwTxtColor);
text->writeDX(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param.game.gameArea.centerX, anchor1 + spaceNewParagraph + spaceBetweenLines * 3, lang::getText(15), 1, noColor, 1, shdwTxtColor);
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(TXT_CENTER | TXT_COLOR | TXT_SHADOW, param.game.gameArea.centerX, anchor2, lang::getText(16), 1, orangeColor, 1, shdwTxtColor);
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 anchor4 = anchor3 + ((param.game.itemSize + text->getCharacterSize()) / 2);
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 0, lang::getText(17), shdwTxtColor);
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 1, lang::getText(18), shdwTxtColor);
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 2, lang::getText(19), shdwTxtColor);
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 3, lang::getText(20), shdwTxtColor);
text->writeShadowed(anchorItem + despX, anchor3 + spaceBetweenItemLines * 4, lang::getText(21), shdwTxtColor);
const int anchor3 = anchor2 + space_post_header;
// const int anchor4 = anchor3 + ((param.game.item_size + text->getCharacterSize()) / 2);
text_->writeShadowed(anchor_item + desp_x, anchor3 + space_between_item_lines * 0, lang::getText(17), shdw_txt_color);
text_->writeShadowed(anchor_item + desp_x, anchor3 + space_between_item_lines * 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.itemSize - 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->update();
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;
section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1;
}
}
}
@@ -282,34 +255,34 @@ void Instructions::render()
fillBackbuffer();
// Prepara para empezar a dibujar en la textura de juego
screen->start();
Screen::get()->start();
// Limpia la pantalla
screen->clean(bgColor);
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->blit();
Screen::get()->blit();
}
// 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();
}
@@ -317,19 +290,21 @@ void Instructions::reloadTextures()
void Instructions::checkEvents()
{
// Comprueba los eventos que hay en la cola
while (SDL_PollEvent(eventHandler) != 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::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();
}
@@ -341,25 +316,25 @@ void Instructions::checkEvents()
void Instructions::checkInput()
{
// Comprueba si se ha pulsado cualquier botón (de los usados para jugar)
if (input->checkAnyButtonPressed())
if (Input::get()->checkAnyButtonPressed())
{
JA_StopMusic();
section::name = section::NAME_TITLE;
section::options = section::OPTIONS_TITLE_1;
section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1;
return;
}
// Comprueba el input para el resto de objetos
screen->checkInput();
Screen::get()->checkInput();
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
checkGlobalInputs();
globalInputs::check();
}
// Bucle para la pantalla de instrucciones
void Instructions::run()
{
while (section::name == section::NAME_INSTRUCTIONS)
while (section::name == section::Name::INSTRUCTIONS)
{
checkInput();
update();

View File

@@ -1,19 +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 <vector> // for vector
class Asset;
#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
class Fade;
class Input;
class Screen;
class Sprite;
class Text;
class Texture;
class Tiledbg;
struct JA_Music_t;
class TiledBG;
struct JA_Music_t; // lines 14-14
/*
Esta clase gestiona un estado del programa. Se encarga de poner en pantalla
@@ -33,28 +30,24 @@ class Instructions
{
private:
// Objetos y punteros
SDL_Renderer *renderer; // El renderizador de la ventana
Screen *screen; // Objeto encargado de dibujar en pantalla
std::vector<Texture *> itemTextures; // Vector con las texturas de los items
std::vector<Sprite *> sprites; // Vector con los sprites de los items
SDL_Event *eventHandler; // Manejador de eventos
SDL_Texture *backbuffer; // Textura para usar como backbuffer
SDL_Texture *texture; // Textura fija con el texto
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
Input *input; // Objeto pata gestionar la entrada
Text *text; // Objeto para escribir texto
Tiledbg *tiledbg; // Objeto para dibujar el mosaico animado de fondo
Fade *fade; // Objeto para renderizar fades
JA_Music_t *music; // Musica de fondo
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
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();
@@ -85,7 +78,7 @@ private:
public:
// Constructor
Instructions(JA_Music_t *music);
Instructions();
// Destructor
~Instructions();

View File

@@ -1,206 +1,190 @@
#include "intro.h"
#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 "asset.h" // for Asset
#include "global_inputs.h" // for checkGlobalInputs
#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 "screen.h" // for Screen
#include "section.h" // for name, name_e, options, options_e
#include "smart_sprite.h" // for SmartSprite
#include "text.h" // for Text
#include "texture.h" // for Texture
#include "utils.h" // for paramGame_t, param_t, zone_t, BLOCK
#include "writer.h" // for Writer
struct JA_Music_t;
#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 <utility> // for move
#include "asset.h" // for Asset
#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, name, Options, options
#include "smart_sprite.h" // for SpriteSmart
#include "text.h" // for Text
#include "texture.h" // for Texture
#include "utils.h" // for Param, ParamGame, Zone, BLOCK, Color
#include "writer.h" // for Writer
struct JA_Music_t; // lines 19-19
// Constructor
Intro::Intro(JA_Music_t *music)
Intro::Intro()
{
// Copia los punteros
this->music = music;
input = Input::get();
asset = Asset::get();
screen = Screen::get();
SDL_Renderer *renderer = screen->getRenderer();
// Reserva memoria para los objetos
eventHandler = new SDL_Event();
texture = new Texture(renderer, asset->get("intro.png"));
text = new Text(asset->get("nokia.png"), asset->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_NULL;
ticks = 0;
ticksSpeed = 15;
scene = 1;
section::name = section::Name::INTRO;
section::options = section::Options::NONE;
ticks_ = 0;
ticks_speed_ = 15;
scene_ = 1;
// Inicializa los bitmaps de la intro
const int totalBitmaps = 6;
constexpr int totalBitmaps = 6;
for (int i = 0; i < totalBitmaps; ++i)
{
SmartSprite *ss = new SmartSprite(texture);
auto ss = std::make_unique<SmartSprite>(texture_);
ss->setWidth(128);
ss->setHeight(96);
ss->setEnabledCounter(20);
ss->setDestX(param.game.gameArea.centerX - 64);
ss->setDestY(param.game.gameArea.firstQuarterY - 24);
bitmaps.push_back(ss);
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[0]->setPosX(-128);
bitmaps[0]->setPosY(param.game.gameArea.firstQuarterY - 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.gameArea.firstQuarterY - 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.gameArea.centerX - 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]->setEnabledCounter(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.gameArea.centerX - 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.gameArea.centerX - 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.gameArea.firstQuarterY - 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
const int totalTexts = 9;
constexpr int totalTexts = 9;
for (int i = 0; i < totalTexts; ++i)
{
Writer *w = new 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->setEnabledCounter(180);
texts.push_back(w);
w->setFinishedCounter(180);
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.gameArea.centerX);
}
}
// Destructor
Intro::~Intro()
{
delete eventHandler;
delete texture;
for (auto bitmap : bitmaps)
{
delete bitmap;
}
for (auto text : texts)
{
delete text;
text->center(param.game.game_area.center_x);
}
}
// Recarga todas las texturas
void Intro::reloadTextures()
{
texture->reLoad();
text->reLoadTexture();
texture_->reLoad();
text_->reLoadTexture();
}
// Comprueba los eventos
void Intro::checkEvents()
{
SDL_Event event;
// Comprueba los eventos que hay en la cola
while (SDL_PollEvent(eventHandler) != 0)
while (SDL_PollEvent(&event))
{
// Evento de salida de la aplicación
if (eventHandler->type == SDL_QUIT)
switch (event.type)
{
section::name = section::NAME_QUIT;
case 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)
case SDL_WINDOWEVENT:
{
if (eventHandler->window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
reloadTextures();
}
break;
}
default:
break;
}
}
}
@@ -209,171 +193,176 @@ void Intro::checkEvents()
void Intro::checkInput()
{
// Comprueba si se ha pulsado cualquier botón (de los usados para jugar)
if (input->checkAnyButtonPressed())
if (Input::get()->checkAnyButtonPressed())
{
JA_StopMusic();
section::name = section::NAME_TITLE;
section::options = section::OPTIONS_TITLE_1;
section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1;
return;
}
// Comprueba el input para el resto de objetos
screen->checkInput();
Screen::get()->checkInput();
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
checkGlobalInputs();
globalInputs::check();
}
// 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;
section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1;
}
break;
}
default:
break;
@@ -383,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->update();
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();
}
@@ -411,32 +400,32 @@ void Intro::update()
void Intro::render()
{
// Prepara para empezar a dibujar en la textura de juego
screen->start();
Screen::get()->start();
// Limpia la pantalla
screen->clean(bgColor);
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();
}
// Vuelca el contenido del renderizador en pantalla
screen->blit();
Screen::get()->blit();
}
// Bucle principal
void Intro::run()
{
JA_PlayMusic(music, 0);
JA_PlayMusic(Resource::get()->getMusic("intro.ogg"), 0);
while (section::name == section::NAME_INTRO)
while (section::name == section::Name::INTRO)
{
checkInput();
update();

View File

@@ -1,16 +1,13 @@
#pragma once
#include <SDL2/SDL_events.h> // for SDL_Event
#include <SDL2/SDL_stdinc.h> // for Uint32, Uint8
#include <vector> // for vector
class Asset;
class Input;
class Screen;
class SmartSprite;
#include <SDL2/SDL_stdinc.h> // for Uint32, Uint8
#include <memory> // for unique_ptr, shared_ptr
#include <vector> // for vector
#include "smart_sprite.h" // for SpriteSmart
#include "writer.h" // for Writer
class Text;
class Texture;
class Writer;
struct JA_Music_t;
struct JA_Music_t; // lines 11-11
/*
Esta clase gestiona un estado del programa. Se encarga de mostrar la secuencia
@@ -21,21 +18,17 @@ struct JA_Music_t;
class Intro
{
private:
// Objetos y punteros
Screen *screen; // Objeto encargado de dibujar en pantalla
Texture *texture; // Textura con los graficos
SDL_Event *eventHandler; // Manejador de eventos
Asset *asset; // Objeto que gestiona todos los ficheros de recursos
Input *input; // Objeto pata gestionar la entrada
std::vector<SmartSprite *> bitmaps; // Vector con los sprites inteligentes para los dibujos de la intro
std::vector<Writer *> texts; // Textos de la intro
Text *text; // Textos de la intro
// Objetos
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
// 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();
@@ -57,10 +50,10 @@ private:
public:
// Constructor
Intro(JA_Music_t *music);
Intro();
// Destructor
~Intro();
~Intro() = default;
// Bucle principal
void run();

View File

@@ -1,72 +1,64 @@
#include "item.h"
#include <stdlib.h> // for rand
#include "animated_sprite.h" // for AnimatedSprite
#include "param.h" // for param
#include <stdlib.h> // for rand
#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, Texture *texture, std::vector<std::string> *animation)
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 = new AnimatedSprite(texture, "", animation);
this->kind = kind;
this->playArea = playArea;
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();
}
// Destructor
Item::~Item()
{
delete sprite;
}
// 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.playArea.rect.x)
if (pos_x_ < param.game.play_area.rect.x)
{
posX = param.game.playArea.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();
@@ -75,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();
}
}
}
@@ -91,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.playArea.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.playArea.rect.y) && !(kind == ITEM_COFFEE_MACHINE))
if ((pos_y_ < param.game.play_area.rect.y) && !(type_ == ItemType::COFFEE_MACHINE))
{
// Corrige
posY = param.game.playArea.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();
}
@@ -160,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_t &Item::getCollider()
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

@@ -1,43 +1,48 @@
#pragma once
#include <SDL2/SDL_rect.h> // for SDL_Rect
#include <SDL2/SDL_stdinc.h> // for Uint16
#include <string> // for string
#include <vector> // for vector
#include "utils.h" // for circle_t
class AnimatedSprite;
#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 "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
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_t 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();
@@ -45,14 +50,18 @@ 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, 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();
~Item() = default;
// Centra el objeto en la posición X
void allignTo(int x);
@@ -66,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();
@@ -85,13 +88,13 @@ public:
int getHeight();
// Obtiene del valor de la variable
int getClass();
ItemType getType();
// Obtiene el valor de la variable
bool isEnabled();
// Obtiene el circulo de colisión
circle_t &getCollider();
Circle &getCollider();
// Informa si el objeto ha colisionado con el suelo
bool isOnFloor();

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,108 +1,86 @@
#include "logo.h"
#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 "asset.h" // for Asset
#include "global_inputs.h" // for checkGlobalInputs
#include "input.h" // for Input
#include "jail_audio.h" // for JA_StopMusic
#include "param.h" // for param
#include "screen.h" // for Screen
#include "section.h" // for name, name_e, options, options_e
#include "sprite.h" // for Sprite
#include "texture.h" // for Texture
#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 <utility> // for move
#include "asset.h" // for Asset
#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, 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
input = Input::get();
screen = Screen::get();
asset = Asset::get();
SDL_Renderer *renderer = screen->getRenderer();
// Reserva memoria para los punteros
eventHandler = new SDL_Event();
jailTexture = new Texture(renderer, asset->get("logo_jailgames.png"));
sinceTexture = new Texture(renderer, asset->get("logo_since_1998.png"));
sinceSprite = new Sprite((param.game.width - sinceTexture->getWidth()) / 2, 83 + jailTexture->getHeight() + 5, sinceTexture->getWidth(), sinceTexture->getHeight(), sinceTexture);
// Inicializa variables
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.gameArea.centerX - jailTexture->getWidth() / 2;
dest.y = param.game.gameArea.centerY - 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 ??
counter_ = 0;
section::name = section::Name::LOGO;
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)
{
Sprite *temp = new 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(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
}
// Destructor
Logo::~Logo()
{
for (auto sprite : jailSprite)
{
delete sprite;
}
delete sinceSprite;
delete eventHandler;
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
void Logo::checkEvents()
{
SDL_Event event;
// Comprueba los eventos que hay en la cola
while (SDL_PollEvent(eventHandler) != 0)
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::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();
}
@@ -114,44 +92,44 @@ void Logo::checkEvents()
void Logo::checkInput()
{
// Comprueba si se ha pulsado cualquier botón (de los usados para jugar)
if (input->checkAnyButtonPressed())
if (Input::get()->checkAnyButtonPressed())
{
JA_StopMusic();
section::name = section::NAME_TITLE;
section::options = section::OPTIONS_TITLE_1;
section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1;
return;
}
// Comprueba el input para el resto de objetos
screen->checkInput();
Screen::get()->checkInput();
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
checkGlobalInputs();
globalInputs::check();
}
// 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);
}
}
}
@@ -162,88 +140,25 @@ void Logo::updateJAILGAMES()
// Gestiona el color de las texturas
void Logo::updateTextureColors()
{
const int inc = 4;
constexpr int inc = 4;
if (counter <= showSinceSprite_cm + inc * 0)
// Manejo de 'sinceTexture'
for (int i = 0; i <= 7; ++i)
{
sinceTexture->setColor(color[0].r, color[0].g, color[0].b);
if (counter_ == SHOW_SINCE_SPRITE_COUNTER_MARK + inc * i)
{
since_texture_->setColor(color_[i].r, color_[i].g, color_[i].b);
}
}
else if (counter == showSinceSprite_cm + inc * 1)
// Manejo de 'jailTexture' y 'sinceTexture' en el fade
for (int i = 0; i <= 6; ++i)
{
sinceTexture->setColor(color[1].r, color[1].g, color[1].b);
}
else if (counter == showSinceSprite_cm + inc * 2)
{
sinceTexture->setColor(color[2].r, color[2].g, color[2].b);
}
else if (counter == showSinceSprite_cm + inc * 3)
{
sinceTexture->setColor(color[3].r, color[3].g, color[3].b);
}
else if (counter == showSinceSprite_cm + inc * 4)
{
sinceTexture->setColor(color[4].r, color[4].g, color[4].b);
}
else if (counter == showSinceSprite_cm + inc * 5)
{
sinceTexture->setColor(color[5].r, color[5].g, color[5].b);
}
else if (counter == showSinceSprite_cm + inc * 6)
{
sinceTexture->setColor(color[6].r, color[6].g, color[6].b);
}
else if (counter == showSinceSprite_cm + inc * 7)
{
sinceTexture->setColor(color[7].r, color[7].g, color[7].b);
}
else if (counter == initFade_cm + inc * 0)
{
jailTexture->setColor(color[6].r, color[6].g, color[6].b);
sinceTexture->setColor(color[6].r, color[6].g, color[6].b);
}
else if (counter == initFade_cm + inc * 1)
{
jailTexture->setColor(color[5].r, color[5].g, color[5].b);
sinceTexture->setColor(color[5].r, color[5].g, color[5].b);
}
else if (counter == initFade_cm + inc * 2)
{
jailTexture->setColor(color[4].r, color[4].g, color[4].b);
sinceTexture->setColor(color[4].r, color[4].g, color[4].b);
}
else if (counter == initFade_cm + inc * 3)
{
jailTexture->setColor(color[3].r, color[3].g, color[3].b);
sinceTexture->setColor(color[3].r, color[3].g, color[3].b);
}
else if (counter == initFade_cm + inc * 4)
{
jailTexture->setColor(color[2].r, color[2].g, color[2].b);
sinceTexture->setColor(color[2].r, color[2].g, color[2].b);
}
else if (counter == initFade_cm + inc * 5)
{
jailTexture->setColor(color[1].r, color[1].g, color[1].b);
sinceTexture->setColor(color[1].r, color[1].g, color[1].b);
}
else if (counter == initFade_cm + inc * 6)
{
jailTexture->setColor(color[0].r, color[0].g, color[0].b);
sinceTexture->setColor(color[0].r, color[0].g, color[0].b);
if (counter_ == INIT_FADE_COUNTER_MARK + inc * i)
{
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);
}
}
}
@@ -251,13 +166,13 @@ 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->update();
Screen::get()->update();
// Comprueba las entradas
checkInput();
@@ -269,18 +184,12 @@ 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);
section::name = section::Name::INTRO;
}
}
}
@@ -289,20 +198,24 @@ void Logo::update()
void Logo::render()
{
// Prepara para empezar a dibujar en la textura de juego
screen->start();
Screen::get()->start();
// Limpia la pantalla
screen->clean();
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->blit();
Screen::get()->blit();
}
// Bucle para el logo del juego
@@ -311,7 +224,7 @@ void Logo::run()
// Detiene la música
JA_StopMusic();
while (section::name == section::NAME_LOGO)
while (section::name == section::Name::LOGO)
{
checkInput();
update();

View File

@@ -1,14 +1,11 @@
#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 <memory> // for unique_ptr, shared_ptr
#include <vector> // for vector
#include "utils.h" // for color_t
class Asset;
class Input;
class Screen;
class Sprite;
#include "sprite.h" // for Sprite
#include "utils.h" // for Color
class Texture;
/*
@@ -23,27 +20,25 @@ class Texture;
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
Screen *screen; // Objeto encargado de dibujar en pantalla
Asset *asset; // Objeto con los ficheros de recursos
Input *input; // Objeto pata gestionar la entrada
Texture *jailTexture; // Textura con los graficos "JAILGAMES"
Texture *sinceTexture; // Textura con los graficos "Since 1998"
SDL_Event *eventHandler; // Manejador de eventos
std::vector<Sprite *> jailSprite; // Vector con los sprites de cada linea que forman el bitmap JAILGAMES
Sprite *sinceSprite; // Sprite para manejar la sinceTexture
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_t> 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();
@@ -71,7 +66,7 @@ public:
Logo();
// Destructor
~Logo();
~Logo() = default;
// Bucle principal
void run();

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 int exit = director->run();
// Destruye el objeto Director
delete director;
const std::string endType = exit == 0 ? "keyboard" : "controller";
std::cout << "\nGame end with " << endType << std::endl;
return exit;
// Bucle principal
return director->run();
}

View File

@@ -1,54 +1,47 @@
#include "manage_hiscore_table.h"
#include <SDL2/SDL_error.h> // for SDL_GetError
#include <SDL2/SDL_rwops.h> // for SDL_RWread, SDL_RWwrite, SDL_RWFromFile
#include <stdlib.h> // for free, malloc
#include <algorithm> // for sort
#include <iostream> // for basic_ostream, char_traits, operator<<
#include "utils.h" // for hiScoreEntry_t
#include <SDL2/SDL_error.h> // for SDL_GetError
#include <SDL2/SDL_rwops.h> // for SDL_RWread, SDL_RWwrite, SDL_RWFromFile
#include <stdlib.h> // for free, malloc
#include <algorithm> // for sort
#include <iostream> // for basic_ostream, char_traits, operator<<
#include "utils.h" // for HiScoreEntry
// Constructor
ManageHiScoreTable::ManageHiScoreTable(std::vector<hiScoreEntry_t> *table)
{
this->table = table;
}
// Destructor
ManageHiScoreTable::~ManageHiScoreTable()
{
}
ManageHiScoreTable::ManageHiScoreTable(std::vector<HiScoreEntry> *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_t entry)
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);
}
}
@@ -57,31 +50,29 @@ void ManageHiScoreTable::sort()
{
struct
{
bool operator()(hiScoreEntry_t a, hiScoreEntry_t 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;
@@ -93,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;
@@ -103,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);
}
}
@@ -120,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

@@ -1,13 +1,13 @@
#pragma once
#include <string> // for string
#include <vector> // for vector
struct hiScoreEntry_t;
#include <string> // for string
#include <vector> // for vector
struct HiScoreEntry;
/*
Esta clase sirve para añadir elementos hiScoreEntry_r a un vector (tabla), de manera
que la tabla siempre está ordenada.
Además tiene un método para dejar la tabla con sus valores iniciales y métodos para
leer y escribir la tabla a un fichero
*/
@@ -17,27 +17,27 @@ class ManageHiScoreTable
{
private:
// Variables
std::vector<hiScoreEntry_t> *table; // Tabla con los records
std::vector<HiScoreEntry> *table_; // Tabla con los records
// Ordena la tabla
void sort();
public:
// Constructor
ManageHiScoreTable(std::vector<hiScoreEntry_t> *table);
explicit ManageHiScoreTable(std::vector<HiScoreEntry> *table);
// Destructor
~ManageHiScoreTable();
~ManageHiScoreTable() = default;
// Resetea la tabla a los valores por defecto
void clear();
// Añade un elemento a la tabla
void add(hiScoreEntry_t entry);
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

@@ -1,296 +1,79 @@
#include "moving_sprite.h"
#include "texture.h" // for Texture
#include "texture.h" // for Texture
// Constructor
MovingSprite::MovingSprite(float x, float y, int w, int h, float velx, float vely, float accelx, float accely, Texture *texture)
{
// Copia los punteros
this->texture = texture;
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 alto y el ancho del sprite
this->w = w;
this->h = h;
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 la posición X,Y del sprite
this->x = x;
this->y = y;
xPrev = x;
yPrev = y;
// Establece la velocidad X,Y del sprite
vx = velx;
vy = vely;
// Establece la aceleración X,Y del sprite
ax = accelx;
ay = accely;
// Establece el zoom W,H del sprite
zoomW = 1;
zoomH = 1;
// Establece el angulo con el que se dibujará
angle = (double)0;
// 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()
{
x = 0.0f; // Posición en el eje X
y = 0.0f; // Posición en el eje Y
x_ = 0.0f; // Posición en el eje X
y_ = 0.0f; // Posición en el eje Y
vx = 0.0f; // Velocidad en el eje X. Cantidad de pixeles a desplazarse
vy = 0.0f; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse
vx_ = 0.0f; // Velocidad en el eje X. Cantidad de pixeles a desplazarse
vy_ = 0.0f; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse
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
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
void MovingSprite::move()
{
if (enabled)
{
xPrev = x;
yPrev = y;
x_ += vx_;
y_ += vy_;
x += vx;
y += vy;
vx_ += ax_;
vy_ += ay_;
vx += ax;
vy += ay;
}
}
// Muestra el sprite por pantalla
void MovingSprite::render()
{
if (enabled)
{
texture->render((int)x, (int)y, &spriteClip, zoomW, zoomH, angle, center, currentFlip);
}
}
// Obtiene el valor de la variable
float MovingSprite::getPosX()
{
return x;
}
// Obtiene el valor de la variable
float MovingSprite::getPosY()
{
return y;
}
// Obtiene el valor de la variable
float MovingSprite::getVelX()
{
return vx;
}
// Obtiene el valor de la variable
float MovingSprite::getVelY()
{
return vy;
}
// Obtiene el valor de la variable
float MovingSprite::getAccelX()
{
return ax;
}
// Obtiene el valor de la variable
float MovingSprite::getAccelY()
{
return ay;
}
// Obtiene el valor de la variable
float MovingSprite::getZoomW()
{
return zoomW;
}
// Obtiene el valor de la variable
float MovingSprite::getZoomH()
{
return zoomH;
}
// Obtiene el valor de la variable
double MovingSprite::getAngle()
{
return angle;
}
// Establece la posición y el tamaño del objeto
void MovingSprite::setRect(SDL_Rect rect)
{
x = (float)rect.x;
y = (float)rect.y;
w = rect.w;
h = rect.h;
}
// Establece el valor de las variables
void MovingSprite::setPos(float x, float y)
{
this->x = x;
this->y = y;
}
// Establece el valor de la variable
void MovingSprite::setPosX(float value)
{
x = value;
}
// Establece el valor de la variable
void MovingSprite::setPosY(float value)
{
y = value;
}
// Establece el valor de la variable
void MovingSprite::setVelX(float value)
{
vx = value;
}
// Establece el valor de la variable
void MovingSprite::setVelY(float value)
{
vy = value;
}
// Establece el valor de la variable
void MovingSprite::setAccelX(float value)
{
ax = value;
}
// Establece el valor de la variable
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()
{
return rotateEnabled;
}
// Obtiene el valor de la variable
Uint16 MovingSprite::getRotateSpeed()
{
return rotateSpeed;
}
// Establece la rotacion
void MovingSprite::rotate()
{
if (enabled)
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)
{
if (value < 1)
{
rotateSpeed = 1;
}
else
{
rotateSpeed = 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;
pos_.x = static_cast<int>(x_);
pos_.y = static_cast<int>(y_);
}
// Actualiza las variables internas del objeto
@@ -298,71 +81,221 @@ void MovingSprite::update()
{
move();
rotate();
}
if (enabled)
// Muestra el sprite por pantalla
void MovingSprite::render()
{
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)
{
++counter %= 60000;
++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()
{
rotateAmount *= -1;
rotate_.amount *= -1;
}
// Establece el valor de la variable
void MovingSprite::setFlip(SDL_RendererFlip flip)
{
currentFlip = flip;
flip_ = flip;
}
// Gira el sprite horizontalmente
void MovingSprite::flip()
{
currentFlip = (currentFlip == SDL_FLIP_HORIZONTAL) ? SDL_FLIP_NONE : SDL_FLIP_HORIZONTAL;
flip_ = (flip_ == SDL_FLIP_HORIZONTAL) ? SDL_FLIP_NONE : SDL_FLIP_HORIZONTAL;
}
// Obtiene el valor de la variable
SDL_RendererFlip MovingSprite::getFlip()
{
return currentFlip;
return flip_;
}
// Devuelve el rectangulo donde está el sprite
SDL_Rect MovingSprite::getRect()
// Obtiene el valor de la variable
float MovingSprite::getPosX() const
{
const SDL_Rect rect = {(int)x, (int)y, w, h};
return rect;
return x_;
}
// Deshace el último movimiento
void MovingSprite::undoMove()
// Obtiene el valor de la variable
float MovingSprite::getPosY() const
{
x = xPrev;
y = yPrev;
return y_;
}
// Deshace el último movimiento en el eje X
void MovingSprite::undoMoveX()
// Obtiene el valor de la variable
float MovingSprite::getVelX() const
{
x = xPrev;
return vx_;
}
// Deshace el último movimiento en el eje Y
void MovingSprite::undoMoveY()
// Obtiene el valor de la variable
float MovingSprite::getVelY() const
{
y = yPrev;
return vy_;
}
// Pone a cero las velocidades de desplacamiento
void MovingSprite::clearVel()
// Obtiene el valor de la variable
float MovingSprite::getAccelX() const
{
vx = vy = 0.0f;
return ax_;
}
// Devuelve el incremento en el eje X en pixels
int MovingSprite::getIncX()
// Obtiene el valor de la variable
float MovingSprite::getAccelY() const
{
return (int)x - (int)xPrev;
return ay_;
}
// Establece la posición y_ el tamaño del objeto
void MovingSprite::setPos(SDL_Rect rect)
{
x_ = static_cast<float>(rect.x);
y_ = static_cast<float>(rect.y);
pos_ = rect;
}
// Establece el valor de las variables
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
void MovingSprite::setVelX(float value)
{
vx_ = value;
}
// Establece el valor de la variable
void MovingSprite::setVelY(float value)
{
vy_ = value;
}
// Establece el valor de la variable
void MovingSprite::setAccelX(float value)
{
ax_ = value;
}
// Establece el valor de la variable
void MovingSprite::setAccelY(float value)
{
ay_ = value;
}

View File

@@ -1,41 +1,45 @@
#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 "sprite.h" // for Sprite
#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
{
protected:
float x; // Posición en el eje X
float y; // Posición en el eje Y
float xPrev; // Posición anterior en el eje X
float yPrev; // Posición anterior en el eje Y
float vx; // Velocidad en el eje X. Cantidad de pixeles a desplazarse
float vy; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse
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
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, Texture *texture = nullptr);
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
float vx_; // Velocidad en el eje X. Cantidad de pixeles a desplazarse
float vy_; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse
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
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
// Incrementa el valor del ángulo
void updateAngle();
// Mueve el sprite
void move();
@@ -43,99 +47,62 @@ 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
float getPosX();
// Obtiene la variable
float getPosX() const;
float getPosY() const;
float getVelX() const;
float getVelY() const;
float getAccelX() const;
float getAccelY() const;
// Obten el valor de la variable
float getPosY();
// Obten el valor de la variable
float getVelX();
// Obten el valor de la variable
float getVelY();
// Obten el valor de la variable
float getAccelX();
// Obten el valor de la variable
float getAccelY();
// Obten el valor de la variable
float getZoomW();
// Obten el valor de la variable
float getZoomH();
// Obten el valor de la variable
double getAngle();
// Obtiene el valor de la variable
bool getRotate();
// Obtiene el valor de la variable
Uint16 getRotateSpeed();
// 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);
// Establece el valor de la variable
void setPosY(float value);
// Establece el valor de la variable
// Establece la variable
void setVelX(float value);
// Establece el valor de la variable
void setVelY(float value);
// Establece el valor de la variable
void setAccelX(float value);
// Establece el valor de la variable
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;
int getRotateSpeed() const;
// Establece el valor de la variable
void setZoomW(float value);
// Establece el valor de la variable
void setZoomH(float value);
// Establece el valor de la variable
void setAngle(double vaue);
// Incrementa el valor de la variable
void incAngle(double value);
// Decrementa el valor de la variable
void decAngle(double value);
// Establece el valor de la variable
void setRotate(bool value);
// Activa o desactiva el efecto derotación
void enableRotate();
void disableRotate();
// Establece el valor de la variable
void setRotateSpeed(int value);
// Establece el valor de la variable
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();
@@ -148,21 +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);
// Deshace el último movimiento
void undoMove();
// Establece el valor de las variables
void setPos(float x, float y);
// Deshace el último movimiento en el eje X
void undoMoveX();
// Establece el valor de la variable
void setPosX(float value);
// Deshace el último movimiento en el eje Y
void undoMoveY();
// Pone a cero las velocidades de desplacamiento
void clearVel();
// Devuelve el incremento en el eje X en pixels
int getIncX();
// 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;
}

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