46 Commits

Author SHA1 Message Date
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
71 changed files with 2415 additions and 822 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 := 2024-12-31
# 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

@@ -28,6 +28,12 @@ Les tecles son les següents:
- **Tecla F4**: Activa o desactiva els shaders - **Tecla F4**: Activa o desactiva els shaders
- **Tecla F5**: Activa o desactiva l'audio
- **Tecla F6**: Activa o desactiva el dispar automàtic
- **Tecla F7**: Canvia el idioma del joc i reinicia
- **Tecla F10**: Reset - **Tecla F10**: Reset
<p align="center"> <p align="center">

View File

@@ -14,7 +14,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

@@ -14,7 +14,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

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;

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.

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

@@ -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));
} }
@@ -105,6 +111,7 @@ void Balloon::render()
SDL_Point p = {24, 24}; SDL_Point p = {24, 24};
sprite_->setRotatingCenter(&p); sprite_->setRotatingCenter(&p);
sprite_->render(); sprite_->render();
// Añade la máscara del borde y los reflejos // Añade la máscara del borde y los reflejos
auto sp = std::make_unique<Sprite>(sprite_->getTexture(), sprite_->getPosition()); auto sp = std::make_unique<Sprite>(sprite_->getTexture(), sprite_->getPosition());
sp->setSpriteClip(BALLOON_SIZE[4], 0, BALLOON_SIZE[4], BALLOON_SIZE[4]); sp->setSpriteClip(BALLOON_SIZE[4], 0, BALLOON_SIZE[4], BALLOON_SIZE[4]);
@@ -122,18 +129,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 +146,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
@@ -170,21 +168,35 @@ void Balloon::move()
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 de la zona de juego excepto para la PowerBall
if (type_ != BalloonType::POWERBALL) /*if (type_ != BalloonType::POWERBALL)
{ {
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)
{ {
y_ = min_y; y_ = min_y;
vy_ = -vy_; vy_ = -vy_;
enableBounce(); enableBounce();
} }
}*/
// Colisión en la parte superior solo si el globo va de subida
if (vy_ < 0)
{
const int min_y = play_area_.y;
if (y_ < min_y)
{
playSound();
y_ = min_y;
vy_ = -vy_;
enableBounce();
}
} }
// 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)
@@ -254,8 +266,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 +387,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 +409,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;
@@ -196,4 +214,5 @@ 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; }
}; };

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

@@ -119,6 +119,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 numEnemies = set.number_of_balloons;
for (int i = 0; i < numEnemies; ++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 numEnemies = set.number_of_balloons;
for (int i = 0; i < numEnemies; ++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()
{ {
@@ -150,7 +174,7 @@ int BalloonManager::calculateScreenPower()
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); const int index = static_cast<int>(size);
balloons_.emplace_back(std::make_shared<Balloon>(x, y, type, size, velx, speed, creation_timer, balloon_textures_.at(index), balloon_animations_.at(index))); balloons_.emplace_back(std::make_shared<Balloon>(x, y, type, size, velx, speed, creation_timer, play_area_, balloon_textures_.at(index), balloon_animations_.at(index)));
return balloons_.back(); return balloons_.back();
} }
@@ -188,7 +212,7 @@ void BalloonManager::createPowerBall()
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]));
power_ball_enabled_ = true; power_ball_enabled_ = true;
power_ball_counter_ = POWERBALL_COUNTER; power_ball_counter_ = POWERBALL_COUNTER;
@@ -279,7 +303,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,13 +363,7 @@ 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)
{
auto p = set.init[i];
createBalloon(p.x, p.y, p.type, p.size, p.vel_x, balloon_speed_, p.creation_counter);
}
} }
// Obtiene el nivel de ameza actual generado por los globos // Obtiene el nivel de ameza actual generado por los globos
@@ -353,4 +371,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,7 @@ 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
// Inicializa // Inicializa
void init(); void init();
@@ -49,9 +53,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();
@@ -103,6 +111,9 @@ public:
// 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_; }
@@ -110,4 +121,5 @@ public:
// 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; }
}; };

471
source/credits.cpp Normal file
View File

@@ -0,0 +1,471 @@
#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_rect.h> // Para SDL_Rect
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
#include <algorithm>
#include <cstdlib>
#include <string> // Para basic_string, string
#include <vector> // Para vector
#include "balloon_manager.h" // Para BalloonManager
#include "global_inputs.h" // Para check
#include "input.h" // Para Input
#include "jail_audio.h" // Para JA_PlayMusic, JA_StopMusic
#include "param.h" // Para Param, ParamGame, param
#include "resource.h" // Para Resource
#include "screen.h" // Para Screen
#include "section.h" // Para Name, name, Options, options
#include "text.h" // Para Text, TEXT_CENTER, TEXT_SHADOW
#include "tiled_bg.h" // Para TiledBG, TiledBGMode
#include "utils.h" // Para Color, no_color, shdw_txt_color, Zone
#include "player.h"
#include "fade.h"
#include "lang.h"
// Textos
constexpr const char TEXT_COPYRIGHT[] = "@2020,2024 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)),
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;
//top_black_rect_ = {play_area_.x, 0, play_area_.w, black_bars_size_};
//bottom_black_rect_ = {play_area_.x, param.game.game_area.rect.h - black_bars_size_, play_area_.w, black_bars_size_};
balloon_manager_->setPlayArea(play_area_);
fade_in_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_in_->setType(FadeType::FULLSCREEN);
fade_in_->setPost(50);
fade_in_->setMode(FadeMode::IN);
fade_in_->activate();
fade_out_->setColor(0, 0, 0);
fade_out_->setType(FadeType::FULLSCREEN);
fade_out_->setPost(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_);
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()
{
if (SDL_GetTicks() - ticks_ > ticks_speed_)
{
ticks_ = SDL_GetTicks();
tiled_bg_->update();
balloon_manager_->update();
updateTextureDstRects();
throwBalloons();
for (auto &player : players_)
{
player->update();
}
updateAllFades();
Screen::get()->update();
globalInputs::update();
++counter_;
}
}
// Dibuja Credits::en patalla
void Credits::render()
{
// Prepara para empezar a dibujar en la textura de juego
Screen::get()->start();
// Limpia la pantalla
Screen::get()->clean();
// Dibuja el fondo, los globos y los jugadores
tiled_bg_->render();
balloon_manager_->render();
for (auto const &player : players_)
{
player->render();
}
// Dibuja los titulos de credito
SDL_RenderCopy(Screen::get()->getRenderer(), text_texture_, &credits_rect_src_, &credits_rect_dst_);
// Dibuja el mini_logo
SDL_RenderCopy(Screen::get()->getRenderer(), text_texture_, &mini_logo_rect_src_, &mini_logo_rect_dst_);
// Dibuja los rectangulos negros
SDL_SetRenderDrawColor(Screen::get()->getRenderer(), 0, 0, 0, 255);
SDL_RenderFillRect(Screen::get()->getRenderer(), &top_black_rect_);
SDL_RenderFillRect(Screen::get()->getRenderer(), &bottom_black_rect_);
SDL_RenderFillRect(Screen::get()->getRenderer(), &left_black_rect_);
SDL_RenderFillRect(Screen::get()->getRenderer(), &right_black_rect_);
// Si el mini_logo está en su destino, lo dibuja encima de lo anterior
if (mini_logo_on_position_)
{
SDL_RenderCopy(Screen::get()->getRenderer(), text_texture_, &mini_logo_rect_src_, &mini_logo_rect_dst_);
}
// Dibuja el fade sobre el resto de elementos
fade_in_->render();
fade_out_->render();
// Vuelca el contenido del renderizador en pantalla
Screen::get()->blit();
}
// 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 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;
ticks_speed_ = 1;
}
}
// 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;
}
// 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));
}

