Compare commits

72 Commits

Author SHA1 Message Date
84595da13a EnterName: si has plenat tots els slots de lletres, apretar una volta mes el de fixar lletra fixa el nom 2025-02-07 14:15:18 +01:00
01591175ef Pos pense que ja està tot apanyat lo de EnterName i Scoreboard 2025-02-07 13:45:07 +01:00
29bc4a64fd Afegit position_overflow_ per a EnterName i poder plenar tots els slots de lletres 2025-02-07 12:31:59 +01:00
559210652f Treballant en scoreboard::fillPanelTextures 2025-02-06 20:58:15 +01:00
44e4ca490d canvi de pc
treballant en enter name
2025-02-06 14:59:25 +01:00
3cebee2ae4 Implementat control de repetició per als eixos del joystick 2025-02-06 12:36:16 +01:00
270d7d1848 Duplicada la font 04b_25 per a tindre versió gris i versió negra. La gris es la que es por modular amb colors.
Eliminada la font nokia que ja no s'estava utilitzant.
Optimitzada la càrrega de fonts al permetre reutilitzar fitxers .txt de altres fonts
2025-02-06 10:31:32 +01:00
ccf005dce1 Afegit el disparador per a la aparició del enemic nou 2025-02-06 09:59:58 +01:00
5755947ff7 La tabla de puntuació ja mostra amb altre color la puntuació que s'acaba d'afegir
fix: la tabla de punts no guardava a disc el estat de 1CC de cada entrada
2025-02-05 22:52:19 +01:00
6f594b9a1f La tabla de puntuacions ja mostra aquelles aconseguides amb 1CC 2025-02-05 15:15:48 +01:00
7e2021da70 canvi de pc 2025-02-05 10:17:49 +01:00
0a9a92d4b7 El text de la tabla de puntuacion ja ix centrat i el "diferent" es el que fa 10 2025-02-05 09:45:30 +01:00
b01763b749 Dels credits ja passa a la tabla de puntuacions 2025-01-26 21:15:13 +01:00
59b9f61d69 Font nova per a la intro 2025-01-26 21:05:43 +01:00
b9f194a2b1 Afegit efecte d'eixida a les instruccions 2025-01-26 20:16:43 +01:00
59936f13eb Arreglos estetics i de colorets en hiscore_table.cpp 2025-01-26 17:48:10 +01:00
bad0a10328 Ja es mouen els sprites en hiscore_table.cpp, falta decidir-se per un disseny concret 2025-01-25 22:57:49 +01:00
52a0c2b91f Treballant en la nova tabla de records: ja pinta amb sprites 2025-01-25 21:17:45 +01:00
f12a456017 Alguns arreglos en updateTimeStopped() 2025-01-25 18:51:39 +01:00
f39e65afaf Ja no se que he tocat i qué no, cosetes del malo nou 2025-01-25 18:47:06 +01:00
d3183237df Estandaritzats els noms dels fitxers de audio
Eliminat el soroll de TNT que feia ANYS que no existía
2025-01-25 18:15:49 +01:00
60302004f4 Afegits efectes de audio nous
Retocats alguns efectes de audio al afagar items per a no solapar dos audios
2025-01-25 18:11:24 +01:00
e60938cb19 El malo nou ja suca cosetes, falta ajustar un poc els paràmetres 2025-01-25 17:41:45 +01:00
2b3cc719ba Fix del fix: aaaara si que lleva el garbage de la zona negra. Havia posat el clean() on no tocava 2025-01-25 13:14:25 +01:00
d01c91ebde Fix: m'havia carregat el shakeEffect() de la pantalla quan havia shaders, i de paso he vist que el que tenbia fet shakejava també les notificacions i els menus de debug. Ale, ja està tot arreglaet.
Fix: tampoc estava netejant la pantalla, pensava que no feia falta, pero quan SDL replena de negre la finestra en pantalla completa, havia gorrinades
2025-01-24 20:20:50 +01:00
7130f2298a Merge branch 'main' of https://gitea.sustancia.synology.me/JailDesigner/coffee_crisis_arcade_edition 2025-01-24 10:44:58 +01:00
380cc17861 Fix: ara apaga el sistem al final del tot, almenys quan ja ha escrit la configuració a disc 2025-01-24 10:43:00 +01:00
a5388873e3 Actualizar README.md 2025-01-05 15:47:51 +01:00
28b37af31d Actualitzada la data de la versió 2025-01-05 14:38:48 +01:00
4d590f79f5 fix: es podia pulsar per a jugar mentre feia el fade cap a la demo 2025-01-05 14:36:38 +01:00
91c8797d7f Screen: optimitzat el circuit de render en pantalla 2025-01-05 14:17:49 +01:00
f207985180 Retocs en el punter del ratolí per al mode ARCADE 2025-01-05 13:44:10 +01:00
a16131335b hi_score_table: actualitzat el fondo amb els elements nous 2025-01-05 13:41:09 +01:00
871e8da642 Corregit el timing de la música en la animació inicial del joc 2025-01-05 13:27:45 +01:00
90b3db8f06 El atenuat de pantalla torna a funcionar. Fade feia dos SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE); que mai tornava a restaurar 2025-01-05 13:07:20 +01:00
668e8e237a Actualitzat README.md 2025-01-05 12:52:14 +01:00
768f466b20 canviat blit() per render() 2025-01-05 10:45:05 +01:00
1f8f9b11ed Segona pasaeta de IWYU 2025-01-05 10:36:17 +01:00
39f61884b0 Pasaeta de IWYU 2025-01-05 10:22:20 +01:00
b1193bd8fd fix: error en la seqüència final de retrocedir en el temps 2025-01-05 09:51:33 +01:00
7f9e2e53e3 Optimitzat el renderitzat dels credits 2025-01-05 09:44:08 +01:00
4cf4c8db6f fix: arreglada la acceleració dels credits sense dependre de vsync 2025-01-05 09:31:57 +01:00
cd806363e8 Modificat el color dels nuvols de la última pantalla
debug: opció de no crear mes globos
2025-01-05 09:22:30 +01:00
198aa45d59 Afegida una lluna i un sol al fondo 2025-01-05 07:32:30 +01:00
0711c8dada fix: al fer el init de stage no es buidava el vector i cada volta afegia mes stages 2025-01-05 07:29:33 +01:00
e1aaad0903 fix: Havia deixat comentat un IF fent proves 2025-01-04 17:01:24 +01:00
b53ee12f56 La powerball ja no es pot destruir fins que no ha fet un rebot 2025-01-04 16:57:50 +01:00
7b6d429bed fix: un vuelo rasante havia trencat els credits 2025-01-04 14:27:37 +01:00
81ee352553 Afegit un lock per evitar que es puga incrementar el poder de la fase
Es necesita almenys un jugador viu per a poder incrementar el poder de la fase
2025-01-04 14:09:10 +01:00
7b8f16610a Afegits estats al fade
Afegida opció de prefade
El modo demo ja comença a meitat del "meollo"
2025-01-04 13:40:22 +01:00
06eb05f065 Canviat un poc el color del segon cel 2025-01-04 12:44:24 +01:00
bccf4c30de Modificada la cadencia de foc sense autofire i arreglades un poc les animacions de cool_down i cooling 2025-01-04 10:47:26 +01:00
5e817ef1d0 Afegit el tamany de la coffee_machine als parametres 2025-01-04 10:04:49 +01:00
eaab646cd3 Modificades les paletes de invulnerabilitat 2025-01-04 09:21:58 +01:00
e887c2a2ab Afegida la opció de crear els globos sense temps de creació en el balloon_manager
Modificat el mode demo per a que la primera oleada estiga ja creada
2025-01-04 00:42:57 +01:00
f573bd02ac El case de les variables en mouse.cpp i mouse.h era incorrecte 2025-01-03 23:57:45 +01:00
b586a117c8 Afegit mouse.cpp per amagar el cursor quan no està moventse 2025-01-03 23:35:48 +01:00
08dfaf7641 Errors tipografics en varios comentaris 2025-01-03 22:48:45 +01:00
ff7f5ea131 Modificada la seqëncia d'inici per a que la musica començe antes 2025-01-03 22:13:46 +01:00
7cc4a2002a Modificat el copyright de 2024 a 2025 2025-01-03 22:04:29 +01:00
de81b798b0 Afegit custom fadeout de so sincronitzat amb el fadeout de video per a quan acaba la partida 2025-01-03 22:02:48 +01:00
5669715285 Input mostra també el numero de joysticks que ha trobat 2025-01-03 21:29:22 +01:00
6531106933 Quedaven mes SDL_Log en jail_audio 2025-01-03 21:28:55 +01:00
51191b1906 Eliminat SDL_Log 2025-01-03 21:21:52 +01:00
6effeb6154 Quan el jugador moria podia quedarse engantxat rebotant en les vores
So aleatori en els rebots del jugador al morir
2025-01-03 20:36:18 +01:00
8c2b1ce649 Separats els estats de joc completat i joc acabat del estat joc jugantse
Al completar el joc, el missatge de game over ja no ix fins que desapareixen els textos anteriors
2025-01-03 19:53:09 +01:00
cc4acecc03 Afegits sons de caminar i de comptador de continuar
Afegits estats al joc i al jugador per a escenificar el inici de la partida
2025-01-03 19:19:22 +01:00
40dfc32e84 Actualitzada la data de la versió 2024-12-31 10:23:01 +01:00
4cd1d91560 Actualitzat jail_audio 2024-12-30 20:08:08 +01:00
e43badd703 Merge branch 'main' of https://gitea.sustancia.synology.me/JailDesigner/coffee_crisis_arcade_edition 2024-12-30 20:06:04 +01:00
71dcf9cf87 Afegit coffee.res, coffee.rc i icon.ico per a tindre iconet en windows 2024-12-30 19:56:35 +01:00
3a8521a1da Arreglat windows_release en Makefile 2024-12-30 19:56:00 +01:00
108 changed files with 2842 additions and 1440 deletions

View File

@@ -10,10 +10,11 @@ TARGET_FILE := $(DIR_BIN)$(TARGET_NAME)
APP_NAME := Coffee Crisis Arcade Edition APP_NAME := Coffee Crisis Arcade Edition
RELEASE_FOLDER := ccae_release RELEASE_FOLDER := ccae_release
RELEASE_FILE := $(RELEASE_FOLDER)/$(TARGET_NAME) RELEASE_FILE := $(RELEASE_FOLDER)/$(TARGET_NAME)
VERSION := 2024-12-30 RESOURCE_FILE := release/coffee.res
VERSION := 2025-02-07
# Nombres para los ficheros de lanzamiento # Nombres para los ficheros de lanzamiento
WINDOWS_RELEASE := $(TARGET_FILE)-$(VERSION)-win32-x64.zip WINDOWS_RELEASE := $(TARGET_NAME)-$(VERSION)-win32-x64.zip
MACOS_INTEL_RELEASE := $(TARGET_FILE)-$(VERSION)-macos-intel.dmg MACOS_INTEL_RELEASE := $(TARGET_FILE)-$(VERSION)-macos-intel.dmg
MACOS_APPLE_SILICON_RELEASE := $(TARGET_FILE)-$(VERSION)-macos-apple-silicon.dmg MACOS_APPLE_SILICON_RELEASE := $(TARGET_FILE)-$(VERSION)-macos-apple-silicon.dmg
LINUX_RELEASE := $(TARGET_FILE)-$(VERSION)-linux.tar.gz LINUX_RELEASE := $(TARGET_FILE)-$(VERSION)-linux.tar.gz
@@ -55,7 +56,8 @@ endif
# Reglas para compilación # Reglas para compilación
windows: windows:
@echo off @echo off
$(CXX) $(SOURCES) $(CXXFLAGS) $(LDFLAGS) -o "$(TARGET_FILE).exe" windres release/coffee.rc -O coff -o $(RESOURCE_FILE)
$(CXX) $(SOURCES) $(RESOURCE_FILE) $(CXXFLAGS) $(LDFLAGS) -o "$(TARGET_FILE).exe"
strip -s -R .comment -R .gnu.version "$(TARGET_FILE).exe" --strip-unneeded strip -s -R .comment -R .gnu.version "$(TARGET_FILE).exe" --strip-unneeded
windows_rec: windows_rec:
@@ -82,7 +84,8 @@ windows_release:
powershell Copy-Item "release\*.dll" -Destination "$(RELEASE_FOLDER)" powershell Copy-Item "release\*.dll" -Destination "$(RELEASE_FOLDER)"
# Compila # Compila
$(CXX) $(SOURCES) $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FILE).exe" windres release/coffee.rc -O coff -o $(RESOURCE_FILE)
$(CXX) $(SOURCES) $(RESOURCE_FILE) $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FILE).exe"
strip -s -R .comment -R .gnu.version "$(RELEASE_FILE).exe" --strip-unneeded strip -s -R .comment -R .gnu.version "$(RELEASE_FILE).exe" --strip-unneeded
# Crea el fichero .zip # Crea el fichero .zip

View File

