85 Commits

Author SHA1 Message Date
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
74d9c9a2b9 Commit per a vore qué està passant amb la música 2024-12-30 19:07:13 +01:00
9532caace8 Arreglades les release de windows, linux i raspberry 2024-12-30 13:44:09 +01:00
0bbd14067a Text::writeToTexture no deixava el renderitzador com estava 2024-12-30 13:43:12 +01:00
cfaa143c44 Actualitzat jail_audio 2024-12-30 13:30:06 +01:00
e61daeb92e Modificats els grafics del enemic nou
Afegits nous audios i veus
Completat el comportament del enemic nou
Ampliat el numero máxim de sons simultanis
2024-12-28 21:23:04 +01:00
d57cc15aee Treballant en el enemic nou 2024-12-27 13:38:07 +01:00
de3b18a407 Posat ordre en el Attract Mode 2024-12-26 13:58:25 +01:00
7f444fef33 Fix: mil minibugs relacionats amb el audio 2024-12-26 10:39:48 +01:00
ca18baefd7 Fix: el modo demo desactivava els sons i ja no s'activaven mai mes 2024-12-26 10:05:41 +01:00
b8dca0a46f Fet el fade out del title de video i audio i el fade in del joc de video i audio
Actualitzat jail_audio a la última versió
2024-12-26 10:03:02 +01:00
ca2c48ea17 Au, paca casa. M'he quedat a mitjes fent un fade de audio sincronitzat amb el fade de video en el titol 2024-12-23 13:56:11 +01:00
fb4d0d12db Afegits roidets de colisió per als globos per a certs moments 2024-12-23 12:37:19 +01:00
fb31445731 Comprova al iniciar que el tamany de finestra no siga mes gran que el tamany de la pantalla 2024-12-23 11:22:26 +01:00
cf4f0459b3 Es pot fer la finestra tan gran com deixe la pantalla, es a dir, el factor de zoom ja no va de 1 a 4 sino de 1 a X 2024-12-23 11:13:14 +01:00
fe0900a686 Afegides veus al jugador
Afegit efectes de so al rebotar el jugador quan mor
2024-12-15 20:00:35 +01:00
3367b70cd5 Afegit delay opcional al flash de la classe Screen 2024-12-09 20:06:59 +01:00
7016849587 FIX: afegit StopChannel en lloc de PauseChannel en el destructor del Logo
Retocada la animació del logo del joc en Title
2024-12-09 19:08:22 +01:00
301c059a26 Afegit botó per activar o desactivar el autofire 2024-12-05 12:24:18 +01:00
e3d0145417 Opció de fer el reset amb o sense reload 2024-12-05 08:25:44 +01:00
f0863b3691 Afegit zoom al subtitol ARCADE EDITION 2024-12-05 08:18:40 +01:00
80e366b208 Treballant en el zoom del titol s'ha arreglat el rebot dels globos i ara mola mes, o aixo pense 2024-12-03 13:59:40 +01:00
3c5bbf2ab0 Afegit zoom a la classe Sprite 2024-12-03 11:39:31 +01:00
1aa0dd3864 Acabats els credits a 320x240 (i per extensió, a qualsevol resolució) 2024-12-03 10:51:19 +01:00
ab45c984a2 Treballant en els credits a 240 2024-12-02 13:45:31 +01:00
020ee81479 Duplicat el fitxers de shaders per a resolucions verticals de 256 i 240 2024-12-02 13:39:19 +01:00
0cd96aced5 Afegit globalInputs::update() a totes les seccions del programa 2024-12-02 11:34:31 +01:00
ad32bb7d45 Treballant en globalInputs::update() 2024-12-02 11:11:03 +01:00
c3a5166ee1 Afegit un pragma per a IWYU 2024-12-02 09:27:51 +01:00
687d329d23 FIX: Faltva corregir el flash de destroyAllBalloons() 2024-11-27 18:58:17 +01:00
faba87c06d FIX: Si saltes el logo talla el so a meitat sonar
FIX: Corregida la lògica del efecte de flash
2024-11-27 18:39:23 +01:00
eed45bdbc6 Notifier no gastava Resource per als sons
Resource no alliberava correctament els elements de JailAudio
2024-11-27 18:20:33 +01:00
6ed37425bf Furtat el so del logo de JAILGAMES de The Pool 2024-11-27 18:02:25 +01:00
b987d06aca El joc ja reinicia correctament 2024-11-27 17:54:52 +01:00
9c9cfdabc2 Canvi de idioma (i reinicia) amb una tecla 2024-11-27 09:48:14 +01:00
9f2448753b Afegides les traduccions dels credits 2024-11-27 09:16:17 +01:00
736bf7e544 Credits acabats e integrats amb la resta del joc. Falta traduirlos pero de moment me la pela un rato 2024-11-26 19:42:26 +01:00
a2d4331430 Treballant en els credits 2024-11-25 22:56:59 +01:00
fd7beee5a1 Continuem treballant en els credits 2024-11-25 17:48:25 +01:00
a36120cf0c Continuemtreballant enels credits 2024-11-24 20:21:46 +01:00
ad221243cb Afegida musica als credits
Els globos ara tenen definida una play_area
Opció de canviar la paleta al text
2024-11-24 19:07:19 +01:00
b8d4c8f17c Començan a treballar en la secció Credits 2024-11-22 20:48:52 +01:00
97 changed files with 3456 additions and 1183 deletions

3
.gitignore vendored
View File

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

156
Makefile
View File