100
source/credits.h Normal file
View File

@@ -0,0 +1,100 @@
#pragma once
#include <SDL2/SDL_render.h> // Para SDL_Texture
#include <SDL2/SDL_stdinc.h> // Para Uint32
#include <memory> // Para unique_ptr
#include "param.h"
#include "options.h"
class BalloonManager;
class TiledBG;
class Player;
class Fade;
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
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 ticks_speed_ = 15; // Velocidad del bucle update
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();
// 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,7 +8,7 @@
#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 <chrono> // 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 <stdio.h> // Para printf, perror
#include <sys/stat.h> // Para mkdir, stat, S_IRWXU #include <sys/stat.h> // Para mkdir, stat, S_IRWXU
@@ -20,6 +21,7 @@
#include <string> // Para operator+, char_traits, allocator #include <string> // Para operator+, char_traits, allocator
#include <vector> // Para vector #include <vector> // Para vector
#include "asset.h" // Para Asset, AssetType #include "asset.h" // Para Asset, AssetType
#include "credits.h" // Para Credits
#include "dbgtxt.h" // Para dbg_init #include "dbgtxt.h" // Para dbg_init
#include "game.h" // Para Game, GAME_MODE_DEMO_OFF, GAME_... #include "game.h" // Para Game, GAME_MODE_DEMO_OFF, GAME_...
#include "global_inputs.h" // Para init #include "global_inputs.h" // Para init
@@ -45,13 +47,6 @@
#include <pwd.h> // para getpwuid, passwd #include <pwd.h> // para getpwuid, passwd
#endif #endif
// Inicia la semilla aleatoria
void initRand()
{
unsigned int seed = static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count());
std::srand(seed);
}
// Constructor // Constructor
Director::Director(int argc, const char *argv[]) Director::Director(int argc, const char *argv[])
{ {
@@ -60,7 +55,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 +68,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 +106,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 +122,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 +180,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 +296,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,8 +385,10 @@ 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/game_start.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/balloon.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/balloon.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bubble1.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/bubble1.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bubble2.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/bubble2.wav", AssetType::SOUND);
@@ -379,9 +405,16 @@ void Director::setFileList()
Asset::get()->add(prefix + "/data/sound/clock.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/clock.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/powerball.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/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/logo.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_coffee.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_power_up.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_no.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_get_ready.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/tabe.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);
@@ -630,6 +668,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 +691,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 +709,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 +732,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

@@ -100,6 +100,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
@@ -121,7 +123,6 @@ void Fade::update()
// 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_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,12 +134,12 @@ 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_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_)
{ {
@@ -156,9 +157,11 @@ void Fade::update()
// 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_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);
} }
@@ -166,11 +169,12 @@ void Fade::update()
// Deja el renderizador como estaba // Deja el renderizador como estaba
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);
} }
} }
else else
@@ -251,12 +255,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 +266,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 +289,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 +297,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 +310,14 @@ 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 (max == 0)
{
return 0;
}
return std::clamp(current * 100 / max, 0, 100);
} }

View File

@@ -45,6 +45,7 @@ private:
int fade_random_squares_mult_; // Cantidad de cuadrados que se pintaran cada vez int fade_random_squares_mult_; // Cantidad de cuadrados que se pintaran cada vez
int post_duration_; // Duración posterior del fade tras finalizar int post_duration_; // Duración posterior del fade tras finalizar
int post_counter_; // Contador para la duración posterior int post_counter_; // Contador para la duración posterior
int value_ = 0; // Estado actual del fade entre 0 y 100
// Inicializa las variables // Inicializa las variables
void init(); void init();
@@ -52,6 +53,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 +75,16 @@ 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 enabled_; }
bool hasEnded() const { return !enabled_ && finished_; }
// Setters
void setType(FadeType type) { type_ = type; }
void setMode(FadeMode mode) { mode_ = mode; }
void setPost(int value) { post_duration_ = value; }
}; };

View File