@@ -1,45 +1,73 @@
# Coffee Crisis Arcade Edition # Coffee Crisis Arcade Edition
Coffee Crisis Arcade Edition es la versió ampliada i millorada del aclamat Coffee Crisis. Preparat per a jugar sense parar amn dos jugadors, nous gràfics i moltes sorpreses mes. **¡La batalla definitiva pel cafè està ací!**
Coffee Crisis Arcade Edition és una versió ampliada i millorada del aclamat Coffee Crisis. Aquesta versió porta l'acció cooperativa al següent nivell, amb:
- **Mode multijugador** per a dues persones.
- **Nous gràfics** que revitalitzen l'experiència arcade clàssica.
- **Moltes sorpreses** per descobrir en cada partida.
Defensa el teu cafè contra les bambolles gegants en aquest trepidant joc d'arcade! 🍵
<p align="center"> <p align="center">
<img src="https://php.sustancia.synology.me/images/ccae_title.png" alt="Titol" <img src="https://php.sustancia.synology.me/images/ccae_title.png" alt="Títol" width="60%" />
</p> </p>
## Controls ## Controls
El joc està optimitzat per a ser jugat amb un mando de jocs, encara que un dels jugadors pot utilitzar el teclat.
Les tecles son les següents:
* **Fletxes**: Mou al personatge El joc està optimitzat per a ser jugat amb un mando de jocs, encara que un dels jugadors pot utilitzar el teclat.
* **Q, W, E**: Disparar a la esquerra, al centre i a la dreta respectivament
### Controls del teclat:
- **Fletxes**: Mou al personatge.
- **Q, W, E**: Disparar a l'esquerra, al centre i a la dreta, respectivament.
> Nota: El joc suporta nomes un jugador amb teclat.
<p align="center"> <p align="center">
<img src="https://php.sustancia.synology.me/images/ccae1.png" alt="Joc" <img src="https://php.sustancia.synology.me/images/ccae1.png" alt="Joc" width="45%" />
<img src="https://php.sustancia.synology.me/images/ccae3.png" alt="Joc" width="45%" />
</p> </p>
## Altres tecles ## Altres tecles
- **Tecla ESC**: Tancar el joc
- **Tecla F1**: Fa la finestra mes xicoteta | Tecla | Funció |
|-------------|----------------------------------------------|
- **Tecla F2**: Fa la finestra mes gran | **ESC** | Tancar el joc |
| **F1** | Fa la finestra més xicoteta |
- **Tecla F3**: Alterna entre el mode de pantalla completa i el de finestra | **F2** | Fa la finestra més gran |
| **F3** | Alterna entre mode de pantalla completa i finestra |
- **Tecla F4**: Activa o desactiva els shaders | **F4** | Activa o desactiva els shaders |
| **F5** | Activa o desactiva l'àudio |
- **Tecla F5**: Activa o desactiva l'audio | **F6** | Activa o desactiva el dispar automàtic |
| **F7** | Canvia l'idioma del joc i reinicia |
- **Tecla F6**: Activa o desactiva el dispar automàtic | **F10** | Reset del joc |
- **Tecla F7**: Canvia el idioma del joc i reinicia
- **Tecla F10**: Reset
<p align="center"> <p align="center">
<img src="https://php.sustancia.synology.me/images/ccae2.png" alt="Joc" <img src="https://php.sustancia.synology.me/images/ccae2.png" alt="Joc" width="50%" />
</p> </p>
## Com instal·lar i jugar
1. Descarrega el joc des de [l'apartat de llançaments](https://gitea.sustancia.synology.me/JailDesigner/coffee_crisis_arcade_edition/releases).
2. Descomprimix i executa l'arxiu `coffee_crisis_arcade_edition.exe`.
3. Gaudeix del joc!
## Agraïments
Vull expressar la meua gratitud a **ChatGPT** i **GitHub Copilot**. Gràcies per ser un suport constant en el desenvolupament d'aquest joc!
També vull agrair a tots els jugadors que fan que aquest projecte valgui la pena. 🕹️❤️
## Com contribuir
Accepte contribucions! Si tens una idea o vols ajudar:
1. Fes un fork d'aquest repositori.
2. Crea una branca nova amb els teus canvis.
3. Fes un pull request.
## Llicència
Aquest joc està subjecte a una llicència [MIT](https://opensource.org/licenses/MIT). Consulta el fitxer LICENSE per a més detalls.
## Agraiments
A chatGPT i sobretot a Copilot. Gracies per estar sempre quan vos he necesitat.

View File

@@ -1,5 +1,7 @@
## GAME ## GAME
game.item_size 20 # Tamaño de los items del juego game.item_size 20 # Tamaño de los items del juego
game.coffee_machine_w 28 # Ancho de la máquina de café
game.coffee_machine_h 37 # Alto de la máquina de café
game.width 320 # Ancho de la resolucion nativa del juego game.width 320 # Ancho de la resolucion nativa del juego
game.height 240 # Alto 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.x 0 # Rectangulo con la posición de la zona de juego

View File

@@ -1,5 +1,7 @@
## GAME ## GAME
game.item_size 20 # Tamaño de los items del juego game.item_size 20 # Tamaño de los items del juego
game.coffee_machine_w 28 # Ancho de la máquina de café
game.coffee_machine_h 37 # Alto de la máquina de café
game.width 320 # Ancho de la resolucion nativa del juego game.width 320 # Ancho de la resolucion nativa del juego
game.height 256 # Alto 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.x 0 # Rectangulo con la posición de la zona de juego

BIN
data/font/04b_25_grey.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
data/font/04b_25_metal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,9 +1,9 @@
frame_width=46 frame_width=49
frame_height=46 frame_height=49
[animation] [animation]
name=powerball name=powerball
speed=10 speed=10
loop=-1 loop=-1
frames=0 frames=1
[/animation] [/animation]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

BIN
data/gfx/game/game_moon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
data/gfx/game/game_sun.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@@ -0,0 +1,9 @@
frame_width=20
frame_height=20
[animation]
name=default
speed=10
loop=0
frames=0,1
[/animation]

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

View File

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 173 B

View File

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 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: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

View File

@@ -2,8 +2,15 @@ frame_width=32
frame_height=32 frame_height=32
[animation] [animation]
name=default name=fly
speed=2 speed=2
loop=0 loop=0
frames=0,1 frames=0,1
[/animation] [/animation]
[animation]
name=hit
speed=2
loop=0
frames=2,3
[/animation]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

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

Binary file not shown.

BIN
data/sound/debian_drop.wav Normal file

Binary file not shown.

Binary file not shown.

BIN
data/sound/tabe_hit.wav Normal file

Binary file not shown.

Binary file not shown.

BIN
data/sound/walk.wav Normal file

Binary file not shown.

2
release/coffee.rc Normal file
View File

@@ -0,0 +1,2 @@
// coffee.rc
IDI_ICON1 ICON "icon.ico"

BIN
release/coffee.res Normal file

Binary file not shown.

BIN
release/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -2,6 +2,7 @@
#include <SDL2/SDL_blendmode.h> // Para SDL_BLENDMODE_BLEND #include <SDL2/SDL_blendmode.h> // Para SDL_BLENDMODE_BLEND
#include <SDL2/SDL_pixels.h> // Para SDL_PIXELFORMAT_RGBA8888 #include <SDL2/SDL_pixels.h> // Para SDL_PIXELFORMAT_RGBA8888
#include <algorithm> // Para clamp, max #include <algorithm> // Para clamp, max
#include <cmath>
#include "moving_sprite.h" // Para MovingSprite #include "moving_sprite.h" // Para MovingSprite
#include "param.h" // Para Param, ParamBackground, param #include "param.h" // Para Param, ParamBackground, param
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
@@ -18,16 +19,22 @@ Background::Background()
bottom_clouds_texture_(Resource::get()->getTexture("game_clouds2.png")), bottom_clouds_texture_(Resource::get()->getTexture("game_clouds2.png")),
grass_texture_(Resource::get()->getTexture("game_grass.png")), grass_texture_(Resource::get()->getTexture("game_grass.png")),
gradients_texture_(Resource::get()->getTexture("game_sky_colors.png")), gradients_texture_(Resource::get()->getTexture("game_sky_colors.png")),
sun_texture_(Resource::get()->getTexture("game_sun.png")),
moon_texture_(Resource::get()->getTexture("game_moon.png")),
rect_({0, 0, gradients_texture_->getWidth() / 2, gradients_texture_->getHeight() / 2}), rect_({0, 0, gradients_texture_->getWidth() / 2, gradients_texture_->getHeight() / 2}),
src_rect_({0, 0, 320, 240}), src_rect_({0, 0, 320, 240}),
dst_rect_({0, 0, 320, 240}), dst_rect_({0, 0, 320, 240}),
base_(rect_.h), base_(rect_.h),
color_(Color(param.background.attenuate_color.r, param.background.attenuate_color.g, param.background.attenuate_color.b)), attenuate_color_(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_(param.background.attenuate_alpha),
alpha_color_text_temp_(param.background.attenuate_alpha) alpha_color_text_temp_(param.background.attenuate_alpha)
{ {
// Precalcula rutas
createSunPath();
createMoonPath();
// Inicializa variables // Inicializa variables
{ {
gradient_rect_[0] = {0, 0, rect_.w, rect_.h}; gradient_rect_[0] = {0, 0, rect_.w, rect_.h};
@@ -55,9 +62,11 @@ Background::Background()
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_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()}); 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()); buildings_sprite_ = std::make_unique<Sprite>(buildings_texture_);
gradient_sprite_ = std::make_unique<Sprite>(gradients_texture_, 0, 0, rect_.w, rect_.h); 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); grass_sprite_ = std::make_unique<Sprite>(grass_texture_, 0, 0, grass_texture_->getWidth(), grass_texture_->getHeight() / 2);
sun_sprite_ = std::make_unique<Sprite>(sun_texture_);
moon_sprite_ = std::make_unique<Sprite>(moon_texture_);
} }
// Inicializa objetos // Inicializa objetos
@@ -79,6 +88,8 @@ Background::Background()
buildings_sprite_->setY(base_ - buildings_sprite_->getHeight()); buildings_sprite_->setY(base_ - buildings_sprite_->getHeight());
grass_sprite_->setY(base_ - grass_sprite_->getHeight()); grass_sprite_->setY(base_ - grass_sprite_->getHeight());
sun_sprite_->setPosition(sun_path_.front());
moon_sprite_->setPosition(moon_path_.front());
} }
// Crea la textura para componer el fondo // Crea la textura para componer el fondo
@@ -88,7 +99,7 @@ Background::Background()
// Crea la textura para atenuar el fondo // Crea la textura para atenuar el fondo
color_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h); color_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h);
SDL_SetTextureBlendMode(color_texture_, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(color_texture_, SDL_BLENDMODE_BLEND);
setColor(color_); setColor(attenuate_color_);
SDL_SetTextureAlphaMod(color_texture_, alpha_color_text_); SDL_SetTextureAlphaMod(color_texture_, alpha_color_text_);
} }
@@ -103,7 +114,7 @@ Background::~Background()
void Background::update() void Background::update()
{ {
// Actualiza el valor de alpha_ // Actualiza el valor de alpha_
updateAlphaColorText(); updateAlphaColorTexture();
// Actualiza las nubes // Actualiza las nubes
updateClouds(); updateClouds();
@@ -114,6 +125,10 @@ void Background::update()
// Calcula el valor de alpha_ // Calcula el valor de alpha_
alpha_ = std::max((255 - (int)(255 * transition_)), 0); alpha_ = std::max((255 - (int)(255 * transition_)), 0);
// Mueve el sol
sun_sprite_->setPosition(sun_path_.at(sun_index_));
moon_sprite_->setPosition(moon_path_.at(moon_index_));
// Incrementa el contador // Incrementa el contador
++counter_; ++counter_;
@@ -181,6 +196,10 @@ void Background::fillCanvas()
// Dibuja el gradiente de fondo // Dibuja el gradiente de fondo
renderGradient(); renderGradient();
// Dibuja los astros
sun_sprite_->render();
moon_sprite_->render();
// Dibuja las nubes de arriba // Dibuja las nubes de arriba
renderTopClouds(); renderTopClouds();
@@ -250,13 +269,13 @@ void Background::setPos(SDL_Rect pos)
// Establece el color_ de atenuación // Establece el color_ de atenuación
void Background::setColor(Color color) void Background::setColor(Color color)
{ {
color_ = color; attenuate_color_ = color;
// Colorea la textura // Colorea la textura
auto temp = SDL_GetRenderTarget(renderer_); auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, color_texture_); SDL_SetRenderTarget(renderer_, color_texture_);
SDL_SetRenderDrawColor(renderer_, color_.r, color_.g, color_.b, 255); SDL_SetRenderDrawColor(renderer_, attenuate_color_.r, attenuate_color_.g, attenuate_color_.b, 255);
SDL_RenderClear(renderer_); SDL_RenderClear(renderer_);
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
@@ -274,7 +293,7 @@ void Background::setAlpha(int alpha)
} }
// Actualiza el valor de alpha_ // Actualiza el valor de alpha_
void Background::updateAlphaColorText() void Background::updateAlphaColorTexture()
{ {
if (alpha_color_text_ == alpha_color_text_temp_) if (alpha_color_text_ == alpha_color_text_temp_)
{ {
@@ -323,3 +342,57 @@ void Background::updateClouds()
bottom_clouds_sprite_b_->setPosX(bottom_clouds_sprite_b_->getWidth()); bottom_clouds_sprite_b_->setPosX(bottom_clouds_sprite_b_->getWidth());
} }
} }
// Precalcula el vector con el recorrido del sol
void Background::createSunPath()
{
constexpr int CENTER_X = 170;
const int center_y = base_ - 80;
constexpr int RADIUS = 120;
// Generar puntos de la curva desde 90 a 180 grados
for (double theta = M_PI / 2; theta <= M_PI; theta += 0.01)
{
int x = CENTER_X + static_cast<int>(RADIUS * cos(theta));
int y = center_y - static_cast<int>(RADIUS * sin(theta));
sun_path_.push_back({x, y});
}
// Agregar puntos en línea recta después de la curva
constexpr int EXTRA_PIXELS = 40;
SDL_Point last_point = sun_path_.back();
for (int i = 1; i <= EXTRA_PIXELS; ++i)
{
sun_path_.push_back({last_point.x, last_point.y + i});
}
}
// Precalcula el vector con el recorrido de la luna
void Background::createMoonPath()
{
constexpr int CENTER_X = 100;
const int center_y = base_ - 50;
constexpr int RADIUS = 140;
// Generar puntos de la curva desde 0 a 90 grados
for (double theta = 0; theta <= M_PI / 2; theta += 0.01)
{
int x = CENTER_X + static_cast<int>(RADIUS * cos(theta));
int y = center_y - static_cast<int>(RADIUS * sin(theta));
moon_path_.push_back({x, y});
}
}
// Establece la posición del sol
void Background::setSunProgression(float progress)
{
progress = std::clamp(progress, 0.0f, 1.0f);
sun_index_ = static_cast<size_t>(progress * (sun_path_.size() - 1));
}
// Establece la posición de la luna
void Background::setMoonProgression(float progress)
{
progress = std::clamp(progress, 0.0f, 1.0f);
moon_index_ = static_cast<size_t>(progress * (moon_path_.size() - 1));
}

View File

@@ -1,12 +1,14 @@
#pragma once #pragma once
#include <SDL2/SDL_rect.h> // para SDL_Rect #include <SDL2/SDL_rect.h> // Para SDL_Rect, SDL_Point
#include <SDL2/SDL_render.h> // para SDL_Renderer, SDL_Texture #include <SDL2/SDL_render.h> // Para SDL_Texture, SDL_Renderer
#include <memory> // para unique_ptr, shared_ptr #include <stddef.h> // Para size_t
#include "utils.h" // para Color #include <memory> // Para unique_ptr, shared_ptr
class MovingSprite; #include <vector> // Para vector
class Sprite; #include "utils.h" // Para Color
class Texture; class MovingSprite; // lines 7-7
class Sprite; // lines 8-8
class Texture; // lines 9-9
/* /*
Esta clase es la encargada de dibujar el fondo que aparece durante la sección Esta clase es la encargada de dibujar el fondo que aparece durante la sección
@@ -51,6 +53,8 @@ private:
std::shared_ptr<Texture> bottom_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> grass_texture_; // Textura con la hierba del suelo
std::shared_ptr<Texture> gradients_texture_; // Textura con los diferentes colores de fondo del juego std::shared_ptr<Texture> gradients_texture_; // Textura con los diferentes colores de fondo del juego
std::shared_ptr<Texture> sun_texture_; // Textura con el sol
std::shared_ptr<Texture> moon_texture_; // Textura con la luna
std::unique_ptr<MovingSprite> top_clouds_sprite_a_; // Sprite para las nubes superiores 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> top_clouds_sprite_b_; // Sprite para las nubes superiores
@@ -60,6 +64,8 @@ private:
std::unique_ptr<Sprite> buildings_sprite_; // Sprite con los edificios de fondo 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> gradient_sprite_; // Sprite con los graficos del degradado de color de fondo
std::unique_ptr<Sprite> grass_sprite_; // Sprite para la hierba std::unique_ptr<Sprite> grass_sprite_; // Sprite para la hierba
std::unique_ptr<Sprite> sun_sprite_; // Sprite para el sol
std::unique_ptr<Sprite> moon_sprite_; // Sprite para la luna
SDL_Texture *canvas_; // Textura para componer el fondo SDL_Texture *canvas_; // Textura para componer el fondo
SDL_Texture *color_texture_; // Textura para atenuar el fondo SDL_Texture *color_texture_; // Textura para atenuar el fondo
@@ -77,9 +83,13 @@ private:
SDL_Rect src_rect_; // Parte del objeto fondo que se va a dibujará en pantalla 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 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 int base_; // Linea de fondo coincidente con el area inferior de la zona de juego
Color color_; // Color para atenuar el fondo Color attenuate_color_; // Color para atenuar el fondo
int alpha_color_text_; // Alpha 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 int alpha_color_text_temp_; // Valor temporal para hacer la transición de alpha
std::vector<SDL_Point> sun_path_; // Vector con el recorrido del sol
std::vector<SDL_Point> moon_path_; // Vector con el recorrido de la luna
size_t sun_index_ = 0; // Posición del vector del recorrido del sol
size_t moon_index_ = 0; // Posición del vector del recorrido de la luna
// Dibuja el gradiente de fondo // Dibuja el gradiente de fondo
void renderGradient(); void renderGradient();
@@ -94,11 +104,17 @@ private:
void fillCanvas(); void fillCanvas();
// Actualiza el valor de alpha // Actualiza el valor de alpha
void updateAlphaColorText(); void updateAlphaColorTexture();
// Actualiza las nubes // Actualiza las nubes
void updateClouds(); void updateClouds();
// Precalcula el vector con el recorrido del sol
void createSunPath();
// Precalcula el vector con el recorrido de la luna
void createMoonPath();
public: public:
// Constructor // Constructor
Background(); Background();
@@ -132,4 +148,10 @@ public:
// Establece la transparencia de la atenuación // Establece la transparencia de la atenuación
void setAlpha(int alpha); void setAlpha(int alpha);
// Establece la posición del sol
void setSunProgression(float progress);
// Establece la posición de la luna
void setMoonProgression(float progress);
}; };

View File

@@ -107,16 +107,28 @@ void Balloon::render()
{ {
if (type_ == BalloonType::POWERBALL) if (type_ == BalloonType::POWERBALL)
{ {
// Renderizado para la PowerBall // Renderiza el fondo azul
{
auto sp = std::make_unique<Sprite>(sprite_->getTexture(), sprite_->getPosition());
sp->setSpriteClip(0, 0, BALLOON_SIZE[4], BALLOON_SIZE[4]);
sp->render();
}
// Renderiza la estrella
if (!invulnerable_)
{
SDL_Point p = {24, 24}; SDL_Point p = {24, 24};
sprite_->setRotatingCenter(&p); sprite_->setRotatingCenter(&p);
sprite_->render(); sprite_->render();
}
// Añade la máscara del borde y los reflejos // Añade la máscara del borde y los reflejos
{
auto sp = std::make_unique<Sprite>(sprite_->getTexture(), sprite_->getPosition()); auto sp = std::make_unique<Sprite>(sprite_->getTexture(), sprite_->getPosition());
sp->setSpriteClip(BALLOON_SIZE[4], 0, BALLOON_SIZE[4], BALLOON_SIZE[4]); sp->setSpriteClip(BALLOON_SIZE[4] * 2, 0, BALLOON_SIZE[4], BALLOON_SIZE[4]);
sp->render(); sp->render();
} }
}
else else
{ {
// Renderizado para el resto de globos // Renderizado para el resto de globos
@@ -167,18 +179,6 @@ void Balloon::move()
// Mueve el globo en vertical // Mueve el globo en vertical
y_ += vy_ * speed_; y_ += vy_ * speed_;
// Colisión en la parte superior de la zona de juego excepto para la PowerBall
/*if (type_ != BalloonType::POWERBALL)
{
const int min_y = play_area_.y;
if (y_ < min_y)
{
y_ = min_y;
vy_ = -vy_;
enableBounce();
}
}*/
// Colisión en la parte superior solo si el globo va de subida // Colisión en la parte superior solo si el globo va de subida
if (vy_ < 0) if (vy_ < 0)
{ {
@@ -203,6 +203,10 @@ void Balloon::move()
{ {
enableBounce(); enableBounce();
} }
else
{
setInvulnerable(false);
}
} }
/* /*
@@ -229,12 +233,6 @@ void Balloon::move()
} }
} }
// Deshabilita el globo
void Balloon::disable() { enabled_ = false; }
// Explosiona el globo
void Balloon::pop() { disable(); }
// Actualiza al globo a su posicion, animación y controla los contadores // Actualiza al globo a su posicion, animación y controla los contadores
void Balloon::update() void Balloon::update()
{ {

View File

@@ -170,12 +170,6 @@ public:
// Actualiza la posición y estados del globo // Actualiza la posición y estados del globo
void move(); void move();
// Deshabilita el globo y pone a cero todos los valores
void disable();
// Explosiona el globo
void pop();
// Actualiza al globo a su posicion, animación y controla los contadores // Actualiza al globo a su posicion, animación y controla los contadores
void update(); void update();
@@ -215,4 +209,5 @@ public:
void setSpeed(float speed) { speed_ = speed; } void setSpeed(float speed) { speed_ = speed; }
void setInvulnerable(bool value) { invulnerable_ = value; } void setInvulnerable(bool value) { invulnerable_ = value; }
void setSound(bool value) { sound_enabled_ = value; } void setSound(bool value) { sound_enabled_ = value; }
void disable() { enabled_ = false; }
}; };

View File

@@ -107,11 +107,18 @@ void BalloonManager::deployBalloonFormation(int stage)
last_balloon_deploy_ = formation; last_balloon_deploy_ = formation;
const auto set = balloon_formations_->getSet(stage, formation); const auto set = balloon_formations_->getSet(stage, formation);
const auto numEnemies = set.number_of_balloons; const auto num_enemies = set.number_of_balloons;
for (int i = 0; i < numEnemies; ++i) for (int i = 0; i < num_enemies; ++i)
{ {
auto p = set.init[i]; auto p = set.init[i];
createBalloon(p.x, p.y, p.type, p.size, p.vel_x, balloon_speed_, p.creation_counter); createBalloon(
p.x,
p.y,
p.type,
p.size,
p.vel_x,
balloon_speed_,
(creation_time_enabled_) ? p.creation_counter : 0);
} }
balloon_deploy_counter_ = 300; balloon_deploy_counter_ = 300;
@@ -123,8 +130,8 @@ void BalloonManager::deployBalloonFormation(int stage)
void BalloonManager::deploySet(int set_number) void BalloonManager::deploySet(int set_number)
{ {
const auto set = balloon_formations_->getSet(set_number); const auto set = balloon_formations_->getSet(set_number);
const auto numEnemies = set.number_of_balloons; const auto num_enemies = set.number_of_balloons;
for (int i = 0; i < numEnemies; ++i) for (int i = 0; i < num_enemies; ++i)
{ {
auto p = set.init[i]; auto p = set.init[i];
createBalloon(p.x, p.y, p.type, p.size, p.vel_x, balloon_speed_, p.creation_counter); createBalloon(p.x, p.y, p.type, p.size, p.vel_x, balloon_speed_, p.creation_counter);
@@ -135,8 +142,8 @@ void BalloonManager::deploySet(int set_number)
void BalloonManager::deploySet(int set_number, int y) void BalloonManager::deploySet(int set_number, int y)
{ {
const auto set = balloon_formations_->getSet(set_number); const auto set = balloon_formations_->getSet(set_number);
const auto numEnemies = set.number_of_balloons; const auto num_enemies = set.number_of_balloons;
for (int i = 0; i < numEnemies; ++i) for (int i = 0; i < num_enemies; ++i)
{ {
auto p = set.init[i]; auto p = set.init[i];
createBalloon(p.x, y, p.type, p.size, p.vel_x, balloon_speed_, p.creation_counter); createBalloon(p.x, y, p.type, p.size, p.vel_x, balloon_speed_, p.creation_counter);
@@ -172,14 +179,21 @@ int BalloonManager::calculateScreenPower()
// Crea un globo nuevo en el vector de globos // Crea un globo nuevo en el vector de globos
std::shared_ptr<Balloon> BalloonManager::createBalloon(float x, int y, BalloonType type, BalloonSize size, float velx, float speed, int creation_timer) std::shared_ptr<Balloon> BalloonManager::createBalloon(float x, int y, BalloonType type, BalloonSize size, float velx, float speed, int creation_timer)
{
if (can_deploy_balloons_)
{ {
const int index = static_cast<int>(size); const int index = static_cast<int>(size);
balloons_.emplace_back(std::make_shared<Balloon>(x, y, type, size, velx, speed, creation_timer, play_area_, balloon_textures_.at(index), balloon_animations_.at(index))); balloons_.emplace_back(std::make_shared<Balloon>(x, y, type, size, velx, speed, creation_timer, play_area_, balloon_textures_.at(index), balloon_animations_.at(index)));
return balloons_.back(); return balloons_.back();
} }
return nullptr;
}
// Crea un globo a partir de otro globo // Crea un globo a partir de otro globo
void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction) void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction)
{
if (can_deploy_balloons_)
{ {
const float vx = direction == "LEFT" ? BALLOON_VELX_NEGATIVE : BALLOON_VELX_POSITIVE; const float vx = direction == "LEFT" ? BALLOON_VELX_NEGATIVE : BALLOON_VELX_POSITIVE;
const auto lower_size = static_cast<BalloonSize>(static_cast<int>(balloon->getSize()) - 1); const auto lower_size = static_cast<BalloonSize>(static_cast<int>(balloon->getSize()) - 1);
@@ -196,9 +210,12 @@ void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon> &balloon,
b->useReverseColor(); b->useReverseColor();
} }
} }
}
// Crea una PowerBall // Crea una PowerBall
void BalloonManager::createPowerBall() void BalloonManager::createPowerBall()
{
if (can_deploy_balloons_)
{ {
constexpr int values = 6; constexpr int values = 6;
constexpr int pos_y = -BALLOON_SIZE[4]; constexpr int pos_y = -BALLOON_SIZE[4];
@@ -213,10 +230,12 @@ void BalloonManager::createPowerBall()
const float vx[values] = {BALLOON_VELX_POSITIVE, BALLOON_VELX_POSITIVE, BALLOON_VELX_POSITIVE, BALLOON_VELX_NEGATIVE, BALLOON_VELX_NEGATIVE, BALLOON_VELX_NEGATIVE}; const float vx[values] = {BALLOON_VELX_POSITIVE, BALLOON_VELX_POSITIVE, BALLOON_VELX_POSITIVE, BALLOON_VELX_NEGATIVE, BALLOON_VELX_NEGATIVE, BALLOON_VELX_NEGATIVE};
balloons_.emplace_back(std::make_unique<Balloon>(x[luck], pos_y, BalloonType::POWERBALL, BalloonSize::SIZE4, vx[luck], balloon_speed_, creation_time, play_area_, balloon_textures_[4], balloon_animations_[4])); balloons_.emplace_back(std::make_unique<Balloon>(x[luck], pos_y, BalloonType::POWERBALL, BalloonSize::SIZE4, vx[luck], balloon_speed_, creation_time, play_area_, balloon_textures_[4], balloon_animations_[4]));
balloons_.back()->setInvulnerable(true);
power_ball_enabled_ = true; power_ball_enabled_ = true;
power_ball_counter_ = POWERBALL_COUNTER; power_ball_counter_ = POWERBALL_COUNTER;
} }
}
// Establece la velocidad de los globos // Establece la velocidad de los globos
void BalloonManager::setBalloonSpeed(float speed) void BalloonManager::setBalloonSpeed(float speed)
@@ -251,7 +270,7 @@ int BalloonManager::popBalloon(std::shared_ptr<Balloon> balloon)
// Agrega la explosión y elimina el globo // Agrega la explosión y elimina el globo
explosions_->add(balloon->getPosX(), balloon->getPosY(), static_cast<int>(balloon->getSize())); explosions_->add(balloon->getPosX(), balloon->getPosY(), static_cast<int>(balloon->getSize()));
balloon->pop(); balloon->disable();
} }
return score; return score;
@@ -287,7 +306,7 @@ int BalloonManager::destroyBalloon(std::shared_ptr<Balloon> &balloon)
// Destruye el globo // Destruye el globo
explosions_->add(balloon->getPosX(), balloon->getPosY(), static_cast<int>(balloon->getSize())); explosions_->add(balloon->getPosX(), balloon->getPosY(), static_cast<int>(balloon->getSize()));
balloon->pop(); balloon->disable();
return score; return score;
} }
@@ -302,7 +321,7 @@ int BalloonManager::destroyAllBalloons()
} }
balloon_deploy_counter_ = 300; balloon_deploy_counter_ = 300;
JA_PlaySound(Resource::get()->getSound("powerball.wav")); JA_PlaySound(Resource::get()->getSound("power_ball_explosion.wav"));
Screen::get()->flash(flash_color, 3); Screen::get()->flash(flash_color, 3);
Screen::get()->shake(); Screen::get()->shake();
@@ -366,6 +385,21 @@ void BalloonManager::createTwoBigBalloons()
deploySet(1); deploySet(1);
} }
// Crea una disposición de globos aleatoria
void BalloonManager::createRandomBalloons()
{
const int num_balloons = 2 + rand() % 4;
for (int i = 0; i < num_balloons; ++i)
{
const float x = param.game.game_area.rect.x + (rand() % param.game.game_area.rect.w) - BALLOON_SIZE[3];
const int y = param.game.game_area.rect.y + (rand() % 50);
const BalloonSize size = static_cast<BalloonSize>(rand() % 4);
const float vel_x = (rand() % 2 == 0) ? BALLOON_VELX_POSITIVE : BALLOON_VELX_NEGATIVE;
const int creation_counter = 0;
createBalloon(x, y, BalloonType::BALLOON, size, vel_x, balloon_speed_, creation_counter);
}
}
// Obtiene el nivel de ameza actual generado por los globos // Obtiene el nivel de ameza actual generado por los globos
int BalloonManager::getMenace() int BalloonManager::getMenace()
{ {

View File

@@ -33,6 +33,8 @@ private:
int power_ball_counter_ = 0; // Contador de formaciones enemigas entre la aparicion de una PowerBall y otra int power_ball_counter_ = 0; // Contador de formaciones enemigas entre la aparicion de una PowerBall y otra
int last_balloon_deploy_ = 0; // Guarda cual ha sido la última formación desplegada para no repetir; int last_balloon_deploy_ = 0; // Guarda cual ha sido la última formación desplegada para no repetir;
SDL_Rect play_area_ = param.game.play_area.rect; // Zona por donde se moveran los globos SDL_Rect play_area_ = param.game.play_area.rect; // Zona por donde se moveran los globos
bool creation_time_enabled_ = true; // Indica si los globos se crean con tiempo
bool can_deploy_balloons_ = true; // Indica si creará globos
// Inicializa // Inicializa
void init(); void init();
@@ -108,6 +110,9 @@ public:
// Crea dos globos gordos // Crea dos globos gordos
void createTwoBigBalloons(); void createTwoBigBalloons();
// Crea una disposición de globos aleatoria
void createRandomBalloons();
// Obtiene el nivel de ameza actual generado por los globos // Obtiene el nivel de ameza actual generado por los globos
int getMenace(); int getMenace();
@@ -117,9 +122,12 @@ public:
// Getters // Getters
float getBalloonSpeed() const { return balloon_speed_; } float getBalloonSpeed() const { return balloon_speed_; }
Balloons &getBalloons() { return balloons_; } Balloons &getBalloons() { return balloons_; }
int getNumBalloons() const { return balloons_.size(); }
// Setters // Setters
void setDefaultBalloonSpeed(float speed) { default_balloon_speed_ = speed; } void setDefaultBalloonSpeed(float speed) { default_balloon_speed_ = speed; }
void resetBalloonSpeed() { setBalloonSpeed(default_balloon_speed_); } void resetBalloonSpeed() { setBalloonSpeed(default_balloon_speed_); }
void setPlayArea(SDL_Rect play_area) { play_area_ = play_area; } void setPlayArea(SDL_Rect play_area) { play_area_ = play_area; }
void setCreationTimeEnabled(bool value) { creation_time_enabled_ = value; }
void setDeployBalloons(bool value) { can_deploy_balloons_ = value; }
}; };

View File

@@ -1,35 +1,40 @@
// IWYU pragma: no_include <bits/std_abs.h>
#include "credits.h" #include "credits.h"
#include <SDL2/SDL_blendmode.h> // Para SDL_BLENDMODE_BLEND #include <SDL2/SDL_blendmode.h> // Para SDL_BLENDMODE_BLEND
#include <SDL2/SDL_events.h> // Para SDL_PollEvent, SDL_Event, SDL_QUIT #include <SDL2/SDL_events.h> // Para SDL_PollEvent, SDL_Event, SDL_QUIT
#include <SDL2/SDL_pixels.h> // Para SDL_PIXELFORMAT_RGBA8888 #include <SDL2/SDL_pixels.h> // Para SDL_PIXELFORMAT_RGBA8888
#include <SDL2/SDL_rect.h> // Para SDL_Rect
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks #include <SDL2/SDL_timer.h> // Para SDL_GetTicks
#include <algorithm> #include <algorithm> // Para max, min, clamp
#include <cstdlib> #include <cstdlib> // Para abs
#include <stdexcept> // Para runtime_error
#include <string> // Para basic_string, string #include <string> // Para basic_string, string
#include <vector> // Para vector #include <vector> // Para vector
#include "balloon_manager.h" // Para BalloonManager #include "balloon_manager.h" // Para BalloonManager
#include "global_inputs.h" // Para check #include "fade.h" // Para Fade, FadeType, FadeMode
#include "global_inputs.h" // Para check, update
#include "input.h" // Para Input #include "input.h" // Para Input
#include "jail_audio.h" // Para JA_PlayMusic, JA_StopMusic #include "jail_audio.h" // Para JA_GetMusicState, JA_SetMusicVolume
#include "lang.h" // Para getText
#include "mouse.h" // Para handleEvent
#include "param.h" // Para Param, ParamGame, param #include "param.h" // Para Param, ParamGame, param
#include "player.h" // Para Player, PlayerState
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "section.h" // Para Name, name, Options, options #include "section.h" // Para Name, name, Options, options
#include "sprite.h" // Para Sprite
#include "text.h" // Para Text, TEXT_CENTER, TEXT_SHADOW #include "text.h" // Para Text, TEXT_CENTER, TEXT_SHADOW
#include "texture.h" // Para Texture
#include "tiled_bg.h" // Para TiledBG, TiledBGMode #include "tiled_bg.h" // Para TiledBG, TiledBGMode
#include "utils.h" // Para Color, no_color, shdw_txt_color, Zone #include "utils.h" // Para Color, Zone, shdw_txt_color, no_color
#include "player.h"
#include "fade.h"
#include "lang.h"
// Textos // Textos
constexpr const char TEXT_COPYRIGHT[] = "@2020,2024 JailDesigner"; constexpr const char TEXT_COPYRIGHT[] = "@2020,2025 JailDesigner";
// Constructor // Constructor
Credits::Credits() Credits::Credits()
: balloon_manager_(std::make_unique<BalloonManager>()), : balloon_manager_(std::make_unique<BalloonManager>()),
text_texture_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), text_texture_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
canvas_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::DIAGONAL)), tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::DIAGONAL)),
fade_in_(std::make_unique<Fade>()), fade_in_(std::make_unique<Fade>()),
fade_out_(std::make_unique<Fade>()) fade_out_(std::make_unique<Fade>())
@@ -39,19 +44,17 @@ Credits::Credits()
throw std::runtime_error("Failed to create SDL texture for text."); throw std::runtime_error("Failed to create SDL texture for text.");
} }
section::name = section::Name::CREDITS; section::name = section::Name::CREDITS;
//top_black_rect_ = {play_area_.x, 0, play_area_.w, black_bars_size_};
//bottom_black_rect_ = {play_area_.x, param.game.game_area.rect.h - black_bars_size_, play_area_.w, black_bars_size_};
balloon_manager_->setPlayArea(play_area_); balloon_manager_->setPlayArea(play_area_);
fade_in_->setColor(fade_color.r, fade_color.g, fade_color.b); fade_in_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_in_->setType(FadeType::FULLSCREEN); fade_in_->setType(FadeType::FULLSCREEN);
fade_in_->setPost(50); fade_in_->setPostDuration(50);
fade_in_->setMode(FadeMode::IN); fade_in_->setMode(FadeMode::IN);
fade_in_->activate(); fade_in_->activate();
fade_out_->setColor(0, 0, 0); fade_out_->setColor(0, 0, 0);
fade_out_->setType(FadeType::FULLSCREEN); fade_out_->setType(FadeType::FULLSCREEN);
fade_out_->setPost(400); fade_out_->setPostDuration(400);
initPlayers(); initPlayers();
SDL_SetTextureBlendMode(text_texture_, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(text_texture_, SDL_BLENDMODE_BLEND);
@@ -63,7 +66,9 @@ Credits::Credits()
Credits::~Credits() Credits::~Credits()
{ {
SDL_DestroyTexture(text_texture_); SDL_DestroyTexture(text_texture_);
SDL_DestroyTexture(canvas_);
resetVolume(); resetVolume();
JA_StopMusic();
} }
// Bucle principal // Bucle principal
@@ -81,9 +86,14 @@ void Credits::run()
// Actualiza las variables // Actualiza las variables
void Credits::update() void Credits::update()
{ {
if (SDL_GetTicks() - ticks_ > ticks_speed_) constexpr Uint32 TICKS_SPEED_ = 15;
if (SDL_GetTicks() - ticks_ > TICKS_SPEED_)
{ {
ticks_ = SDL_GetTicks(); ticks_ = SDL_GetTicks();
const int repeat = want_to_pass_ ? 4 : 1;
for (int i = 0; i < repeat; ++i)
{
tiled_bg_->update(); tiled_bg_->update();
balloon_manager_->update(); balloon_manager_->update();
updateTextureDstRects(); updateTextureDstRects();
@@ -93,9 +103,12 @@ void Credits::update()
player->update(); player->update();
} }
updateAllFades(); updateAllFades();
++counter_;
}
Screen::get()->update(); Screen::get()->update();
globalInputs::update(); globalInputs::update();
++counter_;
fillCanvas();
} }
} }
@@ -105,42 +118,11 @@ void Credits::render()
// Prepara para empezar a dibujar en la textura de juego // Prepara para empezar a dibujar en la textura de juego
Screen::get()->start(); Screen::get()->start();
// Limpia la pantalla // Copia la textura con la zona de juego a la pantalla
Screen::get()->clean(); SDL_RenderCopy(Screen::get()->getRenderer(), canvas_, nullptr, nullptr);
// Dibuja el fondo, los globos y los jugadores
tiled_bg_->render();
balloon_manager_->render();
for (auto const &player : players_)
{
player->render();
}
// Dibuja los titulos de credito
SDL_RenderCopy(Screen::get()->getRenderer(), text_texture_, &credits_rect_src_, &credits_rect_dst_);
// Dibuja el mini_logo
SDL_RenderCopy(Screen::get()->getRenderer(), text_texture_, &mini_logo_rect_src_, &mini_logo_rect_dst_);
// Dibuja los rectangulos negros
SDL_SetRenderDrawColor(Screen::get()->getRenderer(), 0, 0, 0, 255);
SDL_RenderFillRect(Screen::get()->getRenderer(), &top_black_rect_);
SDL_RenderFillRect(Screen::get()->getRenderer(), &bottom_black_rect_);
SDL_RenderFillRect(Screen::get()->getRenderer(), &left_black_rect_);
SDL_RenderFillRect(Screen::get()->getRenderer(), &right_black_rect_);
// Si el mini_logo está en su destino, lo dibuja encima de lo anterior
if (mini_logo_on_position_)
{
SDL_RenderCopy(Screen::get()->getRenderer(), text_texture_, &mini_logo_rect_src_, &mini_logo_rect_dst_);
}
// Dibuja el fade sobre el resto de elementos
fade_in_->render();
fade_out_->render();
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
Screen::get()->blit(); Screen::get()->render();
} }
// Comprueba el manejador de eventos // Comprueba el manejador de eventos
@@ -158,6 +140,9 @@ void Credits::checkEvents()
section::options = section::Options::QUIT_FROM_EVENT; section::options = section::Options::QUIT_FROM_EVENT;
break; break;
} }
// Comprueba el cursor
Mouse::handleEvent(event);
} }
} }
@@ -176,7 +161,6 @@ void Credits::checkInput()
{ {
// Si todavía estan los creditos en marcha, se pasan solos a toda pastilla // Si todavía estan los creditos en marcha, se pasan solos a toda pastilla
want_to_pass_ = true; want_to_pass_ = true;
ticks_speed_ = 1;
} }
} }
@@ -273,6 +257,48 @@ void Credits::fillTextTexture()
mini_logo_final_pos_ = param.game.game_area.center_y - mini_logo_rect_src_.h / 2; mini_logo_final_pos_ = param.game.game_area.center_y - mini_logo_rect_src_.h / 2;
} }
// Dibuja todos los sprites en la textura
void Credits::fillCanvas()
{
// Cambia el destino del renderizador
auto temp = SDL_GetRenderTarget(Screen::get()->getRenderer());
SDL_SetRenderTarget(Screen::get()->getRenderer(), canvas_);
// Dibuja el fondo, los globos y los jugadores
tiled_bg_->render();
balloon_manager_->render();
for (auto const &player : players_)
{
player->render();
}
// Dibuja los titulos de credito
SDL_RenderCopy(Screen::get()->getRenderer(), text_texture_, &credits_rect_src_, &credits_rect_dst_);
// Dibuja el mini_logo
SDL_RenderCopy(Screen::get()->getRenderer(), text_texture_, &mini_logo_rect_src_, &mini_logo_rect_dst_);
// Dibuja los rectangulos negros
SDL_SetRenderDrawColor(Screen::get()->getRenderer(), 0, 0, 0, 255);
SDL_RenderFillRect(Screen::get()->getRenderer(), &top_black_rect_);
SDL_RenderFillRect(Screen::get()->getRenderer(), &bottom_black_rect_);
SDL_RenderFillRect(Screen::get()->getRenderer(), &left_black_rect_);
SDL_RenderFillRect(Screen::get()->getRenderer(), &right_black_rect_);
// Si el mini_logo está en su destino, lo dibuja encima de lo anterior
if (mini_logo_on_position_)
{
SDL_RenderCopy(Screen::get()->getRenderer(), text_texture_, &mini_logo_rect_src_, &mini_logo_rect_dst_);
}
// Dibuja el fade sobre el resto de elementos
fade_in_->render();
fade_out_->render();
// Deja el renderizador apuntando donde estaba
SDL_SetRenderTarget(Screen::get()->getRenderer(), temp);
}
// Actualiza el destino de los rectangulos de las texturas // Actualiza el destino de los rectangulos de las texturas
void Credits::updateTextureDstRects() void Credits::updateTextureDstRects()
{ {
@@ -452,7 +478,7 @@ void Credits::updateAllFades()
fade_out_->update(); fade_out_->update();
if (fade_out_->hasEnded()) if (fade_out_->hasEnded())
{ {
section::name = section::Name::LOGO; section::name = section::Name::HI_SCORE_TABLE;
} }
} }

View File

@@ -1,14 +1,17 @@
#pragma once #pragma once
#include <SDL2/SDL_rect.h> // Para SDL_Rect
#include <SDL2/SDL_render.h> // Para SDL_Texture #include <SDL2/SDL_render.h> // Para SDL_Texture
#include <SDL2/SDL_stdinc.h> // Para Uint32 #include <SDL2/SDL_stdinc.h> // Para Uint32
#include <memory> // Para unique_ptr #include <memory> // Para unique_ptr, shared_ptr
#include "param.h" #include <vector> // Para vector
#include "options.h" #include "options.h" // Para Options, OptionsAudio, OptionsMusic
class BalloonManager; #include "param.h" // Para Param, ParamGame, param
class TiledBG; #include "utils.h" // Para Zone
class Player; class BalloonManager; // lines 8-8
class Fade; class Fade; // lines 11-11
class Player; // lines 10-10
class TiledBG; // lines 9-9
constexpr int PLAY_AREA_HEIGHT = 200; constexpr int PLAY_AREA_HEIGHT = 200;
@@ -18,6 +21,7 @@ private:
// Objetos // Objetos
std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos
SDL_Texture *text_texture_; // Textura con el texto SDL_Texture *text_texture_; // Textura con el texto
SDL_Texture *canvas_; // Textura donde dibujarlo todo
std::unique_ptr<TiledBG> tiled_bg_; // Objeto para dibujar el mosaico animado de fondo std::unique_ptr<TiledBG> tiled_bg_; // Objeto para dibujar el mosaico animado de fondo
std::unique_ptr<Fade> fade_in_; // Objeto para realizar el fundido de entrada std::unique_ptr<Fade> fade_in_; // Objeto para realizar el fundido de entrada
std::unique_ptr<Fade> fade_out_; // Objeto para realizar el fundido de salida std::unique_ptr<Fade> fade_out_; // Objeto para realizar el fundido de salida
@@ -25,7 +29,6 @@ private:
// Variables // Variables
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
Uint32 ticks_speed_ = 15; // Velocidad del bucle update
Uint32 counter_ = 0; // Contador para la lógica de la clase Uint32 counter_ = 0; // Contador para la lógica de la clase
Uint32 counter_pre_fade_ = 0; // Contador para activar el fundido final Uint32 counter_pre_fade_ = 0; // Contador para activar el fundido final
Uint32 counter_prevent_endless_ = 0; // Contador para evitar que el juego se quede para siempre en los creditos Uint32 counter_prevent_endless_ = 0; // Contador para evitar que el juego se quede para siempre en los creditos
@@ -67,6 +70,9 @@ private:
// Crea la textura con el texto // Crea la textura con el texto
void fillTextTexture(); void fillTextTexture();
// Dibuja todos los sprites en la textura
void fillCanvas();
// Actualiza el destino de los rectangulos de las texturas // Actualiza el destino de los rectangulos de las texturas
void updateTextureDstRects(); void updateTextureDstRects();

View File

@@ -8,12 +8,15 @@
#include <SDL2/SDL_hints.h> // Para SDL_SetHint, SDL_HINT_RENDER_DR... #include <SDL2/SDL_hints.h> // Para SDL_SetHint, SDL_HINT_RENDER_DR...
#include <SDL2/SDL_scancode.h> // Para SDL_SCANCODE_0, SDL_SCANCODE_DOWN #include <SDL2/SDL_scancode.h> // Para SDL_SCANCODE_0, SDL_SCANCODE_DOWN
#include <SDL2/SDL_stdinc.h> // Para SDL_bool, Uint32 #include <SDL2/SDL_stdinc.h> // Para SDL_bool, Uint32
#include <chrono> // Para duration, system_clock
#include <errno.h> // Para errno, EEXIST, EACCES, ENAMETOO... #include <errno.h> // Para errno, EEXIST, EACCES, ENAMETOO...
#ifndef _WIN32
#include <pwd.h> // Para getpwuid, passwd
#endif
#include <stdio.h> // Para printf, perror #include <stdio.h> // Para printf, perror
#include <sys/stat.h> // Para mkdir, stat, S_IRWXU #include <sys/stat.h> // Para mkdir, stat, S_IRWXU
#include <unistd.h> // Para getuid #include <unistd.h> // Para getuid
#include <algorithm> // Para min #include <algorithm> // Para min
#include <chrono> // Para chrono
#include <cstdlib> // Para exit, EXIT_FAILURE, size_t, rand #include <cstdlib> // Para exit, EXIT_FAILURE, size_t, rand
#include <iostream> // Para basic_ostream, operator<<, basi... #include <iostream> // Para basic_ostream, operator<<, basi...
#include <memory> // Para make_unique, unique_ptr #include <memory> // Para make_unique, unique_ptr
@@ -24,7 +27,6 @@
#include "credits.h" // Para Credits #include "credits.h" // Para Credits
#include "dbgtxt.h" // Para dbg_init #include "dbgtxt.h" // Para dbg_init
#include "game.h" // Para Game, GAME_MODE_DEMO_OFF, GAME_... #include "game.h" // Para Game, GAME_MODE_DEMO_OFF, GAME_...
#include "global_inputs.h" // Para init
#include "hiscore_table.h" // Para HiScoreTable #include "hiscore_table.h" // Para HiScoreTable
#include "input.h" // Para Input, InputType #include "input.h" // Para Input, InputType
#include "instructions.h" // Para Instructions #include "instructions.h" // Para Instructions
@@ -35,7 +37,7 @@
#include "manage_hiscore_table.h" // Para ManageHiScoreTable #include "manage_hiscore_table.h" // Para ManageHiScoreTable
#include "notifier.h" // Para Notifier #include "notifier.h" // Para Notifier
#include "on_screen_help.h" // Para OnScreenHelp #include "on_screen_help.h" // Para OnScreenHelp
#include "options.h" // Para Options, OptionsController, opt... #include "options.h" // Para Options, options, OptionsContro...
#include "param.h" // Para Param, ParamGame, param, loadPa... #include "param.h" // Para Param, ParamGame, param, loadPa...
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
@@ -43,10 +45,6 @@
#include "title.h" // Para Title #include "title.h" // Para Title
#include "utils.h" // Para Overrides, overrides #include "utils.h" // Para Overrides, overrides
#ifndef _WIN32
#include <pwd.h> // para getpwuid, passwd
#endif
// Constructor // Constructor
Director::Director(int argc, const char *argv[]) Director::Director(int argc, const char *argv[])
{ {
@@ -128,6 +126,10 @@ void Director::close()
SDL_DestroyWindow(window_); SDL_DestroyWindow(window_);
SDL_Quit(); SDL_Quit();
#ifdef ARCADE
shutdownSystem(section::options == section::Options::QUIT_WITH_CONTROLLER);
#endif
} }
// Carga los parametros // Carga los parametros
@@ -388,29 +390,34 @@ void Director::setFileList()
Asset::get()->add(prefix + "/data/music/credits.ogg", AssetType::MUSIC); Asset::get()->add(prefix + "/data/music/credits.ogg", AssetType::MUSIC);
// Sonidos // Sonidos
Asset::get()->add(prefix + "/data/sound/game_start.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/balloon.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/balloon.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bubble1.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/bubble1.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bubble2.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/bubble2.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bubble3.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/bubble3.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bubble4.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/bubble4.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bullet.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/bullet.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/coffeeout.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/hiscore.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/itemdrop.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/itempickup.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/player_collision.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/stage_change.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/title.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/clock.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/clock.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/powerball.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/coffee_out.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/notify.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/continue_clock.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/game_start.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/hi_score_achieved.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/item_drop.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/item_pickup.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/logo.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/logo.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_coffee.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/notify.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_power_up.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/player_collision.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_no.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/power_ball_explosion.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_get_ready.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/stage_change.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/tabe.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/tabe.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/title.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_coffee.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_get_ready.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_no.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_power_up.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/walk.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/debian_drop.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/debian_pickup.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/tabe_hit.wav", AssetType::SOUND);
// Shaders // Shaders
Asset::get()->add(prefix + "/data/shaders/crtpi_256.glsl", AssetType::DATA); Asset::get()->add(prefix + "/data/shaders/crtpi_256.glsl", AssetType::DATA);
@@ -465,6 +472,8 @@ void Director::setFileList()
Asset::get()->add(prefix + "/data/gfx/game/game_grass.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/game/game_grass.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_power_meter.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/game/game_power_meter.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_sky_colors.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/game/game_sky_colors.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_sun.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_moon.png", AssetType::BITMAP);
} }
{ // Intro { // Intro
@@ -488,6 +497,8 @@ void Director::setFileList()
Asset::get()->add(prefix + "/data/gfx/item/item_clock.ani", AssetType::ANIMATION); Asset::get()->add(prefix + "/data/gfx/item/item_clock.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/item/item_coffee.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/item/item_coffee.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_coffee.ani", AssetType::ANIMATION); Asset::get()->add(prefix + "/data/gfx/item/item_coffee.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/item/item_debian.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_debian.ani", AssetType::ANIMATION);
Asset::get()->add(prefix + "/data/gfx/item/item_coffee_machine.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/item/item_coffee_machine.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/item/item_coffee_machine.ani", AssetType::ANIMATION); Asset::get()->add(prefix + "/data/gfx/item/item_coffee_machine.ani", AssetType::ANIMATION);
} }
@@ -503,17 +514,17 @@ void Director::setFileList()
{ // Jugador 1 { // Jugador 1
Asset::get()->add(prefix + "/data/gfx/player/player1.gif", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/player/player1.gif", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/player/player1_one_coffee_palette.pal", AssetType::PALETTE); Asset::get()->add(prefix + "/data/gfx/player/player1_1_coffee_palette.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player1_two_coffee_palette.pal", AssetType::PALETTE); Asset::get()->add(prefix + "/data/gfx/player/player1_2_coffee_palette.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player1_all_white_palette.pal", AssetType::PALETTE); Asset::get()->add(prefix + "/data/gfx/player/player1_invencible_palette.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player1_power.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/player/player1_power.png", AssetType::BITMAP);
} }
{ // Jugador 2 { // Jugador 2
Asset::get()->add(prefix + "/data/gfx/player/player2.gif", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/player/player2.gif", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/player/player2_one_coffee_palette.pal", AssetType::PALETTE); Asset::get()->add(prefix + "/data/gfx/player/player2_1_coffee_palette.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player2_two_coffee_palette.pal", AssetType::PALETTE); Asset::get()->add(prefix + "/data/gfx/player/player2_2_coffee_palette.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player2_all_white_palette.pal", AssetType::PALETTE); Asset::get()->add(prefix + "/data/gfx/player/player2_invencible_palette.gif", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/gfx/player/player2_power.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/player/player2_power.png", AssetType::BITMAP);
} }
@@ -525,8 +536,6 @@ void Director::setFileList()
// Fuentes de texto // Fuentes de texto
Asset::get()->add(prefix + "/data/font/8bithud.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/font/8bithud.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/font/8bithud.txt", AssetType::FONT); Asset::get()->add(prefix + "/data/font/8bithud.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/nokia.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/font/nokia.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/smb2.gif", AssetType::BITMAP); Asset::get()->add(prefix + "/data/font/smb2.gif", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/font/smb2_palette1.pal", AssetType::PALETTE); Asset::get()->add(prefix + "/data/font/smb2_palette1.pal", AssetType::PALETTE);
Asset::get()->add(prefix + "/data/font/smb2.txt", AssetType::FONT); Asset::get()->add(prefix + "/data/font/smb2.txt", AssetType::FONT);
@@ -534,6 +543,8 @@ void Director::setFileList()
Asset::get()->add(prefix + "/data/font/04b_25.txt", AssetType::FONT); Asset::get()->add(prefix + "/data/font/04b_25.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/04b_25_2x.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/font/04b_25_2x.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/font/04b_25_2x.txt", AssetType::FONT); Asset::get()->add(prefix + "/data/font/04b_25_2x.txt", AssetType::FONT);
Asset::get()->add(prefix + "/data/font/04b_25_metal.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/font/04b_25_grey.png", AssetType::BITMAP);
// Textos // Textos
Asset::get()->add(prefix + "/data/lang/es_ES.txt", AssetType::LANG); Asset::get()->add(prefix + "/data/lang/es_ES.txt", AssetType::LANG);
@@ -760,11 +771,6 @@ int Director::run()
// Habilita de nuevo los std::cout // Habilita de nuevo los std::cout
std::cout.rdbuf(orig_buf); std::cout.rdbuf(orig_buf);
#endif #endif
#ifdef ARCADE
// Comprueba si ha de apagar el sistema
if (section::options == section::Options::QUIT_WITH_CONTROLLER)
shutdownSystem();
#endif
return (section::options == section::Options::QUIT_WITH_CONTROLLER) ? 1 : 0; return (section::options == section::Options::QUIT_WITH_CONTROLLER) ? 1 : 0;
} }
@@ -792,20 +798,23 @@ std::string Director::getLangFile(lang::Code code)
#ifdef ARCADE #ifdef ARCADE
// Apaga el sistema // Apaga el sistema
void Director::shutdownSystem() void Director::shutdownSystem(bool shouldShutdown)
{
if (shouldShutdown)
{ {
#ifdef _WIN32 #ifdef _WIN32
// Apaga el sistema en Windows // Apaga el sistema en Windows
system("shutdown /s /t 0"); system("shutdown /s /t 5");
#elif __APPLE__ #elif __APPLE__
// Apaga el sistema en macOS // Apaga el sistema en macOS
system("sudo shutdown -h now"); system("sudo shutdown -h +0.1");
#elif __linux__ #elif __linux__
// Apaga el sistema en Linux // Apaga el sistema en Linux
system("shutdown -h now"); system("sleep 5; shutdown -h now");
#else #else
// Sistema operativo no compatible // Sistema operativo no compatible
#error "Sistema operativo no soportado" #error "Sistema operativo no soportado"
#endif #endif
} }
}
#endif // ARCADE #endif // ARCADE

View File

@@ -74,7 +74,7 @@ private:
std::string getLangFile(lang::Code code); std::string getLangFile(lang::Code code);
#ifdef ARCADE #ifdef ARCADE
// Apaga el sistema // Apaga el sistema
void shutdownSystem(); void shutdownSystem(bool shouldShutdown);
#endif #endif
// Inicializa todo // Inicializa todo

View File

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

View File

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

View File

@@ -30,15 +30,15 @@ void Fade::init()
{ {
type_ = FadeType::CENTER; type_ = FadeType::CENTER;
mode_ = FadeMode::OUT; mode_ = FadeMode::OUT;
enabled_ = false;
finished_ = false;
counter_ = 0; counter_ = 0;
r_ = 0; r_ = 0;
g_ = 0; g_ = 0;
b_ = 0; b_ = 0;
a_ = 0; a_ = 0;
post_duration_ = 20; post_duration_ = 0;
post_counter_ = 0; post_counter_ = 0;
pre_duration_ = 0;
pre_counter_ = 0;
num_squares_width_ = param.fade.num_squares_width; num_squares_width_ = param.fade.num_squares_width;
num_squares_height_ = param.fade.num_squares_height; num_squares_height_ = param.fade.num_squares_height;
fade_random_squares_delay_ = param.fade.random_squares_delay; fade_random_squares_delay_ = param.fade.random_squares_delay;
@@ -48,15 +48,14 @@ void Fade::init()
// Resetea algunas variables para volver a hacer el fade sin perder ciertos parametros // Resetea algunas variables para volver a hacer el fade sin perder ciertos parametros
void Fade::reset() void Fade::reset()
{ {
enabled_ = false; state_ = FadeState::NOT_ENABLED;
finished_ = false;
counter_ = 0; counter_ = 0;
} }
// Pinta una transición en pantalla // Pinta una transición en pantalla
void Fade::render() void Fade::render()
{ {
if (enabled_ || finished_) if (state_ != FadeState::NOT_ENABLED)
{ {
SDL_RenderCopy(renderer_, backbuffer_, nullptr, nullptr); SDL_RenderCopy(renderer_, backbuffer_, nullptr, nullptr);
} }
@@ -65,7 +64,20 @@ void Fade::render()
// Actualiza las variables internas // Actualiza las variables internas
void Fade::update() void Fade::update()
{ {
if (enabled_) if (state_ == FadeState::PRE)
{
// Actualiza el contador
if (pre_counter_ == pre_duration_)
{
state_ = FadeState::FADING;
}
else
{
pre_counter_++;
}
}
if (state_ == FadeState::FADING)
{ {
switch (type_) switch (type_)
{ {
@@ -79,7 +91,7 @@ void Fade::update()
// Comprueba si ha terminado // Comprueba si ha terminado
if (counter_ >= 255 / 4) if (counter_ >= 255 / 4)
{ {
finished_ = true; state_ = FadeState::POST;
} }
break; break;
@@ -110,7 +122,7 @@ void Fade::update()
// Comprueba si ha terminado // Comprueba si ha terminado
if ((counter_ * 4) > param.game.height) if ((counter_ * 4) > param.game.height)
{ {
finished_ = true; state_ = FadeState::POST;
a_ = 255; a_ = 255;
} }
break; break;
@@ -120,9 +132,11 @@ void Fade::update()
{ {
if (counter_ % fade_random_squares_delay_ == 0) if (counter_ % fade_random_squares_delay_ == 0)
{ {
// Dibuja sobre el backbuffer_ // Cambia el renderizador al backbuffer_ y modifica sus opciones
auto temp = SDL_GetRenderTarget(renderer_); auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_); SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_BlendMode blend_mode;
SDL_GetRenderDrawBlendMode(renderer_, &blend_mode);
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE); SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_); SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
@@ -135,6 +149,7 @@ void Fade::update()
} }
// Deja el renderizador como estaba // Deja el renderizador como estaba
SDL_SetRenderDrawBlendMode(renderer_, blend_mode);
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
} }
@@ -143,7 +158,7 @@ void Fade::update()
// Comprueba si ha terminado // Comprueba si ha terminado
if (counter_ * fade_random_squares_mult_ / fade_random_squares_delay_ >= num_squares_width_ * num_squares_height_) if (counter_ * fade_random_squares_mult_ / fade_random_squares_delay_ >= num_squares_width_ * num_squares_height_)
{ {
finished_ = true; state_ = FadeState::POST;
} }
break; break;
@@ -151,12 +166,14 @@ void Fade::update()
case FadeType::VENETIAN: case FadeType::VENETIAN:
{ {
// Counter debe ir de 0 a 150 // Counter debe ir de 0 a 150 <-- comprobar si esto es aún cierto
if (square_.back().h < param.fade.venetian_size) if (square_.back().h < param.fade.venetian_size)
{ {
// Dibuja sobre el backbuffer_ // Dibuja sobre el backbuffer_
auto temp = SDL_GetRenderTarget(renderer_); auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_); SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_BlendMode blend_mode;
SDL_GetRenderDrawBlendMode(renderer_, &blend_mode);
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE); SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_); SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
@@ -167,6 +184,7 @@ void Fade::update()
} }
// Deja el renderizador como estaba // Deja el renderizador como estaba
SDL_SetRenderDrawBlendMode(renderer_, blend_mode);
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
// Modifica el tamaño de los rectangulos // Modifica el tamaño de los rectangulos
@@ -176,42 +194,60 @@ void Fade::update()
// A partir del segundo rectangulo se pinta en función del anterior // A partir del segundo rectangulo se pinta en función del anterior
square_.at(i).h = i == 0 ? h : std::max(square_.at(i - 1).h - 2, 0); square_.at(i).h = i == 0 ? h : std::max(square_.at(i - 1).h - 2, 0);
} }
int completed = 0;
for (const auto &square : square_)
{
if (square.h >= param.fade.venetian_size)
{
++completed;
}
}
value_ = calculateValue(0, square_.size() - 1, completed);
} }
else else
{ {
finished_ = true; state_ = FadeState::POST;
} }
break; break;
} }
default:
break;
}
counter_++;
} }
if (finished_) if (state_ == FadeState::POST)
{ {
// Actualiza el contador // Actualiza el contador
post_counter_ == post_duration_ ? enabled_ = false : post_counter_++; if (post_counter_ == post_duration_)
{
state_ = FadeState::FINISHED;
}
else
{
post_counter_++;
}
// Deja el backbuffer_ todo del mismo color // Deja el backbuffer_ todo del mismo color
cleanBackbuffer(r_, g_, b_, a_); cleanBackbuffer(r_, g_, b_, a_);
} }
counter_++;
}
} }
// Activa el fade // Activa el fade
void Fade::activate() void Fade::activate()
{ {
// Si ya está habilitado, no hay que volverlo a activar // Si ya está habilitado, no hay que volverlo a activar
if (enabled_) if (state_ != FadeState::NOT_ENABLED)
{ {
return; return;
} }
enabled_ = true; state_ = FadeState::PRE;
finished_ = false;
counter_ = 0; counter_ = 0;
post_counter_ = 0; post_counter_ = 0;
pre_counter_ = 0;
switch (type_) switch (type_)
{ {
@@ -315,9 +351,15 @@ void Fade::cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
// Calcula el valor del estado del fade // Calcula el valor del estado del fade
int Fade::calculateValue(int min, int max, int current) int Fade::calculateValue(int min, int max, int current)
{ {
if (max == 0) if (current < min)
{ {
return 0; return 0;
} }
return std::clamp(current * 100 / max, 0, 100);
if (current > max)
{
return 100;
}
return static_cast<int>(100.0 * (current - min) / (max - min));
} }

View File

@@ -21,6 +21,16 @@ enum class FadeMode : Uint8
OUT = 1, OUT = 1,
}; };
// Estados del objeto
enum class FadeState : Uint8
{
NOT_ENABLED = 0,
PRE = 1,
FADING = 2,
POST = 3,
FINISHED = 4,
};
// Clase Fade // Clase Fade
class Fade class Fade
{ {
@@ -32,9 +42,8 @@ private:
// Variables // Variables
FadeType type_; // Tipo de fade a realizar FadeType type_; // Tipo de fade a realizar
FadeMode mode_; // Modo de fade a realizar FadeMode mode_; // Modo de fade a realizar
FadeState state_ = FadeState::NOT_ENABLED; // Estado actual del objeto
Uint16 counter_; // Contador interno 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 Uint8 r_, g_, b_, a_; // Colores para el fade
SDL_Rect rect1_; // Rectangulo usado para crear los efectos de transición SDL_Rect rect1_; // Rectangulo usado para crear los efectos de transición
SDL_Rect rect2_; // Rectangulo usado para crear los efectos de transición SDL_Rect rect2_; // Rectangulo usado para crear los efectos de transición
@@ -43,8 +52,10 @@ private:
std::vector<SDL_Rect> square_; // Vector con los indices de los cuadrados 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_delay_; // Duración entre cada pintado de cuadrados
int fade_random_squares_mult_; // Cantidad de cuadrados que se pintaran cada vez 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_duration_ = 0; // Duración posterior del fade tras finalizar
int post_counter_; // Contador para la duración posterior int post_counter_ = 0; // Contador para la duración posterior
int pre_duration_ = 0; // Duración previa del fade antes de iniciar
int pre_counter_ = 0; // Contador para la duración previa
int value_ = 0; // Estado actual del fade entre 0 y 100 int value_ = 0; // Estado actual del fade entre 0 y 100
// Inicializa las variables // Inicializa las variables
@@ -80,11 +91,12 @@ public:
// Getters // Getters
int getValue() const { return value_; } int getValue() const { return value_; }
bool isEnabled() const { return enabled_; } bool isEnabled() const { return state_ != FadeState::NOT_ENABLED; }
bool hasEnded() const { return !enabled_ && finished_; } bool hasEnded() const { return state_ == FadeState::FINISHED; }
// Setters // Setters
void setType(FadeType type) { type_ = type; } void setType(FadeType type) { type_ = type; }
void setMode(FadeMode mode) { mode_ = mode; } void setMode(FadeMode mode) { mode_ = mode; }
void setPost(int value) { post_duration_ = value; } void setPostDuration(int value) { post_duration_ = value; }
void setPreDuration(int value) { pre_duration_ = value; }
}; };

View File

@@ -15,13 +15,14 @@
#include "balloon_manager.h" // Para BalloonManager #include "balloon_manager.h" // Para BalloonManager
#include "bullet.h" // Para Bullet, BulletType, BulletMoveStatus #include "bullet.h" // Para Bullet, BulletType, BulletMoveStatus
#include "enter_name.h" // Para NAME_LENGHT #include "enter_name.h" // Para NAME_LENGHT
#include "fade.h" // Para Fade, FadeType #include "fade.h" // Para Fade, FadeType, FadeMode
#include "global_inputs.h" // Para check #include "global_inputs.h" // Para check, update
#include "input.h" // Para InputType, Input, INPUT_DO_NOT_ALL... #include "input.h" // Para InputType, Input, INPUT_DO_NOT_ALL...
#include "item.h" // Para Item, ItemType #include "item.h" // Para Item, ItemType
#include "jail_audio.h" // Para JA_PlaySound, JA_GetMusicState #include "jail_audio.h" // Para JA_PlaySound, JA_GetMusicState
#include "lang.h" // Para getText #include "lang.h" // Para getText
#include "manage_hiscore_table.h" // Para ManageHiScoreTable, HiScoreEntry #include "manage_hiscore_table.h" // Para ManageHiScoreTable, HiScoreEntry
#include "mouse.h" // Para handleEvent
#include "notifier.h" // Para Notifier #include "notifier.h" // Para Notifier
#include "param.h" // Para Param, param, ParamGame, ParamFade #include "param.h" // Para Param, param, ParamGame, ParamFade
#include "path_sprite.h" // Para Path, PathSprite, createPath, Path... #include "path_sprite.h" // Para Path, PathSprite, createPath, Path...
@@ -29,13 +30,12 @@
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
#include "scoreboard.h" // Para Scoreboard, ScoreboardMode, SCOREB... #include "scoreboard.h" // Para Scoreboard, ScoreboardMode, SCOREB...
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "section.h" // Para Name, name, Options, options #include "section.h" // Para Name, name, AttractMode, Options
#include "smart_sprite.h" // Para SmartSprite #include "smart_sprite.h" // Para SmartSprite
#include "stage.h" // Para number, get, Stage, power, total_p... #include "stage.h" // Para number, get, Stage, total_power
#include "tabe.h" // Para Tabe #include "tabe.h" // Para Tabe
#include "text.h" // Para Text #include "text.h" // Para Text
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
struct JA_Sound_t; // lines 37-37
// Constructor // Constructor
Game::Game(int player_id, int current_stage, bool demo) Game::Game(int player_id, int current_stage, bool demo)
@@ -67,13 +67,14 @@ Game::Game(int player_id, int current_stage, bool demo)
scoreboard_ = Scoreboard::get(); scoreboard_ = Scoreboard::get();
fade_in_->setColor(fade_color.r, fade_color.g, fade_color.b); fade_in_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_in_->setPost(0); fade_in_->setPreDuration(demo_.enabled ? 80 : 0);
fade_in_->setPostDuration(0);
fade_in_->setType(FadeType::RANDOM_SQUARE); fade_in_->setType(FadeType::RANDOM_SQUARE);
fade_in_->setMode(FadeMode::IN); fade_in_->setMode(FadeMode::IN);
fade_in_->activate(); fade_in_->activate();
fade_out_->setColor(fade_color.r, fade_color.g, fade_color.b); fade_out_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_out_->setPost(param.fade.post_duration); fade_out_->setPostDuration(param.fade.post_duration);
fade_out_->setType(FadeType::VENETIAN); fade_out_->setType(FadeType::VENETIAN);
background_->setPos(param.game.play_area.rect); background_->setPos(param.game.play_area.rect);
@@ -139,6 +140,7 @@ void Game::setResources()
game_text_textures_.emplace_back(Resource::get()->getTexture("game_text_powerup")); game_text_textures_.emplace_back(Resource::get()->getTexture("game_text_powerup"));
game_text_textures_.emplace_back(Resource::get()->getTexture("game_text_one_hit")); game_text_textures_.emplace_back(Resource::get()->getTexture("game_text_one_hit"));
game_text_textures_.emplace_back(Resource::get()->getTexture("game_text_stop")); game_text_textures_.emplace_back(Resource::get()->getTexture("game_text_stop"));
game_text_textures_.emplace_back(Resource::get()->getTexture("game_text_100000_points"));
} }
// Texturas - Items // Texturas - Items
@@ -148,6 +150,7 @@ void Game::setResources()
item_textures_.emplace_back(Resource::get()->getTexture("item_points3_pacmar.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_clock.png"));
item_textures_.emplace_back(Resource::get()->getTexture("item_coffee.png")); item_textures_.emplace_back(Resource::get()->getTexture("item_coffee.png"));
item_textures_.emplace_back(Resource::get()->getTexture("item_debian.png"));
item_textures_.emplace_back(Resource::get()->getTexture("item_coffee_machine.png")); item_textures_.emplace_back(Resource::get()->getTexture("item_coffee_machine.png"));
} }
@@ -180,6 +183,7 @@ void Game::setResources()
item_animations_.emplace_back(Resource::get()->getAnimation("item_points3_pacmar.ani")); item_animations_.emplace_back(Resource::get()->getAnimation("item_points3_pacmar.ani"));
item_animations_.emplace_back(Resource::get()->getAnimation("item_clock.ani")); item_animations_.emplace_back(Resource::get()->getAnimation("item_clock.ani"));
item_animations_.emplace_back(Resource::get()->getAnimation("item_coffee.ani")); item_animations_.emplace_back(Resource::get()->getAnimation("item_coffee.ani"));
item_animations_.emplace_back(Resource::get()->getAnimation("item_debian.ani"));
item_animations_.emplace_back(Resource::get()->getAnimation("item_coffee_machine.ani")); item_animations_.emplace_back(Resource::get()->getAnimation("item_coffee_machine.ani"));
} }
} }
@@ -201,7 +205,7 @@ void Game::updateHiScore()
if (hi_score_achieved_ == false) if (hi_score_achieved_ == false)
{ {
hi_score_achieved_ = true; hi_score_achieved_ = true;
JA_PlaySound(Resource::get()->getSound("hiscore.wav")); JA_PlaySound(Resource::get()->getSound("hi_score_achieved.wav"));
} }
} }
} }
@@ -253,8 +257,6 @@ void Game::renderPlayers()
// Comprueba si hay cambio de fase y actualiza las variables // Comprueba si hay cambio de fase y actualiza las variables
void Game::updateStage() void Game::updateStage()
{
if (state_ == GameState::PLAYING)
{ {
if (Stage::power >= Stage::get(Stage::number).power_to_complete) if (Stage::power >= Stage::get(Stage::number).power_to_complete)
{ {
@@ -281,36 +283,33 @@ void Game::updateStage()
createMessage(paths, text->writeToTexture(caption, 1, -4)); createMessage(paths, text->writeToTexture(caption, 1, -4));
} }
} }
}
}
}
// Actualiza el estado de fade in // Modifica el color de fondo al llegar a la Fase 10
void Game::updateFadeInState() if (Stage::number == 9)
{ {
if (state_ == GameState::FADE_IN) background_->setColor(Color(0xdd, 0x19, 0x1d).darken());
{ background_->setAlpha(96);
if (fade_in_->hasEnded())
{
state_ = GameState::PLAYING;
// Crea los primeros globos y el mensaje de inicio
if (!demo_.enabled)
{
balloon_manager_->createTwoBigBalloons();
evaluateAndSetMenace();
createMessage({paths_.at(0), paths_.at(1)}, Resource::get()->getTexture("game_text_get_ready"));
JA_PlaySound(Resource::get()->getSound("voice_get_ready.wav"));
}
} }
} }
} }
// Actualiza el estado de fin de la partida // Actualiza el estado de fin de la partida
void Game::updateGameOverState() void Game::updateGameStateGameOver()
{
if (state_ == GameState::GAME_OVER)
{ {
fade_out_->update();
updatePlayers();
updateScoreboard();
updateBackground();
balloon_manager_->update();
tabe_->update();
updateBullets();
updateItems();
updateSmartSprites();
updatePathSprites();
updateTimeStopped();
checkBulletCollision();
cleanVectors();
if (game_over_counter_ > 0) if (game_over_counter_ > 0)
{ {
if (game_over_counter_ == GAME_OVER_COUNTER_) if (game_over_counter_ == GAME_OVER_COUNTER_)
@@ -328,6 +327,12 @@ void Game::updateGameOverState()
} }
} }
if (fade_out_->isEnabled())
{
const float vol = static_cast<float>(64 * (100 - fade_out_->getValue())) / 100.0f;
JA_SetSoundVolume(to_JA_volume(static_cast<int>(vol)));
}
if (fade_out_->hasEnded()) if (fade_out_->hasEnded())
{ {
if (game_completed_counter_ > 0) if (game_completed_counter_ > 0)
@@ -340,15 +345,25 @@ void Game::updateGameOverState()
// La partida ha terminado con la derrota de los jugadores // La partida ha terminado con la derrota de los jugadores
section::name = section::Name::HI_SCORE_TABLE; section::name = section::Name::HI_SCORE_TABLE;
} }
} JA_StopChannel(-1);
JA_SetSoundVolume(to_JA_volume(options.audio.sound.volume));
} }
} }
// Gestiona eventos para el estado del final del juego // Gestiona eventos para el estado del final del juego
void Game::updateCompletedState() void Game::updateGameStateCompleted()
{
if (state_ == GameState::COMPLETED)
{ {
updatePlayers();
updateScoreboard();
updateBackground();
balloon_manager_->update();
tabe_->update();
updateBullets();
updateItems();
updateSmartSprites();
updatePathSprites();
cleanVectors();
// Para la música y elimina todos los globos e items // Para la música y elimina todos los globos e items
if (game_completed_counter_ == 0) if (game_completed_counter_ == 0)
{ {
@@ -357,6 +372,7 @@ void Game::updateCompletedState()
balloon_manager_->destroyAllBalloons(); // Destruye a todos los globos balloon_manager_->destroyAllBalloons(); // Destruye a todos los globos
destroyAllItems(); // Destruye todos los items destroyAllItems(); // Destruye todos los items
Stage::power = 0; // Vuelve a dejar el poder a cero, por lo que hubiera podido subir al destruir todos los globos Stage::power = 0; // Vuelve a dejar el poder a cero, por lo que hubiera podido subir al destruir todos los globos
background_->setAlpha(0); // Elimina el tono rojo de las últimas pantallas
} }
// Comienza las celebraciones // Comienza las celebraciones
@@ -384,28 +400,35 @@ void Game::updateCompletedState()
if (game_completed_counter_ == 500) if (game_completed_counter_ == 500)
{ {
for (auto &player : players_) for (auto &player : players_)
{
if (player->isCelebrating()) if (player->isCelebrating())
{ {
player->setPlayingState(player->IsEligibleForHighScore() ? PlayerState::ENTERING_NAME_GAME_COMPLETED : PlayerState::LEAVING_SCREEN); player->setPlayingState(player->IsEligibleForHighScore() ? PlayerState::ENTERING_NAME_GAME_COMPLETED : PlayerState::LEAVING_SCREEN);
} }
} }
}
// Si los jugadores ya no estan y no quedan mensajes en pantalla
if (allPlayersAreGameOver() && path_sprites_.size() == 0)
{
setState(GameState::GAME_OVER);
}
// Incrementa el contador al final // Incrementa el contador al final
++game_completed_counter_; ++game_completed_counter_;
} }
}
// Comprueba el estado del juego // Comprueba el estado del juego
void Game::checkState() void Game::checkState()
{ {
if (state_ != GameState::COMPLETED && Stage::number == 10) if (state_ != GameState::COMPLETED && Stage::number == 10)
{ {
state_ = GameState::COMPLETED; setState(GameState::COMPLETED);
} }
if (state_ != GameState::GAME_OVER && allPlayersAreGameOver()) if (state_ != GameState::GAME_OVER && allPlayersAreGameOver())
{ {
state_ = GameState::GAME_OVER; setState(GameState::GAME_OVER);
} }
} }
@@ -450,37 +473,41 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
case ItemType::DISK: case ItemType::DISK:
{ {
player->addScore(1000); player->addScore(1000);
const auto x = const auto x = item->getPosX() + (item->getWidth() - game_text_textures_.at(0)->getWidth()) / 2;
item->getPosX() + createItemText(x, game_text_textures_.at(0));
(item->getWidth() - game_text_textures_[0]->getWidth()) / 2; JA_PlaySound(Resource::get()->getSound("item_pickup.wav"));
createItemText(x, game_text_textures_[0]);
break; break;
} }
case ItemType::GAVINA: case ItemType::GAVINA:
{ {
player->addScore(2500); player->addScore(2500);
const auto x = const auto x = item->getPosX() + (item->getWidth() - game_text_textures_.at(1)->getWidth()) / 2;
item->getPosX() + createItemText(x, game_text_textures_.at(1));
(item->getWidth() - game_text_textures_[1]->getWidth()) / 2; JA_PlaySound(Resource::get()->getSound("item_pickup.wav"));
createItemText(x, game_text_textures_[1]);
break; break;
} }
case ItemType::PACMAR: case ItemType::PACMAR:
{ {
player->addScore(5000); player->addScore(5000);
const auto x = const auto x = item->getPosX() + (item->getWidth() - game_text_textures_.at(2)->getWidth()) / 2;
item->getPosX() + createItemText(x, game_text_textures_.at(2));
(item->getWidth() - game_text_textures_[2]->getWidth()) / 2; JA_PlaySound(Resource::get()->getSound("item_pickup.wav"));
createItemText(x, game_text_textures_[2]); break;
}
case ItemType::DEBIAN:
{
player->addScore(100000);
const auto x = item->getPosX() + (item->getWidth() - game_text_textures_.at(6)->getWidth()) / 2;
createItemText(x, game_text_textures_.at(6));
JA_PlaySound(Resource::get()->getSound("debian_pickup.wav"));
break; break;
} }
case ItemType::CLOCK: case ItemType::CLOCK:
{ {
enableTimeStopItem(); enableTimeStopItem();
const auto x = const auto x = item->getPosX() + (item->getWidth() - game_text_textures_.at(5)->getWidth()) / 2;
item->getPosX() + createItemText(x, game_text_textures_.at(5));
(item->getWidth() - game_text_textures_[5]->getWidth()) / 2; JA_PlaySound(Resource::get()->getSound("item_pickup.wav"));
createItemText(x, game_text_textures_[5]);
break; break;
} }
case ItemType::COFFEE: case ItemType::COFFEE:
@@ -488,18 +515,14 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
if (player->getCoffees() == 2) if (player->getCoffees() == 2)
{ {
player->addScore(5000); player->addScore(5000);
const auto x = const auto x = item->getPosX() + (item->getWidth() - game_text_textures_.at(2)->getWidth()) / 2;
item->getPosX() + createItemText(x, game_text_textures_.at(2));
(item->getWidth() - game_text_textures_[2]->getWidth()) / 2;
createItemText(x, game_text_textures_[2]);
} }
else else
{ {
player->giveExtraHit(); player->giveExtraHit();
const auto x = const auto x = item->getPosX() + (item->getWidth() - game_text_textures_.at(4)->getWidth()) / 2;
item->getPosX() + createItemText(x, game_text_textures_.at(4));
(item->getWidth() - game_text_textures_[4]->getWidth()) / 2;
createItemText(x, game_text_textures_[4]);
} }
JA_PlaySound(Resource::get()->getSound("voice_coffee.wav")); JA_PlaySound(Resource::get()->getSound("voice_coffee.wav"));
break; break;
@@ -508,10 +531,8 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
{ {
player->setPowerUp(); player->setPowerUp();
coffee_machine_enabled_ = false; coffee_machine_enabled_ = false;
const auto x = const auto x = item->getPosX() + (item->getWidth() - game_text_textures_.at(3)->getWidth()) / 2;
item->getPosX() + createItemText(x, game_text_textures_.at(3));
(item->getWidth() - game_text_textures_[3]->getWidth()) / 2;
createItemText(x, game_text_textures_[3]);
JA_PlaySound(Resource::get()->getSound("voice_power_up.wav")); JA_PlaySound(Resource::get()->getSound("voice_power_up.wav"));
break; break;
} }
@@ -520,18 +541,46 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
} }
updateHiScore(); updateHiScore();
JA_PlaySound(Resource::get()->getSound("itempickup.wav"));
item->disable(); item->disable();
} }
} }
} }
} }
// Comprueba y procesa la colisión entre las balas y los globos // Comprueba y procesa la colisión de las balas
void Game::checkBulletBalloonCollision() void Game::checkBulletCollision()
{ {
for (auto &bullet : bullets_) for (auto &bullet : bullets_)
{ {
// Comprueba la colisión con el Tabe
if (bullet->isEnabled() && tabe_->isEnabled())
if (checkCollision(bullet->getCollider(), tabe_->getCollider()))
{
tabe_->setState(TabeState::HIT);
bullet->disable();
auto pos = tabe_->getCollider();
if (tabe_->tryToGetBonus())
{
createItem(ItemType::DEBIAN, pos.x, pos.y);
JA_PlaySound(Resource::get()->getSound("debian_drop.wav"));
}
else
{
if (rand() % 3 == 0)
{
createItem(ItemType::COFFEE, pos.x, pos.y);
// JA_PlaySound(Resource::get()->getSound("item_drop.wav"));
}
else
{
// JA_PlaySound(Resource::get()->getSound("tabe_hit.wav"));
}
JA_PlaySound(Resource::get()->getSound("tabe_hit.wav"));
}
break;
}
// Comprueba la colisión con los globos
for (auto &balloon : balloon_manager_->getBalloons()) for (auto &balloon : balloon_manager_->getBalloons())
{ {
if (balloon->isEnabled() && (!balloon->isInvulnerable()) && bullet->isEnabled()) if (balloon->isEnabled() && (!balloon->isInvulnerable()) && bullet->isEnabled())
@@ -542,17 +591,17 @@ void Game::checkBulletBalloonCollision()
auto player = getPlayer(bullet->getOwner()); auto player = getPlayer(bullet->getOwner());
// Suelta el item si se da el caso // Suelta el item si se da el caso
const auto droppeditem = dropItem(); const auto dropped_item = dropItem();
if (droppeditem != ItemType::NONE && !demo_.recording) if (dropped_item != ItemType::NONE && !demo_.recording)
{ {
if (droppeditem != ItemType::COFFEE_MACHINE) if (dropped_item != ItemType::COFFEE_MACHINE)
{ {
createItem(droppeditem, balloon->getPosX(), balloon->getPosY()); createItem(dropped_item, balloon->getPosX(), balloon->getPosY());
JA_PlaySound(Resource::get()->getSound("itemdrop.wav")); JA_PlaySound(Resource::get()->getSound("item_drop.wav"));
} }
else else
{ {
createItem(droppeditem, player->getPosX(), 0); createItem(dropped_item, player->getPosX(), param.game.game_area.rect.y - param.game.coffee_machine_h);
coffee_machine_enabled_ = true; coffee_machine_enabled_ = true;
} }
} }
@@ -583,12 +632,16 @@ void Game::checkBulletBalloonCollision()
} }
// Mueve las balas activas // Mueve las balas activas
void Game::moveBullets() void Game::updateBullets()
{ {
for (auto &bullet : bullets_) for (auto &bullet : bullets_)
{
if (bullet->move() == BulletMoveStatus::OUT) if (bullet->move() == BulletMoveStatus::OUT)
{
getPlayer(bullet->getOwner())->decScoreMultiplier(); getPlayer(bullet->getOwner())->decScoreMultiplier();
} }
}
}
// Pinta las balas activas // Pinta las balas activas
void Game::renderBullets() void Game::renderBullets()
@@ -729,7 +782,7 @@ void Game::createItemText(int x, std::shared_ptr<Texture> texture)
const auto h = texture->getHeight(); const auto h = texture->getHeight();
const int y0 = param.game.play_area.rect.h - h; const int y0 = param.game.play_area.rect.h - h;
const int y1 = 155; const int y1 = 160 - (h / 2);
const int y2 = -h; const int y2 = -h;
// Ajusta para que no se dibuje fuera de pantalla // Ajusta para que no se dibuje fuera de pantalla
@@ -802,35 +855,44 @@ void Game::throwCoffee(int x, int y)
void Game::updateSmartSprites() void Game::updateSmartSprites()
{ {
for (auto &sprite : smart_sprites_) for (auto &sprite : smart_sprites_)
{
sprite->update(); sprite->update();
} }
}
// Pinta los SmartSprites activos // Pinta los SmartSprites activos
void Game::renderSmartSprites() void Game::renderSmartSprites()
{ {
for (auto &sprite : smart_sprites_) for (auto &sprite : smart_sprites_)
{
sprite->render(); sprite->render();
} }
}
// Actualiza los PathSprites // Actualiza los PathSprites
void Game::updatePathSprites() void Game::updatePathSprites()
{ {
for (auto &sprite : path_sprites_) for (auto &sprite : path_sprites_)
{
sprite->update(); sprite->update();
} }
}
// Pinta los PathSprites activos // Pinta los PathSprites activos
void Game::renderPathSprites() void Game::renderPathSprites()
{ {
for (auto &sprite : path_sprites_) for (auto &sprite : path_sprites_)
{
sprite->render(); sprite->render();
} }
}
// Acciones a realizar cuando el jugador muere // Acciones a realizar cuando el jugador muere
void Game::killPlayer(std::shared_ptr<Player> &player) void Game::killPlayer(std::shared_ptr<Player> &player)
{ {
if (!player->isPlaying() || player->isInvulnerable()) if (!player->isPlaying() || player->isInvulnerable())
{ // Si no está jugando o tiene inmunidad, no hace nada {
// Si no está jugando o tiene inmunidad, no hace nada
return; return;
} }
@@ -840,18 +902,22 @@ void Game::killPlayer(std::shared_ptr<Player> &player)
// Lo pierde // Lo pierde
player->removeExtraHit(); player->removeExtraHit();
throwCoffee(player->getPosX() + (player->getWidth() / 2), player->getPosY() + (player->getHeight() / 2)); throwCoffee(player->getPosX() + (player->getWidth() / 2), player->getPosY() + (player->getHeight() / 2));
JA_PlaySound(Resource::get()->getSound("coffeeout.wav")); JA_PlaySound(Resource::get()->getSound("coffee_out.wav"));
screen_->shake(); screen_->shake();
} }
else else
{ {
// Si no tiene cafes, muere // Si no tiene cafes, muere
// pauseMusic();
balloon_manager_->stopAllBalloons(); balloon_manager_->stopAllBalloons();
JA_PlaySound(Resource::get()->getSound("player_collision.wav")); JA_PlaySound(Resource::get()->getSound("player_collision.wav"));
screen_->shake(); screen_->shake();
JA_PlaySound(Resource::get()->getSound("voice_no.wav")); JA_PlaySound(Resource::get()->getSound("voice_no.wav"));
player->setPlayingState(PlayerState::DYING); player->setPlayingState(PlayerState::DYING);
if (allPlayersAreNotPlaying())
{
// No se puede subir poder de fase si no hay nadie jugando
Stage::power_can_be_added = false;
}
} }
} }
@@ -864,21 +930,29 @@ void Game::updateTimeStopped()
if (time_stopped_counter_ > 120) if (time_stopped_counter_ > 120)
{ {
if (time_stopped_counter_ % 30 == 0) if (time_stopped_counter_ % 30 == 0)
{
JA_PlaySound(Resource::get()->getSound("clock.wav")); JA_PlaySound(Resource::get()->getSound("clock.wav"));
} }
}
else else
{ {
if (time_stopped_counter_ % 15 == 0)
JA_PlaySound(Resource::get()->getSound("clock.wav"));
if (time_stopped_counter_ % 30 == 0) if (time_stopped_counter_ % 30 == 0)
{
balloon_manager_->normalColorsToAllBalloons(); balloon_manager_->normalColorsToAllBalloons();
if (time_stopped_counter_ % 30 == 15) JA_PlaySound(Resource::get()->getSound("clock.wav"));
}
else if (time_stopped_counter_ % 30 == 15)
{
balloon_manager_->reverseColorsToAllBalloons(); balloon_manager_->reverseColorsToAllBalloons();
JA_PlaySound(Resource::get()->getSound("clock.wav"));
}
} }
} }
else else
{
disableTimeStopItem(); disableTimeStopItem();
} }
}
// Actualiza el juego // Actualiza el juego
void Game::update() void Game::update()
@@ -888,16 +962,38 @@ void Game::update()
if (SDL_GetTicks() - ticks_ > TICKS_SPEED) if (SDL_GetTicks() - ticks_ > TICKS_SPEED)
{ {
ticks_ = SDL_GetTicks(); ticks_ = SDL_GetTicks();
counter_++;
updateDemo(); updateDemo();
#ifdef RECORDING #ifdef RECORDING
updateRecording(); updateRecording();
#endif #endif
updateGame(); if (!paused_)
{
switch (state_)
{
case GameState::FADE_IN:
updateGameStateFadeIn();
break;
case GameState::ENTERING_PLAYER:
updateGameStateEnteringPlayer();
break;
case GameState::SHOWING_GET_READY_MESSAGE:
updateGameStateShowingGetReadyMessage();
break;
case GameState::PLAYING:
updateGameStatePlaying();
break;
case GameState::COMPLETED:
updateGameStateCompleted();
break;
case GameState::GAME_OVER:
updateGameStateGameOver();
break;
default:
break;
}
}
checkMusicStatus();
screen_->update(); screen_->update();
globalInputs::update(); globalInputs::update();
fillCanvas(); fillCanvas();
@@ -910,13 +1006,13 @@ void Game::updateBackground()
// Si el juego está completado, se reduce la velocidad de las nubes // Si el juego está completado, se reduce la velocidad de las nubes
if (state_ == GameState::COMPLETED) if (state_ == GameState::COMPLETED)
{ {
Stage::total_power = (Stage::total_power > 400) ? (Stage::total_power - 25) : 200; Stage::total_power = (Stage::total_power > 200) ? (Stage::total_power - 25) : 200;
} }
// Calcula la velocidad en función de los globos explotados y el total de globos a explotar para acabar el juego // Calcula la velocidad en función de los globos explotados y el total de globos a explotar para acabar el juego
constexpr float clouds_initial_speed = 0.05f; constexpr float CLOUDS_INITIAL_SPEED = 0.05f;
constexpr float clouds_final_speed = 2.00f - clouds_initial_speed; constexpr float CLOUDS_FINAL_SPEED = 2.00f - CLOUDS_INITIAL_SPEED;
const float cloudsSpeed = (-clouds_initial_speed) + (-clouds_final_speed * (static_cast<float>(Stage::total_power) / total_power_to_complete_game_)); const float cloudsSpeed = (-CLOUDS_INITIAL_SPEED) + (-CLOUDS_FINAL_SPEED * (static_cast<float>(Stage::total_power) / total_power_to_complete_game_));
background_->setCloudsSpeed(cloudsSpeed); background_->setCloudsSpeed(cloudsSpeed);
// Calcula la transición de los diferentes fondos // Calcula la transición de los diferentes fondos
@@ -926,6 +1022,11 @@ void Game::updateBackground()
background_->setGradientNumber(static_cast<int>(gradient_number)); background_->setGradientNumber(static_cast<int>(gradient_number));
background_->setTransition(percent); background_->setTransition(percent);
// Calcula la posición del sol
constexpr float sun_final_power = num * 2;
background_->setSunProgression(Stage::total_power / sun_final_power);
background_->setMoonProgression(Stage::total_power / static_cast<float>(total_power_to_complete_game_));
// Actualiza el objeto // Actualiza el objeto
background_->update(); background_->update();
} }
@@ -968,7 +1069,7 @@ void Game::render()
fade_out_->render(); fade_out_->render();
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
screen_->blit(); screen_->render();
} }
// Habilita el efecto del item de detener el tiempo // Habilita el efecto del item de detener el tiempo
@@ -987,16 +1088,6 @@ void Game::disableTimeStopItem()
balloon_manager_->normalColorsToAllBalloons(); balloon_manager_->normalColorsToAllBalloons();
} }
// Comprueba si la música ha de estar sonando
void Game::checkMusicStatus()
{
// Si se ha completado el juego o los jugadores han terminado, detiene la música
if (state_ != GameState::COMPLETED && !allPlayersAreGameOver())
{
playMusic();
}
}
// Bucle para el juego // Bucle para el juego
void Game::run() void Game::run()
{ {
@@ -1144,7 +1235,6 @@ void Game::checkEvents()
pause(!demo_.enabled); pause(!demo_.enabled);
break; break;
} }
case SDL_WINDOWEVENT_FOCUS_GAINED: case SDL_WINDOWEVENT_FOCUS_GAINED:
{ {
pause(false); pause(false);
@@ -1178,7 +1268,10 @@ void Game::checkEvents()
case SDLK_3: // Activa el modo para pasar el juego automaticamente case SDLK_3: // Activa el modo para pasar el juego automaticamente
{ {
auto_pop_balloons_ = !auto_pop_balloons_; auto_pop_balloons_ = !auto_pop_balloons_;
Notifier::get()->showText({"auto_pop_balloons_ " + boolToString(auto_pop_balloons_)}); Notifier::get()->showText({"auto advance: " + boolToString(auto_pop_balloons_)});
if (auto_pop_balloons_)
balloon_manager_->destroyAllBalloons();
balloon_manager_->setDeployBalloons(!auto_pop_balloons_);
break; break;
} }
case SDLK_4: // Suelta un item case SDLK_4: // Suelta un item
@@ -1186,25 +1279,36 @@ void Game::checkEvents()
createItem(ItemType::CLOCK, players_.at(0)->getPosX(), players_.at(0)->getPosY() - 40); createItem(ItemType::CLOCK, players_.at(0)->getPosX(), players_.at(0)->getPosY() - 40);
break; break;
} }
case SDLK_5: // Crea un PathSprite case SDLK_5: // 5.000
{ {
const int x = players_.at(0)->getPosX() + (players_.at(0)->getWidth() - game_text_textures_[3]->getWidth()) / 2; const int x = players_.at(0)->getPosX() + (players_.at(0)->getWidth() - game_text_textures_[3]->getWidth()) / 2;
createItemText(x, game_text_textures_.at(3)); createItemText(x, game_text_textures_.at(2));
break; break;
} }
case SDLK_6: // Crea un mensaje case SDLK_6: // Crea un mensaje
{ {
createMessage({paths_.at(2), paths_.at(3)}, Resource::get()->getTexture("game_text_congratulations")); createMessage({paths_.at(0), paths_.at(1)}, Resource::get()->getTexture("game_text_get_ready"));
break; break;
} }
case SDLK_7: // Flash case SDLK_7: // 100.000
{ {
screen_->flash(flash_color, 3); // screen_->flash(flash_color, 3);
// tabe_->setState(TabeState::HIT);
const int x = players_.at(0)->getPosX() + (players_.at(0)->getWidth() - game_text_textures_[3]->getWidth()) / 2;
createItemText(x, game_text_textures_.at(6));
break;
break; break;
} }
case SDLK_8: case SDLK_8:
{ {
players_.at(0)->setPlayingState(PlayerState::LEAVING_SCREEN); for (auto player : players_)
{
if (player->isPlaying())
{
createItem(ItemType::COFFEE_MACHINE, player->getPosX(), param.game.game_area.rect.y - param.game.coffee_machine_h);
break;
}
}
break; break;
} }
case SDLK_9: case SDLK_9:
@@ -1217,6 +1321,8 @@ void Game::checkEvents()
} }
} }
#endif #endif
// Comprueba el cursor
Mouse::handleEvent(event);
} }
} }
@@ -1264,11 +1370,11 @@ void Game::pause(bool value)
} }
// Añade una puntuación a la tabla de records // Añade una puntuación a la tabla de records
void Game::addScoreToScoreBoard(const std::string &name, int score) void Game::addScoreToScoreBoard(const std::shared_ptr<Player> &player)
{ {
const auto entry = HiScoreEntry(trim(name), score); const auto entry = HiScoreEntry(trim(player->getRecordName()), player->getScore(), player->get1CC());
auto manager = std::make_unique<ManageHiScoreTable>(options.game.hi_score_table); auto manager = std::make_unique<ManageHiScoreTable>(options.game.hi_score_table);
manager->add(entry); options.game.last_hi_score_entry.at(player->getId() - 1) = manager->add(entry);
manager->saveToFile(asset_->get("score.bin")); manager->saveToFile(asset_->get("score.bin"));
hi_score_.name = options.game.hi_score_table.front().name; hi_score_.name = options.game.hi_score_table.front().name;
} }
@@ -1426,8 +1532,11 @@ void Game::handleFireInput(const std::shared_ptr<Player> &player, BulletType bul
: InputType::FIRE_RIGHT); : InputType::FIRE_RIGHT);
createBullet(player->getPosX() + (player->getWidth() / 2) - 6, player->getPosY() + (player->getHeight() / 2), bulletType, player->isPowerUp(), player->getId()); createBullet(player->getPosX() + (player->getWidth() / 2) - 6, player->getPosY() + (player->getHeight() / 2), bulletType, player->isPowerUp(), player->getId());
JA_PlaySound(Resource::get()->getSound("bullet.wav")); JA_PlaySound(Resource::get()->getSound("bullet.wav"));
// Establece un tiempo de espera para el próximo disparo. // Establece un tiempo de espera para el próximo disparo.
player->setFireCooldown(10); const int cooldown = player->isPowerUp() ? 5 : options.game.autofire ? 10
: 7;
player->setFireCooldown(cooldown);
} }
} }
@@ -1437,15 +1546,18 @@ void Game::handlePlayersInput()
for (const auto &player : players_) for (const auto &player : players_)
{ {
if (player->isPlaying()) if (player->isPlaying())
{ // Maneja el input de los jugadores en modo normal. {
// Maneja el input de los jugadores en modo normal.
handleNormalPlayerInput(player); handleNormalPlayerInput(player);
} }
else if (player->isContinue() || player->isWaiting()) else if (player->isContinue() || player->isWaiting())
{ // Gestiona la continuación del jugador. {
// Gestiona la continuación del jugador.
handlePlayerContinue(player); handlePlayerContinue(player);
} }
else if (player->isEnteringName() || player->isEnteringNameGameCompleted()) else if (player->isEnteringName() || player->isEnteringNameGameCompleted())
{ // Gestiona la introducción del nombre del jugador. {
// Gestiona la introducción del nombre del jugador.
handleNameInput(player); handleNameInput(player);
} }
} }
@@ -1515,16 +1627,20 @@ void Game::handlePlayerContinue(const std::shared_ptr<Player> &player)
if (input_->checkInput(InputType::START, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index)) if (input_->checkInput(InputType::START, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index))
{ {
player->setPlayingState(PlayerState::PLAYING); player->setPlayingState(PlayerState::PLAYING);
player->addCredit();
} }
// Disminuye el contador de continuación si se presiona cualquier botón de disparo. // Disminuye el contador de continuación si se presiona cualquier botón de disparo.
if (input_->checkInput(InputType::FIRE_LEFT, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index) || if (input_->checkInput(InputType::FIRE_LEFT, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index) ||
input_->checkInput(InputType::FIRE_CENTER, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index) || input_->checkInput(InputType::FIRE_CENTER, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index) ||
input_->checkInput(InputType::FIRE_RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index)) input_->checkInput(InputType::FIRE_RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index))
{
if (player->getContinueCounter() < 7)
{ {
player->decContinueCounter(); player->decContinueCounter();
} }
} }
}
// Procesa las entradas para la introducción del nombre del jugador. // Procesa las entradas para la introducción del nombre del jugador.
void Game::handleNameInput(const std::shared_ptr<Player> &player) void Game::handleNameInput(const std::shared_ptr<Player> &player)
@@ -1534,12 +1650,11 @@ void Game::handleNameInput(const std::shared_ptr<Player> &player)
input_->checkInput(InputType::FIRE_CENTER, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index) || input_->checkInput(InputType::FIRE_CENTER, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index) ||
input_->checkInput(InputType::FIRE_RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index)) input_->checkInput(InputType::FIRE_RIGHT, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index))
{ {
if (player->getRecordNamePos() == NAME_LENGHT - 1) if (player->getEnterNamePositionOverflow())
{ {
player->setInput(InputType::START); player->setInput(InputType::START);
addScoreToScoreBoard(player->getRecordName(), player->getScore()); addScoreToScoreBoard(player);
const auto status = player->getPlayingState(); player->setPlayingState(PlayerState::SHOWING_NAME);
player->setPlayingState(status == PlayerState::ENTERING_NAME ? PlayerState::CONTINUE : PlayerState::LEAVING_SCREEN);
} }
else else
{ {
@@ -1561,9 +1676,8 @@ void Game::handleNameInput(const std::shared_ptr<Player> &player)
else if (input_->checkInput(InputType::START, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index)) else if (input_->checkInput(InputType::START, INPUT_DO_NOT_ALLOW_REPEAT, options.controllers[controllerIndex].type, options.controllers[controllerIndex].index))
{ {
player->setInput(InputType::START); player->setInput(InputType::START);
addScoreToScoreBoard(player->getRecordName(), player->getScore()); addScoreToScoreBoard(player);
const auto status = player->getPlayingState(); player->setPlayingState(PlayerState::SHOWING_NAME);
player->setPlayingState(status == PlayerState::ENTERING_NAME ? PlayerState::CONTINUE : PlayerState::LEAVING_SCREEN);
} }
} }
@@ -1572,11 +1686,16 @@ void Game::initDemo(int player_id)
{ {
if (demo_.enabled) if (demo_.enabled)
{ {
// Cambia el estado del juego
setState(GameState::PLAYING);
// Aleatoriza la asignación del fichero con los datos del modo demostracion // Aleatoriza la asignación del fichero con los datos del modo demostracion
{
const auto demo1 = rand() % 2; const auto demo1 = rand() % 2;
const auto demo2 = (demo1 == 0) ? 1 : 0; const auto demo2 = (demo1 == 0) ? 1 : 0;
demo_.data.emplace_back(Resource::get()->getDemoData(demo1)); demo_.data.emplace_back(Resource::get()->getDemoData(demo1));
demo_.data.emplace_back(Resource::get()->getDemoData(demo2)); demo_.data.emplace_back(Resource::get()->getDemoData(demo2));
}
// Selecciona una pantalla al azar // Selecciona una pantalla al azar
{ {
@@ -1593,7 +1712,7 @@ void Game::initDemo(int player_id)
} }
// Activa o no al otro jugador // Activa o no al otro jugador
if (rand() % 2 == 0) if (rand() % 3 != 0)
{ {
const auto other_player_id = player_id == 1 ? 2 : 1; const auto other_player_id = player_id == 1 ? 2 : 1;
auto other_player = getPlayer(other_player_id); auto other_player = getPlayer(other_player_id);
@@ -1606,7 +1725,7 @@ void Game::initDemo(int player_id)
for (int i = 0; i < rand() % 3; ++i) for (int i = 0; i < rand() % 3; ++i)
player->giveExtraHit(); player->giveExtraHit();
player->setInvulnerable(false); player->setInvulnerable(true);
} }
// Deshabilita los sonidos // Deshabilita los sonidos
@@ -1705,7 +1824,7 @@ void Game::initPlayers(int player_id)
// Activa el jugador que coincide con el "player_id" // Activa el jugador que coincide con el "player_id"
auto player = getPlayer(player_id); auto player = getPlayer(player_id);
player->setPlayingState(PlayerState::PLAYING); player->setPlayingState((demo_.enabled) ? PlayerState::PLAYING : PlayerState::ENTERING_SCREEN);
player->setInvulnerable(false); player->setInvulnerable(false);
} }
@@ -1751,9 +1870,17 @@ void Game::updateDemo()
{ {
if (demo_.enabled) if (demo_.enabled)
{ {
balloon_manager_->setCreationTimeEnabled((balloon_manager_->getNumBalloons() == 0) ? false : true);
// Actualiza ambos fades
fade_in_->update();
fade_out_->update();
// Incrementa el contador de la demo // Incrementa el contador de la demo
if (demo_.counter < TOTAL_DEMO_DATA) if (demo_.counter < TOTAL_DEMO_DATA)
{
demo_.counter++; demo_.counter++;
}
// Activa el fundido antes de acabar con los datos de la demo // Activa el fundido antes de acabar con los datos de la demo
if (demo_.counter == TOTAL_DEMO_DATA - 200) if (demo_.counter == TOTAL_DEMO_DATA - 200)
@@ -1791,41 +1918,87 @@ void Game::updateRecording()
} }
#endif #endif
// Actualiza las variables durante el transcurso normal del juego // Actualiza las variables durante dicho estado
void Game::updateGame() void Game::updateGameStateFadeIn()
{ {
if (!paused_) fade_in_->update();
updateScoreboard();
updateBackground();
if (fade_in_->hasEnded())
{
setState(GameState::ENTERING_PLAYER);
balloon_manager_->createTwoBigBalloons();
evaluateAndSetMenace();
}
}
// Actualiza las variables durante dicho estado
void Game::updateGameStateEnteringPlayer()
{
balloon_manager_->update();
updatePlayers();
updateScoreboard();
updateBackground();
for (auto player : players_)
{
if (player->isPlaying())
{
setState(GameState::SHOWING_GET_READY_MESSAGE);
createMessage({paths_.at(0), paths_.at(1)}, Resource::get()->getTexture("game_text_get_ready"));
JA_PlaySound(Resource::get()->getSound("voice_get_ready.wav"));
}
}
}
// Actualiza las variables durante dicho estado
void Game::updateGameStateShowingGetReadyMessage()
{
balloon_manager_->update();
updatePathSprites();
updatePlayers();
updateBullets();
updateScoreboard();
updateBackground();
freePathSprites();
if (path_sprites_.size() == 0)
{
setState(GameState::PLAYING);
}
if (counter_ == 100)
{
playMusic();
}
++counter_;
}
// Actualiza las variables durante el transcurso normal del juego
void Game::updateGameStatePlaying()
{ {
#ifdef DEBUG #ifdef DEBUG
if (auto_pop_balloons_ && state_ == GameState::PLAYING) if (auto_pop_balloons_)
{ {
Stage::addPower(5); Stage::addPower(5);
} }
#endif #endif
fade_in_->update();
fade_out_->update();
updatePlayers(); updatePlayers();
checkPlayersStatusPlaying(); checkPlayersStatusPlaying();
updateScoreboard(); updateScoreboard();
updateBackground(); updateBackground();
balloon_manager_->update(); balloon_manager_->update();
tabe_->update(); tabe_->update();
moveBullets(); updateBullets();
updateItems(); updateItems();
updateStage(); updateStage();
updateFadeInState();
updateGameOverState();
updateCompletedState();
updateSmartSprites(); updateSmartSprites();
updatePathSprites(); updatePathSprites();
updateTimeStopped(); updateTimeStopped();
updateHelper(); updateHelper();
checkBulletBalloonCollision(); checkBulletCollision();
updateMenace(); updateMenace();
checkAndUpdateBalloonSpeed(); checkAndUpdateBalloonSpeed();
checkState(); checkState();
cleanVectors(); cleanVectors();
} playMusic();
} }
// Vacía los vectores de elementos deshabilitados // Vacía los vectores de elementos deshabilitados
@@ -1886,3 +2059,10 @@ void Game::checkAndUpdateBalloonSpeed()
} }
} }
} }
// Cambia el estado del juego
void Game::setState(GameState state)
{
state_ = state;
counter_ = 0;
}

View File

@@ -67,6 +67,8 @@ private:
enum class GameState enum class GameState
{ {
FADE_IN, FADE_IN,
ENTERING_PLAYER,
SHOWING_GET_READY_MESSAGE,
PLAYING, PLAYING,
COMPLETED, COMPLETED,
GAME_OVER, GAME_OVER,
@@ -197,11 +199,8 @@ private:
// Comprueba si hay cambio de fase y actualiza las variables // Comprueba si hay cambio de fase y actualiza las variables
void updateStage(); void updateStage();
// Actualiza el estado de fade in
void updateFadeInState();
// Actualiza el estado de fin de la partida // Actualiza el estado de fin de la partida
void updateGameOverState(); void updateGameStateGameOver();
// Destruye todos los items // Destruye todos los items
void destroyAllItems(); void destroyAllItems();
@@ -212,11 +211,11 @@ private:
// Comprueba la colisión entre el jugador y los items // Comprueba la colisión entre el jugador y los items
void checkPlayerItemCollision(std::shared_ptr<Player> &player); void checkPlayerItemCollision(std::shared_ptr<Player> &player);
// Comprueba la colisión entre las balas y los globos // Comprueba y procesa la colisión de las balas
void checkBulletBalloonCollision(); void checkBulletCollision();
// Mueve las balas activas // Mueve las balas activas
void moveBullets(); void updateBullets();
// Pinta las balas activas // Pinta las balas activas
void renderBullets(); void renderBullets();
@@ -311,11 +310,8 @@ private:
// Pausa el juego // Pausa el juego
void pause(bool value); void pause(bool value);
// Comprueba si la música ha de estar sonando
void checkMusicStatus();
// Añade una puntuación a la tabla de records // Añade una puntuación a la tabla de records
void addScoreToScoreBoard(const std::string &name, int score); void addScoreToScoreBoard(const std::shared_ptr<Player> &player);
// Saca del estado de GAME OVER al jugador si el otro está activo // Saca del estado de GAME OVER al jugador si el otro está activo
void checkAndUpdatePlayerStatus(int active_player_index, int inactive_player_index); void checkAndUpdatePlayerStatus(int active_player_index, int inactive_player_index);
@@ -392,11 +388,20 @@ private:
// Actualiza las variables durante el modo de grabación // Actualiza las variables durante el modo de grabación
void updateRecording(); void updateRecording();
#endif #endif
// Actualiza las variables durante dicho estado
void updateGameStateFadeIn();
// Actualiza las variables durante dicho estado
void updateGameStateEnteringPlayer();
// Actualiza las variables durante dicho estado
void updateGameStateShowingGetReadyMessage();
// Actualiza las variables durante el transcurso normal del juego // Actualiza las variables durante el transcurso normal del juego
void updateGame(); void updateGameStatePlaying();
// Gestiona eventos para el estado del final del juego // Gestiona eventos para el estado del final del juego
void updateCompletedState(); void updateGameStateCompleted();
// Comprueba el estado del juego // Comprueba el estado del juego
void checkState(); void checkState();
@@ -413,6 +418,9 @@ private:
// Actualiza la velocidad de los globos en funcion del poder acumulado de la fase // Actualiza la velocidad de los globos en funcion del poder acumulado de la fase
void checkAndUpdateBalloonSpeed(); void checkAndUpdateBalloonSpeed();
// Cambia el estado del juego
void setState(GameState state);
public: public:
// Constructor // Constructor
Game(int playerID, int current_stage, bool demo); Game(int playerID, int current_stage, bool demo);

View File

@@ -1,15 +1,15 @@
#include "game_logo.h" #include "game_logo.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL #include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL
#include <algorithm> // Para max #include <algorithm> // Para max
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
#include "jail_audio.h" // Para JA_PlaySound #include "jail_audio.h" // Para JA_PlaySound
#include "param.h" // Para Param, param, ParamGame, ParamTitle #include "param.h" // Para Param, param, ParamGame, ParamTitle
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
#include "screen.h" // Para Screen
#include "smart_sprite.h" // Para SmartSprite #include "smart_sprite.h" // Para SmartSprite
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "screen.h" #include "utils.h" // Para Color
constexpr int ZOOM_FACTOR = 5; constexpr int ZOOM_FACTOR = 5;
constexpr int FLASH_DELAY = 3; constexpr int FLASH_DELAY = 3;

View File

@@ -1,15 +1,16 @@
#include "global_inputs.h" #include "global_inputs.h"
#include <string> // Para operator+, string #include <string> // Para operator+, string, to_string, basic_string
#include "input.h" // Para Input, InputType, INPUT_DO_NOT_ALLOW_REPEAT #include <vector> // Para vector
#include "asset.h" #include "asset.h" // Para Asset
#include "jail_audio.h" // Para JA_EnableMusic, JA_EnableSound #include "input.h" // Para Input, InputDeviceToUse, InputType, INPU...
#include "lang.h" // Para getText #include "jail_audio.h" // Para JA_SetMusicVolume, JA_SetSoundVolume
#include "lang.h" // Para Code, getText, change, loadFromFile
#include "notifier.h" // Para Notifier #include "notifier.h" // Para Notifier
#include "on_screen_help.h" // Para OnScreenHelp #include "on_screen_help.h" // Para OnScreenHelp
#include "options.h" // Para Options, OptionsAudio, options, OptionsM... #include "options.h" // Para Options, options, OptionsGame, OptionsAudio
#include "screen.h" // Para Screen, ScreenVideoMode
#include "section.h" // Para Name, Options, name, options #include "section.h" // Para Name, Options, name, options
#include "utils.h" // Para boolToOnOff, stringInVector #include "utils.h" // Para boolToOnOff, stringInVector
#include "screen.h"
namespace globalInputs namespace globalInputs
{ {

View File

@@ -1,4 +1,3 @@
#include <vector>
namespace globalInputs namespace globalInputs
{ {
extern int service_pressed_counter; extern int service_pressed_counter;

View File

@@ -4,22 +4,28 @@
#include <SDL2/SDL_pixels.h> // Para SDL_PIXELFORMAT_RGBA8888 #include <SDL2/SDL_pixels.h> // Para SDL_PIXELFORMAT_RGBA8888
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks #include <SDL2/SDL_timer.h> // Para SDL_GetTicks
#include <SDL2/SDL_video.h> // Para SDL_WINDOWEVENT_SIZE_CHANGED #include <SDL2/SDL_video.h> // Para SDL_WINDOWEVENT_SIZE_CHANGED
#include <stdlib.h> // Para rand
#include <algorithm> // Para max #include <algorithm> // Para max
#include <functional> // Para function
#include <vector> // Para vector #include <vector> // Para vector
#include "background.h" // Para Background #include "background.h" // Para Background
#include "fade.h" // Para Fade, FadeMode, FadeType #include "fade.h" // Para Fade, FadeMode, FadeType
#include "global_inputs.h" // Para check #include "global_inputs.h" // Para check, update
#include "input.h" // Para Input #include "input.h" // Para Input
#include "jail_audio.h" // Para JA_GetMusicState, JA_Music_state #include "jail_audio.h" // Para JA_GetMusicState, JA_Music_state
#include "lang.h" // Para getText #include "lang.h" // Para getText
#include "manage_hiscore_table.h" // Para HiScoreEntry #include "manage_hiscore_table.h" // Para HiScoreEntry
#include "mouse.h" // Para handleEvent
#include "options.h" // Para Options, OptionsGame, options #include "options.h" // Para Options, OptionsGame, options
#include "param.h" // Para Param, param, ParamGame, ParamFade #include "param.h" // Para Param, param, ParamGame, ParamFade
#include "path_sprite.h" // Para PathSprite, Path, PathType
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "section.h" // Para Name, name, Options, options #include "section.h" // Para Name, name, Options, options, Attr...
#include "text.h" // Para Text, TEXT_CENTER, TEXT_SHADOW #include "sprite.h" // Para Sprite
#include "utils.h" // Para Color, Zone, fade_color, orange_color #include "text.h" // Para Text, TEXT_COLOR, TEXT_SHADOW
#include "texture.h" // Para Texture
#include "utils.h" // Para Color, easeOutQuint, fade_color
// Constructor // Constructor
HiScoreTable::HiScoreTable() HiScoreTable::HiScoreTable()
@@ -27,35 +33,26 @@ HiScoreTable::HiScoreTable()
backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
fade_(std::make_unique<Fade>()), fade_(std::make_unique<Fade>()),
background_(std::make_unique<Background>()), background_(std::make_unique<Background>()),
text_(Resource::get()->getText("smb2")),
counter_(0), counter_(0),
ticks_(0), ticks_(0),
view_area_({0, 0, param.game.width, param.game.height}), view_area_({0, 0, param.game.width, param.game.height}),
fade_mode_(FadeMode::IN) fade_mode_(FadeMode::IN),
background_fade_color_(Color(0, 0, 0))
{ {
// Inicializa el resto de variables // Inicializa el resto
section::name = section::Name::HI_SCORE_TABLE; section::name = section::Name::HI_SCORE_TABLE;
// Inicializa objetos
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
background_->setPos(param.game.game_area.rect); initFade();
background_->setCloudsSpeed(-0.1f); initBackground();
background_->setGradientNumber(1); iniEntryColors();
background_->setTransition(0.8f); createSprites();
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();
} }
// Destructor // Destructor
HiScoreTable::~HiScoreTable() HiScoreTable::~HiScoreTable()
{ {
SDL_DestroyTexture(backbuffer_); SDL_DestroyTexture(backbuffer_);
options.game.clear_last_hi_score_entries();
} }
// Actualiza las variables // Actualiza las variables
@@ -74,6 +71,9 @@ void HiScoreTable::update()
JA_PlayMusic(Resource::get()->getMusic("title.ogg")); JA_PlayMusic(Resource::get()->getMusic("title.ogg"));
} }
// Actualiza las posiciones de los sprites de texto
updateSprites();
// Actualiza el objeto screen // Actualiza el objeto screen
Screen::get()->update(); Screen::get()->update();
@@ -91,7 +91,7 @@ void HiScoreTable::update()
if (counter_ == 150) if (counter_ == 150)
{ {
background_->setColor(Color(0, 0, 0)); background_->setColor(background_fade_color_.darken());
background_->setAlpha(96); background_->setAlpha(96);
} }
@@ -99,19 +99,15 @@ void HiScoreTable::update()
{ {
fade_->activate(); fade_->activate();
} }
// Dibuja los sprites en la textura
fillTexture();
} }
} }
// Crea el contenido de la textura con la lista de puntuaciones // Dibuja los sprites en la textura
void HiScoreTable::fillTexture() void HiScoreTable::fillTexture()
{ {
// 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 // Pinta en el backbuffer el texto y los sprites
auto temp = SDL_GetRenderTarget(renderer_); auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_); SDL_SetRenderTarget(renderer_, backbuffer_);
@@ -119,22 +115,12 @@ void HiScoreTable::fillTexture()
SDL_RenderClear(renderer_); SDL_RenderClear(renderer_);
// Escribe el texto: Mejores puntuaciones // Escribe el texto: Mejores puntuaciones
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); header_->render();
// Escribe los nombres de la tabla de puntuaciones // Escribe los nombres de la tabla de puntuaciones
for (int i = 0; i < max_names; ++i) for (auto const &entry : entry_names_)
{ {
const auto name_lenght = options.game.hi_score_table[i].name.length(); entry->render();
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 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 // Cambia el destino de renderizado
@@ -163,14 +149,12 @@ void HiScoreTable::render()
fade_->render(); fade_->render();
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
Screen::get()->blit(); Screen::get()->render();
} }
// Recarga todas las texturas // Recarga todas las texturas
void HiScoreTable::reloadTextures() void HiScoreTable::reloadTextures()
{ {
text_->reLoadTexture();
fillTexture();
} }
// Comprueba los eventos // Comprueba los eventos
@@ -196,6 +180,9 @@ void HiScoreTable::checkEvents()
reloadTextures(); reloadTextures();
} }
} }
// Comprueba el cursor
Mouse::handleEvent(event);
} }
} }
@@ -269,3 +256,212 @@ std::string HiScoreTable::format(int number)
return result; return result;
} }
// Crea los sprites con los textos
void HiScoreTable::createSprites()
{
auto header_text = Resource::get()->getText("04b_25_grey");
auto entry_text = Resource::get()->getText("smb2");
// Obtiene el tamaño de la textura
int backbuffer_width;
int backbuffer_height;
SDL_QueryTexture(backbuffer_, nullptr, nullptr, &backbuffer_width, &backbuffer_height);
constexpr int entry_lenght = 22;
constexpr int max_names = 10;
const int space_between_header = entry_text->getCharacterSize() * 4;
const int space_between_lines = entry_text->getCharacterSize() * 2;
const int size = space_between_header + space_between_lines * (max_names - 1) + entry_text->getCharacterSize();
const int first_line = (param.game.height - size) / 2;
// Crea el sprite para el texto de cabecera
header_ = std::make_unique<Sprite>(header_text->writeDXToTexture(TEXT_COLOR, lang::getText(42), -2, background_fade_color_.getInverse().lighten(25)));
header_->setPosition(param.game.game_area.center_x - (header_->getWidth() / 2), first_line);
// Crea los sprites para las entradas en la tabla de puntuaciones
const int animation = rand() % 4;
const std::string sample_line(entry_lenght + 3, ' ');
auto sample_entry = std::make_unique<Sprite>(entry_text->writeDXToTexture(TEXT_SHADOW, sample_line, 1, orange_color, 1, shdw_txt_color));
const auto entry_width = sample_entry->getWidth();
for (int i = 0; i < max_names; ++i)
{
const auto table_position = format(i + 1) + ". ";
const auto score = format(options.game.hi_score_table.at(i).score);
const auto num_dots = entry_lenght - options.game.hi_score_table.at(i).name.size() - score.size();
const auto one_cc = options.game.hi_score_table.at(i).one_credit_complete ? " }" : "";
std::string dots;
for (int j = 0; j < (int)num_dots; ++j)
{
dots = dots + ".";
}
const auto line = table_position + options.game.hi_score_table.at(i).name + dots + score + one_cc;
entry_names_.emplace_back(std::make_shared<PathSprite>(entry_text->writeDXToTexture(TEXT_SHADOW, line, 1, orange_color, 1, shdw_txt_color)));
const int default_pos_x = (backbuffer_width - entry_width) / 2;
const int pos_x = (i < 9) ? default_pos_x : default_pos_x - entry_text->getCharacterSize();
const int pos_y = (i * space_between_lines) + first_line + space_between_header;
constexpr int steps = 80;
switch (animation)
{
case 0: // Ambos lados alternativamente
{
if (i % 2 == 0)
{
entry_names_.back()->addPath(-entry_names_.back()->getWidth(), pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
entry_names_.back()->setPosition(-entry_names_.back()->getWidth(), 0);
}
else
{
entry_names_.back()->addPath(backbuffer_width, pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
entry_names_.back()->setPosition(backbuffer_width, 0);
}
break;
}
case 1: // Entran por la izquierda
{
entry_names_.back()->addPath(-entry_names_.back()->getWidth(), pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
entry_names_.back()->setPosition(-entry_names_.back()->getWidth(), 0);
break;
}
case 2: // Entran por la derecha
{
entry_names_.back()->addPath(backbuffer_width, pos_x, PathType::HORIZONTAL, pos_y, steps, easeOutQuint);
entry_names_.back()->setPosition(backbuffer_width, 0);
break;
}
case 3: // Entran desde la parte inferior
{
entry_names_.back()->addPath(backbuffer_height, pos_y, PathType::VERTICAL, pos_x, steps, easeOutQuint);
entry_names_.back()->setPosition(0, backbuffer_height);
}
default:
break;
}
}
}
// Actualiza las posiciones de los sprites de texto
void HiScoreTable::updateSprites()
{
constexpr int init_counter = 190;
const int counter_between_entries = 16;
if (counter_ >= init_counter)
{
const int counter2 = counter_ - init_counter;
if (counter2 % counter_between_entries == 0)
{
int index = counter2 / counter_between_entries;
if (index < static_cast<int>(entry_names_.size()))
{
entry_names_.at(index)->enable();
}
}
}
for (auto const &entry : entry_names_)
{
entry->update();
}
glowEntryNames();
}
// Inicializa el fade
void HiScoreTable::initFade()
{
fade_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_->setType(FadeType::RANDOM_SQUARE);
fade_->setPostDuration(param.fade.post_duration);
fade_->setMode(fade_mode_);
fade_->activate();
}
// Inicializa el fondo
void HiScoreTable::initBackground()
{
background_->setPos(param.game.game_area.rect);
background_->setCloudsSpeed(-0.1f);
const int lucky = rand() % 3;
switch (lucky)
{
case 0: // Fondo verde
{
background_->setGradientNumber(2);
background_->setTransition(0.0f);
background_->setSunProgression(1.0f);
background_->setMoonProgression(0.0f);
background_fade_color_ = green_sky_color;
break;
}
case 1: // Fondo naranja
{
background_->setGradientNumber(1);
background_->setTransition(0.0f);
background_->setSunProgression(0.65f);
background_->setMoonProgression(0.0f);
background_fade_color_ = pink_sky_color;
break;
}
case 2: // Fondo azul
{
background_->setGradientNumber(0);
background_->setTransition(0.0f);
background_->setSunProgression(0.0f);
background_->setMoonProgression(0.0f);
background_fade_color_ = blue_sky_color;
break;
}
default:
break;
}
}
// Obtiene un color del vector de colores de entradas
Color HiScoreTable::getEntryColor(int counter_)
{
int cycle_length = entry_colors_.size() * 2 - 2;
size_t n = counter_ % cycle_length;
size_t index;
if (n < entry_colors_.size())
{
index = n; // Avanza: 0,1,2,3
}
else
{
index = 2 * (entry_colors_.size() - 1) - n; // Retrocede: 2,1
}
return entry_colors_[index];
}
// Inicializa los colores de las entradas
void HiScoreTable::iniEntryColors()
{
entry_colors_.clear();
entry_colors_.emplace_back(background_fade_color_.getInverse().lighten(75));
entry_colors_.emplace_back(background_fade_color_.getInverse().lighten(50));
entry_colors_.emplace_back(background_fade_color_.getInverse().lighten(25));
entry_colors_.emplace_back(background_fade_color_.getInverse());
}
// Hace brillar los nombres de la tabla de records
void HiScoreTable::glowEntryNames()
{
const Color entry_color = getEntryColor(counter_ / 5);
for (const auto& entry_index : options.game.last_hi_score_entry)
{
if (entry_index != -1)
{
entry_names_.at(entry_index)->getTexture()->setColor(entry_color);
}
}
}

View File

@@ -1,14 +1,18 @@
#pragma once #pragma once
#include <SDL2/SDL_rect.h> // para SDL_Rect #include <SDL2/SDL_rect.h> // Para SDL_Rect
#include <SDL2/SDL_render.h> // para SDL_Renderer, SDL_Texture #include <SDL2/SDL_render.h> // Para SDL_Renderer, SDL_Texture
#include <SDL2/SDL_stdinc.h> // para Uint16, Uint32, Uint8 #include <SDL2/SDL_stdinc.h> // Para Uint16, Uint32, Uint8
#include <memory> // para unique_ptr #include <memory> // Para unique_ptr, shared_ptr
#include <string> // para string #include <string> // Para string
class Background; // lines 8-8 #include <vector> // Para vector
class Fade; // lines 9-9 #include "utils.h"
class Text; // lines 10-10 class Background; // lines 10-10
enum class FadeMode : Uint8; // lines 11-11 class Fade; // lines 11-11
class PathSprite;
class Sprite;
enum class FadeMode : Uint8; // lines 13-13
struct Path;
/* /*
Esta clase gestiona un estado del programa. Se encarga de mostrar la tabla con las puntuaciones Esta clase gestiona un estado del programa. Se encarga de mostrar la tabla con las puntuaciones
@@ -33,13 +37,17 @@ private:
std::unique_ptr<Fade> fade_; // Objeto para renderizar fades std::unique_ptr<Fade> fade_; // Objeto para renderizar fades
std::unique_ptr<Background> background_; // Objeto para dibujar el fondo del juego std::unique_ptr<Background> background_; // Objeto para dibujar el fondo del juego
std::shared_ptr<Text> text_; // Objeto para escribir texto std::unique_ptr<Sprite> header_; // Sprite con la cabecera del texto
std::vector<std::shared_ptr<PathSprite>> entry_names_; // Lista con los spritres de cada uno de los nombres de la tabla de records
std::vector<Path> paths_; // Vector con los recorridos precalculados
// Variables // Variables
Uint16 counter_; // Contador Uint16 counter_ = 0; // Contador
Uint32 ticks_; // Contador de ticks para ajustar la velocidad del programa Uint32 ticks_; // Contador de ticks para ajustar la velocidad del programa
SDL_Rect view_area_; // Parte de la textura que se muestra en pantalla SDL_Rect view_area_; // Parte de la textura que se muestra en pantalla
FadeMode fade_mode_; // Modo de fade a utilizar FadeMode fade_mode_; // Modo de fade a utilizar
Color background_fade_color_; // Color de atenuación del fondo
std::vector<Color> entry_colors_; // Colores para destacar las entradas en la tabla
// Actualiza las variables // Actualiza las variables
void update(); void update();
@@ -56,7 +64,7 @@ private:
// Convierte un entero a un string con separadores de miles // Convierte un entero a un string con separadores de miles
std::string format(int number); std::string format(int number);
// Crea el contenido de la textura con la lista de puntuaciones // Dibuja los sprites en la textura
void fillTexture(); void fillTexture();
// Recarga todas las texturas // Recarga todas las texturas
@@ -65,6 +73,27 @@ private:
// Gestiona el fade // Gestiona el fade
void updateFade(); void updateFade();
// Crea los sprites con los textos
void createSprites();
// Actualiza las posiciones de los sprites de texto
void updateSprites();
// Inicializa el fade
void initFade();
// Inicializa el fondo
void initBackground();
// Obtiene un color del vector de colores de entradas
Color getEntryColor(int counter_);
// Inicializa los colores de las entradas
void iniEntryColors();
// Hace brillar los nombres de la tabla de records
void glowEntryNames();
public: public:
// Constructor // Constructor
HiScoreTable(); HiScoreTable();

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,11 +16,12 @@
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "utils.h" // Para Zone, BLOCK, Color, bg_color #include "utils.h" // Para Zone, BLOCK, Color, bg_color
#include "writer.h" // Para Writer #include "writer.h" // Para Writer
#include "mouse.h"
// Constructor // Constructor
Intro::Intro() Intro::Intro()
: texture_(Resource::get()->getTexture("intro.png")), : texture_(Resource::get()->getTexture("intro.png")),
text_(Resource::get()->getText("nokia")) text_(Resource::get()->getText("04b_25_metal"))
{ {
// Inicializa variables // Inicializa variables
@@ -96,7 +97,7 @@ Intro::Intro()
auto w = std::make_unique<Writer>(text_); auto w = std::make_unique<Writer>(text_);
w->setPosX(BLOCK * 0); w->setPosX(BLOCK * 0);
w->setPosY(param.game.height - (BLOCK * 6)); w->setPosY(param.game.height - (BLOCK * 6));
w->setKerning(-1); w->setKerning(-2);
w->setEnabled(false); w->setEnabled(false);
w->setFinishedCounter(180); w->setFinishedCounter(180);
texts_.push_back(std::move(w)); texts_.push_back(std::move(w));
@@ -169,13 +170,18 @@ void Intro::checkEvents()
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:
{ {
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
{
reloadTextures(); reloadTextures();
}
break; break;
} }
default: default:
break; break;
} }
// Comprueba el cursor
Mouse::handleEvent(event);
} }
} }
@@ -409,7 +415,7 @@ void Intro::render()
} }
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
Screen::get()->blit(); Screen::get()->render();
} }
// Bucle principal // Bucle principal

View File

@@ -14,10 +14,10 @@ Item::Item(ItemType type, float x, float y, SDL_Rect &play_area, std::shared_ptr
{ {
case ItemType::COFFEE_MACHINE: case ItemType::COFFEE_MACHINE:
{ {
width_ = 28; width_ = param.game.coffee_machine_w;
height_ = 37; height_ = param.game.coffee_machine_h;
pos_x_ = ((static_cast<int>(x) + (play_area.w / 2)) % (play_area.w - width_ - 5)) + 2; pos_x_ = ((static_cast<int>(x) + (play_area.w / 2)) % (play_area.w - width_ - 5)) + 2;
pos_y_ = -height_; pos_y_ = y;
vel_x_ = 0.0f; vel_x_ = 0.0f;
vel_y_ = -0.1f; vel_y_ = -0.1f;
accel_y_ = 0.1f; accel_y_ = 0.1f;
@@ -26,8 +26,8 @@ Item::Item(ItemType type, float x, float y, SDL_Rect &play_area, std::shared_ptr
} }
default: default:
{ {
width_ = 20; width_ = param.game.item_size;
height_ = 20; height_ = param.game.item_size;
pos_x_ = x; pos_x_ = x;
pos_y_ = y; pos_y_ = y;
vel_x_ = -1.0f + ((rand() % 5) * 0.5f); vel_x_ = -1.0f + ((rand() % 5) * 0.5f);

View File

@@ -22,8 +22,9 @@ enum class ItemType : int
PACMAR = 3, /**< Pacman */ PACMAR = 3, /**< Pacman */
CLOCK = 4, /**< Reloj */ CLOCK = 4, /**< Reloj */
COFFEE = 5, /**< Café */ COFFEE = 5, /**< Café */
COFFEE_MACHINE = 6,/**< Máquina de café */ DEBIAN = 6, /**< Debian */
NONE = 7, /**< Ninguno */ COFFEE_MACHINE = 7,/**< Máquina de café */
NONE = 8, /**< Ninguno */
}; };
/** /**

View File

@@ -1,24 +1,30 @@
#ifndef JA_USESDLMIXER #ifndef JA_USESDLMIXER
#include "jail_audio.h" #include "jail_audio.h"
#include "stb_vorbis.c" #include <SDL2/SDL_rwops.h> // Para SDL_RWFromMem
#include <SDL2/SDL.h> #include <SDL2/SDL_timer.h> // Para SDL_GetTicks
#include <stdio.h> #include <stdint.h> // Para uint8_t, uint32_t
#include <stdio.h> // Para NULL, fseek, fclose, fopen, fread, ftell
#include <stdlib.h> // Para free, malloc
#include "stb_vorbis.c" // Para stb_vorbis_decode_memory
#define JA_MAX_SIMULTANEOUS_CHANNELS 20 #define JA_MAX_SIMULTANEOUS_CHANNELS 20
struct JA_Sound_t { struct JA_Sound_t
{
Uint32 length{0}; Uint32 length{0};
Uint8 *buffer{NULL}; Uint8 *buffer{NULL};
}; };
struct JA_Channel_t { struct JA_Channel_t
{
JA_Sound_t *sound; JA_Sound_t *sound;
int pos{0}; int pos{0};
int times{0}; int times{0};
JA_Channel_state state{JA_CHANNEL_FREE}; JA_Channel_state state{JA_CHANNEL_FREE};
}; };
struct JA_Music_t { struct JA_Music_t
{
int samples{0}; int samples{0};
Uint32 length{0}; Uint32 length{0};
int pos{0}; int pos{0};
@@ -44,18 +50,24 @@ int fade_start_time;
int fade_duration; int fade_duration;
int fade_initial_volume; int fade_initial_volume;
void audioCallback(void * userdata, uint8_t * stream, int len) { void audioCallback(void *userdata, uint8_t *stream, int len)
{
SDL_memset(stream, 0, len); SDL_memset(stream, 0, len);
if (current_music != NULL && current_music->state == JA_MUSIC_PLAYING) { if (current_music != NULL && current_music->state == JA_MUSIC_PLAYING)
{
int volume = JA_musicVolume; int volume = JA_musicVolume;
if (fading) { if (fading)
{
int time = SDL_GetTicks(); int time = SDL_GetTicks();
if (time > (fade_start_time+fade_duration)) { if (time > (fade_start_time + fade_duration))
{
fading = false; fading = false;
current_music->pos = 0; current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
volume = 0; volume = 0;
} else { }
else
{
const int time_passed = time - fade_start_time; const int time_passed = time - fade_start_time;
const float percent = (float)time_passed / (float)fade_duration; const float percent = (float)time_passed / (float)fade_duration;
volume = JA_musicVolume * (1.0 - percent); volume = JA_musicVolume * (1.0 - percent);
@@ -64,29 +76,41 @@ void audioCallback(void * userdata, uint8_t * stream, int len) {
const int size = SDL_min(len, current_music->length - current_music->pos); const int size = SDL_min(len, current_music->length - current_music->pos);
SDL_MixAudioFormat(stream, (Uint8 *)(current_music->output) + current_music->pos, AUDIO_S16, size, volume); SDL_MixAudioFormat(stream, (Uint8 *)(current_music->output) + current_music->pos, AUDIO_S16, size, volume);
current_music->pos += size; current_music->pos += size;
if (size < len) { if (size < len)
if (current_music->times != 0) { {
if (current_music->times != 0)
{
SDL_MixAudioFormat(stream + size, (Uint8 *)current_music->output, AUDIO_S16, len - size, volume); SDL_MixAudioFormat(stream + size, (Uint8 *)current_music->output, AUDIO_S16, len - size, volume);
current_music->pos = len - size; current_music->pos = len - size;
if (current_music->times > 0) current_music->times--; if (current_music->times > 0)
} else { current_music->times--;
}
else
{
current_music->pos = 0; current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
} }
} }
} }
// Mixar els channels mi amol // Mixar els channels mi amol
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
if (channels[i].state == JA_CHANNEL_PLAYING) { {
if (channels[i].state == JA_CHANNEL_PLAYING)
{
const int size = SDL_min(len, channels[i].sound->length - channels[i].pos); const int size = SDL_min(len, channels[i].sound->length - channels[i].pos);
SDL_MixAudioFormat(stream, channels[i].sound->buffer + channels[i].pos, AUDIO_S16, size, JA_soundVolume); SDL_MixAudioFormat(stream, channels[i].sound->buffer + channels[i].pos, AUDIO_S16, size, JA_soundVolume);
channels[i].pos += size; channels[i].pos += size;
if (size < len) { if (size < len)
if (channels[i].times != 0) { {
if (channels[i].times != 0)
{
SDL_MixAudioFormat(stream + size, channels[i].sound->buffer, AUDIO_S16, len - size, JA_soundVolume); SDL_MixAudioFormat(stream + size, channels[i].sound->buffer, AUDIO_S16, len - size, JA_soundVolume);
channels[i].pos = len - size; channels[i].pos = len - size;
if (channels[i].times > 0) channels[i].times--; if (channels[i].times > 0)
} else { channels[i].times--;
}
else
{
JA_StopChannel(i); JA_StopChannel(i);
} }
} }
@@ -96,30 +120,21 @@ void audioCallback(void * userdata, uint8_t * stream, int len) {
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels) void JA_Init(const int freq, const SDL_AudioFormat format, const int channels)
{ {
#ifdef DEBUG
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
#endif
SDL_Log("Iniciant JailAudio...");
JA_freq = freq; JA_freq = freq;
JA_format = format; JA_format = format;
JA_channels = channels; JA_channels = channels;
SDL_AudioSpec audioSpec{JA_freq, JA_format, JA_channels, 0, 1024, 0, 0, audioCallback, NULL}; SDL_AudioSpec audioSpec{JA_freq, JA_format, JA_channels, 0, 1024, 0, 0, audioCallback, NULL};
if (sdlAudioDevice != 0) SDL_CloseAudioDevice(sdlAudioDevice); if (sdlAudioDevice != 0)
SDL_CloseAudioDevice(sdlAudioDevice);
sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0); sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0);
if (sdlAudioDevice==0)
{
SDL_Log("FAILED!\n");
SDL_Log("Failed to initialize SDL audio!\n");
} else {
SDL_Log("OK!\n");
}
SDL_PauseAudioDevice(sdlAudioDevice, 0); SDL_PauseAudioDevice(sdlAudioDevice, 0);
} }
void JA_Quit() { void JA_Quit()
{
SDL_PauseAudioDevice(sdlAudioDevice, 1); SDL_PauseAudioDevice(sdlAudioDevice, 1);
if (sdlAudioDevice != 0) SDL_CloseAudioDevice(sdlAudioDevice); if (sdlAudioDevice != 0)
SDL_CloseAudioDevice(sdlAudioDevice);
sdlAudioDevice = 0; sdlAudioDevice = 0;
} }
@@ -134,8 +149,8 @@ JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length)
SDL_AudioCVT cvt; SDL_AudioCVT cvt;
SDL_BuildAudioCVT(&cvt, AUDIO_S16, chan, samplerate, JA_format, JA_channels, JA_freq); SDL_BuildAudioCVT(&cvt, AUDIO_S16, chan, samplerate, JA_format, JA_channels, JA_freq);
SDL_Log("Music length: %f\n", float(music->samples)/float(JA_freq)); if (cvt.needed)
if (cvt.needed) { {
cvt.len = music->samples * chan * 2; cvt.len = music->samples * chan * 2;
music->length = cvt.len; music->length = cvt.len;
cvt.buf = (Uint8 *)SDL_malloc(cvt.len * cvt.len_mult); cvt.buf = (Uint8 *)SDL_malloc(cvt.len * cvt.len_mult);
@@ -144,6 +159,7 @@ JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length)
free(music->output); free(music->output);
music->output = (short *)cvt.buf; music->output = (short *)cvt.buf;
} }
music->length = music->samples * chan * 2;
music->pos = 0; music->pos = 0;
music->state = JA_MUSIC_STOPPED; music->state = JA_MUSIC_STOPPED;
@@ -158,7 +174,8 @@ JA_Music_t *JA_LoadMusic(const char* filename)
long fsize = ftell(f); long fsize = ftell(f);
fseek(f, 0, SEEK_SET); fseek(f, 0, SEEK_SET);
Uint8 *buffer = (Uint8 *)malloc(fsize + 1); Uint8 *buffer = (Uint8 *)malloc(fsize + 1);
if (fread(buffer, fsize, 1, f)!=1) return NULL; if (fread(buffer, fsize, 1, f) != 1)
return NULL;
fclose(f); fclose(f);
JA_Music_t *music = JA_LoadMusic(buffer, fsize); JA_Music_t *music = JA_LoadMusic(buffer, fsize);
@@ -170,9 +187,11 @@ JA_Music_t *JA_LoadMusic(const char* filename)
void JA_PlayMusic(JA_Music_t *music, const int loop) void JA_PlayMusic(JA_Music_t *music, const int loop)
{ {
if (!JA_musicEnabled) return; if (!JA_musicEnabled)
return;
if (current_music != NULL) { if (current_music != NULL)
{
current_music->pos = 0; current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
} }
@@ -184,33 +203,41 @@ void JA_PlayMusic(JA_Music_t *music, const int loop)
void JA_PauseMusic() void JA_PauseMusic()
{ {
if (!JA_musicEnabled) return; if (!JA_musicEnabled)
return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return; if (current_music == NULL || current_music->state == JA_MUSIC_INVALID)
return;
current_music->state = JA_MUSIC_PAUSED; current_music->state = JA_MUSIC_PAUSED;
} }
void JA_ResumeMusic() void JA_ResumeMusic()
{ {
if (!JA_musicEnabled) return; if (!JA_musicEnabled)
return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return; if (current_music == NULL || current_music->state == JA_MUSIC_INVALID)
return;
current_music->state = JA_MUSIC_PLAYING; current_music->state = JA_MUSIC_PLAYING;
} }
void JA_StopMusic() void JA_StopMusic()
{ {
if (!JA_musicEnabled) return; if (!JA_musicEnabled)
return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return; if (current_music == NULL || current_music->state == JA_MUSIC_INVALID)
return;
current_music->pos = 0; current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
} }
void JA_FadeOutMusic(const int milliseconds) void JA_FadeOutMusic(const int milliseconds)
{ {
if (!JA_musicEnabled) return; if (!JA_musicEnabled)
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return; return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID)
return;
fading = true; fading = true;
fade_start_time = SDL_GetTicks(); fade_start_time = SDL_GetTicks();
@@ -218,56 +245,63 @@ void JA_FadeOutMusic(const int milliseconds)
fade_initial_volume = JA_musicVolume; fade_initial_volume = JA_musicVolume;
} }
JA_Music_state JA_GetMusicState() { JA_Music_state JA_GetMusicState()
if (!JA_musicEnabled) return JA_MUSIC_DISABLED; {
if (!JA_musicEnabled)
return JA_MUSIC_DISABLED;
if (current_music == NULL) return JA_MUSIC_INVALID; if (current_music == NULL)
return JA_MUSIC_INVALID;
return current_music->state; return current_music->state;
} }
void JA_DeleteMusic(JA_Music_t *music) { void JA_DeleteMusic(JA_Music_t *music)
if (current_music == music) current_music = NULL; {
if (current_music == music)
current_music = NULL;
free(music->output); free(music->output);
delete music; delete music;
} }
int JA_SetMusicVolume(int volume) int JA_SetMusicVolume(int volume)
{ {
JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume; JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0
: volume;
return JA_musicVolume; return JA_musicVolume;
} }
void JA_SetMusicPosition(float value) void JA_SetMusicPosition(float value)
{ {
if (!current_music) return; if (!current_music)
return;
current_music->pos = value * JA_freq; current_music->pos = value * JA_freq;
} }
float JA_GetMusicPosition() float JA_GetMusicPosition()
{ {
if (!current_music) return 0; if (!current_music)
return 0;
return float(current_music->pos) / float(JA_freq); return float(current_music->pos) / float(JA_freq);
} }
void JA_EnableMusic(const bool value) void JA_EnableMusic(const bool value)
{ {
if (!value && current_music != NULL && current_music->state==JA_MUSIC_PLAYING) JA_StopMusic(); if (!value && current_music != NULL && current_music->state == JA_MUSIC_PLAYING)
JA_StopMusic();
JA_musicEnabled = value; JA_musicEnabled = value;
} }
JA_Sound_t *JA_NewSound(Uint8 *buffer, Uint32 length)
{
JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length) {
JA_Sound_t *sound = new JA_Sound_t(); JA_Sound_t *sound = new JA_Sound_t();
sound->buffer = buffer; sound->buffer = buffer;
sound->length = length; sound->length = length;
return sound; return sound;
} }
JA_Sound_t *JA_LoadSound(uint8_t* buffer, uint32_t size) { JA_Sound_t *JA_LoadSound(uint8_t *buffer, uint32_t size)
{
JA_Sound_t *sound = new JA_Sound_t(); JA_Sound_t *sound = new JA_Sound_t();
SDL_AudioSpec wavSpec; SDL_AudioSpec wavSpec;
SDL_LoadWAV_RW(SDL_RWFromMem(buffer, size), 1, &wavSpec, &sound->buffer, &sound->length); SDL_LoadWAV_RW(SDL_RWFromMem(buffer, size), 1, &wavSpec, &sound->buffer, &sound->length);
@@ -285,7 +319,8 @@ JA_Sound_t *JA_LoadSound(uint8_t* buffer, uint32_t size) {
return sound; return sound;
} }
JA_Sound_t *JA_LoadSound(const char* filename) { JA_Sound_t *JA_LoadSound(const char *filename)
{
JA_Sound_t *sound = new JA_Sound_t(); JA_Sound_t *sound = new JA_Sound_t();
SDL_AudioSpec wavSpec; SDL_AudioSpec wavSpec;
SDL_LoadWAV(filename, &wavSpec, &sound->buffer, &sound->length); SDL_LoadWAV(filename, &wavSpec, &sound->buffer, &sound->length);
@@ -305,11 +340,16 @@ JA_Sound_t *JA_LoadSound(const char* filename) {
int JA_PlaySound(JA_Sound_t *sound, const int loop) int JA_PlaySound(JA_Sound_t *sound, const int loop)
{ {
if (!JA_soundEnabled) return -1; if (!JA_soundEnabled)
return -1;
int channel = 0; int channel = 0;
while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; } while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE)
if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) channel = 0; {
channel++;
}
if (channel == JA_MAX_SIMULTANEOUS_CHANNELS)
channel = 0;
channels[channel].sound = sound; channels[channel].sound = sound;
channels[channel].times = loop; channels[channel].times = loop;
@@ -320,9 +360,11 @@ int JA_PlaySound(JA_Sound_t *sound, const int loop)
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop) int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop)
{ {
if (!JA_soundEnabled) return -1; if (!JA_soundEnabled)
return -1;
if (channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return -1; if (channel >= JA_MAX_SIMULTANEOUS_CHANNELS)
return -1;
channels[channel].sound = sound; channels[channel].sound = sound;
channels[channel].times = loop; channels[channel].times = loop;
@@ -333,8 +375,10 @@ int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop)
void JA_DeleteSound(JA_Sound_t *sound) void JA_DeleteSound(JA_Sound_t *sound)
{ {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
if (channels[i].sound == sound) JA_StopChannel(i); {
if (channels[i].sound == sound)
JA_StopChannel(i);
} }
SDL_free(sound->buffer); SDL_free(sound->buffer);
delete sound; delete sound;
@@ -342,41 +386,60 @@ void JA_DeleteSound(JA_Sound_t *sound)
void JA_PauseChannel(const int channel) void JA_PauseChannel(const int channel)
{ {
if (!JA_soundEnabled) return; if (!JA_soundEnabled)
return;
if (channel == -1) { if (channel == -1)
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { {
if (channels[i].state == JA_CHANNEL_PLAYING) channels[i].state = JA_CHANNEL_PAUSED; for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{
if (channels[i].state == JA_CHANNEL_PLAYING)
channels[i].state = JA_CHANNEL_PAUSED;
} }
} else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) { }
if (channels[channel].state == JA_CHANNEL_PLAYING) channels[channel].state = JA_CHANNEL_PAUSED; else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
{
if (channels[channel].state == JA_CHANNEL_PLAYING)
channels[channel].state = JA_CHANNEL_PAUSED;
} }
} }
void JA_ResumeChannel(const int channel) void JA_ResumeChannel(const int channel)
{ {
if (!JA_soundEnabled) return; if (!JA_soundEnabled)
return;
if (channel == -1) { if (channel == -1)
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { {
if (channels[i].state == JA_CHANNEL_PAUSED) channels[i].state = JA_CHANNEL_PLAYING; for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{
if (channels[i].state == JA_CHANNEL_PAUSED)
channels[i].state = JA_CHANNEL_PLAYING;
} }
} else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) { }
if (channels[channel].state == JA_CHANNEL_PAUSED) channels[channel].state = JA_CHANNEL_PLAYING; else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
{
if (channels[channel].state == JA_CHANNEL_PAUSED)
channels[channel].state = JA_CHANNEL_PLAYING;
} }
} }
void JA_StopChannel(const int channel) void JA_StopChannel(const int channel)
{ {
if (!JA_soundEnabled) return; if (!JA_soundEnabled)
return;
if (channel == -1) { if (channel == -1)
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) { {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{
channels[i].state = JA_CHANNEL_FREE; channels[i].state = JA_CHANNEL_FREE;
channels[i].pos = 0; channels[i].pos = 0;
channels[i].sound = NULL; channels[i].sound = NULL;
} }
} else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) { }
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
{
channels[channel].state = JA_CHANNEL_FREE; channels[channel].state = JA_CHANNEL_FREE;
channels[channel].pos = 0; channels[channel].pos = 0;
channels[channel].sound = NULL; channels[channel].sound = NULL;
@@ -385,15 +448,18 @@ void JA_StopChannel(const int channel)
JA_Channel_state JA_GetChannelState(const int channel) JA_Channel_state JA_GetChannelState(const int channel)
{ {
if (!JA_soundEnabled) return JA_SOUND_DISABLED; if (!JA_soundEnabled)
return JA_SOUND_DISABLED;
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID; if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS)
return JA_CHANNEL_INVALID;
return channels[channel].state; return channels[channel].state;
} }
int JA_SetSoundVolume(int volume) int JA_SetSoundVolume(int volume)
{ {
JA_soundVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume; JA_soundVolume = volume > 128 ? 128 : volume < 0 ? 0
: volume;
return JA_soundVolume; return JA_soundVolume;
} }
@@ -401,14 +467,16 @@ void JA_EnableSound(const bool value)
{ {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{ {
if (channels[i].state == JA_CHANNEL_PLAYING) JA_StopChannel(i); if (channels[i].state == JA_CHANNEL_PLAYING)
JA_StopChannel(i);
} }
JA_soundEnabled = value; JA_soundEnabled = value;
} }
int JA_SetVolume(int volume) int JA_SetVolume(int volume)
{ {
JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume; JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0
: volume;
JA_soundVolume = JA_musicVolume / 2; JA_soundVolume = JA_musicVolume / 2;
return JA_musicVolume; return JA_musicVolume;
} }

View File

@@ -1,11 +1,26 @@
#pragma once #pragma once
#include <SDL2/SDL.h>
enum JA_Channel_state { JA_CHANNEL_INVALID, JA_CHANNEL_FREE, JA_CHANNEL_PLAYING, JA_CHANNEL_PAUSED, JA_SOUND_DISABLED }; #include <SDL2/SDL_audio.h> // Para SDL_AudioFormat
enum JA_Music_state { JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, JA_MUSIC_STOPPED, JA_MUSIC_DISABLED }; #include <SDL2/SDL_stdinc.h> // Para Uint32, Uint8
struct JA_Music_t; // lines 4-4
struct JA_Sound_t; // lines 5-5
struct JA_Sound_t; enum JA_Channel_state
struct JA_Music_t; {
JA_CHANNEL_INVALID,
JA_CHANNEL_FREE,
JA_CHANNEL_PLAYING,
JA_CHANNEL_PAUSED,
JA_SOUND_DISABLED
};
enum JA_Music_state
{
JA_MUSIC_INVALID,
JA_MUSIC_PLAYING,
JA_MUSIC_PAUSED,
JA_MUSIC_STOPPED,
JA_MUSIC_DISABLED
};
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels); void JA_Init(const int freq, const SDL_AudioFormat format, const int channels);
void JA_Quit(); void JA_Quit();

View File

@@ -13,6 +13,7 @@
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "utils.h" // Para Color, Zone #include "utils.h" // Para Color, Zone
#include "mouse.h"
// Constructor // Constructor
Logo::Logo() Logo::Logo()
@@ -92,6 +93,9 @@ void Logo::checkEvents()
reloadTextures(); reloadTextures();
} }
} }
// Comprueba el cursor
Mouse::handleEvent(event);
} }
} }
@@ -227,7 +231,7 @@ void Logo::render()
} }
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
Screen::get()->blit(); Screen::get()->render();
} }
// Bucle para el logo del juego // Bucle para el logo del juego

View File

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

View File

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

35
source/mouse.cpp Normal file
View File

@@ -0,0 +1,35 @@
#include "mouse.h"
#include <SDL2/SDL_mouse.h> // Para SDL_ShowCursor
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
namespace Mouse
{
Uint32 cursor_hide_time = 3000; // Tiempo en milisegundos para ocultar el cursor
Uint32 last_mouse_move_time = 0; // Última vez que el ratón se movió
bool cursor_visible = true; // Estado del cursor
void handleEvent(const SDL_Event &event)
{
if (event.type == SDL_MOUSEMOTION)
{
last_mouse_move_time = SDL_GetTicks();
if (!cursor_visible)
{
#ifndef ARCADE
SDL_ShowCursor(SDL_ENABLE);
#endif
cursor_visible = true;
}
}
}
void updateCursorVisibility()
{
Uint32 current_time = SDL_GetTicks();
if (cursor_visible && (current_time - last_mouse_move_time > cursor_hide_time))
{
SDL_ShowCursor(SDL_DISABLE);
cursor_visible = false;
}
}
}

14
source/mouse.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include <SDL2/SDL_events.h> // Para SDL_Event
#include <SDL2/SDL_stdinc.h> // Para Uint32
namespace Mouse
{
extern Uint32 cursor_hide_time; // Tiempo en milisegundos para ocultar el cursor
extern Uint32 last_mouse_move_time; // Última vez que el ratón se movió
extern bool cursor_visible; // Estado del cursor
void handleEvent(const SDL_Event &event);
void updateCursorVisibility();
}

View File

@@ -60,7 +60,7 @@ void Notifier::update()
// Si la notificación anterior está "saliendo", no hagas nada // Si la notificación anterior está "saliendo", no hagas nada
if (i > 0) if (i > 0)
{ {
if (notifications_[i - 1].status == NotificationStatus::RISING) if (notifications_[i - 1].state == NotificationStatus::RISING)
{ {
break; break;
} }
@@ -73,7 +73,7 @@ void Notifier::update()
{ {
if (param.notification.sound) if (param.notification.sound)
{ {
if (notifications_[i].status == NotificationStatus::RISING) if (notifications_[i].state == NotificationStatus::RISING)
{ {
// Reproduce el sonido de la notificación // Reproduce el sonido de la notificación
JA_PlaySound(Resource::get()->getSound("notify.wav")); JA_PlaySound(Resource::get()->getSound("notify.wav"));
@@ -82,7 +82,7 @@ void Notifier::update()
} }
// Comprueba los estados // Comprueba los estados
if (notifications_[i].status == NotificationStatus::RISING) if (notifications_[i].state == NotificationStatus::RISING)
{ {
const float step = ((float)notifications_[i].counter / notifications_[i].travel_dist); const float step = ((float)notifications_[i].counter / notifications_[i].travel_dist);
const int alpha = 255 * step; const int alpha = 255 * step;
@@ -99,21 +99,21 @@ void Notifier::update()
if (notifications_[i].rect.y == notifications_[i].y) if (notifications_[i].rect.y == notifications_[i].y)
{ {
notifications_[i].status = NotificationStatus::STAY; notifications_[i].state = NotificationStatus::STAY;
notifications_[i].texture->setAlpha(255); notifications_[i].texture->setAlpha(255);
notifications_[i].counter = 0; notifications_[i].counter = 0;
} }
} }
else if (notifications_[i].status == NotificationStatus::STAY) else if (notifications_[i].state == NotificationStatus::STAY)
{ {
if (notifications_[i].counter == wait_time_) if (notifications_[i].counter == wait_time_)
{ {
notifications_[i].status = NotificationStatus::VANISHING; notifications_[i].state = NotificationStatus::VANISHING;
notifications_[i].counter = 0; notifications_[i].counter = 0;
} }
} }
else if (notifications_[i].status == NotificationStatus::VANISHING) else if (notifications_[i].state == NotificationStatus::VANISHING)
{ {
const float step = (notifications_[i].counter / (float)notifications_[i].travel_dist); const float step = (notifications_[i].counter / (float)notifications_[i].travel_dist);
@@ -131,7 +131,7 @@ void Notifier::update()
if (notifications_[i].rect.y == notifications_[i].y - notifications_[i].travel_dist) if (notifications_[i].rect.y == notifications_[i].y - notifications_[i].travel_dist)
{ {
notifications_[i].status = NotificationStatus::FINISHED; notifications_[i].state = NotificationStatus::FINISHED;
} }
} }
@@ -146,7 +146,7 @@ void Notifier::clearFinishedNotifications()
{ {
for (int i = (int)notifications_.size() - 1; i >= 0; --i) for (int i = (int)notifications_.size() - 1; i >= 0; --i)
{ {
if (notifications_[i].status == NotificationStatus::FINISHED) if (notifications_[i].state == NotificationStatus::FINISHED)
{ {
notifications_.erase(notifications_.begin() + i); notifications_.erase(notifications_.begin() + i);
} }
@@ -302,7 +302,7 @@ void Notifier::clearNotifications()
{ {
for (auto &notification : notifications_) for (auto &notification : notifications_)
{ {
notification.status = NotificationStatus::FINISHED; notification.state = NotificationStatus::FINISHED;
} }
clearFinishedNotifications(); clearFinishedNotifications();

View File

@@ -1,15 +1,14 @@
#pragma once #pragma once
#include <SDL2/SDL_rect.h> // para SDL_Rect #include <SDL2/SDL_rect.h> // Para SDL_Rect
#include <SDL2/SDL_render.h> // para SDL_Renderer #include <SDL2/SDL_render.h> // Para SDL_Renderer
#include <memory> // para shared_ptr, unique_ptr #include <memory> // Para shared_ptr
#include <string> // para string, basic_string #include <string> // Para string, basic_string
#include <vector> // para vector #include <vector> // Para vector
#include "utils.h" // para Color #include "utils.h" // Para Color
class Sprite; class Sprite; // lines 9-9
class Text; class Text; // lines 10-10
class Texture; class Texture; // lines 11-11
struct JA_Sound_t; // lines 12-12
class Notifier class Notifier
{ {
@@ -37,7 +36,7 @@ private:
std::shared_ptr<Sprite> sprite; std::shared_ptr<Sprite> sprite;
std::vector<std::string> texts; std::vector<std::string> texts;
int counter; int counter;
NotificationStatus status; NotificationStatus state;
NotificationShape shape; NotificationShape shape;
SDL_Rect rect; SDL_Rect rect;
int y; int y;
@@ -46,7 +45,7 @@ private:
// Constructor // Constructor
explicit Notification() explicit Notification()
: texture(nullptr), sprite(nullptr), texts(), counter(0), status(NotificationStatus::RISING), : texture(nullptr), sprite(nullptr), texts(), counter(0), state(NotificationStatus::RISING),
shape(NotificationShape::SQUARED), rect{0, 0, 0, 0}, y(0), travel_dist(0), code("") {} shape(NotificationShape::SQUARED), rect{0, 0, 0, 0}, y(0), travel_dist(0), code("") {}
}; };

View File

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

View File

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

View File

@@ -21,6 +21,8 @@ void initParam()
param.game.width = 320; param.game.width = 320;
param.game.height = 256; param.game.height = 256;
param.game.item_size = 20; param.game.item_size = 20;
param.game.coffee_machine_w = 28;
param.game.coffee_machine_h = 37;
param.game.game_area.rect = {0, 0, param.game.width, param.game.height}; param.game.game_area.rect = {0, 0, param.game.width, param.game.height};
param.game.play_area.rect = {0, 0, param.game.width, 216}; param.game.play_area.rect = {0, 0, param.game.width, 216};
param.game.enter_name_seconds = 30; param.game.enter_name_seconds = 30;
@@ -124,6 +126,16 @@ bool setParams(const std::string &var, const std::string &value)
param.game.item_size = std::stoi(value); param.game.item_size = std::stoi(value);
} }
else if (var == "game.coffee_machine_w")
{
param.game.coffee_machine_w = std::stoi(value);
}
else if (var == "game.coffee_machine_h")
{
param.game.coffee_machine_h = std::stoi(value);
}
else if (var == "game.play_area.rect.x") else if (var == "game.play_area.rect.x")
{ {
param.game.play_area.rect.x = std::stoi(value); param.game.play_area.rect.x = std::stoi(value);

View File

@@ -11,6 +11,8 @@ struct ParamGame
int width; // Ancho de la resolucion nativa del juego int width; // Ancho de la resolucion nativa del juego
int height; // Alto de la resolucion nativa del juego int height; // Alto de la resolucion nativa del juego
int item_size; // Tamaño de los items del juego int item_size; // Tamaño de los items del juego
int coffee_machine_w; // Ancho de la máquina de café
int coffee_machine_h; // Alto de la máquina de café
Zone play_area; // Rectangulo con la posición de la zona de juego Zone play_area; // Rectangulo con la posición de la zona de juego
Zone game_area; // Rectangulo con las dimensiones del juego Zone game_area; // Rectangulo con las dimensiones del juego
int enter_name_seconds; // Duración en segundos para introducir el nombre al finalizar la partida int enter_name_seconds; // Duración en segundos para introducir el nombre al finalizar la partida
@@ -63,7 +65,8 @@ struct ParamNotification
}; };
// Estructura para almacenar todos los parámetros del juego // Estructura para almacenar todos los parámetros del juego
struct Param { struct Param
{
ParamGame game; ParamGame game;
ParamFade fade; ParamFade fade;
SDL_Rect scoreboard; SDL_Rect scoreboard;
@@ -72,14 +75,14 @@ struct Param {
std::vector<ParamBalloon> balloon; std::vector<ParamBalloon> balloon;
ParamNotification notification; ParamNotification notification;
Param() : game(), fade(), scoreboard(), title(), background(), notification() { Param() : game(), fade(), scoreboard(), title(), background(), notification()
{
balloon.reserve(4); balloon.reserve(4);
} }
}; };
extern Param param; extern Param param;
extern Param param; extern Param param;
// Establece valores para los parametros a partir de un fichero de texto // Establece valores para los parametros a partir de un fichero de texto

View File

@@ -1,3 +1,4 @@
// IWYU pragma: no_include <bits/std_abs.h>
#include "path_sprite.h" #include "path_sprite.h"
#include <cstdlib> // Para abs #include <cstdlib> // Para abs
#include <functional> // Para function #include <functional> // Para function
@@ -95,7 +96,17 @@ void PathSprite::addPath(std::vector<SDL_Point> spots, int waiting_counter)
// Habilita el objeto // Habilita el objeto
void PathSprite::enable() void PathSprite::enable()
{ {
if (paths_.size() == 0 || enabled_)
{
return;
}
enabled_ = true; enabled_ = true;
// Establece la posición
auto &path = paths_.at(current_path_);
const auto &p = path.spots.at(path.counter);
setPosition(p);
} }
// Coloca el sprite en los diferentes puntos del recorrido // Coloca el sprite en los diferentes puntos del recorrido
@@ -122,23 +133,31 @@ void PathSprite::moveThroughCurrentPath()
if (path.on_destination) if (path.on_destination)
{ {
if (path.waiting_counter == 0) if (path.waiting_counter == 0)
{
path.finished = true; path.finished = true;
}
else else
{
--path.waiting_counter; --path.waiting_counter;
} }
} }
}
// Cambia de recorrido o finaliza // Cambia de recorrido o finaliza
void PathSprite::goToNextPathOrDie() void PathSprite::goToNextPathOrDie()
{ {
// Comprueba si ha terminado el recorrdo actual // Comprueba si ha terminado el recorrdo actual
if (paths_.at(current_path_).finished) if (paths_.at(current_path_).finished)
{
++current_path_; ++current_path_;
}
// Comprueba si quedan mas recorridos // Comprueba si quedan mas recorridos
if (current_path_ >= static_cast<int>(paths_.size())) if (current_path_ >= static_cast<int>(paths_.size()))
{
enabled_ = false; enabled_ = false;
} }
}
// Indica si ha terminado todos los recorridos // Indica si ha terminado todos los recorridos
bool PathSprite::hasFinished() bool PathSprite::hasFinished()

View File

@@ -65,12 +65,15 @@ public:
// Añade un recorrido // Añade un recorrido
void addPath(Path path, bool centered = false); void addPath(Path path, bool centered = false);
void addPath(std::vector<SDL_Point> spots, int waiting_counter); void addPath(std::vector<SDL_Point> spots, int waiting_counter = 0);
void addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easingFunction, int waiting_counter); void addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easingFunction, int waiting_counter = 0);
// Habilita el objeto // Habilita el objeto
void enable(); void enable();
// Indica si ha terminado todos los recorridos // Indica si ha terminado todos los recorridos
bool hasFinished(); bool hasFinished();
// Getters
int getCurrentPath() const { return current_path_; }
}; };

View File

@@ -10,6 +10,7 @@
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "resource.h" #include "resource.h"
#include "jail_audio.h" #include "jail_audio.h"
#include "stage.h"
// Constructor // Constructor
Player::Player(int id, float x, int y, bool demo, SDL_Rect &play_area, std::vector<std::shared_ptr<Texture>> texture, const std::vector<std::vector<std::string>> &animations) Player::Player(int id, float x, int y, bool demo, SDL_Rect &play_area, std::vector<std::shared_ptr<Texture>> texture, const std::vector<std::vector<std::string>> &animations)
@@ -56,8 +57,8 @@ void Player::init()
vel_y_ = 0; vel_y_ = 0;
score_ = 0; score_ = 0;
score_multiplier_ = 1.0f; score_multiplier_ = 1.0f;
cooldown_ = 10; cool_down_ = 10;
enter_name_->init(); enter_name_->init(last_enter_name_);
// Establece la posición del sprite // Establece la posición del sprite
player_sprite_->clear(); player_sprite_->clear();
@@ -147,6 +148,7 @@ void Player::setInputEnteringName(InputType input)
enter_name_->decIndex(); enter_name_->decIndex();
break; break;
case InputType::START: case InputType::START:
last_enter_name_ = getRecordName();
break; break;
default: default:
break; break;
@@ -174,10 +176,14 @@ void Player::move()
case PlayerState::DYING: case PlayerState::DYING:
{ {
// Si el cadaver abandona el area de juego por los laterales lo hace rebotar // Si el cadaver abandona el area de juego por los laterales lo hace rebotar
if ((player_sprite_->getPosX() < play_area_.x) || (player_sprite_->getPosX() + WIDTH_ > play_area_.w)) const int x = player_sprite_->getPosX();
const int min_x = play_area_.x;
const int max_x = play_area_.x + play_area_.w - WIDTH_;
if ((x < min_x) || (x > max_x))
{ {
player_sprite_->setPosX(std::clamp(x, min_x, max_x));
player_sprite_->setVelX(-player_sprite_->getVelX()); player_sprite_->setVelX(-player_sprite_->getVelX());
JA_PlaySound(Resource::get()->getSound("bubble4.wav")); playRandomBubbleSound();
} }
// Si el cadaver toca el suelo cambia el estado // Si el cadaver toca el suelo cambia el estado
@@ -191,7 +197,7 @@ void Player::move()
pos_y_ = default_pos_y_; pos_y_ = default_pos_y_;
player_sprite_->clear(); player_sprite_->clear();
shiftSprite(); shiftSprite();
JA_PlaySound(Resource::get()->getSound("bubble4.wav")); playRandomBubbleSound();
} }
else else
{ {
@@ -199,13 +205,19 @@ void Player::move()
player_sprite_->setPosY(play_area_.h - HEIGHT_); player_sprite_->setPosY(play_area_.h - HEIGHT_);
player_sprite_->setVelY(player_sprite_->getVelY() * -0.5f); player_sprite_->setVelY(player_sprite_->getVelY() * -0.5f);
player_sprite_->setVelX(player_sprite_->getVelX() * 0.75f); player_sprite_->setVelX(player_sprite_->getVelX() * 0.75f);
JA_PlaySound(Resource::get()->getSound("bubble4.wav")); playRandomBubbleSound();
} }
} }
break; break;
} }
case PlayerState::LEAVING_SCREEN: case PlayerState::LEAVING_SCREEN:
{ {
++step_counter_;
if (step_counter_ % 10 == 0)
{
JA_PlaySound(Resource::get()->getSound("walk.wav"));
}
switch (id_) switch (id_)
{ {
case 1: case 1:
@@ -224,7 +236,45 @@ void Player::move()
shiftSprite(); shiftSprite();
if (pos_x_ == min_x || pos_x_ == max_x) if (pos_x_ == min_x || pos_x_ == max_x)
{
setPlayingState(PlayerState::GAME_OVER); setPlayingState(PlayerState::GAME_OVER);
}
break;
}
case PlayerState::ENTERING_SCREEN:
{
++step_counter_;
if (step_counter_ % 10 == 0)
{
JA_PlaySound(Resource::get()->getSound("walk.wav"));
}
switch (id_)
{
case 1:
setInputPlaying(InputType::RIGHT);
pos_x_ += vel_x_;
if (pos_x_ > default_pos_x_)
{
pos_x_ = default_pos_x_;
setPlayingState(PlayerState::PLAYING);
setInvulnerable(false);
}
break;
case 2:
setInputPlaying(InputType::LEFT);
pos_x_ += vel_x_;
if (pos_x_ < default_pos_x_)
{
pos_x_ = default_pos_x_;
setPlayingState(PlayerState::PLAYING);
setInvulnerable(false);
}
break;
default:
break;
}
shiftSprite();
break; break;
} }
case PlayerState::CREDITS: case PlayerState::CREDITS:
@@ -291,6 +341,7 @@ void Player::setAnimation()
{ {
case PlayerState::PLAYING: case PlayerState::PLAYING:
case PlayerState::ENTERING_NAME_GAME_COMPLETED: case PlayerState::ENTERING_NAME_GAME_COMPLETED:
case PlayerState::ENTERING_SCREEN:
case PlayerState::LEAVING_SCREEN: case PlayerState::LEAVING_SCREEN:
case PlayerState::CREDITS: case PlayerState::CREDITS:
{ {
@@ -352,37 +403,38 @@ void Player::setAnimation()
// Actualiza el valor de la variable // Actualiza el valor de la variable
void Player::updateCooldown() void Player::updateCooldown()
{ {
if (cooldown_ > 0) if (cool_down_ > 0)
{ {
cooldown_ -= power_up_ ? 2 : 1; --cool_down_;
cooling_state_counter_ = 50;
} }
else else
{ {
if (!isCooling()) if (cooling_state_counter_ > 0)
{
if (cooling_state_counter_ == 40)
{ {
cooling_status_counter_ = 40;
switch (firing_state_) switch (firing_state_)
{ {
case PlayerState::FIRING_LEFT: case PlayerState::FIRING_LEFT:
firing_state_ = PlayerState::COOLING_LEFT; setFiringState(PlayerState::COOLING_LEFT);
break; break;
case PlayerState::FIRING_RIGHT: case PlayerState::FIRING_RIGHT:
firing_state_ = PlayerState::COOLING_RIGHT; setFiringState(PlayerState::COOLING_RIGHT);
break; break;
case PlayerState::FIRING_UP: case PlayerState::FIRING_UP:
firing_state_ = PlayerState::COOLING_UP; setFiringState(PlayerState::COOLING_UP);
break; break;
default: default:
break; break;
} }
} }
else if (cooling_status_counter_ > 0) --cooling_state_counter_;
{
--cooling_status_counter_;
} }
else else
{ {
setFiringState(PlayerState::FIRING_NONE); setFiringState(PlayerState::FIRING_NONE);
cooling_state_counter_ = 0;
} }
} }
} }
@@ -398,6 +450,7 @@ void Player::update()
updateInvulnerable(); updateInvulnerable();
updateContinueCounter(); updateContinueCounter();
updateEnterNameCounter(); updateEnterNameCounter();
updateShowingName();
updateScoreboard(); updateScoreboard();
} }
@@ -423,7 +476,7 @@ void Player::updateScoreboard()
case PlayerState::ENTERING_NAME: case PlayerState::ENTERING_NAME:
case PlayerState::ENTERING_NAME_GAME_COMPLETED: case PlayerState::ENTERING_NAME_GAME_COMPLETED:
{ {
Scoreboard::get()->setRecordName(getScoreBoardPanel(), enter_name_->getName()); Scoreboard::get()->setRecordName(getScoreBoardPanel(), enter_name_->getCurrentName());
Scoreboard::get()->setSelectorPos(getScoreBoardPanel(), getRecordNamePos()); Scoreboard::get()->setSelectorPos(getScoreBoardPanel(), getRecordNamePos());
break; break;
} }
@@ -453,6 +506,7 @@ void Player::setPlayingState(PlayerState state)
init(); init();
playing_state_ = PlayerState::PLAYING; playing_state_ = PlayerState::PLAYING;
setScoreboardMode(ScoreboardMode::SCORE); setScoreboardMode(ScoreboardMode::SCORE);
Stage::power_can_be_added = true;
break; break;
} }
case PlayerState::CONTINUE: case PlayerState::CONTINUE:
@@ -473,12 +527,19 @@ void Player::setPlayingState(PlayerState state)
setScoreboardMode(ScoreboardMode::ENTER_NAME); setScoreboardMode(ScoreboardMode::ENTER_NAME);
break; break;
} }
case PlayerState::SHOWING_NAME:
{
showing_name_ticks_ = SDL_GetTicks();
setScoreboardMode(ScoreboardMode::SHOW_NAME);
Scoreboard::get()->setRecordName(scoreboard_panel_, last_enter_name_);
break;
}
case PlayerState::DYING: case PlayerState::DYING:
{ {
// Activa la animación de morir // Activa la animación de morir
player_sprite_->setAccelY(0.2f); player_sprite_->setAccelY(0.2f);
player_sprite_->setVelY(-6.6f); player_sprite_->setVelY(-6.6f);
rand() % 2 == 0 ? player_sprite_->setVelX(3.3f) : player_sprite_->setVelX(-3.3f); (rand() % 2 == 0) ? player_sprite_->setVelX(3.3f) : player_sprite_->setVelX(-3.3f);
break; break;
} }
case PlayerState::DIED: case PlayerState::DIED:
@@ -494,6 +555,7 @@ void Player::setPlayingState(PlayerState state)
} }
case PlayerState::CELEBRATING: case PlayerState::CELEBRATING:
{ {
game_completed_ = true;
setScoreboardMode(ScoreboardMode::SCORE); setScoreboardMode(ScoreboardMode::SCORE);
break; break;
} }
@@ -506,9 +568,29 @@ void Player::setPlayingState(PlayerState state)
} }
case PlayerState::LEAVING_SCREEN: case PlayerState::LEAVING_SCREEN:
{ {
step_counter_ = 0;
setScoreboardMode(ScoreboardMode::GAME_COMPLETED); setScoreboardMode(ScoreboardMode::GAME_COMPLETED);
break; break;
} }
case PlayerState::ENTERING_SCREEN:
{
step_counter_ = 0;
setScoreboardMode(ScoreboardMode::SCORE);
switch (id_)
{
case 1:
pos_x_ = param.game.game_area.rect.x - WIDTH_;
break;
case 2:
pos_x_ = param.game.game_area.rect.x + param.game.game_area.rect.w;
break;
default:
break;
}
break;
}
case PlayerState::CREDITS: case PlayerState::CREDITS:
{ {
vel_x_ = (walking_state_ == PlayerState::WALKING_RIGHT) ? BASE_SPEED_ : -BASE_SPEED_; vel_x_ = (walking_state_ == PlayerState::WALKING_RIGHT) ? BASE_SPEED_ : -BASE_SPEED_;
@@ -639,6 +721,19 @@ void Player::updateEnterNameCounter()
} }
} }
// Actualiza el estado de SHOWING_NAME
void Player::updateShowingName()
{
if (playing_state_ == PlayerState::SHOWING_NAME)
{
constexpr int TICKS_SPEED = 5000;
if (SDL_GetTicks() - enter_name_ticks_ > TICKS_SPEED)
{
game_completed_ ? setPlayingState(PlayerState::LEAVING_SCREEN) : setPlayingState(PlayerState::CONTINUE);
}
}
}
// Decrementa el contador de continuar // Decrementa el contador de continuar
void Player::decContinueCounter() void Player::decContinueCounter()
{ {
@@ -648,6 +743,10 @@ void Player::decContinueCounter()
{ {
setPlayingState(PlayerState::GAME_OVER); setPlayingState(PlayerState::GAME_OVER);
} }
else
{
JA_PlaySound(Resource::get()->getSound("continue_clock.wav"));
}
} }
// Decrementa el contador de entrar nombre // Decrementa el contador de entrar nombre
@@ -687,3 +786,10 @@ void Player::shiftSprite()
player_sprite_->setPosY(pos_y_); player_sprite_->setPosY(pos_y_);
power_sprite_->setPosX(getPosX() - power_up_desp_x_); power_sprite_->setPosX(getPosX() - power_up_desp_x_);
} }
// Hace sonar un ruido al azar
void Player::playRandomBubbleSound()
{
const std::vector<std::string> sounds = {"bubble1.wav", "bubble2.wav", "bubble3.wav", "bubble4.wav"};
JA_PlaySound(Resource::get()->getSound(sounds.at(rand() % sounds.size())));
}

View File

@@ -34,12 +34,14 @@ enum class PlayerState
CONTINUE, // Está con la cuenta atras para continuar CONTINUE, // Está con la cuenta atras para continuar
WAITING, // No está jugando pero puede entrar a jugar WAITING, // No está jugando pero puede entrar a jugar
ENTERING_NAME, // Introduciendo nombre ENTERING_NAME, // Introduciendo nombre
SHOWING_NAME, // Mostrando el nombre introducido
DYING, // El cadaver está volando por ahi DYING, // El cadaver está volando por ahi
DIED, // El cadaver ha desaparecido por el fondo DIED, // El cadaver ha desaparecido por el fondo
GAME_OVER, // No está jugando y no puede entrar a jugar GAME_OVER, // No está jugando y no puede entrar a jugar
CELEBRATING, // Poniendo pose de victoria CELEBRATING, // Poniendo pose de victoria
ENTERING_NAME_GAME_COMPLETED, // Poniendo nombre en el tramo final del juego ENTERING_NAME_GAME_COMPLETED, // Poniendo nombre en el tramo final del juego
LEAVING_SCREEN, // Moviendose fuera de la pantalla LEAVING_SCREEN, // Moviendose fuera de la pantalla
ENTERING_SCREEN, // Entando a la pantalla
CREDITS, // Estado para los creditos del juego CREDITS, // Estado para los creditos del juego
}; };
@@ -68,8 +70,8 @@ private:
int default_pos_y_; // Posición inicial para el jugador int default_pos_y_; // Posición inicial para el jugador
float vel_x_ = 0.0f; // Cantidad de pixeles a desplazarse en el eje X float vel_x_ = 0.0f; // Cantidad de pixeles a desplazarse en el eje X
int vel_y_ = 0.0f; // Cantidad de pixeles a desplazarse en el eje Y int vel_y_ = 0.0f; // Cantidad de pixeles a desplazarse en el eje Y
int cooldown_ = 0; // Contador durante el cual no puede disparar int cool_down_ = 0; // Contador durante el cual no puede disparar
int cooling_status_counter_ = 0; // Contador para la animación del estado cooling int cooling_state_counter_ = 0; // Contador para la animación del estado cooling
int score_ = 0; // Puntos del jugador int score_ = 0; // Puntos del jugador
float score_multiplier_ = 1.0f; // Multiplicador de puntos float score_multiplier_ = 1.0f; // Multiplicador de puntos
PlayerState walking_state_ = PlayerState::WALKING_STOP; // Estado del jugador al moverse PlayerState walking_state_ = PlayerState::WALKING_STOP; // Estado del jugador al moverse
@@ -91,6 +93,11 @@ private:
bool demo_; // Para que el jugador sepa si está en el modo demostración bool demo_; // Para que el jugador sepa si está en el modo demostración
int enter_name_counter_; // Contador para poner nombre int enter_name_counter_; // Contador para poner nombre
Uint32 enter_name_ticks_ = 0; // Variable para poder cambiar el contador de poner nombre en función del tiempo Uint32 enter_name_ticks_ = 0; // Variable para poder cambiar el contador de poner nombre en función del tiempo
Uint32 showing_name_ticks_ = 0; // Tiempo en el que se entra al estado SHOWING_NAME
int step_counter_ = 0; // Cuenta los pasos para los estados en los que camina automáticamente
bool game_completed_ = false; // Indica si ha completado el juego
int credits_used_ = 1; // Indica el numero de veces que ha continuado
std::string last_enter_name_; // Ultimo nombre introducido en la tabla de puntuaciones
// Actualiza el circulo de colisión a la posición del jugador // Actualiza el circulo de colisión a la posición del jugador
void shiftColliders(); void shiftColliders();
@@ -107,6 +114,9 @@ private:
// Actualiza el contador de entrar nombre // Actualiza el contador de entrar nombre
void updateEnterNameCounter(); void updateEnterNameCounter();
// Actualiza el estado de SHOWING_NAME
void updateShowingName();
// Decrementa el contador de entrar nombre // Decrementa el contador de entrar nombre
void decEnterNameCounter(); void decEnterNameCounter();
@@ -116,6 +126,10 @@ private:
// Cambia el modo del marcador // Cambia el modo del marcador
void setScoreboardMode(ScoreboardMode mode); void setScoreboardMode(ScoreboardMode mode);
// Hace sonar un ruido al azar
void playRandomBubbleSound();
// Getters
bool isRenderable() const { return !isWaiting() && !isGameOver(); } bool isRenderable() const { return !isWaiting() && !isGameOver(); }
public: public:
@@ -201,10 +215,10 @@ public:
bool isWaiting() const { return playing_state_ == PlayerState::WAITING; } bool isWaiting() const { return playing_state_ == PlayerState::WAITING; }
// Getters // Getters
bool canFire() const { return cooldown_ > 0 ? false : true; } bool canFire() const { return cool_down_ > 0 ? false : true; }
bool hasExtraHit() const { return extra_hit_; } bool hasExtraHit() const { return extra_hit_; }
bool isCooling() { return firing_state_ == PlayerState::COOLING_LEFT || firing_state_ == PlayerState::COOLING_UP || firing_state_ == PlayerState::COOLING_RIGHT; } bool isCooling() const { return firing_state_ == PlayerState::COOLING_LEFT || firing_state_ == PlayerState::COOLING_UP || firing_state_ == PlayerState::COOLING_RIGHT; }
bool IsEligibleForHighScore() { return score_ > options.game.hi_score_table.back().score; } bool IsEligibleForHighScore() const { return score_ > options.game.hi_score_table.back().score; }
bool isInvulnerable() const { return invulnerable_; } bool isInvulnerable() const { return invulnerable_; }
bool isPowerUp() const { return power_up_; } bool isPowerUp() const { return power_up_; }
Circle &getCollider() { return collider_; } Circle &getCollider() { return collider_; }
@@ -218,16 +232,18 @@ public:
int getPosX() const { return static_cast<int>(pos_x_); } int getPosX() const { return static_cast<int>(pos_x_); }
int getPosY() const { return pos_y_; } int getPosY() const { return pos_y_; }
int getPowerUpCounter() const { return power_up_counter_; } int getPowerUpCounter() const { return power_up_counter_; }
std::string getRecordName() const { return enter_name_->getName(); } std::string getRecordName() const { return enter_name_->getFinalName(); }
int getScore() const { return score_; } int getScore() const { return score_; }
int getScoreBoardPanel() const { return scoreboard_panel_; } int getScoreBoardPanel() const { return scoreboard_panel_; }
int getWidth() const { return WIDTH_; } int getWidth() const { return WIDTH_; }
PlayerState getPlayingState() const { return playing_state_; } PlayerState getPlayingState() const { return playing_state_; }
std::string getName() const { return name_; } std::string getName() const { return name_; }
bool get1CC() const { return game_completed_ && credits_used_ == 1; }
bool getEnterNamePositionOverflow() const { return enter_name_->getPositionOverflow(); }
// Setters // Setters
void setController(int index) { controller_index_ = index; } void setController(int index) { controller_index_ = index; }
void setFireCooldown(int time) { cooldown_ = time; } void setFireCooldown(int time) { cool_down_ = time; }
void setFiringState(PlayerState state) { firing_state_ = state; } void setFiringState(PlayerState state) { firing_state_ = state; }
void setInvulnerableCounter(int value) { invulnerable_counter_ = value; } void setInvulnerableCounter(int value) { invulnerable_counter_ = value; }
void setName(const std::string &name) { name_ = name; } void setName(const std::string &name) { name_ = name; }
@@ -236,4 +252,5 @@ public:
void setScoreBoardPanel(int panel) { scoreboard_panel_ = panel; } void setScoreBoardPanel(int panel) { scoreboard_panel_ = panel; }
void setScoreMultiplier(float value) { score_multiplier_ = value; } void setScoreMultiplier(float value) { score_multiplier_ = value; }
void setWalkingState(PlayerState state) { walking_state_ = state; } void setWalkingState(PlayerState state) { walking_state_ = state; }
void addCredit() { ++credits_used_; }
}; };

View File

@@ -254,14 +254,14 @@ void Resource::addPalettes()
{ {
// Jugador 1 // Jugador 1
std::cout << "\n>> PALETTES" << std::endl; std::cout << "\n>> PALETTES" << std::endl;
getTexture("player1.gif")->addPaletteFromFile(Asset::get()->get("player1_one_coffee_palette.pal")); getTexture("player1.gif")->addPaletteFromFile(Asset::get()->get("player1_1_coffee_palette.gif"));
getTexture("player1.gif")->addPaletteFromFile(Asset::get()->get("player1_two_coffee_palette.pal")); getTexture("player1.gif")->addPaletteFromFile(Asset::get()->get("player1_2_coffee_palette.gif"));
getTexture("player1.gif")->addPaletteFromFile(Asset::get()->get("player1_all_white_palette.pal")); getTexture("player1.gif")->addPaletteFromFile(Asset::get()->get("player1_invencible_palette.gif"));
// Jugador 2 // Jugador 2
getTexture("player2.gif")->addPaletteFromFile(Asset::get()->get("player2_one_coffee_palette.pal")); getTexture("player2.gif")->addPaletteFromFile(Asset::get()->get("player2_1_coffee_palette.gif"));
getTexture("player2.gif")->addPaletteFromFile(Asset::get()->get("player2_two_coffee_palette.pal")); getTexture("player2.gif")->addPaletteFromFile(Asset::get()->get("player2_2_coffee_palette.gif"));
getTexture("player2.gif")->addPaletteFromFile(Asset::get()->get("player2_all_white_palette.pal")); getTexture("player2.gif")->addPaletteFromFile(Asset::get()->get("player2_invencible_palette.gif"));
// Fuentes // Fuentes
getTexture("smb2.gif")->addPaletteFromFile(Asset::get()->get("smb2_palette1.pal")); getTexture("smb2.gif")->addPaletteFromFile(Asset::get()->get("smb2_palette1.pal"));
@@ -301,6 +301,7 @@ void Resource::createTextures()
// Tamaño doble // Tamaño doble
std::vector<NameAndText> strings2X = { std::vector<NameAndText> strings2X = {
NameAndText("game_text_100000_points", "100.000"),
NameAndText("game_text_get_ready", lang::getText(75)), NameAndText("game_text_get_ready", lang::getText(75)),
NameAndText("game_text_last_stage", lang::getText(79)), NameAndText("game_text_last_stage", lang::getText(79)),
NameAndText("game_text_congratulations", lang::getText(50)), NameAndText("game_text_congratulations", lang::getText(50)),
@@ -314,22 +315,35 @@ void Resource::createTextures()
} }
} }
// Crea los objetos de texto
void Resource::createText() void Resource::createText()
{ {
struct ResourceInfo
{
std::string key; // Identificador del recurso
std::string textureFile; // Nombre del archivo de textura
std::string textFile; // Nombre del archivo de texto
// Constructor para facilitar la creación de objetos ResourceInfo
ResourceInfo(const std::string &k, const std::string &tFile, const std::string &txtFile)
: key(k), textureFile(tFile), textFile(txtFile) {}
};
std::cout << "\n>> CREATING TEXT_OBJECTS" << std::endl; std::cout << "\n>> CREATING TEXT_OBJECTS" << std::endl;
std::vector<std::pair<std::string, std::string>> resources = { std::vector<ResourceInfo> resources = {
{"04b_25", "04b_25.png"}, {"04b_25", "04b_25.png", "04b_25.txt"},
{"04b_25_2x", "04b_25_2x.png"}, {"04b_25_2x", "04b_25_2x.png", "04b_25_2x.txt"},
{"8bithud", "8bithud.png"}, {"04b_25_metal", "04b_25_metal.png", "04b_25.txt"},
{"nokia", "nokia.png"}, {"04b_25_grey", "04b_25_grey.png", "04b_25.txt"},
{"smb2", "smb2.gif"}}; {"8bithud", "8bithud.png", "8bithud.txt"},
{"smb2", "smb2.gif", "smb2.txt"}};
for (const auto &resource : resources) for (const auto &resource : resources)
{ {
texts_.emplace_back(ResourceText(resource.first, std::make_shared<Text>(getTexture(resource.second), getTextFile(resource.first + ".txt")))); texts_.emplace_back(ResourceText(resource.key, std::make_shared<Text>(
printWithDots("Text : ", resource.first, "[ DONE ]"); getTexture(resource.textureFile),
getTextFile(resource.textFile))));
printWithDots("Text : ", resource.key, "[ DONE ]");
} }
} }

View File

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

View File

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

View File

@@ -14,6 +14,7 @@
#include "notifier.h" // Para Notifier #include "notifier.h" // Para Notifier
#include "on_screen_help.h" // Para OnScreenHelp #include "on_screen_help.h" // Para OnScreenHelp
#include "options.h" // Para Options, OptionsVideo, options, Options... #include "options.h" // Para Options, OptionsVideo, options, Options...
#include "mouse.h"
#ifndef NO_SHADERS #ifndef NO_SHADERS
#include "jail_shader.h" // para init, render #include "jail_shader.h" // para init, render
@@ -45,7 +46,6 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer)
: window_(window), : window_(window),
renderer_(renderer), renderer_(renderer),
game_canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), game_canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
shader_canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
src_rect_({0, 0, param.game.width, param.game.height}), src_rect_({0, 0, param.game.width, param.game.height}),
dst_rect_({0, 0, param.game.width, param.game.height}) dst_rect_({0, 0, param.game.width, param.game.height})
{ {
@@ -65,7 +65,6 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer)
Screen::~Screen() Screen::~Screen()
{ {
SDL_DestroyTexture(game_canvas_); SDL_DestroyTexture(game_canvas_);
SDL_DestroyTexture(shader_canvas_);
} }
// Limpia la pantalla // Limpia la pantalla
@@ -82,68 +81,44 @@ void Screen::start()
} }
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
void Screen::blit() void Screen::render()
{ {
// Actualiza el contador de FPS // Actualiza el contador de FPS
fps_counter_++; ++fps_counter_;
// Actualiza y dibuja el efecto de flash en la pantalla // Dibuja efectos y elementos sobre el game_canvas_
renderFlash(); renderFlash();
// Atenua la pantalla
renderAttenuate(); renderAttenuate();
renderShake();
// Muestra la ayuda por pantalla
OnScreenHelp::get()->render(); OnScreenHelp::get()->render();
// Muestra información por pantalla
renderInfo(); renderInfo();
// Muestra las notificaciones
Notifier::get()->render(); Notifier::get()->render();
#ifdef NO_SHADERS // Renderiza el contenido del game_canvas_
// Vuelve a dejar el renderizador en modo normal renderScreen();
}
// Renderiza el contenido del game_canvas_
void Screen::renderScreen()
{
// Restablece el objetivo de renderizado al buffer de pantalla predeterminado
SDL_SetRenderTarget(renderer_, nullptr); SDL_SetRenderTarget(renderer_, nullptr);
clean();
// Borra el contenido previo #ifdef NO_SHADERS
SDL_SetRenderDrawColor(renderer_, border_color_.r, border_color_.g, border_color_.b, 0xFF); // Actualiza la pantalla con el contenido del buffer de renderizado
SDL_RenderClear(renderer_);
// Copia la textura de juego en el renderizador en la posición adecuada
if (shake_effect_.enabled)
SDL_RenderCopy(renderer_, game_canvas_, nullptr, nullptr); SDL_RenderCopy(renderer_, game_canvas_, nullptr, nullptr);
SDL_RenderCopy(renderer_, game_canvas_, &src_rect_, &dst_rect_);
// Muestra por pantalla el renderizador
SDL_RenderPresent(renderer_); SDL_RenderPresent(renderer_);
#else #else
if (options.video.shaders) if (options.video.shaders)
{ {
SDL_SetRenderTarget(renderer_, shader_canvas_); // Aplica shaders y renderiza el contenido
SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(renderer_);
if (shake_effect_.enabled)
SDL_RenderCopy(renderer_, game_canvas_, nullptr, nullptr);
SDL_RenderCopy(renderer_, game_canvas_, &src_rect_, &dst_rect_);
SDL_SetRenderTarget(renderer_, nullptr);
shader::render(); shader::render();
} }
else else
{ {
// Vuelve a dejar el renderizador en modo normal // Actualiza la pantalla con el contenido del buffer de renderizado
SDL_SetRenderTarget(renderer_, nullptr); SDL_RenderCopy(renderer_, game_canvas_, nullptr, nullptr);
// Borra el render
SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF);
SDL_RenderClear(renderer_);
// Copia la textura de juego en el renderizador en la posición adecuada
if (shake_effect_.enabled)
SDL_RenderCopy(renderer_, game_canvas_, nullptr, nullptr); // Esta copia es para evitar que se vea negro por los laterales
SDL_RenderCopy(renderer_, game_canvas_, &src_rect_, &dst_rect_);
// Muestra por pantalla el renderizador
SDL_RenderPresent(renderer_); SDL_RenderPresent(renderer_);
} }
#endif #endif
@@ -204,7 +179,7 @@ void Screen::setVideoMode(ScreenVideoMode videoMode)
std::ifstream f(Asset::get()->get(glsl_file).c_str()); std::ifstream f(Asset::get()->get(glsl_file).c_str());
std::string source((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>()); std::string source((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
shader::init(window_, shader_canvas_, source.c_str()); shader::init(window_, game_canvas_, source.c_str());
#endif #endif
} }
} }
@@ -259,6 +234,7 @@ void Screen::update()
Notifier::get()->update(); Notifier::get()->update();
updateFPS(); updateFPS();
OnScreenHelp::get()->update(); OnScreenHelp::get()->update();
Mouse::updateCursorVisibility();
} }
// Agita la pantalla // Agita la pantalla
@@ -339,6 +315,33 @@ void Screen::renderAttenuate()
} }
} }
// Aplica el efecto de agitar la pantalla
void Screen::renderShake()
{
if (shake_effect_.enabled)
{
// Guarda el renderizador actual para dejarlo despues como estaba
auto current_target = SDL_GetRenderTarget(renderer_);
// Crea una textura temporal
auto temp_texture = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height);
// Vuelca game_canvas_ a la textura temporal
SDL_SetRenderTarget(renderer_, temp_texture);
SDL_RenderCopy(renderer_, game_canvas_, nullptr, nullptr);
// Vuelca textura temporal a game_canvas_
SDL_SetRenderTarget(renderer_, game_canvas_);
SDL_RenderCopy(renderer_, temp_texture, &src_rect_, &dst_rect_);
// Elimina la textura temporal
SDL_DestroyTexture(temp_texture);
// Restaura el renderizador de destino original
SDL_SetRenderTarget(renderer_, current_target);
}
}
// Activa / desactiva los shaders // Activa / desactiva los shaders
void Screen::toggleShaders() void Screen::toggleShaders()
{ {
@@ -391,9 +394,11 @@ void Screen::renderInfo()
// Contador de service_pressed_counter // Contador de service_pressed_counter
if (const int counter = globalInputs::service_pressed_counter; counter > 0) if (const int counter = globalInputs::service_pressed_counter; counter > 0)
{
dbg_print(0, 8, std::to_string(counter).c_str(), 255, 0, 255); dbg_print(0, 8, std::to_string(counter).c_str(), 255, 0, 255);
} }
} }
}
// Calcula la nueva posición de la ventana a partir de la antigua al cambiarla de tamaño // Calcula la nueva posición de la ventana a partir de la antigua al cambiarla de tamaño
SDL_Point Screen::getNewPosition() SDL_Point Screen::getNewPosition()

View File

@@ -31,7 +31,6 @@ private:
SDL_Window *window_; // Ventana de la aplicación SDL_Window *window_; // Ventana de la aplicación
SDL_Renderer *renderer_; // El renderizador de la ventana SDL_Renderer *renderer_; // El renderizador de la ventana
SDL_Texture *game_canvas_; // Textura donde se dibuja todo antes de volcarse al renderizador SDL_Texture *game_canvas_; // Textura donde se dibuja todo antes de volcarse al renderizador
SDL_Texture *shader_canvas_; // Textura para pasarle al shader desde gameCanvas
// Variables // Variables
SDL_Rect src_rect_; // Coordenadas de donde va a pillar la textura del juego para dibujarla SDL_Rect src_rect_; // Coordenadas de donde va a pillar la textura del juego para dibujarla
@@ -99,6 +98,9 @@ private:
// Atenua la pantalla // Atenua la pantalla
void renderAttenuate(); void renderAttenuate();
// Aplica el efecto de agitar la pantalla
void renderShake();
// Calcula los frames por segundo // Calcula los frames por segundo
void updateFPS(); void updateFPS();
@@ -108,6 +110,12 @@ private:
// Calcula la nueva posición de la ventana a partir de la antigua al cambiarla de tamaño // Calcula la nueva posición de la ventana a partir de la antigua al cambiarla de tamaño
SDL_Point getNewPosition(); SDL_Point getNewPosition();
// Actualiza la pantalla con el contenido del game_canvas_
void presentGameCanvas();
// Selecciona y ejecuta el método de renderizado adecuado basado en la configuración de shaders
void renderScreen();
// [SINGLETON] Ahora el constructor y el destructor son privados, para no poder crear objetos screen desde fuera // [SINGLETON] Ahora el constructor y el destructor son privados, para no poder crear objetos screen desde fuera
// Constructor // Constructor
@@ -136,7 +144,7 @@ public:
void start(); void start();
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
void blit(); void render();
// Establece el modo de video // Establece el modo de video
void setVideoMode(ScreenVideoMode video_mode); void setVideoMode(ScreenVideoMode video_mode);

View File

@@ -5,30 +5,31 @@ namespace section
// Secciones del programa // Secciones del programa
enum class Name enum class Name
{ {
INIT = 0, INIT,
LOGO = 1, LOGO,
INTRO = 2, INTRO,
TITLE = 3, TITLE,
GAME = 4, GAME,
HI_SCORE_TABLE = 5, HI_SCORE_TABLE,
GAME_DEMO = 6, GAME_DEMO,
INSTRUCTIONS = 7, INSTRUCTIONS,
CREDITS = 8, CREDITS,
QUIT = 9, QUIT,
}; };
// Opciones para la sección // Opciones para la sección
enum class Options enum class Options
{ {
GAME_PLAY_1P = 0, GAME_PLAY_1P,
GAME_PLAY_2P = 1, GAME_PLAY_2P,
TITLE_1 = 2, TITLE_TIME_OUT,
TITLE_2 = 3, TITLE_1,
QUIT_WITH_KEYBOARD = 4, TITLE_2,
QUIT_WITH_CONTROLLER = 5, QUIT_WITH_KEYBOARD,
QUIT_FROM_EVENT = 6, QUIT_WITH_CONTROLLER,
RELOAD = 7, QUIT_FROM_EVENT,
NONE = 8, RELOAD,
NONE,
}; };
// Variables para el Attract Mode // Variables para el Attract Mode

View File

@@ -1,4 +1,5 @@
#include "sprite.h" #include "sprite.h"
#include "texture.h" // Para Texture
// Constructor // Constructor
Sprite::Sprite(std::shared_ptr<Texture> texture, int x, int y, int w, int h) Sprite::Sprite(std::shared_ptr<Texture> texture, int x, int y, int w, int h)

View File

@@ -1,8 +1,8 @@
#pragma once #pragma once
#include <SDL2/SDL_rect.h> // para SDL_Rect, SDL_Point #include <SDL2/SDL_rect.h> // Para SDL_Rect, SDL_Point
#include "texture.h" #include <memory> // Para shared_ptr
#include <memory> class Texture;
// Clase sprite // Clase sprite
class Sprite class Sprite
@@ -37,6 +37,7 @@ public:
// Devuelve el rectangulo donde está el sprite // Devuelve el rectangulo donde está el sprite
SDL_Rect getPosition() const { return pos_; } SDL_Rect getPosition() const { return pos_; }
SDL_Rect &getRect() { return pos_; }
// Establece la posición y el tamaño // Establece la posición y el tamaño
void setX(int x) { pos_.x = x; } void setX(int x) { pos_.x = x; }

View File

@@ -9,6 +9,7 @@ namespace Stage
int power = 0; // Poder acumulado en la fase int power = 0; // Poder acumulado en la fase
int total_power = 0; // Poder total necesario para completar el juego int total_power = 0; // Poder total necesario para completar el juego
int number = 0; // Fase actual int number = 0; // Fase actual
bool power_can_be_added = true; // Habilita la recolecta de poder
// Devuelve una fase // Devuelve una fase
Stage get(int index) { return stages.at(std::min(9, index)); } Stage get(int index) { return stages.at(std::min(9, index)); }
@@ -16,6 +17,7 @@ namespace Stage
// Inicializa las variables del namespace Stage // Inicializa las variables del namespace Stage
void init() void init()
{ {
stages.clear();
stages.emplace_back(Stage(200, 7 + (4 * 1), 7 + (4 * 3))); stages.emplace_back(Stage(200, 7 + (4 * 1), 7 + (4 * 3)));
stages.emplace_back(Stage(300, 7 + (4 * 2), 7 + (4 * 4))); stages.emplace_back(Stage(300, 7 + (4 * 2), 7 + (4 * 4)));
stages.emplace_back(Stage(600, 7 + (4 * 3), 7 + (4 * 5))); stages.emplace_back(Stage(600, 7 + (4 * 3), 7 + (4 * 5)));
@@ -34,8 +36,11 @@ namespace Stage
// Añade poder // Añade poder
void addPower(int amount) void addPower(int amount)
{
if (power_can_be_added)
{ {
power += amount; power += amount;
total_power += amount; total_power += amount;
} }
} }
}

View File

@@ -19,6 +19,7 @@ namespace Stage
extern int power; // Poder acumulado en la fase extern int power; // Poder acumulado en la fase
extern int total_power; // Poder total necesario para completar el juego extern int total_power; // Poder total necesario para completar el juego
extern int number; // Fase actual extern int number; // Fase actual
extern bool power_can_be_added; // Indica si se puede añadir poder a la fase
// Devuelve una fase // Devuelve una fase
Stage get(int index); Stage get(int index);

View File

@@ -1,12 +1,18 @@
// IWYU pragma: no_include <bits/std_abs.h>
#include "tabe.h" #include "tabe.h"
#include "resource.h" #include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL, SDL_FLIP_NONE
#include "param.h" #include <SDL2/SDL.h>
#include "jail_audio.h" #include <stdlib.h> // Para rand, abs
#include <algorithm> #include <algorithm> // Para max
#include "jail_audio.h" // Para JA_PlaySound
#include "param.h" // Para Param, ParamGame, param
#include "resource.h" // Para Resource
#include "utils.h" // Para Zone
// Constructor // Constructor
Tabe::Tabe() Tabe::Tabe()
: sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("tabe.png"), Resource::get()->getAnimation("tabe.ani"))) {} : sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("tabe.png"), Resource::get()->getAnimation("tabe.ani"))),
timer_(TabeTimer(2.5f, 4.0f)) {}
// Actualiza la lógica // Actualiza la lógica
void Tabe::update() void Tabe::update()
@@ -15,6 +21,12 @@ void Tabe::update()
{ {
sprite_->update(); sprite_->update();
move(); move();
updateState();
}
timer_.update();
if (timer_.should_spawn())
{
enable();
} }
} }
@@ -44,7 +56,7 @@ void Tabe::move()
{ {
if (x_ < min_x) if (x_ < min_x)
{ {
enabled_ = false; disable();
} }
if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_ && direction_ == TabeDirection::TO_THE_RIGHT) if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_ && direction_ == TabeDirection::TO_THE_RIGHT)
{ {
@@ -58,7 +70,7 @@ void Tabe::move()
{ {
if (x_ > max_x) if (x_ > max_x)
{ {
enabled_ = false; disable();
} }
if (x_ < param.game.game_area.rect.x && direction_ == TabeDirection::TO_THE_LEFT) if (x_ < param.game.game_area.rect.x && direction_ == TabeDirection::TO_THE_LEFT)
{ {
@@ -97,7 +109,10 @@ void Tabe::enable()
if (!enabled_) if (!enabled_)
{ {
enabled_ = true; enabled_ = true;
y_ = 20.0f; has_bonus_ = true;
hit_counter_ = 0;
number_of_hits_ = 0;
y_ = param.game.game_area.rect.y + 20.0f;
// Establece una dirección aleatoria // Establece una dirección aleatoria
destiny_ = direction_ = rand() % 2 == 0 ? TabeDirection::TO_THE_LEFT : TabeDirection::TO_THE_RIGHT; destiny_ = direction_ = rand() % 2 == 0 ? TabeDirection::TO_THE_LEFT : TabeDirection::TO_THE_RIGHT;
@@ -143,3 +158,67 @@ void Tabe::setRandomFlyPath(TabeDirection direction, int lenght)
break; break;
} }
} }
// Establece el estado
void Tabe::setState(TabeState state)
{
if (enabled_)
{
state_ = state;
switch (state)
{
case TabeState::FLY:
sprite_->setCurrentAnimation("fly");
break;
case TabeState::HIT:
sprite_->setCurrentAnimation("hit");
hit_counter_ = 5;
++number_of_hits_;
break;
default:
break;
}
}
}
// Actualiza el estado
void Tabe::updateState()
{
if (state_ == TabeState::HIT)
{
--hit_counter_;
if (hit_counter_ == 0)
{
setState(TabeState::FLY);
}
}
}
// Intenta obtener el bonus
bool Tabe::tryToGetBonus()
{
if (has_bonus_ && rand() % std::max(1, 15 - number_of_hits_) == 0)
{
has_bonus_ = false;
return true;
}
return false;
}
// Actualiza el temporizador
void Tabe::updateTimer()
{
timer_.current_time = SDL_GetTicks();
timer_.delta_time = timer_.current_time - timer_.last_time;
timer_.last_time = timer_.current_time;
}
// Deshabilita el objeto
void Tabe::disable()
{
enabled_ = false;
timer_.reset();
}

View File

@@ -1,7 +1,9 @@
#pragma once #pragma once
#include "animated_sprite.h" #include <SDL2/SDL_rect.h> // Para SDL_Rect
#include <memory> #include <SDL2/SDL.h>
#include <memory> // Para unique_ptr
#include "animated_sprite.h" // Para AnimatedSprite
enum class TabeDirection : int enum class TabeDirection : int
{ {
@@ -9,6 +11,61 @@ enum class TabeDirection : int
TO_THE_RIGHT = 1, TO_THE_RIGHT = 1,
}; };
enum class TabeState : int
{
FLY = 0,
HIT = 1,
};
struct TabeTimer
{
Uint32 time_until_next_spawn; // Tiempo restante para la próxima aparición
Uint32 min_spawn_time; // Tiempo mínimo entre apariciones
Uint32 max_spawn_time; // Tiempo máximo entre apariciones
Uint32 current_time; // Tiempo actual
Uint32 delta_time; // Diferencia de tiempo desde la última actualización
Uint32 last_time; // Tiempo de la última actualización
// Constructor
TabeTimer(float minTime, float maxTime)
: min_spawn_time(minTime * 60000), max_spawn_time(maxTime * 60000)
{
current_time = SDL_GetTicks();
reset();
}
// Restablece el temporizador con un nuevo tiempo hasta la próxima aparición
void reset()
{
Uint32 range = max_spawn_time - min_spawn_time;
time_until_next_spawn = min_spawn_time + rand() % (range + 1);
last_time = SDL_GetTicks();
}
// Actualiza el temporizador, decrementando el tiempo hasta la próxima aparición
void update()
{
current_time = SDL_GetTicks();
delta_time = current_time - last_time;
last_time = current_time;
if (time_until_next_spawn > delta_time)
{
time_until_next_spawn -= delta_time;
}
else
{
time_until_next_spawn = 0;
}
}
// Indica si el temporizador ha finalizado
bool should_spawn() const
{
return time_until_next_spawn == 0;
}
};
// Clase Tabe // Clase Tabe
class Tabe class Tabe
{ {
@@ -30,6 +87,11 @@ private:
bool enabled_ = false; // Indica si el objeto está activo bool enabled_ = false; // Indica si el objeto está activo
TabeDirection direction_; // Dirección del objeto TabeDirection direction_; // Dirección del objeto
TabeDirection destiny_; // Destino del objeto TabeDirection destiny_; // Destino del objeto
TabeState state_ = TabeState::FLY; // Estado
int hit_counter_ = 0; // Contador para el estado HIT
int number_of_hits_ = 0; // Cantidad de disparos que ha recibido
bool has_bonus_ = true; // Indica si el Tabe aun tiene el bonus para soltar
TabeTimer timer_; // Temporizador para gestionar la aparición del Tabe
// Mueve el objeto // Mueve el objeto
void move(); void move();
@@ -40,6 +102,15 @@ private:
// Establece un vuelo aleatorio // Establece un vuelo aleatorio
void setRandomFlyPath(TabeDirection direction, int lenght); void setRandomFlyPath(TabeDirection direction, int lenght);
// Actualiza el estado
void updateState();
// Actualiza el temporizador
void updateTimer();
// Deshabilita el objeto
void disable();
public: public:
// Constructor // Constructor
Tabe(); Tabe();
@@ -55,4 +126,16 @@ public:
// Habilita el objeto // Habilita el objeto
void enable(); void enable();
// Establece el estado
void setState(TabeState state);
// Intenta obtener el bonus
bool tryToGetBonus();
// Obtiene el area de colisión
SDL_Rect &getCollider() { return sprite_->getRect(); }
// Getters
bool isEnabled() const { return enabled_; }
}; };

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