@@ -1,59 +1,63 @@
# Directorios # Directorios
DIR_ROOT := $(dir $(abspath $(MAKEFILE_LIST))) DIR_ROOT := $(dir $(abspath $(MAKEFILE_LIST)))
DIR_SOURCES:= $(addsuffix /, $(DIR_ROOT)source) DIR_SOURCES := $(addsuffix /, $(DIR_ROOT)source)
DIR_BIN := $(addsuffix /, $(DIR_ROOT)) DIR_BIN := $(addsuffix /, $(DIR_ROOT))
DIR_BUILD := $(addsuffix /, $(DIR_ROOT)build) DIR_BUILD := $(addsuffix /, $(DIR_ROOT)build)
# Variables # Variables
TARGET_NAME := coffee_crisis_arcade_edition TARGET_NAME := coffee_crisis_arcade_edition
TARGET_FILE := $(DIR_BIN)$(TARGET_NAME) 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 := v0.01 RESOURCE_FILE := release/coffee.res
VERSION := 2025-01-05
# 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
RASPI_RELEASE := $(TARGET_FILE)-$(VERSION)-raspberry.tar.gz
# Includes # Includes
INCLUDES:= -I$(DIR_SOURCES) INCLUDES := -I$(DIR_SOURCES)
# Variables según el sistema operativo # Variables según el sistema operativo
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
FixPath = $(subst /,\,$1) FixPath = $(subst /,\\,$1)
SOURCES := source/*.cpp SOURCES := source/*.cpp
CXXFLAGS:= -std=c++20 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows CXXFLAGS := -std=c++20 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows
CXXFLAGS_DEBUG:= -std=c++20 -Wall -g CXXFLAGS_DEBUG := -std=c++20 -Wall -g
LDFLAGS := -lmingw32 -lws2_32 -lSDL2main -lSDL2 -lopengl32 LDFLAGS := -lmingw32 -lws2_32 -lSDL2main -lSDL2 -lopengl32
RM = del /Q RM := del /Q
MKD:= mkdir MKDIR := mkdir
else else
FixPath = $1 FixPath = $1
SOURCES := $(shell find $(DIR_SOURCES) -name '*.cpp') SOURCES := $(shell find $(DIR_SOURCES) -name '*.cpp')
SOURCES := source/*.cpp SOURCES := source/*.cpp
CXXFLAGS:= -std=c++20 -Wall -Os -ffunction-sections -fdata-sections CXXFLAGS := -std=c++20 -Wall -Os -ffunction-sections -fdata-sections
CXXFLAGS_DEBUG:= -std=c++20 -Wall -g CXXFLAGS_DEBUG := -std=c++20 -Wall -g
LDFLAGS := -lSDL2 LDFLAGS := -lSDL2
RM = rm -f RMFILE := rm -f
MKD:= mkdir -p RMDIR := rm -rdf
UNAME_S := $(shell uname -s) MKDIR := mkdir -p
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux) ifeq ($(UNAME_S),Linux)
LDFLAGS += -lGL LDFLAGS += -lGL
endif endif
ifeq ($(UNAME_S),Darwin) ifeq ($(UNAME_S),Darwin)
CXXFLAGS += -Wno-deprecated CXXFLAGS += -Wno-deprecated
CXXFLAGS_DEBUG += -Wno-deprecated CXXFLAGS_DEBUG += -Wno-deprecated
LDFLAGS += -framework OpenGL LDFLAGS += -framework OpenGL
endif endif
endif endif
# Rules # 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:
@@ -80,12 +84,13 @@ 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)
strip -s -R .comment -R .gnu.version "$(RELEASE_FOLDER)/$(TARGET_FILE).exe" --strip-unneeded $(CXX) $(SOURCES) $(RESOURCE_FILE) $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FILE).exe"
strip -s -R .comment -R .gnu.version "$(RELEASE_FILE).exe" --strip-unneeded
# Crea el fichero .zip # Crea el fichero .zip
powershell if (Test-Path $(WINDOWS_RELEASE)) {Remove-Item $(WINDOWS_RELEASE)} powershell if (Test-Path "$(WINDOWS_RELEASE)") {Remove-Item "$(WINDOWS_RELEASE)"}
powershell Compress-Archive -Path "$(RELEASE_FOLDER)"/* -DestinationPath $(WINDOWS_RELEASE) powershell Compress-Archive -Path "$(RELEASE_FOLDER)"/* -DestinationPath "$(WINDOWS_RELEASE)"
# Elimina la carpeta temporal 'RELEASE_FOLDER' # Elimina la carpeta temporal 'RELEASE_FOLDER'
powershell if (Test-Path "$(RELEASE_FOLDER)") {Remove-Item "$(RELEASE_FOLDER)" -Recurse -Force} powershell if (Test-Path "$(RELEASE_FOLDER)") {Remove-Item "$(RELEASE_FOLDER)" -Recurse -Force}
@@ -98,17 +103,17 @@ macos_debug:
macos_release: macos_release:
# Elimina datos de compilaciones anteriores # Elimina datos de compilaciones anteriores
rm -rdf "$(RELEASE_FOLDER)" $(RMDIR) "$(RELEASE_FOLDER)"
rm -rdf Frameworks $(RMDIR) Frameworks
rm -f tmp.dmg $(RMFILE) tmp.dmg
rm -f "$(MACOS_INTEL_RELEASE)" $(RMFILE) "$(MACOS_INTEL_RELEASE)"
rm -f "$(MACOS_APPLE_SILICON_RELEASE)" $(RMFILE) "$(MACOS_APPLE_SILICON_RELEASE)"
# Crea la carpeta temporal para hacer el trabajo y las carpetas obligatorias para crear una app de macos # Crea la carpeta temporal para hacer el trabajo y las carpetas obligatorias para crear una app de macos
mkdir -p "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks" $(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
mkdir -p "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS" $(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS"
mkdir -p "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources" $(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
mkdir -p Frameworks $(MKDIR) Frameworks
# Copia carpetas y ficheros # Copia carpetas y ficheros
cp -R data "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources" cp -R data "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
@@ -123,24 +128,24 @@ macos_release:
ln -s /Applications "$(RELEASE_FOLDER)"/Applications ln -s /Applications "$(RELEASE_FOLDER)"/Applications
# Compila la versión para procesadores Intel # Compila la versión para procesadores Intel
$(CXX) $(SOURCES) -D MACOS_BUNDLE $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_FILE)" -rpath @executable_path/../Frameworks/ -target x86_64-apple-macos10.12 $(CXX) $(SOURCES) -D MACOS_BUNDLE $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)" -rpath @executable_path/../Frameworks/ -target x86_64-apple-macos10.12
# Empaqueta el .dmg de la versión Intel # Empaqueta el .dmg de la versión Intel
hdiutil create tmp.dmg -ov -volname "$(APP_NAME)" -fs HFS+ -srcfolder "$(RELEASE_FOLDER)" hdiutil create tmp.dmg -ov -volname "$(APP_NAME)" -fs HFS+ -srcfolder "$(RELEASE_FOLDER)"
hdiutil convert tmp.dmg -format UDZO -o "$(MACOS_INTEL_RELEASE)" hdiutil convert tmp.dmg -format UDZO -o "$(MACOS_INTEL_RELEASE)"
rm -f tmp.dmg $(RMFILE) tmp.dmg
# Compila la versión para procesadores Apple Silicon # Compila la versión para procesadores Apple Silicon
$(CXX) $(SOURCES) -D MACOS_BUNDLE $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_FILE)" -rpath @executable_path/../Frameworks/ -target arm64-apple-macos11 $(CXX) $(SOURCES) -D MACOS_BUNDLE -D SDL_DISABLE_IMMINTRIN_H $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)" -rpath @executable_path/../Frameworks/ -target arm64-apple-macos11
# Empaqueta el .dmg de la versión Apple Silicon # Empaqueta el .dmg de la versión Apple Silicon
hdiutil create tmp.dmg -ov -volname "$(APP_NAME)" -fs HFS+ -srcfolder "$(RELEASE_FOLDER)" hdiutil create tmp.dmg -ov -volname "$(APP_NAME)" -fs HFS+ -srcfolder "$(RELEASE_FOLDER)"
hdiutil convert tmp.dmg -format UDZO -o "$(MACOS_APPLE_SILICON_RELEASE)" hdiutil convert tmp.dmg -format UDZO -o "$(MACOS_APPLE_SILICON_RELEASE)"
rm -f tmp.dmg $(RMFILE) tmp.dmg
# Elimina las carpetas temporales # Elimina las carpetas temporales
$(RM) Frameworks $(RMDIR) Frameworks
$(RM) "$(RELEASE_FOLDER)" $(RMDIR) "$(RELEASE_FOLDER)"
linux: linux:
$(CXX) $(SOURCES) $(CXXFLAGS) $(LDFLAGS) -o "$(TARGET_FILE)" $(CXX) $(SOURCES) $(CXXFLAGS) $(LDFLAGS) -o "$(TARGET_FILE)"
@@ -151,10 +156,10 @@ linux_debug:
linux_release: linux_release:
# Elimina carpetas previas # Elimina carpetas previas
$(RM) "$(RELEASE_FOLDER)" $(RMDIR) "$(RELEASE_FOLDER)"
# Crea la carpeta temporal para realizar el lanzamiento # Crea la carpeta temporal para realizar el lanzamiento
mkdir -p "$(RELEASE_FOLDER)" $(MKDIR) "$(RELEASE_FOLDER)"
# Copia ficheros # Copia ficheros
cp -R data "$(RELEASE_FOLDER)" cp -R data "$(RELEASE_FOLDER)"
@@ -166,11 +171,11 @@ linux_release:
strip -s -R .comment -R .gnu.version "$(RELEASE_FILE)" --strip-unneeded strip -s -R .comment -R .gnu.version "$(RELEASE_FILE)" --strip-unneeded
# Empaqueta ficheros # Empaqueta ficheros
$(RM) "$(LINUX_RELEASE)" $(RMFILE) "$(LINUX_RELEASE)"
cd "$(RELEASE_FOLDER)" && tar -czvf "../$(LINUX_RELEASE)" * cd "$(RELEASE_FOLDER)" && tar -czvf "$(LINUX_RELEASE)" *
# Elimina la carpeta temporal # Elimina la carpeta temporal
$(RM) "$(RELEASE_FOLDER)" $(RMDIR) "$(RELEASE_FOLDER)"
raspi: raspi:
$(CXX) $(SOURCES) -D ARCADE -D VERBOSE $(CXXFLAGS) $(LDFLAGS) -o $(TARGET_FILE) $(CXX) $(SOURCES) -D ARCADE -D VERBOSE $(CXXFLAGS) $(LDFLAGS) -o $(TARGET_FILE)
@@ -179,12 +184,35 @@ raspi:
raspi_debug: raspi_debug:
$(CXX) $(SOURCES) -D ARCADE -D VERBOSE -D DEBUG $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug" $(CXX) $(SOURCES) -D ARCADE -D VERBOSE -D DEBUG $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
anbernic: raspi_release:
# Elimina carpetas previas # Elimina carpetas previas
$(RM) "$(RELEASE_FOLDER)"_anbernic $(RMDIR) "$(RELEASE_FOLDER)"
# Crea la carpeta temporal para realizar el lanzamiento # Crea la carpeta temporal para realizar el lanzamiento
mkdir -p "$(RELEASE_FOLDER)"_anbernic $(MKDIR) "$(RELEASE_FOLDER)"
# Copia ficheros
cp -R data "$(RELEASE_FOLDER)"
cp LICENSE "$(RELEASE_FOLDER)"
cp README.md "$(RELEASE_FOLDER)"
# Complia
$(CXX) $(SOURCES) -D ARCADE -D VERBOSE $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FILE)"
strip -s -R .comment -R .gnu.version "$(RELEASE_FILE)" --strip-unneeded
# Empaqueta ficheros
$(RMFILE) "$(LINUX_RELEASE)"
cd "$(RELEASE_FOLDER)" && tar -czvf "$(RASPI_RELEASE)" *
# Elimina la carpeta temporal
$(RMDIR) "$(RELEASE_FOLDER)"
anbernic:
# Elimina carpetas previas
$(RMDIR) "$(RELEASE_FOLDER)"_anbernic
# Crea la carpeta temporal para realizar el lanzamiento
$(MKDIR) "$(RELEASE_FOLDER)"_anbernic
# Copia ficheros # Copia ficheros
cp -R data "$(RELEASE_FOLDER)"_anbernic cp -R data "$(RELEASE_FOLDER)"_anbernic

View File

@@ -1,39 +1,72 @@
# 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" />
</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" />
</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 F10**: Reset | **F6** | Activa o desactiva el dispar automàtic |
| **F7** | Canvia l'idioma del joc i reinicia |
| **F10** | Reset del joc |
<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" />
</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
@@ -14,7 +16,7 @@ fade.num_squares_height 120
fade.random_squares_delay 1 fade.random_squares_delay 1
fade.random_squares_mult 500 fade.random_squares_mult 500
fade.post_duration 80 fade.post_duration 80
fade.venetian_size 16 fade.venetian_size 12
## SCOREBOARD ## SCOREBOARD
scoreboard.x 0 scoreboard.x 0

View File

@@ -1,12 +1,14 @@
## 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.width 320 # Ancho de la resolucion nativa del juego game.coffee_machine_w 28 # Ancho de la máquina de café
game.height 256 # Alto de la resolucion nativa del juego game.coffee_machine_h 37 # Alto de la máquina de café
game.play_area.rect.x 0 # Rectangulo con la posición de la zona de juego game.width 320 # Ancho de la resolucion nativa del juego
game.play_area.rect.y 0 # Rectangulo con la posición de la zona de juego game.height 256 # Alto de la resolucion nativa del juego
game.play_area.rect.w 320 # 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
game.play_area.rect.h 216 # Rectangulo con la posición de la zona de juego game.play_area.rect.y 0 # Rectangulo con la posición de la zona de juego
game.enter_name_seconds 60 # Duración en segundos para introducir el nombre al finalizar la partida game.play_area.rect.w 320 # Rectangulo con la posición de la zona de juego
game.play_area.rect.h 216 # Rectangulo con la posición de la zona de juego
game.enter_name_seconds 60 # Duración en segundos para introducir el nombre al finalizar la partida
## FADE ## FADE
fade.num_squares_width 160 fade.num_squares_width 160
@@ -14,7 +16,7 @@ fade.num_squares_height 128
fade.random_squares_delay 1 fade.random_squares_delay 1
fade.random_squares_mult 500 fade.random_squares_mult 500
fade.post_duration 80 fade.post_duration 80
fade.venetian_size 16 fade.venetian_size 12
## SCOREBOARD ## SCOREBOARD
scoreboard.x 0 scoreboard.x 0

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

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

9
data/gfx/tabe/tabe.ani Normal file
View File

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

BIN
data/gfx/tabe/tabe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -359,4 +359,16 @@ SuperPoder!
Temps! Temps!
## 120 - SCOREBOARD ## 120 - SCOREBOARD
Puntuacio Puntuacio
## 121 - CREDITS
PROGRAMAT I DISSENYAT PER
## 122 - CREDITS
GRAFICS DIBUIXATS PER
## 123 - CREDITS
MUSICA COMPOSADA PER
## 124 - CREDITS
EFECTES DE SO

View File

@@ -359,4 +359,16 @@ PowerUp
Stop! Stop!
## 120 - SCOREBOARD ## 120 - SCOREBOARD
Score Score
## 121 - CREDITS
PROGRAMMED AND DESIGNED BY
## 122 - CREDITS
PIXELART DRAWN BY
## 123 - CREDITS
MUSIC COMPOSED BY
## 124 - CREDITS
SOUND EFFECTS

View File

@@ -359,4 +359,16 @@ Potenciador
Tiempo! Tiempo!
## 120 - SCOREBOARD ## 120 - SCOREBOARD
Puntuacion Puntuacion
## 121 - CREDITS
PROGRAMADO Y DISE{ADO POR
## 122 - CREDITS
GRAFICOS DIBUJADOS POR
## 123 - CREDITS
MUSICA COMPUESTA POR
## 124 - CREDITS
EFECTOS DE SONIDO

BIN
data/music/credits.ogg Normal file

Binary file not shown.

234
data/shaders/crtpi_240.glsl Normal file
View File

@@ -0,0 +1,234 @@
/*
crt-pi - A Raspberry Pi friendly CRT shader.
Copyright (C) 2015-2016 davej
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
Notes:
This shader is designed to work well on Raspberry Pi GPUs (i.e. 1080P @ 60Hz on a game with a 4:3 aspect ratio). It pushes the Pi's GPU hard and enabling some features will slow it down so that it is no longer able to match 1080P @ 60Hz. You will need to overclock your Pi to the fastest setting in raspi-config to get the best results from this shader: 'Pi2' for Pi2 and 'Turbo' for original Pi and Pi Zero. Note: Pi2s are slower at running the shader than other Pis, this seems to be down to Pi2s lower maximum memory speed. Pi2s don't quite manage 1080P @ 60Hz - they drop about 1 in 1000 frames. You probably won't notice this, but if you do, try enabling FAKE_GAMMA.
SCANLINES enables scanlines. You'll almost certainly want to use it with MULTISAMPLE to reduce moire effects. SCANLINE_WEIGHT defines how wide scanlines are (it is an inverse value so a higher number = thinner lines). SCANLINE_GAP_BRIGHTNESS defines how dark the gaps between the scan lines are. Darker gaps between scan lines make moire effects more likely.
GAMMA enables gamma correction using the values in INPUT_GAMMA and OUTPUT_GAMMA. FAKE_GAMMA causes it to ignore the values in INPUT_GAMMA and OUTPUT_GAMMA and approximate gamma correction in a way which is faster than true gamma whilst still looking better than having none. You must have GAMMA defined to enable FAKE_GAMMA.
CURVATURE distorts the screen by CURVATURE_X and CURVATURE_Y. Curvature slows things down a lot.
By default the shader uses linear blending horizontally. If you find this too blury, enable SHARPER.
BLOOM_FACTOR controls the increase in width for bright scanlines.
MASK_TYPE defines what, if any, shadow mask to use. MASK_BRIGHTNESS defines how much the mask type darkens the screen.
*/
#pragma parameter CURVATURE_X "Screen curvature - horizontal" 0.10 0.0 1.0 0.01
#pragma parameter CURVATURE_Y "Screen curvature - vertical" 0.15 0.0 1.0 0.01
#pragma parameter MASK_BRIGHTNESS "Mask brightness" 0.70 0.0 1.0 0.01
#pragma parameter SCANLINE_WEIGHT "Scanline weight" 6.0 0.0 15.0 0.1
#pragma parameter SCANLINE_GAP_BRIGHTNESS "Scanline gap brightness" 0.12 0.0 1.0 0.01
#pragma parameter BLOOM_FACTOR "Bloom factor" 1.5 0.0 5.0 0.01
#pragma parameter INPUT_GAMMA "Input gamma" 2.4 0.0 5.0 0.01
#pragma parameter OUTPUT_GAMMA "Output gamma" 2.2 0.0 5.0 0.01
// Haven't put these as parameters as it would slow the code down.
#define SCANLINES
#define MULTISAMPLE
#define GAMMA
//#define FAKE_GAMMA
//#define CURVATURE
//#define SHARPER
// MASK_TYPE: 0 = none, 1 = green/magenta, 2 = trinitron(ish)
#define MASK_TYPE 2
#ifdef GL_ES
#define COMPAT_PRECISION mediump
precision mediump float;
#else
#define COMPAT_PRECISION
#endif
#ifdef PARAMETER_UNIFORM
uniform COMPAT_PRECISION float CURVATURE_X;
uniform COMPAT_PRECISION float CURVATURE_Y;
uniform COMPAT_PRECISION float MASK_BRIGHTNESS;
uniform COMPAT_PRECISION float SCANLINE_WEIGHT;
uniform COMPAT_PRECISION float SCANLINE_GAP_BRIGHTNESS;
uniform COMPAT_PRECISION float BLOOM_FACTOR;
uniform COMPAT_PRECISION float INPUT_GAMMA;
uniform COMPAT_PRECISION float OUTPUT_GAMMA;
#else
#define CURVATURE_X 0.05
#define CURVATURE_Y 0.1
#define MASK_BRIGHTNESS 0.80
#define SCANLINE_WEIGHT 6.0
#define SCANLINE_GAP_BRIGHTNESS 0.12
#define BLOOM_FACTOR 3.5
#define INPUT_GAMMA 2.4
#define OUTPUT_GAMMA 2.2
#endif
/* COMPATIBILITY
- GLSL compilers
*/
//uniform vec2 TextureSize;
#if defined(CURVATURE)
varying vec2 screenScale;
#endif
varying vec2 TEX0;
varying float filterWidth;
#if defined(VERTEX)
//uniform mat4 MVPMatrix;
//attribute vec4 VertexCoord;
//attribute vec2 TexCoord;
//uniform vec2 InputSize;
//uniform vec2 OutputSize;
void main()
{
#if defined(CURVATURE)
screenScale = vec2(1.0, 1.0); //TextureSize / InputSize;
#endif
filterWidth = (768.0 / 240.0) / 3.0;
TEX0 = vec2(gl_MultiTexCoord0.x, 1.0-gl_MultiTexCoord0.y)*1.0001;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
#elif defined(FRAGMENT)
uniform sampler2D Texture;
#if defined(CURVATURE)
vec2 Distort(vec2 coord)
{
vec2 CURVATURE_DISTORTION = vec2(CURVATURE_X, CURVATURE_Y);
// Barrel distortion shrinks the display area a bit, this will allow us to counteract that.
vec2 barrelScale = 1.0 - (0.23 * CURVATURE_DISTORTION);
coord *= screenScale;
coord -= vec2(0.5);
float rsq = coord.x * coord.x + coord.y * coord.y;
coord += coord * (CURVATURE_DISTORTION * rsq);
coord *= barrelScale;
if (abs(coord.x) >= 0.5 || abs(coord.y) >= 0.5)
coord = vec2(-1.0); // If out of bounds, return an invalid value.
else
{
coord += vec2(0.5);
coord /= screenScale;
}
return coord;
}
#endif
float CalcScanLineWeight(float dist)
{
return max(1.0-dist*dist*SCANLINE_WEIGHT, SCANLINE_GAP_BRIGHTNESS);
}
float CalcScanLine(float dy)
{
float scanLineWeight = CalcScanLineWeight(dy);
#if defined(MULTISAMPLE)
scanLineWeight += CalcScanLineWeight(dy-filterWidth);
scanLineWeight += CalcScanLineWeight(dy+filterWidth);
scanLineWeight *= 0.3333333;
#endif
return scanLineWeight;
}
void main()
{
vec2 TextureSize = vec2(320.0, 240.0);
#if defined(CURVATURE)
vec2 texcoord = Distort(TEX0);
if (texcoord.x < 0.0)
gl_FragColor = vec4(0.0);
else
#else
vec2 texcoord = TEX0;
#endif
{
vec2 texcoordInPixels = texcoord * TextureSize;
#if defined(SHARPER)
vec2 tempCoord = floor(texcoordInPixels) + 0.5;
vec2 coord = tempCoord / TextureSize;
vec2 deltas = texcoordInPixels - tempCoord;
float scanLineWeight = CalcScanLine(deltas.y);
vec2 signs = sign(deltas);
deltas.x *= 2.0;
deltas = deltas * deltas;
deltas.y = deltas.y * deltas.y;
deltas.x *= 0.5;
deltas.y *= 8.0;
deltas /= TextureSize;
deltas *= signs;
vec2 tc = coord + deltas;
#else
float tempY = floor(texcoordInPixels.y) + 0.5;
float yCoord = tempY / TextureSize.y;
float dy = texcoordInPixels.y - tempY;
float scanLineWeight = CalcScanLine(dy);
float signY = sign(dy);
dy = dy * dy;
dy = dy * dy;
dy *= 8.0;
dy /= TextureSize.y;
dy *= signY;
vec2 tc = vec2(texcoord.x, yCoord + dy);
#endif
vec3 colour = texture2D(Texture, tc).rgb;
#if defined(SCANLINES)
#if defined(GAMMA)
#if defined(FAKE_GAMMA)
colour = colour * colour;
#else
colour = pow(colour, vec3(INPUT_GAMMA));
#endif
#endif
scanLineWeight *= BLOOM_FACTOR;
colour *= scanLineWeight;
#if defined(GAMMA)
#if defined(FAKE_GAMMA)
colour = sqrt(colour);
#else
colour = pow(colour, vec3(1.0/OUTPUT_GAMMA));
#endif
#endif
#endif
#if MASK_TYPE == 0
gl_FragColor = vec4(colour, 1.0);
#else
#if MASK_TYPE == 1
float whichMask = fract((gl_FragCoord.x*1.0001) * 0.5);
vec3 mask;
if (whichMask < 0.5)
mask = vec3(MASK_BRIGHTNESS, 1.0, MASK_BRIGHTNESS);
else
mask = vec3(1.0, MASK_BRIGHTNESS, 1.0);
#elif MASK_TYPE == 2
float whichMask = fract((gl_FragCoord.x*1.0001) * 0.3333333);
vec3 mask = vec3(MASK_BRIGHTNESS, MASK_BRIGHTNESS, MASK_BRIGHTNESS);
if (whichMask < 0.3333333)
mask.x = 1.0;
else if (whichMask < 0.6666666)
mask.y = 1.0;
else
mask.z = 1.0;
#endif
gl_FragColor = vec4(colour * mask, 1.0);
#endif
}
}
#endif

View File

@@ -97,7 +97,6 @@ void main()
#if defined(CURVATURE) #if defined(CURVATURE)
screenScale = vec2(1.0, 1.0); //TextureSize / InputSize; screenScale = vec2(1.0, 1.0); //TextureSize / InputSize;
#endif #endif
//filterWidth = (768.0 / 240.0) / 3.0;
filterWidth = (768.0 / 256.0) / 3.0; filterWidth = (768.0 / 256.0) / 3.0;
TEX0 = vec2(gl_MultiTexCoord0.x, 1.0-gl_MultiTexCoord0.y)*1.0001; TEX0 = vec2(gl_MultiTexCoord0.x, 1.0-gl_MultiTexCoord0.y)*1.0001;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;

Binary file not shown.

BIN
data/sound/game_start.wav Normal file

Binary file not shown.

BIN
data/sound/logo.wav Normal file

Binary file not shown.

BIN
data/sound/tabe.wav Normal file

Binary file not shown.

BIN
data/sound/voice_coffee.wav Normal file

Binary file not shown.

Binary file not shown.

BIN
data/sound/voice_no.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,12 +2,13 @@
#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 "moving_sprite.h" // Para MovingSprite #include <cmath>
#include "param.h" // Para Param, ParamBackground, param #include "moving_sprite.h" // Para MovingSprite
#include "resource.h" // Para Resource #include "param.h" // Para Param, ParamBackground, param
#include "screen.h" // Para Screen #include "resource.h" // Para Resource
#include "sprite.h" // Para Sprite #include "screen.h" // Para Screen
#include "texture.h" // Para Texture #include "sprite.h" // Para Sprite
#include "texture.h" // Para Texture
// Constructor // Constructor
Background::Background() Background::Background()
@@ -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_)
{ {
@@ -322,4 +341,58 @@ 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,26 +64,32 @@ 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
// Variables // Variables
SDL_Rect gradient_rect_[4]; // Vector con las coordenadas de los 4 degradados para el cielo SDL_Rect gradient_rect_[4]; // Vector con las coordenadas de los 4 degradados para el cielo
SDL_Rect top_clouds_rect_[4]; // Vector con las coordenadas de los 4 nubes de arriba SDL_Rect top_clouds_rect_[4]; // Vector con las coordenadas de los 4 nubes de arriba
SDL_Rect bottom_clouds_rect_[4]; // Vector con las coordenadas de los 4 nubes de abajo SDL_Rect bottom_clouds_rect_[4]; // Vector con las coordenadas de los 4 nubes de abajo
int gradient_number_ = 0; // Indica el número de degradado de fondo que se va a dibujar int gradient_number_ = 0; // Indica el número de degradado de fondo que se va a dibujar
int alpha_ = 0; // Transparencia entre los dos degradados int alpha_ = 0; // Transparencia entre los dos degradados
float clouds_speed_ = 0; // Velocidad a la que se desplazan las nubes float clouds_speed_ = 0; // Velocidad a la que se desplazan las nubes
float transition_ = 0; // Nivel de transición del fondo 0..1 float transition_ = 0; // Nivel de transición del fondo 0..1
int counter_ = 0; // Contador interno int counter_ = 0; // Contador interno
SDL_Rect rect_; // Tamaño del objeto fondo SDL_Rect rect_; // Tamaño del objeto fondo
SDL_Rect src_rect_; // Parte del objeto fondo que se va a dibujará en pantalla SDL_Rect 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

@@ -5,9 +5,11 @@
#include "param.h" // Para Param, param, ParamBalloon, ParamGame #include "param.h" // Para Param, param, ParamBalloon, ParamGame
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "resource.h"
#include "jail_audio.h"
// Constructor // Constructor
Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel_x, float speed, Uint16 creation_timer, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation) Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel_x, float speed, Uint16 creation_timer, SDL_Rect play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation)
: sprite_(std::make_unique<AnimatedSprite>(texture, animation)), : sprite_(std::make_unique<AnimatedSprite>(texture, animation)),
x_(x), x_(x),
y_(y), y_(y),
@@ -19,7 +21,8 @@ Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel
creation_counter_ini_(creation_timer), creation_counter_ini_(creation_timer),
type_(type), type_(type),
size_(size), size_(size),
speed_(speed) speed_(speed),
play_area_(play_area)
{ {
switch (type_) switch (type_)
{ {
@@ -35,6 +38,7 @@ Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel
power_ = BALLOON_POWER[index]; power_ = BALLOON_POWER[index];
menace_ = BALLOON_MENACE[index]; menace_ = BALLOON_MENACE[index];
score_ = BALLOON_SCORE[index]; score_ = BALLOON_SCORE[index];
sound_ = BALLOON_SOUND[index];
break; break;
} }
@@ -49,14 +53,16 @@ Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel
power_ = BALLOON_POWER[index]; power_ = BALLOON_POWER[index];
menace_ = BALLOON_MENACE[index]; menace_ = BALLOON_MENACE[index];
score_ = BALLOON_SCORE[index]; score_ = BALLOON_SCORE[index];
sound_ = BALLOON_SOUND[index];
break; break;
} }
case BalloonType::POWERBALL: case BalloonType::POWERBALL:
{ {
const int index = 3; constexpr int index = 3;
h_ = w_ = BALLOON_SIZE[4]; h_ = w_ = BALLOON_SIZE[4];
sound_ = BALLOON_SOUND[3];
power_ = score_ = menace_ = 0; power_ = score_ = menace_ = 0;
vy_ = 0; vy_ = 0;
@@ -91,8 +97,8 @@ Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel
void Balloon::alignTo(int x) void Balloon::alignTo(int x)
{ {
x_ = static_cast<float>(x - (w_ / 2)); x_ = static_cast<float>(x - (w_ / 2));
const int min_x = param.game.play_area.rect.x; const int min_x = play_area_.x;
const int max_x = param.game.play_area.rect.w - w_; const int max_x = play_area_.w - w_;
x_ = std::clamp(x_, static_cast<float>(min_x), static_cast<float>(max_x)); x_ = std::clamp(x_, static_cast<float>(min_x), static_cast<float>(max_x));
} }
@@ -101,14 +107,27 @@ void Balloon::render()
{ {
if (type_ == BalloonType::POWERBALL) if (type_ == BalloonType::POWERBALL)
{ {
// Renderizado para la PowerBall // Renderiza el fondo azul
SDL_Point p = {24, 24}; {
sprite_->setRotatingCenter(&p); auto sp = std::make_unique<Sprite>(sprite_->getTexture(), sprite_->getPosition());
sprite_->render(); sp->setSpriteClip(0, 0, BALLOON_SIZE[4], BALLOON_SIZE[4]);
sp->render();
}
// Renderiza la estrella
if (!invulnerable_)
{
SDL_Point p = {24, 24};
sprite_->setRotatingCenter(&p);
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()); {
sp->setSpriteClip(BALLOON_SIZE[4], 0, BALLOON_SIZE[4], BALLOON_SIZE[4]); auto sp = std::make_unique<Sprite>(sprite_->getTexture(), sprite_->getPosition());
sp->render(); sp->setSpriteClip(BALLOON_SIZE[4] * 2, 0, BALLOON_SIZE[4], BALLOON_SIZE[4]);
sp->render();
}
} }
else else
{ {
@@ -122,18 +141,8 @@ void Balloon::render()
} }
else else
{ {
if (bouncing_.enabled) // Renderizado normal
{ sprite_->render();
// Renderizado con efecto de bouncing
sprite_->setPos(x_ + bouncing_.despX, y_ + bouncing_.despY);
sprite_->render();
// sprite_->setPos(x_ - bouncing_.despX, y_ - bouncing_.despY);
}
else
{
// Renderizado normal
sprite_->render();
}
} }
} }
} }
@@ -149,10 +158,11 @@ void Balloon::move()
// Colisión en las partes laterales de la zona de juego // Colisión en las partes laterales de la zona de juego
const int clip = 2; const int clip = 2;
const float min_x = param.game.play_area.rect.x - clip; const float min_x = play_area_.x - clip;
const float max_x = param.game.play_area.rect.w - w_ + clip; const float max_x = play_area_.x + play_area_.w - w_ + clip;
if (x_ < min_x || x_ > max_x) if (x_ < min_x || x_ > max_x)
{ {
playSound();
x_ = std::clamp(x_, min_x, max_x); x_ = std::clamp(x_, min_x, max_x);
vx_ = -vx_; vx_ = -vx_;
// Activa el efecto de rebote o invierte la rotación // Activa el efecto de rebote o invierte la rotación
@@ -169,12 +179,13 @@ 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 // Colisión en la parte superior solo si el globo va de subida
if (type_ != BalloonType::POWERBALL) if (vy_ < 0)
{ {
const int min_y = param.game.play_area.rect.y; const int min_y = play_area_.y;
if (y_ < min_y) if (y_ < min_y)
{ {
playSound();
y_ = min_y; y_ = min_y;
vy_ = -vy_; vy_ = -vy_;
enableBounce(); enableBounce();
@@ -182,15 +193,20 @@ void Balloon::move()
} }
// Colisión en la parte inferior de la zona de juego // Colisión en la parte inferior de la zona de juego
const int max_y = param.game.play_area.rect.h - h_; const int max_y = play_area_.y + play_area_.h - h_;
if (y_ > max_y) if (y_ > max_y)
{ {
playSound();
y_ = max_y; y_ = max_y;
vy_ = -default_vy_; vy_ = -default_vy_;
if (type_ != BalloonType::POWERBALL) if (type_ != BalloonType::POWERBALL)
{ {
enableBounce(); enableBounce();
} }
else
{
setInvulnerable(false);
}
} }
/* /*
@@ -217,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()
{ {
@@ -254,8 +264,8 @@ void Balloon::updateState()
x_ += vx_; x_ += vx_;
// Comprueba no se salga por los laterales // Comprueba no se salga por los laterales
const int min_x = param.game.play_area.rect.x; const int min_x = play_area_.x;
const int max_x = param.game.play_area.rect.w - w_; const int max_x = play_area_.w - w_;
if (x_ < min_x || x_ > max_x) if (x_ < min_x || x_ > max_x)
{ {
@@ -375,12 +385,10 @@ void Balloon::updateBounce()
zoomSprite(); zoomSprite();
const auto spriteClip = sprite_->getSpriteClip();
bouncing_.despX = spriteClip.w * (1.0f - bouncing_.zoomW);
bouncing_.despY = spriteClip.h * (1.0f - bouncing_.zoomH);
if (++bouncing_.counter / bouncing_.speed >= MAX_BOUNCE) if (++bouncing_.counter / bouncing_.speed >= MAX_BOUNCE)
{
disableBounce(); disableBounce();
}
} }
} }
@@ -399,4 +407,13 @@ void Balloon::useNormalColor()
{ {
use_reversed_colors_ = false; use_reversed_colors_ = false;
setAnimation(); setAnimation();
}
// Reproduce el sonido al rebotar
void Balloon::playSound()
{
if (sound_enabled_)
{
JA_PlaySound(Resource::get()->getSound(sound_));
}
} }

View File

@@ -1,12 +1,13 @@
#pragma once #pragma once
#include <SDL2/SDL_rect.h> // Para SDL_Rect
#include <SDL2/SDL_stdinc.h> // Para Uint8, Uint16, Uint32 #include <SDL2/SDL_stdinc.h> // Para Uint8, Uint16, Uint32
#include <memory> // Para shared_ptr, unique_ptr #include <memory> // Para shared_ptr, unique_ptr
#include <string> // Para string #include <string> // Para string
#include <vector> // Para vector #include <vector> // Para vector
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
#include "utils.h" // Para Circle #include "utils.h" // Para Circle
class Texture; // lines 10-10 class Texture; // lines 9-9
// Cantidad de elementos del vector con los valores de la deformación del globo al rebotar // Cantidad de elementos del vector con los valores de la deformación del globo al rebotar
constexpr int MAX_BOUNCE = 10; constexpr int MAX_BOUNCE = 10;
@@ -16,6 +17,7 @@ constexpr int BALLOON_SCORE[] = {50, 100, 200, 400};
constexpr int BALLOON_POWER[] = {1, 3, 7, 15}; constexpr int BALLOON_POWER[] = {1, 3, 7, 15};
constexpr int BALLOON_MENACE[] = {1, 2, 4, 8}; constexpr int BALLOON_MENACE[] = {1, 2, 4, 8};
constexpr int BALLOON_SIZE[] = {10, 16, 26, 48, 49}; constexpr int BALLOON_SIZE[] = {10, 16, 26, 48, 49};
const std::string BALLOON_SOUND[] = {"bubble1.wav", "bubble2.wav", "bubble3.wav", "bubble4.wav"};
// Tamaños de globo // Tamaños de globo
enum class BalloonSize : Uint8 enum class BalloonSize : Uint8
@@ -111,6 +113,9 @@ private:
float travel_y_ = 1.0f; // Distancia que ha de recorrer el globo en el eje Y antes de que se le aplique la gravedad float travel_y_ = 1.0f; // Distancia que ha de recorrer el globo en el eje Y antes de que se le aplique la gravedad
float speed_; // Velocidad a la que se mueven los globos float speed_; // Velocidad a la que se mueven los globos
Uint8 power_; // Cantidad de poder que alberga el globo Uint8 power_; // Cantidad de poder que alberga el globo
SDL_Rect play_area_; // Zona por donde se puede mover el globo
std::string sound_; // Archivo de sonido que hace el globo al rebotar
bool sound_enabled_ = false; // Indica si ha de sonar el sonido del globo al rebotar
// Alinea el circulo de colisión con la posición del objeto globo // Alinea el circulo de colisión con la posición del objeto globo
void shiftColliders(); void shiftColliders();
@@ -136,9 +141,22 @@ private:
// Establece la animación correspondiente // Establece la animación correspondiente
void setAnimation(); void setAnimation();
// Reproduce el sonido al rebotar
void playSound();
public: public:
// Constructor // Constructor
Balloon(float x, float y, BalloonType type, BalloonSize size, float vel_x, float speed, Uint16 creation_timer, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation); Balloon(
float x,
float y,
BalloonType type,
BalloonSize size,
float vel_x,
float speed,
Uint16 creation_timer,
SDL_Rect play_area,
std::shared_ptr<Texture> texture,
const std::vector<std::string> &animation);
// Destructor // Destructor
~Balloon() = default; ~Balloon() = default;
@@ -152,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();
@@ -196,4 +208,6 @@ public:
void setVelY(float vel_y) { vy_ = vel_y; } void setVelY(float vel_y) { vy_ = vel_y; }
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 disable() { enabled_ = false; }
}; };

View File

@@ -38,7 +38,6 @@ struct BalloonFormationUnit
BalloonFormationUnit() : number_of_balloons(0), init() {} BalloonFormationUnit() : number_of_balloons(0), init() {}
}; };
using BalloonFormationPool = std::vector<const BalloonFormationUnit *>; using BalloonFormationPool = std::vector<const BalloonFormationUnit *>;
class BalloonFormations class BalloonFormations
@@ -67,4 +66,5 @@ public:
// Getters // Getters
const BalloonFormationPool &getPool(int pool) { return balloon_formation_pool_.at(pool); } const BalloonFormationPool &getPool(int pool) { return balloon_formation_pool_.at(pool); }
const BalloonFormationUnit &getSet(int pool, int set) { return *balloon_formation_pool_.at(pool).at(set); } const BalloonFormationUnit &getSet(int pool, int set) { return *balloon_formation_pool_.at(pool).at(set); }
const BalloonFormationUnit &getSet(int set) const { return balloon_formation_.at(set); }
}; };

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;
@@ -119,6 +126,30 @@ void BalloonManager::deployBalloonFormation(int stage)
} }
} }
// Crea una formación de enemigos específica
void BalloonManager::deploySet(int set_number)
{
const auto set = balloon_formations_->getSet(set_number);
const auto num_enemies = set.number_of_balloons;
for (int i = 0; i < num_enemies; ++i)
{
auto p = set.init[i];
createBalloon(p.x, p.y, p.type, p.size, p.vel_x, balloon_speed_, p.creation_counter);
}
}
// Crea una formación de enemigos específica
void BalloonManager::deploySet(int set_number, int y)
{
const auto set = balloon_formations_->getSet(set_number);
const auto num_enemies = set.number_of_balloons;
for (int i = 0; i < num_enemies; ++i)
{
auto p = set.init[i];
createBalloon(p.x, y, p.type, p.size, p.vel_x, balloon_speed_, p.creation_counter);
}
}
// Vacia del vector de globos los globos que ya no sirven // Vacia del vector de globos los globos que ya no sirven
void BalloonManager::freeBalloons() void BalloonManager::freeBalloons()
{ {
@@ -149,49 +180,61 @@ 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)
{ {
const int index = static_cast<int>(size); if (can_deploy_balloons_)
balloons_.emplace_back(std::make_shared<Balloon>(x, y, type, size, velx, speed, creation_timer, balloon_textures_.at(index), balloon_animations_.at(index))); {
return balloons_.back(); 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)));
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)
{ {
const float vx = direction == "LEFT" ? BALLOON_VELX_NEGATIVE : BALLOON_VELX_POSITIVE; if (can_deploy_balloons_)
const auto lower_size = static_cast<BalloonSize>(static_cast<int>(balloon->getSize()) - 1);
auto b = createBalloon(0, balloon->getPosY(), balloon->getType(), lower_size, vx, balloon_speed_, 0);
const int x = direction == "LEFT" ? balloon->getPosX() + (balloon->getWidth() / 3) : balloon->getPosX() + 2 * (balloon->getWidth() / 3);
b->alignTo(x);
b->setVelY(b->getType() == BalloonType::BALLOON ? -2.50f : BALLOON_VELX_NEGATIVE * 2.0f);
if (balloon->isStopped())
{ {
b->stop(); const float vx = direction == "LEFT" ? BALLOON_VELX_NEGATIVE : BALLOON_VELX_POSITIVE;
} const auto lower_size = static_cast<BalloonSize>(static_cast<int>(balloon->getSize()) - 1);
if (balloon->isUsingReversedColor()) auto b = createBalloon(0, balloon->getPosY(), balloon->getType(), lower_size, vx, balloon_speed_, 0);
{ const int x = direction == "LEFT" ? balloon->getPosX() + (balloon->getWidth() / 3) : balloon->getPosX() + 2 * (balloon->getWidth() / 3);
b->useReverseColor(); b->alignTo(x);
b->setVelY(b->getType() == BalloonType::BALLOON ? -2.50f : BALLOON_VELX_NEGATIVE * 2.0f);
if (balloon->isStopped())
{
b->stop();
}
if (balloon->isUsingReversedColor())
{
b->useReverseColor();
}
} }
} }
// Crea una PowerBall // Crea una PowerBall
void BalloonManager::createPowerBall() void BalloonManager::createPowerBall()
{ {
constexpr int values = 6; if (can_deploy_balloons_)
constexpr int pos_y = -BALLOON_SIZE[4]; {
constexpr int creation_time = 0; constexpr int values = 6;
constexpr int pos_y = -BALLOON_SIZE[4];
constexpr int creation_time = 0;
const auto left = param.game.play_area.rect.x; const auto left = param.game.play_area.rect.x;
const auto center = param.game.play_area.center_x - (BALLOON_SIZE[4] / 2); const auto center = param.game.play_area.center_x - (BALLOON_SIZE[4] / 2);
const auto right = param.game.play_area.rect.w - BALLOON_SIZE[4]; const auto right = param.game.play_area.rect.w - BALLOON_SIZE[4];
const auto luck = rand() % values; const auto luck = rand() % values;
const int x[values] = {left, left, center, center, right, right}; const int x[values] = {left, left, center, center, right, right};
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, 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
@@ -227,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;
@@ -263,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;
} }
@@ -279,7 +322,7 @@ int BalloonManager::destroyAllBalloons()
balloon_deploy_counter_ = 300; balloon_deploy_counter_ = 300;
JA_PlaySound(Resource::get()->getSound("powerball.wav")); JA_PlaySound(Resource::get()->getSound("powerball.wav"));
Screen::get()->flash(flash_color, 100); Screen::get()->flash(flash_color, 3);
Screen::get()->shake(); Screen::get()->shake();
return score; return score;
@@ -339,12 +382,21 @@ void BalloonManager::reLoad()
// Crea dos globos gordos // Crea dos globos gordos
void BalloonManager::createTwoBigBalloons() void BalloonManager::createTwoBigBalloons()
{ {
const auto set = balloon_formations_->getSet(0, 1); deploySet(1);
const auto numEnemies = set.number_of_balloons; }
for (int i = 0; i < numEnemies; ++i)
// 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)
{ {
auto p = set.init[i]; const float x = param.game.game_area.rect.x + (rand() % param.game.game_area.rect.w) - BALLOON_SIZE[3];
createBalloon(p.x, p.y, p.type, p.size, p.vel_x, balloon_speed_, p.creation_counter); 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);
} }
} }
@@ -353,4 +405,13 @@ int BalloonManager::getMenace()
{ {
return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon) return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon)
{ return sum + (balloon->isEnabled() ? balloon->getMenace() : 0); }); { return sum + (balloon->isEnabled() ? balloon->getMenace() : 0); });
}
// Establece el sonido de los globos
void BalloonManager::setSounds(bool value)
{
for (auto &balloon : balloons_)
{
balloon->setSound(value);
}
} }

View File

@@ -1,12 +1,15 @@
#pragma once #pragma once
#include <SDL2/SDL_rect.h> // Para SDL_Rect
#include <memory> // Para shared_ptr, unique_ptr #include <memory> // Para shared_ptr, unique_ptr
#include <string> // Para string #include <string> // Para string
#include <vector> // Para vector #include <vector> // Para vector
#include "balloon.h" // Para BALLOON_SPEED, Balloon #include "balloon.h" // Para BALLOON_SPEED, Balloon
#include "balloon_formations.h" // Para BalloonFormations #include "balloon_formations.h" // Para BalloonFormations
#include "explosions.h" // Para Explosions #include "explosions.h" // Para Explosions
class Texture; #include "param.h" // Para Param, ParamGame, param
#include "utils.h" // Para Zone
class Texture; // lines 10-10
using Balloons = std::vector<std::shared_ptr<Balloon>>; using Balloons = std::vector<std::shared_ptr<Balloon>>;
@@ -29,6 +32,9 @@ private:
bool power_ball_enabled_ = false; // Indica si hay una powerball ya activa bool power_ball_enabled_ = false; // Indica si hay una powerball ya activa
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
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();
@@ -49,9 +55,13 @@ public:
// Vacia del vector de globos los globos que ya no sirven // Vacia del vector de globos los globos que ya no sirven
void freeBalloons(); void freeBalloons();
// Crea una formación de enemigos // Crea una formación de enemigos al azar
void deployBalloonFormation(int stage); void deployBalloonFormation(int stage);
// Crea una formación de enemigos específica
void deploySet(int set);
void deploySet(int set, int y);
// Actualiza la variable enemyDeployCounter // Actualiza la variable enemyDeployCounter
void updateBalloonDeployCounter(); void updateBalloonDeployCounter();
@@ -100,14 +110,24 @@ 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();
// Establece el sonido de los globos
void setSounds(bool value);
// 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 setCreationTimeEnabled(bool value) { creation_time_enabled_ = value; }
void setDeployBalloons(bool value) { can_deploy_balloons_ = value; }
}; };

496
source/credits.cpp Normal file
View File

@@ -0,0 +1,496 @@
// IWYU pragma: no_include <bits/std_abs.h>
#include "credits.h"
#include <SDL2/SDL_blendmode.h> // Para SDL_BLENDMODE_BLEND
#include <SDL2/SDL_events.h> // Para SDL_PollEvent, SDL_Event, SDL_QUIT
#include <SDL2/SDL_pixels.h> // Para SDL_PIXELFORMAT_RGBA8888
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
#include <algorithm> // Para max, min, clamp
#include <cstdlib> // Para abs
#include <stdexcept> // Para runtime_error
#include <string> // Para basic_string, string
#include <vector> // Para vector
#include "balloon_manager.h" // Para BalloonManager
#include "fade.h" // Para Fade, FadeType, FadeMode
#include "global_inputs.h" // Para check, update
#include "input.h" // Para Input
#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 "player.h" // Para Player, PlayerState
#include "resource.h" // Para Resource
#include "screen.h" // Para Screen
#include "section.h" // Para Name, name, Options, options
#include "sprite.h" // Para Sprite
#include "text.h" // Para Text, TEXT_CENTER, TEXT_SHADOW
#include "texture.h" // Para Texture
#include "tiled_bg.h" // Para TiledBG, TiledBGMode
#include "utils.h" // Para Color, Zone, shdw_txt_color, no_color
// Textos
constexpr const char TEXT_COPYRIGHT[] = "@2020,2025 JailDesigner";
// Constructor
Credits::Credits()
: 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)),
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)),
fade_in_(std::make_unique<Fade>()),
fade_out_(std::make_unique<Fade>())
{
if (!text_texture_)
{
throw std::runtime_error("Failed to create SDL texture for text.");
}
section::name = section::Name::CREDITS;
balloon_manager_->setPlayArea(play_area_);
fade_in_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_in_->setType(FadeType::FULLSCREEN);
fade_in_->setPostDuration(50);
fade_in_->setMode(FadeMode::IN);
fade_in_->activate();
fade_out_->setColor(0, 0, 0);
fade_out_->setType(FadeType::FULLSCREEN);
fade_out_->setPostDuration(400);
initPlayers();
SDL_SetTextureBlendMode(text_texture_, SDL_BLENDMODE_BLEND);
fillTextTexture();
steps_ = std::abs((top_black_rect_.h - param.game.game_area.center_y - 1) + ((left_black_rect_.w - param.game.game_area.center_x) / 4));
}
// Destructor
Credits::~Credits()
{
SDL_DestroyTexture(text_texture_);
SDL_DestroyTexture(canvas_);
resetVolume();
}
// Bucle principal
void Credits::run()
{
while (section::name == section::Name::CREDITS)
{
checkInput();
update();
checkEvents(); // Tiene que ir antes del render
render();
}
}
// Actualiza las variables
void Credits::update()
{
constexpr Uint32 TICKS_SPEED_ = 15;
if (SDL_GetTicks() - ticks_ > TICKS_SPEED_)
{
ticks_ = SDL_GetTicks();
const int repeat = want_to_pass_ ? 4 : 1;
for (int i = 0; i < repeat; ++i)
{
tiled_bg_->update();
balloon_manager_->update();
updateTextureDstRects();
throwBalloons();
for (auto &player : players_)
{
player->update();
}
updateAllFades();
++counter_;
}
Screen::get()->update();
globalInputs::update();
fillCanvas();
}
}
// Dibuja Credits::en patalla
void Credits::render()
{
// Prepara para empezar a dibujar en la textura de juego
Screen::get()->start();
// Copia la textura con la zona de juego a la pantalla
SDL_RenderCopy(Screen::get()->getRenderer(), canvas_, nullptr, nullptr);
// Vuelca el contenido del renderizador en pantalla
Screen::get()->render();
}
// Comprueba el manejador de eventos
void Credits::checkEvents()
{
SDL_Event event;
// Comprueba los eventos que hay en la cola
while (SDL_PollEvent(&event))
{
// Evento de salida de la aplicación
if (event.type == SDL_QUIT)
{
section::name = section::Name::QUIT;
section::options = section::Options::QUIT_FROM_EVENT;
break;
}
// Comprueba el cursor
Mouse::handleEvent(event);
}
}
// Comprueba las entradas
void Credits::checkInput()
{
// Comprueba si se ha pulsado cualquier botón (de los usados para jugar)
if (Input::get()->checkAnyButtonPressed())
{
if (mini_logo_on_position_)
{
// Si el mini_logo ha llegado a su posición final, al pulsar cualquier tecla se activa el fundido
fading_ = true;
}
else
{
// Si todavía estan los creditos en marcha, se pasan solos a toda pastilla
want_to_pass_ = true;
}
}
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
globalInputs::check();
}
// Crea la textura con el texto
void Credits::fillTextTexture()
{
auto text = Resource::get()->getText("smb2");
SDL_SetRenderTarget(Screen::get()->getRenderer(), text_texture_);
SDL_SetRenderDrawColor(Screen::get()->getRenderer(), 0, 0, 0, 0);
SDL_RenderClear(Screen::get()->getRenderer());
std::vector<std::string> texts = {
lang::getText(121),
lang::getText(122),
lang::getText(123),
lang::getText(124),
"JAILDESIGNER",
"JAILDOCTOR (INTRO)",
"ERIC MATYAS (SOUNDIMAGE.ORG)",
"WWW.THEMOTIONMONKEY.CO.UK",
"WWW.KENNEY.NL",
"JAILDOCTOR"};
const int space_post_title = 3 + text->getCharacterSize();
const int space_pre_title = text->getCharacterSize() * 4;
const int texts_height = 1 * text->getCharacterSize() + 7 * space_post_title + 3 * space_pre_title;
credits_rect_dst_.h = credits_rect_src_.h = texts_height;
int y = (param.game.height - texts_height) / 2;
y = 0;
text->setPalette(1);
text->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, y, texts.at(0), 1, no_color, 1, shdw_txt_color);
text->setPalette(0);
y += space_post_title;
text->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, y, texts.at(4), 1, no_color, 1, shdw_txt_color);
y += space_pre_title;
text->setPalette(1);
text->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, y, texts.at(1), 1, no_color, 1, shdw_txt_color);
text->setPalette(0);
y += space_post_title;
text->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, y, texts.at(4), 1, no_color, 1, shdw_txt_color);
y += space_pre_title;
text->setPalette(1);
text->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, y, texts.at(2), 1, no_color, 1, shdw_txt_color);
text->setPalette(0);
y += space_post_title;
text->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, y, texts.at(5), 1, no_color, 1, shdw_txt_color);
y += space_post_title;
text->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, y, texts.at(6), 1, no_color, 1, shdw_txt_color);
y += space_pre_title;
text->setPalette(1);
text->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, y, texts.at(3), 1, no_color, 1, shdw_txt_color);
text->setPalette(0);
y += space_post_title;
text->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, y, texts.at(7), 1, no_color, 1, shdw_txt_color);
y += space_post_title;
text->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, y, texts.at(8), 1, no_color, 1, shdw_txt_color);
y += space_post_title;
text->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, y, texts.at(9), 1, no_color, 1, shdw_txt_color);
// Mini logo
y += space_pre_title;
mini_logo_rect_src_.y = y;
auto mini_logo_sprite = std::make_unique<Sprite>(Resource::get()->getTexture("logo_jailgames_mini.png"));
mini_logo_sprite->setPosition(1 + param.game.game_area.center_x - mini_logo_sprite->getWidth() / 2, 1 + y);
Resource::get()->getTexture("logo_jailgames_mini.png")->setColor(shdw_txt_color.r, shdw_txt_color.g, shdw_txt_color.b);
mini_logo_sprite->render();
mini_logo_sprite->setPosition(param.game.game_area.center_x - mini_logo_sprite->getWidth() / 2, y);
Resource::get()->getTexture("logo_jailgames_mini.png")->setColor(255, 255, 255);
mini_logo_sprite->render();
// Texto con el copyright
y += mini_logo_sprite->getHeight() + 3;
text->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, y, TEXT_COPYRIGHT, 1, no_color, 1, shdw_txt_color);
// Resetea el renderizador
SDL_SetRenderTarget(Screen::get()->getRenderer(), nullptr);
// Actualiza las variables
mini_logo_rect_dst_.h = mini_logo_rect_src_.h = mini_logo_sprite->getHeight() + 3 + text->getCharacterSize();
credits_rect_dst_.y = param.game.game_area.rect.h;
mini_logo_rect_dst_.y = credits_rect_dst_.y + credits_rect_dst_.h + 30;
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
void Credits::updateTextureDstRects()
{
if (counter_ % 10 == 0)
{
// Comprueba la posición de la textura con los titulos de credito
if (credits_rect_dst_.y + credits_rect_dst_.h > play_area_.y)
{
--credits_rect_dst_.y;
}
// Comprueba la posición de la textura con el mini_logo
if (mini_logo_rect_dst_.y == mini_logo_final_pos_)
{
mini_logo_on_position_ = true;
// Si el jugador quiere pasar los titulos de credito, el fade se inicia solo
if (want_to_pass_)
{
fading_ = true;
}
// Se activa el contador para evitar que la sección sea infinita
if (counter_prevent_endless_ == 1000)
{
fading_ = true;
}
else
{
++counter_prevent_endless_;
}
}
else
{
--mini_logo_rect_dst_.y;
}
}
}
// Tira globos al escenario
void Credits::throwBalloons()
{
constexpr int speed = 200;
const std::vector<int> sets = {0, 63, 25, 67, 17, 75, 13, 50};
if (counter_ > ((sets.size() - 1) * speed) * 3)
{
return;
}
if (counter_ % speed == 0)
{
const int index = (counter_ / speed) % sets.size();
balloon_manager_->deploySet(sets.at(index), -60);
}
if (counter_ % (speed * 4) == 0 && counter_ > 0)
{
balloon_manager_->createPowerBall();
}
}
// Inicializa los jugadores
void Credits::initPlayers()
{
std::vector<std::vector<std::shared_ptr<Texture>>> player_textures; // Vector con todas las texturas de los jugadores;
std::vector<std::vector<std::string>> player_animations; // Vector con las animaciones del jugador
// Texturas - Player1
{
std::vector<std::shared_ptr<Texture>> player_texture;
player_texture.emplace_back(Resource::get()->getTexture("player1.gif"));
player_texture.emplace_back(Resource::get()->getTexture("player1_power.png"));
player_textures.push_back(player_texture);
}
// Texturas - Player2
{
std::vector<std::shared_ptr<Texture>> player_texture;
player_texture.emplace_back(Resource::get()->getTexture("player2.gif"));
player_texture.emplace_back(Resource::get()->getTexture("player2_power.png"));
player_textures.push_back(player_texture);
}
// Animaciones -- Jugador
{
player_animations.emplace_back(Resource::get()->getAnimation("player.ani"));
player_animations.emplace_back(Resource::get()->getAnimation("player_power.ani"));
}
// Crea los dos jugadores
constexpr int player_width = 30;
const int y = play_area_.y + play_area_.h - player_width;
constexpr bool demo = false;
constexpr int away_distance = 700;
players_.emplace_back(std::make_unique<Player>(1, play_area_.x - away_distance - player_width, y, demo, play_area_, player_textures.at(0), player_animations));
players_.back()->setWalkingState(PlayerState::WALKING_RIGHT);
players_.back()->setPlayingState(PlayerState::CREDITS);
players_.back()->setInvulnerable(false);
players_.emplace_back(std::make_unique<Player>(2, play_area_.x + play_area_.w + away_distance, y, demo, play_area_, player_textures.at(1), player_animations));
players_.back()->setWalkingState(PlayerState::WALKING_LEFT);
players_.back()->setPlayingState(PlayerState::CREDITS);
players_.back()->setInvulnerable(false);
}
// Actualiza los rectangulos negros
void Credits::updateBlackRects()
{
static int current_step = steps_;
if (top_black_rect_.h != param.game.game_area.center_y - 1 && bottom_black_rect_.y != param.game.game_area.center_y + 1)
{
// Si los rectangulos superior e inferior no han llegado al centro
if (counter_ % 4 == 0)
{
// Incrementa la altura del rectangulo superior
top_black_rect_.h = std::min(top_black_rect_.h + 1, param.game.game_area.center_y - 1);
// Incrementa la altura y modifica la posición del rectangulo inferior
++bottom_black_rect_.h;
bottom_black_rect_.y = std::max(bottom_black_rect_.y - 1, param.game.game_area.center_y + 1);
--current_step;
setVolume(static_cast<int>(initial_volume_ * current_step / steps_));
}
}
else
{
// Si los rectangulos superior e inferior han llegado al centro
if (left_black_rect_.w != param.game.game_area.center_x && right_black_rect_.x != param.game.game_area.center_x)
{
// Si los rectangulos izquierdo y derecho no han llegado al centro
// Incrementa la anchura del rectangulo situado a la izquierda
left_black_rect_.w = std::min(left_black_rect_.w + 4, param.game.game_area.center_x);
// Incrementa la anchura y modifica la posición del rectangulo situado a la derecha
right_black_rect_.w += 4;
right_black_rect_.x = std::max(right_black_rect_.x - 4, param.game.game_area.center_x);
--current_step;
setVolume(static_cast<int>(initial_volume_ * current_step / steps_));
}
else
{
// Si los rectangulos izquierdo y derecho han llegado al centro
setVolume(0);
JA_StopMusic();
if (counter_pre_fade_ == 400)
{
fade_out_->activate();
}
else
{
++counter_pre_fade_;
}
}
}
}
// Actualiza el estado de fade
void Credits::updateAllFades()
{
if (fading_)
{
updateBlackRects();
}
fade_in_->update();
if (fade_in_->hasEnded())
{
if (JA_GetMusicState() == JA_MUSIC_INVALID || JA_GetMusicState() == JA_MUSIC_STOPPED)
{
JA_PlayMusic(Resource::get()->getMusic("credits.ogg"));
}
}
fade_out_->update();
if (fade_out_->hasEnded())
{
section::name = section::Name::LOGO;
}
}
// Establece el nivel de volumen
void Credits::setVolume(int amount)
{
options.audio.music.volume = std::clamp(amount, 0, 100);
JA_SetMusicVolume(to_JA_volume(options.audio.music.volume));
}
// Reestablece el nivel de volumen
void Credits::resetVolume()
{
options.audio.music.volume = initial_volume_;
JA_SetMusicVolume(to_JA_volume(options.audio.music.volume));
}

106
source/credits.h Normal file
View File

@@ -0,0 +1,106 @@
#pragma once
#include <SDL2/SDL_rect.h> // Para SDL_Rect
#include <SDL2/SDL_render.h> // Para SDL_Texture
#include <SDL2/SDL_stdinc.h> // Para Uint32
#include <memory> // Para unique_ptr, shared_ptr
#include <vector> // Para vector
#include "options.h" // Para Options, OptionsAudio, OptionsMusic
#include "param.h" // Para Param, ParamGame, param
#include "utils.h" // Para Zone
class BalloonManager; // lines 8-8
class Fade; // lines 11-11
class Player; // lines 10-10
class TiledBG; // lines 9-9
constexpr int PLAY_AREA_HEIGHT = 200;
class Credits
{
private:
// Objetos
std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos
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<Fade> fade_in_; // Objeto para realizar el fundido de entrada
std::unique_ptr<Fade> fade_out_; // Objeto para realizar el fundido de salida
std::vector<std::shared_ptr<Player>> players_; // Vector con los jugadores
// Variables
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
Uint32 counter_ = 0; // Contador para la lógica de la clase
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
int black_bars_size_ = (param.game.game_area.rect.h - PLAY_AREA_HEIGHT) / 2; // Tamaño de las barras negras
int mini_logo_final_pos_ = 0; // Ubicación donde se detiene el minilogo
bool fading_ = false; // Indica si se está realizando el fade final
bool want_to_pass_ = false; // Indica si el jugador quiere saltarse los titulos de crédito
bool mini_logo_on_position_ = false; // Indica si el minilogo ya se ha quedado en su posición
int initial_volume_ = options.audio.music.volume; // Volumen actual al crear el objeto
int steps_ = 0; // Cantidad de pasos a dar para ir reduciendo el audio
// Rectangulos
SDL_Rect credits_rect_src_ = param.game.game_area.rect; // Rectangulo con el texto de los créditos (origen)
SDL_Rect credits_rect_dst_ = param.game.game_area.rect; // Rectangulo con el texto de los créditos (destino)
SDL_Rect mini_logo_rect_src_ = param.game.game_area.rect; // Rectangulo con el mini logo de JailGames y el texto de copyright (origen)
SDL_Rect mini_logo_rect_dst_ = param.game.game_area.rect; // Rectangulo con el mini logo de JailGames y el texto de copyright (destino)
SDL_Rect play_area_ = {
param.game.game_area.rect.x,
param.game.game_area.rect.y + black_bars_size_,
param.game.game_area.rect.w,
PLAY_AREA_HEIGHT}; // Area visible para los creditos
SDL_Rect top_black_rect_ = {play_area_.x, param.game.game_area.rect.y, play_area_.w, black_bars_size_}; // Rectangulo negro superior
SDL_Rect bottom_black_rect_ = {play_area_.x, param.game.game_area.rect.h - black_bars_size_, play_area_.w, black_bars_size_}; // Rectangulo negro inferior
SDL_Rect left_black_rect_ = {play_area_.x, param.game.game_area.center_y - 1, 0, 2}; // Rectangulo negro situado a la izquierda
SDL_Rect right_black_rect_ = {play_area_.x + play_area_.w, param.game.game_area.center_y - 1, 0, 2}; // Rectangulo negro situado a la derecha
// Actualiza las variables
void update();
// Dibuja en pantalla
void render();
// Comprueba el manejador de eventos
void checkEvents();
// Comprueba las entradas
void checkInput();
// Crea la textura con el texto
void fillTextTexture();
// Dibuja todos los sprites en la textura
void fillCanvas();
// Actualiza el destino de los rectangulos de las texturas
void updateTextureDstRects();
// Tira globos al escenario
void throwBalloons();
// Inicializa los jugadores
void initPlayers();
// Actualiza los rectangulos negros
void updateBlackRects();
// Actualiza el estado de fade
void updateAllFades();
// Establece el nivel de volumen
void setVolume(int amount);
// Reestablece el nivel de volumen
void resetVolume();
public:
// Constructor
Credits();
// Destructor
~Credits();
// Bucle principal
void run();
};

View File

@@ -1,3 +1,4 @@
// IWYU pragma: no_include <bits/chrono.h>
#include "director.h" #include "director.h"
#include <SDL2/SDL.h> // Para SDL_Init, SDL_Quit, SDL_INIT_EV... #include <SDL2/SDL.h> // Para SDL_Init, SDL_Quit, SDL_INIT_EV...
#include <SDL2/SDL_audio.h> // Para AUDIO_S16 #include <SDL2/SDL_audio.h> // Para AUDIO_S16
@@ -7,50 +8,42 @@
#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 <bits/chrono.h> // Para duration, system_clock
#include <errno.h> // Para errno, EEXIST, EACCES, ENAMETOO... #include <errno.h> // Para errno, EEXIST, EACCES, ENAMETOO...
#include <stdio.h> // Para printf, perror
#include <sys/stat.h> // Para mkdir, stat, S_IRWXU
#include <unistd.h> // Para getuid
#include <algorithm> // Para min
#include <cstdlib> // Para exit, EXIT_FAILURE, size_t, rand
#include <iostream> // Para basic_ostream, operator<<, basi...
#include <memory> // Para make_unique, unique_ptr
#include <stdexcept> // Para runtime_error
#include <string> // Para operator+, char_traits, allocator
#include <vector> // Para vector
#include "asset.h" // Para Asset, AssetType
#include "dbgtxt.h" // Para dbg_init
#include "game.h" // Para Game, GAME_MODE_DEMO_OFF, GAME_...
#include "global_inputs.h" // Para init
#include "hiscore_table.h" // Para HiScoreTable
#include "input.h" // Para Input, InputType
#include "instructions.h" // Para Instructions
#include "intro.h" // Para Intro
#include "jail_audio.h" // Para JA_SetMusicVolume, JA_SetSoundV...
#include "lang.h" // Para Code, loadFromFile
#include "logo.h" // Para Logo
#include "manage_hiscore_table.h" // Para ManageHiScoreTable
#include "notifier.h" // Para Notifier
#include "on_screen_help.h" // Para OnScreenHelp
#include "options.h" // Para Options, OptionsController, opt...
#include "param.h" // Para Param, ParamGame, param, loadPa...
#include "resource.h" // Para Resource
#include "screen.h" // Para Screen
#include "section.h" // Para Name, Options, name, options
#include "title.h" // Para Title
#include "utils.h" // Para Overrides, overrides
#ifndef _WIN32 #ifndef _WIN32
#include <pwd.h> // para getpwuid, passwd #include <pwd.h> // Para getpwuid, passwd
#endif #endif
#include <stdio.h> // Para printf, perror
// Inicia la semilla aleatoria #include <sys/stat.h> // Para mkdir, stat, S_IRWXU
void initRand() #include <unistd.h> // Para getuid
{ #include <algorithm> // Para min
unsigned int seed = static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count()); #include <chrono> // Para chrono
std::srand(seed); #include <cstdlib> // Para exit, EXIT_FAILURE, size_t, rand
} #include <iostream> // Para basic_ostream, operator<<, basi...
#include <memory> // Para make_unique, unique_ptr
#include <stdexcept> // Para runtime_error
#include <string> // Para operator+, char_traits, allocator
#include <vector> // Para vector
#include "asset.h" // Para Asset, AssetType
#include "credits.h" // Para Credits
#include "dbgtxt.h" // Para dbg_init
#include "game.h" // Para Game, GAME_MODE_DEMO_OFF, GAME_...
#include "hiscore_table.h" // Para HiScoreTable
#include "input.h" // Para Input, InputType
#include "instructions.h" // Para Instructions
#include "intro.h" // Para Intro
#include "jail_audio.h" // Para JA_SetMusicVolume, JA_SetSoundV...
#include "lang.h" // Para Code, loadFromFile
#include "logo.h" // Para Logo
#include "manage_hiscore_table.h" // Para ManageHiScoreTable
#include "notifier.h" // Para Notifier
#include "on_screen_help.h" // Para OnScreenHelp
#include "options.h" // Para Options, options, OptionsContro...
#include "param.h" // Para Param, ParamGame, param, loadPa...
#include "resource.h" // Para Resource
#include "screen.h" // Para Screen
#include "section.h" // Para Name, Options, name, options
#include "title.h" // Para Title
#include "utils.h" // Para Overrides, overrides
// Constructor // Constructor
Director::Director(int argc, const char *argv[]) Director::Director(int argc, const char *argv[])
@@ -60,7 +53,7 @@ Director::Director(int argc, const char *argv[])
section::options = section::Options::GAME_PLAY_1P; section::options = section::Options::GAME_PLAY_1P;
#elif DEBUG #elif DEBUG
section::name = section::Name::LOGO; section::name = section::Name::LOGO;
#else #else // NORMAL GAME
section::name = section::Name::LOGO; section::name = section::Name::LOGO;
section::attract_mode = section::AttractMode::TITLE_TO_DEMO; section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
#endif #endif
@@ -73,42 +66,36 @@ Director::Director(int argc, const char *argv[])
std::cout << "Game start" << std::endl; std::cout << "Game start" << std::endl;
initRand(); // Inicia la semilla aleatoria
unsigned int seed = static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count());
std::srand(seed);
// Comprueba los parametros del programa // Comprueba los parametros del programa
checkProgramArguments(argc, argv); checkProgramArguments(argc, argv);
// Crea la carpeta del sistema donde guardar datos // Crea la carpeta del sistema donde guardar los datos persistentes
createSystemFolder("jailgames"); createSystemFolder("jailgames");
createSystemFolder("jailgames/coffee_crisis_arcade_edition"); createSystemFolder("jailgames/coffee_crisis_arcade_edition");
// Crea el objeto que controla los ficheros de recursos init();
Asset::init(executable_path_); }
// Crea el indice de ficheros Director::~Director()
setFileList(); {
close();
std::cout << "\nBye!" << std::endl;
}
// Carga el fichero de configuración // Inicializa todo
loadOptionsFile(Asset::get()->get("config.txt")); void Director::init()
{
Asset::init(executable_path_); // Crea el objeto que controla los ficheros de recursos
setFileList(); // Crea el indice de ficheros
loadOptionsFile(Asset::get()->get("config.txt")); // Carga el fichero de configuración
loadParams(); // Carga los parametros
loadScoreFile(); // Carga el fichero de puntuaciones
// Carga los parametros para configurar el juego // Inicializa y crea el resto de objetos
#ifdef ANBERNIC
const std::string paramFilePath = asset->get("param_320x240.txt");
#else
const std::string paramFilePath = overrides.param_file == "--320x240" ? Asset::get()->get("param_320x240.txt") : Asset::get()->get("param_320x256.txt");
#endif
loadParamsFromFile(paramFilePath);
// Carga el fichero de puntuaciones
{
auto manager = std::make_unique<ManageHiScoreTable>(options.game.hi_score_table);
if (overrides.clear_hi_score_table)
manager->clear();
else
manager->loadFromFile(Asset::get()->get("score.bin"));
}
// Inicializa todo
initSDL(); initSDL();
initJailAudio(); initJailAudio();
dbg_init(renderer_); dbg_init(renderer_);
@@ -117,12 +104,12 @@ Director::Director(int argc, const char *argv[])
Resource::init(); Resource::init();
Input::init(Asset::get()->get("gamecontrollerdb.txt")); Input::init(Asset::get()->get("gamecontrollerdb.txt"));
bindInputs(); bindInputs();
Notifier::init(std::string(), Resource::get()->getText("8bithud"), Asset::get()->get("notify.wav")); Notifier::init(std::string(), Resource::get()->getText("8bithud"));
OnScreenHelp::init(); OnScreenHelp::init();
globalInputs::init();
} }
Director::~Director() // Cierra todo
void Director::close()
{ {
saveOptionsFile(Asset::get()->get("config.txt")); saveOptionsFile(Asset::get()->get("config.txt"));
@@ -133,12 +120,38 @@ Director::~Director()
Notifier::destroy(); Notifier::destroy();
OnScreenHelp::destroy(); OnScreenHelp::destroy();
JA_Quit();
SDL_DestroyRenderer(renderer_); SDL_DestroyRenderer(renderer_);
SDL_DestroyWindow(window_); SDL_DestroyWindow(window_);
SDL_Quit(); SDL_Quit();
}
std::cout << "\nBye!" << std::endl; // Carga los parametros
void Director::loadParams()
{
// Carga los parametros para configurar el juego
#ifdef ANBERNIC
const std::string paramFilePath = asset->get("param_320x240.txt");
#else
const std::string paramFilePath = overrides.param_file == "--320x240" ? Asset::get()->get("param_320x240.txt") : Asset::get()->get("param_320x256.txt");
#endif
loadParamsFromFile(paramFilePath);
}
// Carga el fichero de puntuaciones
void Director::loadScoreFile()
{
auto manager = std::make_unique<ManageHiScoreTable>(options.game.hi_score_table);
if (overrides.clear_hi_score_table)
{
manager->clear();
}
else
{
manager->loadFromFile(Asset::get()->get("score.bin"));
}
} }
// Asigna los botones y teclas al objeto Input // Asigna los botones y teclas al objeto Input
@@ -165,7 +178,9 @@ void Director::bindInputs()
Input::get()->bindKey(InputType::WINDOW_FULLSCREEN, SDL_SCANCODE_F3); Input::get()->bindKey(InputType::WINDOW_FULLSCREEN, SDL_SCANCODE_F3);
Input::get()->bindKey(InputType::VIDEO_SHADERS, SDL_SCANCODE_F4); Input::get()->bindKey(InputType::VIDEO_SHADERS, SDL_SCANCODE_F4);
Input::get()->bindKey(InputType::MUTE, SDL_SCANCODE_F5); Input::get()->bindKey(InputType::MUTE, SDL_SCANCODE_F5);
Input::get()->bindKey(InputType::SHOWINFO, SDL_SCANCODE_F6); Input::get()->bindKey(InputType::AUTO_FIRE, SDL_SCANCODE_F6);
Input::get()->bindKey(InputType::CHANGE_LANG, SDL_SCANCODE_F7);
Input::get()->bindKey(InputType::SHOWINFO, SDL_SCANCODE_F8);
Input::get()->bindKey(InputType::RESET, SDL_SCANCODE_F10); Input::get()->bindKey(InputType::RESET, SDL_SCANCODE_F10);
// Asigna botones a inputs // Asigna botones a inputs
@@ -279,8 +294,15 @@ bool Director::initSDL()
} }
*/ */
// Obtiene información sobre la pantalla
SDL_DisplayMode DM; SDL_DisplayMode DM;
SDL_GetCurrentDisplayMode(0, &DM); SDL_GetCurrentDisplayMode(0, &DM);
// Calcula el máximo factor de zoom que se puede aplicar a la pantalla
options.video.window.max_size = std::min(DM.w / param.game.width, DM.h / param.game.height);
options.video.window.size = std::min(options.video.window.size, options.video.window.max_size);
// Muestra información sobre el tamaño de la pantalla y de la ventana de juego
std::cout << "\nCurrent display mode: " << DM.w << "x" << DM.h << " @ " << DM.refresh_rate << "Hz" << std::endl; std::cout << "\nCurrent display mode: " << DM.w << "x" << DM.h << " @ " << DM.refresh_rate << "Hz" << std::endl;
std::cout << "Window resolution : " << param.game.width << "x" << param.game.height << " x" << options.video.window.size << std::endl; std::cout << "Window resolution : " << param.game.width << "x" << param.game.height << " x" << options.video.window.size << std::endl;
@@ -361,6 +383,7 @@ void Director::setFileList()
Asset::get()->add(prefix + "/data/music/intro.ogg", AssetType::MUSIC); Asset::get()->add(prefix + "/data/music/intro.ogg", AssetType::MUSIC);
Asset::get()->add(prefix + "/data/music/playing.ogg", AssetType::MUSIC); Asset::get()->add(prefix + "/data/music/playing.ogg", AssetType::MUSIC);
Asset::get()->add(prefix + "/data/music/title.ogg", AssetType::MUSIC); Asset::get()->add(prefix + "/data/music/title.ogg", AssetType::MUSIC);
Asset::get()->add(prefix + "/data/music/credits.ogg", AssetType::MUSIC);
// Sonidos // Sonidos
Asset::get()->add(prefix + "/data/sound/balloon.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/balloon.wav", AssetType::SOUND);
@@ -369,19 +392,29 @@ void Director::setFileList()
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/clock.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/coffeeout.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/coffeeout.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/hiscore.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/itemdrop.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/itempickup.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/logo.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/powerball.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/notify.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/notify.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/player_collision.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/powerball.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/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);
// Shaders // Shaders
Asset::get()->add(prefix + "/data/shaders/crtpi.glsl", AssetType::DATA); Asset::get()->add(prefix + "/data/shaders/crtpi_256.glsl", AssetType::DATA);
Asset::get()->add(prefix + "/data/shaders/crtpi_240.glsl", AssetType::DATA);
// Texturas // Texturas
@@ -420,6 +453,11 @@ void Director::setFileList()
Asset::get()->add(prefix + "/data/gfx/bullet/bullet.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/bullet/bullet.png", AssetType::BITMAP);
} }
{ // Tabe
Asset::get()->add(prefix + "/data/gfx/tabe/tabe.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/tabe/tabe.ani", AssetType::ANIMATION);
}
{ // Juego { // Juego
Asset::get()->add(prefix + "/data/gfx/game/game_buildings.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/game/game_buildings.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_clouds1.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/game/game_clouds1.png", AssetType::BITMAP);
@@ -427,6 +465,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
@@ -465,17 +505,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);
} }
@@ -630,6 +670,13 @@ void Director::runInstructions()
instructions->run(); instructions->run();
} }
// Ejecuta la sección donde se muestran los creditos del programa
void Director::runCredits()
{
auto credits = std::make_unique<Credits>();
credits->run();
}
// Ejecuta la sección donde se muestra la tabla de puntuaciones // Ejecuta la sección donde se muestra la tabla de puntuaciones
void Director::runHiScoreTable() void Director::runHiScoreTable()
{ {
@@ -646,6 +693,16 @@ void Director::runDemoGame()
game->run(); game->run();
} }
// Ejecuta la sección init
void Director::runInit()
{
if (section::options == section::Options::RELOAD)
{
Resource::get()->reload();
}
section::name = section::Name::LOGO;
}
int Director::run() int Director::run()
{ {
// Bucle principal // Bucle principal
@@ -654,7 +711,7 @@ int Director::run()
switch (section::name) switch (section::name)
{ {
case section::Name::INIT: case section::Name::INIT:
section::name = section::Name::LOGO; runInit();
break; break;
case section::Name::LOGO: case section::Name::LOGO:
runLogo(); runLogo();
@@ -677,6 +734,9 @@ int Director::run()
case section::Name::INSTRUCTIONS: case section::Name::INSTRUCTIONS:
runInstructions(); runInstructions();
break; break;
case section::Name::CREDITS:
runCredits();
break;
default: default:
break; break;
} }

View File

@@ -58,12 +58,18 @@ private:
// Ejecuta la sección donde se muestran las instrucciones // Ejecuta la sección donde se muestran las instrucciones
void runInstructions(); void runInstructions();
// Ejecuta la sección donde se muestran los creditos del programa
void runCredits();
// Ejecuta la sección donde se muestra la tabla de puntuaciones // Ejecuta la sección donde se muestra la tabla de puntuaciones
void runHiScoreTable(); void runHiScoreTable();
// Ejecuta el juego en modo demo // Ejecuta el juego en modo demo
void runDemoGame(); void runDemoGame();
// Ejecuta la sección init
void runInit();
// Obtiene una fichero a partir de un lang::Code // Obtiene una fichero a partir de un lang::Code
std::string getLangFile(lang::Code code); std::string getLangFile(lang::Code code);
#ifdef ARCADE #ifdef ARCADE
@@ -71,6 +77,18 @@ private:
void shutdownSystem(); void shutdownSystem();
#endif #endif
// Inicializa todo
void init();
// Cierra todo
void close();
// Carga los parametros
void loadParams();
// Carga el fichero de puntuaciones
void loadScoreFile();
public: public:
// Constructor // Constructor
Director(int argc, const char *argv[]); Director(int argc, const char *argv[]);

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;
@@ -100,6 +112,8 @@ void Fade::update()
SDL_RenderFillRect(renderer_, &rect1_); SDL_RenderFillRect(renderer_, &rect1_);
SDL_RenderFillRect(renderer_, &rect2_); SDL_RenderFillRect(renderer_, &rect2_);
value_ = calculateValue(0, counter_, i);
} }
// Deja el renderizador como estaba // Deja el renderizador como estaba
@@ -108,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;
@@ -118,10 +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_);
@@ -133,16 +148,17 @@ void Fade::update()
SDL_RenderFillRect(renderer_, &square_[index2]); SDL_RenderFillRect(renderer_, &square_[index2]);
} }
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND);
// Deja el renderizador como estaba // Deja el renderizador como estaba
SDL_SetRenderDrawBlendMode(renderer_, blend_mode);
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
} }
value_ = calculateValue(0, static_cast<int>(num_squares_width_ * num_squares_height_), static_cast<int>(counter_ * fade_random_squares_mult_ / fade_random_squares_delay_));
// 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;
@@ -150,64 +166,88 @@ 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_SetRenderDrawColor(renderer_, r_, g_, b_, a_); SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
for (auto rect : square_)
// Dibuja el cuadrado correspondiente
for (const auto rect : square_)
{ {
SDL_RenderFillRect(renderer_, &rect); SDL_RenderFillRect(renderer_, &rect);
} }
// Deja el renderizador como estaba // Deja el renderizador como estaba
SDL_SetRenderDrawBlendMode(renderer_, blend_mode);
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
const auto h = counter_ / 3; // Modifica el tamaño de los rectangulos
for (int i = 0; i < (int)square_.size(); ++i) const auto h = counter_ / 2;
for (size_t i = 0; i < square_.size(); ++i)
{ {
// 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_[i].h = i == 0 ? h : std::max(square_[i - 1].h - 3, 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;
} }
if (finished_)
{
// Actualiza el contador
post_counter_ == post_duration_ ? enabled_ = false : post_counter_++;
// Deja el backbuffer_ todo del mismo color
cleanBackbuffer(r_, g_, b_, a_);
}
counter_++; counter_++;
} }
if (state_ == FadeState::POST)
{
// Actualiza el contador
if (post_counter_ == post_duration_)
{
state_ = FadeState::FINISHED;
}
else
{
post_counter_++;
}
// Deja el backbuffer_ todo del mismo color
cleanBackbuffer(r_, g_, b_, a_);
}
} }
// 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_)
{ {
@@ -251,12 +291,8 @@ void Fade::activate()
} }
// Limpia la textura // Limpia la textura
auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_);
a_ = mode_ == FadeMode::OUT ? 0 : 255; a_ = mode_ == FadeMode::OUT ? 0 : 255;
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_); cleanBackbuffer(r_, g_, b_, a_);
SDL_RenderClear(renderer_);
SDL_SetRenderTarget(renderer_, temp);
// Deja el color listo para usar // Deja el color listo para usar
a_ = mode_ == FadeMode::OUT ? 255 : 0; a_ = mode_ == FadeMode::OUT ? 255 : 0;
@@ -266,12 +302,16 @@ void Fade::activate()
case FadeType::VENETIAN: case FadeType::VENETIAN:
{ {
cleanBackbuffer(0, 0, 0, 0); // Limpia la textura
rect1_ = {0, 0, param.game.width, 0}; a_ = mode_ == FadeMode::OUT ? 0 : 255;
square_.clear(); cleanBackbuffer(r_, g_, b_, a_);
a_ = 255;
// Deja el color listo para usar
a_ = mode_ == FadeMode::OUT ? 255 : 0;
// Añade los cuadrados al vector // Añade los cuadrados al vector
square_.clear();
rect1_ = {0, 0, param.game.width, 0};
const int max = param.game.height / param.fade.venetian_size; const int max = param.game.height / param.fade.venetian_size;
for (int i = 0; i < max; ++i) for (int i = 0; i < max; ++i)
@@ -285,31 +325,6 @@ void Fade::activate()
} }
} }
// Comprueba si está activo
bool Fade::isEnabled() const
{
return enabled_;
}
// Comprueba si ha terminado la transicion
bool Fade::hasEnded() const
{
// Ha terminado cuando ha finalizado la transición y se ha deshabilitado
return !enabled_ && finished_;
}
// Establece el tipo de fade
void Fade::setType(FadeType type)
{
type_ = type;
}
// Establece el modo de fade
void Fade::setMode(FadeMode mode)
{
mode_ = mode;
}
// Establece el color del fade // Establece el color del fade
void Fade::setColor(Uint8 r, Uint8 g, Uint8 b) void Fade::setColor(Uint8 r, Uint8 g, Uint8 b)
{ {
@@ -318,12 +333,6 @@ void Fade::setColor(Uint8 r, Uint8 g, Uint8 b)
b_ = b; b_ = b;
} }
// Establece la duración posterior
void Fade::setPost(int value)
{
post_duration_ = value;
}
// Limpia el backbuffer // Limpia el backbuffer
void Fade::cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a) void Fade::cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{ {
@@ -337,4 +346,20 @@ void Fade::cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
// Vuelve a dejar el renderizador como estaba // Vuelve a dejar el renderizador como estaba
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
}
// Calcula el valor del estado del fade
int Fade::calculateValue(int min, int max, int current)
{
if (current < min)
{
return 0;
}
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
{ {
@@ -30,21 +40,23 @@ private:
SDL_Texture *backbuffer_; // Textura para usar como backbuffer con SDL_TEXTUREACCESS_TARGET SDL_Texture *backbuffer_; // Textura para usar como backbuffer con SDL_TEXTUREACCESS_TARGET
// 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
Uint16 counter_; // Contador interno FadeState state_ = FadeState::NOT_ENABLED; // Estado actual del objeto
bool enabled_; // Indica si el fade está activo Uint16 counter_; // Contador interno
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 int num_squares_width_; // Cantidad total de cuadraditos en horizontal para el FadeType::RANDOM_SQUARE
int num_squares_width_; // Cantidad total de cuadraditos en horizontal para el FadeType::RANDOM_SQUARE int num_squares_height_; // Cantidad total de cuadraditos en vertical para el FadeType::RANDOM_SQUARE
int num_squares_height_; // Cantidad total de cuadraditos en vertical para el FadeType::RANDOM_SQUARE std::vector<SDL_Rect> square_; // Vector con los indices de los cuadrados para el FadeType::RANDOM_SQUARE
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_ = 0; // Duración posterior del fade tras finalizar
int post_duration_; // Duración posterior del fade tras finalizar int post_counter_ = 0; // Contador para la duración posterior
int post_counter_; // 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
// Inicializa las variables // Inicializa las variables
void init(); void init();
@@ -52,6 +64,9 @@ private:
// Limpia el backbuffer // Limpia el backbuffer
void cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a); void cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a);
// Calcula el valor del estado del fade
int calculateValue(int min, int max, int current);
public: public:
// Constructor // Constructor
Fade(); Fade();
@@ -71,21 +86,17 @@ public:
// Activa el fade // Activa el fade
void activate(); void activate();
// Comprueba si ha terminado la transicion
bool hasEnded() const;
// Comprueba si está activo
bool isEnabled() const;
// Establece el tipo de fade
void setType(FadeType type);
// Establece el modo de fade
void setMode(FadeMode mode);
// Establece el color del fade // Establece el color del fade
void setColor(Uint8 r, Uint8 g, Uint8 b); void setColor(Uint8 r, Uint8 g, Uint8 b);
// Establece la duración posterior // Getters
void setPost(int value); int getValue() const { return value_; }
bool isEnabled() const { return state_ != FadeState::NOT_ENABLED; }
bool hasEnded() const { return state_ == FadeState::FINISHED; }
// Setters
void setType(FadeType type) { type_ = type; }
void setMode(FadeMode mode) { mode_ = mode; }
void setPostDuration(int value) { post_duration_ = value; }
void setPreDuration(int value) { pre_duration_ = value; }
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -12,6 +12,7 @@
class Asset; // lines 13-13 class Asset; // lines 13-13
class Background; // lines 14-14 class Background; // lines 14-14
class BalloonManager; class BalloonManager;
class Tabe;
class Bullet; // lines 15-15 class Bullet; // lines 15-15
class Fade; // lines 16-16 class Fade; // lines 16-16
class Input; // lines 17-17 class Input; // lines 17-17
@@ -65,6 +66,9 @@ private:
// Enum // Enum
enum class GameState enum class GameState
{ {
FADE_IN,
ENTERING_PLAYER,
SHOWING_GET_READY_MESSAGE,
PLAYING, PLAYING,
COMPLETED, COMPLETED,
GAME_OVER, GAME_OVER,
@@ -140,8 +144,10 @@ private:
std::vector<std::vector<std::string>> item_animations_; // Vector con las animaciones de los items std::vector<std::vector<std::string>> item_animations_; // Vector con las animaciones de los items
std::vector<std::vector<std::string>> player_animations_; // Vector con las animaciones del jugador std::vector<std::vector<std::string>> player_animations_; // Vector con las animaciones del jugador
std::unique_ptr<Fade> fade_; // Objeto para renderizar fades std::unique_ptr<Fade> fade_in_; // Objeto para renderizar fades
std::unique_ptr<Fade> fade_out_; // Objeto para renderizar fades
std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos
std::unique_ptr<Tabe> tabe_; // Objeto para gestionar el Tabe Volaor
std::vector<Path> paths_; // Vector con los recorridos precalculados almacenados std::vector<Path> paths_; // Vector con los recorridos precalculados almacenados
// Variables // Variables
@@ -164,7 +170,7 @@ private:
int total_power_to_complete_game_; // La suma del poder necesario para completar todas las fases int total_power_to_complete_game_; // La suma del poder necesario para completar todas las fases
int menace_current_ = 0; // Nivel de amenaza actual int menace_current_ = 0; // Nivel de amenaza actual
int menace_threshold_ = 0; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el número de globos int menace_threshold_ = 0; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el número de globos
GameState state_ = GameState::PLAYING; // Estado GameState state_ = GameState::FADE_IN; // Estado
#ifdef DEBUG #ifdef DEBUG
bool auto_pop_balloons_ = false; // Si es true, incrementa automaticamente los globos explotados bool auto_pop_balloons_ = false; // Si es true, incrementa automaticamente los globos explotados
#endif #endif
@@ -194,7 +200,7 @@ private:
void updateStage(); void updateStage();
// 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();
@@ -209,7 +215,7 @@ private:
void checkBulletBalloonCollision(); void checkBulletBalloonCollision();
// Mueve las balas activas // Mueve las balas activas
void moveBullets(); void updateBullets();
// Pinta las balas activas // Pinta las balas activas
void renderBullets(); void renderBullets();
@@ -304,9 +310,6 @@ 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::string &name, int score);
@@ -373,6 +376,9 @@ private:
// Reanuda la música // Reanuda la música
void resumeMusic(); void resumeMusic();
// Hace sonar la música
void playMusic();
// Detiene la música // Detiene la música
void stopMusic(); void stopMusic();
@@ -382,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();
@@ -403,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

@@ -5,9 +5,15 @@
#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 "utils.h" // Para Color
constexpr int ZOOM_FACTOR = 5;
constexpr int FLASH_DELAY = 3;
constexpr int FLASH_LENGHT = FLASH_DELAY + 3;
// Constructor // Constructor
GameLogo::GameLogo(int x, int y) GameLogo::GameLogo(int x, int y)
@@ -15,36 +21,25 @@ GameLogo::GameLogo(int x, int y)
coffee_texture_(Resource::get()->getTexture("title_coffee.png")), coffee_texture_(Resource::get()->getTexture("title_coffee.png")),
crisis_texture_(Resource::get()->getTexture("title_crisis.png")), crisis_texture_(Resource::get()->getTexture("title_crisis.png")),
arcade_edition_texture_(Resource::get()->getTexture("title_arcade_edition.png")), arcade_edition_texture_(Resource::get()->getTexture("title_arcade_edition.png")),
dust_left_sprite_(std::make_unique<AnimatedSprite>(dust_texture_, Resource::get()->getAnimation("title_dust.ani"))), dust_left_sprite_(std::make_unique<AnimatedSprite>(dust_texture_, Resource::get()->getAnimation("title_dust.ani"))),
dust_right_sprite_(std::make_unique<AnimatedSprite>(dust_texture_, Resource::get()->getAnimation("title_dust.ani"))), dust_right_sprite_(std::make_unique<AnimatedSprite>(dust_texture_, Resource::get()->getAnimation("title_dust.ani"))),
coffee_sprite_(std::make_unique<SmartSprite>(coffee_texture_)), coffee_sprite_(std::make_unique<SmartSprite>(coffee_texture_)),
crisis_sprite_(std::make_unique<SmartSprite>(crisis_texture_)), crisis_sprite_(std::make_unique<SmartSprite>(crisis_texture_)),
arcade_edition_sprite_(std::make_unique<Sprite>(arcade_edition_texture_, (param.game.width - arcade_edition_texture_->getWidth()) / 2, param.title.arcade_edition_position, arcade_edition_texture_->getWidth(), arcade_edition_texture_->getHeight())), arcade_edition_sprite_(std::make_unique<Sprite>(arcade_edition_texture_, (param.game.width - arcade_edition_texture_->getWidth()) / 2, param.title.arcade_edition_position, arcade_edition_texture_->getWidth(), arcade_edition_texture_->getHeight())),
x_(x), x_(x),
y_(y) y_(y) {}
{
// Inicializa las variables
init();
}
// Inicializa las variables // Inicializa las variables
void GameLogo::init() void GameLogo::init()
{ {
const auto xp = x_ - coffee_sprite_->getWidth() / 2; const auto xp = x_ - coffee_texture_->getWidth() / 2;
const auto desp = getInitialVerticalDesp(); const auto desp = getInitialVerticalDesp();
// Variables // Variables
status_ = Status::DISABLED; coffee_crisis_status_ = Status::DISABLED;
shake_.desp = 1; arcade_edition_status_ = Status::DISABLED;
shake_.delay = 2; shake_.init(1, 2, 8, xp);
shake_.lenght = 8; zoom_ = 3.0f * ZOOM_FACTOR;
shake_.remaining = shake_.lenght;
shake_.counter = shake_.delay;
shake_.origin = xp;
// Inicializa el bitmap de 'Coffee' // Inicializa el bitmap de 'Coffee'
coffee_sprite_->setPosX(xp); coffee_sprite_->setPosX(xp);
@@ -90,6 +85,9 @@ void GameLogo::init()
dust_left_sprite_->setPosY(y_); dust_left_sprite_->setPosY(y_);
dust_left_sprite_->setWidth(16); dust_left_sprite_->setWidth(16);
dust_left_sprite_->setHeight(16); dust_left_sprite_->setHeight(16);
// Inicializa el bitmap de 'Arcade Edition'
arcade_edition_sprite_->setZoom(zoom_);
} }
// Pinta la clase en pantalla // Pinta la clase en pantalla
@@ -99,8 +97,10 @@ void GameLogo::render()
coffee_sprite_->render(); coffee_sprite_->render();
crisis_sprite_->render(); crisis_sprite_->render();
if (status_ == Status::FINISHED) if (arcade_edition_status_ != Status::DISABLED)
{
arcade_edition_sprite_->render(); arcade_edition_sprite_->render();
}
// Dibuja el polvillo del logo // Dibuja el polvillo del logo
dust_right_sprite_->render(); dust_right_sprite_->render();
@@ -110,20 +110,22 @@ void GameLogo::render()
// Actualiza la lógica de la clase // Actualiza la lógica de la clase
void GameLogo::update() void GameLogo::update()
{ {
switch (status_) switch (coffee_crisis_status_)
{ {
case Status::MOVING: case Status::MOVING:
{ {
coffee_sprite_->update(); coffee_sprite_->update();
crisis_sprite_->update(); crisis_sprite_->update();
// Si los objetos han llegado a su destino, cambiamos de Sección // Si los objetos han llegado a su destino, cambia el estado
if (coffee_sprite_->hasFinished() && crisis_sprite_->hasFinished()) if (coffee_sprite_->hasFinished() && crisis_sprite_->hasFinished())
{ {
status_ = Status::SHAKING; coffee_crisis_status_ = Status::SHAKING;
// Reproduce el efecto sonoro // Reproduce el efecto sonoro
JA_PlaySound(Resource::get()->getSound("title.wav")); JA_PlaySound(Resource::get()->getSound("title.wav"));
Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGHT, FLASH_DELAY);
Screen::get()->shake();
} }
break; break;
@@ -131,7 +133,7 @@ void GameLogo::update()
case Status::SHAKING: case Status::SHAKING:
{ {
// Agita el logo // Agita "COFFEE CRISIS"
if (shake_.remaining > 0) if (shake_.remaining > 0)
{ {
if (shake_.counter > 0) if (shake_.counter > 0)
@@ -151,7 +153,8 @@ void GameLogo::update()
{ {
coffee_sprite_->setPosX(shake_.origin); coffee_sprite_->setPosX(shake_.origin);
crisis_sprite_->setPosX(shake_.origin + 15); crisis_sprite_->setPosX(shake_.origin + 15);
status_ = Status::FINISHED; coffee_crisis_status_ = Status::FINISHED;
arcade_edition_status_ = Status::MOVING;
} }
dust_right_sprite_->update(); dust_right_sprite_->update();
@@ -171,19 +174,74 @@ void GameLogo::update()
default: default:
break; break;
} }
switch (arcade_edition_status_)
{
case Status::MOVING:
{
zoom_ -= 0.1f * ZOOM_FACTOR;
arcade_edition_sprite_->setZoom(zoom_);
if (zoom_ <= 1.0f)
{
arcade_edition_status_ = Status::SHAKING;
zoom_ = 1.0f;
arcade_edition_sprite_->setZoom(zoom_);
shake_.init(1, 2, 8, arcade_edition_sprite_->getX());
JA_PlaySound(Resource::get()->getSound("title.wav"));
Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGHT, FLASH_DELAY);
Screen::get()->shake();
}
break;
}
case Status::SHAKING:
{
// Agita "ARCADE EDITION"
if (shake_.remaining > 0)
{
if (shake_.counter > 0)
{
shake_.counter--;
}
else
{
shake_.counter = shake_.delay;
const auto desp = shake_.remaining % 2 == 0 ? shake_.desp * (-1) : shake_.desp;
arcade_edition_sprite_->setX(shake_.origin + desp);
shake_.remaining--;
}
}
else
{
arcade_edition_sprite_->setX(shake_.origin);
arcade_edition_status_ = Status::FINISHED;
}
break;
}
default:
break;
}
if (coffee_crisis_status_ == Status::FINISHED &&
arcade_edition_status_ == Status::FINISHED &&
post_finished_counter_ > 0)
{
--post_finished_counter_;
}
} }
// Activa la clase // Activa la clase
void GameLogo::enable() void GameLogo::enable()
{ {
init(); init();
status_ = Status::MOVING; coffee_crisis_status_ = Status::MOVING;
} }
// Indica si ha terminado la animación // Indica si ha terminado la animación
bool GameLogo::hasFinished() const bool GameLogo::hasFinished() const
{ {
return status_ == Status::FINISHED; return post_finished_counter_ == 0;
} }
// Recarga las texturas // Recarga las texturas
@@ -192,6 +250,7 @@ void GameLogo::reLoad()
dust_texture_->reLoad(); dust_texture_->reLoad();
coffee_texture_->reLoad(); coffee_texture_->reLoad();
crisis_texture_->reLoad(); crisis_texture_->reLoad();
arcade_edition_texture_->reLoad();
} }
// Calcula el desplazamiento vertical inicial // Calcula el desplazamiento vertical inicial

View File

@@ -20,12 +20,30 @@ private:
struct Shake struct Shake
{ {
int desp; // Pixels de desplazamiento para agitar la pantalla en el eje x int desp = 1; // Pixels de desplazamiento para agitar la pantalla en el eje x
int delay; // Retraso entre cada desplazamiento de la pantalla al agitarse int delay = 2; // Retraso entre cada desplazamiento de la pantalla al agitarse
int counter; // Contador para el retraso int lenght = 8; // Cantidad de desplazamientos a realizar
int lenght; // Cantidad de desplazamientos a realizar int remaining = lenght; // Cantidad de desplazamientos pendientes a realizar
int remaining; // Cantidad de desplazamientos pendientes a realizar int counter = delay; // Contador para el retraso
int origin; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento int origin; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
// Constructor por defect
Shake() = default;
// Constructor
Shake(int d, int de, int l, int o)
: desp(d), delay(de), lenght(l), remaining(l), counter(de), origin(o) {}
// Inicializa los miembros
void init(int d, int de, int l, int o)
{
desp = d;
delay = de;
lenght = l;
remaining = l;
counter = de;
origin = o;
}
}; };
// Objetos y punteros // Objetos y punteros
@@ -43,11 +61,14 @@ private:
std::unique_ptr<Sprite> arcade_edition_sprite_; // Sprite con los graficos de "Arcade Edition" std::unique_ptr<Sprite> arcade_edition_sprite_; // Sprite con los graficos de "Arcade Edition"
// Variables // Variables
int x_; // Posición donde dibujar el logo int x_; // Posición donde dibujar el logo
int y_; // Posición donde dibujar el logo int y_; // Posición donde dibujar el logo
float zoom_; // Zoom aplicado al texto "ARCADE EDITION"
int post_finished_counter_ = 1; // Contador final una vez terminada las animaciones de los logos
Status status_; // Estado en el que se encuentra la clase Status coffee_crisis_status_ = Status::DISABLED; // Estado en el que se encuentra el texto "COFFEE CRISIS"
Shake shake_; // Estructura para generar el efecto de agitación Status arcade_edition_status_ = Status::DISABLED; // Estado en el que se encuentra el texto "ARCADE_EDITION"
Shake shake_; // Estructura para generar el efecto de agitación
// Inicializa las variables // Inicializa las variables
void init(); void init();

View File

@@ -1,30 +1,22 @@
#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 "jail_audio.h" // Para JA_EnableMusic, JA_EnableSound #include "asset.h" // Para Asset
#include "lang.h" // Para getText #include "input.h" // Para Input, InputDeviceToUse, InputType, INPU...
#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
{ {
// Variables // Variables
std::vector<int> service_pressed_counter; int service_pressed_counter = 0;
bool service_pressed = false;
// Inicializa variables
void init()
{
const auto num_inputs = Input::get()->getNumControllers() + 1;
service_pressed_counter.reserve(num_inputs);
for (int i = 0; i < num_inputs; ++i)
{
service_pressed_counter.push_back(0);
}
}
// Termina // Termina
void quit(section::Options code) void quit(section::Options code)
@@ -33,11 +25,13 @@ namespace globalInputs
auto code_found = stringInVector(Notifier::get()->getCodes(), exit_code); auto code_found = stringInVector(Notifier::get()->getCodes(), exit_code);
if (code_found) if (code_found)
{ {
// Si la notificación de salir está activa, cambia de sección
section::name = section::Name::QUIT; section::name = section::Name::QUIT;
section::options = code; section::options = code;
} }
else else
{ {
// Si la notificación de salir no está activa, muestra la notificación
#ifdef ARCADE #ifdef ARCADE
const int index = code == section::Options::QUIT_WITH_CONTROLLER ? 116 : 94; const int index = code == section::Options::QUIT_WITH_CONTROLLER ? 116 : 94;
Notifier::get()->showText({lang::getText(index), std::string()}, -1, exit_code); Notifier::get()->showText({lang::getText(index), std::string()}, -1, exit_code);
@@ -71,6 +65,57 @@ namespace globalInputs
Notifier::get()->showText({"Audio " + boolToOnOff(options.audio.enabled)}); Notifier::get()->showText({"Audio " + boolToOnOff(options.audio.enabled)});
} }
// Obtiene una fichero a partir de un lang::Code
std::string getLangFile(lang::Code code)
{
switch (code)
{
case lang::Code::ba_BA:
return Asset::get()->get("ba_BA.txt");
break;
case lang::Code::es_ES:
return Asset::get()->get("es_ES.txt");
break;
default:
return Asset::get()->get("en_UK.txt");
break;
}
}
// Obtiene una cadena a partir de un lang::Code
std::string getLangName(lang::Code code)
{
switch (code)
{
case lang::Code::ba_BA:
return "ba_BA";
break;
case lang::Code::es_ES:
return "es_ES";
break;
default:
return "en_UK";
break;
}
}
// Cambia el idioma
void changeLang()
{
options.game.language = lang::change(options.game.language);
lang::loadFromFile(getLangFile(static_cast<lang::Code>(options.game.language)));
section::name = section::Name::INIT;
section::options = section::Options::RELOAD;
Notifier::get()->showText({getLangName(options.game.language)});
}
// Cambia el modo de disparo
void toggleFireMode()
{
options.game.autofire = !options.game.autofire;
Notifier::get()->showText({"Autofire " + boolToOnOff(options.game.autofire)});
}
// Comprueba los inputs que se pueden introducir en cualquier sección del juego // Comprueba los inputs que se pueden introducir en cualquier sección del juego
void check() void check()
{ {
@@ -125,6 +170,20 @@ namespace globalInputs
return; return;
} }
// Autofire
if (Input::get()->checkInput(InputType::AUTO_FIRE, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
{
toggleFireMode();
return;
}
// Idioma
if (Input::get()->checkInput(InputType::CHANGE_LANG, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
{
changeLang();
return;
}
// Shaders // Shaders
if (Input::get()->checkInput(InputType::VIDEO_SHADERS, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) if (Input::get()->checkInput(InputType::VIDEO_SHADERS, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
{ {
@@ -143,17 +202,9 @@ namespace globalInputs
// OnScreenHelp // OnScreenHelp
if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
{ {
service_pressed_counter[0]++; service_pressed = true;
if (service_pressed_counter[0] >= 3000)
{
OnScreenHelp::get()->toggleState();
service_pressed_counter[0] = 0;
}
return; return;
} }
service_pressed_counter[0] = 0;
} }
// Mandos // Mandos
@@ -203,18 +254,30 @@ namespace globalInputs
// OnScreenHelp // OnScreenHelp
if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i)) if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, InputDeviceToUse::CONTROLLER, i))
{ {
service_pressed_counter[i + 1]++; service_pressed = true;
if (service_pressed_counter[i + 1] >= 3000)
{
OnScreenHelp::get()->toggleState();
service_pressed_counter[i + 1] = 0;
}
return; return;
} }
service_pressed_counter[i + 1] = 0;
} }
} }
} }
// Actualiza variables
void update()
{
if (service_pressed)
{
++service_pressed_counter;
if (service_pressed_counter >= 200)
{
OnScreenHelp::get()->toggleState();
service_pressed_counter = 0;
}
}
else
{
service_pressed_counter = 0;
}
service_pressed = false;
}
} }

View File

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

View File

@@ -20,6 +20,7 @@
#include "section.h" // Para Name, name, Options, options #include "section.h" // Para Name, name, Options, options
#include "text.h" // Para Text, TEXT_CENTER, TEXT_SHADOW #include "text.h" // Para Text, TEXT_CENTER, TEXT_SHADOW
#include "utils.h" // Para Color, Zone, fade_color, orange_color #include "utils.h" // Para Color, Zone, fade_color, orange_color
#include "mouse.h"
// Constructor // Constructor
HiScoreTable::HiScoreTable() HiScoreTable::HiScoreTable()
@@ -42,9 +43,11 @@ HiScoreTable::HiScoreTable()
background_->setCloudsSpeed(-0.1f); background_->setCloudsSpeed(-0.1f);
background_->setGradientNumber(1); background_->setGradientNumber(1);
background_->setTransition(0.8f); background_->setTransition(0.8f);
background_->setSunProgression(1.0f);
background_->setMoonProgression(0.6f);
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::RANDOM_SQUARE); fade_->setType(FadeType::RANDOM_SQUARE);
fade_->setPost(param.fade.post_duration); fade_->setPostDuration(param.fade.post_duration);
fade_->setMode(fade_mode_); fade_->setMode(fade_mode_);
fade_->activate(); fade_->activate();
@@ -77,6 +80,9 @@ void HiScoreTable::update()
// Actualiza el objeto screen // Actualiza el objeto screen
Screen::get()->update(); Screen::get()->update();
// Actualiza las variables de globalInputs
globalInputs::update();
// Actualiza el fondo // Actualiza el fondo
background_->update(); background_->update();
@@ -160,7 +166,7 @@ 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
@@ -193,6 +199,9 @@ void HiScoreTable::checkEvents()
reloadTextures(); reloadTextures();
} }
} }
// Comprueba el cursor
Mouse::handleEvent(event);
} }
} }
@@ -202,9 +211,10 @@ void HiScoreTable::checkInput()
// Comprueba si se ha pulsado cualquier botón (de los usados para jugar) // Comprueba si se ha pulsado cualquier botón (de los usados para jugar)
if (Input::get()->checkAnyButtonPressed()) if (Input::get()->checkAnyButtonPressed())
{ {
JA_StopMusic(); // JA_StopMusic();
section::name = section::Name::TITLE; section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1; section::options = section::Options::TITLE_1;
section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
return; return;
} }