@@ -14,6 +14,7 @@
#include "balloon.h" // Para Balloon, BALLOON_SPEED #include "balloon.h" // Para Balloon, BALLOON_SPEED
#include "balloon_manager.h" // Para BalloonManager #include "balloon_manager.h" // Para BalloonManager
#include "bullet.h" // Para Bullet, BulletType, BulletMoveStatus #include "bullet.h" // Para Bullet, BulletType, BulletMoveStatus
#include "enter_name.h" // Para NAME_LENGHT
#include "fade.h" // Para Fade, FadeType #include "fade.h" // Para Fade, FadeType
#include "global_inputs.h" // Para check #include "global_inputs.h" // Para check
#include "input.h" // Para InputType, Input, INPUT_DO_NOT_ALL... #include "input.h" // Para InputType, Input, INPUT_DO_NOT_ALL...
@@ -30,9 +31,9 @@
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "section.h" // Para Name, name, Options, options #include "section.h" // Para Name, name, Options, options
#include "smart_sprite.h" // Para SmartSprite #include "smart_sprite.h" // Para SmartSprite
#include "stage.h" // Para get, number, Stage, power #include "stage.h" // Para number, get, Stage, power, total_p...
#include "tabe.h" // Para Tabe
#include "text.h" // Para Text #include "text.h" // Para Text
#include "dbgtxt.h" // Para dbg_print
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
struct JA_Sound_t; // lines 37-37 struct JA_Sound_t; // lines 37-37
@@ -44,8 +45,10 @@ Game::Game(int player_id, int current_stage, bool demo)
input_(Input::get()), input_(Input::get()),
background_(std::make_unique<Background>()), background_(std::make_unique<Background>()),
canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.play_area.rect.w, param.game.play_area.rect.h)), canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.play_area.rect.w, param.game.play_area.rect.h)),
fade_(std::make_unique<Fade>()), fade_in_(std::make_unique<Fade>()),
balloon_manager_(std::make_unique<BalloonManager>()) fade_out_(std::make_unique<Fade>()),
balloon_manager_(std::make_unique<BalloonManager>()),
tabe_(std::make_unique<Tabe>())
{ {
// Pasa variables // Pasa variables
demo_.enabled = demo; demo_.enabled = demo;
@@ -63,9 +66,15 @@ Game::Game(int player_id, int current_stage, bool demo)
Scoreboard::init(); Scoreboard::init();
scoreboard_ = Scoreboard::get(); scoreboard_ = Scoreboard::get();
fade_->setColor(fade_color.r, fade_color.g, fade_color.b); fade_in_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_->setPost(param.fade.post_duration); fade_in_->setPost(0);
fade_->setType(FadeType::VENETIAN); fade_in_->setType(FadeType::RANDOM_SQUARE);
fade_in_->setMode(FadeMode::IN);
fade_in_->activate();
fade_out_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_out_->setPost(param.fade.post_duration);
fade_out_->setType(FadeType::VENETIAN);
background_->setPos(param.game.play_area.rect); background_->setPos(param.game.play_area.rect);
@@ -87,24 +96,25 @@ Game::Game(int player_id, int current_stage, bool demo)
Stage::total_power += Stage::get(i).power_to_complete; Stage::total_power += Stage::get(i).power_to_complete;
} }
#endif #endif
// Crea los primeros globos y el mensaje de inicio
if (!demo_.enabled)
{
balloon_manager_->createTwoBigBalloons();
evaluateAndSetMenace();
createMessage({paths_.at(0), paths_.at(1)}, Resource::get()->getTexture("get_ready"));
}
} }
Game::~Game() Game::~Game()
{ {
// Guarda las puntuaciones en un fichero // MODO DEMO
if (!demo_.enabled) if (demo_.enabled)
{ {
// Habilita los sonidos
JA_EnableSound(true);
}
// MODO JUEGO
else
{
// Guarda las puntuaciones en un fichero
auto manager = std::make_unique<ManageHiScoreTable>(options.game.hi_score_table); auto manager = std::make_unique<ManageHiScoreTable>(options.game.hi_score_table);
manager->saveToFile(asset_->get("score.bin")); manager->saveToFile(asset_->get("score.bin"));
section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
} }
#ifdef RECORDING #ifdef RECORDING
saveDemoFile(Asset::get()->get("demo1.bin"), demo_.data.at(0)); saveDemoFile(Asset::get()->get("demo1.bin"), demo_.data.at(0));
#endif #endif
@@ -213,8 +223,8 @@ void Game::updatePlayers()
if (demo_.enabled && allPlayersAreNotPlaying()) if (demo_.enabled && allPlayersAreNotPlaying())
{ {
fade_->setType(FadeType::RANDOM_SQUARE); fade_out_->setType(FadeType::RANDOM_SQUARE);
fade_->activate(); fade_out_->activate();
} }
} }
@@ -253,7 +263,7 @@ void Game::updateStage()
++Stage::number; ++Stage::number;
JA_PlaySound(Resource::get()->getSound("stage_change.wav")); JA_PlaySound(Resource::get()->getSound("stage_change.wav"));
balloon_manager_->resetBalloonSpeed(); balloon_manager_->resetBalloonSpeed();
screen_->flash(flash_color, 100); screen_->flash(flash_color, 3);
screen_->shake(); screen_->shake();
// Escribe el texto por pantalla // Escribe el texto por pantalla
@@ -262,7 +272,7 @@ void Game::updateStage()
std::vector<Path> paths = {paths_.at(2), paths_.at(3)}; std::vector<Path> paths = {paths_.at(2), paths_.at(3)};
if (Stage::number == 9) if (Stage::number == 9)
{ {
createMessage(paths, Resource::get()->getTexture("last_stage")); createMessage(paths, Resource::get()->getTexture("game_text_last_stage"));
} }
else else
{ {
@@ -275,6 +285,27 @@ void Game::updateStage()
} }
} }
// Actualiza el estado de fade in
void Game::updateFadeInState()
{
if (state_ == GameState::FADE_IN)
{
if (fade_in_->hasEnded())
{
state_ = GameState::PLAYING;
// Crea los primeros globos y el mensaje de inicio
if (!demo_.enabled)
{
balloon_manager_->createTwoBigBalloons();
evaluateAndSetMenace();
createMessage({paths_.at(0), paths_.at(1)}, Resource::get()->getTexture("game_text_get_ready"));
JA_PlaySound(Resource::get()->getSound("voice_get_ready.wav"));
}
}
}
}
// Actualiza el estado de fin de la partida // Actualiza el estado de fin de la partida
void Game::updateGameOverState() void Game::updateGameOverState()
{ {
@@ -283,27 +314,32 @@ void Game::updateGameOverState()
if (game_over_counter_ > 0) if (game_over_counter_ > 0)
{ {
if (game_over_counter_ == GAME_OVER_COUNTER_) if (game_over_counter_ == GAME_OVER_COUNTER_)
createMessage({paths_.at(2), paths_.at(3)}, Resource::get()->getTexture("game_over")); {
createMessage({paths_.at(2), paths_.at(3)}, Resource::get()->getTexture("game_text_game_over"));
JA_FadeOutMusic(1000);
balloon_manager_->setSounds(true);
}
game_over_counter_--; game_over_counter_--;
if ((game_over_counter_ == 250) || (game_over_counter_ == 200) || (game_over_counter_ == 180) || (game_over_counter_ == 120) || (game_over_counter_ == 60))
{
// Hace sonar aleatoriamente uno de los 4 sonidos de burbujas
const auto index = rand() % 4;
JA_Sound_t *sound[4] = {Resource::get()->getSound("bubble1.wav"), Resource::get()->getSound("bubble2.wav"), Resource::get()->getSound("bubble3.wav"), Resource::get()->getSound("bubble4.wav")};
JA_PlaySound(sound[index], 0);
}
if (game_over_counter_ == 150) if (game_over_counter_ == 150)
{ {
fade_->activate(); fade_out_->activate();
} }
} }
if (fade_->hasEnded()) if (fade_out_->hasEnded())
{ {
section::name = section::Name::HI_SCORE_TABLE; if (game_completed_counter_ > 0)
{
// Los jugadores han completado el juego
section::name = section::Name::CREDITS;
}
else
{
// La partida ha terminado con la derrota de los jugadores
section::name = section::Name::HI_SCORE_TABLE;
}
} }
} }
} }
@@ -327,8 +363,8 @@ void Game::updateCompletedState()
// Muestra el mensaje de felicitación y da los puntos a los jugadores // Muestra el mensaje de felicitación y da los puntos a los jugadores
if (game_completed_counter_ == 200) if (game_completed_counter_ == 200)
{ {
createMessage({paths_.at(4), paths_.at(5)}, Resource::get()->getTexture("congratulations")); createMessage({paths_.at(4), paths_.at(5)}, Resource::get()->getTexture("game_text_congratulations"));
createMessage({paths_.at(6), paths_.at(7)}, Resource::get()->getTexture("1000000_points")); createMessage({paths_.at(6), paths_.at(7)}, Resource::get()->getTexture("game_text_1000000_points"));
for (auto &player : players_) for (auto &player : players_)
if (player->isPlaying()) if (player->isPlaying())
@@ -465,6 +501,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
(item->getWidth() - game_text_textures_[4]->getWidth()) / 2; (item->getWidth() - game_text_textures_[4]->getWidth()) / 2;
createItemText(x, game_text_textures_[4]); createItemText(x, game_text_textures_[4]);
} }
JA_PlaySound(Resource::get()->getSound("voice_coffee.wav"));
break; break;
} }
case ItemType::COFFEE_MACHINE: case ItemType::COFFEE_MACHINE:
@@ -475,6 +512,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
item->getPosX() + item->getPosX() +
(item->getWidth() - game_text_textures_[3]->getWidth()) / 2; (item->getWidth() - game_text_textures_[3]->getWidth()) / 2;
createItemText(x, game_text_textures_[3]); createItemText(x, game_text_textures_[3]);
JA_PlaySound(Resource::get()->getSound("voice_power_up.wav"));
break; break;
} }
default: default:
@@ -713,7 +751,9 @@ void Game::createMessage(const std::vector<Path> &paths, std::shared_ptr<Texture
// Inicializa // Inicializa
for (const auto &path : paths) for (const auto &path : paths)
{
path_sprites_.back()->addPath(path, true); path_sprites_.back()->addPath(path, true);
}
path_sprites_.back()->enable(); path_sprites_.back()->enable();
} }
@@ -806,13 +846,12 @@ void Game::killPlayer(std::shared_ptr<Player> &player)
else else
{ {
// Si no tiene cafes, muere // Si no tiene cafes, muere
pauseMusic(); // pauseMusic();
balloon_manager_->stopAllBalloons(); balloon_manager_->stopAllBalloons();
JA_PlaySound(Resource::get()->getSound("player_collision.wav")); JA_PlaySound(Resource::get()->getSound("player_collision.wav"));
screen_->shake(); screen_->shake();
JA_PlaySound(Resource::get()->getSound("coffeeout.wav")); JA_PlaySound(Resource::get()->getSound("voice_no.wav"));
player->setPlayingState(PlayerState::DYING); player->setPlayingState(PlayerState::DYING);
allPlayersAreNotPlaying() ? stopMusic() : resumeMusic();
} }
} }
@@ -860,6 +899,7 @@ void Game::update()
checkMusicStatus(); checkMusicStatus();
screen_->update(); screen_->update();
globalInputs::update();
fillCanvas(); fillCanvas();
} }
} }
@@ -902,11 +942,10 @@ void Game::fillCanvas()
renderItems(); renderItems();
renderSmartSprites(); renderSmartSprites();
balloon_manager_->render(); balloon_manager_->render();
tabe_->render();
renderBullets(); renderBullets();
renderPathSprites(); renderPathSprites();
renderPlayers(); renderPlayers();
// dbg_print(0, 40, std::to_string(menace_current_).c_str(), 255, 0, 0);
// dbg_print(0, 50, std::to_string(menace_threshold_).c_str(), 255, 0, 0);
// Deja el renderizador apuntando donde estaba // Deja el renderizador apuntando donde estaba
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
@@ -925,7 +964,8 @@ void Game::render()
scoreboard_->render(); scoreboard_->render();
// Dibuja el fade // Dibuja el fade
fade_->render(); fade_in_->render();
fade_out_->render();
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
screen_->blit(); screen_->blit();
@@ -950,11 +990,11 @@ void Game::disableTimeStopItem()
// Comprueba si la música ha de estar sonando // Comprueba si la música ha de estar sonando
void Game::checkMusicStatus() void Game::checkMusicStatus()
{ {
// Si la música no está sonando // Si se ha completado el juego o los jugadores han terminado, detiene la música
if (JA_GetMusicState() == JA_MUSIC_INVALID || if (state_ != GameState::COMPLETED && !allPlayersAreGameOver())
JA_GetMusicState() == JA_MUSIC_STOPPED) {
// Si se ha completado el juego o los jugadores han terminado, detiene la música playMusic();
state_ == GameState::COMPLETED || allPlayersAreGameOver() ? JA_StopMusic() : JA_PlayMusic(Resource::get()->getMusic("playing.ogg")); }
} }
// Bucle para el juego // Bucle para el juego
@@ -979,7 +1019,7 @@ void Game::initPaths()
{ {
// Recorrido para el texto de "Get Ready!" (0,1) // Recorrido para el texto de "Get Ready!" (0,1)
{ {
const auto &texture = Resource::get()->getTexture("get_ready"); const auto &texture = Resource::get()->getTexture("game_text_get_ready");
const auto w = texture->getWidth(); const auto w = texture->getWidth();
const int x0 = -w; const int x0 = -w;
const int x1 = param.game.play_area.center_x - w / 2; const int x1 = param.game.play_area.center_x - w / 2;
@@ -989,10 +1029,9 @@ void Game::initPaths()
paths_.emplace_back(Path(createPath(x1, x2, PathType::HORIZONTAL, y, 80, easeInQuint), 0)); paths_.emplace_back(Path(createPath(x1, x2, PathType::HORIZONTAL, y, 80, easeInQuint), 0));
} }
// Recorrido para el texto de "Last Stage!" o de "X stages left" o "Game Over" // Recorrido para el texto de "Last Stage!" o de "X stages left" o "Game Over" (2,3)
// (2,3)
{ {
const auto &texture = Resource::get()->getTexture("last_stage"); const auto &texture = Resource::get()->getTexture("game_text_last_stage");
const auto h = texture->getHeight(); const auto h = texture->getHeight();
const int y0 = param.game.play_area.rect.h - h; const int y0 = param.game.play_area.rect.h - h;
const int y1 = param.game.play_area.center_y - h / 2; const int y1 = param.game.play_area.center_y - h / 2;
@@ -1004,7 +1043,7 @@ void Game::initPaths()
// Recorrido para el texto de "Congratulations!!" (3,4) // Recorrido para el texto de "Congratulations!!" (3,4)
{ {
const auto &texture = Resource::get()->getTexture("congratulations"); const auto &texture = Resource::get()->getTexture("game_text_congratulations");
const auto w = texture->getWidth(); const auto w = texture->getWidth();
const auto h = texture->getHeight(); const auto h = texture->getHeight();
const int x0 = -w; const int x0 = -w;
@@ -1017,7 +1056,7 @@ void Game::initPaths()
// Recorrido para el texto de "1.000.000 points!" (5,6) // Recorrido para el texto de "1.000.000 points!" (5,6)
{ {
const auto &texture = Resource::get()->getTexture("1000000_points"); const auto &texture = Resource::get()->getTexture("game_text_1000000_points");
const auto w = texture->getWidth(); const auto w = texture->getWidth();
const auto h = texture->getHeight(); const auto h = texture->getHeight();
const int x0 = param.game.play_area.rect.w; const int x0 = param.game.play_area.rect.w;
@@ -1155,18 +1194,23 @@ void Game::checkEvents()
} }
case SDLK_6: // Crea un mensaje case SDLK_6: // Crea un mensaje
{ {
createMessage({paths_.at(4), paths_.at(5)}, Resource::get()->getTexture("congratulations")); createMessage({paths_.at(2), paths_.at(3)}, Resource::get()->getTexture("game_text_congratulations"));
createMessage({paths_.at(6), paths_.at(7)}, Resource::get()->getTexture("1000000_points"));
break; break;
} }
case SDLK_7: // Flash case SDLK_7: // Flash
{ {
screen_->flash(flash_color, 100); screen_->flash(flash_color, 3);
break; break;
} }
case SDLK_8: case SDLK_8:
{ {
players_.at(0)->setPlayingState(PlayerState::LEAVING_SCREEN); players_.at(0)->setPlayingState(PlayerState::LEAVING_SCREEN);
break;
}
case SDLK_9:
{
tabe_->enable();
break;
} }
default: default:
break; break;
@@ -1333,7 +1377,8 @@ void Game::handleDemoMode()
if (input_->checkAnyButtonPressed()) if (input_->checkAnyButtonPressed())
{ {
section::name = section::Name::TITLE; // Salir del modo demo y regresar al menú principal. section::name = section::Name::TITLE; // Salir del modo demo y regresar al menú principal.
section::attract_mode = section::AttractMode::TITLE_TO_DEMO; // El juego volverá a mostrar la demo
return; return;
} }
++index; ++index;
@@ -1682,6 +1727,16 @@ void Game::resumeMusic()
} }
} }
// Hace sonar la música
void Game::playMusic()
{
// Si la música no está sonando
if (JA_GetMusicState() == JA_MUSIC_INVALID || JA_GetMusicState() == JA_MUSIC_STOPPED)
{
JA_PlayMusic(Resource::get()->getMusic("playing.ogg"));
}
}
// Detiene la música // Detiene la música
void Game::stopMusic() void Game::stopMusic()
{ {
@@ -1703,12 +1758,12 @@ void Game::updateDemo()
// Activa el fundido antes de acabar con los datos de la demo // Activa el fundido antes de acabar con los datos de la demo
if (demo_.counter == TOTAL_DEMO_DATA - 200) if (demo_.counter == TOTAL_DEMO_DATA - 200)
{ {
fade_->setType(FadeType::RANDOM_SQUARE); fade_out_->setType(FadeType::RANDOM_SQUARE);
fade_->activate(); fade_out_->activate();
} }
// Si ha terminado el fundido, cambia de sección // Si ha terminado el fundido, cambia de sección
if (fade_->hasEnded()) if (fade_out_->hasEnded())
{ {
section::name = section::Name::HI_SCORE_TABLE; section::name = section::Name::HI_SCORE_TABLE;
return; return;
@@ -1747,15 +1802,18 @@ void Game::updateGame()
Stage::addPower(5); Stage::addPower(5);
} }
#endif #endif
fade_->update(); fade_in_->update();
fade_out_->update();
updatePlayers(); updatePlayers();
checkPlayersStatusPlaying(); checkPlayersStatusPlaying();
updateScoreboard(); updateScoreboard();
updateBackground(); updateBackground();
balloon_manager_->update(); balloon_manager_->update();
tabe_->update();
moveBullets(); moveBullets();
updateItems(); updateItems();
updateStage(); updateStage();
updateFadeInState();
updateGameOverState(); updateGameOverState();
updateCompletedState(); updateCompletedState();
updateSmartSprites(); updateSmartSprites();
@@ -1783,21 +1841,24 @@ void Game::cleanVectors()
// Gestiona el nivel de amenaza // Gestiona el nivel de amenaza
void Game::updateMenace() void Game::updateMenace()
{ {
const auto stage = Stage::get(Stage::number); if (state_ == GameState::PLAYING)
const float percent = Stage::power / stage.power_to_complete;
const int difference = stage.max_menace - stage.min_menace;
// Aumenta el nivel de amenaza en función de la puntuación
menace_threshold_ = stage.min_menace + (difference * percent);
// Si el nivel de amenza es inferior al umbral
if (menace_current_ < menace_threshold_)
{ {
// Crea una formación de enemigos const auto stage = Stage::get(Stage::number);
balloon_manager_->deployBalloonFormation(Stage::number); const float percent = Stage::power / stage.power_to_complete;
const int difference = stage.max_menace - stage.min_menace;
// Recalcula el nivel de amenaza con el nuevo globo // Aumenta el nivel de amenaza en función de la puntuación
evaluateAndSetMenace(); menace_threshold_ = stage.min_menace + (difference * percent);
// Si el nivel de amenza es inferior al umbral
if (menace_current_ < menace_threshold_)
{
// Crea una formación de enemigos
balloon_manager_->deployBalloonFormation(Stage::number);
// Recalcula el nivel de amenaza con el nuevo globo
evaluateAndSetMenace();
}
} }
} }

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,7 @@ private:
// Enum // Enum
enum class GameState enum class GameState
{ {
FADE_IN,
PLAYING, PLAYING,
COMPLETED, COMPLETED,
GAME_OVER, GAME_OVER,
@@ -140,8 +142,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 +168,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
@@ -193,6 +197,9 @@ private:
// Comprueba si hay cambio de fase y actualiza las variables // Comprueba si hay cambio de fase y actualiza las variables
void updateStage(); void updateStage();
// Actualiza el estado de fade in
void updateFadeInState();
// Actualiza el estado de fin de la partida // Actualiza el estado de fin de la partida
void updateGameOverState(); void updateGameOverState();
@@ -373,6 +380,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();

View File

@@ -1,4 +1,5 @@
#include "game_logo.h" #include "game_logo.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL #include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL
#include <algorithm> // Para max #include <algorithm> // Para max
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
@@ -8,6 +9,11 @@
#include "smart_sprite.h" // Para SmartSprite #include "smart_sprite.h" // Para SmartSprite
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "screen.h"
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,6 +1,7 @@
#include "global_inputs.h" #include "global_inputs.h"
#include <string> // Para operator+, string #include <string> // Para operator+, string
#include "input.h" // Para Input, InputType, INPUT_DO_NOT_ALLOW_REPEAT #include "input.h" // Para Input, InputType, INPUT_DO_NOT_ALLOW_REPEAT
#include "asset.h"
#include "jail_audio.h" // Para JA_EnableMusic, JA_EnableSound #include "jail_audio.h" // Para JA_EnableMusic, JA_EnableSound
#include "lang.h" // Para getText #include "lang.h" // Para getText
#include "notifier.h" // Para Notifier #include "notifier.h" // Para Notifier
@@ -13,18 +14,8 @@
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 +24,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 +64,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 +169,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 +201,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 +253,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,12 @@
#include <vector> #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

@@ -77,6 +77,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();
@@ -202,9 +205,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

@@ -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

@@ -27,18 +27,16 @@ 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);
@@ -211,11 +209,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_++;
@@ -307,9 +310,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

@@ -382,6 +382,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();
} }
} }
@@ -413,7 +416,6 @@ void Intro::render()
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)),
@@ -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,91 +1,92 @@
#ifndef JA_USESDLMIXER #ifndef JA_USESDLMIXER
#include "jail_audio.h" #include "jail_audio.h"
#include <stdint.h> // para uint8_t #include "stb_vorbis.c"
#include <stdio.h> // para NULL, fseek, fclose, fopen, fread, ftell, FILE #include <SDL2/SDL.h>
#include <stdlib.h> // para free, malloc #include <stdio.h>
#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 {
{ Uint32 length {0};
Uint32 length{0}; Uint8* buffer {NULL};
Uint8 *buffer{NULL};
}; };
struct JA_Channel_t struct JA_Channel_t {
{ JA_Sound_t *sound;
JA_Sound_t *sound; int pos {0};
int pos{0}; int times {0};
int times{0}; JA_Channel_state state { JA_CHANNEL_FREE };
JA_Channel_state state{JA_CHANNEL_FREE};
}; };
struct JA_Music_t struct JA_Music_t {
{ int samples {0};
int samples{0}; Uint32 length {0};
int pos{0}; int pos {0};
int times{0}; int times {0};
short *output{NULL}; short* output {NULL};
JA_Music_state state{JA_MUSIC_INVALID}; JA_Music_state state {JA_MUSIC_INVALID};
}; };
JA_Music_t *current_music{NULL}; JA_Music_t *current_music{NULL};
JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS]; JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS];
int JA_freq{48000}; int JA_freq {48000};
SDL_AudioFormat JA_format{AUDIO_S16}; SDL_AudioFormat JA_format {AUDIO_S16};
Uint8 JA_channels{2}; Uint8 JA_channels {2};
int JA_musicVolume = 128; int JA_musicVolume = 128;
int JA_soundVolume = 64; int JA_soundVolume = 64;
bool JA_musicEnabled = true; bool JA_musicEnabled = true;
bool JA_soundEnabled = true; bool JA_soundEnabled = true;
SDL_AudioDeviceID sdlAudioDevice = 0; SDL_AudioDeviceID sdlAudioDevice = 0;
void audioCallback(void *userdata, uint8_t *stream, int len) bool fading = false;
{ int fade_start_time;
int fade_duration;
int fade_initial_volume;
void audioCallback(void * userdata, uint8_t * stream, int len) {
SDL_memset(stream, 0, len); SDL_memset(stream, 0, len);
if (current_music != NULL && current_music->state == JA_MUSIC_PLAYING) if (current_music != NULL && current_music->state == JA_MUSIC_PLAYING) {
{ int volume = JA_musicVolume;
const int size = SDL_min(len, current_music->samples * 2 - current_music->pos); if (fading) {
SDL_MixAudioFormat(stream, (Uint8 *)(current_music->output + current_music->pos), AUDIO_S16, size, JA_musicVolume); int time = SDL_GetTicks();
current_music->pos += size / 2; if (time > (fade_start_time+fade_duration)) {
if (size < len) fading = false;
{ current_music->pos = 0;
if (current_music->times != 0) current_music->state = JA_MUSIC_STOPPED;
{ volume = 0;
SDL_MixAudioFormat(stream + size, (Uint8 *)current_music->output, AUDIO_S16, len - size, JA_musicVolume); } else {
current_music->pos = (len - size) / 2; const int time_passed = time - fade_start_time;
if (current_music->times > 0) const float percent = (float)time_passed / (float)fade_duration;
current_music->times--; volume = JA_musicVolume * (1.0 - percent);
} }
else }
{ 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 (current_music->times != 0) {
SDL_MixAudioFormat(stream+size, (Uint8*)current_music->output, AUDIO_S16, len-size, volume);
current_music->pos = len-size;
if (current_music->times > 0) current_music->times--;
} else {
current_music->pos = 0; current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
} }
} }
} }
// Mixar els channels mi amol // Mixar els channels mi amol
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
{ if (channels[i].state == JA_CHANNEL_PLAYING) {
if (channels[i].state == JA_CHANNEL_PLAYING)
{
const int size = SDL_min(len, channels[i].sound->length - channels[i].pos); const int size = SDL_min(len, channels[i].sound->length - channels[i].pos);
SDL_MixAudioFormat(stream, channels[i].sound->buffer + channels[i].pos, AUDIO_S16, size, JA_soundVolume); SDL_MixAudioFormat(stream, channels[i].sound->buffer + channels[i].pos, AUDIO_S16, size, JA_soundVolume);
channels[i].pos += size; channels[i].pos += size;
if (size < len) if (size < len) {
{ if (channels[i].times != 0) {
if (channels[i].times != 0) SDL_MixAudioFormat(stream + size, channels[i].sound->buffer, AUDIO_S16, len-size, JA_soundVolume);
{ channels[i].pos = len-size;
SDL_MixAudioFormat(stream + size, channels[i].sound->buffer, AUDIO_S16, len - size, JA_soundVolume); if (channels[i].times > 0) channels[i].times--;
channels[i].pos = len - size; } else {
if (channels[i].times > 0)
channels[i].times--;
}
else
{
JA_StopChannel(i); JA_StopChannel(i);
} }
} }
@@ -95,69 +96,84 @@ void audioCallback(void *userdata, uint8_t *stream, int len)
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels) void JA_Init(const int freq, const SDL_AudioFormat format, const int channels)
{ {
#ifdef DEBUG
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
#endif
SDL_Log("Iniciant JailAudio...");
JA_freq = freq; JA_freq = freq;
JA_format = format; JA_format = format;
JA_channels = channels; JA_channels = channels;
SDL_AudioSpec audioSpec{JA_freq, JA_format, JA_channels, 0, 1024, 0, 0, audioCallback, NULL}; SDL_AudioSpec audioSpec{JA_freq, JA_format, JA_channels, 0, 1024, 0, 0, audioCallback, NULL};
if (sdlAudioDevice != 0) if (sdlAudioDevice != 0) SDL_CloseAudioDevice(sdlAudioDevice);
SDL_CloseAudioDevice(sdlAudioDevice);
sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0); sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0);
if (sdlAudioDevice==0)
{
SDL_Log("FAILED!\n");
SDL_Log("Failed to initialize SDL audio!\n");
} else {
SDL_Log("OK!\n");
}
SDL_PauseAudioDevice(sdlAudioDevice, 0); SDL_PauseAudioDevice(sdlAudioDevice, 0);
} }
void JA_Quit() void JA_Quit() {
{
SDL_PauseAudioDevice(sdlAudioDevice, 1); SDL_PauseAudioDevice(sdlAudioDevice, 1);
if (sdlAudioDevice != 0) if (sdlAudioDevice != 0) SDL_CloseAudioDevice(sdlAudioDevice);
SDL_CloseAudioDevice(sdlAudioDevice);
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;
// [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");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
Uint8 *buffer = (Uint8 *)malloc(fsize + 1);
if (fread(buffer, fsize, 1, f) != 1)
return NULL;
fclose(f);
JA_Music_t *music = new JA_Music_t(); JA_Music_t *music = new JA_Music_t();
music->samples = stb_vorbis_decode_memory(buffer, fsize, &chan, &samplerate, &music->output); music->samples = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &music->output);
free(buffer);
// [RZC 28/08/22] Abans el descomprimiem mentre el teniem obert // [RZC 28/08/22] Abans el descomprimiem mentre el teniem obert
// music->samples = stb_vorbis_decode_filename(filename, &chan, &samplerate, &music->output); // music->samples = stb_vorbis_decode_filename(filename, &chan, &samplerate, &music->output);
SDL_AudioCVT cvt; SDL_AudioCVT cvt;
SDL_BuildAudioCVT(&cvt, AUDIO_S16, chan, samplerate, JA_format, JA_channels, JA_freq); SDL_BuildAudioCVT(&cvt, AUDIO_S16, chan, samplerate, JA_format, JA_channels, JA_freq);
if (cvt.needed) SDL_Log("Music length: %f\n", float(music->samples)/float(JA_freq));
{ if (cvt.needed) {
cvt.len = music->samples * chan * 2; cvt.len = music->samples * chan * 2;
cvt.buf = (Uint8 *)SDL_malloc(cvt.len * cvt.len_mult); music->length = cvt.len;
cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult);
SDL_memcpy(cvt.buf, music->output, cvt.len); SDL_memcpy(cvt.buf, music->output, cvt.len);
SDL_ConvertAudio(&cvt); SDL_ConvertAudio(&cvt);
free(music->output); free(music->output);
music->output = (short *)cvt.buf; music->output = (short*)cvt.buf;
} }
music->length = music->samples * chan * 2;
music->pos = 0; music->pos = 0;
music->state = JA_MUSIC_STOPPED; music->state = JA_MUSIC_STOPPED;
return music; 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.
FILE *f = fopen(filename, "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
Uint8 *buffer = (Uint8*)malloc(fsize + 1);
if (fread(buffer, fsize, 1, f)!=1) return NULL;
fclose(f);
JA_Music_t *music = JA_LoadMusic(buffer, fsize);
free(buffer);
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) {
{
current_music->pos = 0; current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
} }
@@ -169,78 +185,108 @@ void JA_PlayMusic(JA_Music_t *music, const int loop)
void JA_PauseMusic() void JA_PauseMusic()
{ {
if (!JA_musicEnabled) if (!JA_musicEnabled) return;
return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
return;
current_music->state = JA_MUSIC_PAUSED; current_music->state = JA_MUSIC_PAUSED;
} }
void JA_ResumeMusic() void JA_ResumeMusic()
{ {
if (!JA_musicEnabled) if (!JA_musicEnabled) return;
return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
return;
current_music->state = JA_MUSIC_PLAYING; current_music->state = JA_MUSIC_PLAYING;
} }
void JA_StopMusic() void JA_StopMusic()
{ {
if (!JA_musicEnabled) if (!JA_musicEnabled) return;
return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
return;
current_music->pos = 0; current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
} }
JA_Music_state JA_GetMusicState() void JA_FadeOutMusic(const int milliseconds)
{ {
if (!JA_musicEnabled) if (!JA_musicEnabled) return;
return JA_MUSIC_DISABLED; if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
if (current_music == NULL) fading = true;
return JA_MUSIC_INVALID; fade_start_time = SDL_GetTicks();
fade_duration = milliseconds;
fade_initial_volume = JA_musicVolume;
}
JA_Music_state JA_GetMusicState() {
if (!JA_musicEnabled) return JA_MUSIC_DISABLED;
if (current_music == NULL) return JA_MUSIC_INVALID;
return current_music->state; return current_music->state;
} }
void JA_DeleteMusic(JA_Music_t *music) void JA_DeleteMusic(JA_Music_t *music) {
{ if (current_music == music) current_music = NULL;
if (current_music == music)
current_music = NULL;
free(music->output); free(music->output);
delete music; delete music;
} }
int JA_SetMusicVolume(int volume) int JA_SetMusicVolume(int volume)
{ {
JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume;
: 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) JA_StopMusic();
JA_StopMusic();
JA_musicEnabled = value; JA_musicEnabled = value;
} }
JA_Sound_t *JA_NewSound(Uint8 *buffer, Uint32 length)
{
JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length) {
JA_Sound_t *sound = new JA_Sound_t(); JA_Sound_t *sound = new JA_Sound_t();
sound->buffer = buffer; sound->buffer = buffer;
sound->length = length; sound->length = length;
return sound; return sound;
} }
JA_Sound_t *JA_LoadSound(const char *filename) 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 *sound = new JA_Sound_t(); JA_Sound_t *sound = new JA_Sound_t();
SDL_AudioSpec wavSpec; SDL_AudioSpec wavSpec;
SDL_LoadWAV(filename, &wavSpec, &sound->buffer, &sound->length); SDL_LoadWAV(filename, &wavSpec, &sound->buffer, &sound->length);
@@ -248,7 +294,7 @@ JA_Sound_t *JA_LoadSound(const char *filename)
SDL_AudioCVT cvt; SDL_AudioCVT cvt;
SDL_BuildAudioCVT(&cvt, wavSpec.format, wavSpec.channels, wavSpec.freq, JA_format, JA_channels, JA_freq); SDL_BuildAudioCVT(&cvt, wavSpec.format, wavSpec.channels, wavSpec.freq, JA_format, JA_channels, JA_freq);
cvt.len = sound->length; cvt.len = sound->length;
cvt.buf = (Uint8 *)SDL_malloc(cvt.len * cvt.len_mult); cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult);
SDL_memcpy(cvt.buf, sound->buffer, sound->length); SDL_memcpy(cvt.buf, sound->buffer, sound->length);
SDL_ConvertAudio(&cvt); SDL_ConvertAudio(&cvt);
SDL_FreeWAV(sound->buffer); SDL_FreeWAV(sound->buffer);
@@ -260,16 +306,24 @@ 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 -1;
return 0;
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) { channel++; }
{ if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) channel = 0;
channel++;
} channels[channel].sound = sound;
if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) channels[channel].times = loop;
channel = 0; channels[channel].pos = 0;
channels[channel].state = JA_CHANNEL_PLAYING;
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].sound = sound;
channels[channel].times = loop; channels[channel].times = loop;
@@ -280,10 +334,8 @@ int JA_PlaySound(JA_Sound_t *sound, const int loop)
void JA_DeleteSound(JA_Sound_t *sound) void JA_DeleteSound(JA_Sound_t *sound)
{ {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
{ if (channels[i].sound == sound) JA_StopChannel(i);
if (channels[i].sound == sound)
JA_StopChannel(i);
} }
SDL_free(sound->buffer); SDL_free(sound->buffer);
delete sound; delete sound;
@@ -291,60 +343,41 @@ void JA_DeleteSound(JA_Sound_t *sound)
void JA_PauseChannel(const int channel) void JA_PauseChannel(const int channel)
{ {
if (!JA_soundEnabled) if (!JA_soundEnabled) return;
return;
if (channel == -1) if (channel == -1) {
{ for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) if (channels[i].state == JA_CHANNEL_PLAYING) channels[i].state = JA_CHANNEL_PAUSED;
{
if (channels[i].state == JA_CHANNEL_PLAYING)
channels[i].state = JA_CHANNEL_PAUSED;
} }
} } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) if (channels[channel].state == JA_CHANNEL_PLAYING) channels[channel].state = JA_CHANNEL_PAUSED;
{
if (channels[channel].state == JA_CHANNEL_PLAYING)
channels[channel].state = JA_CHANNEL_PAUSED;
} }
} }
void JA_ResumeChannel(const int channel) void JA_ResumeChannel(const int channel)
{ {
if (!JA_soundEnabled) if (!JA_soundEnabled) return;
return;
if (channel == -1) if (channel == -1) {
{ for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) if (channels[i].state == JA_CHANNEL_PAUSED) channels[i].state = JA_CHANNEL_PLAYING;
{
if (channels[i].state == JA_CHANNEL_PAUSED)
channels[i].state = JA_CHANNEL_PLAYING;
} }
} } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) if (channels[channel].state == JA_CHANNEL_PAUSED) channels[channel].state = JA_CHANNEL_PLAYING;
{
if (channels[channel].state == JA_CHANNEL_PAUSED)
channels[channel].state = JA_CHANNEL_PLAYING;
} }
} }
void JA_StopChannel(const int channel) void JA_StopChannel(const int channel)
{ {
if (!JA_soundEnabled) if (!JA_soundEnabled) return;
return;
if (channel == -1) if (channel == -1) {
{ for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{
channels[i].state = JA_CHANNEL_FREE; channels[i].state = JA_CHANNEL_FREE;
channels[i].pos = 0; channels[i].pos = 0;
channels[i].sound = NULL; channels[i].sound = NULL;
} }
} } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
{
channels[channel].state = JA_CHANNEL_FREE; channels[channel].state = JA_CHANNEL_FREE;
channels[channel].pos = 0; channels[channel].pos = 0;
channels[channel].sound = NULL; channels[channel].sound = NULL;
@@ -353,18 +386,15 @@ void JA_StopChannel(const int channel)
JA_Channel_state JA_GetChannelState(const int channel) JA_Channel_state JA_GetChannelState(const int channel)
{ {
if (!JA_soundEnabled) if (!JA_soundEnabled) return JA_SOUND_DISABLED;
return JA_SOUND_DISABLED;
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID;
return JA_CHANNEL_INVALID;
return channels[channel].state; return channels[channel].state;
} }
int JA_SetSoundVolume(int volume) int JA_SetSoundVolume(int volume)
{ {
JA_soundVolume = volume > 128 ? 128 : volume < 0 ? 0 JA_soundVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume;
: volume;
return JA_soundVolume; return JA_soundVolume;
} }
@@ -372,17 +402,15 @@ void JA_EnableSound(const bool value)
{ {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{ {
if (channels[i].state == JA_CHANNEL_PLAYING) if (channels[i].state == JA_CHANNEL_PLAYING) JA_StopChannel(i);
JA_StopChannel(i);
} }
JA_soundEnabled = value; JA_soundEnabled = value;
} }
int JA_SetVolume(int volume) int JA_SetVolume(int volume)
{ {
JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume;
: volume; JA_soundVolume = JA_musicVolume/2;
JA_soundVolume = JA_musicVolume / 2;
return JA_musicVolume; return JA_musicVolume;
} }

View File

@@ -1,43 +1,34 @@
#pragma once #pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h> // para SDL_AudioFormat enum JA_Channel_state { JA_CHANNEL_INVALID, JA_CHANNEL_FREE, JA_CHANNEL_PLAYING, JA_CHANNEL_PAUSED, JA_SOUND_DISABLED };
#include <SDL2/SDL_stdinc.h> // para Uint32, Uint8 enum JA_Music_state { JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, JA_MUSIC_STOPPED, JA_MUSIC_DISABLED };
struct JA_Music_t; // lines 5-5
struct JA_Sound_t; // lines 6-6
enum JA_Channel_state struct JA_Sound_t;
{ struct JA_Music_t;
JA_CHANNEL_INVALID,
JA_CHANNEL_FREE,
JA_CHANNEL_PLAYING,
JA_CHANNEL_PAUSED,
JA_SOUND_DISABLED
};
enum JA_Music_state
{
JA_MUSIC_INVALID,
JA_MUSIC_PLAYING,
JA_MUSIC_PAUSED,
JA_MUSIC_STOPPED,
JA_MUSIC_DISABLED
};
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels); void JA_Init(const int freq, const SDL_AudioFormat format, const int channels);
void JA_Quit(); void JA_Quit();
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(const char *filename); JA_Sound_t *JA_LoadSound(Uint8* buffer, Uint32 length);
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

@@ -59,6 +59,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
@@ -100,7 +101,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 +113,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 +200,9 @@ void Logo::update()
{ {
section::name = section::Name::INTRO; section::name = section::Name::INTRO;
} }
// Actualiza las variables de globalInputs
globalInputs::update();
} }
} }
@@ -226,7 +234,7 @@ void Logo::render()
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)
{ {

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()
@@ -80,8 +74,9 @@ void Notifier::update()
if (param.notification.sound) if (param.notification.sound)
{ {
if (notifications_[i].status == NotificationStatus::RISING) if (notifications_[i].status == 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"));
} }
} }
} }