View File

@@ -245,7 +245,15 @@ bool Input::discoverGameControllers()
} }
std::cout << "\n** LOOKING FOR GAME CONTROLLERS" << std::endl; std::cout << "\n** LOOKING FOR GAME CONTROLLERS" << std::endl;
std::cout << "Gamepads found: " << num_gamepads_ << std::endl; if (num_joysticks_ != num_gamepads_)
{
std::cout << "Joysticks found: " << num_joysticks_ << 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)
{ {

View File

@@ -40,9 +40,11 @@ enum class InputType : int
VIDEO_SHADERS, VIDEO_SHADERS,
RESET, RESET,
MUTE, MUTE,
CHANGE_LANG,
SHOWINFO, SHOWINFO,
CONFIG, CONFIG,
SWAP_CONTROLLERS, SWAP_CONTROLLERS,
AUTO_FIRE,
// Input obligatorio // Input obligatorio
NONE, NONE,

View File

@@ -20,6 +20,7 @@
#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"
// Constructor // Constructor
Instructions::Instructions() Instructions::Instructions()
@@ -27,23 +28,21 @@ Instructions::Instructions()
texture_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), texture_(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)), backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
text_(Resource::get()->getText("smb2")), text_(Resource::get()->getText("smb2")),
tiled_bg_(std::make_unique<TiledBG>((SDL_Rect){0, 0, param.game.width, param.game.height}, TiledBGMode::STATIC)), tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::STATIC)),
fade_(std::make_unique<Fade>()) fade_(std::make_unique<Fade>())
{ {
// Crea un backbuffer para el renderizador // Configura las texturas
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
// Crea una textura para el texto fijo
SDL_SetTextureBlendMode(texture_, SDL_BLENDMODE_BLEND); SDL_SetTextureBlendMode(texture_, SDL_BLENDMODE_BLEND);
// Inicializa variables // Inicializa variables
section::name = section::Name::INSTRUCTIONS; section::name = section::Name::INSTRUCTIONS;
view_ = {0, 0, param.game.width, param.game.height}; view_ = param.game.game_area.rect;
// 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();
@@ -211,11 +210,16 @@ void Instructions::update()
// Mantiene la música sonando // Mantiene la música sonando
if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED)) if ((JA_GetMusicState() == JA_MUSIC_INVALID) || (JA_GetMusicState() == JA_MUSIC_STOPPED))
{
JA_PlayMusic(Resource::get()->getMusic("title.ogg")); JA_PlayMusic(Resource::get()->getMusic("title.ogg"));
}
// Actualiza el objeto screen // Actualiza el objeto screen
Screen::get()->update(); Screen::get()->update();
// Actualiza las variables de globalInputs
globalInputs::update();
// Incrementa el contador // Incrementa el contador
counter_++; counter_++;
@@ -261,7 +265,7 @@ void Instructions::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
@@ -298,6 +302,9 @@ void Instructions::checkEvents()
reloadTextures(); reloadTextures();
} }
} }
// Comprueba el cursor
Mouse::handleEvent(event);
} }
} }
@@ -307,9 +314,10 @@ void Instructions::checkInput()
// Comprueba si se ha pulsado cualquier botón (de los usados para jugar) // Comprueba si se ha pulsado cualquier botón (de los usados para jugar)
if (Input::get()->checkAnyButtonPressed()) if (Input::get()->checkAnyButtonPressed())
{ {
JA_StopMusic(); // JA_StopMusic();
section::name = section::Name::TITLE; section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1; section::options = section::Options::TITLE_1;
section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
return; return;
} }

View File

@@ -16,6 +16,7 @@
#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()
@@ -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);
} }
} }
@@ -382,6 +388,9 @@ void Intro::update()
// Actualiza las escenas de la intro // Actualiza las escenas de la intro
updateScenes(); updateScenes();
// Actualiza las variables de globalInputs
globalInputs::update();
} }
} }
@@ -406,14 +415,13 @@ 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
void Intro::run() void Intro::run()
{ {
JA_PlayMusic(Resource::get()->getMusic("intro.ogg"), 0); JA_PlayMusic(Resource::get()->getMusic("intro.ogg"), 0);
while (section::name == section::Name::INTRO) while (section::name == section::Name::INTRO)
{ {
checkInput(); checkInput();

View File

@@ -1,9 +1,9 @@
#include "item.h" #include "item.h"
#include <algorithm> // para std::clamp #include <stdlib.h> // Para rand
#include <stdlib.h> // para rand #include <algorithm> // Para clamp
#include "animated_sprite.h" // para SpriteAnimated #include "animated_sprite.h" // Para AnimatedSprite
#include "param.h" // para param #include "param.h" // Para Param, ParamGame, param
class Texture; class Texture; // lines 6-6
Item::Item(ItemType type, float x, float y, SDL_Rect &play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation) Item::Item(ItemType type, float x, float y, SDL_Rect &play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation)
: sprite_(std::make_unique<AnimatedSprite>(texture, animation)), : sprite_(std::make_unique<AnimatedSprite>(texture, animation)),
@@ -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);
@@ -73,8 +73,6 @@ void Item::render()
} }
} }
#include <algorithm> // Necesario para std::clamp
void Item::move() void Item::move()
{ {
floor_collision_ = false; floor_collision_ = false;

View File

@@ -1,12 +1,13 @@
#ifndef JA_USESDLMIXER #ifndef JA_USESDLMIXER
#include "jail_audio.h" #include "jail_audio.h"
#include <stdint.h> // para uint8_t #include <SDL2/SDL_rwops.h> // Para SDL_RWFromMem
#include <stdio.h> // para NULL, fseek, fclose, fopen, fread, ftell, FILE #include <SDL2/SDL_timer.h> // Para SDL_GetTicks
#include <stdlib.h> // para free, malloc #include <stdint.h> // Para uint8_t, uint32_t
#include "stb_vorbis.c" // para stb_vorbis_decode_memory #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 5 #define JA_MAX_SIMULTANEOUS_CHANNELS 20
struct JA_Sound_t struct JA_Sound_t
{ {
@@ -25,6 +26,7 @@ struct JA_Channel_t
struct JA_Music_t struct JA_Music_t
{ {
int samples{0}; int samples{0};
Uint32 length{0};
int pos{0}; int pos{0};
int times{0}; int times{0};
short *output{NULL}; short *output{NULL};
@@ -43,20 +45,43 @@ bool JA_musicEnabled = true;
bool JA_soundEnabled = true; bool JA_soundEnabled = true;
SDL_AudioDeviceID sdlAudioDevice = 0; SDL_AudioDeviceID sdlAudioDevice = 0;
bool fading = false;
int fade_start_time;
int fade_duration;
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)
{ {
const int size = SDL_min(len, current_music->samples * 2 - current_music->pos); int volume = JA_musicVolume;
SDL_MixAudioFormat(stream, (Uint8 *)(current_music->output + current_music->pos), AUDIO_S16, size, JA_musicVolume); if (fading)
current_music->pos += size / 2; {
int time = SDL_GetTicks();
if (time > (fade_start_time + fade_duration))
{
fading = false;
current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED;
volume = 0;
}
else
{
const int time_passed = time - fade_start_time;
const float percent = (float)time_passed / (float)fade_duration;
volume = JA_musicVolume * (1.0 - percent);
}
}
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);
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, JA_musicVolume); SDL_MixAudioFormat(stream + size, (Uint8 *)current_music->output, AUDIO_S16, len - size, volume);
current_music->pos = (len - size) / 2; current_music->pos = len - size;
if (current_music->times > 0) if (current_music->times > 0)
current_music->times--; current_music->times--;
} }
@@ -113,10 +138,36 @@ void JA_Quit()
sdlAudioDevice = 0; sdlAudioDevice = 0;
} }
JA_Music_t *JA_LoadMusic(const char *filename) JA_Music_t *JA_LoadMusic(Uint8 *buffer, Uint32 length)
{ {
int chan, samplerate; int chan, samplerate;
JA_Music_t *music = new JA_Music_t();
music->samples = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &music->output);
// [RZC 28/08/22] Abans el descomprimiem mentre el teniem obert
// music->samples = stb_vorbis_decode_filename(filename, &chan, &samplerate, &music->output);
SDL_AudioCVT cvt;
SDL_BuildAudioCVT(&cvt, AUDIO_S16, chan, samplerate, JA_format, JA_channels, JA_freq);
if (cvt.needed)
{
cvt.len = music->samples * chan * 2;
music->length = cvt.len;
cvt.buf = (Uint8 *)SDL_malloc(cvt.len * cvt.len_mult);
SDL_memcpy(cvt.buf, music->output, cvt.len);
SDL_ConvertAudio(&cvt);
free(music->output);
music->output = (short *)cvt.buf;
}
music->length = music->samples * chan * 2;
music->pos = 0;
music->state = JA_MUSIC_STOPPED;
return music;
}
JA_Music_t *JA_LoadMusic(const char *filename)
{
// [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid. // [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid.
FILE *f = fopen(filename, "rb"); FILE *f = fopen(filename, "rb");
fseek(f, 0, SEEK_END); fseek(f, 0, SEEK_END);
@@ -127,33 +178,16 @@ JA_Music_t *JA_LoadMusic(const char *filename)
return NULL; return NULL;
fclose(f); fclose(f);
JA_Music_t *music = new JA_Music_t(); JA_Music_t *music = JA_LoadMusic(buffer, fsize);
music->samples = stb_vorbis_decode_memory(buffer, fsize, &chan, &samplerate, &music->output);
free(buffer); free(buffer);
// [RZC 28/08/22] Abans el descomprimiem mentre el teniem obert
// music->samples = stb_vorbis_decode_filename(filename, &chan, &samplerate, &music->output);
SDL_AudioCVT cvt;
SDL_BuildAudioCVT(&cvt, AUDIO_S16, chan, samplerate, JA_format, JA_channels, JA_freq);
if (cvt.needed)
{
cvt.len = music->samples * chan * 2;
cvt.buf = (Uint8 *)SDL_malloc(cvt.len * cvt.len_mult);
SDL_memcpy(cvt.buf, music->output, cvt.len);
SDL_ConvertAudio(&cvt);
free(music->output);
music->output = (short *)cvt.buf;
}
music->pos = 0;
music->state = JA_MUSIC_STOPPED;
return music; return music;
} }
void JA_PlayMusic(JA_Music_t *music, const int loop) void JA_PlayMusic(JA_Music_t *music, const int loop)
{ {
if (!JA_musicEnabled || !music) if (!JA_musicEnabled)
return; return;
if (current_music != NULL) if (current_music != NULL)
@@ -198,6 +232,19 @@ void JA_StopMusic()
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
} }
void JA_FadeOutMusic(const int milliseconds)
{
if (!JA_musicEnabled)
return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID)
return;
fading = true;
fade_start_time = SDL_GetTicks();
fade_duration = milliseconds;
fade_initial_volume = JA_musicVolume;
}
JA_Music_state JA_GetMusicState() JA_Music_state JA_GetMusicState()
{ {
if (!JA_musicEnabled) if (!JA_musicEnabled)
@@ -223,6 +270,20 @@ int JA_SetMusicVolume(int volume)
return JA_musicVolume; return JA_musicVolume;
} }
void JA_SetMusicPosition(float value)
{
if (!current_music)
return;
current_music->pos = value * JA_freq;
}
float JA_GetMusicPosition()
{
if (!current_music)
return 0;
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) if (!value && current_music != NULL && current_music->state == JA_MUSIC_PLAYING)
@@ -239,6 +300,25 @@ JA_Sound_t *JA_NewSound(Uint8 *buffer, Uint32 length)
return sound; return sound;
} }
JA_Sound_t *JA_LoadSound(uint8_t *buffer, uint32_t size)
{
JA_Sound_t *sound = new JA_Sound_t();
SDL_AudioSpec wavSpec;
SDL_LoadWAV_RW(SDL_RWFromMem(buffer, size), 1, &wavSpec, &sound->buffer, &sound->length);
SDL_AudioCVT cvt;
SDL_BuildAudioCVT(&cvt, wavSpec.format, wavSpec.channels, wavSpec.freq, JA_format, JA_channels, JA_freq);
cvt.len = sound->length;
cvt.buf = (Uint8 *)SDL_malloc(cvt.len * cvt.len_mult);
SDL_memcpy(cvt.buf, sound->buffer, sound->length);
SDL_ConvertAudio(&cvt);
SDL_FreeWAV(sound->buffer);
sound->buffer = cvt.buf;
sound->length = cvt.len_cvt;
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();
@@ -260,8 +340,8 @@ 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 || !sound) if (!JA_soundEnabled)
return 0; return -1;
int channel = 0; int channel = 0;
while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE)
@@ -278,6 +358,21 @@ int JA_PlaySound(JA_Sound_t *sound, const int loop)
return channel; return channel;
} }
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop)
{
if (!JA_soundEnabled)
return -1;
if (channel >= JA_MAX_SIMULTANEOUS_CHANNELS)
return -1;
channels[channel].sound = sound;
channels[channel].times = loop;
channels[channel].pos = 0;
channels[channel].state = JA_CHANNEL_PLAYING;
return channel;
}
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++)