View File

@@ -62,7 +62,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 +72,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

@@ -1,6 +1,5 @@
#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

View File

@@ -1,15 +1,15 @@
#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"
// 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)
@@ -164,7 +164,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 +174,14 @@ void Player::move()
case PlayerState::DYING: case PlayerState::DYING:
{ {
// Si el cadaver abandona el area de juego por los laterales lo hace rebotar // Si el cadaver abandona el area de juego por los laterales lo hace rebotar
if ((player_sprite_->getPosX() < param.game.play_area.rect.x) || (player_sprite_->getPosX() + WIDTH_ > play_area_.w)) if ((player_sprite_->getPosX() < play_area_.x) || (player_sprite_->getPosX() + WIDTH_ > play_area_.w))
{ {
player_sprite_->setVelX(-player_sprite_->getVelX()); player_sprite_->setVelX(-player_sprite_->getVelX());
JA_PlaySound(Resource::get()->getSound("bubble4.wav"));
} }
// 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,13 +191,15 @@ void Player::move()
pos_y_ = default_pos_y_; pos_y_ = default_pos_y_;
player_sprite_->clear(); player_sprite_->clear();
shiftSprite(); shiftSprite();
JA_PlaySound(Resource::get()->getSound("bubble4.wav"));
} }
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);
JA_PlaySound(Resource::get()->getSound("bubble4.wav"));
} }
} }
break; break;
@@ -224,6 +227,41 @@ void Player::move()
setPlayingState(PlayerState::GAME_OVER); setPlayingState(PlayerState::GAME_OVER);
break; 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;
}
default: default:
break; break;
} }
@@ -254,6 +292,7 @@ void Player::setAnimation()
case PlayerState::PLAYING: case PlayerState::PLAYING:
case PlayerState::ENTERING_NAME_GAME_COMPLETED: case PlayerState::ENTERING_NAME_GAME_COMPLETED:
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";
@@ -470,6 +509,11 @@ void Player::setPlayingState(PlayerState state)
setScoreboardMode(ScoreboardMode::GAME_COMPLETED); setScoreboardMode(ScoreboardMode::GAME_COMPLETED);
break; break;
} }
case PlayerState::CREDITS:
{
vel_x_ = (walking_state_ == PlayerState::WALKING_RIGHT) ? BASE_SPEED_ : -BASE_SPEED_;
break;
}
default: default:
break; break;
} }
@@ -615,9 +659,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 +673,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;
} }

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,7 @@ 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
CREDITS, // Estado para los creditos del juego
}; };
// Clase Player // Clase Player

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)
{ {
@@ -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,7 +11,6 @@
#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...
@@ -89,10 +88,10 @@ void Screen::blit()
fps_counter_++; fps_counter_++;
// Actualiza y dibuja el efecto de flash en la pantalla // Actualiza y dibuja el efecto de flash en la pantalla
doFlash(); renderFlash();
// Atenua la pantalla // Atenua la pantalla
doAttenuate(); renderAttenuate();
// Muestra la ayuda por pantalla // Muestra la ayuda por pantalla
OnScreenHelp::get()->render(); OnScreenHelp::get()->render();
@@ -201,7 +200,8 @@ 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_, shader_canvas_, source.c_str());
@@ -235,7 +235,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,6 +255,7 @@ 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();
@@ -307,27 +308,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,7 +390,7 @@ 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);
} }
} }