View File

@@ -1,9 +1,9 @@
#pragma once #pragma once
#include <SDL2/SDL_audio.h> // para SDL_AudioFormat #include <SDL2/SDL_audio.h> // Para SDL_AudioFormat
#include <SDL2/SDL_stdinc.h> // para Uint32, Uint8 #include <SDL2/SDL_stdinc.h> // Para Uint32, Uint8
struct JA_Music_t; // lines 5-5 struct JA_Music_t; // lines 4-4
struct JA_Sound_t; // lines 6-6 struct JA_Sound_t; // lines 5-5
enum JA_Channel_state enum JA_Channel_state
{ {
@@ -26,18 +26,24 @@ void JA_Init(const int freq, const SDL_AudioFormat format, const int channels);
void JA_Quit(); void JA_Quit();
JA_Music_t *JA_LoadMusic(const char *filename); JA_Music_t *JA_LoadMusic(const char *filename);
JA_Music_t *JA_LoadMusic(Uint8 *buffer, Uint32 length);
void JA_PlayMusic(JA_Music_t *music, const int loop = -1); void JA_PlayMusic(JA_Music_t *music, const int loop = -1);
void JA_PauseMusic(); void JA_PauseMusic();
void JA_ResumeMusic(); void JA_ResumeMusic();
void JA_StopMusic(); void JA_StopMusic();
void JA_FadeOutMusic(const int milliseconds);
JA_Music_state JA_GetMusicState(); JA_Music_state JA_GetMusicState();
void JA_DeleteMusic(JA_Music_t *music); void JA_DeleteMusic(JA_Music_t *music);
int JA_SetMusicVolume(int volume); int JA_SetMusicVolume(int volume);
void JA_SetMusicPosition(float value);
float JA_GetMusicPosition();
void JA_EnableMusic(const bool value); void JA_EnableMusic(const bool value);
JA_Sound_t *JA_NewSound(Uint8 *buffer, Uint32 length); JA_Sound_t *JA_NewSound(Uint8 *buffer, Uint32 length);
JA_Sound_t *JA_LoadSound(Uint8 *buffer, Uint32 length);
JA_Sound_t *JA_LoadSound(const char *filename); JA_Sound_t *JA_LoadSound(const char *filename);
int JA_PlaySound(JA_Sound_t *sound, const int loop = 0); int JA_PlaySound(JA_Sound_t *sound, const int loop = 0);
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop = 0);
void JA_PauseChannel(const int channel); void JA_PauseChannel(const int channel);
void JA_ResumeChannel(const int channel); void JA_ResumeChannel(const int channel);
void JA_StopChannel(const int channel); void JA_StopChannel(const int channel);

View File

@@ -40,4 +40,12 @@ namespace lang
{ {
return texts.at(index); return texts.at(index);
} }
// Cambia el idioma seleccionado al siguiente idioma disponible
Code change(Code current_lang)
{
auto index = static_cast<int>(current_lang);
index = (index + 1) % 3;
return static_cast<Code>(index);
}
} }

View File

@@ -16,4 +16,7 @@ namespace lang
// Obtiene la cadena de texto del indice // Obtiene la cadena de texto del indice
std::string getText(int index); std::string getText(int index);
// Cambia el idioma seleccionado al siguiente idioma disponible
Code change(Code current_lang);
} }

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()
@@ -59,6 +60,7 @@ Logo::~Logo()
{ {
jail_texture_->setColor(255, 255, 255); jail_texture_->setColor(255, 255, 255);
since_texture_->setColor(255, 255, 255); since_texture_->setColor(255, 255, 255);
JA_StopChannel(-1);
} }
// Recarga todas las texturas // Recarga todas las texturas
@@ -91,6 +93,9 @@ void Logo::checkEvents()
reloadTextures(); reloadTextures();
} }
} }
// Comprueba el cursor
Mouse::handleEvent(event);
} }
} }
@@ -100,7 +105,6 @@ void Logo::checkInput()
// Comprueba si se ha pulsado cualquier botón (de los usados para jugar) // Comprueba si se ha pulsado cualquier botón (de los usados para jugar)
if (Input::get()->checkAnyButtonPressed()) if (Input::get()->checkAnyButtonPressed())
{ {
JA_StopMusic();
section::name = section::Name::TITLE; section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1; section::options = section::Options::TITLE_1;
return; return;
@@ -113,6 +117,11 @@ void Logo::checkInput()
// Gestiona el logo de JAILGAME // Gestiona el logo de JAILGAME
void Logo::updateJAILGAMES() void Logo::updateJAILGAMES()
{ {
if (counter_ == 30)
{
JA_PlaySound(Resource::get()->getSound("logo.wav"));
}
if (counter_ > 30) if (counter_ > 30)
{ {
for (int i = 0; i < (int)jail_sprite_.size(); ++i) for (int i = 0; i < (int)jail_sprite_.size(); ++i)
@@ -195,6 +204,9 @@ void Logo::update()
{ {
section::name = section::Name::INTRO; section::name = section::Name::INTRO;
} }
// Actualiza las variables de globalInputs
globalInputs::update();
} }
} }
@@ -219,14 +231,14 @@ 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
void Logo::run() void Logo::run()
{ {
// Detiene la música // Detiene la música
JA_StopMusic(); JA_FadeOutMusic(300);
while (section::name == section::Name::LOGO) while (section::name == section::Name::LOGO)
{ {

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

@@ -10,14 +10,15 @@
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "text.h" // Para Text #include "text.h" // Para Text
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "resource.h"
// [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
Notifier *Notifier::notifier_ = nullptr; Notifier *Notifier::notifier_ = nullptr;
// [SINGLETON] Crearemos el objeto screen con esta función estática // [SINGLETON] Crearemos el objeto screen con esta función estática
void Notifier::init(const std::string &icon_file, std::shared_ptr<Text> text, const std::string &sound_file) void Notifier::init(const std::string &icon_file, std::shared_ptr<Text> text)
{ {
Notifier::notifier_ = new Notifier(icon_file, text, sound_file); Notifier::notifier_ = new Notifier(icon_file, text);
} }
// [SINGLETON] Destruiremos el objeto screen con esta función estática // [SINGLETON] Destruiremos el objeto screen con esta función estática
@@ -33,21 +34,14 @@ Notifier *Notifier::get()
} }
// Constructor // Constructor
Notifier::Notifier(std::string icon_file, std::shared_ptr<Text> text, const std::string &sound_file) Notifier::Notifier(std::string icon_file, std::shared_ptr<Text> text)
: renderer_(Screen::get()->getRenderer()), : renderer_(Screen::get()->getRenderer()),
icon_texture_(!icon_file.empty() ? std::make_unique<Texture>(renderer_, icon_file) : nullptr), icon_texture_(!icon_file.empty() ? std::make_unique<Texture>(renderer_, icon_file) : nullptr),
text_(text), text_(text),
bg_color_(param.notification.color), bg_color_(param.notification.color),
wait_time_(150), wait_time_(150),
stack_(false), stack_(false),
has_icons_(!icon_file.empty()), has_icons_(!icon_file.empty()) {}
sound_(JA_LoadSound(sound_file.c_str())) {}
// Destructor
Notifier::~Notifier()
{
JA_DeleteSound(sound_);
}
// Dibuja las notificaciones por pantalla // Dibuja las notificaciones por pantalla
void Notifier::render() void Notifier::render()
@@ -66,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;
} }
@@ -79,15 +73,16 @@ 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 {
JA_PlaySound(sound_); // Reproduce el sonido de la notificación
JA_PlaySound(Resource::get()->getSound("notify.wav"));
} }
} }
} }
// 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;
@@ -104,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);
@@ -136,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;
} }
} }
@@ -151,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);
} }
@@ -307,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("") {}
}; };
@@ -62,7 +61,6 @@ private:
std::vector<Notification> notifications_; // La lista de notificaciones activas std::vector<Notification> notifications_; // La lista de notificaciones activas
bool stack_; // Indica si las notificaciones se apilan bool stack_; // Indica si las notificaciones se apilan
bool has_icons_; // Indica si el notificador tiene textura para iconos bool has_icons_; // Indica si el notificador tiene textura para iconos
JA_Sound_t *sound_; // Sonido a reproducir cuando suena la notificación
// Elimina las notificaciones finalizadas // Elimina las notificaciones finalizadas
void clearFinishedNotifications(); void clearFinishedNotifications();
@@ -73,14 +71,14 @@ private:
// [SINGLETON] Ahora el constructor y el destructor son privados, para no poder crear objetos notifier desde fuera // [SINGLETON] Ahora el constructor y el destructor son privados, para no poder crear objetos notifier desde fuera
// Constructor // Constructor
Notifier(std::string icon_file, std::shared_ptr<Text> text, const std::string &sound_file); Notifier(std::string icon_file, std::shared_ptr<Text> text);
// Destructor // Destructor
~Notifier(); ~Notifier() = default;
public: public:
// [SINGLETON] Crearemos el objeto notifier con esta función estática // [SINGLETON] Crearemos el objeto notifier con esta función estática
static void init(const std::string &icon_file, std::shared_ptr<Text> text, const std::string &sound_file); static void init(const std::string &icon_file, std::shared_ptr<Text> text);
// [SINGLETON] Destruiremos el objeto notifier con esta función estática // [SINGLETON] Destruiremos el objeto notifier con esta función estática
static void destroy(); static void destroy();

View File

@@ -23,7 +23,8 @@ enum class GameDifficulty
// Estructura para las opciones de la ventana // Estructura para las opciones de la ventana
struct OptionsWindow struct OptionsWindow
{ {
int size; // Contiene el valor por el que se multiplica el tamaño de la ventana int size = 1; // Contiene el valor por el que se multiplica el tamaño de la ventana
int max_size = 1; // Tamaño máximo para que el tamaño de la ventana no sea mayor que el tamaño de la pantalla
}; };
// Estructura con opciones para el video // Estructura con opciones para el video

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,6 +1,6 @@
// IWYU pragma: no_include <bits/std_abs.h>
#include "path_sprite.h" #include "path_sprite.h"
#include <cmath> // Para abs #include <cstdlib> // Para abs
#include <stdlib.h> // Para abs
#include <functional> // Para function #include <functional> // Para function
#include <utility> // Para move #include <utility> // Para move
@@ -96,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)
{
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

View File

@@ -73,4 +73,7 @@ public:
// 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

@@ -1,15 +1,16 @@
#include "player.h" #include "player.h"
#include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL, SDL_FLIP_NONE #include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL, SDL_FLIP_NONE, SDL...
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks #include <SDL2/SDL_timer.h> // Para SDL_GetTicks
#include <stdlib.h> // Para rand #include <stdlib.h> // Para rand
#include <algorithm> // Para max, min #include <algorithm> // Para clamp, max, min
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
#include "input.h" // Para InputType #include "input.h" // Para InputType
#include "manage_hiscore_table.h" // Para HiScoreEntry #include "param.h" // Para Param, ParamGame, param
#include "options.h" // Para Options, OptionsGame, options #include "scoreboard.h" // Para Scoreboard, ScoreboardMode
#include "param.h" // Para Param, ParamGame, param #include "texture.h" // Para Texture
#include "scoreboard.h" // Para Scoreboard, ScoreboardMode #include "resource.h"
#include "texture.h" // Para Texture #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,7 +57,7 @@ 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();
// Establece la posición del sprite // Establece la posición del sprite
@@ -164,7 +165,7 @@ void Player::move()
pos_x_ += vel_x_; pos_x_ += vel_x_;
// Si el jugador abandona el area de juego por los laterales, restaura su posición // Si el jugador abandona el area de juego por los laterales, restaura su posición
const float min_x = param.game.play_area.rect.x - 5; const float min_x = play_area_.x - 5;
const float max_x = play_area_.w + 5 - WIDTH_; const float max_x = play_area_.w + 5 - WIDTH_;
pos_x_ = std::clamp(pos_x_, min_x, max_x); pos_x_ = std::clamp(pos_x_, min_x, max_x);
@@ -174,13 +175,18 @@ 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() < param.game.play_area.rect.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());
playRandomBubbleSound();
} }
// Si el cadaver toca el suelo cambia el estado // Si el cadaver toca el suelo cambia el estado
if (player_sprite_->getPosY() > param.game.play_area.rect.h - HEIGHT_) if (player_sprite_->getPosY() > play_area_.h - HEIGHT_)
{ {
if (player_sprite_->getVelY() < 2.0f) if (player_sprite_->getVelY() < 2.0f)
{ {
@@ -190,19 +196,27 @@ void Player::move()
pos_y_ = default_pos_y_; pos_y_ = default_pos_y_;
player_sprite_->clear(); player_sprite_->clear();
shiftSprite(); shiftSprite();
playRandomBubbleSound();
} }
else else
{ {
// Decrementa las velocidades de rebote // Decrementa las velocidades de rebote
player_sprite_->setPosY(param.game.play_area.rect.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);
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:
@@ -221,7 +235,80 @@ 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;
}
case PlayerState::CREDITS:
{
pos_x_ += vel_x_ / 2.0f;
if (vel_x_ > 0)
{
// setInputPlaying(InputType::RIGHT);
if (pos_x_ > param.game.game_area.rect.w - WIDTH_)
{
pos_x_ = param.game.game_area.rect.w - WIDTH_;
vel_x_ *= -1;
// setInputPlaying(InputType::LEFT);
}
}
else
{
// setInputPlaying(InputType::LEFT);
if (pos_x_ < param.game.game_area.rect.x)
{
pos_x_ = param.game.game_area.rect.x;
vel_x_ *= -1;
// setInputPlaying(InputType::RIGHT);
}
}
if (pos_x_ > param.game.game_area.center_x - WIDTH_ / 2)
{
setWalkingState(PlayerState::WALKING_LEFT);
}
else
{
setWalkingState(PlayerState::WALKING_RIGHT);
}
shiftSprite();
break; break;
} }
default: default:
@@ -253,7 +340,9 @@ 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:
{ {
// Crea cadenas de texto para componer el nombre de la animación // Crea cadenas de texto para componer el nombre de la animación
const std::string a_walking = walking_state_ == PlayerState::WALKING_STOP ? "stand" : "walk"; const std::string a_walking = walking_state_ == PlayerState::WALKING_STOP ? "stand" : "walk";
@@ -313,37 +402,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)
{ {
cooling_status_counter_ = 40; if (cooling_state_counter_ == 40)
switch (firing_state_)
{ {
case PlayerState::FIRING_LEFT: switch (firing_state_)
firing_state_ = PlayerState::COOLING_LEFT; {
break; case PlayerState::FIRING_LEFT:
case PlayerState::FIRING_RIGHT: setFiringState(PlayerState::COOLING_LEFT);
firing_state_ = PlayerState::COOLING_RIGHT; break;
break; case PlayerState::FIRING_RIGHT:
case PlayerState::FIRING_UP: setFiringState(PlayerState::COOLING_RIGHT);
firing_state_ = PlayerState::COOLING_UP; break;
break; case PlayerState::FIRING_UP:
default: setFiringState(PlayerState::COOLING_UP);
break; break;
default:
break;
}
} }
} --cooling_state_counter_;
else if (cooling_status_counter_ > 0)
{
--cooling_status_counter_;
} }
else else
{ {
setFiringState(PlayerState::FIRING_NONE); setFiringState(PlayerState::FIRING_NONE);
cooling_state_counter_ = 0;
} }
} }
} }
@@ -414,6 +504,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:
@@ -467,9 +558,34 @@ 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:
{
vel_x_ = (walking_state_ == PlayerState::WALKING_RIGHT) ? BASE_SPEED_ : -BASE_SPEED_;
break;
}
default: default:
break; break;
} }
@@ -604,6 +720,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
@@ -615,9 +735,13 @@ void Player::decEnterNameCounter()
{ {
enter_name_counter_ = param.game.enter_name_seconds; enter_name_counter_ = param.game.enter_name_seconds;
if (playing_state_ == PlayerState::ENTERING_NAME) if (playing_state_ == PlayerState::ENTERING_NAME)
{
setPlayingState(PlayerState::CONTINUE); setPlayingState(PlayerState::CONTINUE);
}
else else
{
setPlayingState(PlayerState::LEAVING_SCREEN); setPlayingState(PlayerState::LEAVING_SCREEN);
}
} }
} }
@@ -625,7 +749,9 @@ void Player::decEnterNameCounter()
int Player::getRecordNamePos() const int Player::getRecordNamePos() const
{ {
if (enter_name_) if (enter_name_)
{
return enter_name_->getPosition(); return enter_name_->getPosition();
}
return 0; return 0;
} }
@@ -636,4 +762,11 @@ void Player::shiftSprite()
player_sprite_->setPosX(pos_x_); player_sprite_->setPosX(pos_x_);
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