View File

@@ -51,12 +51,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 +90,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();
@@ -152,7 +163,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

@@ -13,7 +13,8 @@ namespace section
HI_SCORE_TABLE = 5, HI_SCORE_TABLE = 5,
GAME_DEMO = 6, GAME_DEMO = 6,
INSTRUCTIONS = 7, INSTRUCTIONS = 7,
QUIT = 8, CREDITS = 8,
QUIT = 9,
}; };
// Opciones para la sección // Opciones para la sección
@@ -26,7 +27,8 @@ namespace section
QUIT_WITH_KEYBOARD = 4, QUIT_WITH_KEYBOARD = 4,
QUIT_WITH_CONTROLLER = 5, QUIT_WITH_CONTROLLER = 5,
QUIT_FROM_EVENT = 6, QUIT_FROM_EVENT = 6,
NONE = 7, RELOAD = 7,
NONE = 8,
}; };
// Variables para el Attract Mode // Variables para el Attract Mode

View File

@@ -19,31 +19,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 +36,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

@@ -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,5 +1,6 @@
#include "stage.h" #include "stage.h"
#include <vector> #include <algorithm> // Para min
#include <vector> // Para vector
namespace Stage namespace Stage
{ {

145
source/tabe.cpp Normal file
View File

@@ -0,0 +1,145 @@
#include "tabe.h"
#include "resource.h"
#include "param.h"
#include "jail_audio.h"
#include <algorithm>
// 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

@@ -29,15 +29,16 @@
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_->setPost(param.fade.post_duration);
@@ -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,7 +71,10 @@ 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())
{ {
@@ -85,18 +90,19 @@ void Title::update()
} }
} }
// 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;
@@ -118,6 +124,27 @@ void Title::update()
fade_->activate(); fade_->activate();
post_fade_ = -1; post_fade_ = -1;
} }
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 +164,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 +178,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();
@@ -238,24 +277,28 @@ 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_->activate(); JA_PlaySound(Resource::get()->getSound("game_start.wav"));
JA_FadeOutMusic(1500);
post_fade_ = controller.player_id; post_fade_ = controller.player_id;
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 +306,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 +385,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

@@ -18,7 +18,7 @@ namespace section
constexpr const char TEXT_COPYRIGHT[] = "@2020,2024 JailDesigner"; constexpr const char TEXT_COPYRIGHT[] = "@2020,2024 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 +27,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,12 +40,19 @@ 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
@@ -54,6 +62,7 @@ private:
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 int post_fade_ = 0; // Opción a realizar cuando termina el fundido
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();