@@ -1,18 +1,18 @@
#pragma once #pragma once
#include "animated_sprite.h" // Para AnimatedSprite #include <SDL2/SDL_rect.h> // Para SDL_Rect
#include "enter_name.h" // Para EnterName #include <SDL2/SDL_stdinc.h> // Para Uint32
#include "utils.h" // Para Circle #include <memory> // Para unique_ptr, shared_ptr
#include <SDL2/SDL_rect.h> // Para SDL_Rect #include <string> // Para string
#include <SDL2/SDL_stdinc.h> // Para Uint32 #include <vector> // Para vector
#include <memory> // Para unique_ptr, shared_ptr #include "animated_sprite.h" // Para AnimatedSprite
#include <string> // Para string #include "enter_name.h" // Para EnterName
#include <vector> // Para vector #include "manage_hiscore_table.h" // Para HiScoreEntry
#include "options.h" #include "options.h" // Para Options, OptionsGame, options
#include "utils.h" // Para Circle
class Texture; // lines 12-12 class Texture; // lines 13-13
enum class InputType : int; // lines 13-13 enum class InputType : int; // lines 14-14
enum class ScoreboardMode; // lines 14-14 enum class ScoreboardMode; // lines 15-15
// Estados del jugador // Estados del jugador
enum class PlayerState enum class PlayerState
@@ -40,6 +40,8 @@ enum class PlayerState
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
}; };
// Clase Player // Clase Player
@@ -67,8 +69,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
@@ -90,6 +92,7 @@ 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
int step_counter_ = 0; // Cuenta los pasos para los estados en los que camina automáticamente
// 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();
@@ -115,6 +118,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:
@@ -200,10 +207,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_; }
@@ -226,7 +233,7 @@ public:
// 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; }

View File

@@ -34,6 +34,24 @@ Resource *Resource::get()
// Constructor // Constructor
Resource::Resource() Resource::Resource()
{
load();
}
// Vacia todos los vectores de recursos
void Resource::clear()
{
clearSounds();
clearMusics();
textures_.clear();
text_files_.clear();
texts_.clear();
animations_.clear();
demos_.clear();
}
// Carga todos los recursos
void Resource::load()
{ {
std::cout << "** LOADING RESOURCES" << std::endl; std::cout << "** LOADING RESOURCES" << std::endl;
loadSounds(); loadSounds();
@@ -48,6 +66,13 @@ Resource::Resource()
std::cout << "\n** RESOURCES LOADED" << std::endl; std::cout << "\n** RESOURCES LOADED" << std::endl;
} }
// Recarga todos los recursos
void Resource::reload()
{
clear();
load();
}
// Obtiene el sonido a partir de un nombre // Obtiene el sonido a partir de un nombre
JA_Sound_t *Resource::getSound(const std::string &name) JA_Sound_t *Resource::getSound(const std::string &name)
{ {
@@ -229,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"));
@@ -265,7 +290,7 @@ void Resource::createTextures()
NameAndText("game_text_powerup", lang::getText(117)), NameAndText("game_text_powerup", lang::getText(117)),
NameAndText("game_text_one_hit", lang::getText(118)), NameAndText("game_text_one_hit", lang::getText(118)),
NameAndText("game_text_stop", lang::getText(119)), NameAndText("game_text_stop", lang::getText(119)),
NameAndText("1000000_points", lang::getText(76))}; NameAndText("game_text_1000000_points", lang::getText(76))};
auto text = getText("04b_25"); auto text = getText("04b_25");
for (const auto &s : strings) for (const auto &s : strings)
@@ -276,10 +301,10 @@ void Resource::createTextures()
// Tamaño doble // Tamaño doble
std::vector<NameAndText> strings2X = { std::vector<NameAndText> strings2X = {
NameAndText("get_ready", lang::getText(75)), NameAndText("game_text_get_ready", lang::getText(75)),
NameAndText("last_stage", lang::getText(79)), NameAndText("game_text_last_stage", lang::getText(79)),
NameAndText("congratulations", lang::getText(50)), NameAndText("game_text_congratulations", lang::getText(50)),
NameAndText("game_over", "Game Over")}; NameAndText("game_text_game_over", "Game Over")};
auto text2 = getText("04b_25_2x"); auto text2 = getText("04b_25_2x");
for (const auto &s : strings2X) for (const auto &s : strings2X)
@@ -307,3 +332,33 @@ void Resource::createText()
printWithDots("Text : ", resource.first, "[ DONE ]"); printWithDots("Text : ", resource.first, "[ DONE ]");
} }
} }
// Vacía el vector de sonidos
void Resource::clearSounds()
{
// Itera sobre el vector y libera los recursos asociados a cada JA_Sound_t
for (auto &sound : sounds_)
{
if (sound.sound)
{
JA_DeleteSound(sound.sound);
sound.sound = nullptr;
}
}
sounds_.clear(); // Limpia el vector después de liberar todos los recursos
}
// Vacía el vector de musicas
void Resource::clearMusics()
{
// Itera sobre el vector y libera los recursos asociados a cada JA_Music_t
for (auto &music : musics_)
{
if (music.music)
{
JA_DeleteMusic(music.music);
music.music = nullptr;
}
}
musics_.clear(); // Limpia el vector después de liberar todos los recursos
}

View File

@@ -117,6 +117,18 @@ private:
// Crea los objetos de texto // Crea los objetos de texto
void createText(); void createText();
// Vacia todos los vectores de recursos
void clear();
// Carga todos los recursos
void load();
// Vacía el vector de sonidos
void clearSounds();
// Vacía el vector de musicas
void clearMusics();
// [SINGLETON] Ahora el constructor y el destructor son privados, para no poder crear objetos resource desde fuera // [SINGLETON] Ahora el constructor y el destructor son privados, para no poder crear objetos resource desde fuera
// Constructor // Constructor
@@ -155,4 +167,7 @@ public:
// Obtiene el fichero con los datos para el modo demostración a partir de un çindice // Obtiene el fichero con los datos para el modo demostración a partir de un çindice
DemoData &getDemoData(int index); DemoData &getDemoData(int index);
// Recarga todos los recursos
void reload();
}; };

View File

@@ -11,10 +11,10 @@
#include "asset.h" // Para Asset #include "asset.h" // Para Asset
#include "dbgtxt.h" // Para dbg_print #include "dbgtxt.h" // Para dbg_print
#include "global_inputs.h" // Para service_pressed_counter #include "global_inputs.h" // Para service_pressed_counter
#include "jail_shader.h" // Para init, render
#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
@@ -46,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})
{ {
@@ -66,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
@@ -83,69 +81,41 @@ 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_
doFlash(); renderFlash();
renderAttenuate();
// Atenua la pantalla
doAttenuate();
// 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 // Restablece el objetivo de renderizado al buffer de pantalla predeterminado
// Vuelve a dejar el renderizador en modo normal
SDL_SetRenderTarget(renderer_, nullptr); SDL_SetRenderTarget(renderer_, nullptr);
// Borra el contenido previo // Renderiza el contenido del game_canvas_ o aplica shaders según configuración
SDL_SetRenderDrawColor(renderer_, border_color_.r, border_color_.g, border_color_.b, 0xFF); renderScreen();
SDL_RenderClear(renderer_); }
// Copia la textura de juego en el renderizador en la posición adecuada // Selecciona y ejecuta el método de renderizado adecuado basado en la configuración de shaders
if (shake_effect_.enabled) void Screen::renderScreen()
SDL_RenderCopy(renderer_, game_canvas_, nullptr, nullptr); {
SDL_RenderCopy(renderer_, game_canvas_, &src_rect_, &dst_rect_); #ifdef NO_SHADERS
// Actualiza la pantalla con el contenido del game_canvas_
// Muestra por pantalla el renderizador presentGameCanvas();
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 game_canvas_
SDL_SetRenderTarget(renderer_, nullptr); presentGameCanvas();
// 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_);
} }
#endif #endif
} }
@@ -201,10 +171,11 @@ void Screen::setVideoMode(ScreenVideoMode videoMode)
if (options.video.shaders) if (options.video.shaders)
{ {
#ifndef NO_SHADERS #ifndef NO_SHADERS
std::ifstream f(Asset::get()->get("crtpi.glsl").c_str()); const std::string glsl_file = param.game.game_area.rect.h == 256 ? "crtpi_256.glsl" : "crtpi_240.glsl";
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
} }
} }
@@ -235,7 +206,7 @@ void Screen::decWindowSize()
void Screen::incWindowSize() void Screen::incWindowSize()
{ {
++options.video.window.size; ++options.video.window.size;
options.video.window.size = std::min(options.video.window.size, 4); options.video.window.size = std::min(options.video.window.size, options.video.window.max_size);
setVideoMode(ScreenVideoMode::WINDOW); setVideoMode(ScreenVideoMode::WINDOW);
} }
@@ -255,9 +226,11 @@ void Screen::setBlendMode(SDL_BlendMode blendMode)
void Screen::update() void Screen::update()
{ {
updateShakeEffect(); updateShakeEffect();
updateFlash();
Notifier::get()->update(); Notifier::get()->update();
updateFPS(); updateFPS();
OnScreenHelp::get()->update(); OnScreenHelp::get()->update();
Mouse::updateCursorVisibility();
} }
// Agita la pantalla // Agita la pantalla
@@ -307,27 +280,29 @@ void Screen::updateShakeEffect()
} }
// Pone la pantalla de color // Pone la pantalla de color
void Screen::flash(Color color, int lenght) void Screen::flash(Color color, int lenght, int delay)
{ {
flash_effect_ = FlashEffect(true, lenght, color); flash_effect_ = FlashEffect(true, lenght, delay, color);
} }
// Actualiza y dibuja el efecto de flash en la pantalla // Actualiza y dibuja el efecto de flash en la pantalla
void Screen::doFlash() void Screen::renderFlash()
{ {
if (flash_effect_.enabled) if (flash_effect_.isRendarable())
{ {
// Dibuja el color del flash en la textura
SDL_SetRenderDrawColor(renderer_, flash_effect_.color.r, flash_effect_.color.g, flash_effect_.color.b, 0xFF); SDL_SetRenderDrawColor(renderer_, flash_effect_.color.r, flash_effect_.color.g, flash_effect_.color.b, 0xFF);
SDL_RenderClear(renderer_); SDL_RenderClear(renderer_);
// Actualiza la lógica del efecto
flash_effect_.counter > 0 ? flash_effect_.counter-- : flash_effect_.enabled = false;
} }
} }
// Actualiza el efecto de flash
void Screen::updateFlash()
{
flash_effect_.update();
}
// Atenua la pantalla // Atenua la pantalla
void Screen::doAttenuate() void Screen::renderAttenuate()
{ {
if (attenuate_effect_) if (attenuate_effect_)
{ {
@@ -387,8 +362,11 @@ void Screen::renderInfo()
dbg_print(0, 0, info_resolution_.c_str(), 255, 255, 0); dbg_print(0, 0, info_resolution_.c_str(), 255, 255, 0);
// Contador de service_pressed_counter // Contador de service_pressed_counter
if (const int counter = globalInputs::service_pressed_counter[0]; counter > 0) if (const int counter = globalInputs::service_pressed_counter; counter > 0)
dbg_print(0, 8, std::to_string(counter).c_str(), 255, 0, 255); dbg_print(0, 8, std::to_string(counter).c_str(), 255, 0, 255);
const std::string atten = attenuate_effect_ ? "ATTEN YES" : "ATTEN NO";
dbg_print(0, 16, atten.c_str(), 255, 0, 0);
} }
} }
@@ -426,4 +404,19 @@ SDL_Point Screen::getNewPosition()
new_pos.y = std::clamp(new_pos.y, 30, DM.h - new_height); new_pos.y = std::clamp(new_pos.y, 30, DM.h - new_height);
return new_pos; return new_pos;
}
// Actualiza la pantalla con el contenido del game_canvas_
void Screen::presentGameCanvas()
{
// Copia la textura de juego en el renderizador en la posición adecuada
if (shake_effect_.enabled)
{
// Esta copia es para evitar que se vea negro por los laterales
SDL_RenderCopy(renderer_, game_canvas_, nullptr, nullptr);
}
SDL_RenderCopy(renderer_, game_canvas_, &src_rect_, &dst_rect_);
// Actualiza la pantalla con el contenido del buffer de renderizado
SDL_RenderPresent(renderer_);
} }

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
@@ -51,12 +50,20 @@ private:
struct FlashEffect struct FlashEffect
{ {
bool enabled; // Indica si el efecto está activo bool enabled; // Indica si el efecto está activo
int lenght; // Duración del efecto
int delay; // Frames iniciales en los que no se aplica
int counter; // Contador para el efecto int counter; // Contador para el efecto
Color color; // Color del efecto Color color; // Color del efecto
// Constructor // Constructor
explicit FlashEffect(bool en = false, int cnt = 0, Color col = Color(0xFF, 0xFF, 0xFF)) explicit FlashEffect(bool enabled = false, int lenght = 0, int delay = 0, Color color = Color(0xFF, 0xFF, 0xFF))
: enabled(en), counter(cnt), color(col) {} : enabled(enabled), lenght(lenght), delay(delay), counter(lenght), color(color) {}
// Actualiza
void update() { (enabled && counter > 0) ? counter-- : enabled = false; }
// Indica si se pude dibujar
bool isRendarable() { return enabled && counter < lenght - delay; }
}; };
struct ShakeEffect struct ShakeEffect
@@ -82,11 +89,14 @@ private:
// Actualiza la logica para agitar la pantalla // Actualiza la logica para agitar la pantalla
void updateShakeEffect(); void updateShakeEffect();
// Actualiza y dibuja el efecto de flash en la pantalla // Dibuja el efecto de flash en la pantalla
void doFlash(); void renderFlash();
// Actualiza el efecto de flash
void updateFlash();
// Atenua la pantalla // Atenua la pantalla
void doAttenuate(); void renderAttenuate();
// Calcula los frames por segundo // Calcula los frames por segundo
void updateFPS(); void updateFPS();
@@ -97,6 +107,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
@@ -125,7 +141,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);
@@ -152,7 +168,7 @@ public:
void shake(); void shake();
// Pone la pantalla de color // Pone la pantalla de color
void flash(Color color, int lenght); void flash(Color color, int lenght, int delay = 0);
// Activa / desactiva los shaders // Activa / desactiva los shaders
void toggleShaders(); void toggleShaders();

View File

@@ -5,28 +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,
QUIT = 8, CREDITS,
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,
NONE = 7, QUIT_FROM_EVENT,
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)
@@ -19,31 +20,7 @@ Sprite::Sprite(std::shared_ptr<Texture> texture)
// Muestra el sprite por pantalla // Muestra el sprite por pantalla
void Sprite::render() void Sprite::render()
{ {
texture_->render(pos_.x, pos_.y, &sprite_clip_); texture_->render(pos_.x, pos_.y, &sprite_clip_, zoom_, zoom_);
}
// Obten el valor de la variable
int Sprite::getX() const
{
return pos_.x;
}
// Obten el valor de la variable
int Sprite::getY() const
{
return pos_.y;
}
// Obten el valor de la variable
int Sprite::getWidth() const
{
return pos_.w;
}
// Obten el valor de la variable
int Sprite::getHeight() const
{
return pos_.h;
} }
// Establece la posición del objeto // Establece la posición del objeto
@@ -60,84 +37,6 @@ void Sprite::setPosition(SDL_Point p)
pos_.y = p.y; pos_.y = p.y;
} }
// Establece la posición del objeto
void Sprite::setPosition(SDL_Rect r)
{
pos_ = r;
}
// Establece el valor de la variable
void Sprite::setX(int x)
{
pos_.x = x;
}
// Establece el valor de la variable
void Sprite::setY(int y)
{
pos_.y = y;
}
// Establece el valor de la variable
void Sprite::setWidth(int w)
{
pos_.w = w;
}
// Establece el valor de la variable
void Sprite::setHeight(int h)
{
pos_.h = h;
}
// Obten el valor de la variable
SDL_Rect Sprite::getSpriteClip() const
{
return sprite_clip_;
}
// Establece el valor de la variable
void Sprite::setSpriteClip(SDL_Rect rect)
{
sprite_clip_ = rect;
}
// Establece el valor de la variable
void Sprite::setSpriteClip(int x, int y, int w, int h)
{
sprite_clip_ = (SDL_Rect){x, y, w, h};
}
// Obten el valor de la variable
std::shared_ptr<Texture> Sprite::getTexture() const
{
return texture_;
}
// Establece el valor de la variable
void Sprite::setTexture(std::shared_ptr<Texture> texture)
{
texture_ = texture;
}
// Devuelve el rectangulo donde está el sprite
SDL_Rect Sprite::getPosition() const
{
return pos_;
}
// Incrementa el valor de la variable
void Sprite::incX(int value)
{
pos_.x += value;
}
// Incrementa el valor de la variable
void Sprite::incY(int value)
{
pos_.y += value;
}
// Reinicia las variables a cero // Reinicia las variables a cero
void Sprite::clear() void Sprite::clear()
{ {

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
@@ -12,6 +12,7 @@ protected:
std::shared_ptr<Texture> texture_; // Textura donde estan todos los dibujos del sprite std::shared_ptr<Texture> texture_; // Textura donde estan todos los dibujos del sprite
SDL_Rect pos_; // Posición y tamaño donde dibujar el sprite SDL_Rect pos_; // Posición y tamaño donde dibujar el sprite
SDL_Rect sprite_clip_; // Rectangulo de origen de la textura que se dibujará en pantalla SDL_Rect sprite_clip_; // Rectangulo de origen de la textura que se dibujará en pantalla
double zoom_ = 1.0f; // Zoom aplicado a la textura
public: public:
// Constructor // Constructor
@@ -28,40 +29,43 @@ public:
// Reinicia las variables a cero // Reinicia las variables a cero
virtual void clear(); virtual void clear();
// Obten el valor de la variable // Obtiene la posición y el tamaño
int getX() const; int getX() const { return pos_.x; }
int getY() const; int getY() const { return pos_.y; }
int getWidth() const; int getWidth() const { return pos_.w; }
int getHeight() const; int getHeight() const { return pos_.h; }
// Devuelve el rectangulo donde está el sprite // Devuelve el rectangulo donde está el sprite
SDL_Rect getPosition() const; SDL_Rect getPosition() const { return pos_; }
// Establece el valor de la variable // Establece la posición y el tamaño
void setX(int x); void setX(int x) { pos_.x = x; }
void setY(int y); void setY(int y) { pos_.y = y; }
void setWidth(int w); void setWidth(int w) { pos_.w = w; }
void setHeight(int h); void setHeight(int h) { pos_.h = h; }
// Establece la posición del objeto // Establece la posición del objeto
void setPosition(int x, int y); void setPosition(int x, int y);
void setPosition(SDL_Point p); void setPosition(SDL_Point p);
void setPosition(SDL_Rect r); void setPosition(SDL_Rect r) { pos_ = r; }
// Incrementa el valor de la variable // Establece el nivel de zoom
void incX(int value); void setZoom(float zoom) { zoom_ = zoom; }
void incY(int value);
// Obten el valor de la variable // Aumenta o disminuye la posición
SDL_Rect getSpriteClip() const; void incX(int value) { pos_.x += value; }
void incY(int value) { pos_.y += value; }
// Establece el valor de la variable // Obtiene el rectangulo que se dibuja de la textura
void setSpriteClip(SDL_Rect rect); SDL_Rect getSpriteClip() const { return sprite_clip_; }
void setSpriteClip(int x, int y, int w, int h);
// Obten el valor de la variable // Establece el rectangulo que se dibuja de la textura
std::shared_ptr<Texture> getTexture() const; void setSpriteClip(SDL_Rect rect) { sprite_clip_ = rect; }
void setSpriteClip(int x, int y, int w, int h) { sprite_clip_ = (SDL_Rect){x, y, w, h}; }
// Establece el valor de la variable // Obtiene un puntero a la textura
void setTexture(std::shared_ptr<Texture> texture); std::shared_ptr<Texture> getTexture() const { return texture_; }
// Establece la textura a utilizar
void setTexture(std::shared_ptr<Texture> texture) { texture_ = texture; }
}; };

View File

@@ -1,13 +1,15 @@
#include "stage.h" #include "stage.h"
#include <vector> #include <algorithm> // Para min
#include <vector> // Para vector
namespace Stage namespace Stage
{ {
std::vector<Stage> stages; // Variable con los datos de cada pantalla std::vector<Stage> stages; // Variable con los datos de cada pantalla
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)); }
@@ -15,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,7 +37,10 @@ namespace Stage
// Añade poder // Añade poder
void addPower(int amount) void addPower(int amount)
{ {
power += amount; if (power_can_be_added)
total_power += amount; {
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);

148
source/tabe.cpp Normal file
View File

@@ -0,0 +1,148 @@
// IWYU pragma: no_include <bits/std_abs.h>
#include "tabe.h"
#include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL, SDL_FLIP_NONE
#include <stdlib.h> // Para rand, abs
#include "jail_audio.h" // Para JA_PlaySound
#include "param.h" // Para Param, ParamGame, param
#include "resource.h" // Para Resource
#include "utils.h" // Para Zone
// Constructor
Tabe::Tabe()
: sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("tabe.png"), Resource::get()->getAnimation("tabe.ani"))) {}
// Actualiza la lógica
void Tabe::update()
{
if (enabled_)
{
sprite_->update();
move();
}
}
// Dibuja el objeto
void Tabe::render()
{
if (enabled_)
{
sprite_->render();
}
}
// Mueve el objeto
void Tabe::move()
{
const int x = static_cast<int>(x_);
speed_ += accel_;
x_ += speed_;
fly_distance_ -= std::abs(x - static_cast<int>(x_));
// Comprueba si sale por los bordes
const float min_x = param.game.game_area.rect.x - WIDTH_;
const float max_x = param.game.game_area.rect.x + param.game.game_area.rect.w;
switch (destiny_)
{
case TabeDirection::TO_THE_LEFT:
{
if (x_ < min_x)
{
enabled_ = false;
}
if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_ && direction_ == TabeDirection::TO_THE_RIGHT)
{
setRandomFlyPath(TabeDirection::TO_THE_LEFT, 80);
x_ = param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_;
}
break;
}
case TabeDirection::TO_THE_RIGHT:
{
if (x_ > max_x)
{
enabled_ = false;
}
if (x_ < param.game.game_area.rect.x && direction_ == TabeDirection::TO_THE_LEFT)
{
setRandomFlyPath(TabeDirection::TO_THE_RIGHT, 80);
x_ = param.game.game_area.rect.x;
}
break;
}
default:
break;
}
if (fly_distance_ <= 0)
{
if (waiting_counter_ > 0)
{
accel_ = speed_ = 0.0f;
--waiting_counter_;
}
else
{
constexpr int CHOICES = 4;
const TabeDirection left[CHOICES] = {TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_RIGHT};
const TabeDirection right[CHOICES] = {TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_RIGHT, TabeDirection::TO_THE_RIGHT, TabeDirection::TO_THE_RIGHT};
const TabeDirection direction = destiny_ == TabeDirection::TO_THE_LEFT ? left[rand() % CHOICES] : right[rand() % CHOICES];
setRandomFlyPath(direction, 20 + rand() % 40);
}
}
shiftSprite();
}
// Habilita el objeto
void Tabe::enable()
{
if (!enabled_)
{
enabled_ = true;
y_ = 20.0f;
// Establece una dirección aleatoria
destiny_ = direction_ = rand() % 2 == 0 ? TabeDirection::TO_THE_LEFT : TabeDirection::TO_THE_RIGHT;
// Establece la posición inicial
x_ = (direction_ == TabeDirection::TO_THE_LEFT) ? param.game.game_area.rect.x + param.game.game_area.rect.w : param.game.game_area.rect.x - WIDTH_;
// Crea una ruta de vuelo
setRandomFlyPath(direction_, 60);
shiftSprite();
}
}
// Establece un vuelo aleatorio
void Tabe::setRandomFlyPath(TabeDirection direction, int lenght)
{
direction_ = direction;
fly_distance_ = lenght;
waiting_counter_ = 5 + rand() % 15;
JA_PlaySound(Resource::get()->getSound("tabe.wav"));
constexpr float SPEED = 2.0f;
switch (direction)
{
case TabeDirection::TO_THE_LEFT:
{
speed_ = -1.0f * SPEED;
accel_ = -1.0f * (1 + rand() % 10) / 30.0f;
sprite_->setFlip(SDL_FLIP_NONE);
break;
}
case TabeDirection::TO_THE_RIGHT:
{
speed_ = SPEED;
accel_ = (1 + rand() % 10) / 30.0f;
sprite_->setFlip(SDL_FLIP_HORIZONTAL);
break;
}
default:
break;
}
}

58
source/tabe.h Normal file
View File

@@ -0,0 +1,58 @@
#pragma once
#include "animated_sprite.h"
#include <memory>
enum class TabeDirection : int
{
TO_THE_LEFT = 0,
TO_THE_RIGHT = 1,
};
// Clase Tabe
class Tabe
{
private:
// Constantes
static constexpr int WIDTH_ = 32;
static constexpr int HEIGHT_ = 32;
// Punteros
std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los graficos y animaciones
// Variables
float x_ = 0; // Posición del objeto
float y_ = 0; // Posición del objeto
float speed_ = 0.0f; // Velocidad de movimiento del objeto
float accel_ = 0.0f; // Aceleración del objeto
int fly_distance_ = 0; // Distancia de vuelo
int waiting_counter_ = 0; // Tiempo que pasa quieto el objeto
bool enabled_ = false; // Indica si el objeto está activo
TabeDirection direction_; // Dirección del objeto
TabeDirection destiny_; // Destino del objeto
// Mueve el objeto
void move();
// Actualiza la posición del sprite
void shiftSprite() { sprite_->setPos(x_, y_); }
// Establece un vuelo aleatorio
void setRandomFlyPath(TabeDirection direction, int lenght);
public:
// Constructor
Tabe();
// Destructor
~Tabe() = default;
// Actualiza la lógica
void update();
// Dibuja el objeto
void render();
// Habilita el objeto
void enable();
};

View File

@@ -161,12 +161,14 @@ std::shared_ptr<Texture> Text::writeToTexture(const std::string &text, int zoom,
auto texture = std::make_shared<Texture>(renderer); auto texture = std::make_shared<Texture>(renderer);
auto width = lenght(text, kerning) * zoom; auto width = lenght(text, kerning) * zoom;
auto height = box_height_ * zoom; auto height = box_height_ * zoom;
auto temp = SDL_GetRenderTarget(renderer);
texture->createBlank(width, height, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET); texture->createBlank(width, height, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET);
texture->setBlendMode(SDL_BLENDMODE_BLEND); texture->setBlendMode(SDL_BLENDMODE_BLEND);
texture->setAsRenderTarget(renderer); texture->setAsRenderTarget(renderer);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
zoom == 1 ? write(0, 0, text, kerning) : write2X(0, 0, text, kerning); zoom == 1 ? write(0, 0, text, kerning) : write2X(0, 0, text, kerning);
SDL_SetRenderTarget(renderer, temp);
return texture; return texture;
} }
@@ -264,4 +266,13 @@ void Text::reLoadTexture()
void Text::setFixedWidth(bool value) void Text::setFixedWidth(bool value)
{ {
fixed_width_ = value; fixed_width_ = value;
}
// Establece una paleta
void Text::setPalette(int number)
{
auto temp = SDL_GetRenderTarget(Screen::get()->getRenderer());
SDL_SetRenderTarget(Screen::get()->getRenderer(), nullptr);
sprite_->getTexture()->setPalette(number);
SDL_SetRenderTarget(Screen::get()->getRenderer(), temp);
} }

View File

@@ -78,4 +78,7 @@ public:
// Establece si se usa un tamaño fijo de letra // Establece si se usa un tamaño fijo de letra
void setFixedWidth(bool value); void setFixedWidth(bool value);
// Establece una paleta
void setPalette(int number);
}; };

View File

@@ -190,8 +190,16 @@ void Texture::render(int x, int y, SDL_Rect *clip, float zoomW, float zoomH, dou
renderQuad.h = clip->h; renderQuad.h = clip->h;
} }
renderQuad.w = renderQuad.w * zoomW; // Calcula el zoom y las coordenadas
renderQuad.h = renderQuad.h * zoomH; if (zoomH != 1.0f || zoomW != 1.0f)
{
renderQuad.x = renderQuad.x + (renderQuad.w / 2);
renderQuad.y = renderQuad.y + (renderQuad.h / 2);
renderQuad.w = renderQuad.w * zoomW;
renderQuad.h = renderQuad.h * zoomH;
renderQuad.x = renderQuad.x - (renderQuad.w / 2);
renderQuad.y = renderQuad.y - (renderQuad.h / 2);
}
// Renderiza a pantalla // Renderiza a pantalla
SDL_RenderCopyEx(renderer_, texture_, clip, &renderQuad, angle, center, flip); SDL_RenderCopyEx(renderer_, texture_, clip, &renderQuad, angle, center, flip);

View File

@@ -1,7 +1,6 @@
#include "title.h" #include "title.h"
#include <SDL2/SDL_events.h> // Para SDL_PollEvent, SDL_Event, SDL_KEYDOWN #include <SDL2/SDL_events.h> // Para SDL_PollEvent, SDL_Event, SDL_KEYDOWN
#include <SDL2/SDL_keycode.h> // Para SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5 #include <SDL2/SDL_keycode.h> // Para SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_5
#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 <stddef.h> // Para size_t #include <stddef.h> // Para size_t
#include <string> // Para char_traits, operator+, basic_string #include <string> // Para char_traits, operator+, basic_string
@@ -9,16 +8,17 @@
#include "define_buttons.h" // Para DefineButtons #include "define_buttons.h" // Para DefineButtons
#include "fade.h" // Para Fade, FadeType #include "fade.h" // Para Fade, FadeType
#include "game_logo.h" // Para GameLogo #include "game_logo.h" // Para GameLogo
#include "global_inputs.h" // Para check #include "global_inputs.h" // Para check, update
#include "input.h" // Para Input, InputType, INPUT_DO_NOT_ALLOW_R... #include "input.h" // Para Input, InputType, INPUT_DO_NOT_ALLOW_R...
#include "jail_audio.h" // Para JA_GetMusicState, JA_Music_state, JA_P... #include "jail_audio.h" // Para JA_GetMusicState, JA_FadeOutMusic, JA_...
#include "lang.h" // Para getText #include "lang.h" // Para getText
#include "mouse.h" // Para handleEvent
#include "notifier.h" // Para Notifier #include "notifier.h" // Para Notifier
#include "options.h" // Para OptionsController, Options, options #include "options.h" // Para OptionsController, Options, options
#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 "screen.h" // Para Screen
#include "section.h" // Para Options, options, Name, name, AttractMode #include "section.h" // Para Options, Name, name, AttractMode, options
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "text.h" // Para TEXT_CENTER, TEXT_SHADOW, Text #include "text.h" // Para TEXT_CENTER, TEXT_SHADOW, Text
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
@@ -29,18 +29,19 @@
Title::Title() Title::Title()
: text_(Resource::get()->getText("smb2")), : text_(Resource::get()->getText("smb2")),
fade_(std::make_unique<Fade>()), fade_(std::make_unique<Fade>()),
tiled_bg_(std::make_unique<TiledBG>((SDL_Rect){0, 0, param.game.width, param.game.height}, TiledBGMode::RANDOM)), tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::RANDOM)),
game_logo_(std::make_unique<GameLogo>(param.game.game_area.center_x, param.title.title_c_c_position)), game_logo_(std::make_unique<GameLogo>(param.game.game_area.center_x, param.title.title_c_c_position)),
mini_logo_texture_(Resource::get()->getTexture("logo_jailgames_mini.png")), mini_logo_sprite_(std::make_unique<Sprite>(Resource::get()->getTexture("logo_jailgames_mini.png"))),
mini_logo_sprite_(std::make_unique<Sprite>(mini_logo_texture_, param.game.game_area.center_x - mini_logo_texture_->getWidth() / 2, 0, mini_logo_texture_->getWidth(), mini_logo_texture_->getHeight())),
define_buttons_(std::make_unique<DefineButtons>()), define_buttons_(std::make_unique<DefineButtons>()),
num_controllers_(Input::get()->getNumControllers()) num_controllers_(Input::get()->getNumControllers()),
state_(TitleState::LOGO_ANIMATING)
{ {
// Configura objetos // Configura objetos
game_logo_->enable(); game_logo_->enable();
mini_logo_sprite_->setX(param.game.game_area.center_x - mini_logo_sprite_->getWidth() / 2);
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::RANDOM_SQUARE); fade_->setType(FadeType::RANDOM_SQUARE);
fade_->setPost(param.fade.post_duration); fade_->setPostDuration(param.fade.post_duration);
Resource::get()->getTexture("smb2.gif")->setPalette(1); Resource::get()->getTexture("smb2.gif")->setPalette(1);
// Asigna valores a otras variables // Asigna valores a otras variables
@@ -54,6 +55,7 @@ Title::Title()
Title::~Title() Title::~Title()
{ {
Resource::get()->getTexture("smb2.gif")->setPalette(0); Resource::get()->getTexture("smb2.gif")->setPalette(0);
JA_StopChannel(-1);
} }
// Actualiza las variables del objeto // Actualiza las variables del objeto
@@ -69,34 +71,40 @@ void Title::update()
// Actualiza el objeto screen // Actualiza el objeto screen
Screen::get()->update(); Screen::get()->update();
// Comprueba el fade_ y si se ha acabado // Actualiza las variables de globalInputs
globalInputs::update();
// Comprueba el fundido
fade_->update(); fade_->update();
if (fade_->hasEnded()) if (fade_->hasEnded())
{ {
if (post_fade_ == -1) if (selection_ == section::Options::TITLE_TIME_OUT)
{ {
// El menu ha hecho time out
section::name = next_section_; section::name = next_section_;
} }
else else
{ {
// Se ha pulsado para jugar
section::name = section::Name::GAME; section::name = section::Name::GAME;
section::options = post_fade_ == 1 ? section::Options::GAME_PLAY_1P : section::Options::GAME_PLAY_2P; section::options = selection_;
JA_StopMusic(); JA_StopMusic();
} }
} }
// Sección 1 - Titulo animandose // Establece la lógica según el estado
if (section::options == section::Options::TITLE_1) switch (state_)
{
case TitleState::LOGO_ANIMATING:
{ {
game_logo_->update(); game_logo_->update();
if (game_logo_->hasFinished()) if (game_logo_->hasFinished())
{ {
section::options = section::Options::TITLE_2; state_ = TitleState::LOGO_FINISHED;
} }
break;
} }
case TitleState::LOGO_FINISHED:
// Sección 2 - La pantalla con el titulo, el fondo animado y la música
else if (section::options == section::Options::TITLE_2)
{ {
// El contador solo sube si no estamos definiendo botones // El contador solo sube si no estamos definiendo botones
counter_ = define_buttons_->isEnabled() ? 0 : counter_ + 1; counter_ = define_buttons_->isEnabled() ? 0 : counter_ + 1;
@@ -115,9 +123,32 @@ void Title::update()
if (counter_ == param.title.title_duration) if (counter_ == param.title.title_duration)
{ {
// El menu ha hecho time out
fade_->setPostDuration(0);
fade_->activate(); fade_->activate();
post_fade_ = -1; selection_ = section::Options::TITLE_TIME_OUT;
} }
break;
}
case TitleState::START_HAS_BEEN_PRESSED:
{
// Actualiza el logo con el título del juego
game_logo_->update();
// Actualiza el mosaico de fondo
tiled_bg_->update();
if (counter_ == 100)
{
fade_->activate();
}
++counter_;
break;
}
default:
break;
} }
} }
} }
@@ -137,16 +168,10 @@ void Title::render()
// Dibuja el logo con el título del juego // Dibuja el logo con el título del juego
game_logo_->render(); game_logo_->render();
if (section::options == section::Options::TITLE_2) constexpr Color shadow = Color(0x14, 0x87, 0xc4);
if (state_ != TitleState::LOGO_ANIMATING)
{ {
constexpr Color shadow = Color(0x14, 0x87, 0xc4);
// 'PRESS TO PLAY'
if (counter_ % 50 > 14 && !define_buttons_->isEnabled())
{
text_->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, param.title.press_start_position, lang::getText(23), 1, no_color, 1, shadow);
}
// Mini logo // Mini logo
const int pos1 = (param.game.height / 5 * 4) + BLOCK; const int pos1 = (param.game.height / 5 * 4) + BLOCK;
const int pos2 = pos1 + mini_logo_sprite_->getHeight() + 3; const int pos2 = pos1 + mini_logo_sprite_->getHeight() + 3;
@@ -157,6 +182,24 @@ void Title::render()
text_->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, pos2, TEXT_COPYRIGHT, 1, no_color, 1, shadow); text_->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, pos2, TEXT_COPYRIGHT, 1, no_color, 1, shadow);
} }
if (state_ == TitleState::LOGO_FINISHED)
{
// 'PRESS TO PLAY'
if (counter_ % 50 > 14 && !define_buttons_->isEnabled())
{
text_->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, param.title.press_start_position, lang::getText(23), 1, no_color, 1, shadow);
}
}
if (state_ == TitleState::START_HAS_BEEN_PRESSED)
{
// 'PRESS TO PLAY'
if (counter_ % 10 > 4 && !define_buttons_->isEnabled())
{
text_->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, param.title.press_start_position, lang::getText(23), 1, no_color, 1, shadow);
}
}
// Define Buttons // Define Buttons
define_buttons_->render(); define_buttons_->render();
@@ -164,7 +207,7 @@ void Title::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();
} }
// Comprueba los eventos // Comprueba los eventos
@@ -231,6 +274,9 @@ void Title::checkEvents()
break; break;
} }
} }
// Comprueba el cursor
Mouse::handleEvent(event);
} }
} }
} }
@@ -238,24 +284,39 @@ void Title::checkEvents()
// Comprueba las entradas // Comprueba las entradas
void Title::checkInput() void Title::checkInput()
{ {
// Comprueba los controladores solo si no se estan definiendo los botones // Comprueba las entradas solo si no se estan definiendo los botones
if (!define_buttons_->isEnabled()) if (!define_buttons_->isEnabled())
{ {
// Comprueba los métodos de control // Comprueba todos los métodos de control
for (const auto &controller : options.controllers) for (const auto &controller : options.controllers)
{ {
// START
if (Input::get()->checkInput(InputType::START, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index) && if (Input::get()->checkInput(InputType::START, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index) &&
!Input::get()->checkInput(InputType::SERVICE, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index)) !Input::get()->checkInput(InputType::SERVICE, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index))
{ {
if (section::options == section::Options::TITLE_2 || ALLOW_TITLE_ANIMATION_SKIP) if ((state_ == TitleState::LOGO_FINISHED || ALLOW_TITLE_ANIMATION_SKIP) && !fade_->isEnabled())
{ {
fade_->activate(); JA_PlaySound(Resource::get()->getSound("game_start.wav"));
post_fade_ = controller.player_id; JA_FadeOutMusic(1500);
switch (controller.player_id)
{
case 1:
selection_ = section::Options::GAME_PLAY_1P;
break;
case 2:
selection_ = section::Options::GAME_PLAY_2P;
break;
default:
selection_ = section::Options::TITLE_TIME_OUT;
break;
}
state_ = TitleState::START_HAS_BEEN_PRESSED;
counter_ = 0;
return; return;
} }
} }
// Comprueba si se va a intercambiar la asignación de mandos a jugadores // SWAP_CONTROLLERS
if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, controller.type, controller.index) && if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, controller.type, controller.index) &&
Input::get()->checkInput(InputType::SWAP_CONTROLLERS, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index)) Input::get()->checkInput(InputType::SWAP_CONTROLLERS, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index))
{ {
@@ -263,7 +324,7 @@ void Title::checkInput()
return; return;
} }
// Comprueba si algun mando quiere ser configurado // CONFIG
if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, controller.type, controller.index) && if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, controller.type, controller.index) &&
Input::get()->checkInput(InputType::CONFIG, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index)) Input::get()->checkInput(InputType::CONFIG, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index))
{ {
@@ -342,7 +403,6 @@ void Title::showControllers()
} }
} }
// std::string spaces(lang::getText(100).length() + 3, ' '); // Muestra la notificación
// std::string kb_text = spaces + lang::getText(69);
Notifier::get()->showText({text.at(0), text.at(1)}); Notifier::get()->showText({text.at(0), text.at(1)});
} }

View File

@@ -2,23 +2,19 @@
#include <SDL2/SDL_stdinc.h> // Para Uint32 #include <SDL2/SDL_stdinc.h> // Para Uint32
#include <memory> // Para unique_ptr, shared_ptr #include <memory> // Para unique_ptr, shared_ptr
class DefineButtons; // lines 6-6 #include "section.h" // Para Options
class Fade; // lines 7-7 class DefineButtons; // lines 5-5
class GameLogo; // lines 8-8 class Fade; // lines 6-6
class Sprite; // lines 9-9 class GameLogo; // lines 7-7
class Text; // lines 10-10 class Sprite; // lines 8-8
class Texture; // lines 11-11 class Text; // lines 9-9
class TiledBG; // lines 12-12 class TiledBG; // lines 11-11
namespace section
{
enum class Name;
}
// Textos // Textos
constexpr const char TEXT_COPYRIGHT[] = "@2020,2024 JailDesigner"; constexpr const char TEXT_COPYRIGHT[] = "@2020,2025 JailDesigner";
// Parámetros // Parámetros
constexpr bool ALLOW_TITLE_ANIMATION_SKIP = true; constexpr bool ALLOW_TITLE_ANIMATION_SKIP = false;
/* /*
Esta clase gestiona un estado del programa. Se encarga de la parte del titulo o menu Esta clase gestiona un estado del programa. Se encarga de la parte del titulo o menu
@@ -27,9 +23,10 @@ constexpr bool ALLOW_TITLE_ANIMATION_SKIP = true;
- Dibujar el tileado de fondo - Dibujar el tileado de fondo
- Redifinir los botones de los mandos de juego - Redifinir los botones de los mandos de juego
Esta clase tiene dos estados: Esta clase tiene tres estados:
- El titulo está animandose, con el fondo estático - El titulo está animandose, con el fondo estático
- El titulo ya está en su sitio y el fondo se está animando - El titulo ya está en su sitio y el fondo se está animando
- Se ha pulsado el botón de start
Por razones de diseño, no se permite saltarse la animación del titulo, aunque es Por razones de diseño, no se permite saltarse la animación del titulo, aunque es
configurable mediante un define configurable mediante un define
@@ -39,21 +36,29 @@ constexpr bool ALLOW_TITLE_ANIMATION_SKIP = true;
class Title class Title
{ {
private: private:
// Enumeraciones
enum class TitleState
{
LOGO_ANIMATING,
LOGO_FINISHED,
START_HAS_BEEN_PRESSED,
};
// Objetos y punteros // Objetos y punteros
std::shared_ptr<Text> text_; // Objeto de texto para poder escribir textos en pantalla std::shared_ptr<Text> text_; // Objeto de texto para poder escribir textos en pantalla
std::unique_ptr<Fade> fade_; // Objeto para realizar fundidos en pantalla std::unique_ptr<Fade> fade_; // Objeto para realizar fundidos en pantalla
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<GameLogo> game_logo_; // Objeto para dibujar el logo con el título del juego std::unique_ptr<GameLogo> game_logo_; // Objeto para dibujar el logo con el título del juego
std::shared_ptr<Texture> mini_logo_texture_; // Textura con el logo de JailGames mini
std::unique_ptr<Sprite> mini_logo_sprite_; // Sprite con el logo de JailGames mini std::unique_ptr<Sprite> mini_logo_sprite_; // Sprite con el logo de JailGames mini
std::unique_ptr<DefineButtons> define_buttons_; // Objeto para definir los botones del joystic std::unique_ptr<DefineButtons> define_buttons_; // Objeto para definir los botones del joystic
// Variable // Variable
int counter_ = 0; // Temporizador para la pantalla de titulo int counter_ = 0; // Temporizador para la pantalla de titulo
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
section::Name next_section_; // Indica cual es la siguiente sección a cargar cuando termine el contador del titulo section::Name next_section_; // Indica cual es la siguiente sección a cargar cuando termine el contador del titulo
int post_fade_ = 0; // Opción a realizar cuando termina el fundido section::Options selection_ = section::Options::TITLE_TIME_OUT; // Opción elegida en el titulo
int num_controllers_; // Número de mandos conectados int num_controllers_; // Número de mandos conectados
TitleState state_; // Estado en el que se encuentra la sección
// Actualiza las variables del objeto // Actualiza las variables del objeto
void update(); void update();