Compare commits
63 Commits
960ee367df
...
metal-inte
| Author | SHA1 | Date | |
|---|---|---|---|
| b3f6e2fcf0 | |||
| 7f00942517 | |||
| fb9c78eb49 | |||
| 62f65cbd5a | |||
| 057d3dcfee | |||
| c85336a4d0 | |||
| e4702e4e24 | |||
| 928335576c | |||
| fe950e6f17 | |||
| 6e81b6e60c | |||
| 74f6fe3501 | |||
| dfdb679054 | |||
| 26ed479306 | |||
| 32e9da55ef | |||
| 610083578e | |||
| 7250073d60 | |||
| dfa06870e4 | |||
| 81f3a25143 | |||
| 5aca95f3d2 | |||
| 7b193605e6 | |||
| 089a5b15d7 | |||
| e6a14ca57d | |||
| 467d609c28 | |||
| e03c798000 | |||
| 52d76b7338 | |||
| 83ee9c2649 | |||
| 43788bb01a | |||
| 58cf78e1e3 | |||
| 6bf8490776 | |||
| 8cfe28922c | |||
| 63990c75c2 | |||
| 94dca528ab | |||
| 4b6b89ceb2 | |||
| ed077c1da5 | |||
| 2819b3628e | |||
| 1e9e664012 | |||
| 0c8b39cee7 | |||
| d7b3af5ab8 | |||
| 5e5227305f | |||
| 3fc15a9512 | |||
| e774e0e8ad | |||
| a95776e6c7 | |||
| 0428ff26d5 | |||
| fc3e2deb1f | |||
| 65ca17f938 | |||
| ff2a51a507 | |||
| fe0083abd4 | |||
| 1c058694fd | |||
| cb0c3266d5 | |||
| 8ddc5d94f1 | |||
| b359a73d50 | |||
| 142603db71 | |||
| 1ec272f017 | |||
| 327987447d | |||
| ada5025c65 | |||
| 1ced698093 | |||
| 2a4c47a6ca | |||
| 6102504d32 | |||
| a123b3aa93 | |||
| 81d486f2d3 | |||
| 0c10898bdc | |||
| a3cd404545 | |||
| 5c708fc60a |
@@ -6,7 +6,16 @@ BreakBeforeBraces: Attach # Llaves en la misma línea
|
|||||||
AllowShortIfStatementsOnASingleLine: true
|
AllowShortIfStatementsOnASingleLine: true
|
||||||
AllowShortBlocksOnASingleLine: true
|
AllowShortBlocksOnASingleLine: true
|
||||||
AllowShortFunctionsOnASingleLine: All
|
AllowShortFunctionsOnASingleLine: All
|
||||||
AlignOperands: false
|
AlignOperands: DontAlign
|
||||||
AlignAfterOpenBracket: DontAlign
|
AlignAfterOpenBracket: DontAlign
|
||||||
BinPackArguments: false
|
BinPackArguments: false
|
||||||
BinPackParameters: false
|
BinPackParameters: false
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
AllowAllConstructorInitializersOnNextLine: false
|
||||||
|
PackConstructorInitializers: Never
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
|||||||
15
.clang-tidy
@@ -1,8 +1,21 @@
|
|||||||
Checks: >
|
Checks: >
|
||||||
readability-*,
|
readability-*,
|
||||||
modernize-*,
|
modernize-*,
|
||||||
|
performance-*,
|
||||||
|
bugprone-unchecked-optional-access,
|
||||||
|
bugprone-sizeof-expression,
|
||||||
|
bugprone-suspicious-missing-comma,
|
||||||
|
bugprone-suspicious-index,
|
||||||
|
bugprone-undefined-memory-manipulation,
|
||||||
|
bugprone-use-after-move,
|
||||||
|
bugprone-out-of-bound-access,
|
||||||
-readability-identifier-length,
|
-readability-identifier-length,
|
||||||
-readability-magic-numbers
|
-readability-magic-numbers,
|
||||||
|
-bugprone-narrowing-conversions,
|
||||||
|
-performance-enum-size,
|
||||||
|
-performance-inefficient-string-concatenation,
|
||||||
|
-bugprone-integer-division,
|
||||||
|
-bugprone-easily-swappable-parameters,
|
||||||
|
|
||||||
WarningsAsErrors: '*'
|
WarningsAsErrors: '*'
|
||||||
# Solo incluir archivos de tu código fuente
|
# Solo incluir archivos de tu código fuente
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ set(APP_SOURCES
|
|||||||
source/main.cpp
|
source/main.cpp
|
||||||
source/param.cpp
|
source/param.cpp
|
||||||
source/resource.cpp
|
source/resource.cpp
|
||||||
|
source/resource_helper.cpp
|
||||||
|
source/resource_loader.cpp
|
||||||
|
source/resource_pack.cpp
|
||||||
source/screen.cpp
|
source/screen.cpp
|
||||||
source/text.cpp
|
source/text.cpp
|
||||||
source/writer.cpp
|
source/writer.cpp
|
||||||
|
|||||||
22
LICENSE
@@ -1 +1,21 @@
|
|||||||
GNU General Public License v3.0 only
|
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
|
||||||
|
|
||||||
|
Copyright (c) 2025 Coffee Crisis Arcade Edition
|
||||||
|
|
||||||
|
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
|
||||||
|
|
||||||
|
You are free to:
|
||||||
|
- Share — copy and redistribute the material in any medium or format
|
||||||
|
- Adapt — remix, transform, and build upon the material
|
||||||
|
|
||||||
|
Under the following terms:
|
||||||
|
- Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
|
||||||
|
- NonCommercial — You may not use the material for commercial purposes.
|
||||||
|
- ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
|
||||||
|
|
||||||
|
No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
|
||||||
|
|
||||||
|
To view a copy of this license, visit:
|
||||||
|
https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
25
Makefile
@@ -71,6 +71,9 @@ APP_SOURCES := \
|
|||||||
source/path_sprite.cpp \
|
source/path_sprite.cpp \
|
||||||
source/player.cpp \
|
source/player.cpp \
|
||||||
source/resource.cpp \
|
source/resource.cpp \
|
||||||
|
source/resource_helper.cpp \
|
||||||
|
source/resource_loader.cpp \
|
||||||
|
source/resource_pack.cpp \
|
||||||
source/scoreboard.cpp \
|
source/scoreboard.cpp \
|
||||||
source/screen.cpp \
|
source/screen.cpp \
|
||||||
source/sections/credits.cpp \
|
source/sections/credits.cpp \
|
||||||
@@ -104,7 +107,7 @@ INCLUDES := -Isource -Isource/external
|
|||||||
# 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)
|
||||||
CXXFLAGS := -std=c++20 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows -DWINDOWS_BUILD
|
CXXFLAGS := -std=c++20 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -static-libgcc -Wl,-Bstatic -lpthread -Wl,-Bdynamic -Wl,-subsystem,windows -DWINDOWS_BUILD
|
||||||
CXXFLAGS_DEBUG := -std=c++20 -Wall -g -D_DEBUG -DWINDOWS_BUILD
|
CXXFLAGS_DEBUG := -std=c++20 -Wall -g -D_DEBUG -DWINDOWS_BUILD
|
||||||
LDFLAGS := -lmingw32 -lws2_32 -lSDL3 -lopengl32
|
LDFLAGS := -lmingw32 -lws2_32 -lSDL3 -lopengl32
|
||||||
RM := del /Q
|
RM := del /Q
|
||||||
@@ -158,8 +161,9 @@ windows_release:
|
|||||||
powershell if (Test-Path "$(RELEASE_FOLDER)") {Remove-Item "$(RELEASE_FOLDER)" -Recurse -Force}
|
powershell if (Test-Path "$(RELEASE_FOLDER)") {Remove-Item "$(RELEASE_FOLDER)" -Recurse -Force}
|
||||||
powershell if (-not (Test-Path "$(RELEASE_FOLDER)")) {New-Item "$(RELEASE_FOLDER)" -ItemType Directory}
|
powershell if (-not (Test-Path "$(RELEASE_FOLDER)")) {New-Item "$(RELEASE_FOLDER)" -ItemType Directory}
|
||||||
|
|
||||||
# Copia la carpeta 'data'
|
# Copia la carpeta 'config' y el archivo 'resources.pack'
|
||||||
powershell Copy-Item -Path "data" -Destination "$(RELEASE_FOLDER)" -recurse -Force
|
powershell Copy-Item -Path "config" -Destination "$(RELEASE_FOLDER)" -recurse -Force
|
||||||
|
powershell Copy-Item -Path "resources.pack" -Destination "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
# Copia los ficheros que estan en la raíz del proyecto
|
# Copia los ficheros que estan en la raíz del proyecto
|
||||||
powershell Copy-Item "LICENSE" -Destination "$(RELEASE_FOLDER)"
|
powershell Copy-Item "LICENSE" -Destination "$(RELEASE_FOLDER)"
|
||||||
@@ -203,7 +207,8 @@ macos_release:
|
|||||||
$(MKDIR) Frameworks
|
$(MKDIR) Frameworks
|
||||||
|
|
||||||
# Copia carpetas y ficheros
|
# Copia carpetas y ficheros
|
||||||
cp -R data "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
cp -R config "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||||
|
cp resources.pack "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||||
cp -R release/frameworks/SDL3.xcframework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
|
cp -R release/frameworks/SDL3.xcframework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
|
||||||
cp -R release/frameworks/SDL3.xcframework Frameworks
|
cp -R release/frameworks/SDL3.xcframework Frameworks
|
||||||
cp release/*.icns "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
cp release/*.icns "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||||
@@ -262,7 +267,8 @@ linux_release:
|
|||||||
$(MKDIR) "$(RELEASE_FOLDER)"
|
$(MKDIR) "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
# Copia ficheros
|
# Copia ficheros
|
||||||
cp -R data "$(RELEASE_FOLDER)"
|
cp -R config "$(RELEASE_FOLDER)"
|
||||||
|
cp resources.pack "$(RELEASE_FOLDER)"
|
||||||
cp LICENSE "$(RELEASE_FOLDER)"
|
cp LICENSE "$(RELEASE_FOLDER)"
|
||||||
cp README.md "$(RELEASE_FOLDER)"
|
cp README.md "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
@@ -291,7 +297,8 @@ linux_release_desktop:
|
|||||||
$(MKDIR) "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)"
|
$(MKDIR) "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)"
|
||||||
|
|
||||||
# Copia ficheros del juego
|
# Copia ficheros del juego
|
||||||
cp -R data "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)/"
|
cp -R config "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)/"
|
||||||
|
cp resources.pack "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)/"
|
||||||
cp LICENSE "$(RELEASE_FOLDER)/$(TARGET_NAME)/"
|
cp LICENSE "$(RELEASE_FOLDER)/$(TARGET_NAME)/"
|
||||||
cp README.md "$(RELEASE_FOLDER)/$(TARGET_NAME)/"
|
cp README.md "$(RELEASE_FOLDER)/$(TARGET_NAME)/"
|
||||||
|
|
||||||
@@ -391,7 +398,8 @@ raspi_release:
|
|||||||
$(MKDIR) "$(RELEASE_FOLDER)"
|
$(MKDIR) "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
# Copia ficheros
|
# Copia ficheros
|
||||||
cp -R data "$(RELEASE_FOLDER)"
|
cp -R config "$(RELEASE_FOLDER)"
|
||||||
|
cp resources.pack "$(RELEASE_FOLDER)"
|
||||||
cp LICENSE "$(RELEASE_FOLDER)"
|
cp LICENSE "$(RELEASE_FOLDER)"
|
||||||
cp README.md "$(RELEASE_FOLDER)"
|
cp README.md "$(RELEASE_FOLDER)"
|
||||||
|
|
||||||
@@ -416,7 +424,8 @@ anbernic:
|
|||||||
$(MKDIR) "$(RELEASE_FOLDER)"_anbernic
|
$(MKDIR) "$(RELEASE_FOLDER)"_anbernic
|
||||||
|
|
||||||
# Copia ficheros
|
# Copia ficheros
|
||||||
cp -R data "$(RELEASE_FOLDER)"_anbernic
|
cp -R config "$(RELEASE_FOLDER)"_anbernic
|
||||||
|
cp resources.pack "$(RELEASE_FOLDER)"_anbernic
|
||||||
|
|
||||||
# Compila
|
# Compila
|
||||||
$(CXX) $(APP_SOURCES) $(INCLUDES) -DANBERNIC -DNO_SHADERS -DARCADE -DVERBOSE $(CXXFLAGS) $(LDFLAGS) -o $(RELEASE_FOLDER)_anbernic/$(TARGET_NAME)
|
$(CXX) $(APP_SOURCES) $(INCLUDES) -DANBERNIC -DNO_SHADERS -DARCADE -DVERBOSE $(CXXFLAGS) $(LDFLAGS) -o $(RELEASE_FOLDER)_anbernic/$(TARGET_NAME)
|
||||||
|
|||||||
@@ -9,14 +9,17 @@ DATA|${SYSTEM_FOLDER}/controllers.json|optional,absolute
|
|||||||
DATA|${SYSTEM_FOLDER}/score.bin|optional,absolute
|
DATA|${SYSTEM_FOLDER}/score.bin|optional,absolute
|
||||||
|
|
||||||
# Archivos de configuración del juego
|
# Archivos de configuración del juego
|
||||||
DATA|${PREFIX}/data/config/formations.txt
|
DATA|${PREFIX}/config/formations.txt
|
||||||
DATA|${PREFIX}/data/config/gamecontrollerdb.txt
|
DATA|${PREFIX}/config/gamecontrollerdb.txt
|
||||||
DATA|${PREFIX}/data/config/param_320x240.txt
|
DATA|${PREFIX}/config/param_320x240.txt
|
||||||
DATA|${PREFIX}/data/config/param_320x256.txt
|
DATA|${PREFIX}/config/param_320x256.txt
|
||||||
DATA|${PREFIX}/data/config/pools.txt
|
DATA|${PREFIX}/config/param_red.txt
|
||||||
DATA|${PREFIX}/data/config/stages.txt
|
DATA|${PREFIX}/config/pools.txt
|
||||||
DEMODATA|${PREFIX}/data/config/demo1.bin
|
DATA|${PREFIX}/config/stages.txt
|
||||||
DEMODATA|${PREFIX}/data/config/demo2.bin
|
|
||||||
|
# Archivos con los datos de la demo
|
||||||
|
DEMODATA|${PREFIX}/data/demo/demo1.bin
|
||||||
|
DEMODATA|${PREFIX}/data/demo/demo2.bin
|
||||||
|
|
||||||
# Música
|
# Música
|
||||||
MUSIC|${PREFIX}/data/music/credits.ogg
|
MUSIC|${PREFIX}/data/music/credits.ogg
|
||||||
@@ -49,6 +52,7 @@ SOUND|${PREFIX}/data/sound/notify.wav
|
|||||||
SOUND|${PREFIX}/data/sound/player_collision.wav
|
SOUND|${PREFIX}/data/sound/player_collision.wav
|
||||||
SOUND|${PREFIX}/data/sound/power_ball_explosion.wav
|
SOUND|${PREFIX}/data/sound/power_ball_explosion.wav
|
||||||
SOUND|${PREFIX}/data/sound/service_menu_adjust.wav
|
SOUND|${PREFIX}/data/sound/service_menu_adjust.wav
|
||||||
|
SOUND|${PREFIX}/data/sound/service_menu_back.wav
|
||||||
SOUND|${PREFIX}/data/sound/service_menu_move.wav
|
SOUND|${PREFIX}/data/sound/service_menu_move.wav
|
||||||
SOUND|${PREFIX}/data/sound/service_menu_select.wav
|
SOUND|${PREFIX}/data/sound/service_menu_select.wav
|
||||||
SOUND|${PREFIX}/data/sound/stage_change.wav
|
SOUND|${PREFIX}/data/sound/stage_change.wav
|
||||||
@@ -56,12 +60,12 @@ SOUND|${PREFIX}/data/sound/tabe_hit.wav
|
|||||||
SOUND|${PREFIX}/data/sound/tabe.wav
|
SOUND|${PREFIX}/data/sound/tabe.wav
|
||||||
SOUND|${PREFIX}/data/sound/title.wav
|
SOUND|${PREFIX}/data/sound/title.wav
|
||||||
SOUND|${PREFIX}/data/sound/voice_aw_aw_aw.wav
|
SOUND|${PREFIX}/data/sound/voice_aw_aw_aw.wav
|
||||||
SOUND|${PREFIX}/data/sound/voice_brbrbr.wav
|
|
||||||
SOUND|${PREFIX}/data/sound/voice_coffee.wav
|
SOUND|${PREFIX}/data/sound/voice_coffee.wav
|
||||||
SOUND|${PREFIX}/data/sound/voice_credit_thankyou.wav
|
SOUND|${PREFIX}/data/sound/voice_credit_thankyou.wav
|
||||||
SOUND|${PREFIX}/data/sound/voice_get_ready.wav
|
SOUND|${PREFIX}/data/sound/voice_get_ready.wav
|
||||||
SOUND|${PREFIX}/data/sound/voice_no.wav
|
SOUND|${PREFIX}/data/sound/voice_no.wav
|
||||||
SOUND|${PREFIX}/data/sound/voice_power_up.wav
|
SOUND|${PREFIX}/data/sound/voice_power_up.wav
|
||||||
|
SOUND|${PREFIX}/data/sound/voice_recover.wav
|
||||||
SOUND|${PREFIX}/data/sound/voice_thankyou.wav
|
SOUND|${PREFIX}/data/sound/voice_thankyou.wav
|
||||||
SOUND|${PREFIX}/data/sound/walk.wav
|
SOUND|${PREFIX}/data/sound/walk.wav
|
||||||
|
|
||||||
@@ -171,12 +175,14 @@ BITMAP|${PREFIX}/data/gfx/player/hit.png
|
|||||||
|
|
||||||
# Fuentes de texto
|
# Fuentes de texto
|
||||||
BITMAP|${PREFIX}/data/font/04b_25_2x.png
|
BITMAP|${PREFIX}/data/font/04b_25_2x.png
|
||||||
|
BITMAP|${PREFIX}/data/font/04b_25_2x_white.png
|
||||||
BITMAP|${PREFIX}/data/font/04b_25_flat_2x.png
|
BITMAP|${PREFIX}/data/font/04b_25_flat_2x.png
|
||||||
BITMAP|${PREFIX}/data/font/04b_25_flat.png
|
BITMAP|${PREFIX}/data/font/04b_25_flat.png
|
||||||
BITMAP|${PREFIX}/data/font/04b_25_grey.png
|
BITMAP|${PREFIX}/data/font/04b_25_grey.png
|
||||||
BITMAP|${PREFIX}/data/font/04b_25_metal.png
|
BITMAP|${PREFIX}/data/font/04b_25_metal.png
|
||||||
BITMAP|${PREFIX}/data/font/04b_25_reversed_2x.png
|
BITMAP|${PREFIX}/data/font/04b_25_reversed_2x.png
|
||||||
BITMAP|${PREFIX}/data/font/04b_25_reversed.png
|
BITMAP|${PREFIX}/data/font/04b_25_reversed.png
|
||||||
|
BITMAP|${PREFIX}/data/font/04b_25_white.png
|
||||||
BITMAP|${PREFIX}/data/font/04b_25.png
|
BITMAP|${PREFIX}/data/font/04b_25.png
|
||||||
BITMAP|${PREFIX}/data/font/8bithud.png
|
BITMAP|${PREFIX}/data/font/8bithud.png
|
||||||
BITMAP|${PREFIX}/data/font/aseprite.png
|
BITMAP|${PREFIX}/data/font/aseprite.png
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Archivo de configuración de formaciones de globos
|
# Coffee Crisis Arcade Edition - Archivo de configuración de formaciones de globos
|
||||||
# Formato por línea: x, desp, y, vel_x, tipo, tamaño, retraso_tiempo_creacion
|
# Formato por línea: x, desp, y, vel_x, tipo, tamaño, retraso_tiempo_creacion
|
||||||
# Variables disponibles:
|
# Variables disponibles:
|
||||||
# X0_0, X0_50, X0_100, X1_0, X1_100, X2_0, X2_100, X3_0, X3_100
|
# X0_0, X0_50, X0_100, X1_0, X1_100, X2_0, X2_100, X3_0, X3_100
|
||||||
151
config/param_320x240.txt
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
# Coffee Crisis Arcade Edition - Fichero de parametros
|
||||||
|
# Formato: PARAMETRO VALOR
|
||||||
|
|
||||||
|
# --- GAME ---
|
||||||
|
game.item_size 20 # Tamaño de los items del juego (en píxeles)
|
||||||
|
game.item_text_outline_color E0E0E0F0 # Color del outline del texto de los items (RGBA hex)
|
||||||
|
game.width 320 # Ancho de la resolución nativa del juego (en píxeles)
|
||||||
|
game.height 240 # Alto de la resolución nativa del juego (en píxeles)
|
||||||
|
game.play_area.rect.x 0 # Posición X de la zona jugable
|
||||||
|
game.play_area.rect.y 0 # Posición Y de la zona jugable
|
||||||
|
game.play_area.rect.w 320 # Ancho de la zona jugable
|
||||||
|
game.play_area.rect.h 200 # Alto de la zona jugable
|
||||||
|
game.name_entry_idle_time 10 # Segundos para introducir el nombre al finalizar la partida si no se pulsa nada
|
||||||
|
game.name_entry_total_time 60 # Segundos totales para introducir el nombre al finalizar la partida
|
||||||
|
game.hit_stop false # Indica si debe haber un paro cuando el jugador es golpeado por un globo
|
||||||
|
game.hit_stop_ms 500 # Cantidad de milisegundos que dura el hit_stop
|
||||||
|
|
||||||
|
# --- FADE ---
|
||||||
|
fade.color 1F2B30 # Color hexadecimal para el efecto de fundido
|
||||||
|
fade.num_squares_width 64 # Número de cuadrados en el eje X para el fundido
|
||||||
|
fade.num_squares_height 48 # Número de cuadrados en el eje Y para el fundido
|
||||||
|
fade.random_squares_duration_ms 1200 # Duración del fade en milisegundos
|
||||||
|
fade.post_duration_ms 500 # Duración tras el fundido en milisegundos
|
||||||
|
fade.venetian_size 12 # Tamaño de las bandas para el efecto veneciano (en píxeles)
|
||||||
|
|
||||||
|
# --- SCOREBOARD ---
|
||||||
|
scoreboard.rect.x 0 # Posición X del marcador
|
||||||
|
scoreboard.rect.y 216 # Posición Y del marcador
|
||||||
|
scoreboard.rect.w 320 # Ancho del marcador
|
||||||
|
scoreboard.rect.h 40 # Alto del marcador
|
||||||
|
scoreboard.separator_autocolor true # ¿El separador usa color automático?
|
||||||
|
scoreboard.separator_color 0D1A2B # Color del separador (hexadecimal)
|
||||||
|
scoreboard.easy_color 4B692F # Color para la dificultad fácil
|
||||||
|
scoreboard.normal_color 2E3F47 # Color para la dificultad normal
|
||||||
|
scoreboard.hard_color 76428A # Color para la dificultad difícil
|
||||||
|
scoreboard.text_autocolor true # ¿El texto usa color automático?
|
||||||
|
scoreboard.text_color1 FFFFFF # Color principal del texto del marcador
|
||||||
|
scoreboard.text_color2 FFFFFF # Color secundario del texto del marcador
|
||||||
|
scoreboard.skip_countdown_value 8 # Valor para saltar la cuenta atrás (segundos)
|
||||||
|
|
||||||
|
# --- TITLE ---
|
||||||
|
title.press_start_position 180 # Posición Y del texto "Press Start"
|
||||||
|
title.title_duration 800 # Duración de la pantalla de título (frames)
|
||||||
|
title.arcade_edition_position 123 # Posición Y del subtítulo "Arcade Edition"
|
||||||
|
title.title_c_c_position 80 # Posición Y del título principal
|
||||||
|
title.bg_color 41526F # Color de fondo en la sección titulo
|
||||||
|
|
||||||
|
# --- BACKGROUND ---
|
||||||
|
background.attenuate_color FFFFFF00 # Color de atenuación del fondo (RGBA hexadecimal)
|
||||||
|
|
||||||
|
# --- BALLOONS ---
|
||||||
|
balloon.settings[0].vel 2.75f # Velocidad inicial del globo 1
|
||||||
|
balloon.settings[0].grav 0.09f # Gravedad aplicada al globo 1
|
||||||
|
balloon.settings[1].vel 3.70f # Velocidad inicial del globo 2
|
||||||
|
balloon.settings[1].grav 0.10f # Gravedad aplicada al globo 2
|
||||||
|
balloon.settings[2].vel 4.70f # Velocidad inicial del globo 3
|
||||||
|
balloon.settings[2].grav 0.10f # Gravedad aplicada al globo 3
|
||||||
|
balloon.settings[3].vel 5.45f # Velocidad inicial del globo 4
|
||||||
|
balloon.settings[3].grav 0.10f # Gravedad aplicada al globo 4
|
||||||
|
|
||||||
|
balloon.color[0] blue # Color de creación del globo normal
|
||||||
|
balloon.color[1] orange # Color del globo normal
|
||||||
|
balloon.color[2] red # Color de creación del globo que rebota
|
||||||
|
balloon.color[3] green # Color del globo que rebota
|
||||||
|
|
||||||
|
balloon.bouncing_sound false # Indica si los globos hacer sonido al rebotar
|
||||||
|
|
||||||
|
# --- NOTIFICATION ---
|
||||||
|
notification.pos_v TOP # Posición vertical de la notificación (TOP/BOTTOM)
|
||||||
|
notification.pos_h LEFT # Posición horizontal de la notificación (LEFT/RIGHT)
|
||||||
|
notification.sound false # ¿La notificación reproduce sonido?
|
||||||
|
notification.color 303030 # Color de fondo de la notificación (hexadecimal)
|
||||||
|
|
||||||
|
# --- SERVICE MENU ---
|
||||||
|
service_menu.title_color 99FF62 # Color del título del menú de servicio
|
||||||
|
service_menu.text_color FFFFFF # Color del texto del menú de servicio
|
||||||
|
service_menu.selected_color FFDC44 # Color de la opción seleccionada en el menú de servicio
|
||||||
|
service_menu.bg_color 000F00F5 # Color de fondo del menú de servicio (RGBA hexadecimal)
|
||||||
|
service_menu.drop_shadow false # ¿El menú de servicio tiene sombra?
|
||||||
|
|
||||||
|
service_menu.window_message.bg_color 141E32F0 # Color de fondo de ventanas de mensaje (RGBA hexadecimal)
|
||||||
|
service_menu.window_message.border_color 6496C8FF # Color del borde de ventanas de mensaje (RGBA hexadecimal)
|
||||||
|
service_menu.window_message.title_color 6496C8FF # Color del título en ventanas de mensaje (RGBA hexadecimal)
|
||||||
|
service_menu.window_message.text_color DCDCDCFF # Color del texto en ventanas de mensaje (RGBA hexadecimal)
|
||||||
|
service_menu.window_message.padding 15.0f # Espaciado interno de ventanas de mensaje (píxeles)
|
||||||
|
service_menu.window_message.line_spacing 5.0f # Espaciado entre líneas de texto (píxeles)
|
||||||
|
service_menu.window_message.title_separator_spacing 20.0f # Espaciado entre título y contenido (píxeles)
|
||||||
|
service_menu.window_message.min_width 200.0f # Ancho mínimo de ventanas de mensaje (píxeles)
|
||||||
|
service_menu.window_message.min_height 32.0f # Alto mínimo de ventanas de mensaje (píxeles)
|
||||||
|
service_menu.window_message.max_width_ratio 0.8f # Ratio máximo de ancho respecto a pantalla (0.0-1.0)
|
||||||
|
service_menu.window_message.max_height_ratio 0.8f # Ratio máximo de alto respecto a pantalla (0.0-1.0)
|
||||||
|
service_menu.window_message.text_safety_margin 15.0f # Margen de seguridad para el texto (píxeles)
|
||||||
|
service_menu.window_message.animation_duration 0.3f # Duración de animaciones de ventanas (segundos)
|
||||||
|
|
||||||
|
# --- INTRO ---
|
||||||
|
intro.bg_color 4664BD # Color de fondo de la intro
|
||||||
|
intro.card_color CBDBFC # Color de las tarjetas en la intro
|
||||||
|
intro.shadow_color 00000080 # Color de la sombra de las tarjetas en la intro
|
||||||
|
intro.text_distance_from_bottom 48 # Posicion del texto
|
||||||
|
|
||||||
|
# --- DEBUG ---
|
||||||
|
debug.color 00FFFF # Color para elementos de depuración
|
||||||
|
|
||||||
|
# --- RESOURCE ---
|
||||||
|
resource.color FFFFFF # Color de recurso 1
|
||||||
|
resource.color FFFFFF # Color de recurso 2
|
||||||
|
|
||||||
|
# --- TABE ---
|
||||||
|
tabe.min_spawn_time 2.0f # Tiempo mínimo en minutos para que aparezca el Tabe
|
||||||
|
tabe.max_spawn_time 3.0f # Tiempo máximo en minutos para que aparezca el Tabe
|
||||||
|
|
||||||
|
# --- PLAYER ---
|
||||||
|
# Jugador 1 - Camiseta por defecto
|
||||||
|
player.default_shirt[0].darkest 028ECFFF # Tono más oscuro - bordes y contornos (Jugador 1, por defecto)
|
||||||
|
player.default_shirt[0].dark 0297DBFF # Tono oscuro - sombras (Jugador 1, por defecto)
|
||||||
|
player.default_shirt[0].base 029FE8FF # Tono principal - color base (Jugador 1, por defecto)
|
||||||
|
player.default_shirt[0].light 03A9F4FF # Tono claro - zonas iluminadas (Jugador 1, por defecto)
|
||||||
|
|
||||||
|
# Jugador 2 - Camiseta por defecto
|
||||||
|
player.default_shirt[1].darkest 8E8E8EFF # Tono más oscuro - bordes y contornos (Jugador 2, por defecto)
|
||||||
|
player.default_shirt[1].dark AEADADFF # Tono oscuro - sombras (Jugador 2, por defecto)
|
||||||
|
player.default_shirt[1].base E4E4E4FF # Tono principal - color base (Jugador 2, por defecto)
|
||||||
|
player.default_shirt[1].light F7F1F1FF # Tono claro - zonas iluminadas (Jugador 2, por defecto)
|
||||||
|
|
||||||
|
# Jugador 1 - Camiseta con 1 café
|
||||||
|
player.one_coffee_shirt[0].darkest 3D9C70FF # Tono más oscuro - bordes y contornos (Jugador 1, 1 café)
|
||||||
|
player.one_coffee_shirt[0].dark 4FA370FF # Tono oscuro - sombras (Jugador 1, 1 café)
|
||||||
|
player.one_coffee_shirt[0].base 5DDE70FF # Tono principal - color base (Jugador 1, 1 café)
|
||||||
|
player.one_coffee_shirt[0].light 7DF25CFF # Tono claro - zonas iluminadas (Jugador 1, 1 café)
|
||||||
|
|
||||||
|
# Jugador 1 - Camiseta con 2 cafés
|
||||||
|
player.two_coffee_shirt[0].darkest D6A41AFF # Tono más oscuro - bordes y contornos (Jugador 1, 2 cafés)
|
||||||
|
player.two_coffee_shirt[0].dark E3AE1BFF # Tono oscuro - sombras (Jugador 1, 2 cafés)
|
||||||
|
player.two_coffee_shirt[0].base EFB71DFF # Tono principal - color base (Jugador 1, 2 cafés)
|
||||||
|
player.two_coffee_shirt[0].light FCC11EFF # Tono claro - zonas iluminadas (Jugador 1, 2 cafés)
|
||||||
|
|
||||||
|
# Jugador 2 - Camiseta con 1 café
|
||||||
|
player.one_coffee_shirt[1].darkest 2E8B57FF # Tono más oscuro - bordes y contornos (Jugador 2, 1 café)
|
||||||
|
player.one_coffee_shirt[1].dark 3CB371FF # Tono oscuro - sombras (Jugador 2, 1 café)
|
||||||
|
player.one_coffee_shirt[1].base 48D181FF # Tono principal - color base (Jugador 2, 1 café)
|
||||||
|
player.one_coffee_shirt[1].light 55EF8DFF # Tono claro - zonas iluminadas (Jugador 2, 1 café)
|
||||||
|
|
||||||
|
# Jugador 2 - Camiseta con 2 cafés
|
||||||
|
player.two_coffee_shirt[1].darkest E08500FF # Tono más oscuro - bordes y contornos (Jugador 2, 2 cafés)
|
||||||
|
player.two_coffee_shirt[1].dark FA7D00FF # Tono oscuro - sombras (Jugador 2, 2 cafés)
|
||||||
|
player.two_coffee_shirt[1].base FAA200FF # Tono principal - color base (Jugador 2, 2 cafés)
|
||||||
|
player.two_coffee_shirt[1].light FA8500FF # Tono claro - zonas iluminadas (Jugador 2, 2 cafés)
|
||||||
|
|
||||||
|
# Colores de contorno de los jugadores
|
||||||
|
player.outline_color[0] 66323FFF # Color del contorno del sprite del Jugador 1
|
||||||
|
player.outline_color[1] 422028FF # Color del contorno del sprite del Jugador 2
|
||||||
150
config/param_320x256.txt
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
# Coffee Crisis Arcade Edition - Fichero de parametros
|
||||||
|
# Formato: PARAMETRO VALOR
|
||||||
|
|
||||||
|
# --- GAME ---
|
||||||
|
game.item_size 20 # Tamaño de los items del juego (en píxeles)
|
||||||
|
game.item_text_outline_color E0E0E0F0 # Color del outline del texto de los items (RGBA hex)
|
||||||
|
game.width 320 # Ancho de la resolución nativa del juego (en píxeles)
|
||||||
|
game.height 256 # Alto de la resolución nativa del juego (en píxeles)
|
||||||
|
game.play_area.rect.x 0 # Posición X de la zona jugable
|
||||||
|
game.play_area.rect.y 0 # Posición Y de la zona jugable
|
||||||
|
game.play_area.rect.w 320 # Ancho de la zona jugable
|
||||||
|
game.play_area.rect.h 216 # Alto de la zona jugable
|
||||||
|
game.name_entry_idle_time 10 # Segundos para introducir el nombre al finalizar la partida si no se pulsa nada
|
||||||
|
game.name_entry_total_time 60 # Segundos totales para introducir el nombre al finalizar la partida
|
||||||
|
game.hit_stop false # Indica si debe haber un paro cuando el jugador es golpeado por un globo
|
||||||
|
game.hit_stop_ms 500 # Cantidad de milisegundos que dura el hit_stop
|
||||||
|
|
||||||
|
# --- FADE ---
|
||||||
|
fade.color 1F2B30 # Color hexadecimal para el efecto de fundido
|
||||||
|
fade.num_squares_width 64 # Número de cuadrados en el eje X para el fundido
|
||||||
|
fade.num_squares_height 48 # Número de cuadrados en el eje Y para el fundido
|
||||||
|
fade.random_squares_duration_ms 1200 # Duración del fade en milisegundos
|
||||||
|
fade.post_duration_ms 500 # Duración tras el fundido en milisegundos
|
||||||
|
fade.venetian_size 12 # Tamaño de las bandas para el efecto veneciano (en píxeles)
|
||||||
|
|
||||||
|
# --- SCOREBOARD ---
|
||||||
|
scoreboard.rect.x 0 # Posición X del marcador
|
||||||
|
scoreboard.rect.y 216 # Posición Y del marcador
|
||||||
|
scoreboard.rect.w 320 # Ancho del marcador
|
||||||
|
scoreboard.rect.h 40 # Alto del marcador
|
||||||
|
scoreboard.separator_autocolor true # ¿El separador usa color automático?
|
||||||
|
scoreboard.separator_color 0D1A2B # Color del separador (hexadecimal)
|
||||||
|
scoreboard.easy_color 4B692F # Color para la dificultad fácil
|
||||||
|
scoreboard.normal_color 2E3F47 # Color para la dificultad normal
|
||||||
|
scoreboard.hard_color 76428A # Color para la dificultad difícil
|
||||||
|
scoreboard.text_autocolor true # ¿El texto usa color automático?
|
||||||
|
scoreboard.text_color1 FFFFFF # Color principal del texto del marcador
|
||||||
|
scoreboard.text_color2 FFFFFF # Color secundario del texto del marcador
|
||||||
|
scoreboard.skip_countdown_value 8 # Valor para saltar la cuenta atrás (segundos)
|
||||||
|
|
||||||
|
# --- TITLE ---
|
||||||
|
title.press_start_position 180 # Posición Y del texto "Press Start"
|
||||||
|
title.title_duration 800 # Duración de la pantalla de título (frames)
|
||||||
|
title.arcade_edition_position 123 # Posición Y del subtítulo "Arcade Edition"
|
||||||
|
title.title_c_c_position 80 # Posición Y del título principal
|
||||||
|
title.bg_color 41526F # Color de fondo en la sección titulo
|
||||||
|
|
||||||
|
# --- BACKGROUND ---
|
||||||
|
background.attenuate_color FFFFFF00 # Color de atenuación del fondo (RGBA hexadecimal)
|
||||||
|
|
||||||
|
# --- BALLOONS ---
|
||||||
|
balloon.settings[0].vel 2.75f # Velocidad inicial del globo 1
|
||||||
|
balloon.settings[0].grav 0.09f # Gravedad aplicada al globo 1
|
||||||
|
balloon.settings[1].vel 3.70f # Velocidad inicial del globo 2
|
||||||
|
balloon.settings[1].grav 0.10f # Gravedad aplicada al globo 2
|
||||||
|
balloon.settings[2].vel 4.70f # Velocidad inicial del globo 3
|
||||||
|
balloon.settings[2].grav 0.10f # Gravedad aplicada al globo 3
|
||||||
|
balloon.settings[3].vel 5.45f # Velocidad inicial del globo 4
|
||||||
|
balloon.settings[3].grav 0.10f # Gravedad aplicada al globo 4
|
||||||
|
|
||||||
|
balloon.color[0] blue # Color de creación del globo normal
|
||||||
|
balloon.color[1] orange # Color del globo normal
|
||||||
|
balloon.color[2] red # Color de creación del globo que rebota
|
||||||
|
balloon.color[3] green # Color del globo que rebota
|
||||||
|
|
||||||
|
balloon.bouncing_sound false # Indica si los globos hacer sonido al rebotar
|
||||||
|
|
||||||
|
# --- NOTIFICATION ---
|
||||||
|
notification.pos_v TOP # Posición vertical de la notificación (TOP/BOTTOM)
|
||||||
|
notification.pos_h LEFT # Posición horizontal de la notificación (LEFT/RIGHT)
|
||||||
|
notification.sound false # ¿La notificación reproduce sonido?
|
||||||
|
notification.color 303030 # Color de fondo de la notificación (hexadecimal)
|
||||||
|
|
||||||
|
# --- SERVICE MENU ---
|
||||||
|
service_menu.title_color 99FF62 # Color del título del menú de servicio
|
||||||
|
service_menu.text_color FFFFFF # Color del texto del menú de servicio
|
||||||
|
service_menu.selected_color FFDC44 # Color de la opción seleccionada en el menú de servicio
|
||||||
|
service_menu.bg_color 000F00F5 # Color de fondo del menú de servicio (RGBA hexadecimal)
|
||||||
|
service_menu.drop_shadow false # ¿El menú de servicio tiene sombra?
|
||||||
|
|
||||||
|
service_menu.window_message.bg_color 141E32F0 # Color de fondo de ventanas de mensaje (RGBA hexadecimal)
|
||||||
|
service_menu.window_message.border_color 6496C8FF # Color del borde de ventanas de mensaje (RGBA hexadecimal)
|
||||||
|
service_menu.window_message.title_color 6496C8FF # Color del título en ventanas de mensaje (RGBA hexadecimal)
|
||||||
|
service_menu.window_message.text_color DCDCDCFF # Color del texto en ventanas de mensaje (RGBA hexadecimal)
|
||||||
|
service_menu.window_message.padding 15.0f # Espaciado interno de ventanas de mensaje (píxeles)
|
||||||
|
service_menu.window_message.line_spacing 5.0f # Espaciado entre líneas de texto (píxeles)
|
||||||
|
service_menu.window_message.title_separator_spacing 20.0f # Espaciado entre título y contenido (píxeles)
|
||||||
|
service_menu.window_message.min_width 200.0f # Ancho mínimo de ventanas de mensaje (píxeles)
|
||||||
|
service_menu.window_message.min_height 32.0f # Alto mínimo de ventanas de mensaje (píxeles)
|
||||||
|
service_menu.window_message.max_width_ratio 0.8f # Ratio máximo de ancho respecto a pantalla (0.0-1.0)
|
||||||
|
service_menu.window_message.max_height_ratio 0.8f # Ratio máximo de alto respecto a pantalla (0.0-1.0)
|
||||||
|
service_menu.window_message.text_safety_margin 15.0f # Margen de seguridad para el texto (píxeles)
|
||||||
|
service_menu.window_message.animation_duration 0.3f # Duración de animaciones de ventanas (segundos)
|
||||||
|
|
||||||
|
# --- INTRO ---
|
||||||
|
intro.bg_color 4664BD # Color de fondo de la intro
|
||||||
|
intro.card_color CBDBFC # Color de las tarjetas en la intro
|
||||||
|
intro.shadow_color 00000080 # Color de la sombra de las tarjetas en la intro
|
||||||
|
intro.text_distance_from_bottom 48 # Posición del texto desde la parte inferior
|
||||||
|
|
||||||
|
# --- DEBUG ---
|
||||||
|
debug.color 00FFFF # Color para elementos de depuración
|
||||||
|
|
||||||
|
# --- RESOURCE ---
|
||||||
|
resource.color FFFFFF # Color de recursos
|
||||||
|
|
||||||
|
# --- TABE ---
|
||||||
|
tabe.min_spawn_time 2.0f # Tiempo mínimo en segundos para que aparezca el Tabe
|
||||||
|
tabe.max_spawn_time 3.0f # Tiempo máximo en segundos para que aparezca el Tabe
|
||||||
|
|
||||||
|
# --- PLAYER ---
|
||||||
|
# Jugador 1 - Camiseta por defecto
|
||||||
|
player.default_shirt[0].darkest 028ECFFF # Tono más oscuro - bordes y contornos (Jugador 1, por defecto)
|
||||||
|
player.default_shirt[0].dark 0297DBFF # Tono oscuro - sombras (Jugador 1, por defecto)
|
||||||
|
player.default_shirt[0].base 029FE8FF # Tono principal - color base (Jugador 1, por defecto)
|
||||||
|
player.default_shirt[0].light 03A9F4FF # Tono claro - zonas iluminadas (Jugador 1, por defecto)
|
||||||
|
|
||||||
|
# Jugador 2 - Camiseta por defecto
|
||||||
|
player.default_shirt[1].darkest 8E8E8EFF # Tono más oscuro - bordes y contornos (Jugador 2, por defecto)
|
||||||
|
player.default_shirt[1].dark AEADADFF # Tono oscuro - sombras (Jugador 2, por defecto)
|
||||||
|
player.default_shirt[1].base E4E4E4FF # Tono principal - color base (Jugador 2, por defecto)
|
||||||
|
player.default_shirt[1].light F7F1F1FF # Tono claro - zonas iluminadas (Jugador 2, por defecto)
|
||||||
|
|
||||||
|
# Jugador 1 - Camiseta con 1 café
|
||||||
|
player.one_coffee_shirt[0].darkest 3D9C70FF # Tono más oscuro - bordes y contornos (Jugador 1, 1 café)
|
||||||
|
player.one_coffee_shirt[0].dark 4FA370FF # Tono oscuro - sombras (Jugador 1, 1 café)
|
||||||
|
player.one_coffee_shirt[0].base 5DDE70FF # Tono principal - color base (Jugador 1, 1 café)
|
||||||
|
player.one_coffee_shirt[0].light 7DF25CFF # Tono claro - zonas iluminadas (Jugador 1, 1 café)
|
||||||
|
|
||||||
|
# Jugador 1 - Camiseta con 2 cafés
|
||||||
|
player.two_coffee_shirt[0].darkest D6A41AFF # Tono más oscuro - bordes y contornos (Jugador 1, 2 cafés)
|
||||||
|
player.two_coffee_shirt[0].dark E3AE1BFF # Tono oscuro - sombras (Jugador 1, 2 cafés)
|
||||||
|
player.two_coffee_shirt[0].base EFB71DFF # Tono principal - color base (Jugador 1, 2 cafés)
|
||||||
|
player.two_coffee_shirt[0].light FCC11EFF # Tono claro - zonas iluminadas (Jugador 1, 2 cafés)
|
||||||
|
|
||||||
|
# Jugador 2 - Camiseta con 1 café
|
||||||
|
player.one_coffee_shirt[1].darkest 2E8B57FF # Tono más oscuro - bordes y contornos (Jugador 2, 1 café)
|
||||||
|
player.one_coffee_shirt[1].dark 3CB371FF # Tono oscuro - sombras (Jugador 2, 1 café)
|
||||||
|
player.one_coffee_shirt[1].base 48D181FF # Tono principal - color base (Jugador 2, 1 café)
|
||||||
|
player.one_coffee_shirt[1].light 55EF8DFF # Tono claro - zonas iluminadas (Jugador 2, 1 café)
|
||||||
|
|
||||||
|
# Jugador 2 - Camiseta con 2 cafés
|
||||||
|
player.two_coffee_shirt[1].darkest E08500FF # Tono más oscuro - bordes y contornos (Jugador 2, 2 cafés)
|
||||||
|
player.two_coffee_shirt[1].dark FA7D00FF # Tono oscuro - sombras (Jugador 2, 2 cafés)
|
||||||
|
player.two_coffee_shirt[1].base FAA200FF # Tono principal - color base (Jugador 2, 2 cafés)
|
||||||
|
player.two_coffee_shirt[1].light FA8500FF # Tono claro - zonas iluminadas (Jugador 2, 2 cafés)
|
||||||
|
|
||||||
|
# Colores de contorno de los jugadores
|
||||||
|
player.outline_color[0] 66323FFF # Color del contorno del sprite del Jugador 1
|
||||||
|
player.outline_color[1] 422028FF # Color del contorno del sprite del Jugador 2
|
||||||
150
config/param_red.txt
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
# Coffee Crisis Arcade Edition - Fichero de parametros - RED THEME
|
||||||
|
# Formato: PARAMETRO VALOR
|
||||||
|
|
||||||
|
# --- GAME ---
|
||||||
|
game.item_size 20 # Tamaño de los items del juego (en píxeles)
|
||||||
|
game.item_text_outline_color FFB8B8F0 # Color del outline del texto de los items (RGBA hex) - Rojo claro
|
||||||
|
game.width 320 # Ancho de la resolución nativa del juego (en píxeles)
|
||||||
|
game.height 256 # Alto de la resolución nativa del juego (en píxeles)
|
||||||
|
game.play_area.rect.x 0 # Posición X de la zona jugable
|
||||||
|
game.play_area.rect.y 0 # Posición Y de la zona jugable
|
||||||
|
game.play_area.rect.w 320 # Ancho de la zona jugable
|
||||||
|
game.play_area.rect.h 216 # Alto de la zona jugable
|
||||||
|
game.name_entry_idle_time 10 # Segundos para introducir el nombre al finalizar la partida si no se pulsa nada
|
||||||
|
game.name_entry_total_time 60 # Segundos totales para introducir el nombre al finalizar la partida
|
||||||
|
game.hit_stop false # Indica si debe haber un paro cuando el jugador es golpeado por un globo
|
||||||
|
game.hit_stop_ms 500 # Cantidad de milisegundos que dura el hit_stop
|
||||||
|
|
||||||
|
# --- FADE ---
|
||||||
|
fade.color 5C1F1F # Color hexadecimal para el efecto de fundido - Rojo oscuro
|
||||||
|
fade.num_squares_width 64 # Número de cuadrados en el eje X para el fundido
|
||||||
|
fade.num_squares_height 48 # Número de cuadrados en el eje Y para el fundido
|
||||||
|
fade.random_squares_duration_ms 1200 # Duración del fade en milisegundos
|
||||||
|
fade.post_duration_ms 500 # Duración tras el fundido en milisegundos
|
||||||
|
fade.venetian_size 12 # Tamaño de las bandas para el efecto veneciano (en píxeles)
|
||||||
|
|
||||||
|
# --- SCOREBOARD ---
|
||||||
|
scoreboard.rect.x 0 # Posición X del marcador
|
||||||
|
scoreboard.rect.y 216 # Posición Y del marcador
|
||||||
|
scoreboard.rect.w 320 # Ancho del marcador
|
||||||
|
scoreboard.rect.h 40 # Alto del marcador
|
||||||
|
scoreboard.separator_autocolor true # ¿El separador usa color automático?
|
||||||
|
scoreboard.separator_color 2B0D0D # Color del separador - Rojo muy oscuro
|
||||||
|
scoreboard.easy_color 8B4A2F # Color para la dificultad fácil - Marrón rojizo
|
||||||
|
scoreboard.normal_color 6B2F2F # Color para la dificultad normal - Rojo medio
|
||||||
|
scoreboard.hard_color A73030 # Color para la dificultad difícil - Rojo fuerte
|
||||||
|
scoreboard.text_autocolor true # ¿El texto usa color automático?
|
||||||
|
scoreboard.text_color1 FFE6E6 # Color principal del texto del marcador - Blanco rosado
|
||||||
|
scoreboard.text_color2 FFE6E6 # Color secundario del texto del marcador - Blanco rosado
|
||||||
|
scoreboard.skip_countdown_value 8 # Valor para saltar la cuenta atrás (segundos)
|
||||||
|
|
||||||
|
# --- TITLE ---
|
||||||
|
title.press_start_position 180 # Posición Y del texto "Press Start"
|
||||||
|
title.title_duration 800 # Duración de la pantalla de título (frames)
|
||||||
|
title.arcade_edition_position 123 # Posición Y del subtítulo "Arcade Edition"
|
||||||
|
title.title_c_c_position 80 # Posición Y del título principal
|
||||||
|
title.bg_color 8B4A3A # Color de fondo en la sección titulo - Marrón rojizo
|
||||||
|
|
||||||
|
# --- BACKGROUND ---
|
||||||
|
background.attenuate_color FF4A3A40 # Color de atenuación del fondo (RGBA hexadecimal) - Blanco rosado
|
||||||
|
|
||||||
|
# --- BALLOONS ---
|
||||||
|
balloon.settings[0].vel 2.75f # Velocidad inicial del globo 1
|
||||||
|
balloon.settings[0].grav 0.09f # Gravedad aplicada al globo 1
|
||||||
|
balloon.settings[1].vel 3.70f # Velocidad inicial del globo 2
|
||||||
|
balloon.settings[1].grav 0.10f # Gravedad aplicada al globo 2
|
||||||
|
balloon.settings[2].vel 4.70f # Velocidad inicial del globo 3
|
||||||
|
balloon.settings[2].grav 0.10f # Gravedad aplicada al globo 3
|
||||||
|
balloon.settings[3].vel 5.45f # Velocidad inicial del globo 4
|
||||||
|
balloon.settings[3].grav 0.10f # Gravedad aplicada al globo 4
|
||||||
|
|
||||||
|
balloon.color[0] orange # Color de creación del globo normal
|
||||||
|
balloon.color[1] red # Color del globo normal
|
||||||
|
balloon.color[2] blue # Color de creación del globo que rebota
|
||||||
|
balloon.color[3] green # Color del globo que rebota
|
||||||
|
|
||||||
|
balloon.bouncing_sound false # Indica si los globos hacer sonido al rebotar
|
||||||
|
|
||||||
|
# --- NOTIFICATION ---
|
||||||
|
notification.pos_v TOP # Posición vertical de la notificación (TOP/BOTTOM)
|
||||||
|
notification.pos_h LEFT # Posición horizontal de la notificación (LEFT/RIGHT)
|
||||||
|
notification.sound false # ¿La notificación reproduce sonido?
|
||||||
|
notification.color 4D1A1A # Color de fondo de la notificación - Rojo oscuro
|
||||||
|
|
||||||
|
# --- SERVICE MENU ---
|
||||||
|
service_menu.title_color FF9966 # Color del título del menú de servicio - Naranja claro
|
||||||
|
service_menu.text_color FFE6E6 # Color del texto del menú de servicio - Blanco rosado
|
||||||
|
service_menu.selected_color FFB366 # Color de la opción seleccionada - Naranja dorado
|
||||||
|
service_menu.bg_color 331A0AF5 # Color de fondo del menú de servicio - Marrón rojizo oscuro con alpha
|
||||||
|
service_menu.drop_shadow false # ¿El menú de servicio tiene sombra?
|
||||||
|
|
||||||
|
service_menu.window_message.bg_color 4D1A1AF0 # Color de fondo de ventanas - Rojo oscuro con alpha
|
||||||
|
service_menu.window_message.border_color CC6633FF # Color del borde de ventanas - Naranja rojizo
|
||||||
|
service_menu.window_message.title_color CC6633FF # Color del título en ventanas - Naranja rojizo
|
||||||
|
service_menu.window_message.text_color FFE6E6FF # Color del texto en ventanas - Blanco rosado
|
||||||
|
service_menu.window_message.padding 15.0f # Espaciado interno de ventanas de mensaje (píxeles)
|
||||||
|
service_menu.window_message.line_spacing 5.0f # Espaciado entre líneas de texto (píxeles)
|
||||||
|
service_menu.window_message.title_separator_spacing 20.0f # Espaciado entre título y contenido (píxeles)
|
||||||
|
service_menu.window_message.min_width 200.0f # Ancho mínimo de ventanas de mensaje (píxeles)
|
||||||
|
service_menu.window_message.min_height 32.0f # Alto mínimo de ventanas de mensaje (píxeles)
|
||||||
|
service_menu.window_message.max_width_ratio 0.8f # Ratio máximo de ancho respecto a pantalla (0.0-1.0)
|
||||||
|
service_menu.window_message.max_height_ratio 0.8f # Ratio máximo de alto respecto a pantalla (0.0-1.0)
|
||||||
|
service_menu.window_message.text_safety_margin 15.0f # Margen de seguridad para el texto (píxeles)
|
||||||
|
service_menu.window_message.animation_duration 0.3f # Duración de animaciones de ventanas (segundos)
|
||||||
|
|
||||||
|
# --- INTRO ---
|
||||||
|
intro.bg_color B8664D # Color de fondo de la intro - Naranja tierra
|
||||||
|
intro.card_color FFE6CC # Color de las tarjetas en la intro - Crema rojizo
|
||||||
|
intro.shadow_color 66000080 # Color de la sombra de las tarjetas - Rojo muy oscuro con alpha
|
||||||
|
intro.text_distance_from_bottom 48 # Posición del texto desde la parte inferior
|
||||||
|
|
||||||
|
# --- DEBUG ---
|
||||||
|
debug.color FF6666 # Color para elementos de depuración - Rojo claro
|
||||||
|
|
||||||
|
# --- RESOURCE ---
|
||||||
|
resource.color FFE6E6 # Color de recursos - Blanco rosado
|
||||||
|
|
||||||
|
# --- TABE ---
|
||||||
|
tabe.min_spawn_time 2.0f # Tiempo mínimo en segundos para que aparezca el Tabe
|
||||||
|
tabe.max_spawn_time 3.0f # Tiempo máximo en segundos para que aparezca el Tabe
|
||||||
|
|
||||||
|
# --- PLAYER ---
|
||||||
|
# Jugador 1 - Camiseta por defecto (tonos rojos)
|
||||||
|
player.default_shirt[0].darkest B33030FF # Tono más oscuro - Rojo fuerte
|
||||||
|
player.default_shirt[0].dark CC4040FF # Tono oscuro - Rojo medio
|
||||||
|
player.default_shirt[0].base E65050FF # Tono principal - Rojo claro
|
||||||
|
player.default_shirt[0].light FF6666FF # Tono claro - Rojo muy claro
|
||||||
|
|
||||||
|
# Jugador 2 - Camiseta por defecto (tonos naranjas)
|
||||||
|
player.default_shirt[1].darkest B36030FF # Tono más oscuro - Naranja oscuro
|
||||||
|
player.default_shirt[1].dark CC7540FF # Tono oscuro - Naranja medio
|
||||||
|
player.default_shirt[1].base E68A50FF # Tono principal - Naranja claro
|
||||||
|
player.default_shirt[1].light FF9966FF # Tono claro - Naranja muy claro
|
||||||
|
|
||||||
|
# Jugador 1 - Camiseta con 1 café (tonos rojizos más intensos)
|
||||||
|
player.one_coffee_shirt[0].darkest 8B2635FF # Tono más oscuro - Rojo granate
|
||||||
|
player.one_coffee_shirt[0].dark A53040FF # Tono oscuro - Rojo granate claro
|
||||||
|
player.one_coffee_shirt[0].base BF3A50FF # Tono principal - Rojo vibrante
|
||||||
|
player.one_coffee_shirt[0].light D94460FF # Tono claro - Rojo vibrante claro
|
||||||
|
|
||||||
|
# Jugador 1 - Camiseta con 2 cafés (tonos naranja dorado)
|
||||||
|
player.two_coffee_shirt[0].darkest CC6600FF # Tono más oscuro - Naranja dorado oscuro
|
||||||
|
player.two_coffee_shirt[0].dark E6750AFF # Tono oscuro - Naranja dorado
|
||||||
|
player.two_coffee_shirt[0].base FF8514FF # Tono principal - Naranja dorado claro
|
||||||
|
player.two_coffee_shirt[0].light FF991EFF # Tono claro - Naranja dorado muy claro
|
||||||
|
|
||||||
|
# Jugador 2 - Camiseta con 1 café (tonos terracotas)
|
||||||
|
player.one_coffee_shirt[1].darkest A0472DFF # Tono más oscuro - Terracota oscuro
|
||||||
|
player.one_coffee_shirt[1].dark B8553AFF # Tono oscuro - Terracota medio
|
||||||
|
player.one_coffee_shirt[1].base D06347FF # Tono principal - Terracota claro
|
||||||
|
player.one_coffee_shirt[1].light E87154FF # Tono claro - Terracota muy claro
|
||||||
|
|
||||||
|
# Jugador 2 - Camiseta con 2 cafés (tonos naranjas cálidos)
|
||||||
|
player.two_coffee_shirt[1].darkest CC5500FF # Tono más oscuro - Naranja intenso
|
||||||
|
player.two_coffee_shirt[1].dark E66600FF # Tono oscuro - Naranja fuerte
|
||||||
|
player.two_coffee_shirt[1].base FF7700FF # Tono principal - Naranja brillante
|
||||||
|
player.two_coffee_shirt[1].light FF8800FF # Tono claro - Naranja muy brillante
|
||||||
|
|
||||||
|
# Colores de contorno de los jugadores
|
||||||
|
player.outline_color[0] 994D33FF # Color del contorno del Jugador 1 - Marrón rojizo
|
||||||
|
player.outline_color[1] 664433FF # Color del contorno del Jugador 2 - Marrón tierra
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Archivo de configuración de pools de formaciones de globos
|
# Coffee Crisis Arcade Edition - Archivo de configuración de pools de formaciones de globos
|
||||||
# Formato: POOL: <id> FORMATIONS: <id1>, <id2>, <id3>, ...
|
# Formato: POOL: <id> FORMATIONS: <id1>, <id2>, <id3>, ...
|
||||||
# Los IDs de formación pueden repetirse
|
# Los IDs de formación pueden repetirse
|
||||||
# Los pools no necesitan estar ordenados ni ser consecutivos
|
# Los pools no necesitan estar ordenados ni ser consecutivos
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# Archivo de configuración de fases
|
# Coffee Crisis Arcade Edition - Archivo de configuración de fases
|
||||||
# Formato: power_to_complete,min_menace,max_menace,name
|
# Formato: power_to_complete,min_menace,max_menace,name
|
||||||
# Líneas que empiezan con # son comentarios y se ignoran
|
# Líneas que empiezan con # son comentarios y se ignoran
|
||||||
|
|
||||||
@@ -7,13 +7,13 @@
|
|||||||
300, 15, 23, Primeros pasos
|
300, 15, 23, Primeros pasos
|
||||||
|
|
||||||
# Fases intermedias - Incremento de dificultad
|
# Fases intermedias - Incremento de dificultad
|
||||||
600, 19, 27, Intensificación
|
400, 19, 27, Intensificación
|
||||||
600, 19, 27, Persistencia
|
400, 19, 27, Persistencia
|
||||||
600, 23, 31, Desafío medio
|
400, 23, 31, Desafío medio
|
||||||
600, 23, 31, Resistencia
|
400, 23, 31, Resistencia
|
||||||
|
|
||||||
# Fases avanzadas - Desafío final
|
# Fases avanzadas - Desafío final
|
||||||
650, 27, 35, Aproximación final
|
600, 27, 35, Aproximación final
|
||||||
750, 27, 35, Penúltimo obstáculo
|
600, 27, 35, Penúltimo obstáculo
|
||||||
850, 31, 39, Clímax
|
700, 31, 39, Clímax
|
||||||
950, 35, 47, Maestría
|
950, 35, 47, Maestría
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
## --- GAME ---
|
|
||||||
game.item_size 20 # Tamaño de los items del juego (en píxeles)
|
|
||||||
game.width 320 # Ancho de la resolución nativa del juego (en píxeles)
|
|
||||||
game.height 240 # Alto de la resolución nativa del juego (en píxeles)
|
|
||||||
game.play_area.rect.x 0 # Posición X de la zona jugable
|
|
||||||
game.play_area.rect.y 0 # Posición Y de la zona jugable
|
|
||||||
game.play_area.rect.w 320 # Ancho de la zona jugable
|
|
||||||
game.play_area.rect.h 200 # Alto de la zona jugable
|
|
||||||
game.name_entry_idle_time 10 # Segundos para introducir el nombre al finalizar la partida si no se pulsa nada
|
|
||||||
game.name_entry_total_time 60 # Segundos totales para introducir el nombre al finalizar la partida
|
|
||||||
game.hit_stop false # Indica si debe haber un paro cuando el jugador es golpeado por un globo
|
|
||||||
game.hit_stop_ms 500 # Cantidad de milisegundos que dura el hit_stop
|
|
||||||
|
|
||||||
## --- FADE ---
|
|
||||||
fade.color 1F2B30 # Color hexadecimal para el efecto de fundido
|
|
||||||
fade.num_squares_width 160 # Número de cuadrados en el eje X para el fundido
|
|
||||||
fade.num_squares_height 120 # Número de cuadrados en el eje Y para el fundido
|
|
||||||
fade.random_squares_delay 1 # Delay entre aparición de cuadrados aleatorios (frames)
|
|
||||||
fade.random_squares_mult 500 # Multiplicador para la velocidad de aparición aleatoria
|
|
||||||
fade.post_duration 80 # Duración tras el fundido (frames)
|
|
||||||
fade.venetian_size 12 # Tamaño de las bandas para el efecto veneciano (en píxeles)
|
|
||||||
|
|
||||||
## --- SCOREBOARD ---
|
|
||||||
scoreboard.rect.x 0 # Posición X del marcador
|
|
||||||
scoreboard.rect.y 216 # Posición Y del marcador
|
|
||||||
scoreboard.rect.w 320 # Ancho del marcador
|
|
||||||
scoreboard.rect.h 40 # Alto del marcador
|
|
||||||
scoreboard.separator_autocolor true # ¿El separador usa color automático?
|
|
||||||
scoreboard.separator_color 0D1A2B # Color del separador (hexadecimal)
|
|
||||||
scoreboard.easy_color 4B692F # Color para la dificultad fácil
|
|
||||||
scoreboard.normal_color 2E3F47 # Color para la dificultad normal
|
|
||||||
scoreboard.hard_color 76428A # Color para la dificultad difícil
|
|
||||||
scoreboard.text_autocolor true # ¿El texto usa color automático?
|
|
||||||
scoreboard.text_color1 FFFFFF # Color principal del texto del marcador
|
|
||||||
scoreboard.text_color2 FFFFFF # Color secundario del texto del marcador
|
|
||||||
scoreboard.skip_countdown_value 8 # Valor para saltar la cuenta atrás (segundos)
|
|
||||||
|
|
||||||
## --- TITLE ---
|
|
||||||
title.press_start_position 180 # Posición Y del texto "Press Start"
|
|
||||||
title.title_duration 800 # Duración de la pantalla de título (frames)
|
|
||||||
title.arcade_edition_position 123 # Posición Y del subtítulo "Arcade Edition"
|
|
||||||
title.title_c_c_position 80 # Posición Y del título principal
|
|
||||||
title.bg_color 41526F # Color de fondo en la sección titulo
|
|
||||||
|
|
||||||
## --- BACKGROUND ---
|
|
||||||
background.attenuate_color FFFFFF00 # Color de atenuación del fondo (RGBA hexadecimal)
|
|
||||||
|
|
||||||
## --- BALLOONS ---
|
|
||||||
balloon.settings[0].vel 2.75f # Velocidad inicial del globo 1
|
|
||||||
balloon.settings[0].grav 0.09f # Gravedad aplicada al globo 1
|
|
||||||
balloon.settings[1].vel 3.70f # Velocidad inicial del globo 2
|
|
||||||
balloon.settings[1].grav 0.10f # Gravedad aplicada al globo 2
|
|
||||||
balloon.settings[2].vel 4.70f # Velocidad inicial del globo 3
|
|
||||||
balloon.settings[2].grav 0.10f # Gravedad aplicada al globo 3
|
|
||||||
balloon.settings[3].vel 5.45f # Velocidad inicial del globo 4
|
|
||||||
balloon.settings[3].grav 0.10f # Gravedad aplicada al globo 4
|
|
||||||
|
|
||||||
balloon.color[0] blue # Color de creación del globo normal
|
|
||||||
balloon.color[1] orange # Color del globo normal
|
|
||||||
balloon.color[2] red # Color de creación del globo que rebota
|
|
||||||
balloon.color[3] green # Color del globo que rebota
|
|
||||||
|
|
||||||
balloon.bouncing_sound false # Indica si los globos hacer sonido al rebotar
|
|
||||||
|
|
||||||
## --- NOTIFICATION ---
|
|
||||||
notification.pos_v TOP # Posición vertical de la notificación (TOP/BOTTOM)
|
|
||||||
notification.pos_h LEFT # Posición horizontal de la notificación (LEFT/RIGHT)
|
|
||||||
notification.sound false # ¿La notificación reproduce sonido?
|
|
||||||
notification.color 303030 # Color de fondo de la notificación (hexadecimal)
|
|
||||||
|
|
||||||
## --- SERVICE MENU ---
|
|
||||||
service_menu.title_color 99FF62 # Color del título del menú de servicio
|
|
||||||
service_menu.text_color FFFFFF # Color del texto del menú de servicio
|
|
||||||
service_menu.selected_color FFDC44 # Color de la opción seleccionada en el menú de servicio
|
|
||||||
service_menu.bg_color 003000F5 # Color de fondo del menú de servicio (RGBA hexadecimal)
|
|
||||||
service_menu.drop_shadow false # ¿El menú de servicio tiene sombra?
|
|
||||||
|
|
||||||
## --- INTRO ---
|
|
||||||
intro.bg_color 4664BD # Color de fondo de la intro
|
|
||||||
intro.card_color CBDBFC # Color de las tarjetas en la intro
|
|
||||||
intro.shadow_color 00000080 # Color de la sombra de las tarjetas en la intro
|
|
||||||
intro.text_distance_from_bottom 48 # Posicion del texto
|
|
||||||
|
|
||||||
## --- DEBUG ---
|
|
||||||
debug.color 00FFFF # Color para elementos de depuración
|
|
||||||
|
|
||||||
## --- RESOURCE ---
|
|
||||||
resource.color FFFFFF # Color de recurso 1
|
|
||||||
resource.color FFFFFF # Color de recurso 2
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
## --- GAME ---
|
|
||||||
game.item_size 20 # Tamaño de los items del juego (en píxeles)
|
|
||||||
game.width 320 # Ancho de la resolución nativa del juego (en píxeles)
|
|
||||||
game.height 256 # Alto de la resolución nativa del juego (en píxeles)
|
|
||||||
game.play_area.rect.x 0 # Posición X de la zona jugable
|
|
||||||
game.play_area.rect.y 0 # Posición Y de la zona jugable
|
|
||||||
game.play_area.rect.w 320 # Ancho de la zona jugable
|
|
||||||
game.play_area.rect.h 216 # Alto de la zona jugable
|
|
||||||
game.name_entry_idle_time 10 # Segundos para introducir el nombre al finalizar la partida si no se pulsa nada
|
|
||||||
game.name_entry_total_time 60 # Segundos totales para introducir el nombre al finalizar la partida
|
|
||||||
game.hit_stop false # Indica si debe haber un paro cuando el jugador es golpeado por un globo
|
|
||||||
game.hit_stop_ms 500 # Cantidad de milisegundos que dura el hit_stop
|
|
||||||
|
|
||||||
## --- FADE ---
|
|
||||||
fade.color 1F2B30 # Color hexadecimal para el efecto de fundido
|
|
||||||
fade.num_squares_width 160 # Número de cuadrados en el eje X para el fundido
|
|
||||||
fade.num_squares_height 128 # Número de cuadrados en el eje Y para el fundido
|
|
||||||
fade.random_squares_delay 1 # Delay entre aparición de cuadrados aleatorios (frames)
|
|
||||||
fade.random_squares_mult 500 # Multiplicador para la velocidad de aparición aleatoria
|
|
||||||
fade.post_duration 80 # Duración tras el fundido (frames)
|
|
||||||
fade.venetian_size 12 # Tamaño de las bandas para el efecto veneciano (en píxeles)
|
|
||||||
|
|
||||||
## --- SCOREBOARD ---
|
|
||||||
scoreboard.rect.x 0 # Posición X del marcador
|
|
||||||
scoreboard.rect.y 216 # Posición Y del marcador
|
|
||||||
scoreboard.rect.w 320 # Ancho del marcador
|
|
||||||
scoreboard.rect.h 40 # Alto del marcador
|
|
||||||
scoreboard.separator_autocolor true # ¿El separador usa color automático?
|
|
||||||
scoreboard.separator_color 0D1A2B # Color del separador (hexadecimal)
|
|
||||||
scoreboard.easy_color 4B692F # Color para la dificultad fácil
|
|
||||||
scoreboard.normal_color 2E3F47 # Color para la dificultad normal
|
|
||||||
scoreboard.hard_color 76428A # Color para la dificultad difícil
|
|
||||||
scoreboard.text_autocolor true # ¿El texto usa color automático?
|
|
||||||
scoreboard.text_color1 FFFFFF # Color principal del texto del marcador
|
|
||||||
scoreboard.text_color2 FFFFFF # Color secundario del texto del marcador
|
|
||||||
scoreboard.skip_countdown_value 8 # Valor para saltar la cuenta atrás (segundos)
|
|
||||||
|
|
||||||
## --- TITLE ---
|
|
||||||
title.press_start_position 180 # Posición Y del texto "Press Start"
|
|
||||||
title.title_duration 800 # Duración de la pantalla de título (frames)
|
|
||||||
title.arcade_edition_position 123 # Posición Y del subtítulo "Arcade Edition"
|
|
||||||
title.title_c_c_position 80 # Posición Y del título principal
|
|
||||||
title.bg_color 41526F # Color de fondo en la sección titulo
|
|
||||||
|
|
||||||
## --- BACKGROUND ---
|
|
||||||
background.attenuate_color FFFFFF00 # Color de atenuación del fondo (RGBA hexadecimal)
|
|
||||||
|
|
||||||
## --- BALLOONS ---
|
|
||||||
balloon.settings[0].vel 2.75f # Velocidad inicial del globo 1
|
|
||||||
balloon.settings[0].grav 0.09f # Gravedad aplicada al globo 1
|
|
||||||
balloon.settings[1].vel 3.70f # Velocidad inicial del globo 2
|
|
||||||
balloon.settings[1].grav 0.10f # Gravedad aplicada al globo 2
|
|
||||||
balloon.settings[2].vel 4.70f # Velocidad inicial del globo 3
|
|
||||||
balloon.settings[2].grav 0.10f # Gravedad aplicada al globo 3
|
|
||||||
balloon.settings[3].vel 5.45f # Velocidad inicial del globo 4
|
|
||||||
balloon.settings[3].grav 0.10f # Gravedad aplicada al globo 4
|
|
||||||
|
|
||||||
balloon.color[0] blue # Color de creación del globo normal
|
|
||||||
balloon.color[1] orange # Color del globo normal
|
|
||||||
balloon.color[2] red # Color de creación del globo que rebota
|
|
||||||
balloon.color[3] green # Color del globo que rebota
|
|
||||||
|
|
||||||
balloon.bouncing_sound false # Indica si los globos hacer sonido al rebotar
|
|
||||||
|
|
||||||
## --- NOTIFICATION ---
|
|
||||||
notification.pos_v TOP # Posición vertical de la notificación (TOP/BOTTOM)
|
|
||||||
notification.pos_h LEFT # Posición horizontal de la notificación (LEFT/RIGHT)
|
|
||||||
notification.sound false # ¿La notificación reproduce sonido?
|
|
||||||
notification.color 303030 # Color de fondo de la notificación (hexadecimal)
|
|
||||||
|
|
||||||
## --- SERVICE MENU ---
|
|
||||||
service_menu.title_color 99FF62 # Color del título del menú de servicio
|
|
||||||
service_menu.text_color FFFFFF # Color del texto del menú de servicio
|
|
||||||
service_menu.selected_color FFDC44 # Color de la opción seleccionada en el menú de servicio
|
|
||||||
service_menu.bg_color 000F00F5 # Color de fondo del menú de servicio (RGBA hexadecimal)
|
|
||||||
service_menu.drop_shadow false # ¿El menú de servicio tiene sombra?
|
|
||||||
|
|
||||||
## --- INTRO ---
|
|
||||||
intro.bg_color 4664BD # Color de fondo de la intro
|
|
||||||
intro.card_color CBDBFC # Color de las tarjetas en la intro
|
|
||||||
intro.shadow_color 00000080 # Color de la sombra de las tarjetas en la intro
|
|
||||||
intro.text_distance_from_bottom 48 # Posicion del texto
|
|
||||||
|
|
||||||
## --- DEBUG ---
|
|
||||||
debug.color 00FFFF # Color para elementos de depuración
|
|
||||||
|
|
||||||
## --- RESOURCE ---
|
|
||||||
resource.color FFFFFF # Color de recurso 1
|
|
||||||
resource.color FFFFFF # Color de recurso 2
|
|
||||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
BIN
data/font/04b_25_2x_white.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
data/font/04b_25_white.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 872 B After Width: | Height: | Size: 882 B |
BIN
data/sound/click-2.wav
Normal file
BIN
data/sound/click-3.wav
Normal file
BIN
data/sound/service_menu_back.wav
Normal file
BIN
data/sound/voice_recover.wav
Normal file
15
linux_utils/generate_compile_commands_json.sh
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 🏁 Ruta base del proyecto
|
||||||
|
BASE_DIR="/home/sergio/gitea/coffee_crisis_arcade_edition"
|
||||||
|
|
||||||
|
# 📁 Ruta al build
|
||||||
|
BUILD_DIR="$BASE_DIR/build"
|
||||||
|
|
||||||
|
# 📄 Archivo de mapping personalizado
|
||||||
|
MAPPING_FILE="$BASE_DIR/linux_utils/sdl3_mapping.imp"
|
||||||
|
|
||||||
|
# 📦 Generar compile_commands.json
|
||||||
|
echo "🔧 Generando compile_commands.json..."
|
||||||
|
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -S "$BASE_DIR" -B "$BUILD_DIR"
|
||||||
|
|
||||||
44
linux_utils/run_clang-tidy.sh
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Script para ejecutar clang-tidy en múltiples directorios
|
||||||
|
# Uso: ./run_clang-tidy.sh
|
||||||
|
|
||||||
|
# Lista de rutas donde ejecutar clang-tidy
|
||||||
|
PATHS=(
|
||||||
|
"/home/sergio/gitea/coffee_crisis_arcade_edition/source"
|
||||||
|
"/home/sergio/gitea/coffee_crisis_arcade_edition/source/sections"
|
||||||
|
"/home/sergio/gitea/coffee_crisis_arcade_edition/source/ui"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ruta del directorio build (relativa desde donde se ejecuta el script)
|
||||||
|
BUILD_DIR="/home/sergio/gitea/coffee_crisis_arcade_edition/build/"
|
||||||
|
|
||||||
|
# Función para procesar un directorio
|
||||||
|
process_directory() {
|
||||||
|
local dir="$1"
|
||||||
|
|
||||||
|
echo "=== Procesando directorio: $dir ==="
|
||||||
|
|
||||||
|
# Verificar que el directorio existe
|
||||||
|
if [[ ! -d "$dir" ]]; then
|
||||||
|
echo "Error: El directorio $dir no existe"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Cambiar al directorio y ejecutar find con -maxdepth 1 para un solo nivel
|
||||||
|
cd "$dir" || return 1
|
||||||
|
|
||||||
|
# Buscar archivos .cpp, .h, .hpp solo en el nivel actual (no subdirectorios)
|
||||||
|
find . -maxdepth 1 \( -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \) | \
|
||||||
|
xargs -P4 -I{} bash -c 'echo "Procesando: {}"; clang-tidy {} -p '"$BUILD_DIR"' --fix'
|
||||||
|
|
||||||
|
echo "=== Completado: $dir ==="
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
# Procesar cada directorio en la lista
|
||||||
|
for path in "${PATHS[@]}"; do
|
||||||
|
process_directory "$path"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "¡Proceso completado para todos los directorios!"
|
||||||
@@ -9,22 +9,40 @@
|
|||||||
#include <stdexcept> // Para runtime_error
|
#include <stdexcept> // Para runtime_error
|
||||||
#include <utility> // Para pair
|
#include <utility> // Para pair
|
||||||
|
|
||||||
#include "texture.h" // Para Texture
|
#include "resource_helper.h" // Para ResourceHelper
|
||||||
#include "utils.h" // Para printWithDots
|
#include "texture.h" // Para Texture
|
||||||
|
#include "utils.h" // Para printWithDots
|
||||||
|
|
||||||
// Carga las animaciones en un vector(Animations) desde un fichero
|
// Carga las animaciones en un vector(Animations) desde un fichero
|
||||||
auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffer {
|
auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffer {
|
||||||
std::ifstream file(file_path);
|
// Intentar cargar desde ResourceHelper primero
|
||||||
if (!file) {
|
auto resource_data = ResourceHelper::loadFile(file_path);
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str());
|
std::istringstream stream;
|
||||||
throw std::runtime_error("Fichero no encontrado: " + file_path);
|
bool using_resource_data = false;
|
||||||
|
|
||||||
|
if (!resource_data.empty()) {
|
||||||
|
std::string content(resource_data.begin(), resource_data.end());
|
||||||
|
stream.str(content);
|
||||||
|
using_resource_data = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback a archivo directo
|
||||||
|
std::ifstream file;
|
||||||
|
if (!using_resource_data) {
|
||||||
|
file.open(file_path);
|
||||||
|
if (!file) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str());
|
||||||
|
throw std::runtime_error("Fichero no encontrado: " + file_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream& input_stream = using_resource_data ? stream : static_cast<std::istream&>(file);
|
||||||
|
|
||||||
printWithDots("Animation : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]");
|
printWithDots("Animation : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]");
|
||||||
|
|
||||||
std::vector<std::string> buffer;
|
std::vector<std::string> buffer;
|
||||||
std::string line;
|
std::string line;
|
||||||
while (std::getline(file, line)) {
|
while (std::getline(input_stream, line)) {
|
||||||
if (!line.empty()) {
|
if (!line.empty()) {
|
||||||
buffer.push_back(line);
|
buffer.push_back(line);
|
||||||
}
|
}
|
||||||
@@ -35,7 +53,7 @@ auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffe
|
|||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const std::string& file_path)
|
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const std::string& file_path)
|
||||||
: MovingSprite(texture) {
|
: MovingSprite(std::move(texture)) {
|
||||||
// Carga las animaciones
|
// Carga las animaciones
|
||||||
if (!file_path.empty()) {
|
if (!file_path.empty()) {
|
||||||
auto buffer = loadAnimationsFromFile(file_path);
|
auto buffer = loadAnimationsFromFile(file_path);
|
||||||
@@ -45,7 +63,7 @@ AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const std::stri
|
|||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer& animations)
|
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer& animations)
|
||||||
: MovingSprite(texture) {
|
: MovingSprite(std::move(texture)) {
|
||||||
if (!animations.empty()) {
|
if (!animations.empty()) {
|
||||||
loadFromAnimationsFileBuffer(animations);
|
loadFromAnimationsFileBuffer(animations);
|
||||||
}
|
}
|
||||||
@@ -176,7 +194,7 @@ void AnimatedSprite::loadFromAnimationsFileBuffer(const AnimationsFileBuffer& so
|
|||||||
|
|
||||||
// Procesa una línea de configuración
|
// Procesa una línea de configuración
|
||||||
void AnimatedSprite::processConfigLine(const std::string& line, AnimationConfig& config) {
|
void AnimatedSprite::processConfigLine(const std::string& line, AnimationConfig& config) {
|
||||||
size_t pos = line.find("=");
|
size_t pos = line.find('=');
|
||||||
if (pos == std::string::npos) {
|
if (pos == std::string::npos) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -230,7 +248,7 @@ auto AnimatedSprite::processAnimationBlock(const AnimationsFileBuffer& source, s
|
|||||||
|
|
||||||
// Procesa un parámetro individual de animación
|
// Procesa un parámetro individual de animación
|
||||||
void AnimatedSprite::processAnimationParameter(const std::string& line, Animation& animation, const AnimationConfig& config) {
|
void AnimatedSprite::processAnimationParameter(const std::string& line, Animation& animation, const AnimationConfig& config) {
|
||||||
size_t pos = line.find("=");
|
size_t pos = line.find('=');
|
||||||
if (pos == std::string::npos) {
|
if (pos == std::string::npos) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,15 @@
|
|||||||
#include <memory> // Para allocator, shared_ptr
|
#include <memory> // Para allocator, shared_ptr
|
||||||
#include <string> // Para string, hash
|
#include <string> // Para string, hash
|
||||||
#include <unordered_map> // Para unordered_map
|
#include <unordered_map> // Para unordered_map
|
||||||
#include <vector> // Para vector
|
#include <utility>
|
||||||
|
#include <vector> // Para vector
|
||||||
|
|
||||||
#include "moving_sprite.h" // Para MovingSprite
|
#include "moving_sprite.h" // Para MovingSprite
|
||||||
|
|
||||||
// Declaración adelantada
|
// Declaración adelantada
|
||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
// Estructura de Animación
|
// --- Estructuras ---
|
||||||
struct Animation {
|
struct Animation {
|
||||||
static constexpr int DEFAULT_SPEED = 5;
|
static constexpr int DEFAULT_SPEED = 5;
|
||||||
|
|
||||||
@@ -37,19 +38,20 @@ struct AnimationConfig {
|
|||||||
int max_tiles = 1;
|
int max_tiles = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Alias de tipo para buffer de animaciones
|
// --- Tipos ---
|
||||||
using AnimationsFileBuffer = std::vector<std::string>;
|
using AnimationsFileBuffer = std::vector<std::string>; // Buffer de animaciones
|
||||||
|
|
||||||
// Carga las animaciones desde un fichero en un vector de strings
|
// --- Funciones ---
|
||||||
auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffer;
|
auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffer; // Carga las animaciones desde un fichero
|
||||||
|
|
||||||
// Clase AnimatedSprite: Sprite animado que hereda de MovingSprite
|
// --- Clase AnimatedSprite: sprite animado que hereda de MovingSprite ---
|
||||||
class AnimatedSprite : public MovingSprite {
|
class AnimatedSprite : public MovingSprite {
|
||||||
public:
|
public:
|
||||||
// --- Constructores y destructor ---
|
// --- Constructores y destructor ---
|
||||||
AnimatedSprite(std::shared_ptr<Texture> texture, const std::string& file_path);
|
AnimatedSprite(std::shared_ptr<Texture> texture, const std::string& file_path);
|
||||||
AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer& animations);
|
AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer& animations);
|
||||||
explicit AnimatedSprite(std::shared_ptr<Texture> texture) : MovingSprite(texture) {}
|
explicit AnimatedSprite(std::shared_ptr<Texture> texture)
|
||||||
|
: MovingSprite(std::move(texture)) {}
|
||||||
~AnimatedSprite() override = default;
|
~AnimatedSprite() override = default;
|
||||||
|
|
||||||
// --- Métodos principales ---
|
// --- Métodos principales ---
|
||||||
@@ -70,12 +72,10 @@ class AnimatedSprite : public MovingSprite {
|
|||||||
auto getAnimationIndex(const std::string& name) -> int; // Obtiene el índice de una animación por nombre
|
auto getAnimationIndex(const std::string& name) -> int; // Obtiene el índice de una animación por nombre
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// --- Datos de animación ---
|
// --- Variables de estado ---
|
||||||
std::vector<Animation> animations_; // Vector de animaciones disponibles
|
std::vector<Animation> animations_; // Vector de animaciones disponibles
|
||||||
int current_animation_ = 0; // Índice de la animación activa
|
std::unordered_map<std::string, int> animation_indices_; // Mapa para búsqueda rápida por nombre
|
||||||
|
int current_animation_ = 0; // Índice de la animación activa
|
||||||
// --- Mapa para búsqueda rápida de animaciones por nombre ---
|
|
||||||
std::unordered_map<std::string, int> animation_indices_;
|
|
||||||
|
|
||||||
// --- Métodos internos ---
|
// --- Métodos internos ---
|
||||||
void animate(); // Calcula el frame correspondiente a la animación
|
void animate(); // Calcula el frame correspondiente a la animación
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
#include <sstream> // Para basic_istringstream
|
#include <sstream> // Para basic_istringstream
|
||||||
#include <stdexcept> // Para runtime_error
|
#include <stdexcept> // Para runtime_error
|
||||||
|
|
||||||
#include "utils.h" // Para getFileName
|
#include "resource_helper.h" // Para ResourceHelper
|
||||||
|
#include "utils.h" // Para getFileName
|
||||||
|
|
||||||
// Singleton
|
// Singleton
|
||||||
Asset *Asset::instance = nullptr;
|
Asset *Asset::instance = nullptr;
|
||||||
@@ -92,7 +93,7 @@ void Asset::loadFromFile(const std::string &config_file_path, const std::string
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::string type_str = parts[0];
|
const std::string &type_str = parts[0];
|
||||||
std::string path = parts[1];
|
std::string path = parts[1];
|
||||||
|
|
||||||
// Valores por defecto
|
// Valores por defecto
|
||||||
@@ -139,6 +140,17 @@ auto Asset::get(const std::string &filename) const -> std::string {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Carga datos del archivo usando ResourceHelper
|
||||||
|
auto Asset::loadData(const std::string &filename) const -> std::vector<uint8_t> {
|
||||||
|
auto it = file_list_.find(filename);
|
||||||
|
if (it != file_list_.end()) {
|
||||||
|
return ResourceHelper::loadFile(it->second.file);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found for data loading", filename.c_str());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
// Verifica si un recurso existe
|
// Verifica si un recurso existe
|
||||||
auto Asset::exists(const std::string &filename) const -> bool {
|
auto Asset::exists(const std::string &filename) const -> bool {
|
||||||
return file_list_.find(filename) != file_list_.end();
|
return file_list_.find(filename) != file_list_.end();
|
||||||
@@ -194,9 +206,16 @@ auto Asset::check() const -> bool {
|
|||||||
|
|
||||||
// Comprueba que existe un fichero
|
// Comprueba que existe un fichero
|
||||||
auto Asset::checkFile(const std::string &path) -> bool {
|
auto Asset::checkFile(const std::string &path) -> bool {
|
||||||
std::ifstream file(path);
|
// Intentar primero con ResourceHelper
|
||||||
bool success = file.good();
|
auto data = ResourceHelper::loadFile(path);
|
||||||
file.close();
|
bool success = !data.empty();
|
||||||
|
|
||||||
|
// Si no se encuentra en el pack, intentar con filesystem directo
|
||||||
|
if (!success) {
|
||||||
|
std::ifstream file(path);
|
||||||
|
success = file.good();
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
|||||||
@@ -1,25 +1,26 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <cstdint> // Para uint8_t
|
||||||
#include <unordered_map>
|
#include <string> // Para string
|
||||||
#include <utility>
|
#include <unordered_map> // Para unordered_map
|
||||||
#include <vector>
|
#include <utility> // Para move
|
||||||
|
#include <vector> // Para vector
|
||||||
|
|
||||||
// Clase Asset: gestor optimizado de recursos (singleton)
|
// --- Clase Asset: gestor optimizado de recursos (singleton) ---
|
||||||
class Asset {
|
class Asset {
|
||||||
public:
|
public:
|
||||||
// Tipos de recursos
|
// --- Enums ---
|
||||||
enum class Type : int {
|
enum class Type : int {
|
||||||
BITMAP,
|
BITMAP, // Imágenes
|
||||||
MUSIC,
|
MUSIC, // Música
|
||||||
SOUND,
|
SOUND, // Sonidos
|
||||||
FONT,
|
FONT, // Fuentes
|
||||||
LANG,
|
LANG, // Idiomas
|
||||||
DATA,
|
DATA, // Datos
|
||||||
DEMODATA,
|
DEMODATA, // Datos de demo
|
||||||
ANIMATION,
|
ANIMATION, // Animaciones
|
||||||
PALETTE,
|
PALETTE, // Paletas
|
||||||
SIZE,
|
SIZE, // Tamaño
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Métodos de singleton ---
|
// --- Métodos de singleton ---
|
||||||
@@ -33,37 +34,41 @@ class Asset {
|
|||||||
void add(const std::string &file_path, Type type, bool required = true, bool absolute = false);
|
void add(const std::string &file_path, Type type, bool required = true, bool absolute = false);
|
||||||
void loadFromFile(const std::string &config_file_path, const std::string &prefix = "", const std::string &system_folder = ""); // Con soporte para variables
|
void loadFromFile(const std::string &config_file_path, const std::string &prefix = "", const std::string &system_folder = ""); // Con soporte para variables
|
||||||
[[nodiscard]] auto get(const std::string &filename) const -> std::string; // Mantener nombre original
|
[[nodiscard]] auto get(const std::string &filename) const -> std::string; // Mantener nombre original
|
||||||
|
[[nodiscard]] auto loadData(const std::string &filename) const -> std::vector<uint8_t>; // Carga datos del archivo
|
||||||
[[nodiscard]] auto check() const -> bool;
|
[[nodiscard]] auto check() const -> bool;
|
||||||
[[nodiscard]] auto getListByType(Type type) const -> std::vector<std::string>;
|
[[nodiscard]] auto getListByType(Type type) const -> std::vector<std::string>;
|
||||||
[[nodiscard]] auto exists(const std::string &filename) const -> bool; // Nueva función para verificar existencia
|
[[nodiscard]] auto exists(const std::string &filename) const -> bool; // Nueva función para verificar existencia
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Estructura interna para almacenar información de cada recurso ---
|
// --- Estructuras privadas ---
|
||||||
struct Item {
|
struct Item {
|
||||||
std::string file; // Ruta completa del archivo (mantener nombre original)
|
std::string file; // Ruta completa del archivo
|
||||||
Type type; // Tipo de recurso
|
Type type; // Tipo de recurso
|
||||||
bool required; // Indica si el archivo es obligatorio
|
bool required; // Indica si el archivo es obligatorio
|
||||||
|
|
||||||
Item(std::string path, Type asset_type, bool is_required)
|
Item(std::string path, Type asset_type, bool is_required)
|
||||||
: file(std::move(path)), type(asset_type), required(is_required) {}
|
: file(std::move(path)),
|
||||||
|
type(asset_type),
|
||||||
|
required(is_required) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Variables internas ---
|
// --- Variables internas ---
|
||||||
std::unordered_map<std::string, Item> file_list_; // Mapa para búsqueda O(1) (mantener nombre original)
|
std::unordered_map<std::string, Item> file_list_; // Mapa para búsqueda O(1)
|
||||||
std::string executable_path_; // Ruta del ejecutable
|
std::string executable_path_; // Ruta del ejecutable
|
||||||
|
|
||||||
// --- Métodos internos ---
|
// --- Métodos internos ---
|
||||||
[[nodiscard]] static auto checkFile(const std::string &path) -> bool;
|
[[nodiscard]] static auto checkFile(const std::string &path) -> bool; // Verifica si un archivo existe
|
||||||
[[nodiscard]] static auto getTypeName(Type type) -> std::string;
|
[[nodiscard]] static auto getTypeName(Type type) -> std::string; // Obtiene el nombre del tipo
|
||||||
[[nodiscard]] static auto parseAssetType(const std::string &type_str) -> Type;
|
[[nodiscard]] static auto parseAssetType(const std::string &type_str) -> Type; // Convierte string a tipo
|
||||||
void addToMap(const std::string &file_path, Type type, bool required, bool absolute);
|
void addToMap(const std::string &file_path, Type type, bool required, bool absolute); // Añade archivo al mapa
|
||||||
[[nodiscard]] static auto replaceVariables(const std::string &path, const std::string &prefix, const std::string &system_folder) -> std::string;
|
[[nodiscard]] static auto replaceVariables(const std::string &path, const std::string &prefix, const std::string &system_folder) -> std::string; // Reemplaza variables en la ruta
|
||||||
static auto parseOptions(const std::string &options, bool &required, bool &absolute) -> void;
|
static auto parseOptions(const std::string &options, bool &required, bool &absolute) -> void; // Parsea opciones
|
||||||
|
|
||||||
// --- Patrón Singleton ---
|
// --- Constructores y destructor privados (singleton) ---
|
||||||
explicit Asset(std::string executable_path)
|
explicit Asset(std::string executable_path) // Constructor privado
|
||||||
: executable_path_(std::move(executable_path)) {}
|
: executable_path_(std::move(executable_path)) {}
|
||||||
~Asset() = default;
|
~Asset() = default; // Destructor privado
|
||||||
|
|
||||||
static Asset *instance;
|
// --- Instancia singleton ---
|
||||||
|
static Asset *instance; // Instancia única de Asset
|
||||||
};
|
};
|
||||||
106
source/asset_integrated.cpp
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#include "asset_integrated.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
bool AssetIntegrated::resource_pack_enabled_ = false;
|
||||||
|
|
||||||
|
void AssetIntegrated::initWithResourcePack(const std::string &executable_path,
|
||||||
|
const std::string &resource_pack_path) {
|
||||||
|
// Inicializar Asset normal
|
||||||
|
Asset::init(executable_path);
|
||||||
|
|
||||||
|
// Inicializar ResourceLoader
|
||||||
|
auto &loader = ResourceLoader::getInstance();
|
||||||
|
if (loader.initialize(resource_pack_path, true)) {
|
||||||
|
resource_pack_enabled_ = true;
|
||||||
|
std::cout << "Asset system initialized with resource pack: " << resource_pack_path << std::endl;
|
||||||
|
} else {
|
||||||
|
resource_pack_enabled_ = false;
|
||||||
|
std::cout << "Asset system initialized in fallback mode (filesystem)" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> AssetIntegrated::loadFile(const std::string &filename) {
|
||||||
|
if (shouldUseResourcePack(filename) && resource_pack_enabled_) {
|
||||||
|
// Intentar cargar del pack de recursos
|
||||||
|
auto &loader = ResourceLoader::getInstance();
|
||||||
|
|
||||||
|
// Convertir ruta completa a ruta relativa para el pack
|
||||||
|
std::string relativePath = filename;
|
||||||
|
|
||||||
|
// Si la ruta contiene "data/", extraer la parte relativa
|
||||||
|
size_t dataPos = filename.find("data/");
|
||||||
|
if (dataPos != std::string::npos) {
|
||||||
|
relativePath = filename.substr(dataPos + 5); // +5 para saltar "data/"
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data = loader.loadResource(relativePath);
|
||||||
|
if (!data.empty()) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: cargar del filesystem
|
||||||
|
std::ifstream file(filename, std::ios::binary | std::ios::ate);
|
||||||
|
if (!file) {
|
||||||
|
std::cerr << "Error: Could not open file: " << filename << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::streamsize fileSize = file.tellg();
|
||||||
|
file.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
std::vector<uint8_t> data(fileSize);
|
||||||
|
if (!file.read(reinterpret_cast<char *>(data.data()), fileSize)) {
|
||||||
|
std::cerr << "Error: Could not read file: " << filename << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssetIntegrated::fileExists(const std::string &filename) const {
|
||||||
|
if (shouldUseResourcePack(filename) && resource_pack_enabled_) {
|
||||||
|
auto &loader = ResourceLoader::getInstance();
|
||||||
|
|
||||||
|
// Convertir ruta completa a ruta relativa para el pack
|
||||||
|
std::string relativePath = filename;
|
||||||
|
size_t dataPos = filename.find("data/");
|
||||||
|
if (dataPos != std::string::npos) {
|
||||||
|
relativePath = filename.substr(dataPos + 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loader.resourceExists(relativePath)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verificar en filesystem
|
||||||
|
return std::filesystem::exists(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AssetIntegrated::getSystemPath(const std::string &filename) const {
|
||||||
|
// Los archivos de sistema/config siempre van al filesystem
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssetIntegrated::shouldUseResourcePack(const std::string &filepath) const {
|
||||||
|
// Los archivos que NO van al pack:
|
||||||
|
// - Archivos de config/ (ahora están fuera de data/)
|
||||||
|
// - Archivos con absolute=true en assets.txt
|
||||||
|
// - Archivos de sistema (${SYSTEM_FOLDER})
|
||||||
|
|
||||||
|
if (filepath.find("/config/") != std::string::npos ||
|
||||||
|
filepath.find("config/") == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filepath.find("/data/") != std::string::npos ||
|
||||||
|
filepath.find("data/") == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
29
source/asset_integrated.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "asset.h"
|
||||||
|
#include "resource_loader.h"
|
||||||
|
|
||||||
|
// Extensión de Asset que integra ResourceLoader
|
||||||
|
class AssetIntegrated : public Asset {
|
||||||
|
public:
|
||||||
|
// Inicializa Asset con ResourceLoader
|
||||||
|
static void initWithResourcePack(const std::string &executable_path,
|
||||||
|
const std::string &resource_pack_path = "resources.pack");
|
||||||
|
|
||||||
|
// Carga un archivo usando ResourceLoader como primera opción
|
||||||
|
std::vector<uint8_t> loadFile(const std::string &filename);
|
||||||
|
|
||||||
|
// Verifica si un archivo existe (pack o filesystem)
|
||||||
|
bool fileExists(const std::string &filename) const;
|
||||||
|
|
||||||
|
// Obtiene la ruta completa para archivos del sistema/config
|
||||||
|
std::string getSystemPath(const std::string &filename) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool resource_pack_enabled_;
|
||||||
|
|
||||||
|
// Determina si un archivo debe cargarse del pack o del filesystem
|
||||||
|
bool shouldUseResourcePack(const std::string &filepath) const;
|
||||||
|
};
|
||||||
@@ -100,7 +100,7 @@ void Audio::stopAllSounds() const {
|
|||||||
|
|
||||||
// Realiza un fundido de salida de la música
|
// Realiza un fundido de salida de la música
|
||||||
void Audio::fadeOutMusic(int milliseconds) const {
|
void Audio::fadeOutMusic(int milliseconds) const {
|
||||||
if (music_enabled_) {
|
if (music_enabled_ && music_.state == MusicState::PLAYING) {
|
||||||
#ifndef NO_AUDIO
|
#ifndef NO_AUDIO
|
||||||
JA_FadeOutMusic(milliseconds);
|
JA_FadeOutMusic(milliseconds);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -3,19 +3,20 @@
|
|||||||
#include <string> // Para string
|
#include <string> // Para string
|
||||||
#include <utility> // Para move
|
#include <utility> // Para move
|
||||||
|
|
||||||
// Clase Audio: gestor de audio (singleton)
|
// --- Clase Audio: gestor de audio (singleton) ---
|
||||||
class Audio {
|
class Audio {
|
||||||
public:
|
public:
|
||||||
|
// --- Enums ---
|
||||||
enum class Group : int {
|
enum class Group : int {
|
||||||
ALL = -1,
|
ALL = -1, // Todos los grupos
|
||||||
GAME = 0,
|
GAME = 0, // Sonidos del juego
|
||||||
INTERFACE = 1
|
INTERFACE = 1 // Sonidos de la interfaz
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Constantes ---
|
// --- Constantes ---
|
||||||
static constexpr int MAX_VOLUME = 100;
|
static constexpr int MAX_VOLUME = 100; // Volumen máximo
|
||||||
static constexpr int MIN_VOLUME = 0;
|
static constexpr int MIN_VOLUME = 0; // Volumen mínimo
|
||||||
static constexpr int FREQUENCY = 48000;
|
static constexpr int FREQUENCY = 48000; // Frecuencia de audio
|
||||||
|
|
||||||
// --- Métodos de singleton ---
|
// --- Métodos de singleton ---
|
||||||
static void init(); // Inicializa el objeto Audio
|
static void init(); // Inicializa el objeto Audio
|
||||||
@@ -60,39 +61,44 @@ class Audio {
|
|||||||
void setMusicVolume(int volume) const; // Ajustar volumen de música
|
void setMusicVolume(int volume) const; // Ajustar volumen de música
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// --- Enums privados ---
|
||||||
enum class MusicState {
|
enum class MusicState {
|
||||||
PLAYING,
|
PLAYING, // Reproduciendo música
|
||||||
PAUSED,
|
PAUSED, // Música pausada
|
||||||
STOPPED,
|
STOPPED, // Música detenida
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --- Estructuras privadas ---
|
||||||
struct Music {
|
struct Music {
|
||||||
MusicState state; // Estado actual de la música (reproduciendo, detenido, en pausa)
|
MusicState state; // Estado actual de la música (reproduciendo, detenido, en pausa)
|
||||||
std::string name; // Última pista de música reproducida
|
std::string name; // Última pista de música reproducida
|
||||||
bool loop; // Indica si la última pista de música se debe reproducir en bucle
|
bool loop; // Indica si la última pista de música se debe reproducir en bucle
|
||||||
|
|
||||||
// Constructor para inicializar la música con valores predeterminados
|
// Constructor para inicializar la música con valores predeterminados
|
||||||
Music() : state(MusicState::STOPPED), loop(false) {}
|
Music()
|
||||||
|
: state(MusicState::STOPPED),
|
||||||
|
loop(false) {}
|
||||||
|
|
||||||
// Constructor para inicializar con valores específicos
|
// Constructor para inicializar con valores específicos
|
||||||
Music(MusicState init_state, std::string init_name, bool init_loop)
|
Music(MusicState init_state, std::string init_name, bool init_loop)
|
||||||
: state(init_state), name(std::move(init_name)), loop(init_loop) {}
|
: state(init_state),
|
||||||
|
name(std::move(init_name)),
|
||||||
|
loop(init_loop) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
Music music_;
|
// --- Variables de estado ---
|
||||||
|
Music music_; // Estado de la música
|
||||||
// --- Variables de Estado ---
|
|
||||||
bool enabled_ = true; // Estado general del audio
|
bool enabled_ = true; // Estado general del audio
|
||||||
bool sound_enabled_ = true; // Estado de los efectos de sonido
|
bool sound_enabled_ = true; // Estado de los efectos de sonido
|
||||||
bool music_enabled_ = true; // Estado de la música
|
bool music_enabled_ = true; // Estado de la música
|
||||||
|
|
||||||
// --- Inicializa SDL Audio ---
|
// --- Métodos internos ---
|
||||||
void initSDLAudio();
|
void initSDLAudio(); // Inicializa SDL Audio
|
||||||
|
|
||||||
// --- Patrón Singleton ---
|
// --- Constructores y destructor privados (singleton) ---
|
||||||
Audio(); // Constructor privado
|
Audio(); // Constructor privado
|
||||||
~Audio(); // Destructor privado
|
~Audio(); // Destructor privado
|
||||||
|
|
||||||
// --- Singleton ---
|
// --- Instancia singleton ---
|
||||||
static Audio *instance;
|
static Audio *instance; // Instancia única de Audio
|
||||||
};
|
};
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <algorithm> // Para clamp, max
|
#include <algorithm> // Para clamp, max
|
||||||
#include <cmath> // Para M_PI, cos, sin
|
#include <cmath> // Para M_PI, cos, sin
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "moving_sprite.h" // Para MovingSprite
|
#include "moving_sprite.h" // Para MovingSprite
|
||||||
#include "param.h" // Para Param, ParamBackground, param
|
#include "param.h" // Para Param, ParamBackground, param
|
||||||
@@ -15,11 +16,7 @@
|
|||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Background::Background(float total_progress_to_complete)
|
Background::Background(float total_progress_to_complete)
|
||||||
: total_progress_to_complete_(total_progress_to_complete),
|
: renderer_(Screen::get()->getRenderer()),
|
||||||
progress_per_stage_(total_progress_to_complete_ / STAGES),
|
|
||||||
sun_completion_progress_(total_progress_to_complete_ * SUN_COMPLETION_FACTOR),
|
|
||||||
|
|
||||||
renderer_(Screen::get()->getRenderer()),
|
|
||||||
|
|
||||||
buildings_texture_(Resource::get()->getTexture("game_buildings.png")),
|
buildings_texture_(Resource::get()->getTexture("game_buildings.png")),
|
||||||
top_clouds_texture_(Resource::get()->getTexture("game_clouds1.png")),
|
top_clouds_texture_(Resource::get()->getTexture("game_clouds1.png")),
|
||||||
@@ -29,9 +26,13 @@ Background::Background(float total_progress_to_complete)
|
|||||||
sun_texture_(Resource::get()->getTexture("game_sun.png")),
|
sun_texture_(Resource::get()->getTexture("game_sun.png")),
|
||||||
moon_texture_(Resource::get()->getTexture("game_moon.png")),
|
moon_texture_(Resource::get()->getTexture("game_moon.png")),
|
||||||
|
|
||||||
|
total_progress_to_complete_(total_progress_to_complete),
|
||||||
|
progress_per_stage_(total_progress_to_complete_ / STAGES),
|
||||||
|
sun_completion_progress_(total_progress_to_complete_ * SUN_COMPLETION_FACTOR),
|
||||||
|
|
||||||
rect_(SDL_FRect{0, 0, static_cast<float>(gradients_texture_->getWidth() / 2), static_cast<float>(gradients_texture_->getHeight() / 2)}),
|
rect_(SDL_FRect{0, 0, static_cast<float>(gradients_texture_->getWidth() / 2), static_cast<float>(gradients_texture_->getHeight() / 2)}),
|
||||||
src_rect_({0, 0, 320, 240}),
|
src_rect_({.x = 0, .y = 0, .w = 320, .h = 240}),
|
||||||
dst_rect_({0, 0, 320, 240}),
|
dst_rect_({.x = 0, .y = 0, .w = 320, .h = 240}),
|
||||||
attenuate_color_(Color(param.background.attenuate_color.r, param.background.attenuate_color.g, param.background.attenuate_color.b)),
|
attenuate_color_(Color(param.background.attenuate_color.r, param.background.attenuate_color.g, param.background.attenuate_color.b)),
|
||||||
|
|
||||||
alpha_color_texture_(param.background.attenuate_color.a),
|
alpha_color_texture_(param.background.attenuate_color.a),
|
||||||
@@ -58,17 +59,17 @@ void Background::initializePaths() {
|
|||||||
|
|
||||||
// Inicializa los rectángulos de gradientes y nubes
|
// Inicializa los rectángulos de gradientes y nubes
|
||||||
void Background::initializeRects() {
|
void Background::initializeRects() {
|
||||||
gradient_rect_[0] = {0, 0, rect_.w, rect_.h};
|
gradient_rect_[0] = {.x = 0, .y = 0, .w = rect_.w, .h = rect_.h};
|
||||||
gradient_rect_[1] = {rect_.w, 0, rect_.w, rect_.h};
|
gradient_rect_[1] = {.x = rect_.w, .y = 0, .w = rect_.w, .h = rect_.h};
|
||||||
gradient_rect_[2] = {0, rect_.h, rect_.w, rect_.h};
|
gradient_rect_[2] = {.x = 0, .y = rect_.h, .w = rect_.w, .h = rect_.h};
|
||||||
gradient_rect_[3] = {rect_.w, rect_.h, rect_.w, rect_.h};
|
gradient_rect_[3] = {.x = rect_.w, .y = rect_.h, .w = rect_.w, .h = rect_.h};
|
||||||
|
|
||||||
const float TOP_CLOUDS_TEXTURE_HEIGHT = top_clouds_texture_->getHeight() / 4;
|
const float TOP_CLOUDS_TEXTURE_HEIGHT = top_clouds_texture_->getHeight() / 4;
|
||||||
const float BOTTOM_CLOUDS_TEXTURE_HEIGHT = bottom_clouds_texture_->getHeight() / 4;
|
const float BOTTOM_CLOUDS_TEXTURE_HEIGHT = bottom_clouds_texture_->getHeight() / 4;
|
||||||
|
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 4; ++i) {
|
||||||
top_clouds_rect_[i] = {0, i * TOP_CLOUDS_TEXTURE_HEIGHT, static_cast<float>(top_clouds_texture_->getWidth()), TOP_CLOUDS_TEXTURE_HEIGHT};
|
top_clouds_rect_[i] = {.x = 0, .y = i * TOP_CLOUDS_TEXTURE_HEIGHT, .w = static_cast<float>(top_clouds_texture_->getWidth()), .h = TOP_CLOUDS_TEXTURE_HEIGHT};
|
||||||
bottom_clouds_rect_[i] = {0, i * BOTTOM_CLOUDS_TEXTURE_HEIGHT, static_cast<float>(bottom_clouds_texture_->getWidth()), BOTTOM_CLOUDS_TEXTURE_HEIGHT};
|
bottom_clouds_rect_[i] = {.x = 0, .y = i * BOTTOM_CLOUDS_TEXTURE_HEIGHT, .w = static_cast<float>(bottom_clouds_texture_->getWidth()), .h = BOTTOM_CLOUDS_TEXTURE_HEIGHT};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,7 +172,7 @@ void Background::incrementProgress(float amount) {
|
|||||||
// Establece la progresión absoluta
|
// Establece la progresión absoluta
|
||||||
void Background::setProgress(float absolute_progress) {
|
void Background::setProgress(float absolute_progress) {
|
||||||
float old_progress = progress_;
|
float old_progress = progress_;
|
||||||
progress_ = std::clamp(absolute_progress, 0.0f, total_progress_to_complete_);
|
progress_ = std::clamp(absolute_progress, 0.0F, total_progress_to_complete_);
|
||||||
|
|
||||||
// Notifica el cambio si hay callback y el progreso cambió
|
// Notifica el cambio si hay callback y el progreso cambió
|
||||||
if (progress_callback_ && progress_ != old_progress) {
|
if (progress_callback_ && progress_ != old_progress) {
|
||||||
@@ -187,11 +188,11 @@ void Background::setState(State new_state) {
|
|||||||
// Reinicia la progresión
|
// Reinicia la progresión
|
||||||
void Background::reset() {
|
void Background::reset() {
|
||||||
float old_progress = progress_;
|
float old_progress = progress_;
|
||||||
progress_ = 0.0f;
|
progress_ = 0.0F;
|
||||||
state_ = State::NORMAL;
|
state_ = State::NORMAL;
|
||||||
manual_mode_ = false;
|
manual_mode_ = false;
|
||||||
gradient_number_ = 0;
|
gradient_number_ = 0;
|
||||||
transition_ = 0.0f;
|
transition_ = 0.0F;
|
||||||
sun_index_ = 0;
|
sun_index_ = 0;
|
||||||
moon_index_ = 0;
|
moon_index_ = 0;
|
||||||
|
|
||||||
@@ -208,7 +209,7 @@ void Background::setManualMode(bool manual) {
|
|||||||
|
|
||||||
// Establece callback para sincronización automática
|
// Establece callback para sincronización automática
|
||||||
void Background::setProgressCallback(ProgressCallback callback) {
|
void Background::setProgressCallback(ProgressCallback callback) {
|
||||||
progress_callback_ = callback;
|
progress_callback_ = std::move(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Elimina el callback
|
// Elimina el callback
|
||||||
@@ -224,8 +225,8 @@ void Background::setCloudsSpeed(float value) {
|
|||||||
// Las nubes inferiores van a la mitad de velocidad que las superiores
|
// Las nubes inferiores van a la mitad de velocidad que las superiores
|
||||||
top_clouds_sprite_a_->setVelX(value);
|
top_clouds_sprite_a_->setVelX(value);
|
||||||
top_clouds_sprite_b_->setVelX(value);
|
top_clouds_sprite_b_->setVelX(value);
|
||||||
bottom_clouds_sprite_a_->setVelX(value / 2.0f);
|
bottom_clouds_sprite_a_->setVelX(value / 2.0F);
|
||||||
bottom_clouds_sprite_b_->setVelX(value / 2.0f);
|
bottom_clouds_sprite_b_->setVelX(value / 2.0F);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Establece el degradado de fondo
|
// Establece el degradado de fondo
|
||||||
@@ -262,19 +263,19 @@ void Background::updateProgression() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Calcula la transición de los diferentes fondos
|
// Calcula la transición de los diferentes fondos
|
||||||
const float gradient_number_float = std::min(progress_ / progress_per_stage_, 3.0F);
|
const float GRADIENT_NUMBER_FLOAT = std::min(progress_ / progress_per_stage_, 3.0F);
|
||||||
const float percent = gradient_number_float - static_cast<int>(gradient_number_float);
|
const float PERCENT = GRADIENT_NUMBER_FLOAT - static_cast<int>(GRADIENT_NUMBER_FLOAT);
|
||||||
|
|
||||||
gradient_number_ = static_cast<size_t>(gradient_number_float);
|
gradient_number_ = static_cast<size_t>(GRADIENT_NUMBER_FLOAT);
|
||||||
transition_ = percent;
|
transition_ = PERCENT;
|
||||||
|
|
||||||
// Calcula la posición del sol
|
// Calcula la posición del sol
|
||||||
const float sun_progression = std::min(progress_ / sun_completion_progress_, 1.0f);
|
const float SUN_PROGRESSION = std::min(progress_ / sun_completion_progress_, 1.0F);
|
||||||
sun_index_ = static_cast<size_t>(sun_progression * (sun_path_.size() - 1));
|
sun_index_ = static_cast<size_t>(SUN_PROGRESSION * (sun_path_.size() - 1));
|
||||||
|
|
||||||
// Calcula la posición de la luna
|
// Calcula la posición de la luna
|
||||||
const float moon_progression = std::min(progress_ / total_progress_to_complete_, 1.0f);
|
const float MOON_PROGRESSION = std::min(progress_ / total_progress_to_complete_, 1.0F);
|
||||||
moon_index_ = static_cast<size_t>(moon_progression * (moon_path_.size() - 1));
|
moon_index_ = static_cast<size_t>(MOON_PROGRESSION * (moon_path_.size() - 1));
|
||||||
|
|
||||||
// Actualiza la velocidad de las nubes
|
// Actualiza la velocidad de las nubes
|
||||||
updateCloudsSpeed();
|
updateCloudsSpeed();
|
||||||
@@ -294,22 +295,22 @@ void Background::updateCloudsSpeed() {
|
|||||||
if (state_ == State::COMPLETED) {
|
if (state_ == State::COMPLETED) {
|
||||||
float completion_factor = (progress_ - MINIMUM_COMPLETED_PROGRESS) /
|
float completion_factor = (progress_ - MINIMUM_COMPLETED_PROGRESS) /
|
||||||
(total_progress_to_complete_ - MINIMUM_COMPLETED_PROGRESS);
|
(total_progress_to_complete_ - MINIMUM_COMPLETED_PROGRESS);
|
||||||
completion_factor = std::max(0.1f, completion_factor);
|
completion_factor = std::max(0.1F, completion_factor);
|
||||||
base_clouds_speed *= completion_factor;
|
base_clouds_speed *= completion_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aplicar velocidades diferentes para nubes superiores e inferiores
|
// Aplicar velocidades diferentes para nubes superiores e inferiores
|
||||||
const float top_clouds_speed = base_clouds_speed;
|
const float TOP_CLOUDS_SPEED = base_clouds_speed;
|
||||||
const float bottom_clouds_speed = base_clouds_speed / 2.0f;
|
const float BOTTOM_CLOUDS_SPEED = base_clouds_speed / 2.0F;
|
||||||
|
|
||||||
// Aplicar las velocidades a los sprites correspondientes
|
// Aplicar las velocidades a los sprites correspondientes
|
||||||
top_clouds_sprite_a_->setVelX(top_clouds_speed);
|
top_clouds_sprite_a_->setVelX(TOP_CLOUDS_SPEED);
|
||||||
top_clouds_sprite_b_->setVelX(top_clouds_speed);
|
top_clouds_sprite_b_->setVelX(TOP_CLOUDS_SPEED);
|
||||||
bottom_clouds_sprite_a_->setVelX(bottom_clouds_speed);
|
bottom_clouds_sprite_a_->setVelX(BOTTOM_CLOUDS_SPEED);
|
||||||
bottom_clouds_sprite_b_->setVelX(bottom_clouds_speed);
|
bottom_clouds_sprite_b_->setVelX(BOTTOM_CLOUDS_SPEED);
|
||||||
|
|
||||||
// Guardar la velocidad principal
|
// Guardar la velocidad principal
|
||||||
clouds_speed_ = top_clouds_speed;
|
clouds_speed_ = TOP_CLOUDS_SPEED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualiza las nubes
|
// Actualiza las nubes
|
||||||
@@ -478,7 +479,7 @@ void Background::createSunPath() {
|
|||||||
const int NUM_STEPS = static_cast<int>((M_PI - M_PI / 2) / STEP) + 1;
|
const int NUM_STEPS = static_cast<int>((M_PI - M_PI / 2) / STEP) + 1;
|
||||||
|
|
||||||
for (int i = 0; i < NUM_STEPS; ++i) {
|
for (int i = 0; i < NUM_STEPS; ++i) {
|
||||||
double theta = M_PI / 2 + i * STEP;
|
double theta = M_PI / 2 + (i * STEP);
|
||||||
float x = CENTER_X + (RADIUS * cos(theta));
|
float x = CENTER_X + (RADIUS * cos(theta));
|
||||||
float y = CENTER_Y - (RADIUS * sin(theta));
|
float y = CENTER_Y - (RADIUS * sin(theta));
|
||||||
sun_path_.push_back({x, y});
|
sun_path_.push_back({x, y});
|
||||||
@@ -501,9 +502,9 @@ void Background::createMoonPath() {
|
|||||||
constexpr double STEP = 0.01;
|
constexpr double STEP = 0.01;
|
||||||
const int NUM_STEPS = static_cast<int>((M_PI / 2) / STEP) + 1;
|
const int NUM_STEPS = static_cast<int>((M_PI / 2) / STEP) + 1;
|
||||||
|
|
||||||
constexpr float FREEZE_PERCENTAGE = 0.2f; // Porcentaje final del recorrido que se mantiene fijo
|
constexpr float FREEZE_PERCENTAGE = 0.2F; // Porcentaje final del recorrido que se mantiene fijo
|
||||||
|
|
||||||
const int FREEZE_START_INDEX = static_cast<int>(NUM_STEPS * (1.0f - FREEZE_PERCENTAGE));
|
const int FREEZE_START_INDEX = static_cast<int>(NUM_STEPS * (1.0F - FREEZE_PERCENTAGE));
|
||||||
|
|
||||||
for (int i = 0; i < NUM_STEPS; ++i) {
|
for (int i = 0; i < NUM_STEPS; ++i) {
|
||||||
double theta = i * STEP;
|
double theta = i * STEP;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include <array> // Para array
|
#include <array> // Para array
|
||||||
#include <cstddef> // Para size_t
|
#include <cstddef> // Para size_t
|
||||||
#include <functional> // Para std::function
|
#include <functional> // Para function
|
||||||
#include <memory> // Para unique_ptr, shared_ptr
|
#include <memory> // Para unique_ptr, shared_ptr
|
||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
@@ -14,140 +14,109 @@ class MovingSprite;
|
|||||||
class Sprite;
|
class Sprite;
|
||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
/*
|
// --- Clase Background: gestiona el fondo de la sección jugable ---
|
||||||
Esta clase gestiona el fondo que aparece en la sección jugable.
|
|
||||||
|
|
||||||
Maneja internamente su progresión a través de diferentes estados del día/noche,
|
|
||||||
controlando las transiciones entre gradientes, posiciones del sol/luna y velocidad de nubes.
|
|
||||||
|
|
||||||
Estados:
|
|
||||||
- NORMAL: Progresión normal del día
|
|
||||||
- COMPLETED: Reducción gradual de la actividad (nubes más lentas)
|
|
||||||
|
|
||||||
Métodos clave:
|
|
||||||
- incrementProgress() -> Avanza la progresión del fondo
|
|
||||||
- setState() -> Cambia el estado del fondo
|
|
||||||
- setColor/setAlpha -> Efectos de atenuación
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Background {
|
class Background {
|
||||||
public:
|
public:
|
||||||
// Enumeración de estados
|
// --- Enums ---
|
||||||
enum class State {
|
enum class State {
|
||||||
NORMAL,
|
NORMAL, // Progresión normal del día
|
||||||
COMPLETED
|
COMPLETED // Reducción gradual de la actividad
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constructor y Destructor
|
// --- Tipos ---
|
||||||
Background(float total_progress_to_complete = 6100.0f);
|
using ProgressCallback = std::function<void(float)>; // Callback para sincronización
|
||||||
~Background();
|
|
||||||
|
|
||||||
// Actualización y renderizado
|
// --- Constructor y destructor ---
|
||||||
|
Background(float total_progress_to_complete = 6100.0F); // Constructor principal
|
||||||
|
~Background(); // Destructor
|
||||||
|
|
||||||
|
// --- Métodos principales ---
|
||||||
void update(); // Actualiza la lógica del objeto
|
void update(); // Actualiza la lógica del objeto
|
||||||
void render(); // Dibuja el objeto
|
void render(); // Dibuja el objeto
|
||||||
|
void reset(); // Reinicia la progresión
|
||||||
|
|
||||||
// Configuración de posición
|
// --- Configuración ---
|
||||||
void setPos(SDL_FRect pos); // Establece la posición del objeto
|
void setPos(SDL_FRect pos); // Establece la posición del objeto
|
||||||
|
void setState(State new_state); // Cambia el estado del fondo
|
||||||
// Control de progresión
|
|
||||||
void incrementProgress(float amount = 1.0f); // Incrementa la progresión interna
|
|
||||||
void setProgress(float absolute_progress); // Establece la progresión absoluta
|
|
||||||
void setState(State new_state); // Cambia el estado del fondo
|
|
||||||
void reset(); // Reinicia la progresión
|
|
||||||
|
|
||||||
// Sistema de callback para sincronización automática
|
|
||||||
using ProgressCallback = std::function<void(float)>;
|
|
||||||
void setProgressCallback(ProgressCallback callback); // Establece callback para sincronización
|
void setProgressCallback(ProgressCallback callback); // Establece callback para sincronización
|
||||||
void removeProgressCallback(); // Elimina el callback
|
void removeProgressCallback(); // Elimina el callback
|
||||||
|
void setManualMode(bool manual); // Activa/desactiva el modo manual
|
||||||
|
void setCloudsSpeed(float value); // Ajusta la velocidad de las nubes
|
||||||
|
void setGradientNumber(int value); // Establece el degradado de fondo
|
||||||
|
void setTransition(float value); // Ajusta la transición entre texturas
|
||||||
|
void setSunProgression(float progress); // Establece la posición del sol
|
||||||
|
void setMoonProgression(float progress); // Establece la posición de la luna
|
||||||
|
void setColor(Color color); // Establece el color de atenuación
|
||||||
|
void setAlpha(int alpha); // Ajusta la transparencia del fondo
|
||||||
|
|
||||||
// Configuración manual (para uso fuera del juego principal)
|
// --- Control de progresión ---
|
||||||
void setManualMode(bool manual); // Activa/desactiva el modo manual
|
void incrementProgress(float amount = 1.0F); // Incrementa la progresión interna
|
||||||
void setCloudsSpeed(float value); // Ajusta la velocidad de las nubes
|
void setProgress(float absolute_progress); // Establece la progresión absoluta
|
||||||
void setGradientNumber(int value); // Establece el degradado de fondo
|
|
||||||
void setTransition(float value); // Ajusta la transición entre texturas
|
|
||||||
void setSunProgression(float progress); // Establece la posición del sol
|
|
||||||
void setMoonProgression(float progress); // Establece la posición de la luna
|
|
||||||
|
|
||||||
// Configuración de efectos visuales
|
// --- Getters ---
|
||||||
void setColor(Color color); // Establece el color de atenuación
|
[[nodiscard]] auto getProgress() const -> float { return progress_; } // Obtiene el progreso actual
|
||||||
void setAlpha(int alpha); // Ajusta la transparencia del fondo
|
[[nodiscard]] auto getState() const -> State { return state_; } // Obtiene el estado actual
|
||||||
|
[[nodiscard]] auto getCurrentGradient() const -> int { return static_cast<int>(gradient_number_); } // Obtiene el gradiente actual
|
||||||
// Getters para información del estado
|
|
||||||
float getProgress() const { return progress_; }
|
|
||||||
State getState() const { return state_; }
|
|
||||||
int getCurrentGradient() const { return static_cast<int>(gradient_number_); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Constantes de configuración
|
// --- Constantes ---
|
||||||
static constexpr size_t STAGES = 4;
|
static constexpr size_t STAGES = 4; // Número de etapas
|
||||||
static constexpr float COMPLETED_REDUCTION_RATE = 25.0f;
|
static constexpr float COMPLETED_REDUCTION_RATE = 25.0F; // Tasa de reducción completada
|
||||||
static constexpr float MINIMUM_COMPLETED_PROGRESS = 200.0f;
|
static constexpr float MINIMUM_COMPLETED_PROGRESS = 200.0F; // Progreso mínimo completado
|
||||||
static constexpr float SUN_COMPLETION_FACTOR = 0.5f; // El sol completa su recorrido a la mitad del progreso total
|
static constexpr float SUN_COMPLETION_FACTOR = 0.5F; // Factor de completado del sol
|
||||||
|
|
||||||
// Configuración paramétrica
|
// --- Objetos y punteros ---
|
||||||
const float total_progress_to_complete_;
|
SDL_Renderer *renderer_; // Renderizador de la ventana
|
||||||
const float progress_per_stage_;
|
SDL_Texture *canvas_; // Textura para componer el fondo
|
||||||
const float sun_completion_progress_;
|
SDL_Texture *color_texture_; // Textura para atenuar el fondo
|
||||||
|
std::shared_ptr<Texture> buildings_texture_; // Textura de edificios
|
||||||
|
std::shared_ptr<Texture> top_clouds_texture_; // Textura de nubes superiores
|
||||||
|
std::shared_ptr<Texture> bottom_clouds_texture_; // Textura de nubes inferiores
|
||||||
|
std::shared_ptr<Texture> grass_texture_; // Textura de hierba
|
||||||
|
std::shared_ptr<Texture> gradients_texture_; // Textura de gradientes
|
||||||
|
std::shared_ptr<Texture> sun_texture_; // Textura del sol
|
||||||
|
std::shared_ptr<Texture> moon_texture_; // Textura de la luna
|
||||||
|
std::unique_ptr<MovingSprite> top_clouds_sprite_a_; // Sprite de nubes superiores A
|
||||||
|
std::unique_ptr<MovingSprite> top_clouds_sprite_b_; // Sprite de nubes superiores B
|
||||||
|
std::unique_ptr<MovingSprite> bottom_clouds_sprite_a_; // Sprite de nubes inferiores A
|
||||||
|
std::unique_ptr<MovingSprite> bottom_clouds_sprite_b_; // Sprite de nubes inferiores B
|
||||||
|
std::unique_ptr<Sprite> buildings_sprite_; // Sprite de edificios
|
||||||
|
std::unique_ptr<Sprite> gradient_sprite_; // Sprite de gradiente
|
||||||
|
std::unique_ptr<Sprite> grass_sprite_; // Sprite de hierba
|
||||||
|
std::unique_ptr<Sprite> sun_sprite_; // Sprite del sol
|
||||||
|
std::unique_ptr<Sprite> moon_sprite_; // Sprite de la luna
|
||||||
|
|
||||||
// Objetos y punteros
|
// --- Variables de configuración ---
|
||||||
SDL_Renderer *renderer_; // Renderizador de la ventana
|
const float total_progress_to_complete_; // Progreso total para completar
|
||||||
|
const float progress_per_stage_; // Progreso por etapa
|
||||||
|
const float sun_completion_progress_; // Progreso de completado del sol
|
||||||
|
ProgressCallback progress_callback_; // Callback para notificar cambios de progreso
|
||||||
|
|
||||||
// Texturas
|
// --- Variables de estado ---
|
||||||
std::shared_ptr<Texture> buildings_texture_;
|
std::vector<SDL_FPoint> sun_path_; // Recorrido del sol
|
||||||
std::shared_ptr<Texture> top_clouds_texture_;
|
std::vector<SDL_FPoint> moon_path_; // Recorrido de la luna
|
||||||
std::shared_ptr<Texture> bottom_clouds_texture_;
|
|
||||||
std::shared_ptr<Texture> grass_texture_;
|
|
||||||
std::shared_ptr<Texture> gradients_texture_;
|
|
||||||
std::shared_ptr<Texture> sun_texture_;
|
|
||||||
std::shared_ptr<Texture> moon_texture_;
|
|
||||||
|
|
||||||
// Sprites
|
|
||||||
std::unique_ptr<MovingSprite> top_clouds_sprite_a_;
|
|
||||||
std::unique_ptr<MovingSprite> top_clouds_sprite_b_;
|
|
||||||
std::unique_ptr<MovingSprite> bottom_clouds_sprite_a_;
|
|
||||||
std::unique_ptr<MovingSprite> bottom_clouds_sprite_b_;
|
|
||||||
std::unique_ptr<Sprite> buildings_sprite_;
|
|
||||||
std::unique_ptr<Sprite> gradient_sprite_;
|
|
||||||
std::unique_ptr<Sprite> grass_sprite_;
|
|
||||||
std::unique_ptr<Sprite> sun_sprite_;
|
|
||||||
std::unique_ptr<Sprite> moon_sprite_;
|
|
||||||
|
|
||||||
// Buffers de renderizado
|
|
||||||
SDL_Texture *canvas_; // Textura para componer el fondo
|
|
||||||
SDL_Texture *color_texture_; // Textura para atenuar el fondo
|
|
||||||
|
|
||||||
// Variables de estado y progresión
|
|
||||||
State state_ = State::NORMAL;
|
|
||||||
float progress_ = 0.0f; // Progresión interna (0 a total_progress_to_complete_)
|
|
||||||
bool manual_mode_ = false; // Si está en modo manual, no actualiza automáticamente
|
|
||||||
ProgressCallback progress_callback_; // Callback para notificar cambios de progreso
|
|
||||||
|
|
||||||
// Variables de renderizado
|
|
||||||
SDL_FRect rect_; // Tamaño del objeto
|
|
||||||
SDL_FRect src_rect_; // Parte del objeto para copiar en pantalla
|
|
||||||
SDL_FRect dst_rect_; // Posición en pantalla donde se copia el objeto
|
|
||||||
std::array<SDL_FRect, STAGES> gradient_rect_; // Fondos degradados
|
std::array<SDL_FRect, STAGES> gradient_rect_; // Fondos degradados
|
||||||
std::array<SDL_FRect, 4> top_clouds_rect_; // Nubes superiores
|
std::array<SDL_FRect, 4> top_clouds_rect_; // Nubes superiores
|
||||||
std::array<SDL_FRect, 4> bottom_clouds_rect_; // Nubes inferiores
|
std::array<SDL_FRect, 4> bottom_clouds_rect_; // Nubes inferiores
|
||||||
|
SDL_FRect rect_; // Tamaño del objeto
|
||||||
|
SDL_FRect src_rect_; // Parte del objeto para copiar en pantalla
|
||||||
|
SDL_FRect dst_rect_; // Posición en pantalla donde se copia el objeto
|
||||||
Color attenuate_color_; // Color de atenuación
|
Color attenuate_color_; // Color de atenuación
|
||||||
|
State state_ = State::NORMAL; // Estado actual
|
||||||
|
float progress_ = 0.0F; // Progresión interna
|
||||||
|
float clouds_speed_ = 0; // Velocidad de las nubes
|
||||||
|
float transition_ = 0; // Porcentaje de transición
|
||||||
|
size_t gradient_number_ = 0; // Índice de fondo degradado
|
||||||
|
size_t counter_ = 0; // Contador interno
|
||||||
|
size_t alpha_color_texture_ = 0; // Transparencia de atenuación
|
||||||
|
size_t previous_alpha_color_texture_ = 0; // Transparencia anterior
|
||||||
|
size_t sun_index_ = 0; // Índice del recorrido del sol
|
||||||
|
size_t moon_index_ = 0; // Índice del recorrido de la luna
|
||||||
|
int base_ = 0; // Posición base del fondo
|
||||||
|
Uint8 alpha_ = 0; // Transparencia entre fases
|
||||||
|
bool manual_mode_ = false; // Si está en modo manual
|
||||||
|
|
||||||
std::vector<SDL_FPoint> sun_path_; // Recorrido del sol
|
// --- Métodos internos ---
|
||||||
std::vector<SDL_FPoint> moon_path_; // Recorrido de la luna
|
|
||||||
|
|
||||||
float clouds_speed_ = 0; // Velocidad de las nubes
|
|
||||||
float transition_ = 0; // Porcentaje de transición
|
|
||||||
|
|
||||||
size_t gradient_number_ = 0; // Índice de fondo degradado
|
|
||||||
size_t counter_ = 0; // Contador interno
|
|
||||||
size_t alpha_color_texture_ = 0; // Transparencia de atenuación
|
|
||||||
size_t previous_alpha_color_texture_ = 0; // Transparencia anterior
|
|
||||||
size_t sun_index_ = 0; // Índice del recorrido del sol
|
|
||||||
size_t moon_index_ = 0; // Índice del recorrido de la luna
|
|
||||||
int base_ = 0; // Posición base del fondo
|
|
||||||
|
|
||||||
Uint8 alpha_ = 0; // Transparencia entre fases
|
|
||||||
|
|
||||||
// Métodos internos
|
|
||||||
void initializePaths(); // Inicializa las rutas del sol y la luna
|
void initializePaths(); // Inicializa las rutas del sol y la luna
|
||||||
void initializeRects(); // Inicializa los rectángulos de gradientes y nubes
|
void initializeRects(); // Inicializa los rectángulos de gradientes y nubes
|
||||||
void initializeSprites(); // Crea los sprites
|
void initializeSprites(); // Crea los sprites
|
||||||
|
|||||||
@@ -11,20 +11,21 @@
|
|||||||
#include "texture.h" // Para Texture
|
#include "texture.h" // Para Texture
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Balloon::Balloon(float x, float y, Type type, Size size, float vel_x, float speed, Uint16 creation_timer, SDL_FRect play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation)
|
Balloon::Balloon(const Config& config)
|
||||||
: sprite_(std::make_unique<AnimatedSprite>(texture, animation)),
|
: sprite_(std::make_unique<AnimatedSprite>(config.texture, config.animation)),
|
||||||
x_(x),
|
x_(config.x),
|
||||||
y_(y),
|
y_(config.y),
|
||||||
vx_(vel_x),
|
vx_(config.vel_x),
|
||||||
being_created_(creation_timer > 0),
|
being_created_(config.creation_counter > 0),
|
||||||
invulnerable_(creation_timer > 0),
|
invulnerable_(config.creation_counter > 0),
|
||||||
stopped_(creation_timer > 0),
|
stopped_(config.creation_counter > 0),
|
||||||
creation_counter_(creation_timer),
|
creation_counter_(config.creation_counter),
|
||||||
creation_counter_ini_(creation_timer),
|
creation_counter_ini_(config.creation_counter),
|
||||||
type_(type),
|
type_(config.type),
|
||||||
size_(size),
|
size_(config.size),
|
||||||
speed_(speed),
|
speed_(config.speed),
|
||||||
play_area_(play_area) {
|
play_area_(config.play_area),
|
||||||
|
sound_(config.sound) {
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
case Type::BALLOON: {
|
case Type::BALLOON: {
|
||||||
vy_ = 0;
|
vy_ = 0;
|
||||||
@@ -37,14 +38,13 @@ Balloon::Balloon(float x, float y, Type type, Size size, float vel_x, float spee
|
|||||||
power_ = POWER.at(INDEX);
|
power_ = POWER.at(INDEX);
|
||||||
menace_ = MENACE.at(INDEX);
|
menace_ = MENACE.at(INDEX);
|
||||||
score_ = SCORE.at(INDEX);
|
score_ = SCORE.at(INDEX);
|
||||||
bouncing_sound_ = BOUNCING_SOUND.at(INDEX);
|
sound_.bouncing_file = BOUNCING_SOUND.at(INDEX);
|
||||||
popping_sound_ = POPPING_SOUND.at(INDEX);
|
sound_.popping_file = POPPING_SOUND.at(INDEX);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Type::FLOATER: {
|
case Type::FLOATER: {
|
||||||
default_vy_ = max_vy_ = vy_ = fabs(vx_ * 2.0F);
|
default_vy_ = max_vy_ = vy_ = std::fabs(vx_ * 2.0F);
|
||||||
gravity_ = 0.00F;
|
gravity_ = 0.00F;
|
||||||
|
|
||||||
const int INDEX = static_cast<int>(size_);
|
const int INDEX = static_cast<int>(size_);
|
||||||
@@ -52,17 +52,16 @@ Balloon::Balloon(float x, float y, Type type, Size size, float vel_x, float spee
|
|||||||
power_ = POWER.at(INDEX);
|
power_ = POWER.at(INDEX);
|
||||||
menace_ = MENACE.at(INDEX);
|
menace_ = MENACE.at(INDEX);
|
||||||
score_ = SCORE.at(INDEX);
|
score_ = SCORE.at(INDEX);
|
||||||
bouncing_sound_ = BOUNCING_SOUND.at(INDEX);
|
sound_.bouncing_file = BOUNCING_SOUND.at(INDEX);
|
||||||
popping_sound_ = POPPING_SOUND.at(INDEX);
|
sound_.popping_file = POPPING_SOUND.at(INDEX);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Type::POWERBALL: {
|
case Type::POWERBALL: {
|
||||||
constexpr int INDEX = 3;
|
constexpr int INDEX = 3;
|
||||||
h_ = w_ = WIDTH.at(4);
|
h_ = w_ = WIDTH.at(4);
|
||||||
bouncing_sound_ = BOUNCING_SOUND.at(3);
|
sound_.bouncing_file = BOUNCING_SOUND.at(3);
|
||||||
popping_sound_ = "power_ball_explosion.wav";
|
sound_.popping_file = "power_ball_explosion.wav";
|
||||||
power_ = score_ = menace_ = 0;
|
power_ = score_ = menace_ = 0;
|
||||||
|
|
||||||
vy_ = 0;
|
vy_ = 0;
|
||||||
@@ -70,9 +69,8 @@ Balloon::Balloon(float x, float y, Type type, Size size, float vel_x, float spee
|
|||||||
gravity_ = param.balloon.settings.at(INDEX).grav;
|
gravity_ = param.balloon.settings.at(INDEX).grav;
|
||||||
default_vy_ = param.balloon.settings.at(INDEX).vel;
|
default_vy_ = param.balloon.settings.at(INDEX).vel;
|
||||||
|
|
||||||
sprite_->setRotate(creation_timer <= 0);
|
sprite_->setRotate(config.creation_counter <= 0);
|
||||||
sprite_->setRotateAmount(vx_ > 0.0F ? 2.0 : -2.0);
|
sprite_->setRotateAmount(vx_ > 0.0F ? 2.0 : -2.0);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,8 +231,14 @@ void Balloon::applyGravity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Balloon::playBouncingSound() {
|
void Balloon::playBouncingSound() {
|
||||||
if (bouncing_sound_enabled_) {
|
if (sound_.enabled && sound_.bouncing_enabled) {
|
||||||
playSound(bouncing_sound_);
|
Audio::get()->playSound(sound_.bouncing_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Balloon::playPoppingSound() {
|
||||||
|
if (sound_.enabled && sound_.poping_enabled) {
|
||||||
|
Audio::get()->playSound(sound_.popping_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,23 +372,8 @@ void Balloon::useNormalColor() {
|
|||||||
setAnimation();
|
setAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reproduce sonido
|
|
||||||
void Balloon::playSound(const std::string &name) const {
|
|
||||||
if (!sound_enabled_) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static auto *audio_ = Audio::get();
|
|
||||||
audio_->playSound(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Explota el globo
|
// Explota el globo
|
||||||
void Balloon::pop(bool should_sound) {
|
void Balloon::pop(bool should_sound) {
|
||||||
if (should_sound) {
|
if (should_sound) { playPoppingSound(); }
|
||||||
if (poping_sound_enabled_) {
|
|
||||||
playSound(popping_sound_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enabled_ = false;
|
enabled_ = false;
|
||||||
}
|
}
|
||||||
155
source/balloon.h
@@ -25,10 +25,16 @@ class Balloon {
|
|||||||
static constexpr std::array<int, 5> WIDTH = {10, 16, 26, 48, 49};
|
static constexpr std::array<int, 5> WIDTH = {10, 16, 26, 48, 49};
|
||||||
|
|
||||||
static constexpr std::array<std::string_view, 4> BOUNCING_SOUND = {
|
static constexpr std::array<std::string_view, 4> BOUNCING_SOUND = {
|
||||||
"balloon_bounce0.wav", "balloon_bounce1.wav", "balloon_bounce2.wav", "balloon_bounce3.wav"};
|
"balloon_bounce0.wav",
|
||||||
|
"balloon_bounce1.wav",
|
||||||
|
"balloon_bounce2.wav",
|
||||||
|
"balloon_bounce3.wav"};
|
||||||
|
|
||||||
static constexpr std::array<std::string_view, 4> POPPING_SOUND = {
|
static constexpr std::array<std::string_view, 4> POPPING_SOUND = {
|
||||||
"balloon_pop0.wav", "balloon_pop1.wav", "balloon_pop2.wav", "balloon_pop3.wav"};
|
"balloon_pop0.wav",
|
||||||
|
"balloon_pop1.wav",
|
||||||
|
"balloon_pop2.wav",
|
||||||
|
"balloon_pop3.wav"};
|
||||||
|
|
||||||
static constexpr float VELX_POSITIVE = 0.7F;
|
static constexpr float VELX_POSITIVE = 0.7F;
|
||||||
static constexpr float VELX_NEGATIVE = -0.7F;
|
static constexpr float VELX_NEGATIVE = -0.7F;
|
||||||
@@ -38,31 +44,46 @@ class Balloon {
|
|||||||
static constexpr int POWERBALL_SCREENPOWER_MINIMUM = 10;
|
static constexpr int POWERBALL_SCREENPOWER_MINIMUM = 10;
|
||||||
static constexpr int POWERBALL_COUNTER = 8;
|
static constexpr int POWERBALL_COUNTER = 8;
|
||||||
|
|
||||||
|
// --- Enums ---
|
||||||
enum class Size : Uint8 {
|
enum class Size : Uint8 {
|
||||||
SMALL = 0,
|
SMALL = 0, // Tamaño pequeño
|
||||||
MEDIUM = 1,
|
MEDIUM = 1, // Tamaño mediano
|
||||||
LARGE = 2,
|
LARGE = 2, // Tamaño grande
|
||||||
EXTRALARGE = 3,
|
EXTRALARGE = 3, // Tamaño extra grande
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Type : Uint8 {
|
enum class Type : Uint8 {
|
||||||
BALLOON = 0,
|
BALLOON = 0, // Globo normal
|
||||||
FLOATER = 1,
|
FLOATER = 1, // Globo flotante
|
||||||
POWERBALL = 2,
|
POWERBALL = 2, // Globo de poder
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- Estructura para manejo de sonido ---
|
||||||
|
struct Sound {
|
||||||
|
std::string bouncing_file; // Archivo de sonido al rebotar
|
||||||
|
std::string popping_file; // Archivo de sonido al explotar
|
||||||
|
bool bouncing_enabled = false; // Si debe sonar el globo al rebotar
|
||||||
|
bool poping_enabled = true; // Si debe sonar el globo al explotar
|
||||||
|
bool enabled = true; // Indica si los globos deben hacer algun sonido
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- Estructura de configuración para inicialización ---
|
||||||
|
struct Config {
|
||||||
|
float x = 0.0F;
|
||||||
|
float y = 0.0F;
|
||||||
|
Type type = Type::BALLOON;
|
||||||
|
Size size = Size::EXTRALARGE;
|
||||||
|
float vel_x = VELX_POSITIVE;
|
||||||
|
float speed = SPEED.at(0);
|
||||||
|
Uint16 creation_counter = 0;
|
||||||
|
SDL_FRect play_area = {.x = 0.0F, .y = 0.0F, .w = 0.0F, .h = 0.0F};
|
||||||
|
std::shared_ptr<Texture> texture = nullptr;
|
||||||
|
std::vector<std::string> animation;
|
||||||
|
Sound sound;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Constructores y destructor ---
|
// --- Constructores y destructor ---
|
||||||
Balloon(
|
Balloon(const Config& config);
|
||||||
float x,
|
|
||||||
float y,
|
|
||||||
Type type,
|
|
||||||
Size size,
|
|
||||||
float vel_x,
|
|
||||||
float speed,
|
|
||||||
Uint16 creation_timer,
|
|
||||||
SDL_FRect play_area,
|
|
||||||
std::shared_ptr<Texture> texture,
|
|
||||||
const std::vector<std::string>& animation);
|
|
||||||
~Balloon() = default;
|
~Balloon() = default;
|
||||||
|
|
||||||
// --- Métodos principales ---
|
// --- Métodos principales ---
|
||||||
@@ -101,9 +122,9 @@ class Balloon {
|
|||||||
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 setBouncingSound(bool value) { bouncing_sound_enabled_ = value; }
|
void setBouncingSound(bool value) { sound_.bouncing_enabled = value; }
|
||||||
void setPoppingSound(bool value) { poping_sound_enabled_ = value; }
|
void setPoppingSound(bool value) { sound_.poping_enabled = value; }
|
||||||
void setSound(bool value) { sound_enabled_ = value; }
|
void setSound(bool value) { sound_.enabled = value; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Estructura para el efecto de rebote ---
|
// --- Estructura para el efecto de rebote ---
|
||||||
@@ -113,10 +134,28 @@ class Balloon {
|
|||||||
|
|
||||||
// Tablas de valores predefinidos para el efecto de rebote
|
// Tablas de valores predefinidos para el efecto de rebote
|
||||||
static constexpr std::array<float, BOUNCE_FRAMES> HORIZONTAL_ZOOM_VALUES = {
|
static constexpr std::array<float, BOUNCE_FRAMES> HORIZONTAL_ZOOM_VALUES = {
|
||||||
1.10F, 1.05F, 1.00F, 0.95F, 0.90F, 0.95F, 1.00F, 1.02F, 1.05F, 1.02F};
|
1.10F,
|
||||||
|
1.05F,
|
||||||
|
1.00F,
|
||||||
|
0.95F,
|
||||||
|
0.90F,
|
||||||
|
0.95F,
|
||||||
|
1.00F,
|
||||||
|
1.02F,
|
||||||
|
1.05F,
|
||||||
|
1.02F};
|
||||||
|
|
||||||
static constexpr std::array<float, BOUNCE_FRAMES> VERTICAL_ZOOM_VALUES = {
|
static constexpr std::array<float, BOUNCE_FRAMES> VERTICAL_ZOOM_VALUES = {
|
||||||
0.90F, 0.95F, 1.00F, 1.05F, 1.10F, 1.05F, 1.00F, 0.98F, 0.95F, 0.98F};
|
0.90F,
|
||||||
|
0.95F,
|
||||||
|
1.00F,
|
||||||
|
1.05F,
|
||||||
|
1.10F,
|
||||||
|
1.05F,
|
||||||
|
1.00F,
|
||||||
|
0.98F,
|
||||||
|
0.95F,
|
||||||
|
0.98F};
|
||||||
|
|
||||||
// Estado del efecto
|
// Estado del efecto
|
||||||
bool enabled_ = false; // Si el efecto está activo
|
bool enabled_ = false; // Si el efecto está activo
|
||||||
@@ -202,47 +241,43 @@ class Balloon {
|
|||||||
std::unique_ptr<AnimatedSprite> sprite_; // Sprite del objeto globo
|
std::unique_ptr<AnimatedSprite> sprite_; // Sprite del objeto globo
|
||||||
|
|
||||||
// --- Variables de estado y físicas ---
|
// --- Variables de estado y físicas ---
|
||||||
float x_; // Posición X
|
float x_; // Posición X
|
||||||
float y_; // Posición Y
|
float y_; // Posición Y
|
||||||
float w_; // Ancho
|
float w_; // Ancho
|
||||||
float h_; // Alto
|
float h_; // Alto
|
||||||
float vx_; // Velocidad X
|
float vx_; // Velocidad X
|
||||||
float vy_; // Velocidad Y
|
float vy_; // Velocidad Y
|
||||||
float gravity_; // Aceleración en Y
|
float gravity_; // Aceleración en Y
|
||||||
float default_vy_; // Velocidad inicial al rebotar
|
float default_vy_; // Velocidad inicial al rebotar
|
||||||
float max_vy_; // Máxima velocidad en Y
|
float max_vy_; // Máxima velocidad en Y
|
||||||
bool being_created_; // Si el globo se está creando
|
bool being_created_; // Si el globo se está creando
|
||||||
bool enabled_ = true; // Si el globo está activo
|
bool enabled_ = true; // Si el globo está activo
|
||||||
bool invulnerable_; // Si el globo es invulnerable
|
bool invulnerable_; // Si el globo es invulnerable
|
||||||
bool stopped_; // Si el globo está parado
|
bool stopped_; // Si el globo está parado
|
||||||
bool use_reversed_colors_ = false; // Si se usa el color alternativo
|
bool use_reversed_colors_ = false; // Si se usa el color alternativo
|
||||||
Circle collider_; // Círculo de colisión
|
Circle collider_; // Círculo de colisión
|
||||||
Uint16 creation_counter_; // Temporizador de creación
|
Uint16 creation_counter_; // Temporizador de creación
|
||||||
Uint16 creation_counter_ini_; // Valor inicial del temporizador de creación
|
Uint16 creation_counter_ini_; // Valor inicial del temporizador de creación
|
||||||
Uint16 score_; // Puntos al destruir el globo
|
Uint16 score_; // Puntos al destruir el globo
|
||||||
Type type_; // Tipo de globo
|
Type type_; // Tipo de globo
|
||||||
Size size_; // Tamaño de globo
|
Size size_; // Tamaño de globo
|
||||||
Uint8 menace_; // Amenaza que genera el globo
|
Uint8 menace_; // Amenaza que genera el globo
|
||||||
Uint32 counter_ = 0; // Contador interno
|
Uint32 counter_ = 0; // Contador interno
|
||||||
float travel_y_ = 1.0F; // Distancia a recorrer en Y antes de aplicar gravedad
|
float travel_y_ = 1.0F; // Distancia a recorrer en Y antes de aplicar gravedad
|
||||||
float speed_; // Velocidad del globo
|
float speed_; // Velocidad del globo
|
||||||
Uint8 power_; // Poder que alberga el globo
|
Uint8 power_; // Poder que alberga el globo
|
||||||
SDL_FRect play_area_; // Zona de movimiento del globo
|
SDL_FRect play_area_; // Zona de movimiento del globo
|
||||||
std::string bouncing_sound_; // Archivo de sonido al rebotar
|
Sound sound_; // Configuración de sonido del globo
|
||||||
std::string popping_sound_; // Archivo de sonido al explotar
|
BounceEffect bounce_effect_; // Efecto de rebote
|
||||||
bool bouncing_sound_enabled_ = false; // Si debe sonar el globo al rebotar
|
|
||||||
bool poping_sound_enabled_ = true; // Si debe sonar el globo al explotar
|
|
||||||
bool sound_enabled_ = true; // Indica si los globos deben hacer algun sonido
|
|
||||||
BounceEffect bounce_effect_; // Efecto de rebote
|
|
||||||
|
|
||||||
// --- Posicionamiento y transformación ---
|
// --- Posicionamiento y transformación ---
|
||||||
void shiftColliders(); // Alinea el círculo de colisión con el sprite
|
void shiftColliders(); // Alinea el círculo de colisión con el sprite
|
||||||
void shiftSprite(); // Alinea el sprite en pantalla
|
void shiftSprite(); // Alinea el sprite en pantalla
|
||||||
|
|
||||||
// --- Animación y sonido ---
|
// --- Animación y sonido ---
|
||||||
void setAnimation(); // Establece la animación correspondiente
|
void setAnimation(); // Establece la animación correspondiente
|
||||||
void playSound(const std::string& name) const; // Reproduce un sonido por nombre
|
void playBouncingSound(); // Reproduce el sonido de rebote
|
||||||
void playBouncingSound(); // Reproduce el sonido de rebote
|
void playPoppingSound(); // Reproduce el sonido de reventar
|
||||||
|
|
||||||
// --- Movimiento y física ---
|
// --- Movimiento y física ---
|
||||||
void handleHorizontalMovement(); // Maneja el movimiento horizontal
|
void handleHorizontalMovement(); // Maneja el movimiento horizontal
|
||||||
|
|||||||
@@ -13,21 +13,26 @@
|
|||||||
// --- Clase BalloonFormations ---
|
// --- Clase BalloonFormations ---
|
||||||
class BalloonFormations {
|
class BalloonFormations {
|
||||||
public:
|
public:
|
||||||
// --- Estructuras de datos ---
|
// --- Estructuras ---
|
||||||
struct SpawnParams {
|
struct SpawnParams {
|
||||||
int x = 0; // Posición en el eje X donde crear el globo
|
float x = 0; // Posición en el eje X donde crear el globo
|
||||||
int y = 0; // Posición en el eje Y donde crear el globo
|
float y = 0; // Posición en el eje Y donde crear el globo
|
||||||
float vel_x = 0.0F; // Velocidad inicial en el eje X
|
float vel_x = 0.0F; // Velocidad inicial en el eje X
|
||||||
Balloon::Type type = Balloon::Type::BALLOON; // Tipo de globo
|
Balloon::Type type = Balloon::Type::BALLOON; // Tipo de globo
|
||||||
Balloon::Size size = Balloon::Size::SMALL; // Tamaño de globo
|
Balloon::Size size = Balloon::Size::SMALL; // Tamaño de globo
|
||||||
int creation_counter = 0; // Temporizador para la creación del globo
|
Uint16 creation_counter = 0; // Temporizador para la creación del globo
|
||||||
|
|
||||||
// Constructor por defecto
|
// Constructor por defecto
|
||||||
SpawnParams() = default;
|
SpawnParams() = default;
|
||||||
|
|
||||||
// Constructor con parámetros
|
// Constructor con parámetros
|
||||||
SpawnParams(int x, int y, float vel_x, Balloon::Type type, Balloon::Size size, int creation_counter)
|
SpawnParams(float x, float y, float vel_x, Balloon::Type type, Balloon::Size size, Uint16 creation_counter)
|
||||||
: x(x), y(y), vel_x(vel_x), type(type), size(size), creation_counter(creation_counter) {}
|
: x(x),
|
||||||
|
y(y),
|
||||||
|
vel_x(vel_x),
|
||||||
|
type(type),
|
||||||
|
size(size),
|
||||||
|
creation_counter(creation_counter) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Formation {
|
struct Formation {
|
||||||
@@ -41,8 +46,8 @@ class BalloonFormations {
|
|||||||
Formation() = default;
|
Formation() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Vector de índices a formaciones
|
// --- Types ---
|
||||||
using Pool = std::vector<int>;
|
using Pool = std::vector<int>; // Vector de índices a formaciones
|
||||||
|
|
||||||
// --- Constructor y destructor ---
|
// --- Constructor y destructor ---
|
||||||
BalloonFormations() {
|
BalloonFormations() {
|
||||||
@@ -79,28 +84,20 @@ class BalloonFormations {
|
|||||||
static constexpr int BALLOON_SPAWN_HEIGHT = 208; // Altura desde el suelo en la que aparecen los globos
|
static constexpr int BALLOON_SPAWN_HEIGHT = 208; // Altura desde el suelo en la que aparecen los globos
|
||||||
static constexpr int DEFAULT_CREATION_TIME = 200; // Tiempo base de creación de los globos para las formaciones
|
static constexpr int DEFAULT_CREATION_TIME = 200; // Tiempo base de creación de los globos para las formaciones
|
||||||
|
|
||||||
// --- Datos ---
|
// --- Variables ---
|
||||||
std::vector<Formation> formations_; // Vector con todas las formaciones disponibles
|
std::vector<Formation> formations_; // Vector con todas las formaciones disponibles
|
||||||
std::vector<Pool> pools_; // Vector de pools, cada pool contiene índices a formaciones
|
std::vector<Pool> pools_; // Vector de pools, cada pool contiene índices a formaciones
|
||||||
|
|
||||||
// --- Inicialización de formaciones ---
|
// --- Métodos internos ---
|
||||||
void initFormations(); // Inicializa la lista principal de formaciones de globos disponibles
|
void initFormations(); // Inicializa la lista principal de formaciones de globos disponibles
|
||||||
void initFormationPools(); // Carga los pools desde archivo de configuración
|
void initFormationPools(); // Carga los pools desde archivo de configuración
|
||||||
|
|
||||||
// --- Carga y análisis de datos ---
|
|
||||||
auto loadFormationsFromFile(const std::string& filename, const std::map<std::string, float>& variables) -> bool;
|
auto loadFormationsFromFile(const std::string& filename, const std::map<std::string, float>& variables) -> bool;
|
||||||
auto parseBalloonLine(const std::string& line, const std::map<std::string, float>& variables) -> std::optional<SpawnParams>;
|
auto parseBalloonLine(const std::string& line, const std::map<std::string, float>& variables) -> std::optional<SpawnParams>;
|
||||||
auto loadPoolsFromFile(const std::string& filename) -> bool; // Nueva función para cargar pools
|
auto loadPoolsFromFile(const std::string& filename) -> bool; // Nueva función para cargar pools
|
||||||
auto parsePoolLine(const std::string& line) -> std::optional<std::pair<int, std::vector<int>>>; // Nueva función para parsear líneas de pools
|
auto parsePoolLine(const std::string& line) -> std::optional<std::pair<int, std::vector<int>>>; // Nueva función para parsear líneas de pools
|
||||||
|
|
||||||
// --- Evaluación de expresiones ---
|
|
||||||
auto evaluateExpression(const std::string& expr, const std::map<std::string, float>& variables) -> float;
|
auto evaluateExpression(const std::string& expr, const std::map<std::string, float>& variables) -> float;
|
||||||
auto evaluateSimpleExpression(const std::string& expr, const std::map<std::string, float>& variables) -> float;
|
auto evaluateSimpleExpression(const std::string& expr, const std::map<std::string, float>& variables) -> float;
|
||||||
|
|
||||||
// --- Utilidades ---
|
|
||||||
static auto trim(const std::string& str) -> std::string;
|
static auto trim(const std::string& str) -> std::string;
|
||||||
|
|
||||||
// --- Generación de variantes ---
|
|
||||||
void createFloaterVariants();
|
void createFloaterVariants();
|
||||||
void loadDefaultFormations();
|
void loadDefaultFormations();
|
||||||
void loadDefaultPools(); // Nueva función para pools por defecto
|
void loadDefaultPools(); // Nueva función para pools por defecto
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ void BalloonManager::init() {
|
|||||||
|
|
||||||
// Actualiza
|
// Actualiza
|
||||||
void BalloonManager::update() {
|
void BalloonManager::update() {
|
||||||
for (auto balloon : balloons_) {
|
for (const auto &balloon : balloons_) {
|
||||||
balloon->update();
|
balloon->update();
|
||||||
}
|
}
|
||||||
updateBalloonDeployCounter();
|
updateBalloonDeployCounter();
|
||||||
@@ -107,7 +107,15 @@ void BalloonManager::deployRandomFormation(int stage) {
|
|||||||
// Crea los globos de la formación
|
// Crea los globos de la formación
|
||||||
const auto BALLOONS = balloon_formations_->getFormationFromPool(stage, formation_id).balloons;
|
const auto BALLOONS = balloon_formations_->getFormationFromPool(stage, formation_id).balloons;
|
||||||
for (auto balloon : BALLOONS) {
|
for (auto balloon : BALLOONS) {
|
||||||
createBalloon(balloon.x, balloon.y, balloon.type, balloon.size, balloon.vel_x, balloon_speed_, (creation_time_enabled_) ? balloon.creation_counter : 0);
|
Balloon::Config config = {
|
||||||
|
.x = balloon.x,
|
||||||
|
.y = balloon.y,
|
||||||
|
.type = balloon.type,
|
||||||
|
.size = balloon.size,
|
||||||
|
.vel_x = balloon.vel_x,
|
||||||
|
.speed = balloon_speed_,
|
||||||
|
.creation_counter = static_cast<Uint16>(creation_time_enabled_ ? balloon.creation_counter : 0)};
|
||||||
|
createBalloon(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reinicia el contador para el próximo despliegue
|
// Reinicia el contador para el próximo despliegue
|
||||||
@@ -120,22 +128,38 @@ void BalloonManager::deployRandomFormation(int stage) {
|
|||||||
void BalloonManager::deployFormation(int formation_id) {
|
void BalloonManager::deployFormation(int formation_id) {
|
||||||
const auto BALLOONS = balloon_formations_->getFormation(formation_id).balloons;
|
const auto BALLOONS = balloon_formations_->getFormation(formation_id).balloons;
|
||||||
for (auto balloon : BALLOONS) {
|
for (auto balloon : BALLOONS) {
|
||||||
createBalloon(balloon.x, balloon.y, balloon.type, balloon.size, balloon.vel_x, balloon_speed_, balloon.creation_counter);
|
Balloon::Config config = {
|
||||||
|
.x = balloon.x,
|
||||||
|
.y = balloon.y,
|
||||||
|
.type = balloon.type,
|
||||||
|
.size = balloon.size,
|
||||||
|
.vel_x = balloon.vel_x,
|
||||||
|
.speed = balloon_speed_,
|
||||||
|
.creation_counter = balloon.creation_counter};
|
||||||
|
createBalloon(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crea una formación de globos específica a una altura determinada
|
// Crea una formación de globos específica a una altura determinada
|
||||||
void BalloonManager::deployFormation(int formation_id, int y) {
|
void BalloonManager::deployFormation(int formation_id, float y) {
|
||||||
const auto BALLOONS = balloon_formations_->getFormation(formation_id).balloons;
|
const auto BALLOONS = balloon_formations_->getFormation(formation_id).balloons;
|
||||||
for (auto balloon : BALLOONS) {
|
for (auto balloon : BALLOONS) {
|
||||||
createBalloon(balloon.x, y, balloon.type, balloon.size, balloon.vel_x, balloon_speed_, balloon.creation_counter);
|
Balloon::Config config = {
|
||||||
|
.x = balloon.x,
|
||||||
|
.y = y,
|
||||||
|
.type = balloon.type,
|
||||||
|
.size = balloon.size,
|
||||||
|
.vel_x = balloon.vel_x,
|
||||||
|
.speed = balloon_speed_,
|
||||||
|
.creation_counter = balloon.creation_counter};
|
||||||
|
createBalloon(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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() {
|
||||||
auto it = std::remove_if(balloons_.begin(), balloons_.end(), [](const auto &balloon) { return !balloon->isEnabled(); });
|
auto result = std::ranges::remove_if(balloons_, [](const auto &balloon) { return !balloon->isEnabled(); });
|
||||||
balloons_.erase(it, balloons_.end());
|
balloons_.erase(result.begin(), balloons_.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualiza la variable enemyDeployCounter
|
// Actualiza la variable enemyDeployCounter
|
||||||
@@ -154,13 +178,16 @@ auto BalloonManager::calculateScreenPower() -> int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Crea un globo nuevo en el vector de globos
|
// Crea un globo nuevo en el vector de globos
|
||||||
auto BalloonManager::createBalloon(float x, int y, Balloon::Type type, Balloon::Size size, float velx, float speed, int creation_timer) -> std::shared_ptr<Balloon> {
|
auto BalloonManager::createBalloon(Balloon::Config config) -> std::shared_ptr<Balloon> {
|
||||||
if (can_deploy_balloons_) {
|
if (can_deploy_balloons_) {
|
||||||
const int INDEX = static_cast<int>(size);
|
const int INDEX = static_cast<int>(config.size);
|
||||||
balloons_.emplace_back(std::make_shared<Balloon>(x, y, type, size, velx, speed, creation_timer, play_area_, balloon_textures_.at(INDEX), balloon_animations_.at(INDEX)));
|
config.play_area = play_area_;
|
||||||
balloons_.back()->setSound(sound_enabled_);
|
config.texture = balloon_textures_.at(INDEX);
|
||||||
balloons_.back()->setBouncingSound(bouncing_sound_enabled_);
|
config.animation = balloon_animations_.at(INDEX);
|
||||||
balloons_.back()->setPoppingSound(poping_sound_enabled_);
|
config.sound.enabled = sound_enabled_;
|
||||||
|
config.sound.bouncing_enabled = bouncing_sound_enabled_;
|
||||||
|
config.sound.poping_enabled = poping_sound_enabled_;
|
||||||
|
balloons_.emplace_back(std::make_shared<Balloon>(config));
|
||||||
return balloons_.back();
|
return balloons_.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,19 +198,24 @@ auto BalloonManager::createBalloon(float x, int y, Balloon::Type type, Balloon::
|
|||||||
void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction) {
|
void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction) {
|
||||||
if (can_deploy_balloons_) {
|
if (can_deploy_balloons_) {
|
||||||
// Calcula parametros
|
// Calcula parametros
|
||||||
const float VX = direction == "LEFT" ? Balloon::VELX_NEGATIVE : Balloon::VELX_POSITIVE;
|
|
||||||
const auto SIZE = static_cast<Balloon::Size>(static_cast<int>(balloon->getSize()) - 1);
|
|
||||||
const int PARENT_HEIGHT = balloon->getHeight();
|
const int PARENT_HEIGHT = balloon->getHeight();
|
||||||
const int CHILD_HEIGHT = Balloon::WIDTH.at(static_cast<int>(balloon->getSize()) - 1);
|
const int CHILD_HEIGHT = Balloon::WIDTH.at(static_cast<int>(balloon->getSize()) - 1);
|
||||||
const int CHILD_WIDTH = CHILD_HEIGHT;
|
const int CHILD_WIDTH = CHILD_HEIGHT;
|
||||||
const float Y = balloon->getPosY() + ((PARENT_HEIGHT - CHILD_HEIGHT) / 2);
|
|
||||||
float x = direction == "LEFT" ? balloon->getPosX() + (balloon->getWidth() / 3) : balloon->getPosX() + (2 * (balloon->getWidth() / 3));
|
const float X = direction == "LEFT" ? balloon->getPosX() + (balloon->getWidth() / 3) : balloon->getPosX() + (2 * (balloon->getWidth() / 3));
|
||||||
const float MIN_X = play_area_.x;
|
const float MIN_X = play_area_.x;
|
||||||
const float MAX_X = play_area_.w - CHILD_WIDTH;
|
const float MAX_X = play_area_.w - CHILD_WIDTH;
|
||||||
x = std::clamp(x - (CHILD_WIDTH / 2), MIN_X, MAX_X);
|
|
||||||
|
Balloon::Config config = {
|
||||||
|
.x = std::clamp(X - (CHILD_WIDTH / 2), MIN_X, MAX_X),
|
||||||
|
.y = balloon->getPosY() + ((PARENT_HEIGHT - CHILD_HEIGHT) / 2),
|
||||||
|
.size = static_cast<Balloon::Size>(static_cast<int>(balloon->getSize()) - 1),
|
||||||
|
.vel_x = direction == "LEFT" ? Balloon::VELX_NEGATIVE : Balloon::VELX_POSITIVE,
|
||||||
|
.speed = balloon_speed_,
|
||||||
|
.creation_counter = 0};
|
||||||
|
|
||||||
// Crea el globo
|
// Crea el globo
|
||||||
auto b = createBalloon(x, Y, balloon->getType(), SIZE, VX, balloon_speed_, 0);
|
auto b = createBalloon(config);
|
||||||
|
|
||||||
// Establece parametros
|
// Establece parametros
|
||||||
b->setVelY(b->getType() == Balloon::Type::BALLOON ? -2.50F : Balloon::VELX_NEGATIVE * 2.0F);
|
b->setVelY(b->getType() == Balloon::Type::BALLOON ? -2.50F : Balloon::VELX_NEGATIVE * 2.0F);
|
||||||
@@ -198,18 +230,32 @@ void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon> &balloon,
|
|||||||
void BalloonManager::createPowerBall() {
|
void BalloonManager::createPowerBall() {
|
||||||
if (can_deploy_balloons_) {
|
if (can_deploy_balloons_) {
|
||||||
constexpr int VALUES = 6;
|
constexpr int VALUES = 6;
|
||||||
constexpr float POS_Y = -Balloon::WIDTH.at(4);
|
const int LUCK = rand() % VALUES;
|
||||||
constexpr int CREATION_TIME = 0;
|
|
||||||
|
|
||||||
const float LEFT = param.game.play_area.rect.x;
|
const float LEFT = param.game.play_area.rect.x;
|
||||||
const float CENTER = param.game.play_area.center_x - (Balloon::WIDTH.at(4) / 2);
|
const float CENTER = param.game.play_area.center_x - (Balloon::WIDTH.at(4) / 2);
|
||||||
const float RIGHT = param.game.play_area.rect.w - Balloon::WIDTH.at(4);
|
const float RIGHT = param.game.play_area.rect.w - Balloon::WIDTH.at(4);
|
||||||
|
|
||||||
const int LUCK = rand() % VALUES;
|
|
||||||
const std::array<float, VALUES> POS_X = {LEFT, LEFT, CENTER, CENTER, RIGHT, RIGHT};
|
const std::array<float, VALUES> POS_X = {LEFT, LEFT, CENTER, CENTER, RIGHT, RIGHT};
|
||||||
const std::array<float, VALUES> VEL_X = {Balloon::VELX_POSITIVE, Balloon::VELX_POSITIVE, Balloon::VELX_POSITIVE, Balloon::VELX_NEGATIVE, Balloon::VELX_NEGATIVE, Balloon::VELX_NEGATIVE};
|
const std::array<float, VALUES> VEL_X = {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>(POS_X[LUCK], POS_Y, Balloon::Type::POWERBALL, Balloon::Size::EXTRALARGE, VEL_X[LUCK], balloon_speed_, CREATION_TIME, play_area_, balloon_textures_[4], balloon_animations_[4]));
|
Balloon::Config config = {
|
||||||
|
.x = POS_X.at(LUCK),
|
||||||
|
.y = -Balloon::WIDTH.at(4),
|
||||||
|
.type = Balloon::Type::POWERBALL,
|
||||||
|
.size = Balloon::Size::EXTRALARGE,
|
||||||
|
.vel_x = VEL_X.at(LUCK),
|
||||||
|
.speed = balloon_speed_,
|
||||||
|
.creation_counter = 0,
|
||||||
|
.play_area = play_area_,
|
||||||
|
.texture = balloon_textures_.at(4),
|
||||||
|
.animation = balloon_animations_.at(4),
|
||||||
|
.sound = {
|
||||||
|
.bouncing_enabled = bouncing_sound_enabled_,
|
||||||
|
.poping_enabled = poping_sound_enabled_,
|
||||||
|
.enabled = sound_enabled_}};
|
||||||
|
|
||||||
|
balloons_.emplace_back(std::make_unique<Balloon>(config));
|
||||||
balloons_.back()->setInvulnerable(true);
|
balloons_.back()->setInvulnerable(true);
|
||||||
|
|
||||||
power_ball_enabled_ = true;
|
power_ball_enabled_ = true;
|
||||||
@@ -226,7 +272,7 @@ void BalloonManager::setBalloonSpeed(float speed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Explosiona un globo. Lo destruye y crea otros dos si es el caso
|
// Explosiona un globo. Lo destruye y crea otros dos si es el caso
|
||||||
auto BalloonManager::popBalloon(std::shared_ptr<Balloon> balloon) -> int {
|
auto BalloonManager::popBalloon(const std::shared_ptr<Balloon> &balloon) -> int {
|
||||||
stage_info_->addPower(1);
|
stage_info_->addPower(1);
|
||||||
int score = 0;
|
int score = 0;
|
||||||
|
|
||||||
@@ -291,7 +337,7 @@ auto BalloonManager::destroyAllBalloons() -> int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
balloon_deploy_counter_ = 300;
|
balloon_deploy_counter_ = 300;
|
||||||
Screen::get()->flash(FLASH_COLOR, 3);
|
Screen::get()->flash(Colors::FLASH, 3);
|
||||||
Screen::get()->shake();
|
Screen::get()->shake();
|
||||||
|
|
||||||
return score;
|
return score;
|
||||||
@@ -334,19 +380,6 @@ void BalloonManager::createTwoBigBalloons() {
|
|||||||
deployFormation(1);
|
deployFormation(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crea una disposición de globos aleatoria
|
|
||||||
void BalloonManager::createRandomBalloons() {
|
|
||||||
const int NUM_BALLOONS = 2 + rand() % 4;
|
|
||||||
for (int i = 0; i < NUM_BALLOONS; ++i) {
|
|
||||||
const float X = param.game.game_area.rect.x + (rand() % static_cast<int>(param.game.game_area.rect.w)) - Balloon::WIDTH.at(3);
|
|
||||||
const int Y = param.game.game_area.rect.y + (rand() % 50);
|
|
||||||
const auto SIZE = static_cast<Balloon::Size>(rand() % 4);
|
|
||||||
const float VEL_X = (rand() % 2 == 0) ? Balloon::VELX_POSITIVE : Balloon::VELX_NEGATIVE;
|
|
||||||
const int CREATION_COUNTER = 0;
|
|
||||||
createBalloon(X, Y, Balloon::Type::BALLOON, SIZE, VEL_X, balloon_speed_, CREATION_COUNTER);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtiene el nivel de ameza actual generado por los globos
|
// Obtiene el nivel de ameza actual generado por los globos
|
||||||
auto BalloonManager::getMenace() -> int {
|
auto BalloonManager::getMenace() -> int {
|
||||||
return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon) { return sum + (balloon->isEnabled() ? balloon->getMenace() : 0); });
|
return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon) { return sum + (balloon->isEnabled() ? balloon->getMenace() : 0); });
|
||||||
|
|||||||
@@ -17,35 +17,35 @@
|
|||||||
|
|
||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
|
// --- Types ---
|
||||||
using Balloons = std::vector<std::shared_ptr<Balloon>>;
|
using Balloons = std::vector<std::shared_ptr<Balloon>>;
|
||||||
|
|
||||||
// Clase BalloonManager
|
// --- Clase BalloonManager: gestiona todos los globos del juego ---
|
||||||
class BalloonManager {
|
class BalloonManager {
|
||||||
public:
|
public:
|
||||||
// Constructor y Destructor
|
// --- Constructor y destructor ---
|
||||||
BalloonManager(IStageInfo *stage_info);
|
BalloonManager(IStageInfo *stage_info);
|
||||||
~BalloonManager() = default;
|
~BalloonManager() = default;
|
||||||
|
|
||||||
// Actualización y Renderizado
|
// --- Métodos principales ---
|
||||||
void update(); // Actualiza el estado de los globos
|
void update(); // Actualiza el estado de los globos
|
||||||
void render(); // Renderiza los globos en pantalla
|
void render(); // Renderiza los globos en pantalla
|
||||||
|
|
||||||
// Gestión de globos
|
// --- Gestión de globos ---
|
||||||
void freeBalloons(); // Libera globos que ya no sirven
|
void freeBalloons(); // Libera globos que ya no sirven
|
||||||
|
|
||||||
// Creación de formaciones enemigas
|
// --- Creación de formaciones enemigas ---
|
||||||
void deployRandomFormation(int stage); // Crea una formación de globos aleatoria
|
void deployRandomFormation(int stage); // Crea una formación de globos aleatoria
|
||||||
void deployFormation(int formation_id); // Crea una formación específica
|
void deployFormation(int formation_id); // Crea una formación específica
|
||||||
void deployFormation(int formation_id, int y); // Crea una formación específica con coordenadas
|
void deployFormation(int formation_id, float y); // Crea una formación específica con coordenadas
|
||||||
|
|
||||||
// Creación de globos
|
// --- Creación de globos ---
|
||||||
auto createBalloon(float x, int y, Balloon::Type type, Balloon::Size size, float velx, float speed, int creation_timer) -> std::shared_ptr<Balloon>; // Crea un nuevo globo
|
auto createBalloon(Balloon::Config config) -> std::shared_ptr<Balloon>; // Crea un nuevo globo
|
||||||
void createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction); // Crea un globo a partir de otro
|
void createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction); // Crea un globo a partir de otro
|
||||||
void createPowerBall(); // Crea una PowerBall
|
void createPowerBall(); // Crea una PowerBall
|
||||||
void createTwoBigBalloons(); // Crea dos globos grandes
|
void createTwoBigBalloons(); // Crea dos globos grandes
|
||||||
void createRandomBalloons(); // Crea una disposición aleatoria de globos
|
|
||||||
|
|
||||||
// Control de velocidad y despliegue
|
// --- Control de velocidad y despliegue ---
|
||||||
void setBalloonSpeed(float speed); // Ajusta la velocidad de los globos
|
void setBalloonSpeed(float speed); // Ajusta la velocidad de los globos
|
||||||
void setDefaultBalloonSpeed(float speed) { default_balloon_speed_ = speed; }; // Establece la velocidad base
|
void setDefaultBalloonSpeed(float speed) { default_balloon_speed_ = speed; }; // Establece la velocidad base
|
||||||
void resetBalloonSpeed() { setBalloonSpeed(default_balloon_speed_); }; // Restablece la velocidad de los globos
|
void resetBalloonSpeed() { setBalloonSpeed(default_balloon_speed_); }; // Restablece la velocidad de los globos
|
||||||
@@ -53,61 +53,61 @@ class BalloonManager {
|
|||||||
auto canPowerBallBeCreated() -> bool; // Indica si se puede crear una PowerBall
|
auto canPowerBallBeCreated() -> bool; // Indica si se puede crear una PowerBall
|
||||||
auto calculateScreenPower() -> int; // Calcula el poder de los globos en pantalla
|
auto calculateScreenPower() -> int; // Calcula el poder de los globos en pantalla
|
||||||
|
|
||||||
// Manipulación de globos existentes
|
// --- Manipulación de globos existentes ---
|
||||||
auto popBalloon(std::shared_ptr<Balloon> balloon) -> int; // Explosiona un globo, creando otros si aplica
|
auto popBalloon(const std::shared_ptr<Balloon> &balloon) -> int; // Explosiona un globo, creando otros si aplica
|
||||||
auto destroyBalloon(std::shared_ptr<Balloon> &balloon) -> int; // Explosiona un globo sin crear otros
|
auto destroyBalloon(std::shared_ptr<Balloon> &balloon) -> int; // Explosiona un globo sin crear otros
|
||||||
auto destroyAllBalloons() -> int; // Destruye todos los globos
|
auto destroyAllBalloons() -> int; // Destruye todos los globos
|
||||||
void stopAllBalloons(); // Detiene el movimiento de los globos
|
void stopAllBalloons(); // Detiene el movimiento de los globos
|
||||||
void startAllBalloons(); // Reactiva el movimiento de los globos
|
void startAllBalloons(); // Reactiva el movimiento de los globos
|
||||||
|
|
||||||
// Cambios de apariencia
|
// --- Cambios de apariencia ---
|
||||||
void reverseColorsToAllBalloons(); // Invierte los colores de los globos
|
void reverseColorsToAllBalloons(); // Invierte los colores de los globos
|
||||||
void normalColorsToAllBalloons(); // Restaura los colores originales
|
void normalColorsToAllBalloons(); // Restaura los colores originales
|
||||||
|
|
||||||
// Configuración de sonido
|
// --- Configuración de sonido ---
|
||||||
void setSounds(bool value); // Activa o desactiva los sonidos de los globos
|
void setSounds(bool value); // Activa o desactiva los sonidos de los globos
|
||||||
void setBouncingSounds(bool value); // Activa o desactiva los sonidos de rebote los globos
|
void setBouncingSounds(bool value); // Activa o desactiva los sonidos de rebote los globos
|
||||||
void setPoppingSounds(bool value); // Activa o desactiva los sonidos de los globos al explotar
|
void setPoppingSounds(bool value); // Activa o desactiva los sonidos de los globos al explotar
|
||||||
|
|
||||||
// Configuración de juego
|
// --- Configuración de juego ---
|
||||||
void setPlayArea(SDL_FRect play_area) { play_area_ = play_area; }; // Define el área de juego
|
void setPlayArea(SDL_FRect play_area) { play_area_ = play_area; }; // Define el área de juego
|
||||||
void setCreationTimeEnabled(bool value) { creation_time_enabled_ = value; }; // Activa o desactiva el tiempo de creación de globos
|
void setCreationTimeEnabled(bool value) { creation_time_enabled_ = value; }; // Activa o desactiva el tiempo de creación de globos
|
||||||
void enableBalloonDeployment(bool value) { can_deploy_balloons_ = value; }; // Activa o desactiva la generación de globos
|
void enableBalloonDeployment(bool value) { can_deploy_balloons_ = value; }; // Activa o desactiva la generación de globos
|
||||||
|
|
||||||
// Obtención de información
|
// --- Getters ---
|
||||||
auto getMenace() -> int; // Obtiene el nivel de amenaza generado por los globos
|
auto getMenace() -> int; // Obtiene el nivel de amenaza generado por los globos
|
||||||
[[nodiscard]] auto getBalloonSpeed() const -> float { return balloon_speed_; }
|
[[nodiscard]] auto getBalloonSpeed() const -> float { return balloon_speed_; }
|
||||||
auto getBalloons() -> Balloons & { return balloons_; }
|
auto getBalloons() -> Balloons & { return balloons_; }
|
||||||
[[nodiscard]] auto getNumBalloons() const -> int { return balloons_.size(); }
|
[[nodiscard]] auto getNumBalloons() const -> int { return balloons_.size(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// --- Constantes ---
|
||||||
static const int DEFAULT_BALLOON_DEPLOY_COUNTER = 300;
|
static const int DEFAULT_BALLOON_DEPLOY_COUNTER = 300;
|
||||||
|
|
||||||
Balloons balloons_; // Vector con los globos activos
|
// --- Objetos y punteros ---
|
||||||
std::unique_ptr<Explosions> explosions_; // Objeto para gestionar explosiones
|
Balloons balloons_; // Vector con los globos activos
|
||||||
std::unique_ptr<BalloonFormations> balloon_formations_; // Objeto para manejar formaciones enemigas
|
std::unique_ptr<Explosions> explosions_; // Objeto para gestionar explosiones
|
||||||
|
std::unique_ptr<BalloonFormations> balloon_formations_; // Objeto para manejar formaciones enemigas
|
||||||
std::vector<std::shared_ptr<Texture>> balloon_textures_; // Texturas de los globos
|
std::vector<std::shared_ptr<Texture>> balloon_textures_; // Texturas de los globos
|
||||||
std::vector<std::shared_ptr<Texture>> explosions_textures_; // Texturas de explosiones
|
std::vector<std::shared_ptr<Texture>> explosions_textures_; // Texturas de explosiones
|
||||||
|
|
||||||
std::vector<std::vector<std::string>> balloon_animations_; // Animaciones de los globos
|
std::vector<std::vector<std::string>> balloon_animations_; // Animaciones de los globos
|
||||||
std::vector<std::vector<std::string>> explosions_animations_; // Animaciones de las explosiones
|
std::vector<std::vector<std::string>> explosions_animations_; // Animaciones de las explosiones
|
||||||
|
IStageInfo *stage_info_; // Informacion de la pantalla actual
|
||||||
|
|
||||||
// Variables de control de globos
|
// --- Variables de estado ---
|
||||||
|
SDL_FRect play_area_ = param.game.play_area.rect;
|
||||||
float balloon_speed_ = Balloon::SPEED.at(0);
|
float balloon_speed_ = Balloon::SPEED.at(0);
|
||||||
float default_balloon_speed_ = Balloon::SPEED.at(0);
|
float default_balloon_speed_ = Balloon::SPEED.at(0);
|
||||||
int balloon_deploy_counter_ = 0;
|
int balloon_deploy_counter_ = 0;
|
||||||
bool power_ball_enabled_ = false;
|
|
||||||
int power_ball_counter_ = 0;
|
int power_ball_counter_ = 0;
|
||||||
int last_balloon_deploy_ = 0;
|
int last_balloon_deploy_ = 0;
|
||||||
SDL_FRect play_area_ = param.game.play_area.rect;
|
bool power_ball_enabled_ = false;
|
||||||
bool creation_time_enabled_ = true;
|
bool creation_time_enabled_ = true;
|
||||||
bool can_deploy_balloons_ = true;
|
bool can_deploy_balloons_ = true;
|
||||||
bool bouncing_sound_enabled_ = false; // Si debe sonar el globo al rebotar
|
bool bouncing_sound_enabled_ = false; // Si debe sonar el globo al rebotar
|
||||||
bool poping_sound_enabled_ = true; // Si debe sonar el globo al explotar
|
bool poping_sound_enabled_ = true; // Si debe sonar el globo al explotar
|
||||||
bool sound_enabled_ = true; // Indica si los globos deben hacer algun sonido
|
bool sound_enabled_ = true; // Indica si los globos deben hacer algun sonido
|
||||||
IStageInfo *stage_info_; // Informacion de la pantalla actual
|
|
||||||
|
|
||||||
// Metodos privados
|
// --- Métodos internos ---
|
||||||
void init();
|
void init();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
// Constructor
|
// Constructor
|
||||||
Bullet::Bullet(float x, float y, BulletType bullet_type, bool powered, Player::Id owner)
|
Bullet::Bullet(float x, float y, BulletType bullet_type, bool powered, Player::Id owner)
|
||||||
: sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("bullet.png"), Resource::get()->getAnimation("bullet.ani"))),
|
: sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("bullet.png"), Resource::get()->getAnimation("bullet.ani"))),
|
||||||
pos_x_(x),
|
|
||||||
pos_y_(y),
|
|
||||||
bullet_type_(bullet_type),
|
bullet_type_(bullet_type),
|
||||||
owner_(owner) {
|
owner_(owner),
|
||||||
|
pos_x_(x),
|
||||||
|
pos_y_(y) {
|
||||||
vel_x_ = calculateVelocity(bullet_type_);
|
vel_x_ = calculateVelocity(bullet_type_);
|
||||||
sprite_->setCurrentAnimation(buildAnimationString(bullet_type_, powered));
|
sprite_->setCurrentAnimation(buildAnimationString(bullet_type_, powered));
|
||||||
|
|
||||||
|
|||||||
@@ -9,65 +9,62 @@
|
|||||||
#include "player.h" // Para Player
|
#include "player.h" // Para Player
|
||||||
#include "utils.h" // Para Circle
|
#include "utils.h" // Para Circle
|
||||||
|
|
||||||
// Tipos de balas
|
// --- Enums ---
|
||||||
enum class BulletType : Uint8 {
|
enum class BulletType : Uint8 {
|
||||||
UP,
|
UP, // Bala hacia arriba
|
||||||
LEFT,
|
LEFT, // Bala hacia la izquierda
|
||||||
RIGHT,
|
RIGHT, // Bala hacia la derecha
|
||||||
NONE
|
NONE // Sin bala
|
||||||
};
|
};
|
||||||
|
|
||||||
// Resultado del movimiento de la bala
|
|
||||||
enum class BulletMoveStatus : Uint8 {
|
enum class BulletMoveStatus : Uint8 {
|
||||||
OK = 0,
|
OK = 0, // Movimiento normal
|
||||||
OUT = 1
|
OUT = 1 // Fuera de los límites
|
||||||
};
|
};
|
||||||
|
|
||||||
// Clase Bullet
|
// --- Clase Bullet: representa una bala del jugador ---
|
||||||
class Bullet {
|
class Bullet {
|
||||||
public:
|
public:
|
||||||
// Constantes
|
// --- Constantes ---
|
||||||
static constexpr float WIDTH = 12.0F;
|
static constexpr float WIDTH = 12.0F; // Anchura de la bala
|
||||||
static constexpr float HEIGHT = 12.0F;
|
static constexpr float HEIGHT = 12.0F; // Altura de la bala
|
||||||
|
|
||||||
// Constructor y Destructor
|
// --- Constructor y destructor ---
|
||||||
Bullet(float x, float y, BulletType bullet_type, bool powered, Player::Id owner);
|
Bullet(float x, float y, BulletType bullet_type, bool powered, Player::Id owner); // Constructor principal
|
||||||
~Bullet() = default;
|
~Bullet() = default; // Destructor
|
||||||
|
|
||||||
// Métodos principales
|
// --- Métodos principales ---
|
||||||
void render(); // Dibuja la bala en pantalla
|
void render(); // Dibuja la bala en pantalla
|
||||||
auto update() -> BulletMoveStatus; // Actualiza el estado del objeto
|
auto update() -> BulletMoveStatus; // Actualiza el estado del objeto
|
||||||
|
void disable(); // Desactiva la bala
|
||||||
|
|
||||||
// Estado de la bala
|
// --- Getters ---
|
||||||
[[nodiscard]] auto isEnabled() const -> bool; // Comprueba si está activa
|
[[nodiscard]] auto isEnabled() const -> bool; // Comprueba si está activa
|
||||||
void disable(); // Desactiva la bala
|
|
||||||
|
|
||||||
// Getters
|
|
||||||
[[nodiscard]] auto getOwner() const -> Player::Id; // Devuelve el identificador del dueño
|
[[nodiscard]] auto getOwner() const -> Player::Id; // Devuelve el identificador del dueño
|
||||||
auto getCollider() -> Circle &; // Devuelve el círculo de colisión
|
auto getCollider() -> Circle &; // Devuelve el círculo de colisión
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Constantes
|
// --- Constantes ---
|
||||||
static constexpr float VEL_Y = -3.0F;
|
static constexpr float VEL_Y = -3.0F; // Velocidad vertical
|
||||||
static constexpr float VEL_X_LEFT = -2.0F;
|
static constexpr float VEL_X_LEFT = -2.0F; // Velocidad izquierda
|
||||||
static constexpr float VEL_X_RIGHT = 2.0F;
|
static constexpr float VEL_X_RIGHT = 2.0F; // Velocidad derecha
|
||||||
static constexpr float VEL_X_CENTER = 0.0F;
|
static constexpr float VEL_X_CENTER = 0.0F; // Velocidad central
|
||||||
|
|
||||||
// Propiedades
|
// --- Objetos y punteros ---
|
||||||
std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos
|
std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos
|
||||||
|
|
||||||
float pos_x_; // Posición en el eje X
|
// --- Variables de estado ---
|
||||||
float pos_y_; // Posición en el eje Y
|
Circle collider_; // Círculo de colisión
|
||||||
float vel_x_; // Velocidad en el eje X
|
|
||||||
|
|
||||||
BulletType bullet_type_; // Tipo de bala
|
BulletType bullet_type_; // Tipo de bala
|
||||||
Player::Id owner_; // Identificador del dueño
|
Player::Id owner_; // Identificador del dueño
|
||||||
Circle collider_; // Círculo de colisión
|
float pos_x_; // Posición en el eje X
|
||||||
|
float pos_y_; // Posición en el eje Y
|
||||||
|
float vel_x_; // Velocidad en el eje X
|
||||||
|
|
||||||
// Métodos internos
|
// --- Métodos internos ---
|
||||||
void shiftColliders(); // Ajusta el círculo de colisión
|
void shiftColliders(); // Ajusta el círculo de colisión
|
||||||
void shiftSprite(); // Ajusta el sprite
|
void shiftSprite(); // Ajusta el sprite
|
||||||
auto move() -> BulletMoveStatus; // Mueve la bala y devuelve su estado
|
auto move() -> BulletMoveStatus; // Mueve la bala y devuelve su estado
|
||||||
static auto calculateVelocity(BulletType bullet_type) -> float; // Calcula la velocidad horizontal de la bala basada en su tipo
|
static auto calculateVelocity(BulletType bullet_type) -> float; // Calcula la velocidad horizontal de la bala
|
||||||
static auto buildAnimationString(BulletType bullet_type, bool powered) -> std::string; // Construye el string de animación basado en el tipo de bala y si está potenciada
|
static auto buildAnimationString(BulletType bullet_type, bool powered) -> std::string; // Construye el string de animación
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -42,22 +42,8 @@ auto Color::fromHex(const std::string &hex_str) -> Color {
|
|||||||
return Color(r, g, b, a);
|
return Color(r, g, b, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtiene un color del vector de colores imitando al Coche Fantástico
|
// Implementaciones de métodos estáticos de Color
|
||||||
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color {
|
constexpr auto Color::rgbToHsv(Color color) -> HSV {
|
||||||
int cycle_length = colors.size() * 2 - 2;
|
|
||||||
size_t n = counter % cycle_length;
|
|
||||||
|
|
||||||
size_t index;
|
|
||||||
if (n < colors.size()) {
|
|
||||||
index = n; // Avanza: 0,1,2,3
|
|
||||||
} else {
|
|
||||||
index = 2 * (colors.size() - 1) - n; // Retrocede: 2,1
|
|
||||||
}
|
|
||||||
|
|
||||||
return colors[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr auto rgbToHsv(Color color) -> HSV {
|
|
||||||
float r = color.r / 255.0F;
|
float r = color.r / 255.0F;
|
||||||
float g = color.g / 255.0F;
|
float g = color.g / 255.0F;
|
||||||
float b = color.b / 255.0F;
|
float b = color.b / 255.0F;
|
||||||
@@ -84,10 +70,10 @@ constexpr auto rgbToHsv(Color color) -> HSV {
|
|||||||
float s = (max <= 0.0F) ? 0.0F : delta / max;
|
float s = (max <= 0.0F) ? 0.0F : delta / max;
|
||||||
float v = max;
|
float v = max;
|
||||||
|
|
||||||
return {h, s, v};
|
return {.h = h, .s = s, .v = v};
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto hsvToRgb(HSV hsv) -> Color {
|
constexpr auto Color::hsvToRgb(HSV hsv) -> Color {
|
||||||
float c = hsv.v * hsv.s;
|
float c = hsv.v * hsv.s;
|
||||||
float x = c * (1 - std::abs(std::fmod(hsv.h / 60.0F, 2) - 1));
|
float x = c * (1 - std::abs(std::fmod(hsv.h / 60.0F, 2) - 1));
|
||||||
float m = hsv.v - c;
|
float m = hsv.v - c;
|
||||||
@@ -128,12 +114,29 @@ constexpr auto hsvToRgb(HSV hsv) -> Color {
|
|||||||
static_cast<uint8_t>(roundf((b + m) * 255)));
|
static_cast<uint8_t>(roundf((b + m) * 255)));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto generateMirroredCycle(Color base, ColorCycleStyle style) -> ColorCycle {
|
// Implementaciones del namespace Colors
|
||||||
ColorCycle result{};
|
namespace Colors {
|
||||||
HSV base_hsv = rgbToHsv(base);
|
// Obtiene un color del vector de colores imitando al Coche Fantástico
|
||||||
|
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color {
|
||||||
|
int cycle_length = (colors.size() * 2) - 2;
|
||||||
|
size_t n = counter % cycle_length;
|
||||||
|
|
||||||
for (size_t i = 0; i < COLOR_CYCLE_SIZE; ++i) {
|
size_t index;
|
||||||
float t = static_cast<float>(i) / (COLOR_CYCLE_SIZE - 1); // 0 → 1
|
if (n < colors.size()) {
|
||||||
|
index = n; // Avanza: 0,1,2,3
|
||||||
|
} else {
|
||||||
|
index = 2 * (colors.size() - 1) - n; // Retrocede: 2,1
|
||||||
|
}
|
||||||
|
|
||||||
|
return colors[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto generateMirroredCycle(Color base, ColorCycleStyle style) -> Cycle {
|
||||||
|
Cycle result{};
|
||||||
|
HSV base_hsv = Color::rgbToHsv(base);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < CYCLE_SIZE; ++i) {
|
||||||
|
float t = static_cast<float>(i) / (CYCLE_SIZE - 1); // 0 → 1
|
||||||
float hue_shift = 0.0F;
|
float hue_shift = 0.0F;
|
||||||
float sat_shift = 0.0F;
|
float sat_shift = 0.0F;
|
||||||
float val_shift = 0.0F;
|
float val_shift = 0.0F;
|
||||||
@@ -169,14 +172,15 @@ auto generateMirroredCycle(Color base, ColorCycleStyle style) -> ColorCycle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HSV adjusted = {
|
HSV adjusted = {
|
||||||
fmodf(base_hsv.h + hue_shift + 360.0F, 360.0F),
|
.h = fmodf(base_hsv.h + hue_shift + 360.0F, 360.0F),
|
||||||
fminf(1.0F, fmaxf(0.0F, base_hsv.s + sat_shift)),
|
.s = fminf(1.0F, fmaxf(0.0F, base_hsv.s + sat_shift)),
|
||||||
fminf(1.0F, fmaxf(0.0F, base_hsv.v + val_shift))};
|
.v = fminf(1.0F, fmaxf(0.0F, base_hsv.v + val_shift))};
|
||||||
|
|
||||||
Color c = hsvToRgb(adjusted);
|
Color c = Color::hsvToRgb(adjusted);
|
||||||
result[i] = c;
|
result[i] = c;
|
||||||
result[2 * COLOR_CYCLE_SIZE - 1 - i] = c; // espejo
|
result[(2 * CYCLE_SIZE) - 1 - i] = c; // espejo
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
} // namespace Colors
|
||||||
@@ -9,12 +9,14 @@
|
|||||||
#include <string> // Para string
|
#include <string> // Para string
|
||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
// --- Constantes ---
|
// --- Estructura HSV: define un color en formato HSV ---
|
||||||
constexpr size_t COLOR_CYCLE_SIZE = 6; // Mitad del ciclo espejado
|
struct HSV {
|
||||||
|
float h; // Matiz (Hue)
|
||||||
|
float s; // Saturación (Saturation)
|
||||||
|
float v; // Valor (Value)
|
||||||
|
};
|
||||||
|
|
||||||
// --- Estructuras y tipos ---
|
// --- Estructura Color: define un color RGBA ---
|
||||||
|
|
||||||
// Estructura para definir un color RGBA
|
|
||||||
struct Color {
|
struct Color {
|
||||||
private:
|
private:
|
||||||
static constexpr int DEFAULT_LIGHTEN_AMOUNT = 50;
|
static constexpr int DEFAULT_LIGHTEN_AMOUNT = 50;
|
||||||
@@ -34,10 +36,17 @@ struct Color {
|
|||||||
|
|
||||||
Uint8 r, g, b, a;
|
Uint8 r, g, b, a;
|
||||||
|
|
||||||
constexpr Color() : r(MIN_COLOR_VALUE), g(MIN_COLOR_VALUE), b(MIN_COLOR_VALUE), a(DEFAULT_ALPHA) {}
|
constexpr Color()
|
||||||
|
: r(MIN_COLOR_VALUE),
|
||||||
|
g(MIN_COLOR_VALUE),
|
||||||
|
b(MIN_COLOR_VALUE),
|
||||||
|
a(DEFAULT_ALPHA) {}
|
||||||
|
|
||||||
explicit constexpr Color(Uint8 red, Uint8 green, Uint8 blue, Uint8 alpha = DEFAULT_ALPHA)
|
explicit constexpr Color(Uint8 red, Uint8 green, Uint8 blue, Uint8 alpha = DEFAULT_ALPHA)
|
||||||
: r(red), g(green), b(blue), a(alpha) {}
|
: r(red),
|
||||||
|
g(green),
|
||||||
|
b(blue),
|
||||||
|
a(alpha) {}
|
||||||
|
|
||||||
[[nodiscard]] constexpr auto INVERSE() const -> Color {
|
[[nodiscard]] constexpr auto INVERSE() const -> Color {
|
||||||
return Color(MAX_COLOR_VALUE - r, MAX_COLOR_VALUE - g, MAX_COLOR_VALUE - b, a);
|
return Color(MAX_COLOR_VALUE - r, MAX_COLOR_VALUE - g, MAX_COLOR_VALUE - b, a);
|
||||||
@@ -62,6 +71,10 @@ struct Color {
|
|||||||
// Método estático para crear Color desde string hexadecimal
|
// Método estático para crear Color desde string hexadecimal
|
||||||
static auto fromHex(const std::string &hex_str) -> Color;
|
static auto fromHex(const std::string &hex_str) -> Color;
|
||||||
|
|
||||||
|
// Conversiones de formato de color
|
||||||
|
[[nodiscard]] constexpr static auto rgbToHsv(Color color) -> HSV;
|
||||||
|
[[nodiscard]] constexpr static auto hsvToRgb(HSV hsv) -> Color;
|
||||||
|
|
||||||
[[nodiscard]] constexpr auto IS_EQUAL_TO(const Color &other) const -> bool {
|
[[nodiscard]] constexpr auto IS_EQUAL_TO(const Color &other) const -> bool {
|
||||||
return r == other.r && g == other.g && b == other.b && a == other.a;
|
return r == other.r && g == other.g && b == other.b && a == other.a;
|
||||||
}
|
}
|
||||||
@@ -81,14 +94,17 @@ struct Color {
|
|||||||
|
|
||||||
return Color(new_r, new_g, new_b, new_a);
|
return Color(new_r, new_g, new_b, new_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convierte el color a un entero de 32 bits en formato RGBA
|
||||||
|
[[nodiscard]] constexpr auto TO_UINT32() const -> Uint32 {
|
||||||
|
return (static_cast<Uint32>(r) << 24) |
|
||||||
|
(static_cast<Uint32>(g) << 16) |
|
||||||
|
(static_cast<Uint32>(b) << 8) |
|
||||||
|
static_cast<Uint32>(a);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Estructura para definir un color HSV
|
// --- Enum ColorCycleStyle: define estilos de ciclo de color ---
|
||||||
struct HSV {
|
|
||||||
float h, s, v;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Estructura para definir el ciclo de color
|
|
||||||
enum class ColorCycleStyle {
|
enum class ColorCycleStyle {
|
||||||
SUBTLE_PULSE, // Variación leve en brillo (por defecto)
|
SUBTLE_PULSE, // Variación leve en brillo (por defecto)
|
||||||
HUE_WAVE, // Variación suave en tono (sin verde)
|
HUE_WAVE, // Variación suave en tono (sin verde)
|
||||||
@@ -97,23 +113,27 @@ enum class ColorCycleStyle {
|
|||||||
LIGHT_FLASH // Ilumina hacia el centro y regresa
|
LIGHT_FLASH // Ilumina hacia el centro y regresa
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --- Namespace Colors: constantes y utilidades de color ---
|
||||||
|
namespace Colors {
|
||||||
|
// --- Constantes ---
|
||||||
|
constexpr size_t CYCLE_SIZE = 6; // Mitad del ciclo espejado
|
||||||
|
|
||||||
// --- Alias ---
|
// --- Alias ---
|
||||||
using ColorCycle = std::array<Color, 2 * COLOR_CYCLE_SIZE>;
|
using Cycle = std::array<Color, 2 * CYCLE_SIZE>;
|
||||||
|
|
||||||
// --- Colores predefinidos ---
|
// --- Colores predefinidos ---
|
||||||
constexpr Color NO_TEXT_COLOR = Color(0XFF, 0XFF, 0XFF);
|
constexpr Color NO_COLOR_MOD = Color(0XFF, 0XFF, 0XFF);
|
||||||
constexpr Color SHADOW_TEXT_COLOR = Color(0X43, 0X43, 0X4F);
|
constexpr Color SHADOW_TEXT = Color(0X43, 0X43, 0X4F);
|
||||||
constexpr Color TITLE_SHADOW_TEXT_COLOR = Color(0x14, 0x87, 0xc4);
|
constexpr Color TITLE_SHADOW_TEXT = Color(0x14, 0x87, 0xc4);
|
||||||
constexpr Color ORANGE_TEXT_COLOR = Color(0XFF, 0X7A, 0X00);
|
constexpr Color ORANGE_TEXT = Color(0XFF, 0X7A, 0X00);
|
||||||
|
|
||||||
constexpr Color FLASH_COLOR = Color(0XFF, 0XFF, 0XFF);
|
constexpr Color FLASH = Color(0XFF, 0XFF, 0XFF);
|
||||||
|
|
||||||
constexpr Color BLUE_SKY_COLOR = Color(0X02, 0X88, 0XD1);
|
constexpr Color BLUE_SKY = Color(0X02, 0X88, 0XD1);
|
||||||
constexpr Color PINK_SKY_COLOR = Color(0XFF, 0X6B, 0X97);
|
constexpr Color PINK_SKY = Color(0XFF, 0X6B, 0X97);
|
||||||
constexpr Color GREEN_SKY_COLOR = Color(0X00, 0X79, 0X6B);
|
constexpr Color GREEN_SKY = Color(0X00, 0X79, 0X6B);
|
||||||
|
|
||||||
// --- Funciones ---
|
// --- Funciones ---
|
||||||
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color;
|
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color;
|
||||||
constexpr auto rgbToHsv(Color color) -> HSV;
|
auto generateMirroredCycle(Color base, ColorCycleStyle style = ColorCycleStyle::SUBTLE_PULSE) -> Cycle;
|
||||||
constexpr auto hsvToRgb(HSV hsv) -> Color;
|
} // namespace Colors
|
||||||
auto generateMirroredCycle(Color base, ColorCycleStyle style = ColorCycleStyle::SUBTLE_PULSE) -> ColorCycle;
|
|
||||||
241
source/defaults.h
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h> // Para SDL_ScaleMode
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "color.h"
|
||||||
|
#include "ui/notifier.h" // Para Notifier::Position
|
||||||
|
|
||||||
|
// --- Namespace GameDefaults: configuración centralizada con valores por defecto del juego ---
|
||||||
|
namespace GameDefaults {
|
||||||
|
|
||||||
|
// --- GAME ---
|
||||||
|
namespace Game {
|
||||||
|
constexpr float WIDTH = 320.0F;
|
||||||
|
constexpr float HEIGHT = 256.0F;
|
||||||
|
constexpr float ITEM_SIZE = 20.0F;
|
||||||
|
constexpr int NAME_ENTRY_IDLE_TIME = 10;
|
||||||
|
constexpr int NAME_ENTRY_TOTAL_TIME = 60;
|
||||||
|
constexpr bool HIT_STOP = false;
|
||||||
|
constexpr int HIT_STOP_MS = 500;
|
||||||
|
constexpr const char* ITEM_TEXT_OUTLINE_COLOR = "FFFFFF00"; // 255, 255, 255, 0
|
||||||
|
|
||||||
|
// Play area por defecto
|
||||||
|
constexpr float PLAY_AREA_X = 0.0F;
|
||||||
|
constexpr float PLAY_AREA_Y = 0.0F;
|
||||||
|
constexpr float PLAY_AREA_W = 320.0F;
|
||||||
|
constexpr float PLAY_AREA_H = 216.0F;
|
||||||
|
} // namespace Game
|
||||||
|
|
||||||
|
// --- FADE ---
|
||||||
|
namespace Fade {
|
||||||
|
constexpr const char* COLOR = "1F2B30";
|
||||||
|
constexpr float NUM_SQUARES_WIDTH = 160.0F;
|
||||||
|
constexpr float NUM_SQUARES_HEIGHT = 128.0F;
|
||||||
|
constexpr int RANDOM_SQUARES_DURATION_MS = 1;
|
||||||
|
constexpr int POST_DURATION_MS = 80;
|
||||||
|
constexpr float VENETIAN_SIZE = 12.0F;
|
||||||
|
} // namespace Fade
|
||||||
|
|
||||||
|
// --- SCOREBOARD ---
|
||||||
|
namespace Scoreboard {
|
||||||
|
constexpr float RECT_X = 0.0F;
|
||||||
|
constexpr float RECT_Y = 216.0F;
|
||||||
|
constexpr float RECT_W = 320.0F;
|
||||||
|
constexpr float RECT_H = 40.0F;
|
||||||
|
constexpr bool SEPARATOR_AUTOCOLOR = true;
|
||||||
|
constexpr const char* SEPARATOR_COLOR = "0D1A2B";
|
||||||
|
constexpr const char* EASY_COLOR = "4B692F";
|
||||||
|
constexpr const char* NORMAL_COLOR = "2E3F47";
|
||||||
|
constexpr const char* HARD_COLOR = "76428A";
|
||||||
|
constexpr bool TEXT_AUTOCOLOR = true;
|
||||||
|
constexpr const char* TEXT_COLOR1 = "FFFFFF";
|
||||||
|
constexpr const char* TEXT_COLOR2 = "FFFFFF";
|
||||||
|
constexpr int SKIP_COUNTDOWN_VALUE = 8;
|
||||||
|
} // namespace Scoreboard
|
||||||
|
|
||||||
|
// --- TITLE ---
|
||||||
|
namespace Title {
|
||||||
|
constexpr int PRESS_START_POSITION = 180;
|
||||||
|
constexpr int DURATION = 800;
|
||||||
|
constexpr int ARCADE_EDITION_POSITION = 123;
|
||||||
|
constexpr int TITLE_C_C_POSITION = 80;
|
||||||
|
constexpr const char* BG_COLOR = "41526F";
|
||||||
|
} // namespace Title
|
||||||
|
|
||||||
|
// --- BACKGROUND ---
|
||||||
|
namespace Background {
|
||||||
|
constexpr const char* ATTENUATE_COLOR = "FFFFFF00";
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- BALLOONS ---
|
||||||
|
namespace Balloon {
|
||||||
|
// Configuración de física para cada nivel de globo
|
||||||
|
struct BalloonSettings {
|
||||||
|
float vel;
|
||||||
|
float grav;
|
||||||
|
constexpr BalloonSettings(float v, float g)
|
||||||
|
: vel(v),
|
||||||
|
grav(g) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr std::array<BalloonSettings, 4> SETTINGS = {{
|
||||||
|
BalloonSettings(2.75F, 0.09F), // Globo 0
|
||||||
|
BalloonSettings(3.70F, 0.10F), // Globo 1
|
||||||
|
BalloonSettings(4.70F, 0.10F), // Globo 2
|
||||||
|
BalloonSettings(5.45F, 0.10F) // Globo 3
|
||||||
|
}};
|
||||||
|
|
||||||
|
constexpr std::array<const char*, 4> COLORS = {
|
||||||
|
"blue",
|
||||||
|
"orange",
|
||||||
|
"red",
|
||||||
|
"green"};
|
||||||
|
|
||||||
|
constexpr bool BOUNCING_SOUND = false;
|
||||||
|
} // namespace Balloon
|
||||||
|
|
||||||
|
// --- NOTIFICATION ---
|
||||||
|
namespace Notification {
|
||||||
|
constexpr Notifier::Position POS_V = Notifier::Position::TOP;
|
||||||
|
constexpr Notifier::Position POS_H = Notifier::Position::LEFT;
|
||||||
|
constexpr bool SOUND = false;
|
||||||
|
constexpr const char* COLOR = "303030";
|
||||||
|
} // namespace Notification
|
||||||
|
|
||||||
|
// --- SERVICE MENU ---
|
||||||
|
namespace ServiceMenu {
|
||||||
|
constexpr const char* TITLE_COLOR = "99FF62";
|
||||||
|
constexpr const char* TEXT_COLOR = "FFFFFF";
|
||||||
|
constexpr const char* SELECTED_COLOR = "FFDC44";
|
||||||
|
constexpr const char* BG_COLOR = "000F00F5";
|
||||||
|
constexpr bool DROP_SHADOW = false;
|
||||||
|
|
||||||
|
// WindowMessage defaults
|
||||||
|
namespace WindowMessage {
|
||||||
|
constexpr const char* BG_COLOR = "141E32F0"; // Color(20, 30, 50, 240)
|
||||||
|
constexpr const char* BORDER_COLOR = "6496C8FF"; // Color(100, 150, 200, 255)
|
||||||
|
constexpr const char* TITLE_COLOR = "6496C8FF"; // Color(100, 150, 200, 255)
|
||||||
|
constexpr const char* TEXT_COLOR = "DCDCDCFF"; // Color(220, 220, 220, 255)
|
||||||
|
constexpr float PADDING = 15.0F;
|
||||||
|
constexpr float LINE_SPACING = 5.0F;
|
||||||
|
constexpr float TITLE_SEPARATOR_SPACING = 10.0F; // Cambiado a float
|
||||||
|
constexpr float MIN_WIDTH = 250.0F;
|
||||||
|
constexpr float MIN_HEIGHT = 32.0F; // Cambiado a float
|
||||||
|
constexpr float MAX_WIDTH_RATIO = 0.8F; // Nuevo
|
||||||
|
constexpr float MAX_HEIGHT_RATIO = 0.8F; // Nuevo
|
||||||
|
constexpr float TEXT_SAFETY_MARGIN = 15.0F;
|
||||||
|
constexpr float ANIMATION_DURATION = 0.3F;
|
||||||
|
} // namespace WindowMessage
|
||||||
|
} // namespace ServiceMenu
|
||||||
|
|
||||||
|
// --- INTRO ---
|
||||||
|
namespace Intro {
|
||||||
|
constexpr const char* BG_COLOR = "4664BD";
|
||||||
|
constexpr const char* CARD_COLOR = "CBDBFC";
|
||||||
|
constexpr const char* SHADOW_COLOR = "00000080";
|
||||||
|
constexpr int TEXT_DISTANCE_FROM_BOTTOM = 48;
|
||||||
|
} // namespace Intro
|
||||||
|
|
||||||
|
// --- DEBUG ---
|
||||||
|
namespace Debug {
|
||||||
|
constexpr const char* COLOR = "00FFFF";
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- RESOURCE ---
|
||||||
|
namespace Resource {
|
||||||
|
constexpr const char* COLOR = "FFFFFF";
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- TABE ---
|
||||||
|
namespace Tabe {
|
||||||
|
constexpr float MIN_SPAWN_TIME = 2.0F;
|
||||||
|
constexpr float MAX_SPAWN_TIME = 3.0F;
|
||||||
|
} // namespace Tabe
|
||||||
|
|
||||||
|
// --- PLAYER ---
|
||||||
|
namespace Player {
|
||||||
|
namespace DefaultShirt {
|
||||||
|
// Player 0 (Jugador 1)
|
||||||
|
constexpr const char* PLAYER0_DARKEST = "028ECFFF"; // 2, 142, 207, 255
|
||||||
|
constexpr const char* PLAYER0_DARK = "0297DBFF"; // 2, 151, 219, 255
|
||||||
|
constexpr const char* PLAYER0_BASE = "029FE8FF"; // 2, 159, 232, 255
|
||||||
|
constexpr const char* PLAYER0_LIGHT = "03A9F4FF"; // 3, 169, 244, 255
|
||||||
|
|
||||||
|
// Player 1 (Jugador 2)
|
||||||
|
constexpr const char* PLAYER1_DARKEST = "8E8E8EFF"; // 142, 142, 142, 255
|
||||||
|
constexpr const char* PLAYER1_DARK = "AEADADFF"; // 174, 173, 173, 255
|
||||||
|
constexpr const char* PLAYER1_BASE = "E4E4E4FF"; // 228, 228, 228, 255
|
||||||
|
constexpr const char* PLAYER1_LIGHT = "F7F1F1FF"; // 247, 241, 241, 255
|
||||||
|
} // namespace DefaultShirt
|
||||||
|
|
||||||
|
namespace OneCoffeeShirt {
|
||||||
|
// Player 0 (Jugador 1)
|
||||||
|
constexpr const char* PLAYER0_DARKEST = "3D9C70FF"; // 61, 156, 112, 255
|
||||||
|
constexpr const char* PLAYER0_DARK = "4FA370FF"; // 79, 163, 112, 255
|
||||||
|
constexpr const char* PLAYER0_BASE = "5DDE70FF"; // 93, 222, 112, 255
|
||||||
|
constexpr const char* PLAYER0_LIGHT = "7DF25CFF"; // 125, 242, 92, 255
|
||||||
|
|
||||||
|
// Player 1 (Jugador 2)
|
||||||
|
constexpr const char* PLAYER1_DARKEST = "2E8B57FF"; // 46, 139, 87, 255
|
||||||
|
constexpr const char* PLAYER1_DARK = "3CB371FF"; // 60, 179, 113, 255
|
||||||
|
constexpr const char* PLAYER1_BASE = "48D181FF"; // 72, 209, 129, 255
|
||||||
|
constexpr const char* PLAYER1_LIGHT = "55EF8DFF"; // 85, 239, 141, 255
|
||||||
|
} // namespace OneCoffeeShirt
|
||||||
|
|
||||||
|
namespace TwoCoffeeShirt {
|
||||||
|
// Player 0 (Jugador 1)
|
||||||
|
constexpr const char* PLAYER0_DARKEST = "D6A41AFF"; // 214, 164, 26, 255
|
||||||
|
constexpr const char* PLAYER0_DARK = "E3AE1BFF"; // 227, 174, 27, 255
|
||||||
|
constexpr const char* PLAYER0_BASE = "EFB71DFF"; // 239, 183, 29, 255
|
||||||
|
constexpr const char* PLAYER0_LIGHT = "FCC11EFF"; // 252, 193, 30, 255
|
||||||
|
|
||||||
|
// Player 1 (Jugador 2)
|
||||||
|
constexpr const char* PLAYER1_DARKEST = "E08500FF"; // 224, 133, 0, 255
|
||||||
|
constexpr const char* PLAYER1_DARK = "FA7D00FF"; // 250, 125, 0, 255
|
||||||
|
constexpr const char* PLAYER1_BASE = "FAA200FF"; // 250, 162, 0, 255
|
||||||
|
constexpr const char* PLAYER1_LIGHT = "FA8500FF"; // 250, 133, 0, 255
|
||||||
|
} // namespace TwoCoffeeShirt
|
||||||
|
|
||||||
|
namespace OutlineColor {
|
||||||
|
// Player 0 (Jugador 1)
|
||||||
|
constexpr const char* PLAYER0 = "66323FFF";
|
||||||
|
|
||||||
|
// Player 1 (Jugador 2)
|
||||||
|
constexpr const char* PLAYER1 = "422028FF";
|
||||||
|
} // namespace OutlineColor
|
||||||
|
} // namespace Player
|
||||||
|
|
||||||
|
// --- OPTIONS ---
|
||||||
|
namespace Options {
|
||||||
|
// Window
|
||||||
|
constexpr const char* WINDOW_CAPTION = "Coffee Crisis Arcade Edition";
|
||||||
|
constexpr int WINDOW_ZOOM = 2;
|
||||||
|
constexpr int WINDOW_MAX_ZOOM = 2;
|
||||||
|
|
||||||
|
// Video
|
||||||
|
constexpr SDL_ScaleMode VIDEO_SCALE_MODE = SDL_ScaleMode::SDL_SCALEMODE_NEAREST;
|
||||||
|
constexpr bool VIDEO_FULLSCREEN = false;
|
||||||
|
constexpr bool VIDEO_VSYNC = true;
|
||||||
|
constexpr bool VIDEO_INTEGER_SCALE = true;
|
||||||
|
constexpr bool VIDEO_SHADERS = true;
|
||||||
|
|
||||||
|
// Music
|
||||||
|
constexpr bool MUSIC_ENABLED = true;
|
||||||
|
constexpr int MUSIC_VOLUME = 100;
|
||||||
|
|
||||||
|
// Sound
|
||||||
|
constexpr bool SOUND_ENABLED = true;
|
||||||
|
constexpr int SOUND_VOLUME = 100;
|
||||||
|
|
||||||
|
// Audio
|
||||||
|
constexpr bool AUDIO_ENABLED = true;
|
||||||
|
constexpr int AUDIO_VOLUME = 100;
|
||||||
|
|
||||||
|
// Settings
|
||||||
|
constexpr bool SETTINGS_AUTOFIRE = true;
|
||||||
|
constexpr bool SETTINGS_SHUTDOWN_ENABLED = false;
|
||||||
|
constexpr const char* PARAMS_FILE = "param_320x256.txt";
|
||||||
|
} // namespace Options
|
||||||
|
} // namespace GameDefaults
|
||||||
@@ -19,25 +19,12 @@ DefineButtons::DefineButtons()
|
|||||||
clearButtons();
|
clearButtons();
|
||||||
|
|
||||||
auto gamepads = input_->getGamepads();
|
auto gamepads = input_->getGamepads();
|
||||||
for (auto gamepad : gamepads) {
|
for (const auto &gamepad : gamepads) {
|
||||||
controller_names_.emplace_back(Input::getControllerName(gamepad));
|
controller_names_.emplace_back(Input::getControllerName(gamepad));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crear la ventana de mensaje
|
// Crear la ventana de mensaje
|
||||||
WindowMessage::Config config;
|
WindowMessage::Config config(param.service_menu.window_message);
|
||||||
config.bg_color = Color{20, 30, 50, 240}; // Fondo azul oscuro semi-transparente
|
|
||||||
config.border_color = Color{100, 150, 200, 255}; // Borde azul claro
|
|
||||||
config.title_color = Color{100, 150, 200, 255}; // Titulo azul claro
|
|
||||||
config.text_color = Color{220, 220, 220, 255}; // Texto gris claro
|
|
||||||
config.padding = 15.0F;
|
|
||||||
config.line_spacing = 5.0F;
|
|
||||||
config.title_separator_spacing = 15;
|
|
||||||
config.min_width = 250.0F;
|
|
||||||
config.text_safety_margin = 15.0F;
|
|
||||||
config.min_width = 100;
|
|
||||||
config.min_height = 32;
|
|
||||||
config.animation_duration = 0.3F;
|
|
||||||
|
|
||||||
auto text_renderer = Resource::get()->getText("04b_25_flat");
|
auto text_renderer = Resource::get()->getText("04b_25_flat");
|
||||||
window_message_ = std::make_unique<WindowMessage>(
|
window_message_ = std::make_unique<WindowMessage>(
|
||||||
text_renderer,
|
text_renderer,
|
||||||
@@ -85,6 +72,9 @@ void DefineButtons::handleEvents(const SDL_Event &event) {
|
|||||||
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
||||||
checkEnd();
|
checkEnd();
|
||||||
break;
|
break;
|
||||||
|
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
||||||
|
doControllerAxisMotion(event.gaxis);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -99,6 +89,8 @@ auto DefineButtons::enable(Options::Gamepad *options_gamepad) -> bool {
|
|||||||
index_button_ = 0;
|
index_button_ = 0;
|
||||||
message_shown_ = false;
|
message_shown_ = false;
|
||||||
closing_ = false;
|
closing_ = false;
|
||||||
|
l2_was_pressed_ = false;
|
||||||
|
r2_was_pressed_ = false;
|
||||||
clearButtons();
|
clearButtons();
|
||||||
updateWindowMessage();
|
updateWindowMessage();
|
||||||
|
|
||||||
@@ -117,6 +109,8 @@ void DefineButtons::disable() {
|
|||||||
finished_ = false;
|
finished_ = false;
|
||||||
message_shown_ = false;
|
message_shown_ = false;
|
||||||
closing_ = false;
|
closing_ = false;
|
||||||
|
l2_was_pressed_ = false;
|
||||||
|
r2_was_pressed_ = false;
|
||||||
|
|
||||||
if (window_message_) {
|
if (window_message_) {
|
||||||
window_message_->hide();
|
window_message_->hide();
|
||||||
@@ -132,15 +126,65 @@ void DefineButtons::doControllerButtonDown(const SDL_GamepadButtonEvent &event)
|
|||||||
|
|
||||||
const auto BUTTON = static_cast<SDL_GamepadButton>(event.button);
|
const auto BUTTON = static_cast<SDL_GamepadButton>(event.button);
|
||||||
if (checkButtonNotInUse(BUTTON)) {
|
if (checkButtonNotInUse(BUTTON)) {
|
||||||
buttons_.at(index_button_).button = BUTTON;
|
buttons_.at(index_button_).button = static_cast<int>(BUTTON);
|
||||||
incIndexButton();
|
incIndexButton();
|
||||||
updateWindowMessage();
|
updateWindowMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DefineButtons::doControllerAxisMotion(const SDL_GamepadAxisEvent &event) {
|
||||||
|
auto gamepad = input_->getGamepad(event.which);
|
||||||
|
|
||||||
|
if (!gamepad || gamepad != options_gamepad_->instance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Solo manejamos L2 y R2 como botones con lógica de transición
|
||||||
|
if (event.axis == SDL_GAMEPAD_AXIS_LEFT_TRIGGER) {
|
||||||
|
bool l2_is_pressed_now = event.value > 16384;
|
||||||
|
|
||||||
|
// Solo actuar en la transición de no presionado a presionado
|
||||||
|
if (l2_is_pressed_now && !l2_was_pressed_) {
|
||||||
|
const auto TRIGGER_BUTTON = Input::TRIGGER_L2_AS_BUTTON;
|
||||||
|
if (checkTriggerNotInUse(TRIGGER_BUTTON)) {
|
||||||
|
buttons_.at(index_button_).button = TRIGGER_BUTTON;
|
||||||
|
incIndexButton();
|
||||||
|
updateWindowMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detectar liberación del trigger para llamar checkEnd()
|
||||||
|
if (!l2_is_pressed_now && l2_was_pressed_) {
|
||||||
|
checkEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
l2_was_pressed_ = l2_is_pressed_now;
|
||||||
|
|
||||||
|
} else if (event.axis == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) {
|
||||||
|
bool r2_is_pressed_now = event.value > 16384;
|
||||||
|
|
||||||
|
// Solo actuar en la transición de no presionado a presionado
|
||||||
|
if (r2_is_pressed_now && !r2_was_pressed_) {
|
||||||
|
const auto TRIGGER_BUTTON = Input::TRIGGER_R2_AS_BUTTON;
|
||||||
|
if (checkTriggerNotInUse(TRIGGER_BUTTON)) {
|
||||||
|
buttons_.at(index_button_).button = TRIGGER_BUTTON;
|
||||||
|
incIndexButton();
|
||||||
|
updateWindowMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detectar liberación del trigger para llamar checkEnd()
|
||||||
|
if (!r2_is_pressed_now && r2_was_pressed_) {
|
||||||
|
checkEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
r2_was_pressed_ = r2_is_pressed_now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DefineButtons::bindButtons(Options::Gamepad *options_gamepad) {
|
void DefineButtons::bindButtons(Options::Gamepad *options_gamepad) {
|
||||||
for (const auto &button : buttons_) {
|
for (const auto &button : buttons_) {
|
||||||
Input::bindGameControllerButton(options_gamepad->instance, button.action, button.button);
|
Input::bindGameControllerButton(options_gamepad->instance, button.action, static_cast<SDL_GamepadButton>(button.button));
|
||||||
}
|
}
|
||||||
|
|
||||||
Input::bindGameControllerButton(options_gamepad->instance, Input::Action::SM_SELECT, Input::Action::FIRE_LEFT);
|
Input::bindGameControllerButton(options_gamepad->instance, Input::Action::SM_SELECT, Input::Action::FIRE_LEFT);
|
||||||
@@ -161,13 +205,19 @@ auto DefineButtons::checkButtonNotInUse(SDL_GamepadButton button) -> bool {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto DefineButtons::checkTriggerNotInUse(int trigger_button) -> bool {
|
||||||
|
return std::ranges::all_of(buttons_, [trigger_button](const auto &b) {
|
||||||
|
return b.button != trigger_button;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void DefineButtons::clearButtons() {
|
void DefineButtons::clearButtons() {
|
||||||
buttons_.clear();
|
buttons_.clear();
|
||||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_LEFT"), Input::Action::FIRE_LEFT, SDL_GAMEPAD_BUTTON_INVALID);
|
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_LEFT"), Input::Action::FIRE_LEFT, static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID));
|
||||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_UP"), Input::Action::FIRE_CENTER, SDL_GAMEPAD_BUTTON_INVALID);
|
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_UP"), Input::Action::FIRE_CENTER, static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID));
|
||||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_RIGHT"), Input::Action::FIRE_RIGHT, SDL_GAMEPAD_BUTTON_INVALID);
|
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_RIGHT"), Input::Action::FIRE_RIGHT, static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID));
|
||||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] START"), Input::Action::START, SDL_GAMEPAD_BUTTON_INVALID);
|
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] START"), Input::Action::START, static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID));
|
||||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] SERVICE_MENU"), Input::Action::SERVICE, SDL_GAMEPAD_BUTTON_INVALID);
|
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] SERVICE_MENU"), Input::Action::SERVICE, static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefineButtons::checkEnd() {
|
void DefineButtons::checkEnd() {
|
||||||
|
|||||||
@@ -15,57 +15,65 @@ namespace Options {
|
|||||||
struct Gamepad;
|
struct Gamepad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Clase DefineButtons: configuración de botones de gamepad ---
|
||||||
class DefineButtons {
|
class DefineButtons {
|
||||||
public:
|
public:
|
||||||
|
// --- Estructuras ---
|
||||||
struct Button {
|
struct Button {
|
||||||
std::string label;
|
std::string label;
|
||||||
Input::Action action;
|
Input::Action action;
|
||||||
SDL_GamepadButton button;
|
int button;
|
||||||
|
|
||||||
Button(std::string label, Input::Action action, SDL_GamepadButton button)
|
Button(std::string label, Input::Action action, int button)
|
||||||
: label(std::move(label)), action(action), button(button) {}
|
: label(std::move(label)),
|
||||||
|
action(action),
|
||||||
|
button(button) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --- Constructor y destructor ---
|
||||||
DefineButtons();
|
DefineButtons();
|
||||||
~DefineButtons() = default;
|
~DefineButtons() = default;
|
||||||
|
|
||||||
|
// --- Métodos principales ---
|
||||||
void render();
|
void render();
|
||||||
void update();
|
void update();
|
||||||
void handleEvents(const SDL_Event &event);
|
void handleEvents(const SDL_Event &event);
|
||||||
auto enable(Options::Gamepad *options_gamepad) -> bool;
|
auto enable(Options::Gamepad *options_gamepad) -> bool;
|
||||||
void disable();
|
void disable();
|
||||||
|
|
||||||
|
// --- Getters ---
|
||||||
[[nodiscard]] auto isReadyToClose() const -> bool;
|
[[nodiscard]] auto isReadyToClose() const -> bool;
|
||||||
[[nodiscard]] auto isEnabled() const -> bool { return enabled_; }
|
[[nodiscard]] auto isEnabled() const -> bool { return enabled_; }
|
||||||
[[nodiscard]] auto isFinished() const -> bool { return finished_; }
|
[[nodiscard]] auto isFinished() const -> bool { return finished_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Constante para cuánto tiempo mostrar el mensaje (en frames)
|
// --- Constantes ---
|
||||||
static constexpr size_t MESSAGE_DISPLAY_FRAMES = 120; // ~2 segundos a 60fps
|
static constexpr size_t MESSAGE_DISPLAY_FRAMES = 120; // Cuánto tiempo mostrar el mensaje (en frames) ~2 segundos a 60fps
|
||||||
|
|
||||||
// Punteros
|
// --- Objetos y punteros ---
|
||||||
Input *input_ = nullptr; // Entrada del usuario
|
Input *input_ = nullptr; // Entrada del usuario
|
||||||
Options::Gamepad *options_gamepad_ = nullptr; // Opciones del gamepad
|
Options::Gamepad *options_gamepad_ = nullptr; // Opciones del gamepad
|
||||||
std::unique_ptr<WindowMessage> window_message_; // Mensaje de ventana
|
std::unique_ptr<WindowMessage> window_message_; // Mensaje de ventana
|
||||||
|
|
||||||
// Vectores y strings
|
// --- Variables de estado ---
|
||||||
std::vector<Button> buttons_; // Lista de botones
|
std::vector<Button> buttons_; // Lista de botones
|
||||||
std::vector<std::string> controller_names_; // Nombres de los controladores
|
std::vector<std::string> controller_names_; // Nombres de los controladores
|
||||||
|
size_t index_button_ = 0; // Índice del botón seleccionado
|
||||||
|
size_t message_timer_ = 0; // Contador de frames para el mensaje
|
||||||
|
bool enabled_ = false; // Flag para indicar si está activo
|
||||||
|
bool finished_ = false; // Flag para indicar si ha terminado
|
||||||
|
bool closing_ = false; // Flag para indicar que está cerrando
|
||||||
|
bool message_shown_ = false; // Flag para indicar que ya mostró el mensaje
|
||||||
|
bool l2_was_pressed_ = false; // Estado anterior del trigger L2
|
||||||
|
bool r2_was_pressed_ = false; // Estado anterior del trigger R2
|
||||||
|
|
||||||
// size_t
|
// --- Métodos internos ---
|
||||||
size_t index_button_ = 0; // Índice del botón seleccionado
|
|
||||||
size_t message_timer_ = 0; // Contador de frames para el mensaje
|
|
||||||
|
|
||||||
// bools
|
|
||||||
bool enabled_ = false; // Flag para indicar si está activo
|
|
||||||
bool finished_ = false; // Flag para indicar si ha terminado
|
|
||||||
bool closing_ = false; // Flag para indicar que está cerrando
|
|
||||||
bool message_shown_ = false; // Flag para indicar que ya mostró el mensaje
|
|
||||||
|
|
||||||
// Métodos
|
|
||||||
void incIndexButton();
|
void incIndexButton();
|
||||||
void doControllerButtonDown(const SDL_GamepadButtonEvent &event);
|
void doControllerButtonDown(const SDL_GamepadButtonEvent &event);
|
||||||
|
void doControllerAxisMotion(const SDL_GamepadAxisEvent &event);
|
||||||
void bindButtons(Options::Gamepad *options_gamepad);
|
void bindButtons(Options::Gamepad *options_gamepad);
|
||||||
auto checkButtonNotInUse(SDL_GamepadButton button) -> bool;
|
auto checkButtonNotInUse(SDL_GamepadButton button) -> bool;
|
||||||
|
auto checkTriggerNotInUse(int trigger_button) -> bool;
|
||||||
void clearButtons();
|
void clearButtons();
|
||||||
void checkEnd();
|
void checkEnd();
|
||||||
void updateWindowMessage();
|
void updateWindowMessage();
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ static std::vector<Info> difficulties_list;
|
|||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
difficulties_list = {
|
difficulties_list = {
|
||||||
{Code::EASY, "Easy"},
|
{.code = Code::EASY, .name = "Easy"},
|
||||||
{Code::NORMAL, "Normal"},
|
{.code = Code::NORMAL, .name = "Normal"},
|
||||||
{Code::HARD, "Hard"}};
|
{.code = Code::HARD, .name = "Hard"}};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto getDifficulties() -> std::vector<Info>& {
|
auto getDifficulties() -> std::vector<Info>& {
|
||||||
|
|||||||
@@ -1,52 +1,28 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string> // Para string
|
||||||
#include <vector>
|
#include <vector> // Para vector
|
||||||
|
|
||||||
namespace Difficulty {
|
namespace Difficulty {
|
||||||
|
|
||||||
/**
|
// --- Enums ---
|
||||||
* @brief Códigos que identifican unívocamente cada nivel de dificultad.
|
|
||||||
*/
|
|
||||||
enum class Code {
|
enum class Code {
|
||||||
EASY = 0,
|
EASY = 0, // Dificultad fácil
|
||||||
NORMAL = 1,
|
NORMAL = 1, // Dificultad normal
|
||||||
HARD = 2,
|
HARD = 2, // Dificultad difícil
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
// --- Estructuras ---
|
||||||
* @brief Estructura que asocia un código de dificultad con su nombre traducible.
|
|
||||||
*/
|
|
||||||
struct Info {
|
struct Info {
|
||||||
Code code;
|
Code code; // Código de dificultad
|
||||||
std::string name;
|
std::string name; // Nombre traducible
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Interfaz Pública ---
|
// --- Funciones ---
|
||||||
|
void init(); // Inicializa la lista de dificultades con sus valores por defecto
|
||||||
|
|
||||||
/**
|
auto getDifficulties() -> std::vector<Info>&; // Devuelve una referencia al vector de todas las dificultades
|
||||||
* @brief Inicializa la lista de dificultades con sus valores por defecto.
|
auto getNameFromCode(Code code) -> std::string; // Obtiene el nombre de una dificultad a partir de su código
|
||||||
*/
|
auto getCodeFromName(const std::string& name) -> Code; // Obtiene el código de una dificultad a partir de su nombre
|
||||||
void init();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Devuelve una referencia al vector de todas las dificultades para su lectura o modificación.
|
|
||||||
* @return Referencia a `std::vector<Info>&`.
|
|
||||||
*/
|
|
||||||
auto getDifficulties() -> std::vector<Info>&;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Obtiene el nombre de una dificultad a partir de su código.
|
|
||||||
* @param code El código de la dificultad.
|
|
||||||
* @return El nombre de la dificultad.
|
|
||||||
*/
|
|
||||||
auto getNameFromCode(Code code) -> std::string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Obtiene el código de una dificultad a partir de su nombre.
|
|
||||||
* @param name El nombre de la dificultad.
|
|
||||||
* @return El código de la dificultad.
|
|
||||||
*/
|
|
||||||
auto getCodeFromName(const std::string& name) -> Code;
|
|
||||||
|
|
||||||
} // namespace Difficulty
|
} // namespace Difficulty
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "param.h" // Para loadParamsFromFile
|
#include "param.h" // Para loadParamsFromFile
|
||||||
#include "player.h" // Para Player
|
#include "player.h" // Para Player
|
||||||
#include "resource.h" // Para Resource
|
#include "resource.h" // Para Resource
|
||||||
|
#include "resource_helper.h" // Para ResourceHelper
|
||||||
#include "screen.h" // Para Screen
|
#include "screen.h" // Para Screen
|
||||||
#include "section.hpp" // Para Name, Options, name, options, AttractMode, attract_mode
|
#include "section.hpp" // Para Name, Options, name, options, AttractMode, attract_mode
|
||||||
#include "sections/credits.h" // Para Credits
|
#include "sections/credits.h" // Para Credits
|
||||||
@@ -41,7 +42,7 @@ Director::Director(int argc, std::span<char *> argv) {
|
|||||||
Section::name = Section::Name::GAME;
|
Section::name = Section::Name::GAME;
|
||||||
Section::options = Section::Options::GAME_PLAY_1P;
|
Section::options = Section::Options::GAME_PLAY_1P;
|
||||||
#elif _DEBUG
|
#elif _DEBUG
|
||||||
Section::name = Section::Name::GAME;
|
Section::name = Section::Name::HI_SCORE_TABLE;
|
||||||
Section::options = Section::Options::GAME_PLAY_1P;
|
Section::options = Section::Options::GAME_PLAY_1P;
|
||||||
#else // NORMAL GAME
|
#else // NORMAL GAME
|
||||||
Section::name = Section::Name::LOGO;
|
Section::name = Section::Name::LOGO;
|
||||||
@@ -76,7 +77,13 @@ Director::~Director() {
|
|||||||
// Inicializa todo
|
// Inicializa todo
|
||||||
void Director::init() {
|
void Director::init() {
|
||||||
// Configuración inicial de parametros
|
// Configuración inicial de parametros
|
||||||
Asset::init(executable_path_); // Inicializa el sistema de gestión de archivos
|
Asset::init(executable_path_); // Inicializa el sistema de gestión de archivos
|
||||||
|
|
||||||
|
#ifdef MACOS_BUNDLE
|
||||||
|
ResourceHelper::initializeResourceSystem(executable_path_ + "/../Resources/resources.pack");
|
||||||
|
#else
|
||||||
|
ResourceHelper::initializeResourceSystem("resources.pack");
|
||||||
|
#endif
|
||||||
loadAssets(); // Crea el índice de archivos
|
loadAssets(); // Crea el índice de archivos
|
||||||
Input::init(Asset::get()->get("gamecontrollerdb.txt"), Asset::get()->get("controllers.json")); // Carga configuración de controles
|
Input::init(Asset::get()->get("gamecontrollerdb.txt"), Asset::get()->get("controllers.json")); // Carga configuración de controles
|
||||||
Options::setConfigFile(Asset::get()->get("config.txt")); // Establece el fichero de configuración
|
Options::setConfigFile(Asset::get()->get("config.txt")); // Establece el fichero de configuración
|
||||||
@@ -124,9 +131,9 @@ void Director::close() {
|
|||||||
void Director::loadParams() {
|
void Director::loadParams() {
|
||||||
// Carga los parametros para configurar el juego
|
// Carga los parametros para configurar el juego
|
||||||
#ifdef ANBERNIC
|
#ifdef ANBERNIC
|
||||||
const std::string paramFilePath = asset->get("param_320x240.txt");
|
const std::string PARAM_FILE_PATH = Asset::get()->get("param_320x240.txt");
|
||||||
#else
|
#else
|
||||||
const std::string PARAM_FILE_PATH = overrides.param_file == "--320x240" ? Asset::get()->get("param_320x240.txt") : Asset::get()->get("param_320x256.txt");
|
const std::string PARAM_FILE_PATH = Asset::get()->get(Options::settings.params_file);
|
||||||
#endif
|
#endif
|
||||||
loadParamsFromFile(PARAM_FILE_PATH);
|
loadParamsFromFile(PARAM_FILE_PATH);
|
||||||
}
|
}
|
||||||
@@ -154,7 +161,7 @@ void Director::loadAssets() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Cargar la configuración de assets (también aplicar el prefijo al archivo de configuración)
|
// Cargar la configuración de assets (también aplicar el prefijo al archivo de configuración)
|
||||||
std::string config_path = executable_path_ + PREFIX + "/data/config/assets.txt";
|
std::string config_path = executable_path_ + PREFIX + "/config/assets.txt";
|
||||||
Asset::get()->loadFromFile(config_path, PREFIX, system_folder_);
|
Asset::get()->loadFromFile(config_path, PREFIX, system_folder_);
|
||||||
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Assets configuration loaded successfully");
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Assets configuration loaded successfully");
|
||||||
@@ -188,7 +195,7 @@ void Director::createSystemFolder(const std::string &folder) {
|
|||||||
|
|
||||||
if (result != SystemUtils::Result::SUCCESS) {
|
if (result != SystemUtils::Result::SUCCESS) {
|
||||||
std::cerr << "Error creando carpeta del sistema: "
|
std::cerr << "Error creando carpeta del sistema: "
|
||||||
<< SystemUtils::resultToString(result) << std::endl;
|
<< SystemUtils::resultToString(result) << '\n';
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,7 +328,7 @@ void Director::shutdownSystem(bool should_shutdown) {
|
|||||||
auto result = SystemShutdown::shutdownSystem(5, true); // 5 segundos, forzar apps
|
auto result = SystemShutdown::shutdownSystem(5, true); // 5 segundos, forzar apps
|
||||||
|
|
||||||
if (result != SystemShutdown::ShutdownResult::SUCCESS) {
|
if (result != SystemShutdown::ShutdownResult::SUCCESS) {
|
||||||
std::cerr << SystemShutdown::resultToString(result) << std::endl;
|
std::cerr << SystemShutdown::resultToString(result) << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@ namespace Lang {
|
|||||||
enum class Code : int;
|
enum class Code : int;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Clase Director: gestor principal de la aplicación ---
|
||||||
class Director {
|
class Director {
|
||||||
public:
|
public:
|
||||||
// --- Constructor y destructor ---
|
// --- Constructor y destructor ---
|
||||||
|
|||||||
@@ -42,10 +42,13 @@ void EnterName::incPosition() {
|
|||||||
if (position_ >= NAME_SIZE) {
|
if (position_ >= NAME_SIZE) {
|
||||||
position_ = NAME_SIZE; // Mantenemos en el índice máximo válido.
|
position_ = NAME_SIZE; // Mantenemos en el índice máximo válido.
|
||||||
position_overflow_ = true; // Activamos el flag de overflow.
|
position_overflow_ = true; // Activamos el flag de overflow.
|
||||||
} else if (position_ > 0) // No es necesario verificar position_ < MAX_NAME_LENGHT
|
} else if (position_ > 0) // No es necesario verificar position_ < MAX_NAME_LENGTH
|
||||||
{
|
{
|
||||||
// Copiamos el índice del carácter anterior si es posible.
|
// Copiamos el índice del carácter anterior si es posible.
|
||||||
character_index_[position_] = character_index_[position_ - 1];
|
// character_index_[position_] = character_index_[position_ - 1];
|
||||||
|
|
||||||
|
// Ponemos el caracter "espacio"
|
||||||
|
character_index_[position_] = 0;
|
||||||
} else {
|
} else {
|
||||||
// Si position_ es 0, inicializamos el carácter actual.
|
// Si position_ es 0, inicializamos el carácter actual.
|
||||||
character_index_[position_] = 0;
|
character_index_[position_] = 0;
|
||||||
@@ -74,7 +77,7 @@ void EnterName::decPosition() {
|
|||||||
// character_index_[position_] = 0;
|
// character_index_[position_] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si position_ es menor que NAME_LENGHT, aseguramos que el overflow esté desactivado.
|
// Si position_ es menor que NAME_LENGTH, aseguramos que el overflow esté desactivado.
|
||||||
if (position_ < NAME_SIZE) {
|
if (position_ < NAME_SIZE) {
|
||||||
position_overflow_ = false;
|
position_overflow_ = false;
|
||||||
}
|
}
|
||||||
@@ -144,12 +147,19 @@ auto EnterName::findIndex(char character) const -> int {
|
|||||||
// Devuelve un nombre al azar
|
// Devuelve un nombre al azar
|
||||||
auto EnterName::getRandomName() -> std::string {
|
auto EnterName::getRandomName() -> std::string {
|
||||||
static constexpr std::array<std::string_view, 8> NAMES = {
|
static constexpr std::array<std::string_view, 8> NAMES = {
|
||||||
"BAL1", "TABE", "DOC", "MON", "SAM1", "JORDI", "JDES", "PEPE"};
|
"BAL1",
|
||||||
|
"TABE",
|
||||||
|
"DOC",
|
||||||
|
"MON",
|
||||||
|
"SAM1",
|
||||||
|
"JORDI",
|
||||||
|
"JDES",
|
||||||
|
"PEPE"};
|
||||||
return std::string(NAMES[rand() % NAMES.size()]);
|
return std::string(NAMES[rand() % NAMES.size()]);
|
||||||
}
|
}
|
||||||
// Obtiene el nombre final introducido
|
// Obtiene el nombre final introducido
|
||||||
auto EnterName::getFinalName() -> std::string {
|
auto EnterName::getFinalName() -> std::string {
|
||||||
auto name = trim(name_.substr(0, position_));
|
auto name = trim(name_.substr(0, position_ + 1)); // Devuelve el texto intruducido incluyendo el del selector
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
name = getRandomName();
|
name = getRandomName();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
|
|
||||||
#include "utils.h" // Para trim
|
#include "utils.h" // Para trim
|
||||||
|
|
||||||
// Tamaño máximo del nombre
|
// --- Constantes ---
|
||||||
constexpr size_t NAME_SIZE = 5;
|
constexpr size_t NAME_SIZE = 5; // Tamaño máximo del nombre
|
||||||
|
|
||||||
// Clase EnterName
|
// --- Clase EnterName: gestor de entrada de nombre del jugador ---
|
||||||
class EnterName {
|
class EnterName {
|
||||||
public:
|
public:
|
||||||
EnterName();
|
EnterName();
|
||||||
@@ -29,11 +29,12 @@ class EnterName {
|
|||||||
[[nodiscard]] auto getPositionOverflow() const -> bool { return position_overflow_; } // Indica si la posición excede el límite
|
[[nodiscard]] auto getPositionOverflow() const -> bool { return position_overflow_; } // Indica si la posición excede el límite
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// --- Variables de estado ---
|
||||||
std::string character_list_; // Lista de caracteres permitidos
|
std::string character_list_; // Lista de caracteres permitidos
|
||||||
std::string name_; // Nombre en proceso
|
std::string name_; // Nombre en proceso
|
||||||
|
std::array<int, NAME_SIZE> character_index_; // Índices a "character_list_"
|
||||||
size_t position_ = 0; // Índice del carácter que se edita
|
size_t position_ = 0; // Índice del carácter que se edita
|
||||||
bool position_overflow_ = false; // Flag para exceder límite
|
bool position_overflow_ = false; // Flag para exceder límite
|
||||||
std::array<int, NAME_SIZE> character_index_; // Índices a "character_list_"
|
|
||||||
|
|
||||||
void updateNameFromCharacterIndex(); // Actualiza "name_" según "character_index_"
|
void updateNameFromCharacterIndex(); // Actualiza "name_" según "character_index_"
|
||||||
void initCharacterIndex(const std::string &name); // Inicializa índices desde el nombre
|
void initCharacterIndex(const std::string &name); // Inicializa índices desde el nombre
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ void Explosions::render() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Añade texturas al objeto
|
// Añade texturas al objeto
|
||||||
void Explosions::addTexture(int size, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation) {
|
void Explosions::addTexture(int size, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation) {
|
||||||
textures_.emplace_back(size, texture, animation);
|
textures_.emplace_back(size, texture, animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,53 +1,47 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory> // Para unique_ptr, shared_ptr
|
#include <memory> // Para unique_ptr, shared_ptr
|
||||||
#include <string> // Para string
|
#include <string> // Para string
|
||||||
#include <utility>
|
#include <utility> // Para move
|
||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
#include "animated_sprite.h" // Para AnimatedSprite
|
#include "animated_sprite.h" // Para AnimatedSprite
|
||||||
|
|
||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
// Estructura para almacenar la información de una textura de explosión
|
// --- Estructura ExplosionTexture: almacena información de una textura de explosión ---
|
||||||
struct ExplosionTexture {
|
struct ExplosionTexture {
|
||||||
int size; // Tamaño de la explosión
|
int size; // Tamaño de la explosión
|
||||||
std::shared_ptr<Texture> texture; // Textura para la explosión
|
std::shared_ptr<Texture> texture; // Textura para la explosión
|
||||||
std::vector<std::string> animation; // Animación para la textura
|
std::vector<std::string> animation; // Animación para la textura
|
||||||
|
|
||||||
ExplosionTexture(int sz, std::shared_ptr<Texture> tex, const std::vector<std::string> &anim)
|
ExplosionTexture(int sz, std::shared_ptr<Texture> tex, const std::vector<std::string> &anim)
|
||||||
: size(sz), texture(std::move(tex)), animation(anim) {}
|
: size(sz),
|
||||||
|
texture(std::move(tex)),
|
||||||
|
animation(anim) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Clase Explosions
|
// --- Clase Explosions: gestor de explosiones ---
|
||||||
class Explosions {
|
class Explosions {
|
||||||
public:
|
public:
|
||||||
// Constructor y destructor
|
// --- Constructor y destructor ---
|
||||||
Explosions() = default;
|
Explosions() = default; // Constructor por defecto
|
||||||
~Explosions() = default;
|
~Explosions() = default; // Destructor por defecto
|
||||||
|
|
||||||
// Actualiza la lógica de la clase
|
// --- Métodos principales ---
|
||||||
void update();
|
void update(); // Actualiza la lógica de la clase
|
||||||
|
void render(); // Dibuja el objeto en pantalla
|
||||||
|
|
||||||
// Dibuja el objeto en pantalla
|
// --- Configuración ---
|
||||||
void render();
|
void addTexture(int size, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation); // Añade texturas al objeto
|
||||||
|
void add(int x, int y, int size); // Añade una explosión
|
||||||
// Añade texturas al objeto
|
|
||||||
void addTexture(int size, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation);
|
|
||||||
|
|
||||||
// Añade una explosión
|
|
||||||
void add(int x, int y, int size);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Vector con las texturas a utilizar
|
// --- Variables de estado ---
|
||||||
std::vector<ExplosionTexture> textures_;
|
std::vector<ExplosionTexture> textures_; // Vector con las texturas a utilizar
|
||||||
|
std::vector<std::unique_ptr<AnimatedSprite>> explosions_; // Lista con todas las explosiones
|
||||||
|
|
||||||
// Lista con todas las explosiones
|
// --- Métodos internos ---
|
||||||
std::vector<std::unique_ptr<AnimatedSprite>> explosions_;
|
void freeExplosions(); // Vacía el vector de elementos finalizados
|
||||||
|
auto getIndexBySize(int size) -> int; // Busca una textura a partir del tamaño
|
||||||
// Vacia el vector de elementos finalizados
|
|
||||||
void freeExplosions();
|
|
||||||
|
|
||||||
// Busca una textura a partir del tamaño
|
|
||||||
auto getIndexBySize(int size) -> int;
|
|
||||||
};
|
};
|
||||||
16
source/external/jail_shader.h
vendored
@@ -4,6 +4,20 @@
|
|||||||
#include <string> // Para basic_string, string
|
#include <string> // Para basic_string, string
|
||||||
|
|
||||||
namespace shader {
|
namespace shader {
|
||||||
bool init(SDL_Window *ventana, SDL_Texture *texturaBackBuffer, const std::string &vertexShader, const std::string &fragmentShader = "");
|
bool init(SDL_Window *ventana, SDL_Texture *texturaBackBuffer, const std::string &shaderSource, const std::string &fragmentShader = "");
|
||||||
void render();
|
void render();
|
||||||
|
void cleanup();
|
||||||
|
bool isUsingOpenGL();
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
namespace metal {
|
||||||
|
bool initMetal(SDL_Window* window, SDL_Texture* backBuffer, const std::string& shaderFilename);
|
||||||
|
SDL_Texture* createMetalRenderTarget(SDL_Renderer* renderer, int width, int height);
|
||||||
|
void updateMetalTexture(SDL_Texture* backBuffer);
|
||||||
|
void renderMetal();
|
||||||
|
void renderWithPostProcessing(SDL_Renderer* renderer, SDL_Texture* sourceTexture);
|
||||||
|
void cleanupMetal();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace shader
|
} // namespace shader
|
||||||
387
source/external/jail_shader_metal.mm
vendored
Normal file
@@ -0,0 +1,387 @@
|
|||||||
|
#include "jail_shader.h"
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3/SDL_metal.h>
|
||||||
|
#include <Metal/Metal.h>
|
||||||
|
#include <QuartzCore/CAMetalLayer.h>
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <vector>
|
||||||
|
#include "../asset.h"
|
||||||
|
|
||||||
|
namespace shader {
|
||||||
|
namespace metal {
|
||||||
|
|
||||||
|
// Metal objects
|
||||||
|
id<MTLDevice> device = nullptr;
|
||||||
|
id<MTLRenderPipelineState> pipelineState = nullptr;
|
||||||
|
id<MTLBuffer> vertexBuffer = nullptr;
|
||||||
|
id<MTLTexture> backBufferTexture = nullptr;
|
||||||
|
id<MTLTexture> gameCanvasTexture = nullptr; // Our custom render target texture
|
||||||
|
id<MTLSamplerState> sampler = nullptr;
|
||||||
|
|
||||||
|
// SDL objects (references from main shader module)
|
||||||
|
SDL_Window* win = nullptr;
|
||||||
|
SDL_Renderer* renderer = nullptr;
|
||||||
|
SDL_Texture* backBuffer = nullptr;
|
||||||
|
|
||||||
|
// Vertex data for fullscreen quad
|
||||||
|
struct Vertex {
|
||||||
|
float position[4]; // x, y, z, w
|
||||||
|
float texcoord[2]; // u, v
|
||||||
|
};
|
||||||
|
|
||||||
|
const Vertex quadVertices[] = {
|
||||||
|
// Position (x, y, z, w) // TexCoord (u, v) - Standard OpenGL-style coordinates
|
||||||
|
{{-1.0f, -1.0f, 0.0f, 1.0f}, {0.0f, 1.0f}}, // Bottom-left
|
||||||
|
{{ 1.0f, -1.0f, 0.0f, 1.0f}, {1.0f, 1.0f}}, // Bottom-right
|
||||||
|
{{-1.0f, 1.0f, 0.0f, 1.0f}, {0.0f, 0.0f}}, // Top-left
|
||||||
|
{{ 1.0f, 1.0f, 0.0f, 1.0f}, {1.0f, 0.0f}}, // Top-right
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string loadMetalShader(const std::string& filename) {
|
||||||
|
// Try to load the .metal file from the same location as GLSL files
|
||||||
|
auto data = Asset::get()->loadData(filename);
|
||||||
|
if (!data.empty()) {
|
||||||
|
return std::string(data.begin(), data.end());
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Texture* createMetalRenderTarget(SDL_Renderer* renderer, int width, int height) {
|
||||||
|
if (!renderer) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "createMetalRenderTarget: No renderer provided");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crear textura Metal como render target
|
||||||
|
SDL_Texture* metalTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
|
||||||
|
if (!metalTexture) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create Metal render target texture: %s", SDL_GetError());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configurar filtrado nearest neighbor para look pixelado
|
||||||
|
SDL_SetTextureScaleMode(metalTexture, SDL_SCALEMODE_NEAREST);
|
||||||
|
|
||||||
|
// Try to extract and store the Metal texture directly
|
||||||
|
SDL_PropertiesID props = SDL_GetTextureProperties(metalTexture);
|
||||||
|
if (props != 0) {
|
||||||
|
const char* propertyNames[] = {
|
||||||
|
"SDL.texture.metal.texture",
|
||||||
|
"SDL.renderer.metal.texture",
|
||||||
|
"metal.texture",
|
||||||
|
"texture.metal",
|
||||||
|
"MTLTexture",
|
||||||
|
"texture"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const char* propName : propertyNames) {
|
||||||
|
gameCanvasTexture = (__bridge id<MTLTexture>)SDL_GetPointerProperty(props, propName, nullptr);
|
||||||
|
if (gameCanvasTexture) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Successfully extracted Metal texture via property '%s' (size: %lux%lu)",
|
||||||
|
propName, [gameCanvasTexture width], [gameCanvasTexture height]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gameCanvasTexture) {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Could not extract Metal texture from SDL texture - shaders may not work");
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Created Metal render target texture (%dx%d)", width, height);
|
||||||
|
return metalTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initMetal(SDL_Window* window, SDL_Texture* backBufferTexture, const std::string& shaderFilename) {
|
||||||
|
// Store references
|
||||||
|
win = window;
|
||||||
|
backBuffer = backBufferTexture;
|
||||||
|
renderer = SDL_GetRenderer(window);
|
||||||
|
|
||||||
|
if (!renderer) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get SDL renderer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Metal layer from SDL renderer and extract device from it
|
||||||
|
CAMetalLayer* metalLayer = (__bridge CAMetalLayer*)SDL_GetRenderMetalLayer(renderer);
|
||||||
|
if (!metalLayer) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get Metal layer from SDL renderer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
device = metalLayer.device;
|
||||||
|
if (!device) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to get Metal device from layer");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Got Metal device from SDL layer: %s", [[device name] UTF8String]);
|
||||||
|
|
||||||
|
// Note: We no longer need our own texture - we'll use the backBuffer directly
|
||||||
|
|
||||||
|
// Load and compile shaders
|
||||||
|
std::string metalShaderSource = loadMetalShader(shaderFilename);
|
||||||
|
if (metalShaderSource.empty()) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load Metal shader: %s", shaderFilename.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Loaded Metal shader %s (length: %zu)",
|
||||||
|
shaderFilename.c_str(), metalShaderSource.length());
|
||||||
|
|
||||||
|
NSString* shaderNSString = [NSString stringWithUTF8String:metalShaderSource.c_str()];
|
||||||
|
NSError* error = nil;
|
||||||
|
id<MTLLibrary> library = [device newLibraryWithSource:shaderNSString options:nil error:&error];
|
||||||
|
if (!library || error) {
|
||||||
|
if (error) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to compile Metal shader: %s",
|
||||||
|
[[error localizedDescription] UTF8String]);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"vertex_main"];
|
||||||
|
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"fragment_main"];
|
||||||
|
|
||||||
|
if (!vertexFunction || !fragmentFunction) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load Metal shader functions");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create render pipeline
|
||||||
|
MTLRenderPipelineDescriptor* pipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||||
|
pipelineDescriptor.vertexFunction = vertexFunction;
|
||||||
|
pipelineDescriptor.fragmentFunction = fragmentFunction;
|
||||||
|
pipelineDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
|
||||||
|
|
||||||
|
// Set up vertex descriptor
|
||||||
|
MTLVertexDescriptor* vertexDescriptor = [[MTLVertexDescriptor alloc] init];
|
||||||
|
vertexDescriptor.attributes[0].format = MTLVertexFormatFloat4;
|
||||||
|
vertexDescriptor.attributes[0].offset = 0;
|
||||||
|
vertexDescriptor.attributes[0].bufferIndex = 0;
|
||||||
|
vertexDescriptor.attributes[1].format = MTLVertexFormatFloat2;
|
||||||
|
vertexDescriptor.attributes[1].offset = 4 * sizeof(float);
|
||||||
|
vertexDescriptor.attributes[1].bufferIndex = 0;
|
||||||
|
vertexDescriptor.layouts[0].stride = sizeof(Vertex);
|
||||||
|
vertexDescriptor.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
|
||||||
|
|
||||||
|
pipelineDescriptor.vertexDescriptor = vertexDescriptor;
|
||||||
|
|
||||||
|
pipelineState = [device newRenderPipelineStateWithDescriptor:pipelineDescriptor error:&error];
|
||||||
|
if (!pipelineState || error) {
|
||||||
|
if (error) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create Metal render pipeline: %s",
|
||||||
|
[[error localizedDescription] UTF8String]);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create vertex buffer
|
||||||
|
vertexBuffer = [device newBufferWithBytes:quadVertices
|
||||||
|
length:sizeof(quadVertices)
|
||||||
|
options:MTLResourceOptionCPUCacheModeDefault];
|
||||||
|
|
||||||
|
// Create sampler state for nearest neighbor filtering (pixelated look)
|
||||||
|
MTLSamplerDescriptor* samplerDescriptor = [[MTLSamplerDescriptor alloc] init];
|
||||||
|
samplerDescriptor.minFilter = MTLSamplerMinMagFilterNearest;
|
||||||
|
samplerDescriptor.magFilter = MTLSamplerMinMagFilterNearest;
|
||||||
|
samplerDescriptor.sAddressMode = MTLSamplerAddressModeClampToEdge;
|
||||||
|
samplerDescriptor.tAddressMode = MTLSamplerAddressModeClampToEdge;
|
||||||
|
|
||||||
|
sampler = [device newSamplerStateWithDescriptor:samplerDescriptor];
|
||||||
|
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "** Metal shader system initialized successfully");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateMetalTexture(SDL_Texture* backBuffer) {
|
||||||
|
if (!device || !backBuffer) return;
|
||||||
|
|
||||||
|
// Only log this occasionally to avoid spam
|
||||||
|
static int attemptCount = 0;
|
||||||
|
static bool hasLogged = false;
|
||||||
|
|
||||||
|
// Try multiple property names that SDL3 might use
|
||||||
|
SDL_PropertiesID props = SDL_GetTextureProperties(backBuffer);
|
||||||
|
if (props != 0) {
|
||||||
|
const char* propertyNames[] = {
|
||||||
|
"SDL.texture.metal.texture",
|
||||||
|
"SDL.renderer.metal.texture",
|
||||||
|
"metal.texture",
|
||||||
|
"texture.metal",
|
||||||
|
"MTLTexture",
|
||||||
|
"texture"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const char* propName : propertyNames) {
|
||||||
|
id<MTLTexture> sdlMetalTexture = (__bridge id<MTLTexture>)SDL_GetPointerProperty(props, propName, nullptr);
|
||||||
|
if (sdlMetalTexture) {
|
||||||
|
backBufferTexture = sdlMetalTexture;
|
||||||
|
if (!hasLogged) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Got Metal texture via property '%s' (size: %lux%lu)",
|
||||||
|
propName, [backBufferTexture width], [backBufferTexture height]);
|
||||||
|
hasLogged = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we can't get the texture after several attempts, log once and continue
|
||||||
|
if (!hasLogged && attemptCount++ > 10) {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Could not access SDL Metal texture after %d attempts - shader will be skipped", attemptCount);
|
||||||
|
hasLogged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderMetal() {
|
||||||
|
if (!renderer || !device || !pipelineState) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Metal render failed: missing components");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Correct pipeline: backBuffer → Metal shaders → screen (no double rendering)
|
||||||
|
|
||||||
|
// Try to get the Metal texture directly from the SDL backBuffer texture
|
||||||
|
updateMetalTexture(backBuffer);
|
||||||
|
|
||||||
|
if (!backBufferTexture) {
|
||||||
|
static int fallbackLogCount = 0;
|
||||||
|
if (fallbackLogCount++ < 3) {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Metal texture not available - falling back to normal SDL rendering (attempt %d)", fallbackLogCount);
|
||||||
|
}
|
||||||
|
// Fallback: render without shaders using normal SDL path
|
||||||
|
SDL_SetRenderTarget(renderer, nullptr);
|
||||||
|
SDL_RenderTexture(renderer, backBuffer, nullptr, nullptr);
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply Metal CRT shader directly: backBuffer texture → screen
|
||||||
|
SDL_SetRenderTarget(renderer, nullptr);
|
||||||
|
|
||||||
|
// Get Metal command encoder to render directly to screen
|
||||||
|
void* encoder_ptr = SDL_GetRenderMetalCommandEncoder(renderer);
|
||||||
|
if (encoder_ptr) {
|
||||||
|
id<MTLRenderCommandEncoder> encoder = (__bridge id<MTLRenderCommandEncoder>)encoder_ptr;
|
||||||
|
|
||||||
|
static int debugCount = 0;
|
||||||
|
if (debugCount++ < 5) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Metal render attempt %d: encoder=%p, pipeline=%p, texture=%p",
|
||||||
|
debugCount, encoder, pipelineState, backBufferTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply CRT shader effect directly to backBuffer texture
|
||||||
|
[encoder setRenderPipelineState:pipelineState];
|
||||||
|
[encoder setVertexBuffer:vertexBuffer offset:0 atIndex:0];
|
||||||
|
[encoder setFragmentTexture:backBufferTexture atIndex:0];
|
||||||
|
[encoder setFragmentSamplerState:sampler atIndex:0];
|
||||||
|
|
||||||
|
// Draw fullscreen quad with CRT effect directly to screen
|
||||||
|
[encoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||||
|
|
||||||
|
static int successCount = 0;
|
||||||
|
if (successCount++ < 5) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Applied CRT shader to backBuffer (attempt %d) - texture size: %lux%lu",
|
||||||
|
successCount, [backBufferTexture width], [backBufferTexture height]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Fallback: render normally without shaders
|
||||||
|
SDL_RenderTexture(renderer, backBuffer, nullptr, nullptr);
|
||||||
|
|
||||||
|
static int fallbackCount = 0;
|
||||||
|
if (fallbackCount++ < 3) {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Failed to get Metal command encoder - fallback rendering");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderWithPostProcessing(SDL_Renderer* renderer, SDL_Texture* sourceTexture) {
|
||||||
|
if (!renderer || !sourceTexture || !device || !pipelineState) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Metal post-processing failed: missing components");
|
||||||
|
// Fallback: render normally without shaders
|
||||||
|
SDL_SetRenderTarget(renderer, nullptr);
|
||||||
|
SDL_RenderTexture(renderer, sourceTexture, nullptr, nullptr);
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use our stored Metal texture if available
|
||||||
|
id<MTLTexture> metalTexture = gameCanvasTexture;
|
||||||
|
|
||||||
|
if (!metalTexture) {
|
||||||
|
static int fallbackLogCount = 0;
|
||||||
|
if (fallbackLogCount++ < 3) {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "gameCanvasTexture not available - falling back to normal rendering (attempt %d)", fallbackLogCount);
|
||||||
|
}
|
||||||
|
// Fallback: render normally without shaders
|
||||||
|
SDL_SetRenderTarget(renderer, nullptr);
|
||||||
|
SDL_RenderTexture(renderer, sourceTexture, nullptr, nullptr);
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply Metal CRT shader post-processing: sourceTexture → screen
|
||||||
|
SDL_SetRenderTarget(renderer, nullptr);
|
||||||
|
|
||||||
|
// Get Metal command encoder to render directly to screen
|
||||||
|
void* encoder_ptr = SDL_GetRenderMetalCommandEncoder(renderer);
|
||||||
|
if (encoder_ptr) {
|
||||||
|
id<MTLRenderCommandEncoder> encoder = (__bridge id<MTLRenderCommandEncoder>)encoder_ptr;
|
||||||
|
|
||||||
|
static int debugCount = 0;
|
||||||
|
if (debugCount++ < 3) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Metal post-processing attempt %d: encoder=%p, pipeline=%p, texture=%p",
|
||||||
|
debugCount, encoder, pipelineState, metalTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply CRT shader effect to sourceTexture
|
||||||
|
[encoder setRenderPipelineState:pipelineState];
|
||||||
|
[encoder setVertexBuffer:vertexBuffer offset:0 atIndex:0];
|
||||||
|
[encoder setFragmentTexture:metalTexture atIndex:0];
|
||||||
|
[encoder setFragmentSamplerState:sampler atIndex:0];
|
||||||
|
|
||||||
|
// Draw fullscreen quad with CRT effect directly to screen
|
||||||
|
[encoder drawPrimitives:MTLPrimitiveTypeTriangleStrip vertexStart:0 vertexCount:4];
|
||||||
|
|
||||||
|
static int successCount = 0;
|
||||||
|
if (successCount++ < 3) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Applied CRT post-processing (attempt %d) - texture size: %lux%lu",
|
||||||
|
successCount, [metalTexture width], [metalTexture height]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Fallback: render normally without shaders
|
||||||
|
SDL_RenderTexture(renderer, sourceTexture, nullptr, nullptr);
|
||||||
|
|
||||||
|
static int fallbackCount = 0;
|
||||||
|
if (fallbackCount++ < 3) {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Failed to get Metal command encoder for post-processing - fallback rendering");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_RenderPresent(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanupMetal() {
|
||||||
|
// Release Metal objects (ARC handles most of this automatically)
|
||||||
|
pipelineState = nullptr;
|
||||||
|
backBufferTexture = nullptr;
|
||||||
|
gameCanvasTexture = nullptr;
|
||||||
|
vertexBuffer = nullptr;
|
||||||
|
sampler = nullptr;
|
||||||
|
device = nullptr;
|
||||||
|
renderer = nullptr;
|
||||||
|
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Metal shader system cleaned up");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace metal
|
||||||
|
} // namespace shader
|
||||||
|
|
||||||
|
#endif // __APPLE__
|
||||||
483
source/fade.cpp
@@ -27,32 +27,40 @@ Fade::~Fade() {
|
|||||||
|
|
||||||
// Inicializa las variables
|
// Inicializa las variables
|
||||||
void Fade::init() {
|
void Fade::init() {
|
||||||
type_ = FadeType::CENTER;
|
type_ = Type::CENTER;
|
||||||
mode_ = FadeMode::OUT;
|
mode_ = Mode::OUT;
|
||||||
counter_ = 0;
|
counter_ = 0;
|
||||||
r_ = 0;
|
r_ = 0;
|
||||||
g_ = 0;
|
g_ = 0;
|
||||||
b_ = 0;
|
b_ = 0;
|
||||||
a_ = 0;
|
a_ = 0;
|
||||||
post_duration_ = 0;
|
post_duration_ = 0;
|
||||||
post_counter_ = 0;
|
post_start_time_ = 0;
|
||||||
pre_duration_ = 0;
|
pre_duration_ = 0;
|
||||||
pre_counter_ = 0;
|
pre_start_time_ = 0;
|
||||||
num_squares_width_ = param.fade.num_squares_width;
|
num_squares_width_ = param.fade.num_squares_width;
|
||||||
num_squares_height_ = param.fade.num_squares_height;
|
num_squares_height_ = param.fade.num_squares_height;
|
||||||
fade_random_squares_delay_ = param.fade.random_squares_delay;
|
random_squares_duration_ = param.fade.random_squares_duration_ms; // Usar como duración en ms
|
||||||
fade_random_squares_mult_ = param.fade.random_squares_mult;
|
square_transition_duration_ = random_squares_duration_ / 4; // 25% del tiempo total para la transición individual
|
||||||
|
random_squares_start_time_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resetea algunas variables para volver a hacer el fade sin perder ciertos parametros
|
// Resetea algunas variables para volver a hacer el fade sin perder ciertos parametros
|
||||||
void Fade::reset() {
|
void Fade::reset() {
|
||||||
state_ = FadeState::NOT_ENABLED;
|
state_ = State::NOT_ENABLED;
|
||||||
counter_ = 0;
|
counter_ = 0;
|
||||||
|
post_start_time_ = 0;
|
||||||
|
pre_start_time_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pinta una transición en pantalla
|
// Pinta una transición en pantalla
|
||||||
void Fade::render() {
|
void Fade::render() {
|
||||||
if (state_ != FadeState::NOT_ENABLED) {
|
if (state_ != State::NOT_ENABLED) {
|
||||||
|
// Para fade IN terminado, no renderizar (auto-desactivación visual)
|
||||||
|
if (state_ == State::FINISHED && mode_ == Mode::IN) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_RenderTexture(renderer_, backbuffer_, nullptr, nullptr);
|
SDL_RenderTexture(renderer_, backbuffer_, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,13 +68,13 @@ void Fade::render() {
|
|||||||
// Actualiza las variables internas
|
// Actualiza las variables internas
|
||||||
void Fade::update() {
|
void Fade::update() {
|
||||||
switch (state_) {
|
switch (state_) {
|
||||||
case FadeState::PRE:
|
case State::PRE:
|
||||||
updatePreState();
|
updatePreState();
|
||||||
break;
|
break;
|
||||||
case FadeState::FADING:
|
case State::FADING:
|
||||||
updateFadingState();
|
updateFadingState();
|
||||||
break;
|
break;
|
||||||
case FadeState::POST:
|
case State::POST:
|
||||||
updatePostState();
|
updatePostState();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -75,25 +83,36 @@ void Fade::update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Fade::updatePreState() {
|
void Fade::updatePreState() {
|
||||||
if (pre_counter_ == pre_duration_) {
|
// Sistema basado en tiempo únicamente
|
||||||
state_ = FadeState::FADING;
|
Uint32 elapsed_time = SDL_GetTicks() - pre_start_time_;
|
||||||
} else {
|
|
||||||
pre_counter_++;
|
if (elapsed_time >= static_cast<Uint32>(pre_duration_)) {
|
||||||
|
state_ = State::FADING;
|
||||||
|
// CRÍTICO: Reinicializar tiempo de inicio para tipos que usan random_squares_start_time_
|
||||||
|
if (type_ == Type::RANDOM_SQUARE2 || type_ == Type::DIAGONAL) {
|
||||||
|
random_squares_start_time_ = SDL_GetTicks();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fade::updateFadingState() {
|
void Fade::updateFadingState() {
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
case FadeType::FULLSCREEN:
|
case Type::FULLSCREEN:
|
||||||
updateFullscreenFade();
|
updateFullscreenFade();
|
||||||
break;
|
break;
|
||||||
case FadeType::CENTER:
|
case Type::CENTER:
|
||||||
updateCenterFade();
|
updateCenterFade();
|
||||||
break;
|
break;
|
||||||
case FadeType::RANDOM_SQUARE:
|
case Type::RANDOM_SQUARE:
|
||||||
updateRandomSquareFade();
|
updateRandomSquareFade();
|
||||||
break;
|
break;
|
||||||
case FadeType::VENETIAN:
|
case Type::RANDOM_SQUARE2:
|
||||||
|
updateRandomSquare2Fade();
|
||||||
|
break;
|
||||||
|
case Type::DIAGONAL:
|
||||||
|
updateDiagonalFade();
|
||||||
|
break;
|
||||||
|
case Type::VENETIAN:
|
||||||
updateVenetianFade();
|
updateVenetianFade();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -102,23 +121,36 @@ void Fade::updateFadingState() {
|
|||||||
counter_++;
|
counter_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Fade::changeToPostState() {
|
||||||
|
state_ = State::POST;
|
||||||
|
post_start_time_ = SDL_GetTicks();
|
||||||
|
}
|
||||||
|
|
||||||
void Fade::updatePostState() {
|
void Fade::updatePostState() {
|
||||||
if (post_counter_ == post_duration_) {
|
// Sistema basado en tiempo únicamente
|
||||||
state_ = FadeState::FINISHED;
|
Uint32 elapsed_time = SDL_GetTicks() - post_start_time_;
|
||||||
} else {
|
|
||||||
post_counter_++;
|
if (elapsed_time >= static_cast<Uint32>(post_duration_)) {
|
||||||
|
state_ = State::FINISHED;
|
||||||
}
|
}
|
||||||
cleanBackbuffer(r_, g_, b_, a_);
|
|
||||||
|
// Mantener el alpha final correcto para cada tipo de fade
|
||||||
|
Uint8 post_alpha = a_;
|
||||||
|
if (type_ == Type::RANDOM_SQUARE2 || type_ == Type::DIAGONAL) {
|
||||||
|
post_alpha = (mode_ == Mode::OUT) ? 255 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanBackbuffer(r_, g_, b_, post_alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fade::updateFullscreenFade() {
|
void Fade::updateFullscreenFade() {
|
||||||
// Modifica la transparencia
|
// Modifica la transparencia
|
||||||
a_ = mode_ == FadeMode::OUT ? std::min(counter_ * 4, 255) : 255 - std::min(counter_ * 4, 255);
|
a_ = mode_ == Mode::OUT ? std::min(counter_ * 4, 255) : 255 - std::min(counter_ * 4, 255);
|
||||||
SDL_SetTextureAlphaMod(backbuffer_, a_);
|
SDL_SetTextureAlphaMod(backbuffer_, a_);
|
||||||
|
|
||||||
// Comprueba si ha terminado
|
// Comprueba si ha terminado
|
||||||
if (counter_ >= 255 / 4) {
|
if (counter_ >= 255 / 4) {
|
||||||
state_ = FadeState::POST;
|
changeToPostState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,8 +159,8 @@ void Fade::updateCenterFade() {
|
|||||||
|
|
||||||
// Comprueba si ha terminado
|
// Comprueba si ha terminado
|
||||||
if ((counter_ * 4) > param.game.height) {
|
if ((counter_ * 4) > param.game.height) {
|
||||||
state_ = FadeState::POST;
|
|
||||||
a_ = 255;
|
a_ = 255;
|
||||||
|
changeToPostState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,20 +183,243 @@ void Fade::drawCenterFadeRectangles() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Fade::updateRandomSquareFade() {
|
void Fade::updateRandomSquareFade() {
|
||||||
if (counter_ % fade_random_squares_delay_ == 0) {
|
Uint32 elapsed_time = SDL_GetTicks() - random_squares_start_time_;
|
||||||
drawRandomSquares();
|
float progress = static_cast<float>(elapsed_time) / random_squares_duration_;
|
||||||
}
|
|
||||||
|
|
||||||
value_ = calculateValue(0, (num_squares_width_ * num_squares_height_), (counter_ * fade_random_squares_mult_ / fade_random_squares_delay_));
|
// Calcula cuántos cuadrados deberían estar activos
|
||||||
|
int total_squares = num_squares_width_ * num_squares_height_;
|
||||||
|
int active_squares = static_cast<int>(progress * total_squares);
|
||||||
|
active_squares = std::min(active_squares, total_squares);
|
||||||
|
|
||||||
|
// Dibuja los cuadrados activos
|
||||||
|
drawRandomSquares(active_squares);
|
||||||
|
|
||||||
|
value_ = calculateValue(0, total_squares, active_squares);
|
||||||
|
|
||||||
// Comprueba si ha terminado
|
// Comprueba si ha terminado
|
||||||
if (counter_ * fade_random_squares_mult_ / fade_random_squares_delay_ >=
|
if (elapsed_time >= static_cast<Uint32>(random_squares_duration_)) {
|
||||||
num_squares_width_ * num_squares_height_) {
|
changeToPostState();
|
||||||
state_ = FadeState::POST;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fade::drawRandomSquares() {
|
void Fade::updateRandomSquare2Fade() {
|
||||||
|
Uint32 elapsed_time = SDL_GetTicks() - random_squares_start_time_;
|
||||||
|
|
||||||
|
int total_squares = num_squares_width_ * num_squares_height_;
|
||||||
|
|
||||||
|
// Calcula el tiempo de activación: total - tiempo que necesitan los últimos cuadrados
|
||||||
|
int activation_time = random_squares_duration_ - square_transition_duration_;
|
||||||
|
activation_time = std::max(activation_time, square_transition_duration_); // Mínimo igual a la duración de transición
|
||||||
|
|
||||||
|
// Lógica diferente según el modo
|
||||||
|
int squares_to_activate = 0;
|
||||||
|
|
||||||
|
if (mode_ == Mode::OUT) {
|
||||||
|
// OUT: Activa cuadrados gradualmente
|
||||||
|
if (elapsed_time < static_cast<Uint32>(activation_time)) {
|
||||||
|
float activation_progress = static_cast<float>(elapsed_time) / activation_time;
|
||||||
|
squares_to_activate = static_cast<int>(activation_progress * total_squares);
|
||||||
|
} else {
|
||||||
|
squares_to_activate = total_squares; // Activar todos
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activa nuevos cuadrados y guarda su tiempo de activación
|
||||||
|
for (int i = 0; i < squares_to_activate && i < total_squares; ++i) {
|
||||||
|
if (square_age_[i] == -1) {
|
||||||
|
square_age_[i] = elapsed_time; // Guarda el tiempo de activación
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// IN: Todos los cuadrados empiezan activos desde el inicio
|
||||||
|
squares_to_activate = total_squares;
|
||||||
|
|
||||||
|
// Activa cuadrados gradualmente con tiempo de inicio escalonado
|
||||||
|
float activation_progress = static_cast<float>(elapsed_time) / activation_time;
|
||||||
|
int squares_starting_transition = static_cast<int>(activation_progress * total_squares);
|
||||||
|
|
||||||
|
// Asegurar que al menos 1 cuadrado se active desde el primer frame
|
||||||
|
squares_starting_transition = std::max(squares_starting_transition, 1);
|
||||||
|
squares_starting_transition = std::min(squares_starting_transition, total_squares);
|
||||||
|
|
||||||
|
for (int i = 0; i < squares_starting_transition; ++i) {
|
||||||
|
if (square_age_[i] == -1) {
|
||||||
|
square_age_[i] = elapsed_time; // Empieza la transición a transparente
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawRandomSquares2();
|
||||||
|
|
||||||
|
value_ = calculateValue(0, total_squares, squares_to_activate);
|
||||||
|
|
||||||
|
// Comprueba si ha terminado - todos los cuadrados han completado su transición
|
||||||
|
bool all_completed = (squares_to_activate >= total_squares);
|
||||||
|
if (all_completed) {
|
||||||
|
// Verificar que todos han completado su transición individual
|
||||||
|
for (int i = 0; i < total_squares; ++i) {
|
||||||
|
if (square_age_[i] >= 0) { // Cuadrado activado
|
||||||
|
Uint32 square_elapsed = elapsed_time - square_age_[i];
|
||||||
|
if (square_elapsed < static_cast<Uint32>(square_transition_duration_)) {
|
||||||
|
all_completed = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (all_completed) {
|
||||||
|
// Pintar textura final: OUT opaca, IN transparente
|
||||||
|
Uint8 final_alpha = (mode_ == Mode::OUT) ? 255 : 0;
|
||||||
|
cleanBackbuffer(r_, g_, b_, final_alpha);
|
||||||
|
changeToPostState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fade::updateDiagonalFade() {
|
||||||
|
Uint32 elapsed_time = SDL_GetTicks() - random_squares_start_time_;
|
||||||
|
|
||||||
|
int total_squares = num_squares_width_ * num_squares_height_;
|
||||||
|
|
||||||
|
// Calcula el tiempo de activación: total - tiempo que necesitan los últimos cuadrados
|
||||||
|
int activation_time = random_squares_duration_ - square_transition_duration_;
|
||||||
|
activation_time = std::max(activation_time, square_transition_duration_);
|
||||||
|
|
||||||
|
// Calcula cuántas diagonales deberían estar activas
|
||||||
|
int max_diagonal = num_squares_width_ + num_squares_height_ - 1; // Número total de diagonales
|
||||||
|
int active_diagonals = 0;
|
||||||
|
|
||||||
|
if (mode_ == Mode::OUT) {
|
||||||
|
// OUT: Activa diagonales gradualmente desde esquina superior izquierda
|
||||||
|
if (elapsed_time < static_cast<Uint32>(activation_time)) {
|
||||||
|
float activation_progress = static_cast<float>(elapsed_time) / activation_time;
|
||||||
|
active_diagonals = static_cast<int>(activation_progress * max_diagonal);
|
||||||
|
} else {
|
||||||
|
active_diagonals = max_diagonal; // Activar todas
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activa cuadrados por diagonales
|
||||||
|
for (int diagonal = 0; diagonal < active_diagonals; ++diagonal) {
|
||||||
|
activateDiagonal(diagonal, elapsed_time);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// IN: Todas las diagonales empiezan activas, van desapareciendo
|
||||||
|
active_diagonals = max_diagonal;
|
||||||
|
|
||||||
|
// Activa diagonales gradualmente para transición
|
||||||
|
if (elapsed_time < static_cast<Uint32>(activation_time)) {
|
||||||
|
float activation_progress = static_cast<float>(elapsed_time) / activation_time;
|
||||||
|
int diagonals_starting_transition = static_cast<int>(activation_progress * max_diagonal);
|
||||||
|
|
||||||
|
for (int diagonal = 0; diagonal < diagonals_starting_transition; ++diagonal) {
|
||||||
|
activateDiagonal(diagonal, elapsed_time);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Activar transición en todas las diagonales restantes
|
||||||
|
for (int diagonal = 0; diagonal < max_diagonal; ++diagonal) {
|
||||||
|
activateDiagonal(diagonal, elapsed_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawDiagonal();
|
||||||
|
|
||||||
|
value_ = calculateValue(0, total_squares, active_diagonals * (total_squares / max_diagonal));
|
||||||
|
|
||||||
|
// Comprueba si ha terminado - todas las diagonales activadas y último cuadrado completó transición
|
||||||
|
bool all_completed = (active_diagonals >= max_diagonal);
|
||||||
|
if (all_completed) {
|
||||||
|
// Verificar que todos han completado su transición individual
|
||||||
|
for (int i = 0; i < total_squares; ++i) {
|
||||||
|
if (square_age_[i] >= 0) { // Cuadrado activado
|
||||||
|
Uint32 square_elapsed = elapsed_time - square_age_[i];
|
||||||
|
if (square_elapsed < static_cast<Uint32>(square_transition_duration_)) {
|
||||||
|
all_completed = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (all_completed) {
|
||||||
|
// Pintar textura final: OUT opaca, IN transparente
|
||||||
|
Uint8 final_alpha = (mode_ == Mode::OUT) ? 255 : 0;
|
||||||
|
cleanBackbuffer(r_, g_, b_, final_alpha);
|
||||||
|
changeToPostState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fade::activateDiagonal(int diagonal_index, Uint32 current_time) {
|
||||||
|
// Para cada diagonal, activamos los cuadrados que pertenecen a esa diagonal
|
||||||
|
// Diagonal 0: (0,0)
|
||||||
|
// Diagonal 1: (1,0), (0,1)
|
||||||
|
// Diagonal 2: (2,0), (1,1), (0,2)
|
||||||
|
// etc.
|
||||||
|
|
||||||
|
for (int x = 0; x < num_squares_width_; ++x) {
|
||||||
|
int y = diagonal_index - x;
|
||||||
|
|
||||||
|
// Verificar que y está dentro de los límites
|
||||||
|
if (y >= 0 && y < num_squares_height_) {
|
||||||
|
// Convertir coordenadas (x,y) a índice en el vector
|
||||||
|
int index = y * num_squares_width_ + x;
|
||||||
|
|
||||||
|
if (index >= 0 && index < static_cast<int>(square_age_.size())) {
|
||||||
|
if (square_age_[index] == -1) {
|
||||||
|
square_age_[index] = current_time; // Guarda el tiempo de activación
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fade::drawDiagonal() {
|
||||||
|
auto *temp = SDL_GetRenderTarget(renderer_);
|
||||||
|
SDL_SetRenderTarget(renderer_, backbuffer_);
|
||||||
|
|
||||||
|
// CRÍTICO: Limpiar la textura antes de dibujar
|
||||||
|
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
|
||||||
|
SDL_RenderClear(renderer_);
|
||||||
|
|
||||||
|
SDL_BlendMode blend_mode;
|
||||||
|
SDL_GetRenderDrawBlendMode(renderer_, &blend_mode);
|
||||||
|
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND); // Usar BLEND para alpha
|
||||||
|
|
||||||
|
Uint32 current_time = SDL_GetTicks() - random_squares_start_time_;
|
||||||
|
|
||||||
|
// Lógica unificada: sobre textura transparente, pintar cuadrados según su estado
|
||||||
|
for (size_t i = 0; i < square_.size(); ++i) {
|
||||||
|
Uint8 current_alpha = 0;
|
||||||
|
|
||||||
|
if (square_age_[i] == -1) {
|
||||||
|
// Cuadrado no activado
|
||||||
|
if (mode_ == Mode::OUT) {
|
||||||
|
current_alpha = 0; // OUT: transparente si no activado
|
||||||
|
} else {
|
||||||
|
current_alpha = a_; // IN: opaco si no activado
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Cuadrado activado - calculamos progreso
|
||||||
|
Uint32 square_elapsed = current_time - square_age_[i];
|
||||||
|
float progress = std::min(static_cast<float>(square_elapsed) / square_transition_duration_, 1.0f);
|
||||||
|
|
||||||
|
if (mode_ == Mode::OUT) {
|
||||||
|
current_alpha = static_cast<Uint8>(progress * a_); // 0 → 255
|
||||||
|
} else {
|
||||||
|
current_alpha = static_cast<Uint8>((1.0f - progress) * a_); // 255 → 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_alpha > 0) {
|
||||||
|
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, current_alpha);
|
||||||
|
SDL_RenderFillRect(renderer_, &square_[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_SetRenderDrawBlendMode(renderer_, blend_mode);
|
||||||
|
SDL_SetRenderTarget(renderer_, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fade::drawRandomSquares(int active_count) {
|
||||||
auto *temp = SDL_GetRenderTarget(renderer_);
|
auto *temp = SDL_GetRenderTarget(renderer_);
|
||||||
SDL_SetRenderTarget(renderer_, backbuffer_);
|
SDL_SetRenderTarget(renderer_, backbuffer_);
|
||||||
|
|
||||||
@@ -173,13 +428,56 @@ void Fade::drawRandomSquares() {
|
|||||||
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_);
|
||||||
|
|
||||||
const int INDEX = std::min(counter_ / fade_random_squares_delay_,
|
// Dibuja solo los cuadrados activos
|
||||||
(num_squares_width_ * num_squares_height_) - 1);
|
for (int i = 0; i < active_count && i < static_cast<int>(square_.size()); ++i) {
|
||||||
|
SDL_RenderFillRect(renderer_, &square_[i]);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < fade_random_squares_mult_; ++i) {
|
SDL_SetRenderDrawBlendMode(renderer_, blend_mode);
|
||||||
const int INDEX2 = std::min(INDEX * fade_random_squares_mult_ + i,
|
SDL_SetRenderTarget(renderer_, temp);
|
||||||
static_cast<int>(square_.size()) - 1);
|
}
|
||||||
SDL_RenderFillRect(renderer_, &square_[INDEX2]);
|
|
||||||
|
void Fade::drawRandomSquares2() {
|
||||||
|
auto *temp = SDL_GetRenderTarget(renderer_);
|
||||||
|
SDL_SetRenderTarget(renderer_, backbuffer_);
|
||||||
|
|
||||||
|
// CRÍTICO: Limpiar la textura antes de dibujar
|
||||||
|
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, 0);
|
||||||
|
SDL_RenderClear(renderer_);
|
||||||
|
|
||||||
|
SDL_BlendMode blend_mode;
|
||||||
|
SDL_GetRenderDrawBlendMode(renderer_, &blend_mode);
|
||||||
|
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND); // Usar BLEND para alpha
|
||||||
|
|
||||||
|
Uint32 current_time = SDL_GetTicks() - random_squares_start_time_;
|
||||||
|
|
||||||
|
// Lógica unificada: sobre textura transparente, pintar cuadrados según su estado
|
||||||
|
for (size_t i = 0; i < square_.size(); ++i) {
|
||||||
|
Uint8 current_alpha = 0;
|
||||||
|
|
||||||
|
if (square_age_[i] == -1) {
|
||||||
|
// Cuadrado no activado
|
||||||
|
if (mode_ == Mode::OUT) {
|
||||||
|
current_alpha = 0; // OUT: transparente si no activado
|
||||||
|
} else {
|
||||||
|
current_alpha = a_; // IN: opaco si no activado
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Cuadrado activado - calculamos progreso
|
||||||
|
Uint32 square_elapsed = current_time - square_age_[i];
|
||||||
|
float progress = std::min(static_cast<float>(square_elapsed) / square_transition_duration_, 1.0f);
|
||||||
|
|
||||||
|
if (mode_ == Mode::OUT) {
|
||||||
|
current_alpha = static_cast<Uint8>(progress * a_); // 0 → 255
|
||||||
|
} else {
|
||||||
|
current_alpha = static_cast<Uint8>((1.0f - progress) * a_); // 255 → 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_alpha > 0) {
|
||||||
|
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, current_alpha);
|
||||||
|
SDL_RenderFillRect(renderer_, &square_[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_SetRenderDrawBlendMode(renderer_, blend_mode);
|
SDL_SetRenderDrawBlendMode(renderer_, blend_mode);
|
||||||
@@ -192,7 +490,7 @@ void Fade::updateVenetianFade() {
|
|||||||
updateVenetianRectangles();
|
updateVenetianRectangles();
|
||||||
calculateVenetianProgress();
|
calculateVenetianProgress();
|
||||||
} else {
|
} else {
|
||||||
state_ = FadeState::POST;
|
changeToPostState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,31 +531,30 @@ void Fade::calculateVenetianProgress() {
|
|||||||
// Activa el fade
|
// Activa el fade
|
||||||
void Fade::activate() {
|
void Fade::activate() {
|
||||||
// Si ya está habilitado, no hay que volverlo a activar
|
// Si ya está habilitado, no hay que volverlo a activar
|
||||||
if (state_ != FadeState::NOT_ENABLED) {
|
if (state_ != State::NOT_ENABLED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
state_ = FadeState::PRE;
|
state_ = State::PRE;
|
||||||
counter_ = 0;
|
counter_ = 0;
|
||||||
post_counter_ = 0;
|
pre_start_time_ = SDL_GetTicks();
|
||||||
pre_counter_ = 0;
|
|
||||||
|
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
case FadeType::FULLSCREEN: {
|
case Type::FULLSCREEN: {
|
||||||
// Pinta el backbuffer_ de color sólido
|
// Pinta el backbuffer_ de color sólido
|
||||||
cleanBackbuffer(r_, g_, b_, 255);
|
cleanBackbuffer(r_, g_, b_, 255);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case FadeType::CENTER: {
|
case Type::CENTER: {
|
||||||
rect1_ = {0, 0, param.game.width, 0};
|
rect1_ = {.x = 0, .y = 0, .w = param.game.width, .h = 0};
|
||||||
rect2_ = {0, 0, param.game.width, 0};
|
rect2_ = {.x = 0, .y = 0, .w = param.game.width, .h = 0};
|
||||||
a_ = 64;
|
a_ = 64;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case FadeType::RANDOM_SQUARE: {
|
case Type::RANDOM_SQUARE: {
|
||||||
rect1_ = {0, 0, static_cast<float>(param.game.width / num_squares_width_), static_cast<float>(param.game.height / num_squares_height_)};
|
rect1_ = {.x = 0, .y = 0, .w = static_cast<float>(param.game.width / num_squares_width_), .h = static_cast<float>(param.game.height / num_squares_height_)};
|
||||||
square_.clear();
|
square_.clear();
|
||||||
|
|
||||||
// Añade los cuadrados al vector
|
// Añade los cuadrados al vector
|
||||||
@@ -278,26 +575,96 @@ void Fade::activate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Limpia la textura
|
// Limpia la textura
|
||||||
a_ = mode_ == FadeMode::OUT ? 0 : 255;
|
a_ = mode_ == Mode::OUT ? 0 : 255;
|
||||||
cleanBackbuffer(r_, g_, b_, a_);
|
cleanBackbuffer(r_, g_, b_, a_);
|
||||||
|
|
||||||
// Deja el color listo para usar
|
// Deja el color listo para usar
|
||||||
a_ = mode_ == FadeMode::OUT ? 255 : 0;
|
a_ = mode_ == Mode::OUT ? 255 : 0;
|
||||||
|
|
||||||
|
// Inicializa el tiempo de inicio
|
||||||
|
random_squares_start_time_ = SDL_GetTicks();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case FadeType::VENETIAN: {
|
case Type::RANDOM_SQUARE2: {
|
||||||
|
rect1_ = {.x = 0, .y = 0, .w = static_cast<float>(param.game.width / num_squares_width_), .h = static_cast<float>(param.game.height / num_squares_height_)};
|
||||||
|
square_.clear();
|
||||||
|
square_age_.clear();
|
||||||
|
|
||||||
|
// Añade los cuadrados al vector
|
||||||
|
for (int i = 0; i < num_squares_width_ * num_squares_height_; ++i) {
|
||||||
|
rect1_.x = (i % num_squares_width_) * rect1_.w;
|
||||||
|
rect1_.y = (i / num_squares_width_) * rect1_.h;
|
||||||
|
square_.push_back(rect1_);
|
||||||
|
square_age_.push_back(-1); // -1 indica cuadrado no activado aún
|
||||||
|
}
|
||||||
|
|
||||||
|
// Desordena el vector de cuadrados y edades
|
||||||
|
auto num = num_squares_width_ * num_squares_height_;
|
||||||
|
while (num > 1) {
|
||||||
|
auto num_arreu = rand() % num;
|
||||||
|
SDL_FRect temp_rect = square_[num_arreu];
|
||||||
|
int temp_age = square_age_[num_arreu];
|
||||||
|
square_[num_arreu] = square_[num - 1];
|
||||||
|
square_age_[num_arreu] = square_age_[num - 1];
|
||||||
|
square_[num - 1] = temp_rect;
|
||||||
|
square_age_[num - 1] = temp_age;
|
||||||
|
num--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Textura inicial: OUT transparente, IN opaca
|
||||||
|
Uint8 initial_alpha = (mode_ == Mode::OUT) ? 0 : 255;
|
||||||
|
cleanBackbuffer(r_, g_, b_, initial_alpha);
|
||||||
|
|
||||||
|
// Deja el color listo para usar (alpha target para los cuadrados)
|
||||||
|
a_ = 255; // Siempre usar 255 como alpha target
|
||||||
|
|
||||||
|
// Inicializa el tiempo de inicio y recalcula la duración de transición
|
||||||
|
random_squares_start_time_ = SDL_GetTicks();
|
||||||
|
square_transition_duration_ = std::max(random_squares_duration_ / 4, 100); // Mínimo 100ms
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Type::DIAGONAL: {
|
||||||
|
rect1_ = {.x = 0, .y = 0, .w = static_cast<float>(param.game.width / num_squares_width_), .h = static_cast<float>(param.game.height / num_squares_height_)};
|
||||||
|
square_.clear();
|
||||||
|
square_age_.clear();
|
||||||
|
|
||||||
|
// Añade los cuadrados al vector en orden (sin desordenar)
|
||||||
|
for (int i = 0; i < num_squares_width_ * num_squares_height_; ++i) {
|
||||||
|
rect1_.x = (i % num_squares_width_) * rect1_.w;
|
||||||
|
rect1_.y = (i / num_squares_width_) * rect1_.h;
|
||||||
|
square_.push_back(rect1_);
|
||||||
|
square_age_.push_back(-1); // -1 indica cuadrado no activado aún
|
||||||
|
}
|
||||||
|
|
||||||
|
// Textura inicial: OUT transparente, IN opaca
|
||||||
|
Uint8 initial_alpha = (mode_ == Mode::OUT) ? 0 : 255;
|
||||||
|
cleanBackbuffer(r_, g_, b_, initial_alpha);
|
||||||
|
|
||||||
|
// Deja el color listo para usar (alpha target para los cuadrados)
|
||||||
|
a_ = 255; // Siempre usar 255 como alpha target
|
||||||
|
|
||||||
|
// Inicializa el tiempo de inicio y recalcula la duración de transición
|
||||||
|
random_squares_start_time_ = SDL_GetTicks();
|
||||||
|
square_transition_duration_ = std::max(random_squares_duration_ / 4, 100); // Mínimo 100ms
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Type::VENETIAN: {
|
||||||
// Limpia la textura
|
// Limpia la textura
|
||||||
a_ = mode_ == FadeMode::OUT ? 0 : 255;
|
a_ = mode_ == Mode::OUT ? 0 : 255;
|
||||||
cleanBackbuffer(r_, g_, b_, a_);
|
cleanBackbuffer(r_, g_, b_, a_);
|
||||||
|
|
||||||
// Deja el color listo para usar
|
// Deja el color listo para usar
|
||||||
a_ = mode_ == FadeMode::OUT ? 255 : 0;
|
a_ = mode_ == Mode::OUT ? 255 : 0;
|
||||||
|
|
||||||
// Añade los cuadrados al vector
|
// Añade los cuadrados al vector
|
||||||
square_.clear();
|
square_.clear();
|
||||||
rect1_ = {0, 0, param.game.width, 0};
|
rect1_ = {.x = 0, .y = 0, .w = param.game.width, .h = 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) {
|
||||||
|
|||||||
115
source/fade.h
@@ -6,31 +6,32 @@
|
|||||||
|
|
||||||
struct Color;
|
struct Color;
|
||||||
|
|
||||||
// Tipos de fundido
|
// --- Clase Fade: gestor de transiciones de fundido ---
|
||||||
enum class FadeType : Uint8 {
|
|
||||||
FULLSCREEN = 0,
|
|
||||||
CENTER = 1,
|
|
||||||
RANDOM_SQUARE = 2,
|
|
||||||
VENETIAN = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Modos de fundido
|
|
||||||
enum class FadeMode : Uint8 {
|
|
||||||
IN = 0,
|
|
||||||
OUT = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Estados del objeto
|
|
||||||
enum class FadeState : Uint8 {
|
|
||||||
NOT_ENABLED = 0,
|
|
||||||
PRE = 1,
|
|
||||||
FADING = 2,
|
|
||||||
POST = 3,
|
|
||||||
FINISHED = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
class Fade {
|
class Fade {
|
||||||
public:
|
public:
|
||||||
|
// --- Enums ---
|
||||||
|
enum class Type : Uint8 {
|
||||||
|
FULLSCREEN = 0, // Fundido de pantalla completa
|
||||||
|
CENTER = 1, // Fundido desde el centro
|
||||||
|
RANDOM_SQUARE = 2, // Fundido con cuadrados aleatorios
|
||||||
|
RANDOM_SQUARE2 = 3, // Fundido con cuadrados aleatorios (variante 2)
|
||||||
|
DIAGONAL = 4, // Fundido diagonal desde esquina superior izquierda
|
||||||
|
VENETIAN = 5, // Fundido tipo persiana veneciana
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Mode : Uint8 {
|
||||||
|
IN = 0, // Fundido de entrada
|
||||||
|
OUT = 1, // Fundido de salida
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class State : Uint8 {
|
||||||
|
NOT_ENABLED = 0, // No activado
|
||||||
|
PRE = 1, // Estado previo
|
||||||
|
FADING = 2, // Fundiendo
|
||||||
|
POST = 3, // Estado posterior
|
||||||
|
FINISHED = 4, // Finalizado
|
||||||
|
};
|
||||||
|
|
||||||
// --- Constructores y destructor ---
|
// --- Constructores y destructor ---
|
||||||
Fade();
|
Fade();
|
||||||
~Fade();
|
~Fade();
|
||||||
@@ -42,17 +43,17 @@ class Fade {
|
|||||||
void activate(); // Activa el fade
|
void activate(); // Activa el fade
|
||||||
|
|
||||||
// --- Configuración ---
|
// --- Configuración ---
|
||||||
void setColor(Uint8 r, Uint8 g, Uint8 b);
|
void setColor(Uint8 r, Uint8 g, Uint8 b); // Establece el color RGB del fade
|
||||||
void setColor(Color color);
|
void setColor(Color color); // Establece el color del fade
|
||||||
void setType(FadeType type) { type_ = type; }
|
void setType(Type type) { type_ = type; } // Establece el tipo de fade
|
||||||
void setMode(FadeMode mode) { mode_ = mode; }
|
void setMode(Mode mode) { mode_ = mode; } // Establece el modo de fade
|
||||||
void setPostDuration(int value) { post_duration_ = value; }
|
void setPostDuration(int value) { post_duration_ = value; } // Duración posterior al fade en milisegundos
|
||||||
void setPreDuration(int value) { pre_duration_ = value; }
|
void setPreDuration(int value) { pre_duration_ = value; } // Duración previa al fade en milisegundos
|
||||||
|
|
||||||
// --- Getters ---
|
// --- Getters ---
|
||||||
[[nodiscard]] auto getValue() const -> int { return value_; }
|
[[nodiscard]] auto getValue() const -> int { return value_; }
|
||||||
[[nodiscard]] auto isEnabled() const -> bool { return state_ != FadeState::NOT_ENABLED; }
|
[[nodiscard]] auto isEnabled() const -> bool { return state_ != State::NOT_ENABLED; }
|
||||||
[[nodiscard]] auto hasEnded() const -> bool { return state_ == FadeState::FINISHED; }
|
[[nodiscard]] auto hasEnded() const -> bool { return state_ == State::FINISHED; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Objetos y punteros ---
|
// --- Objetos y punteros ---
|
||||||
@@ -60,28 +61,24 @@ class Fade {
|
|||||||
SDL_Texture *backbuffer_; // Backbuffer para efectos
|
SDL_Texture *backbuffer_; // Backbuffer para efectos
|
||||||
|
|
||||||
// --- Variables de estado ---
|
// --- Variables de estado ---
|
||||||
FadeType type_; // Tipo de fade
|
std::vector<SDL_FRect> square_; // Vector de cuadrados
|
||||||
FadeMode mode_; // Modo de fade
|
std::vector<int> square_age_; // Edad de cada cuadrado (para RANDOM_SQUARE2)
|
||||||
FadeState state_ = FadeState::NOT_ENABLED; // Estado actual
|
SDL_FRect rect1_, rect2_; // Rectángulos para efectos
|
||||||
Uint16 counter_; // Contador interno
|
Type type_; // Tipo de fade
|
||||||
|
Mode mode_; // Modo de fade
|
||||||
// --- Parámetros de color y geometría ---
|
State state_ = State::NOT_ENABLED; // Estado actual
|
||||||
Uint8 r_, g_, b_, a_; // Color del fade
|
Uint16 counter_; // Contador interno
|
||||||
SDL_FRect rect1_, rect2_; // Rectángulos para efectos
|
Uint8 r_, g_, b_, a_; // Color del fade (RGBA)
|
||||||
|
int num_squares_width_; // Cuadrados en horizontal
|
||||||
// --- Parámetros para RANDOM_SQUARE ---
|
int num_squares_height_; // Cuadrados en vertical
|
||||||
int num_squares_width_; // Cuadrados en horizontal
|
Uint32 random_squares_start_time_; // Tiempo de inicio del fade de cuadrados
|
||||||
int num_squares_height_; // Cuadrados en vertical
|
int random_squares_duration_; // Duración total en milisegundos
|
||||||
std::vector<SDL_FRect> square_; // Vector de cuadrados
|
int square_transition_duration_; // Duración de transición de cada cuadrado en ms
|
||||||
int fade_random_squares_delay_; // Delay entre cuadrados
|
int post_duration_ = 0; // Duración posterior en milisegundos
|
||||||
int fade_random_squares_mult_; // Cuadrados por paso
|
Uint32 post_start_time_ = 0; // Tiempo de inicio del estado POST
|
||||||
|
int pre_duration_ = 0; // Duración previa en milisegundos
|
||||||
// --- Temporizadores ---
|
Uint32 pre_start_time_ = 0; // Tiempo de inicio del estado PRE
|
||||||
int post_duration_ = 0, post_counter_ = 0;
|
int value_ = 0; // Estado del fade (0-100)
|
||||||
int pre_duration_ = 0, pre_counter_ = 0;
|
|
||||||
|
|
||||||
// --- Valor de progreso ---
|
|
||||||
int value_ = 0; // Estado del fade (0-100)
|
|
||||||
|
|
||||||
// --- Inicialización y limpieza ---
|
// --- Inicialización y limpieza ---
|
||||||
void init(); // Inicializa variables
|
void init(); // Inicializa variables
|
||||||
@@ -94,17 +91,23 @@ class Fade {
|
|||||||
void updatePreState(); // Actualiza el estado previo al fade
|
void updatePreState(); // Actualiza el estado previo al fade
|
||||||
void updateFadingState(); // Actualiza el estado durante el fade
|
void updateFadingState(); // Actualiza el estado durante el fade
|
||||||
void updatePostState(); // Actualiza el estado posterior al fade
|
void updatePostState(); // Actualiza el estado posterior al fade
|
||||||
|
void changeToPostState(); // Cambia al estado POST e inicializa el tiempo
|
||||||
|
|
||||||
// --- Efectos de fundido (fade) ---
|
// --- Efectos de fundido (fade) ---
|
||||||
void updateFullscreenFade(); // Actualiza el fundido de pantalla completa
|
void updateFullscreenFade(); // Actualiza el fundido de pantalla completa
|
||||||
void updateCenterFade(); // Actualiza el fundido desde el centro
|
void updateCenterFade(); // Actualiza el fundido desde el centro
|
||||||
void updateRandomSquareFade(); // Actualiza el fundido con cuadrados aleatorios
|
void updateRandomSquareFade(); // Actualiza el fundido con cuadrados aleatorios
|
||||||
|
void updateRandomSquare2Fade(); // Actualiza el fundido con cuadrados aleatorios (variante 2)
|
||||||
|
void updateDiagonalFade(); // Actualiza el fundido diagonal
|
||||||
void updateVenetianFade(); // Actualiza el fundido tipo persiana veneciana
|
void updateVenetianFade(); // Actualiza el fundido tipo persiana veneciana
|
||||||
void updateVenetianRectangles(); // Actualiza los rectángulos del efecto veneciano
|
void updateVenetianRectangles(); // Actualiza los rectángulos del efecto veneciano
|
||||||
void calculateVenetianProgress(); // Calcula el progreso del efecto veneciano
|
void calculateVenetianProgress(); // Calcula el progreso del efecto veneciano
|
||||||
|
|
||||||
// --- Dibujo de efectos visuales ---
|
// --- Dibujo de efectos visuales ---
|
||||||
void drawCenterFadeRectangles(); // Dibuja los rectángulos del fundido central
|
void drawCenterFadeRectangles(); // Dibuja los rectángulos del fundido central
|
||||||
void drawRandomSquares(); // Dibuja los cuadrados aleatorios del fundido
|
void drawRandomSquares(int active_count = -1); // Dibuja los cuadrados aleatorios del fundido
|
||||||
void drawVenetianBlinds(); // Dibuja las persianas venecianas del fundido
|
void drawRandomSquares2(); // Dibuja los cuadrados con transición de color (RANDOM_SQUARE2)
|
||||||
|
void drawDiagonal(); // Dibuja los cuadrados con patrón diagonal
|
||||||
|
void activateDiagonal(int diagonal_index, Uint32 current_time); // Activa una diagonal específica
|
||||||
|
void drawVenetianBlinds(); // Dibuja las persianas venecianas del fundido
|
||||||
};
|
};
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
constexpr int ZOOM_FACTOR = 5;
|
constexpr int ZOOM_FACTOR = 5;
|
||||||
constexpr int FLASH_DELAY = 3;
|
constexpr int FLASH_DELAY = 3;
|
||||||
constexpr int FLASH_LENGHT = FLASH_DELAY + 3;
|
constexpr int FLASH_LENGTH = FLASH_DELAY + 3;
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
GameLogo::GameLogo(int x, int y)
|
GameLogo::GameLogo(int x, int y)
|
||||||
@@ -34,7 +34,7 @@ GameLogo::GameLogo(int x, int y)
|
|||||||
|
|
||||||
// Inicializa las variables
|
// Inicializa las variables
|
||||||
void GameLogo::init() {
|
void GameLogo::init() {
|
||||||
const auto XP = x_ - coffee_texture_->getWidth() / 2;
|
const auto XP = x_ - (coffee_texture_->getWidth() / 2);
|
||||||
const auto DESP = getInitialVerticalDesp();
|
const auto DESP = getInitialVerticalDesp();
|
||||||
|
|
||||||
// Configura texturas
|
// Configura texturas
|
||||||
@@ -236,7 +236,7 @@ void GameLogo::finishArcadeEditionMoving() {
|
|||||||
|
|
||||||
void GameLogo::playTitleEffects() {
|
void GameLogo::playTitleEffects() {
|
||||||
Audio::get()->playSound("title.wav");
|
Audio::get()->playSound("title.wav");
|
||||||
Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGHT, FLASH_DELAY);
|
Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGTH, FLASH_DELAY);
|
||||||
Screen::get()->shake();
|
Screen::get()->shake();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
// Clase GameLogo
|
// --- Clase GameLogo: gestor del logo del juego ---
|
||||||
class GameLogo {
|
class GameLogo {
|
||||||
public:
|
public:
|
||||||
// --- Constructores y destructor ---
|
// --- Constructores y destructor ---
|
||||||
@@ -24,30 +24,36 @@ class GameLogo {
|
|||||||
[[nodiscard]] auto hasFinished() const -> bool; // Indica si ha terminado la animación
|
[[nodiscard]] auto hasFinished() const -> bool; // Indica si ha terminado la animación
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Tipos internos ---
|
// --- Enums ---
|
||||||
enum class Status {
|
enum class Status {
|
||||||
DISABLED,
|
DISABLED, // Deshabilitado
|
||||||
MOVING,
|
MOVING, // En movimiento
|
||||||
SHAKING,
|
SHAKING, // Temblando
|
||||||
FINISHED,
|
FINISHED, // Terminado
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --- Estructuras privadas ---
|
||||||
struct Shake {
|
struct Shake {
|
||||||
int desp = 1; // 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 = 2; // Retraso entre cada desplazamiento de la pantalla al agitarse
|
int delay = 2; // Retraso entre cada desplazamiento de la pantalla al agitarse
|
||||||
int lenght = 8; // Cantidad de desplazamientos a realizar
|
int length = 8; // Cantidad de desplazamientos a realizar
|
||||||
int remaining = lenght; // Cantidad de desplazamientos pendientes a realizar
|
int remaining = length; // Cantidad de desplazamientos pendientes a realizar
|
||||||
int counter = delay; // Contador para el retraso
|
int counter = delay; // Contador para el retraso
|
||||||
int origin = 0; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
|
int origin = 0; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
|
||||||
|
|
||||||
Shake() = default;
|
Shake() = default;
|
||||||
Shake(int d, int de, int l, int o)
|
Shake(int d, int de, int l, int o)
|
||||||
: desp(d), delay(de), lenght(l), remaining(l), counter(de), origin(o) {}
|
: desp(d),
|
||||||
|
delay(de),
|
||||||
|
length(l),
|
||||||
|
remaining(l),
|
||||||
|
counter(de),
|
||||||
|
origin(o) {}
|
||||||
|
|
||||||
void init(int d, int de, int l, int o) {
|
void init(int d, int de, int l, int o) {
|
||||||
desp = d;
|
desp = d;
|
||||||
delay = de;
|
delay = de;
|
||||||
lenght = l;
|
length = l;
|
||||||
remaining = l;
|
remaining = l;
|
||||||
counter = de;
|
counter = de;
|
||||||
origin = o;
|
origin = o;
|
||||||
@@ -67,14 +73,13 @@ class GameLogo {
|
|||||||
std::unique_ptr<Sprite> arcade_edition_sprite_; // Sprite de "Arcade Edition"
|
std::unique_ptr<Sprite> arcade_edition_sprite_; // Sprite de "Arcade Edition"
|
||||||
|
|
||||||
// --- Variables de estado ---
|
// --- Variables de estado ---
|
||||||
float x_; // Posición X del logo
|
Shake shake_; // Efecto de agitación
|
||||||
float y_; // Posición Y del logo
|
|
||||||
float zoom_ = 1.0F; // Zoom aplicado al texto "ARCADE EDITION"
|
|
||||||
int post_finished_counter_ = 1; // Contador final tras animaciones
|
|
||||||
|
|
||||||
Status coffee_crisis_status_ = Status::DISABLED; // Estado de "COFFEE CRISIS"
|
Status coffee_crisis_status_ = Status::DISABLED; // Estado de "COFFEE CRISIS"
|
||||||
Status arcade_edition_status_ = Status::DISABLED; // Estado de "ARCADE EDITION"
|
Status arcade_edition_status_ = Status::DISABLED; // Estado de "ARCADE EDITION"
|
||||||
Shake shake_; // Efecto de agitación
|
float x_; // Posición X del logo
|
||||||
|
float y_; // Posición Y del logo
|
||||||
|
float zoom_ = 1.0F; // Zoom aplicado al texto "ARCADE EDITION"
|
||||||
|
int post_finished_counter_ = 1; // Contador final tras animaciones
|
||||||
|
|
||||||
// --- Inicialización ---
|
// --- Inicialización ---
|
||||||
void init(); // Inicializa las variables
|
void init(); // Inicializa las variables
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "external/json.hpp"
|
#include "external/json.hpp"
|
||||||
#include "input_types.h" // Solo incluimos los tipos compartidos
|
#include "input_types.h" // Solo incluimos los tipos compartidos
|
||||||
|
|
||||||
|
// --- Estructuras ---
|
||||||
struct GamepadConfig {
|
struct GamepadConfig {
|
||||||
std::string name; // Nombre del dispositivo
|
std::string name; // Nombre del dispositivo
|
||||||
std::string path; // Ruta física del dispositivo
|
std::string path; // Ruta física del dispositivo
|
||||||
@@ -29,12 +30,14 @@ struct GamepadConfig {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using GamepadConfigs = std::vector<GamepadConfig>;
|
// --- Tipos ---
|
||||||
|
using GamepadConfigs = std::vector<GamepadConfig>; // Vector de configuraciones de gamepad
|
||||||
|
|
||||||
|
// --- Clase GamepadConfigManager: gestor de configuraciones de gamepad ---
|
||||||
class GamepadConfigManager {
|
class GamepadConfigManager {
|
||||||
public:
|
public:
|
||||||
// Escribir vector de GamepadConfig a archivo JSON
|
// --- Métodos estáticos ---
|
||||||
static auto writeToJson(const GamepadConfigs& configs, const std::string& filename) -> bool {
|
static auto writeToJson(const GamepadConfigs& configs, const std::string& filename) -> bool { // Escribir configuraciones a JSON
|
||||||
try {
|
try {
|
||||||
nlohmann::json j;
|
nlohmann::json j;
|
||||||
j["gamepads"] = nlohmann::json::array();
|
j["gamepads"] = nlohmann::json::array();
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
// --- Namespace GlobalEvents: maneja eventos globales del juego ---
|
||||||
namespace GlobalEvents {
|
namespace GlobalEvents {
|
||||||
// Comprueba los eventos que se pueden producir en cualquier sección del juego
|
// --- Funciones ---
|
||||||
void handle(const SDL_Event &event);
|
void handle(const SDL_Event &event); // Comprueba los eventos que se pueden producir en cualquier sección del juego
|
||||||
} // namespace GlobalEvents
|
} // namespace GlobalEvents
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "global_inputs.h"
|
#include "global_inputs.h"
|
||||||
|
|
||||||
|
#include <algorithm> // Para std::ranges::any_of
|
||||||
#include <functional> // Para function
|
#include <functional> // Para function
|
||||||
#include <memory> // Para allocator, shared_ptr
|
#include <memory> // Para allocator, shared_ptr
|
||||||
#include <string> // Para operator+, char_traits, string, to_string
|
#include <string> // Para operator+, char_traits, string, to_string
|
||||||
@@ -145,11 +146,11 @@ auto checkServiceButton() -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mandos
|
// Mandos
|
||||||
for (auto gamepad : Input::get()->getGamepads()) {
|
if (std::ranges::any_of(Input::get()->getGamepads(), [](const auto& gamepad) {
|
||||||
if (Input::get()->checkAction(Input::Action::SERVICE, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
return Input::get()->checkAction(Input::Action::SERVICE, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad);
|
||||||
toggleServiceMenu();
|
})) {
|
||||||
return true;
|
toggleServiceMenu();
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -176,14 +177,13 @@ auto checkSystemInputs() -> bool {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto& [action, func] : ACTIONS) {
|
return std::ranges::any_of(ACTIONS, [](const auto& pair) {
|
||||||
if (Input::get()->checkAction(action, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
if (Input::get()->checkAction(pair.first, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
|
||||||
func();
|
pair.second();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
|
});
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comprueba el resto de entradas
|
// Comprueba el resto de entradas
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// --- Namespace GlobalInputs: gestiona inputs globales del juego ---
|
||||||
namespace GlobalInputs {
|
namespace GlobalInputs {
|
||||||
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
|
// --- Funciones ---
|
||||||
auto check() -> bool;
|
auto check() -> bool; // Comprueba los inputs que se pueden introducir en cualquier sección del juego
|
||||||
} // namespace GlobalInputs
|
} // namespace GlobalInputs
|
||||||
65
source/hit.h
@@ -7,55 +7,44 @@
|
|||||||
#include "sprite.h" // Para Sprite
|
#include "sprite.h" // Para Sprite
|
||||||
#include "texture.h" // Para Texture
|
#include "texture.h" // Para Texture
|
||||||
|
|
||||||
// Estructura que representa una colisión o impacto visual
|
// --- Estructura Hit: representa una colisión o impacto visual ---
|
||||||
struct Hit {
|
struct Hit {
|
||||||
private:
|
|
||||||
// Indica si el Hit está activo o no
|
|
||||||
bool enabled_{false};
|
|
||||||
|
|
||||||
// Sprite asociado al Hit, gestionado con un puntero único
|
|
||||||
std::unique_ptr<Sprite> sprite_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Elimina el constructor por defecto para obligar a pasar una textura
|
// --- Constructor ---
|
||||||
Hit() = delete;
|
Hit() = delete; // Elimina el constructor por defecto para obligar a pasar una textura
|
||||||
|
explicit Hit(const std::shared_ptr<Texture>& texture) // Constructor con textura obligatoria
|
||||||
// Constructor que obliga a pasar una textura compartida para crear el Sprite
|
|
||||||
// Esto evita que se pueda crear un Hit sin recursos gráficos válidos
|
|
||||||
explicit Hit(std::shared_ptr<Texture> texture)
|
|
||||||
: sprite_(std::make_unique<Sprite>(texture)) {}
|
: sprite_(std::make_unique<Sprite>(texture)) {}
|
||||||
|
|
||||||
// Establece la posición del Sprite en el espacio
|
// --- Métodos principales ---
|
||||||
void setPos(SDL_FPoint position) {
|
void create(SDL_FPoint position) { // Crea un "Hit" en la posición especificada
|
||||||
SDL_FPoint centered_position = {position.x - (sprite_->getWidth() / 2), position.y - (sprite_->getHeight() / 2)};
|
|
||||||
sprite_->setPosition(centered_position);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Activa o desactiva el Hit
|
|
||||||
void enable(bool value) {
|
|
||||||
enabled_ = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consulta si el Hit está activo
|
|
||||||
[[nodiscard]] auto isEnabled() const -> bool {
|
|
||||||
return enabled_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Crea un "Hit" en la posición especificada
|
|
||||||
void create(SDL_FPoint position) {
|
|
||||||
setPos(position);
|
setPos(position);
|
||||||
enable(true);
|
enable(true);
|
||||||
}
|
}
|
||||||
|
void render() { // Dibuja el hit
|
||||||
// Dibuja el hit
|
|
||||||
void render() {
|
|
||||||
if (enabled_) {
|
if (enabled_) {
|
||||||
sprite_->render();
|
sprite_->render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void disable() { // Deshabilita el hit
|
||||||
// Deshabilita el hit
|
|
||||||
void disable() {
|
|
||||||
enabled_ = false;
|
enabled_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Configuración ---
|
||||||
|
void setPos(SDL_FPoint position) { // Establece la posición del Sprite en el espacio
|
||||||
|
SDL_FPoint centered_position = {position.x - (sprite_->getWidth() / 2), position.y - (sprite_->getHeight() / 2)};
|
||||||
|
sprite_->setPosition(centered_position);
|
||||||
|
}
|
||||||
|
void enable(bool value) { // Activa o desactiva el Hit
|
||||||
|
enabled_ = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Getters ---
|
||||||
|
[[nodiscard]] auto isEnabled() const -> bool { // Consulta si el Hit está activo
|
||||||
|
return enabled_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// --- Variables de estado ---
|
||||||
|
std::unique_ptr<Sprite> sprite_; // Sprite asociado al Hit
|
||||||
|
bool enabled_{false}; // Indica si el Hit está activo
|
||||||
};
|
};
|
||||||
|
|||||||
105
source/input.cpp
@@ -36,21 +36,21 @@ void Input::bindKey(Action action, SDL_Scancode code) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Asigna inputs a botones del mando
|
// Asigna inputs a botones del mando
|
||||||
void Input::bindGameControllerButton(std::shared_ptr<Gamepad> gamepad, Action action, SDL_GamepadButton button) {
|
void Input::bindGameControllerButton(const std::shared_ptr<Gamepad> &gamepad, Action action, SDL_GamepadButton button) {
|
||||||
if (gamepad != nullptr) {
|
if (gamepad != nullptr) {
|
||||||
gamepad->bindings[action].button = button;
|
gamepad->bindings[action].button = button;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Asigna inputs a botones del mando
|
// Asigna inputs a botones del mando
|
||||||
void Input::bindGameControllerButton(std::shared_ptr<Gamepad> gamepad, Action action_target, Action action_source) {
|
void Input::bindGameControllerButton(const std::shared_ptr<Gamepad> &gamepad, Action action_target, Action action_source) {
|
||||||
if (gamepad != nullptr) {
|
if (gamepad != nullptr) {
|
||||||
gamepad->bindings[action_target].button = gamepad->bindings[action_source].button;
|
gamepad->bindings[action_target].button = gamepad->bindings[action_source].button;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Comprueba si alguna acción está activa
|
// Comprueba si alguna acción está activa
|
||||||
auto Input::checkAction(Action action, bool repeat, bool check_keyboard, std::shared_ptr<Gamepad> gamepad) -> bool {
|
auto Input::checkAction(Action action, bool repeat, bool check_keyboard, const std::shared_ptr<Gamepad> &gamepad) -> bool {
|
||||||
bool success_keyboard = false;
|
bool success_keyboard = false;
|
||||||
bool success_controller = false;
|
bool success_controller = false;
|
||||||
|
|
||||||
@@ -65,6 +65,10 @@ auto Input::checkAction(Action action, bool repeat, bool check_keyboard, std::sh
|
|||||||
if (gamepad != nullptr) {
|
if (gamepad != nullptr) {
|
||||||
success_controller = checkAxisInput(action, gamepad, repeat);
|
success_controller = checkAxisInput(action, gamepad, repeat);
|
||||||
|
|
||||||
|
if (!success_controller) {
|
||||||
|
success_controller = checkTriggerInput(action, gamepad, repeat);
|
||||||
|
}
|
||||||
|
|
||||||
if (!success_controller) {
|
if (!success_controller) {
|
||||||
if (repeat) { // El usuario quiere saber si está pulsada (estado mantenido)
|
if (repeat) { // El usuario quiere saber si está pulsada (estado mantenido)
|
||||||
success_controller = gamepad->bindings[action].is_held;
|
success_controller = gamepad->bindings[action].is_held;
|
||||||
@@ -78,7 +82,7 @@ auto Input::checkAction(Action action, bool repeat, bool check_keyboard, std::sh
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Comprueba si hay almenos una acción activa
|
// Comprueba si hay almenos una acción activa
|
||||||
auto Input::checkAnyInput(bool check_keyboard, std::shared_ptr<Gamepad> gamepad) -> bool {
|
auto Input::checkAnyInput(bool check_keyboard, const std::shared_ptr<Gamepad> &gamepad) -> bool {
|
||||||
// Obtenemos el número total de acciones posibles para iterar sobre ellas.
|
// Obtenemos el número total de acciones posibles para iterar sobre ellas.
|
||||||
|
|
||||||
// --- Comprobación del Teclado ---
|
// --- Comprobación del Teclado ---
|
||||||
@@ -118,7 +122,7 @@ auto Input::checkAnyButton(bool repeat) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Comprueba los mandos
|
// Comprueba los mandos
|
||||||
for (auto gamepad : gamepads_) {
|
for (const auto &gamepad : gamepads_) {
|
||||||
if (checkAction(bi, repeat, DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
if (checkAction(bi, repeat, DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -132,7 +136,9 @@ auto Input::checkAnyButton(bool repeat) -> bool {
|
|||||||
auto Input::gameControllerFound() const -> bool { return !gamepads_.empty(); }
|
auto Input::gameControllerFound() const -> bool { return !gamepads_.empty(); }
|
||||||
|
|
||||||
// Obten el nombre de un mando de juego
|
// Obten el nombre de un mando de juego
|
||||||
auto Input::getControllerName(std::shared_ptr<Gamepad> gamepad) -> std::string { return gamepad == nullptr ? std::string() : gamepad->name; }
|
auto Input::getControllerName(const std::shared_ptr<Gamepad> &gamepad) -> std::string {
|
||||||
|
return gamepad == nullptr ? std::string() : gamepad->name;
|
||||||
|
}
|
||||||
|
|
||||||
// Obtiene la lista de nombres de mandos
|
// Obtiene la lista de nombres de mandos
|
||||||
auto Input::getControllerNames() const -> std::vector<std::string> {
|
auto Input::getControllerNames() const -> std::vector<std::string> {
|
||||||
@@ -166,8 +172,8 @@ auto Input::getGamepadByName(const std::string &name) const -> std::shared_ptr<I
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Obtiene el SDL_GamepadButton asignado a un action
|
// Obtiene el SDL_GamepadButton asignado a un action
|
||||||
auto Input::getControllerBinding(std::shared_ptr<Gamepad> gamepad, Action action) -> SDL_GamepadButton {
|
auto Input::getControllerBinding(const std::shared_ptr<Gamepad> &gamepad, Action action) -> SDL_GamepadButton {
|
||||||
return gamepad->bindings[action].button;
|
return static_cast<SDL_GamepadButton>(gamepad->bindings[action].button);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convierte un InputAction a std::string
|
// Convierte un InputAction a std::string
|
||||||
@@ -202,7 +208,7 @@ auto Input::stringToInput(const std::string &name) -> Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Comprueba el eje del mando
|
// Comprueba el eje del mando
|
||||||
auto Input::checkAxisInput(Action action, std::shared_ptr<Gamepad> gamepad, bool repeat) -> bool {
|
auto Input::checkAxisInput(Action action, const std::shared_ptr<Gamepad> &gamepad, bool repeat) -> bool {
|
||||||
// Umbral para considerar el eje como activo
|
// Umbral para considerar el eje como activo
|
||||||
bool axis_active_now = false;
|
bool axis_active_now = false;
|
||||||
|
|
||||||
@@ -243,9 +249,57 @@ auto Input::checkAxisInput(Action action, std::shared_ptr<Gamepad> gamepad, bool
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Comprueba los triggers del mando como botones digitales
|
||||||
|
auto Input::checkTriggerInput(Action action, const std::shared_ptr<Gamepad> &gamepad, bool repeat) -> bool {
|
||||||
|
// Solo manejamos botones específicos que pueden ser triggers
|
||||||
|
if (gamepad->bindings[action].button != static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID)) {
|
||||||
|
// Solo procesamos L2 y R2 como triggers
|
||||||
|
int button = gamepad->bindings[action].button;
|
||||||
|
|
||||||
|
// Verificar si el botón mapeado corresponde a un trigger virtual
|
||||||
|
// (Para esto necesitamos valores especiales que representen L2/R2 como botones)
|
||||||
|
bool trigger_active_now = false;
|
||||||
|
|
||||||
|
// Usamos constantes especiales para L2 y R2 como botones
|
||||||
|
if (button == TRIGGER_L2_AS_BUTTON) { // L2 como botón
|
||||||
|
Sint16 trigger_value = SDL_GetGamepadAxis(gamepad->pad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER);
|
||||||
|
trigger_active_now = trigger_value > TRIGGER_THRESHOLD;
|
||||||
|
} else if (button == TRIGGER_R2_AS_BUTTON) { // R2 como botón
|
||||||
|
Sint16 trigger_value = SDL_GetGamepadAxis(gamepad->pad, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER);
|
||||||
|
trigger_active_now = trigger_value > TRIGGER_THRESHOLD;
|
||||||
|
} else {
|
||||||
|
return false; // No es un trigger
|
||||||
|
}
|
||||||
|
|
||||||
|
// Referencia al binding correspondiente
|
||||||
|
auto &binding = gamepad->bindings[action];
|
||||||
|
|
||||||
|
if (repeat) {
|
||||||
|
// Si se permite repetir, simplemente devolvemos el estado actual
|
||||||
|
return trigger_active_now;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si no se permite repetir, aplicamos la lógica de transición
|
||||||
|
if (trigger_active_now && !binding.trigger_active) {
|
||||||
|
// Transición de inactivo a activo
|
||||||
|
binding.trigger_active = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!trigger_active_now && binding.trigger_active) {
|
||||||
|
// Transición de activo a inactivo
|
||||||
|
binding.trigger_active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mantener el estado actual
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Input::addGamepadMappingsFromFile() {
|
void Input::addGamepadMappingsFromFile() {
|
||||||
if (SDL_AddGamepadMappingsFromFile(gamepad_mappings_file_.c_str()) < 0) {
|
if (SDL_AddGamepadMappingsFromFile(gamepad_mappings_file_.c_str()) < 0) {
|
||||||
std::cout << "Error, could not load " << gamepad_mappings_file_.c_str() << " file: " << SDL_GetError() << std::endl;
|
std::cout << "Error, could not load " << gamepad_mappings_file_.c_str() << " file: " << SDL_GetError() << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,6 +334,7 @@ void Input::resetInputStates() {
|
|||||||
for (auto &binding : gamepad->bindings) {
|
for (auto &binding : gamepad->bindings) {
|
||||||
binding.second.is_held = false;
|
binding.second.is_held = false;
|
||||||
binding.second.just_pressed = false;
|
binding.second.just_pressed = false;
|
||||||
|
binding.second.trigger_active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -297,9 +352,9 @@ void Input::update() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- MANDOS ---
|
// --- MANDOS ---
|
||||||
for (auto gamepad : gamepads_) {
|
for (const auto &gamepad : gamepads_) {
|
||||||
for (auto &binding : gamepad->bindings) {
|
for (auto &binding : gamepad->bindings) {
|
||||||
bool button_is_down_now = static_cast<int>(SDL_GetGamepadButton(gamepad->pad, binding.second.button)) != 0;
|
bool button_is_down_now = static_cast<int>(SDL_GetGamepadButton(gamepad->pad, static_cast<SDL_GamepadButton>(binding.second.button))) != 0;
|
||||||
|
|
||||||
// El estado .is_held del fotograma anterior nos sirve para saber si es un pulso nuevo
|
// El estado .is_held del fotograma anterior nos sirve para saber si es un pulso nuevo
|
||||||
binding.second.just_pressed = button_is_down_now && !binding.second.is_held;
|
binding.second.just_pressed = button_is_down_now && !binding.second.is_held;
|
||||||
@@ -321,13 +376,13 @@ auto Input::handleEvent(const SDL_Event &event) -> std::string {
|
|||||||
auto Input::addGamepad(int device_index) -> std::string {
|
auto Input::addGamepad(int device_index) -> std::string {
|
||||||
SDL_Gamepad *pad = SDL_OpenGamepad(device_index);
|
SDL_Gamepad *pad = SDL_OpenGamepad(device_index);
|
||||||
if (pad == nullptr) {
|
if (pad == nullptr) {
|
||||||
std::cerr << "Error al abrir el gamepad: " << SDL_GetError() << std::endl;
|
std::cerr << "Error al abrir el gamepad: " << SDL_GetError() << '\n';
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto gamepad = std::make_shared<Gamepad>(pad);
|
auto gamepad = std::make_shared<Gamepad>(pad);
|
||||||
auto name = gamepad->name;
|
auto name = gamepad->name;
|
||||||
std::cout << "Gamepad connected (" << name << ")" << std::endl;
|
std::cout << "Gamepad connected (" << name << ")" << '\n';
|
||||||
applyGamepadConfig(gamepad);
|
applyGamepadConfig(gamepad);
|
||||||
saveGamepadConfigFromGamepad(gamepad);
|
saveGamepadConfigFromGamepad(gamepad);
|
||||||
gamepads_.push_back(std::move(gamepad));
|
gamepads_.push_back(std::move(gamepad));
|
||||||
@@ -335,23 +390,23 @@ auto Input::addGamepad(int device_index) -> std::string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto Input::removeGamepad(SDL_JoystickID id) -> std::string {
|
auto Input::removeGamepad(SDL_JoystickID id) -> std::string {
|
||||||
auto it = std::find_if(gamepads_.begin(), gamepads_.end(), [id](const std::shared_ptr<Gamepad> &gamepad) {
|
auto it = std::ranges::find_if(gamepads_, [id](const std::shared_ptr<Gamepad> &gamepad) {
|
||||||
return gamepad->instance_id == id;
|
return gamepad->instance_id == id;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (it != gamepads_.end()) {
|
if (it != gamepads_.end()) {
|
||||||
std::string name = (*it)->name;
|
std::string name = (*it)->name;
|
||||||
std::cout << "Gamepad disconnected (" << name << ")" << std::endl;
|
std::cout << "Gamepad disconnected (" << name << ")" << '\n';
|
||||||
gamepads_.erase(it);
|
gamepads_.erase(it);
|
||||||
return name + " DISCONNECTED";
|
return name + " DISCONNECTED";
|
||||||
}
|
}
|
||||||
std::cerr << "No se encontró el gamepad con ID " << id << std::endl;
|
std::cerr << "No se encontró el gamepad con ID " << id << '\n';
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::printConnectedGamepads() const {
|
void Input::printConnectedGamepads() const {
|
||||||
if (gamepads_.empty()) {
|
if (gamepads_.empty()) {
|
||||||
std::cout << "No hay gamepads conectados." << std::endl;
|
std::cout << "No hay gamepads conectados." << '\n';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,7 +414,7 @@ void Input::printConnectedGamepads() const {
|
|||||||
for (const auto &gamepad : gamepads_) {
|
for (const auto &gamepad : gamepads_) {
|
||||||
std::string name = gamepad->name.empty() ? "Desconocido" : gamepad->name;
|
std::string name = gamepad->name.empty() ? "Desconocido" : gamepad->name;
|
||||||
std::cout << " - ID: " << gamepad->instance_id
|
std::cout << " - ID: " << gamepad->instance_id
|
||||||
<< ", Nombre: " << name << ")" << std::endl;
|
<< ", Nombre: " << name << ")" << '\n';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,13 +434,13 @@ void Input::applyGamepadConfig(std::shared_ptr<Gamepad> gamepad) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Buscar configuración por RUTA (path) ---
|
// --- Buscar configuración por RUTA (path) ---
|
||||||
auto config_it = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), [&gamepad](const GamepadConfig &config) {
|
auto config_it = std::ranges::find_if(gamepad_configs_, [&gamepad](const GamepadConfig &config) {
|
||||||
return config.path == gamepad->path;
|
return config.path == gamepad->path;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (config_it != gamepad_configs_.end()) {
|
if (config_it != gamepad_configs_.end()) {
|
||||||
// Se encontró una configuración específica para este puerto/dispositivo. La aplicamos.
|
// Se encontró una configuración específica para este puerto/dispositivo. La aplicamos.
|
||||||
std::cout << "Applying custom config for gamepad at path: " << gamepad->path << std::endl;
|
std::cout << "Applying custom config for gamepad at path: " << gamepad->path << '\n';
|
||||||
for (const auto &[action, button] : config_it->bindings) {
|
for (const auto &[action, button] : config_it->bindings) {
|
||||||
if (gamepad->bindings.find(action) != gamepad->bindings.end()) {
|
if (gamepad->bindings.find(action) != gamepad->bindings.end()) {
|
||||||
gamepad->bindings[action].button = button;
|
gamepad->bindings[action].button = button;
|
||||||
@@ -401,7 +456,7 @@ void Input::saveGamepadConfigFromGamepad(std::shared_ptr<Gamepad> gamepad) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- CAMBIO CLAVE: Buscar si ya existe una configuración por RUTA (path) ---
|
// --- CAMBIO CLAVE: Buscar si ya existe una configuración por RUTA (path) ---
|
||||||
auto config_it = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), [&gamepad](const GamepadConfig &config) {
|
auto config_it = std::ranges::find_if(gamepad_configs_, [&gamepad](const GamepadConfig &config) {
|
||||||
return config.path == gamepad->path;
|
return config.path == gamepad->path;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -411,7 +466,7 @@ void Input::saveGamepadConfigFromGamepad(std::shared_ptr<Gamepad> gamepad) {
|
|||||||
|
|
||||||
// Copiar todos los bindings actuales del gamepad
|
// Copiar todos los bindings actuales del gamepad
|
||||||
for (const auto &[action, buttonState] : gamepad->bindings) {
|
for (const auto &[action, buttonState] : gamepad->bindings) {
|
||||||
new_config.bindings[action] = buttonState.button;
|
new_config.bindings[action] = static_cast<SDL_GamepadButton>(buttonState.button);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_it != gamepad_configs_.end()) {
|
if (config_it != gamepad_configs_.end()) {
|
||||||
@@ -434,7 +489,7 @@ void Input::setGamepadConfigsFile(const std::string &filename) {
|
|||||||
|
|
||||||
// Método para obtener configuración de un gamepad específico (opcional)
|
// Método para obtener configuración de un gamepad específico (opcional)
|
||||||
auto Input::getGamepadConfig(const std::string &gamepad_name) -> GamepadConfig * {
|
auto Input::getGamepadConfig(const std::string &gamepad_name) -> GamepadConfig * {
|
||||||
auto config_it = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), [&gamepad_name](const GamepadConfig &config) {
|
auto config_it = std::ranges::find_if(gamepad_configs_, [&gamepad_name](const GamepadConfig &config) {
|
||||||
return config.name == gamepad_name;
|
return config.name == gamepad_name;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -443,7 +498,7 @@ auto Input::getGamepadConfig(const std::string &gamepad_name) -> GamepadConfig *
|
|||||||
|
|
||||||
// Método para eliminar configuración de gamepad (opcional)
|
// Método para eliminar configuración de gamepad (opcional)
|
||||||
auto Input::removeGamepadConfig(const std::string &gamepad_name) -> bool {
|
auto Input::removeGamepadConfig(const std::string &gamepad_name) -> bool {
|
||||||
auto config_it = std::find_if(gamepad_configs_.begin(), gamepad_configs_.end(), [&gamepad_name](const GamepadConfig &config) {
|
auto config_it = std::ranges::find_if(gamepad_configs_, [&gamepad_name](const GamepadConfig &config) {
|
||||||
return config.name == gamepad_name;
|
return config.name == gamepad_name;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -11,18 +11,19 @@
|
|||||||
#include "gamepad_config_manager.h" // Para GamepadConfig (ptr only), GamepadConfigs
|
#include "gamepad_config_manager.h" // Para GamepadConfig (ptr only), GamepadConfigs
|
||||||
#include "input_types.h" // Para InputAction
|
#include "input_types.h" // Para InputAction
|
||||||
|
|
||||||
// Clase Input: gestiona la entrada de teclado y mandos (singleton)
|
// --- Clase Input: gestiona la entrada de teclado y mandos (singleton) ---
|
||||||
class Input {
|
class Input {
|
||||||
public:
|
public:
|
||||||
// --- Constantes ---
|
// --- Constantes ---
|
||||||
static constexpr bool ALLOW_REPEAT = true;
|
static constexpr bool ALLOW_REPEAT = true; // Permite repetición
|
||||||
static constexpr bool DO_NOT_ALLOW_REPEAT = false;
|
static constexpr bool DO_NOT_ALLOW_REPEAT = false; // No permite repetición
|
||||||
|
static constexpr bool CHECK_KEYBOARD = true; // Comprueba teclado
|
||||||
|
static constexpr bool DO_NOT_CHECK_KEYBOARD = false; // No comprueba teclado
|
||||||
|
static constexpr int TRIGGER_L2_AS_BUTTON = 100; // L2 como botón
|
||||||
|
static constexpr int TRIGGER_R2_AS_BUTTON = 101; // R2 como botón
|
||||||
|
|
||||||
static constexpr bool CHECK_KEYBOARD = true;
|
// --- Tipos ---
|
||||||
static constexpr bool DO_NOT_CHECK_KEYBOARD = false;
|
using Action = InputAction; // Alias para mantener compatibilidad
|
||||||
|
|
||||||
// Alias para mantener compatibilidad con el código existente
|
|
||||||
using Action = InputAction;
|
|
||||||
|
|
||||||
// --- Estructuras ---
|
// --- Estructuras ---
|
||||||
struct KeyState {
|
struct KeyState {
|
||||||
@@ -31,17 +32,23 @@ class Input {
|
|||||||
bool just_pressed; // Se acaba de pulsar en este fotograma
|
bool just_pressed; // Se acaba de pulsar en este fotograma
|
||||||
|
|
||||||
KeyState(Uint8 scancode = 0, bool is_held = false, bool just_pressed = false)
|
KeyState(Uint8 scancode = 0, bool is_held = false, bool just_pressed = false)
|
||||||
: scancode(scancode), is_held(is_held), just_pressed(just_pressed) {}
|
: scancode(scancode),
|
||||||
|
is_held(is_held),
|
||||||
|
just_pressed(just_pressed) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ButtonState {
|
struct ButtonState {
|
||||||
SDL_GamepadButton button; // GameControllerButton asociado
|
int button; // GameControllerButton asociado
|
||||||
bool is_held; // Está pulsada ahora mismo
|
bool is_held; // Está pulsada ahora mismo
|
||||||
bool just_pressed; // Se acaba de pulsar en este fotograma
|
bool just_pressed; // Se acaba de pulsar en este fotograma
|
||||||
bool axis_active; // Estado del eje
|
bool axis_active; // Estado del eje
|
||||||
|
bool trigger_active{false}; // Estado del trigger como botón digital
|
||||||
|
|
||||||
ButtonState(SDL_GamepadButton btn = SDL_GAMEPAD_BUTTON_INVALID, bool is_held = false, bool just_pressed = false, bool axis_act = false)
|
ButtonState(int btn = static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID), bool is_held = false, bool just_pressed = false, bool axis_act = false)
|
||||||
: button(btn), is_held(is_held), just_pressed(just_pressed), axis_active(axis_act) {}
|
: button(btn),
|
||||||
|
is_held(is_held),
|
||||||
|
just_pressed(just_pressed),
|
||||||
|
axis_active(axis_act) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Keyboard {
|
struct Keyboard {
|
||||||
@@ -102,23 +109,23 @@ class Input {
|
|||||||
path(std::string(SDL_GetGamepadPath(pad))),
|
path(std::string(SDL_GetGamepadPath(pad))),
|
||||||
bindings{
|
bindings{
|
||||||
// Movimiento del jugador
|
// Movimiento del jugador
|
||||||
{Action::UP, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_UP)},
|
{Action::UP, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_UP))},
|
||||||
{Action::DOWN, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_DOWN)},
|
{Action::DOWN, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_DOWN))},
|
||||||
{Action::LEFT, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_LEFT)},
|
{Action::LEFT, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_LEFT))},
|
||||||
{Action::RIGHT, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_RIGHT)},
|
{Action::RIGHT, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_RIGHT))},
|
||||||
|
|
||||||
// Disparo del jugador
|
// Disparo del jugador
|
||||||
{Action::FIRE_LEFT, ButtonState(SDL_GAMEPAD_BUTTON_WEST)},
|
{Action::FIRE_LEFT, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_WEST))},
|
||||||
{Action::FIRE_CENTER, ButtonState(SDL_GAMEPAD_BUTTON_NORTH)},
|
{Action::FIRE_CENTER, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_NORTH))},
|
||||||
{Action::FIRE_RIGHT, ButtonState(SDL_GAMEPAD_BUTTON_EAST)},
|
{Action::FIRE_RIGHT, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_EAST))},
|
||||||
|
|
||||||
// Interfaz
|
// Interfaz
|
||||||
{Action::START, ButtonState(SDL_GAMEPAD_BUTTON_START)},
|
{Action::START, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_START))},
|
||||||
{Action::SERVICE, ButtonState(SDL_GAMEPAD_BUTTON_BACK)},
|
{Action::SERVICE, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_BACK))},
|
||||||
|
|
||||||
// Menu de servicio
|
// Menu de servicio
|
||||||
{Action::SM_SELECT, ButtonState(SDL_GAMEPAD_BUTTON_WEST)},
|
{Action::SM_SELECT, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_WEST))},
|
||||||
{Action::SM_BACK, ButtonState(SDL_GAMEPAD_BUTTON_NORTH)}} {}
|
{Action::SM_BACK, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_NORTH))}} {}
|
||||||
|
|
||||||
~Gamepad() {
|
~Gamepad() {
|
||||||
if (pad != nullptr) {
|
if (pad != nullptr) {
|
||||||
@@ -128,11 +135,12 @@ class Input {
|
|||||||
|
|
||||||
// Reasigna un botón a una acción
|
// Reasigna un botón a una acción
|
||||||
void rebindAction(Action action, SDL_GamepadButton new_button) {
|
void rebindAction(Action action, SDL_GamepadButton new_button) {
|
||||||
bindings[action] = new_button;
|
bindings[action] = static_cast<int>(new_button);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using Gamepads = std::vector<std::shared_ptr<Gamepad>>;
|
// --- Tipos ---
|
||||||
|
using Gamepads = std::vector<std::shared_ptr<Gamepad>>; // Vector de gamepads
|
||||||
|
|
||||||
// --- Métodos de singleton ---
|
// --- Métodos de singleton ---
|
||||||
static void init(const std::string &game_controller_db_path, const std::string &gamepad_configs_file);
|
static void init(const std::string &game_controller_db_path, const std::string &gamepad_configs_file);
|
||||||
@@ -141,18 +149,18 @@ class Input {
|
|||||||
|
|
||||||
// --- Métodos de configuración de controles ---
|
// --- Métodos de configuración de controles ---
|
||||||
void bindKey(Action action, SDL_Scancode code);
|
void bindKey(Action action, SDL_Scancode code);
|
||||||
static void bindGameControllerButton(std::shared_ptr<Gamepad> gamepad, Action action, SDL_GamepadButton button);
|
static void bindGameControllerButton(const std::shared_ptr<Gamepad> &gamepad, Action action, SDL_GamepadButton button);
|
||||||
static void bindGameControllerButton(std::shared_ptr<Gamepad> gamepad, Action action_target, Action action_source);
|
static void bindGameControllerButton(const std::shared_ptr<Gamepad> &gamepad, Action action_target, Action action_source);
|
||||||
|
|
||||||
// --- Métodos de consulta de entrada ---
|
// --- Métodos de consulta de entrada ---
|
||||||
void update();
|
void update();
|
||||||
auto checkAction(Action action, bool repeat = true, bool check_keyboard = true, std::shared_ptr<Gamepad> gamepad = nullptr) -> bool;
|
auto checkAction(Action action, bool repeat = true, bool check_keyboard = true, const std::shared_ptr<Gamepad> &gamepad = nullptr) -> bool;
|
||||||
auto checkAnyInput(bool check_keyboard = true, std::shared_ptr<Gamepad> gamepad = nullptr) -> bool;
|
auto checkAnyInput(bool check_keyboard = true, const std::shared_ptr<Gamepad> &gamepad = nullptr) -> bool;
|
||||||
auto checkAnyButton(bool repeat = DO_NOT_ALLOW_REPEAT) -> bool;
|
auto checkAnyButton(bool repeat = DO_NOT_ALLOW_REPEAT) -> bool;
|
||||||
|
|
||||||
// --- Métodos de gestión de mandos ---
|
// --- Métodos de gestión de mandos ---
|
||||||
[[nodiscard]] auto gameControllerFound() const -> bool;
|
[[nodiscard]] auto gameControllerFound() const -> bool;
|
||||||
static auto getControllerName(std::shared_ptr<Gamepad> gamepad) -> std::string;
|
static auto getControllerName(const std::shared_ptr<Gamepad> &gamepad) -> std::string;
|
||||||
auto getControllerNames() const -> std::vector<std::string>;
|
auto getControllerNames() const -> std::vector<std::string>;
|
||||||
[[nodiscard]] auto getNumGamepads() const -> int;
|
[[nodiscard]] auto getNumGamepads() const -> int;
|
||||||
auto getGamepad(SDL_JoystickID id) const -> std::shared_ptr<Gamepad>;
|
auto getGamepad(SDL_JoystickID id) const -> std::shared_ptr<Gamepad>;
|
||||||
@@ -160,7 +168,7 @@ class Input {
|
|||||||
auto getGamepads() const -> const Gamepads & { return gamepads_; }
|
auto getGamepads() const -> const Gamepads & { return gamepads_; }
|
||||||
|
|
||||||
// --- Métodos de consulta y utilidades ---
|
// --- Métodos de consulta y utilidades ---
|
||||||
[[nodiscard]] static auto getControllerBinding(std::shared_ptr<Gamepad> gamepad, Action action) -> SDL_GamepadButton;
|
[[nodiscard]] static auto getControllerBinding(const std::shared_ptr<Gamepad> &gamepad, Action action) -> SDL_GamepadButton;
|
||||||
[[nodiscard]] static auto inputToString(Action action) -> std::string;
|
[[nodiscard]] static auto inputToString(Action action) -> std::string;
|
||||||
[[nodiscard]] static auto stringToInput(const std::string &name) -> Action;
|
[[nodiscard]] static auto stringToInput(const std::string &name) -> Action;
|
||||||
|
|
||||||
@@ -178,6 +186,7 @@ class Input {
|
|||||||
private:
|
private:
|
||||||
// --- Constantes ---
|
// --- Constantes ---
|
||||||
static constexpr Sint16 AXIS_THRESHOLD = 30000;
|
static constexpr Sint16 AXIS_THRESHOLD = 30000;
|
||||||
|
static constexpr Sint16 TRIGGER_THRESHOLD = 16384; // Umbral para triggers (aproximadamente 50% del rango)
|
||||||
static constexpr std::array<Action, 4> BUTTON_INPUTS = {Action::FIRE_LEFT, Action::FIRE_CENTER, Action::FIRE_RIGHT, Action::START}; // Listado de los inputs para jugar que utilizan botones, ni palancas ni crucetas
|
static constexpr std::array<Action, 4> BUTTON_INPUTS = {Action::FIRE_LEFT, Action::FIRE_CENTER, Action::FIRE_RIGHT, Action::START}; // Listado de los inputs para jugar que utilizan botones, ni palancas ni crucetas
|
||||||
|
|
||||||
// --- Variables internas ---
|
// --- Variables internas ---
|
||||||
@@ -189,7 +198,8 @@ class Input {
|
|||||||
|
|
||||||
// --- Métodos internos ---
|
// --- Métodos internos ---
|
||||||
void initSDLGamePad();
|
void initSDLGamePad();
|
||||||
static auto checkAxisInput(Action action, std::shared_ptr<Gamepad> gamepad, bool repeat) -> bool;
|
static auto checkAxisInput(Action action, const std::shared_ptr<Gamepad> &gamepad, bool repeat) -> bool;
|
||||||
|
static auto checkTriggerInput(Action action, const std::shared_ptr<Gamepad> &gamepad, bool repeat) -> bool;
|
||||||
auto addGamepad(int device_index) -> std::string;
|
auto addGamepad(int device_index) -> std::string;
|
||||||
auto removeGamepad(SDL_JoystickID id) -> std::string;
|
auto removeGamepad(SDL_JoystickID id) -> std::string;
|
||||||
void addGamepadMappingsFromFile();
|
void addGamepadMappingsFromFile();
|
||||||
|
|||||||
@@ -73,7 +73,9 @@ const std::unordered_map<SDL_GamepadButton, std::string> BUTTON_TO_STRING = {
|
|||||||
{SDL_GAMEPAD_BUTTON_DPAD_UP, "DPAD_UP"},
|
{SDL_GAMEPAD_BUTTON_DPAD_UP, "DPAD_UP"},
|
||||||
{SDL_GAMEPAD_BUTTON_DPAD_DOWN, "DPAD_DOWN"},
|
{SDL_GAMEPAD_BUTTON_DPAD_DOWN, "DPAD_DOWN"},
|
||||||
{SDL_GAMEPAD_BUTTON_DPAD_LEFT, "DPAD_LEFT"},
|
{SDL_GAMEPAD_BUTTON_DPAD_LEFT, "DPAD_LEFT"},
|
||||||
{SDL_GAMEPAD_BUTTON_DPAD_RIGHT, "DPAD_RIGHT"}};
|
{SDL_GAMEPAD_BUTTON_DPAD_RIGHT, "DPAD_RIGHT"},
|
||||||
|
{static_cast<SDL_GamepadButton>(100), "L2_AS_BUTTON"},
|
||||||
|
{static_cast<SDL_GamepadButton>(101), "R2_AS_BUTTON"}};
|
||||||
|
|
||||||
const std::unordered_map<std::string, SDL_GamepadButton> STRING_TO_BUTTON = {
|
const std::unordered_map<std::string, SDL_GamepadButton> STRING_TO_BUTTON = {
|
||||||
{"WEST", SDL_GAMEPAD_BUTTON_WEST},
|
{"WEST", SDL_GAMEPAD_BUTTON_WEST},
|
||||||
@@ -87,7 +89,9 @@ const std::unordered_map<std::string, SDL_GamepadButton> STRING_TO_BUTTON = {
|
|||||||
{"DPAD_UP", SDL_GAMEPAD_BUTTON_DPAD_UP},
|
{"DPAD_UP", SDL_GAMEPAD_BUTTON_DPAD_UP},
|
||||||
{"DPAD_DOWN", SDL_GAMEPAD_BUTTON_DPAD_DOWN},
|
{"DPAD_DOWN", SDL_GAMEPAD_BUTTON_DPAD_DOWN},
|
||||||
{"DPAD_LEFT", SDL_GAMEPAD_BUTTON_DPAD_LEFT},
|
{"DPAD_LEFT", SDL_GAMEPAD_BUTTON_DPAD_LEFT},
|
||||||
{"DPAD_RIGHT", SDL_GAMEPAD_BUTTON_DPAD_RIGHT}};
|
{"DPAD_RIGHT", SDL_GAMEPAD_BUTTON_DPAD_RIGHT},
|
||||||
|
{"L2_AS_BUTTON", static_cast<SDL_GamepadButton>(100)},
|
||||||
|
{"R2_AS_BUTTON", static_cast<SDL_GamepadButton>(101)}};
|
||||||
|
|
||||||
const std::unordered_map<InputAction, InputAction> ACTION_TO_ACTION = {
|
const std::unordered_map<InputAction, InputAction> ACTION_TO_ACTION = {
|
||||||
{InputAction::SM_SELECT, InputAction::FIRE_LEFT},
|
{InputAction::SM_SELECT, InputAction::FIRE_LEFT},
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
// Acciones de entrada posibles en el juego
|
// --- Enums ---
|
||||||
enum class InputAction : int {
|
enum class InputAction : int { // Acciones de entrada posibles en el juego
|
||||||
// Inputs de movimiento
|
// Inputs de movimiento
|
||||||
UP,
|
UP,
|
||||||
DOWN,
|
DOWN,
|
||||||
@@ -47,9 +47,9 @@ enum class InputAction : int {
|
|||||||
SIZE,
|
SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mapas para convertir entre enums y strings
|
// --- Variables ---
|
||||||
extern const std::unordered_map<InputAction, std::string> ACTION_TO_STRING;
|
extern const std::unordered_map<InputAction, std::string> ACTION_TO_STRING; // Mapeo de acción a string
|
||||||
extern const std::unordered_map<std::string, InputAction> STRING_TO_ACTION;
|
extern const std::unordered_map<std::string, InputAction> STRING_TO_ACTION; // Mapeo de string a acción
|
||||||
extern const std::unordered_map<SDL_GamepadButton, std::string> BUTTON_TO_STRING;
|
extern const std::unordered_map<SDL_GamepadButton, std::string> BUTTON_TO_STRING; // Mapeo de botón a string
|
||||||
extern const std::unordered_map<std::string, SDL_GamepadButton> STRING_TO_BUTTON;
|
extern const std::unordered_map<std::string, SDL_GamepadButton> STRING_TO_BUTTON; // Mapeo de string a botón
|
||||||
extern const std::unordered_map<InputAction, InputAction> ACTION_TO_ACTION;
|
extern const std::unordered_map<InputAction, InputAction> ACTION_TO_ACTION; // Mapeo de acción a acción
|
||||||
@@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
class Texture; // lines 6-6
|
class Texture; // lines 6-6
|
||||||
|
|
||||||
Item::Item(ItemType type, float x, float y, SDL_FRect &play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation)
|
Item::Item(ItemType type, float x, float y, SDL_FRect &play_area, const 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)),
|
||||||
type_(type),
|
play_area_(play_area),
|
||||||
play_area_(play_area) {
|
type_(type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ItemType::COFFEE_MACHINE: {
|
case ItemType::COFFEE_MACHINE: {
|
||||||
width_ = COFFEE_MACHINE_WIDTH;
|
width_ = COFFEE_MACHINE_WIDTH;
|
||||||
@@ -29,7 +29,15 @@ Item::Item(ItemType type, float x, float y, SDL_FRect &play_area, std::shared_pt
|
|||||||
height_ = param.game.item_size;
|
height_ = param.game.item_size;
|
||||||
pos_x_ = x;
|
pos_x_ = x;
|
||||||
pos_y_ = y;
|
pos_y_ = y;
|
||||||
vel_x_ = -1.0F + ((rand() % 5) * 0.5F);
|
// 6 velocidades: 3 negativas (-1.0, -0.66, -0.33) y 3 positivas (0.33, 0.66, 1.0)
|
||||||
|
const int direction = rand() % 6;
|
||||||
|
if (direction < 3) {
|
||||||
|
// Velocidades negativas: -1.0, -0.66, -0.33
|
||||||
|
vel_x_ = -1.0F + (direction * 0.33F);
|
||||||
|
} else {
|
||||||
|
// Velocidades positivas: 0.33, 0.66, 1.0
|
||||||
|
vel_x_ = 0.33F + ((direction - 3) * 0.33F);
|
||||||
|
}
|
||||||
vel_y_ = -4.0F;
|
vel_y_ = -4.0F;
|
||||||
accel_y_ = 0.2F;
|
accel_y_ = 0.2F;
|
||||||
collider_.r = width_ / 2;
|
collider_.r = width_ / 2;
|
||||||
@@ -82,9 +90,9 @@ void Item::move() {
|
|||||||
const float MAX_X = play_area_.w - width_;
|
const float MAX_X = play_area_.w - width_;
|
||||||
pos_x_ = std::clamp(pos_x_, MIN_X, MAX_X);
|
pos_x_ = std::clamp(pos_x_, MIN_X, MAX_X);
|
||||||
|
|
||||||
// Si toca el borde lateral, invierte la velocidad horizontal
|
// Si toca el borde lateral
|
||||||
if (pos_x_ == MIN_X || pos_x_ == MAX_X) {
|
if (pos_x_ == MIN_X || pos_x_ == MAX_X) {
|
||||||
vel_x_ = -vel_x_;
|
vel_x_ = -vel_x_; // Invierte la velocidad horizontal
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si colisiona por arriba, rebota (excepto la máquina de café)
|
// Si colisiona por arriba, rebota (excepto la máquina de café)
|
||||||
@@ -92,8 +100,8 @@ void Item::move() {
|
|||||||
// Corrige
|
// Corrige
|
||||||
pos_y_ = param.game.play_area.rect.y;
|
pos_y_ = param.game.play_area.rect.y;
|
||||||
|
|
||||||
// Invierte la velocidad
|
// Fuerza la velocidad hacia abajo para evitar oscilaciones
|
||||||
vel_y_ = -vel_y_;
|
vel_y_ = std::abs(vel_y_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Si colisiona con la parte inferior
|
// Si colisiona con la parte inferior
|
||||||
@@ -181,17 +189,17 @@ auto Item::getCoffeeMachineSpawn(int player_x, int item_width, int area_width, i
|
|||||||
// Ambos lados disponibles, elegir aleatoriamente
|
// Ambos lados disponibles, elegir aleatoriamente
|
||||||
if (rand() % 2 == 0) {
|
if (rand() % 2 == 0) {
|
||||||
// Lado izquierdo
|
// Lado izquierdo
|
||||||
return rand() % (exclude_left - LEFT_BOUND) + LEFT_BOUND;
|
return (rand() % (exclude_left - LEFT_BOUND)) + LEFT_BOUND;
|
||||||
} // Lado derecho
|
} // Lado derecho
|
||||||
return rand() % (RIGHT_BOUND - exclude_right) + exclude_right;
|
return (rand() % (RIGHT_BOUND - exclude_right)) + exclude_right;
|
||||||
}
|
}
|
||||||
if (can_spawn_left) {
|
if (can_spawn_left) {
|
||||||
// Solo lado izquierdo disponible
|
// Solo lado izquierdo disponible
|
||||||
return rand() % (exclude_left - LEFT_BOUND) + LEFT_BOUND;
|
return (rand() % (exclude_left - LEFT_BOUND)) + LEFT_BOUND;
|
||||||
}
|
}
|
||||||
if (can_spawn_right) {
|
if (can_spawn_right) {
|
||||||
// Solo lado derecho disponible
|
// Solo lado derecho disponible
|
||||||
return rand() % (RIGHT_BOUND - exclude_right) + exclude_right;
|
return (rand() % (RIGHT_BOUND - exclude_right)) + exclude_right;
|
||||||
} // No hay espacio suficiente lejos del jugador
|
} // No hay espacio suficiente lejos del jugador
|
||||||
// Por ahora, intentar spawn en el extremo más lejano posible
|
// Por ahora, intentar spawn en el extremo más lejano posible
|
||||||
int distance_to_left = abs(player_x - LEFT_BOUND);
|
int distance_to_left = abs(player_x - LEFT_BOUND);
|
||||||
|
|||||||
@@ -11,8 +11,7 @@
|
|||||||
|
|
||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
// Tipos de objetos disponibles en el juego.
|
// --- Enums ---
|
||||||
// Define los diferentes tipos de objetos que pueden existir en el juego.
|
|
||||||
enum class ItemType : int {
|
enum class ItemType : int {
|
||||||
DISK = 1, // Disco
|
DISK = 1, // Disco
|
||||||
GAVINA = 2, // Gavina
|
GAVINA = 2, // Gavina
|
||||||
@@ -24,81 +23,57 @@ enum class ItemType : int {
|
|||||||
NONE = 8, // Ninguno
|
NONE = 8, // Ninguno
|
||||||
};
|
};
|
||||||
|
|
||||||
// Clase Item.
|
// --- Clase Item: representa un objeto en el juego ---
|
||||||
// Representa un objeto en el juego, con sus propiedades y métodos para gestionar su comportamiento.
|
|
||||||
class Item {
|
class Item {
|
||||||
public:
|
public:
|
||||||
// Constantes
|
// --- Constantes ---
|
||||||
static constexpr int COFFEE_MACHINE_WIDTH = 30;
|
static constexpr int COFFEE_MACHINE_WIDTH = 30; // Anchura de la máquina de café
|
||||||
static constexpr int COFFEE_MACHINE_HEIGHT = 39;
|
static constexpr int COFFEE_MACHINE_HEIGHT = 39; // Altura de la máquina de café
|
||||||
|
|
||||||
// Constructor. Inicializa un objeto Item con el tipo, posición, área de juego, textura y animación.
|
// --- Constructor y destructor ---
|
||||||
Item(ItemType type, float x, float y, SDL_FRect &play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation);
|
Item(ItemType type, float x, float y, SDL_FRect &play_area, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation); // Constructor principal
|
||||||
|
~Item() = default; // Destructor
|
||||||
|
|
||||||
// Destructor.
|
// --- Métodos principales ---
|
||||||
~Item() = default;
|
void alignTo(int x); // Centra el objeto en la posición X indicada
|
||||||
|
void render(); // Renderiza el objeto en pantalla
|
||||||
|
void disable(); // Desactiva el objeto
|
||||||
|
void update(); // Actualiza la posición, animación y contadores
|
||||||
|
|
||||||
// Centra el objeto en la posición X indicada, asegurando que no se salga del área de juego.
|
// --- Getters ---
|
||||||
void alignTo(int x);
|
[[nodiscard]] auto getPosX() const -> float { return pos_x_; } // Obtiene la posición X
|
||||||
|
[[nodiscard]] auto getPosY() const -> float { return pos_y_; } // Obtiene la posición Y
|
||||||
// Renderiza el objeto en pantalla si está habilitado.
|
[[nodiscard]] auto getWidth() const -> int { return width_; } // Obtiene la anchura
|
||||||
// Si el tiempo de vida es mayor que 200, renderiza el sprite.
|
[[nodiscard]] auto getHeight() const -> int { return height_; } // Obtiene la altura
|
||||||
// Si es menor o igual a 200, renderiza el sprite de forma intermitente.
|
[[nodiscard]] auto getType() const -> ItemType { return type_; } // Obtiene el tipo
|
||||||
void render();
|
[[nodiscard]] auto isEnabled() const -> bool { return enabled_; } // Verifica si está habilitado
|
||||||
|
[[nodiscard]] auto isOnFloor() const -> bool { return floor_collision_; } // Verifica si está en el suelo
|
||||||
// Desactiva el objeto estableciendo su estado enabled_ a false.
|
auto getCollider() -> Circle & { return collider_; } // Obtiene el colisionador
|
||||||
void disable();
|
|
||||||
|
|
||||||
// Actualiza la posición, animación y contadores del objeto.
|
|
||||||
// Llama a move(), sprite_->update() y updateTimeToLive().
|
|
||||||
void update();
|
|
||||||
|
|
||||||
// Getters
|
|
||||||
[[nodiscard]] auto getPosX() const -> float { return pos_x_; }
|
|
||||||
[[nodiscard]] auto getPosY() const -> float { return pos_y_; }
|
|
||||||
[[nodiscard]] auto getWidth() const -> int { return width_; }
|
|
||||||
[[nodiscard]] auto getHeight() const -> int { return height_; }
|
|
||||||
[[nodiscard]] auto getType() const -> ItemType { return type_; }
|
|
||||||
[[nodiscard]] auto isEnabled() const -> bool { return enabled_; }
|
|
||||||
[[nodiscard]] auto isOnFloor() const -> bool { return floor_collision_; }
|
|
||||||
auto getCollider() -> Circle & { return collider_; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Objetos y punteros
|
// --- Objetos y punteros ---
|
||||||
std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos del objeto
|
std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos del objeto
|
||||||
|
|
||||||
// Variables de estado y físicas
|
// --- Variables de estado ---
|
||||||
|
SDL_FRect play_area_; // Rectángulo con la zona de juego
|
||||||
|
Circle collider_; // Círculo de colisión del objeto
|
||||||
|
ItemType type_; // Tipo de objeto
|
||||||
float pos_x_; // Posición X del objeto
|
float pos_x_; // Posición X del objeto
|
||||||
float pos_y_; // Posición Y del objeto
|
float pos_y_; // Posición Y del objeto
|
||||||
int width_; // Ancho del objeto
|
|
||||||
int height_; // Alto del objeto
|
|
||||||
float vel_x_; // Velocidad en el eje X
|
float vel_x_; // Velocidad en el eje X
|
||||||
float vel_y_; // Velocidad en el eje Y
|
float vel_y_; // Velocidad en el eje Y
|
||||||
float accel_x_ = 0.0F; // Aceleración en el eje X
|
float accel_x_ = 0.0F; // Aceleración en el eje X
|
||||||
float accel_y_; // Aceleración en el eje Y
|
float accel_y_; // Aceleración en el eje Y
|
||||||
bool floor_collision_ = false; // Indica si el objeto colisiona con el suelo
|
int width_; // Ancho del objeto
|
||||||
ItemType type_; // Tipo de objeto
|
int height_; // Alto del objeto
|
||||||
bool enabled_ = true; // Indica si el objeto está habilitado
|
|
||||||
Circle collider_; // Círculo de colisión del objeto
|
|
||||||
SDL_FRect play_area_; // Rectángulo con la zona de juego
|
|
||||||
Uint16 time_to_live_ = 600; // Tiempo que el objeto está presente
|
Uint16 time_to_live_ = 600; // Tiempo que el objeto está presente
|
||||||
|
bool floor_collision_ = false; // Indica si el objeto colisiona con el suelo
|
||||||
|
bool enabled_ = true; // Indica si el objeto está habilitado
|
||||||
|
|
||||||
// Alinea el círculo de colisión con la posición del objeto.
|
// --- Métodos internos ---
|
||||||
// Actualiza las coordenadas X e Y del colisionador.
|
void shiftColliders(); // Alinea el círculo de colisión con la posición del objeto
|
||||||
void shiftColliders();
|
void shiftSprite(); // Coloca el sprite en la posición del objeto
|
||||||
|
void move(); // Actualiza la posición y estados del objeto
|
||||||
// Coloca el sprite en la posición del objeto.
|
void updateTimeToLive(); // Actualiza el contador de tiempo de vida
|
||||||
// Actualiza las coordenadas X e Y del sprite.
|
static auto getCoffeeMachineSpawn(int player_x, int item_width, int area_width, int margin = 2) -> int; // Calcula la zona de aparición de la máquina de café
|
||||||
void shiftSprite();
|
|
||||||
|
|
||||||
// Actualiza la posición y estados del objeto.
|
|
||||||
// Controla las colisiones con los límites del área de juego y actualiza sprite y colisionador.
|
|
||||||
void move();
|
|
||||||
|
|
||||||
// Actualiza el contador de tiempo de vida del objeto.
|
|
||||||
// Si el tiempo de vida es mayor a 0, lo decrementa. Si llega a 0, desactiva el objeto.
|
|
||||||
void updateTimeToLive();
|
|
||||||
|
|
||||||
// Calcula la zona de aparición de la máquina de café
|
|
||||||
static auto getCoffeeMachineSpawn(int player_x, int item_width, int area_width, int margin = 2) -> int;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "difficulty.h" // Para Difficulty
|
#include "difficulty.h" // Para Difficulty
|
||||||
#include "external/json.hpp" // Para basic_json, iteration_proxy_value, oper...
|
#include "external/json.hpp" // Para basic_json, iteration_proxy_value, oper...
|
||||||
#include "options.h" // Para SettingsOpt...
|
#include "options.h" // Para SettingsOpt...
|
||||||
|
#include "resource_helper.h" // Para ResourceHelper
|
||||||
|
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
|
||||||
@@ -27,14 +28,24 @@ std::vector<Language> languages = {
|
|||||||
auto loadFromFile(const std::string &file_path) -> bool {
|
auto loadFromFile(const std::string &file_path) -> bool {
|
||||||
texts.clear();
|
texts.clear();
|
||||||
|
|
||||||
std::ifstream rfile(file_path);
|
// Intentar cargar desde ResourceHelper primero
|
||||||
if (!rfile.is_open()) {
|
auto resource_data = ResourceHelper::loadFile(file_path);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
json j;
|
json j;
|
||||||
rfile >> j;
|
|
||||||
|
if (!resource_data.empty()) {
|
||||||
|
// Cargar desde datos del pack
|
||||||
|
std::string content(resource_data.begin(), resource_data.end());
|
||||||
|
j = json::parse(content);
|
||||||
|
} else {
|
||||||
|
// Fallback a filesystem directo
|
||||||
|
std::ifstream rfile(file_path);
|
||||||
|
if (!rfile.is_open()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
rfile >> j;
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &el : j.items()) {
|
for (const auto &el : j.items()) {
|
||||||
texts[el.key()] = el.value();
|
texts[el.key()] = el.value();
|
||||||
|
|||||||
@@ -1,27 +1,30 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string> // Para string, basic_string
|
#include <string> // Para string, basic_string
|
||||||
#include <utility>
|
#include <utility> // Para move
|
||||||
|
|
||||||
|
// --- Namespace Lang: gestión de idiomas y textos ---
|
||||||
namespace Lang {
|
namespace Lang {
|
||||||
// --- Códigos de idioma soportados ---
|
// --- Enums ---
|
||||||
enum class Code : int {
|
enum class Code : int {
|
||||||
SPANISH = 0,
|
SPANISH = 0, // Español
|
||||||
VALENCIAN = 1,
|
VALENCIAN = 1, // Valenciano
|
||||||
ENGLISH = 2
|
ENGLISH = 2 // Inglés
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Estructura que representa un idioma ---
|
// --- Estructuras ---
|
||||||
struct Language {
|
struct Language {
|
||||||
Code code; // Código que identifica al idioma
|
Code code; // Código que identifica al idioma
|
||||||
std::string name; // Nombre que identifica el idioma
|
std::string name; // Nombre que identifica el idioma
|
||||||
std::string file_name; // Nombre del fichero con los textos
|
std::string file_name; // Nombre del fichero con los textos
|
||||||
|
|
||||||
Language(Code c, std::string n, std::string fn)
|
Language(Code c, std::string n, std::string fn)
|
||||||
: code(c), name(std::move(n)), file_name(std::move(fn)) {}
|
: code(c),
|
||||||
|
name(std::move(n)),
|
||||||
|
file_name(std::move(fn)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Métodos ---
|
// --- Funciones ---
|
||||||
auto loadFromFile(const std::string &file_path) -> bool; // Carga los textos desde el fichero JSON especificado
|
auto loadFromFile(const std::string &file_path) -> bool; // Carga los textos desde el fichero JSON especificado
|
||||||
auto getText(const std::string &key) -> std::string; // Obtiene el texto por clave
|
auto getText(const std::string &key) -> std::string; // Obtiene el texto por clave
|
||||||
auto getNextLangCode(Code current_lang) -> Code; // Obtiene el código del siguiente idioma (circular)
|
auto getNextLangCode(Code current_lang) -> Code; // Obtiene el código del siguiente idioma (circular)
|
||||||
|
|||||||
@@ -17,5 +17,5 @@ auto main(int argc, char* argv[]) -> int {
|
|||||||
auto director = std::make_unique<Director>(argc, std::span<char*>(argv, argc));
|
auto director = std::make_unique<Director>(argc, std::span<char*>(argv, argc));
|
||||||
|
|
||||||
// Bucle principal
|
// Bucle principal
|
||||||
return director->run();
|
return Director::run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ auto ManageHiScoreTable::add(const HiScoreEntry &entry) -> int {
|
|||||||
sort();
|
sort();
|
||||||
|
|
||||||
// Encontrar la posición del nuevo elemento
|
// Encontrar la posición del nuevo elemento
|
||||||
auto it = std::find_if(table_.begin(), table_.end(), [&](const HiScoreEntry &e) { return e.name == entry.name &&
|
auto it = std::ranges::find_if(table_, [&](const HiScoreEntry &e) {
|
||||||
e.score == entry.score &&
|
return e.name == entry.name && e.score == entry.score && e.one_credit_complete == entry.one_credit_complete;
|
||||||
e.one_credit_complete == entry.one_credit_complete; });
|
});
|
||||||
|
|
||||||
int position = -1;
|
int position = -1;
|
||||||
if (it != table_.end()) {
|
if (it != table_.end()) {
|
||||||
@@ -66,7 +66,7 @@ void ManageHiScoreTable::sort() {
|
|||||||
auto operator()(const HiScoreEntry &a, const HiScoreEntry &b) const -> bool { return a.score > b.score; }
|
auto operator()(const HiScoreEntry &a, const HiScoreEntry &b) const -> bool { return a.score > b.score; }
|
||||||
} score_descending_comparator;
|
} score_descending_comparator;
|
||||||
|
|
||||||
std::sort(table_.begin(), table_.end(), score_descending_comparator);
|
std::ranges::sort(table_, score_descending_comparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Carga la tabla desde un fichero
|
// Carga la tabla desde un fichero
|
||||||
|
|||||||
@@ -3,26 +3,21 @@
|
|||||||
#include <string> // Para std::string
|
#include <string> // Para std::string
|
||||||
#include <vector> // Para std::vector
|
#include <vector> // Para std::vector
|
||||||
|
|
||||||
/*
|
// --- Estructuras ---
|
||||||
Esta clase sirve para añadir elementos HiScoreEntry a un vector (tabla), de manera
|
|
||||||
que la tabla siempre está ordenada.
|
|
||||||
|
|
||||||
Además tiene un método para dejar la tabla con sus valores iniciales y métodos para
|
|
||||||
leer y escribir la tabla a un fichero.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// --- Estructura para las entradas de la tabla de records ---
|
|
||||||
struct HiScoreEntry {
|
struct HiScoreEntry {
|
||||||
std::string name; // Nombre
|
std::string name; // Nombre
|
||||||
int score; // Puntuación
|
int score; // Puntuación
|
||||||
bool one_credit_complete; // Indica si se ha conseguido 1CC
|
bool one_credit_complete; // Indica si se ha conseguido 1CC
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
explicit HiScoreEntry(const std::string &n = "", int s = 0, bool occ = false)
|
explicit HiScoreEntry(const std::string &name = "", int score = 0, bool one_credit_complete = false)
|
||||||
: name(n.substr(0, 6)), score(s), one_credit_complete(occ) {}
|
: name(name.substr(0, 6)),
|
||||||
|
score(score),
|
||||||
|
one_credit_complete(one_credit_complete) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
using Table = std::vector<HiScoreEntry>;
|
// --- Tipos ---
|
||||||
|
using Table = std::vector<HiScoreEntry>; // Tabla de puntuaciones
|
||||||
|
|
||||||
// --- Clase ManageHiScoreTable ---
|
// --- Clase ManageHiScoreTable ---
|
||||||
class ManageHiScoreTable {
|
class ManageHiScoreTable {
|
||||||
@@ -30,10 +25,10 @@ class ManageHiScoreTable {
|
|||||||
// --- Constantes ---
|
// --- Constantes ---
|
||||||
static constexpr int NO_ENTRY = -1;
|
static constexpr int NO_ENTRY = -1;
|
||||||
|
|
||||||
// Constructor y destructor
|
// --- Constructor y destructor ---
|
||||||
explicit ManageHiScoreTable(Table &table)
|
explicit ManageHiScoreTable(Table &table) // Constructor con referencia a tabla
|
||||||
: table_(table) {}
|
: table_(table) {}
|
||||||
~ManageHiScoreTable() = default;
|
~ManageHiScoreTable() = default; // Destructor
|
||||||
|
|
||||||
// --- Métodos públicos ---
|
// --- Métodos públicos ---
|
||||||
void clear(); // Resetea la tabla a los valores por defecto
|
void clear(); // Resetea la tabla a los valores por defecto
|
||||||
|
|||||||
@@ -2,13 +2,14 @@
|
|||||||
|
|
||||||
#include <SDL3/SDL.h> // Para Uint32, SDL_Event
|
#include <SDL3/SDL.h> // Para Uint32, SDL_Event
|
||||||
|
|
||||||
|
// --- Namespace Mouse: gestión del ratón ---
|
||||||
namespace Mouse {
|
namespace Mouse {
|
||||||
// --- Variables de estado del cursor ---
|
// --- Variables de estado del cursor ---
|
||||||
extern Uint32 cursor_hide_time; // Tiempo en milisegundos para ocultar el cursor tras inactividad
|
extern Uint32 cursor_hide_time; // Tiempo en milisegundos para ocultar el cursor tras inactividad
|
||||||
extern Uint32 last_mouse_move_time; // Última vez (en ms) que el ratón se movió
|
extern Uint32 last_mouse_move_time; // Última vez (en ms) que el ratón se movió
|
||||||
extern bool cursor_visible; // Indica si el cursor está visible
|
extern bool cursor_visible; // Indica si el cursor está visible
|
||||||
|
|
||||||
// --- Gestión de eventos y visibilidad ---
|
// --- Funciones ---
|
||||||
void handleEvent(const SDL_Event &event); // Procesa eventos de ratón (movimiento, clic, etc.)
|
void handleEvent(const SDL_Event &event); // Procesa eventos de ratón (movimiento, clic, etc.)
|
||||||
void updateCursorVisibility(); // Actualiza la visibilidad del cursor según la inactividad
|
void updateCursorVisibility(); // Actualiza la visibilidad del cursor según la inactividad
|
||||||
} // namespace Mouse
|
} // namespace Mouse
|
||||||
@@ -1,32 +1,32 @@
|
|||||||
#include "moving_sprite.h"
|
#include "moving_sprite.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "texture.h" // Para Texture
|
#include "texture.h" // Para Texture
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos, Rotate rotate, float zoom_w, float zoom_h, SDL_FlipMode flip)
|
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos, Rotate rotate, float horizontal_zoom, float vertical_zoom, SDL_FlipMode flip)
|
||||||
: Sprite(texture, pos),
|
: Sprite(std::move(texture), pos),
|
||||||
|
rotate_(rotate),
|
||||||
|
flip_(flip),
|
||||||
x_(pos.x),
|
x_(pos.x),
|
||||||
y_(pos.y),
|
y_(pos.y),
|
||||||
rotate_(rotate),
|
horizontal_zoom_(horizontal_zoom),
|
||||||
horizontal_zoom_(zoom_w),
|
vertical_zoom_(vertical_zoom) {}
|
||||||
vertical_zoom_(zoom_h),
|
|
||||||
flip_(flip) {}
|
|
||||||
|
|
||||||
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos)
|
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos)
|
||||||
: Sprite(texture, pos),
|
: Sprite(std::move(texture), pos),
|
||||||
|
flip_(SDL_FLIP_NONE),
|
||||||
x_(pos.x),
|
x_(pos.x),
|
||||||
y_(pos.y),
|
y_(pos.y),
|
||||||
|
|
||||||
horizontal_zoom_(1.0F),
|
horizontal_zoom_(1.0F),
|
||||||
vertical_zoom_(1.0F),
|
vertical_zoom_(1.0F) {}
|
||||||
flip_(SDL_FLIP_NONE) {}
|
|
||||||
|
|
||||||
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture)
|
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture)
|
||||||
: Sprite(texture),
|
: Sprite(std::move(texture)),
|
||||||
|
flip_(SDL_FLIP_NONE),
|
||||||
horizontal_zoom_(1.0F),
|
horizontal_zoom_(1.0F),
|
||||||
vertical_zoom_(1.0F),
|
vertical_zoom_(1.0F) { Sprite::clear(); }
|
||||||
flip_(SDL_FLIP_NONE) { Sprite::clear(); }
|
|
||||||
|
|
||||||
// Reinicia todas las variables
|
// Reinicia todas las variables
|
||||||
void MovingSprite::clear() {
|
void MovingSprite::clear() {
|
||||||
|
|||||||
@@ -9,23 +9,21 @@
|
|||||||
|
|
||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
// Clase MovingSprite. Añade movimiento y efectos de rotación, zoom y flip al sprite
|
// --- Clase MovingSprite: añade movimiento y efectos de rotación, zoom y flip al sprite ---
|
||||||
class MovingSprite : public Sprite {
|
class MovingSprite : public Sprite {
|
||||||
public:
|
public:
|
||||||
// --- Estructura para la rotación ---
|
// --- Estructuras ---
|
||||||
struct Rotate {
|
struct Rotate {
|
||||||
bool enabled{false}; // Indica si ha de rotar
|
bool enabled{false}; // Indica si ha de rotar
|
||||||
int counter{0}; // Contador
|
int counter{0}; // Contador
|
||||||
int speed{1}; // Velocidad de giro
|
int speed{1}; // Velocidad de giro
|
||||||
double angle{0.0}; // Ángulo para dibujarlo
|
double angle{0.0}; // Ángulo para dibujarlo
|
||||||
float amount{0.0F}; // Cantidad de grados a girar en cada iteración
|
float amount{0.0F}; // Cantidad de grados a girar en cada iteración
|
||||||
SDL_FPoint center; // Centro de rotación
|
SDL_FPoint center{.x = 0.0F, .y = 0.0F}; // Centro de rotación
|
||||||
|
|
||||||
Rotate() : center({0.0F, 0.0F}) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Constructores y destructor ---
|
// --- Constructores y destructor ---
|
||||||
MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos, MovingSprite::Rotate rotate, float zoom_w, float zoom_h, SDL_FlipMode flip);
|
MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos, MovingSprite::Rotate rotate, float horizontal_zoom, float vertical_zoom, SDL_FlipMode flip);
|
||||||
MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos);
|
MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos);
|
||||||
explicit MovingSprite(std::shared_ptr<Texture> texture);
|
explicit MovingSprite(std::shared_ptr<Texture> texture);
|
||||||
~MovingSprite() override = default;
|
~MovingSprite() override = default;
|
||||||
@@ -36,58 +34,48 @@ class MovingSprite : public Sprite {
|
|||||||
void stop(); // Elimina el movimiento del sprite
|
void stop(); // Elimina el movimiento del sprite
|
||||||
void render() override; // Muestra el sprite por pantalla
|
void render() override; // Muestra el sprite por pantalla
|
||||||
|
|
||||||
// --- Getters de posición y movimiento ---
|
// --- Configuración ---
|
||||||
[[nodiscard]] auto getPosX() const -> float { return x_; }
|
void setPos(SDL_FRect rect); // Establece la posición y el tamaño del objeto
|
||||||
[[nodiscard]] auto getPosY() const -> float { return y_; }
|
void setPos(float pos_x, float pos_y); // Establece la posición del objeto
|
||||||
[[nodiscard]] auto getVelX() const -> float { return vx_; }
|
void setPosX(float pos_x); // Establece la posición X
|
||||||
[[nodiscard]] auto getVelY() const -> float { return vy_; }
|
void setPosY(float pos_y); // Establece la posición Y
|
||||||
[[nodiscard]] auto getAccelX() const -> float { return ax_; }
|
void setVelX(float value) { vx_ = value; } // Establece la velocidad X
|
||||||
[[nodiscard]] auto getAccelY() const -> float { return ay_; }
|
void setVelY(float value) { vy_ = value; } // Establece la velocidad Y
|
||||||
|
void setAccelX(float value) { ax_ = value; } // Establece la aceleración X
|
||||||
|
void setAccelY(float value) { ay_ = value; } // Establece la aceleración Y
|
||||||
|
void setHorizontalZoom(float value) { horizontal_zoom_ = value; } // Establece el zoom horizontal
|
||||||
|
void setVerticalZoom(float value) { vertical_zoom_ = value; } // Establece el zoom vertical
|
||||||
|
void setAngle(double value) { rotate_.angle = value; } // Establece el ángulo
|
||||||
|
void setRotatingCenter(SDL_FPoint point) { rotate_.center = point; } // Establece el centro de rotación
|
||||||
|
void setRotate(bool enable); // Activa o desactiva el efecto de rotación
|
||||||
|
void setRotateSpeed(int value) { rotate_.speed = std::max(1, value); } // Establece la velocidad de rotación
|
||||||
|
void setRotateAmount(double value) { rotate_.amount = value; } // Establece la cantidad de rotación
|
||||||
|
void switchRotate() { rotate_.amount *= -1; } // Cambia el sentido de la rotación
|
||||||
|
void setFlip(SDL_FlipMode flip) { flip_ = flip; } // Establece el flip
|
||||||
|
void flip() { flip_ = (flip_ == SDL_FLIP_HORIZONTAL) ? SDL_FLIP_NONE : SDL_FLIP_HORIZONTAL; } // Cambia el flip
|
||||||
|
|
||||||
// --- Setters de movimiento ---
|
// --- Getters ---
|
||||||
void setVelX(float value) { vx_ = value; }
|
[[nodiscard]] auto getPosX() const -> float { return x_; } // Obtiene la posición X
|
||||||
void setVelY(float value) { vy_ = value; }
|
[[nodiscard]] auto getPosY() const -> float { return y_; } // Obtiene la posición Y
|
||||||
void setAccelX(float value) { ax_ = value; }
|
[[nodiscard]] auto getVelX() const -> float { return vx_; } // Obtiene la velocidad X
|
||||||
void setAccelY(float value) { ay_ = value; }
|
[[nodiscard]] auto getVelY() const -> float { return vy_; } // Obtiene la velocidad Y
|
||||||
|
[[nodiscard]] auto getAccelX() const -> float { return ax_; } // Obtiene la aceleración X
|
||||||
// --- Rotación ---
|
[[nodiscard]] auto getAccelY() const -> float { return ay_; } // Obtiene la aceleración Y
|
||||||
[[nodiscard]] auto isRotating() const -> bool { return rotate_.enabled; }
|
[[nodiscard]] auto isRotating() const -> bool { return rotate_.enabled; } // Verifica si está rotando
|
||||||
void setHorizontalZoom(float value) { horizontal_zoom_ = value; }
|
auto getFlip() -> SDL_FlipMode { return flip_; } // Obtiene el flip
|
||||||
void setVerticalZoom(float value) { vertical_zoom_ = value; }
|
|
||||||
void setAngle(double value) { rotate_.angle = value; }
|
|
||||||
void setRotatingCenter(SDL_FPoint point) { rotate_.center = point; }
|
|
||||||
void setRotate(bool enable); // Activa o desactiva el efecto de rotación
|
|
||||||
void setRotateSpeed(int value) { rotate_.speed = std::max(1, value); }
|
|
||||||
void setRotateAmount(double value) { rotate_.amount = value; }
|
|
||||||
void switchRotate() { rotate_.amount *= -1; } // Cambia el sentido de la rotación
|
|
||||||
|
|
||||||
// --- Flip ---
|
|
||||||
void setFlip(SDL_FlipMode flip) { flip_ = flip; }
|
|
||||||
void flip() { flip_ = (flip_ == SDL_FLIP_HORIZONTAL) ? SDL_FLIP_NONE : SDL_FLIP_HORIZONTAL; }
|
|
||||||
auto getFlip() -> SDL_FlipMode { return flip_; }
|
|
||||||
|
|
||||||
// --- Posición y tamaño ---
|
|
||||||
void setPos(SDL_FRect rect); // Establece la posición y el tamaño del objeto
|
|
||||||
void setPos(float pos_x, float pos_y); // Establece la posición del objeto
|
|
||||||
void setPosX(float pos_x); // Establece la posición X
|
|
||||||
void setPosY(float pos_y); // Establece la posición Y
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// --- Variables de posición y movimiento ---
|
// --- Variables de estado ---
|
||||||
float x_ = 0.0F; // Posición en el eje X
|
|
||||||
float y_ = 0.0F; // Posición en el eje Y
|
|
||||||
|
|
||||||
float vx_ = 0.0F; // Velocidad en el eje X. Cantidad de píxeles a desplazarse
|
|
||||||
float vy_ = 0.0F; // Velocidad en el eje Y. Cantidad de píxeles a desplazarse
|
|
||||||
|
|
||||||
float ax_ = 0.0F; // Aceleración en el eje X. Variación de la velocidad
|
|
||||||
float ay_ = 0.0F; // Aceleración en el eje Y. Variación de la velocidad
|
|
||||||
|
|
||||||
// --- Efectos visuales ---
|
|
||||||
Rotate rotate_; // Variables usadas para controlar la rotación del sprite
|
Rotate rotate_; // Variables usadas para controlar la rotación del sprite
|
||||||
|
SDL_FlipMode flip_; // Indica cómo se voltea el sprite
|
||||||
|
float x_ = 0.0F; // Posición en el eje X
|
||||||
|
float y_ = 0.0F; // Posición en el eje Y
|
||||||
|
float vx_ = 0.0F; // Velocidad en el eje X
|
||||||
|
float vy_ = 0.0F; // Velocidad en el eje Y
|
||||||
|
float ax_ = 0.0F; // Aceleración en el eje X
|
||||||
|
float ay_ = 0.0F; // Aceleración en el eje Y
|
||||||
float horizontal_zoom_; // Zoom aplicado a la anchura
|
float horizontal_zoom_; // Zoom aplicado a la anchura
|
||||||
float vertical_zoom_; // Zoom aplicado a la altura
|
float vertical_zoom_; // Zoom aplicado a la altura
|
||||||
SDL_FlipMode flip_; // Indica cómo se voltea el sprite
|
|
||||||
|
|
||||||
// --- Métodos internos ---
|
// --- Métodos internos ---
|
||||||
void updateAngle() { rotate_.angle += rotate_.amount; } // Incrementa el valor del ángulo
|
void updateAngle() { rotate_.angle += rotate_.amount; } // Incrementa el valor del ángulo
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <fstream> // Para basic_ostream, operator<<, basic_ostream::operator<<, basic_ofstream, basic_istream, basic_ifstream, ifstream, ofstream
|
#include <fstream> // Para basic_ostream, operator<<, basic_ostream::operator<<, basic_ofstream, basic_istream, basic_ifstream, ifstream, ofstream
|
||||||
#include <functional> // Para function
|
#include <functional> // Para function
|
||||||
#include <map> // Para map, operator==, _Rb_tree_const_iterator
|
#include <map> // Para map, operator==, _Rb_tree_const_iterator
|
||||||
|
#include <ranges> // Para std::ranges::any_of
|
||||||
#include <stdexcept> // Para invalid_argument, out_of_range
|
#include <stdexcept> // Para invalid_argument, out_of_range
|
||||||
#include <string> // Para char_traits, stoi, operator==, operator<<, allocator, string, basic_string, operator<=>, getline
|
#include <string> // Para char_traits, stoi, operator==, operator<<, allocator, string, basic_string, operator<=>, getline
|
||||||
#include <utility> // Para swap, pair
|
#include <utility> // Para swap, pair
|
||||||
@@ -65,7 +66,7 @@ auto loadFromFile() -> bool {
|
|||||||
std::string line;
|
std::string line;
|
||||||
while (std::getline(file, line)) {
|
while (std::getline(file, line)) {
|
||||||
if (line.substr(0, 1) != "#") {
|
if (line.substr(0, 1) != "#") {
|
||||||
int pos = line.find("=");
|
int pos = line.find('=');
|
||||||
if (!set(line.substr(0, pos), line.substr(pos + 1, line.length()))) {
|
if (!set(line.substr(0, pos), line.substr(pos + 1, line.length()))) {
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Unknown parameter: %s", line.substr(0, pos).c_str());
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Unknown parameter: %s", line.substr(0, pos).c_str());
|
||||||
}
|
}
|
||||||
@@ -133,6 +134,7 @@ auto saveToFile() -> bool {
|
|||||||
file << "game.difficulty=" << static_cast<int>(settings.difficulty) << "\n";
|
file << "game.difficulty=" << static_cast<int>(settings.difficulty) << "\n";
|
||||||
file << "game.autofire=" << boolToString(settings.autofire) << "\n";
|
file << "game.autofire=" << boolToString(settings.autofire) << "\n";
|
||||||
file << "game.shutdown_enabled=" << boolToString(settings.shutdown_enabled) << "\n";
|
file << "game.shutdown_enabled=" << boolToString(settings.shutdown_enabled) << "\n";
|
||||||
|
file << "game.params_file=" << settings.params_file << "\n";
|
||||||
|
|
||||||
// Opciones de mandos
|
// Opciones de mandos
|
||||||
file << "\n## CONTROLLERS\n";
|
file << "\n## CONTROLLERS\n";
|
||||||
@@ -207,6 +209,7 @@ auto set(const std::string& var, const std::string& value) -> bool {
|
|||||||
}},
|
}},
|
||||||
{"game.autofire", [](const auto& val) { settings.autofire = stringToBool(val); }},
|
{"game.autofire", [](const auto& val) { settings.autofire = stringToBool(val); }},
|
||||||
{"game.shutdown_enabled", [](const auto& val) { settings.shutdown_enabled = stringToBool(val); }},
|
{"game.shutdown_enabled", [](const auto& val) { settings.shutdown_enabled = stringToBool(val); }},
|
||||||
|
{"game.params_file", [](const auto& val) { settings.params_file = val; }},
|
||||||
// Teclado
|
// Teclado
|
||||||
{"keyboard.player", [](const auto& val) { keyboard.player_id = static_cast<Player::Id>(stoi(val)); }}};
|
{"keyboard.player", [](const auto& val) { keyboard.player_id = static_cast<Player::Id>(stoi(val)); }}};
|
||||||
|
|
||||||
@@ -392,12 +395,10 @@ void GamepadManager::clearUnassignedGamepadSlots() {
|
|||||||
auto GamepadManager::isGamepadAssigned(
|
auto GamepadManager::isGamepadAssigned(
|
||||||
const std::shared_ptr<Input::Gamepad>& physical_gamepad,
|
const std::shared_ptr<Input::Gamepad>& physical_gamepad,
|
||||||
const std::vector<std::shared_ptr<Input::Gamepad>>& assigned_instances) -> bool {
|
const std::vector<std::shared_ptr<Input::Gamepad>>& assigned_instances) -> bool {
|
||||||
for (const auto& assigned : assigned_instances) {
|
return std::ranges::any_of(assigned_instances,
|
||||||
if (assigned == physical_gamepad) {
|
[&physical_gamepad](const auto& assigned) {
|
||||||
return true; // Encontrado, por lo tanto, ya está asignado.
|
return assigned == physical_gamepad;
|
||||||
}
|
});
|
||||||
}
|
|
||||||
return false; // No se encontró en la lista.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convierte un player id a texto segun Lang
|
// Convierte un player id a texto segun Lang
|
||||||
@@ -413,7 +414,7 @@ auto playerIdToString(Player::Id player_id) -> std::string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convierte un texto a player id segun Lang
|
// Convierte un texto a player id segun Lang
|
||||||
auto stringToPlayerId(std::string name) -> Player::Id {
|
auto stringToPlayerId(const std::string& name) -> Player::Id {
|
||||||
if (name == Lang::getText("[SERVICE_MENU] PLAYER1")) {
|
if (name == Lang::getText("[SERVICE_MENU] PLAYER1")) {
|
||||||
return Player::Id::PLAYER1;
|
return Player::Id::PLAYER1;
|
||||||
}
|
}
|
||||||
|
|||||||
114
source/options.h
@@ -11,83 +11,62 @@
|
|||||||
#include <stdexcept> // Para out_of_range, invalid_argument
|
#include <stdexcept> // Para out_of_range, invalid_argument
|
||||||
#include <string> // Para char_traits, string, allocator, operator==, swap, operator<<, basic_string, stoi
|
#include <string> // Para char_traits, string, allocator, operator==, swap, operator<<, basic_string, stoi
|
||||||
#include <string_view> // Para string_view
|
#include <string_view> // Para string_view
|
||||||
|
#include <utility> // Para swap
|
||||||
#include <vector> // Para vector
|
#include <vector> // Para vector
|
||||||
|
|
||||||
|
#include "defaults.h" // Para GameDefaults
|
||||||
#include "difficulty.h" // Para Code
|
#include "difficulty.h" // Para Code
|
||||||
#include "input.h" // Para Input
|
#include "input.h" // Para Input
|
||||||
#include "lang.h" // Para Code
|
#include "lang.h" // Para Code
|
||||||
#include "manage_hiscore_table.h" // Para ManageHiScoreTable, Table
|
#include "manage_hiscore_table.h" // Para ManageHiScoreTable, Table
|
||||||
#include "player.h" // Para Player
|
#include "player.h" // Para Player
|
||||||
|
|
||||||
|
// --- Namespace Options: gestión de configuración y opciones del juego ---
|
||||||
namespace Options {
|
namespace Options {
|
||||||
|
|
||||||
// --- Opciones de ventana ---
|
// --- Estructuras ---
|
||||||
struct Window {
|
struct Window {
|
||||||
std::string caption; // Texto que aparece en la barra de título de la ventana
|
std::string caption = GameDefaults::Options::WINDOW_CAPTION; // Texto que aparece en la barra de título de la ventana
|
||||||
int zoom{2}; // Valor por el que se multiplica el tamaño de la ventana
|
int zoom = GameDefaults::Options::WINDOW_ZOOM; // Valor por el que se multiplica el tamaño de la ventana
|
||||||
int max_zoom{2}; // Tamaño máximo para que la ventana no sea mayor que la pantalla
|
int max_zoom = GameDefaults::Options::WINDOW_MAX_ZOOM; // Tamaño máximo para que la ventana no sea mayor que la pantalla
|
||||||
|
|
||||||
// Constructor por defecto con valores iniciales
|
|
||||||
Window()
|
|
||||||
: caption("Coffee Crisis Arcade Edition") {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Opciones de vídeo ---
|
|
||||||
struct Video {
|
struct Video {
|
||||||
SDL_ScaleMode scale_mode{SDL_ScaleMode::SDL_SCALEMODE_NEAREST}; // Filtro usado para el escalado de la imagen
|
SDL_ScaleMode scale_mode = GameDefaults::Options::VIDEO_SCALE_MODE; // Filtro usado para el escalado de la imagen
|
||||||
bool fullscreen{false}; // Indica si se usa pantalla completa
|
bool fullscreen = GameDefaults::Options::VIDEO_FULLSCREEN; // Indica si se usa pantalla completa
|
||||||
bool vsync{true}; // Indica si se usa vsync
|
bool vsync = GameDefaults::Options::VIDEO_VSYNC; // Indica si se usa vsync
|
||||||
bool integer_scale{true}; // Indica si se usa escalado entero
|
bool integer_scale = GameDefaults::Options::VIDEO_INTEGER_SCALE; // Indica si se usa escalado entero
|
||||||
bool shaders{false}; // Indica si se usan shaders para los filtros de vídeo
|
bool shaders = GameDefaults::Options::VIDEO_SHADERS; // Indica si se usan shaders para los filtros de vídeo
|
||||||
std::string info; // Información sobre el modo de vídeo
|
std::string info; // Información sobre el modo de vídeo
|
||||||
|
|
||||||
// Constructor por defecto con valores iniciales
|
|
||||||
Video() = default;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Opciones de música ---
|
|
||||||
struct Music {
|
struct Music {
|
||||||
bool enabled{true}; // Indica si la música suena o no
|
bool enabled = GameDefaults::Options::MUSIC_ENABLED; // Indica si la música suena o no
|
||||||
int volume{100}; // Volumen de la música
|
int volume = GameDefaults::Options::MUSIC_VOLUME; // Volumen de la música
|
||||||
|
|
||||||
// Constructor por defecto
|
|
||||||
Music() = default;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Opciones de sonido ---
|
|
||||||
struct Sound {
|
struct Sound {
|
||||||
bool enabled{true}; // Indica si los sonidos suenan o no
|
bool enabled = GameDefaults::Options::SOUND_ENABLED; // Indica si los sonidos suenan o no
|
||||||
int volume{100}; // Volumen de los sonidos
|
int volume = GameDefaults::Options::SOUND_VOLUME; // Volumen de los sonidos
|
||||||
|
|
||||||
// Constructor por defecto
|
|
||||||
Sound() = default;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Opciones de audio ---
|
|
||||||
struct Audio {
|
struct Audio {
|
||||||
Music music; // Opciones para la música
|
Music music; // Opciones para la música
|
||||||
Sound sound; // Opciones para los efectos de sonido
|
Sound sound; // Opciones para los efectos de sonido
|
||||||
bool enabled{true}; // Indica si el audio está activo o no
|
bool enabled = GameDefaults::Options::AUDIO_ENABLED; // Indica si el audio está activo o no
|
||||||
int volume{100}; // Volumen general del audio
|
int volume = GameDefaults::Options::AUDIO_VOLUME; // Volumen general del audio
|
||||||
|
|
||||||
// Constructor por defecto
|
|
||||||
Audio() = default;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Opciones de configuración ---
|
|
||||||
struct Settings {
|
struct Settings {
|
||||||
Difficulty::Code difficulty{Difficulty::Code::NORMAL}; // Dificultad del juego
|
Difficulty::Code difficulty = Difficulty::Code::NORMAL; // Dificultad del juego
|
||||||
Lang::Code language{Lang::Code::VALENCIAN}; // Idioma usado en el juego
|
Lang::Code language = Lang::Code::VALENCIAN; // Idioma usado en el juego
|
||||||
bool autofire{true}; // Indicador de autofire
|
bool autofire = GameDefaults::Options::SETTINGS_AUTOFIRE; // Indicador de autofire
|
||||||
bool shutdown_enabled{false}; // Especifica si se puede apagar el sistema
|
bool shutdown_enabled = GameDefaults::Options::SETTINGS_SHUTDOWN_ENABLED; // Especifica si se puede apagar el sistema
|
||||||
Table hi_score_table; // Tabla de mejores puntuaciones
|
Table hi_score_table; // Tabla de mejores puntuaciones
|
||||||
std::vector<int> glowing_entries; // Últimas posiciones de entrada en la tabla
|
std::vector<int> glowing_entries = {ManageHiScoreTable::NO_ENTRY, ManageHiScoreTable::NO_ENTRY}; // Últimas posiciones de entrada en la tabla
|
||||||
std::string config_file; // Ruta al fichero donde guardar la configuración y las opciones del juego
|
std::string config_file; // Ruta al fichero donde guardar la configuración y las opciones del juego
|
||||||
std::string controllers_file; // Ruta al fichero con las configuraciones de los mandos
|
std::string controllers_file; // Ruta al fichero con las configuraciones de los mandos
|
||||||
|
std::string params_file = GameDefaults::Options::PARAMS_FILE; // Ruta al fichero de parámetros del juego
|
||||||
// Constructor por defecto con valores iniciales
|
|
||||||
Settings()
|
|
||||||
: glowing_entries({ManageHiScoreTable::NO_ENTRY, ManageHiScoreTable::NO_ENTRY}) {}
|
|
||||||
|
|
||||||
// Reinicia las últimas entradas de puntuación
|
// Reinicia las últimas entradas de puntuación
|
||||||
void clearLastHiScoreEntries() {
|
void clearLastHiScoreEntries() {
|
||||||
@@ -96,7 +75,6 @@ struct Settings {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Estructura para gamepad individual ---
|
|
||||||
struct Gamepad {
|
struct Gamepad {
|
||||||
std::shared_ptr<Input::Gamepad> instance = nullptr; // Referencia al mando
|
std::shared_ptr<Input::Gamepad> instance = nullptr; // Referencia al mando
|
||||||
std::string name; // Nombre del mando
|
std::string name; // Nombre del mando
|
||||||
@@ -107,7 +85,7 @@ struct Gamepad {
|
|||||||
: player_id(custom_player_id) {}
|
: player_id(custom_player_id) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Manager para los gamepads ---
|
// --- Clases ---
|
||||||
class GamepadManager {
|
class GamepadManager {
|
||||||
public:
|
public:
|
||||||
void init() {
|
void init() {
|
||||||
@@ -144,7 +122,7 @@ class GamepadManager {
|
|||||||
const std::string& name) -> bool {
|
const std::string& name) -> bool {
|
||||||
try {
|
try {
|
||||||
auto& gamepad = getGamepad(player_id);
|
auto& gamepad = getGamepad(player_id);
|
||||||
gamepad.instance = instance;
|
gamepad.instance = std::move(instance);
|
||||||
gamepad.name = name;
|
gamepad.name = name;
|
||||||
return true;
|
return true;
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception&) {
|
||||||
@@ -161,7 +139,7 @@ class GamepadManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void resyncGamepadsWithPlayers() {
|
void resyncGamepadsWithPlayers() {
|
||||||
for (auto player : players_) {
|
for (const auto& player : players_) {
|
||||||
switch (player->getId()) {
|
switch (player->getId()) {
|
||||||
case Player::Id::PLAYER1:
|
case Player::Id::PLAYER1:
|
||||||
player->setGamepad(gamepads_[0].instance);
|
player->setGamepad(gamepads_[0].instance);
|
||||||
@@ -226,11 +204,11 @@ class GamepadManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addPlayer(std::shared_ptr<Player> player) { players_.push_back(player); } // Añade un jugador a la lista
|
void addPlayer(const std::shared_ptr<Player>& player) { players_.push_back(player); } // Añade un jugador a la lista
|
||||||
void clearPlayers() { players_.clear(); } // Limpia la lista de jugadores
|
void clearPlayers() { players_.clear(); } // Limpia la lista de jugadores
|
||||||
|
|
||||||
// Asigna el mando a un jugador
|
// Asigna el mando a un jugador
|
||||||
void assignTo(Input::Gamepad gamepad, Player::Id player_id) {
|
void assignTo(const Input::Gamepad& gamepad, Player::Id player_id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Asigna los mandos físicos basándose en la configuración actual de nombres.
|
// Asigna los mandos físicos basándose en la configuración actual de nombres.
|
||||||
@@ -279,8 +257,8 @@ struct Keyboard {
|
|||||||
Player::Id player_id = Player::Id::PLAYER1; // Jugador asociado al teclado
|
Player::Id player_id = Player::Id::PLAYER1; // Jugador asociado al teclado
|
||||||
std::vector<std::shared_ptr<Player>> players; // Punteros a los jugadores
|
std::vector<std::shared_ptr<Player>> players; // Punteros a los jugadores
|
||||||
|
|
||||||
void addPlayer(std::shared_ptr<Player> player) { players.push_back(player); } // Añade un jugador a la lista
|
void addPlayer(const std::shared_ptr<Player>& player) { players.push_back(player); } // Añade un jugador a la lista
|
||||||
void clearPlayers() { players.clear(); } // Limpia la lista de jugadores
|
void clearPlayers() { players.clear(); } // Limpia la lista de jugadores
|
||||||
|
|
||||||
// Asigna el teclado a un jugador
|
// Asigna el teclado a un jugador
|
||||||
void assignTo(Player::Id player_id) {
|
void assignTo(Player::Id player_id) {
|
||||||
@@ -291,17 +269,13 @@ struct Keyboard {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Opciones pendientes de aplicar ---
|
|
||||||
struct PendingChanges {
|
struct PendingChanges {
|
||||||
Lang::Code new_language{Lang::Code::VALENCIAN}; // Idioma en espera de aplicar
|
Lang::Code new_language = Lang::Code::VALENCIAN; // Idioma en espera de aplicar
|
||||||
Difficulty::Code new_difficulty{Difficulty::Code::NORMAL}; // Dificultad en espera de aplicar
|
Difficulty::Code new_difficulty = Difficulty::Code::NORMAL; // Dificultad en espera de aplicar
|
||||||
bool has_pending_changes{false}; // Indica si hay cambios pendientes
|
bool has_pending_changes = false; // Indica si hay cambios pendientes
|
||||||
|
|
||||||
// Constructor por defecto con valores iniciales
|
|
||||||
PendingChanges() = default;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Variables globales ---
|
// --- Variables ---
|
||||||
extern Window window; // Opciones de la ventana
|
extern Window window; // Opciones de la ventana
|
||||||
extern Settings settings; // Opciones del juego
|
extern Settings settings; // Opciones del juego
|
||||||
extern Video video; // Opciones de vídeo
|
extern Video video; // Opciones de vídeo
|
||||||
@@ -310,7 +284,7 @@ extern GamepadManager gamepad_manager; // Manager de mandos para cada jugador
|
|||||||
extern Keyboard keyboard; // Opciones para el teclado
|
extern Keyboard keyboard; // Opciones para el teclado
|
||||||
extern PendingChanges pending_changes; // Opciones que se aplican al cerrar
|
extern PendingChanges pending_changes; // Opciones que se aplican al cerrar
|
||||||
|
|
||||||
// --- Funciones de configuración ---
|
// --- Funciones ---
|
||||||
void init(); // Inicializa las opciones del programa
|
void init(); // Inicializa las opciones del programa
|
||||||
void setConfigFile(const std::string& file_path); // Establece el fichero de configuración
|
void setConfigFile(const std::string& file_path); // Establece el fichero de configuración
|
||||||
void setControllersFile(const std::string& file_path); // Establece el fichero de configuración de mandos
|
void setControllersFile(const std::string& file_path); // Establece el fichero de configuración de mandos
|
||||||
@@ -321,7 +295,7 @@ void swapKeyboard();
|
|||||||
void swapControllers(); // Intercambia los jugadores asignados a los dos primeros mandos
|
void swapControllers(); // Intercambia los jugadores asignados a los dos primeros mandos
|
||||||
auto getPlayerWhoUsesKeyboard() -> Player::Id; // Averigua quién está usando el teclado
|
auto getPlayerWhoUsesKeyboard() -> Player::Id; // Averigua quién está usando el teclado
|
||||||
auto playerIdToString(Player::Id player_id) -> std::string; // Convierte un player id a texto segun Lang
|
auto playerIdToString(Player::Id player_id) -> std::string; // Convierte un player id a texto segun Lang
|
||||||
auto stringToPlayerId(std::string name) -> Player::Id; // Convierte un texto a player id segun Lang
|
auto stringToPlayerId(const std::string& name) -> Player::Id; // Convierte un texto a player id segun Lang
|
||||||
void applyPendingChanges(); // Aplica los cambios pendientes copiando los valores a sus variables
|
void applyPendingChanges(); // Aplica los cambios pendientes copiando los valores a sus variables
|
||||||
void checkPendingChanges(); // Verifica si hay cambios pendientes
|
void checkPendingChanges(); // Verifica si hay cambios pendientes
|
||||||
auto assignGamepadByName(const std::string& gamepad_name, Player::Id player_id) -> bool; // Buscar y asignar un mando disponible por nombre
|
auto assignGamepadByName(const std::string& gamepad_name, Player::Id player_id) -> bool; // Buscar y asignar un mando disponible por nombre
|
||||||
|
|||||||
250
source/param.cpp
@@ -10,93 +10,42 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "color.h"
|
#include "color.h"
|
||||||
|
#include "ui/notifier.h" // Para Notifier::Position
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
// Variable global - ahora se inicializa automáticamente con valores por defecto
|
||||||
Param param;
|
Param param;
|
||||||
|
|
||||||
// Calcula variables a partir de otras variables
|
// Declaraciones de funciones privadas
|
||||||
void precalculateZones();
|
namespace {
|
||||||
|
|
||||||
// Asigna variables a partir de dos cadenas
|
|
||||||
auto setParams(const std::string& var, const std::string& value) -> bool;
|
auto setParams(const std::string& var, const std::string& value) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
// Establece valores por defecto a las variables
|
// Implementación del método privado de Param
|
||||||
void initParam() {
|
void Param::precalculateZones() {
|
||||||
// GAME
|
// playArea - cálculos basados en el rectángulo actual
|
||||||
param.game.width = 320;
|
game.play_area.center_x = game.play_area.rect.w / 2;
|
||||||
param.game.height = 256;
|
game.play_area.first_quarter_x = game.play_area.rect.w / 4;
|
||||||
param.game.item_size = 20;
|
game.play_area.third_quarter_x = game.play_area.rect.w / 4 * 3;
|
||||||
param.game.game_area.rect = {0, 0, param.game.width, param.game.height};
|
game.play_area.center_y = game.play_area.rect.h / 2;
|
||||||
param.game.play_area.rect = {0, 0, param.game.width, 216};
|
game.play_area.first_quarter_y = game.play_area.rect.h / 4;
|
||||||
param.game.name_entry_idle_time = 10;
|
game.play_area.third_quarter_y = game.play_area.rect.h / 4 * 3;
|
||||||
param.game.name_entry_total_time = 60;
|
|
||||||
param.game.speed = 15;
|
|
||||||
param.game.hit_stop = true;
|
|
||||||
param.game.hit_stop_ms = 300;
|
|
||||||
precalculateZones();
|
|
||||||
|
|
||||||
// SCOREBOARD
|
// gameArea - cálculos basados en width y height actuales
|
||||||
param.scoreboard.rect = {0, 216, param.game.width, 40};
|
game.game_area.rect = {.x = 0, .y = 0, .w = game.width, .h = game.height};
|
||||||
param.scoreboard.separator_autocolor = false;
|
game.game_area.center_x = game.game_area.rect.w / 2;
|
||||||
param.scoreboard.separator_color = Color();
|
game.game_area.first_quarter_x = game.game_area.rect.w / 4;
|
||||||
param.scoreboard.easy_color = Color();
|
game.game_area.third_quarter_x = game.game_area.rect.w / 4 * 3;
|
||||||
param.scoreboard.normal_color = Color();
|
game.game_area.center_y = game.game_area.rect.h / 2;
|
||||||
param.scoreboard.hard_color = Color();
|
game.game_area.first_quarter_y = game.game_area.rect.h / 4;
|
||||||
param.scoreboard.text_autocolor = false;
|
game.game_area.third_quarter_y = game.game_area.rect.h / 4 * 3;
|
||||||
param.scoreboard.text_color1 = Color();
|
|
||||||
param.scoreboard.text_color2 = Color();
|
|
||||||
param.scoreboard.skip_countdown_value = 8;
|
|
||||||
|
|
||||||
// FADE
|
|
||||||
param.fade.num_squares_width = param.game.width / 2;
|
|
||||||
param.fade.num_squares_height = param.game.height / 2;
|
|
||||||
param.fade.random_squares_delay = 1;
|
|
||||||
param.fade.random_squares_mult = 500;
|
|
||||||
param.fade.post_duration = 80;
|
|
||||||
param.fade.venetian_size = 16;
|
|
||||||
|
|
||||||
// TITLE
|
|
||||||
param.title.press_start_position = 160;
|
|
||||||
param.title.title_duration = 800;
|
|
||||||
param.title.arcade_edition_position = 123;
|
|
||||||
param.title.title_c_c_position = 11;
|
|
||||||
param.title.bg_color = Color(255, 255, 255);
|
|
||||||
|
|
||||||
// BACKGROUND
|
|
||||||
param.background.attenuate_color = Color(255, 255, 255, 0);
|
|
||||||
|
|
||||||
// BALLOONS
|
|
||||||
param.balloon.settings.at(0) = ParamBalloon::Settings(0.09F, 2.60F);
|
|
||||||
param.balloon.settings.at(1) = ParamBalloon::Settings(0.10F, 3.50F);
|
|
||||||
param.balloon.settings.at(2) = ParamBalloon::Settings(0.10F, 4.50F);
|
|
||||||
param.balloon.settings.at(3) = ParamBalloon::Settings(0.10F, 4.95F);
|
|
||||||
|
|
||||||
param.balloon.color.at(0) = "blue";
|
|
||||||
param.balloon.color.at(1) = "orange";
|
|
||||||
param.balloon.color.at(2) = "red";
|
|
||||||
param.balloon.color.at(3) = "green";
|
|
||||||
|
|
||||||
param.balloon.bouncing_sound = false;
|
|
||||||
|
|
||||||
// NOTIFICATION
|
|
||||||
param.notification.pos_v = NotifyPosition::TOP;
|
|
||||||
param.notification.pos_h = NotifyPosition::LEFT;
|
|
||||||
param.notification.sound = false;
|
|
||||||
param.notification.color = Color(48, 48, 48);
|
|
||||||
|
|
||||||
// INTRO
|
|
||||||
param.intro.bg_color = Color::fromHex("543149");
|
|
||||||
param.intro.card_color = Color::fromHex("CBDBFC");
|
|
||||||
param.intro.shadow_color = Color::fromHex("00000080");
|
|
||||||
param.intro.text_distance_from_bottom = 48;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Carga los parámetros desde un archivo
|
// Carga los parámetros desde un archivo
|
||||||
void loadParamsFromFile(const std::string& file_path) {
|
void loadParamsFromFile(const std::string& file_path) {
|
||||||
// Inicializa los parámetros con valores por defecto
|
// Los parámetros ya están inicializados con valores por defecto
|
||||||
initParam();
|
// Solo necesitamos abrir el archivo y sobrescribir los valores que aparezcan
|
||||||
|
|
||||||
// Abre el archivo
|
|
||||||
std::ifstream file(file_path);
|
std::ifstream file(file_path);
|
||||||
if (!file.is_open()) {
|
if (!file.is_open()) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo abrir el archivo %s", file_path.c_str());
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo abrir el archivo %s", file_path.c_str());
|
||||||
@@ -106,8 +55,9 @@ void loadParamsFromFile(const std::string& file_path) {
|
|||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\nReading file: %s", getFileName(file_path).c_str());
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\nReading file: %s", getFileName(file_path).c_str());
|
||||||
|
|
||||||
std::string line;
|
std::string line;
|
||||||
std::string param1;
|
std::string param_name;
|
||||||
std::string param2;
|
std::string param_value;
|
||||||
|
|
||||||
while (std::getline(file, line)) {
|
while (std::getline(file, line)) {
|
||||||
// Elimina comentarios
|
// Elimina comentarios
|
||||||
auto comment_pos = line.find('#');
|
auto comment_pos = line.find('#');
|
||||||
@@ -117,21 +67,23 @@ void loadParamsFromFile(const std::string& file_path) {
|
|||||||
|
|
||||||
// Usa un stream para separar palabras
|
// Usa un stream para separar palabras
|
||||||
std::istringstream iss(line);
|
std::istringstream iss(line);
|
||||||
if (iss >> param1 >> param2) {
|
if (iss >> param_name >> param_value) {
|
||||||
if (!setParams(param1, param2)) {
|
if (!setParams(param_name, param_value)) {
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Parámetro desconocido: %s", param1.c_str());
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Parámetro desconocido: %s", param_name.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cierra el archivo
|
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
// Realiza cálculos adicionales después de cargar los parámetros
|
// Recalcula las zonas después de cargar todos los parámetros
|
||||||
precalculateZones();
|
param.precalculateZones();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implementación local de setParams
|
||||||
|
namespace {
|
||||||
auto setParams(const std::string& var, const std::string& value) -> bool {
|
auto setParams(const std::string& var, const std::string& value) -> bool {
|
||||||
|
// Mapas estáticos para diferentes tipos de parámetros
|
||||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> INT_PARAMS = {
|
static const std::unordered_map<std::string, std::function<void(const std::string&)>> INT_PARAMS = {
|
||||||
{"game.width", [](const std::string& v) { param.game.width = std::stoi(v); }},
|
{"game.width", [](const std::string& v) { param.game.width = std::stoi(v); }},
|
||||||
{"game.height", [](const std::string& v) { param.game.height = std::stoi(v); }},
|
{"game.height", [](const std::string& v) { param.game.height = std::stoi(v); }},
|
||||||
@@ -145,9 +97,8 @@ auto setParams(const std::string& var, const std::string& value) -> bool {
|
|||||||
{"game.hit_stop_ms", [](const std::string& v) { param.game.hit_stop_ms = std::stoi(v); }},
|
{"game.hit_stop_ms", [](const std::string& v) { param.game.hit_stop_ms = std::stoi(v); }},
|
||||||
{"fade.num_squares_width", [](const std::string& v) { param.fade.num_squares_width = std::stoi(v); }},
|
{"fade.num_squares_width", [](const std::string& v) { param.fade.num_squares_width = std::stoi(v); }},
|
||||||
{"fade.num_squares_height", [](const std::string& v) { param.fade.num_squares_height = std::stoi(v); }},
|
{"fade.num_squares_height", [](const std::string& v) { param.fade.num_squares_height = std::stoi(v); }},
|
||||||
{"fade.random_squares_delay", [](const std::string& v) { param.fade.random_squares_delay = std::stoi(v); }},
|
{"fade.random_squares_duration_ms", [](const std::string& v) { param.fade.random_squares_duration_ms = std::stoi(v); }},
|
||||||
{"fade.random_squares_mult", [](const std::string& v) { param.fade.random_squares_mult = std::stoi(v); }},
|
{"fade.post_duration_ms", [](const std::string& v) { param.fade.post_duration_ms = std::stoi(v); }},
|
||||||
{"fade.post_duration", [](const std::string& v) { param.fade.post_duration = std::stoi(v); }},
|
|
||||||
{"fade.venetian_size", [](const std::string& v) { param.fade.venetian_size = std::stoi(v); }},
|
{"fade.venetian_size", [](const std::string& v) { param.fade.venetian_size = std::stoi(v); }},
|
||||||
{"scoreboard.rect.x", [](const std::string& v) { param.scoreboard.rect.x = std::stoi(v); }},
|
{"scoreboard.rect.x", [](const std::string& v) { param.scoreboard.rect.x = std::stoi(v); }},
|
||||||
{"scoreboard.rect.y", [](const std::string& v) { param.scoreboard.rect.y = std::stoi(v); }},
|
{"scoreboard.rect.y", [](const std::string& v) { param.scoreboard.rect.y = std::stoi(v); }},
|
||||||
@@ -175,11 +126,42 @@ auto setParams(const std::string& var, const std::string& value) -> bool {
|
|||||||
{"service_menu.text_color", [](const std::string& v) { param.service_menu.text_color = Color::fromHex(v); }},
|
{"service_menu.text_color", [](const std::string& v) { param.service_menu.text_color = Color::fromHex(v); }},
|
||||||
{"service_menu.selected_color", [](const std::string& v) { param.service_menu.selected_color = Color::fromHex(v); }},
|
{"service_menu.selected_color", [](const std::string& v) { param.service_menu.selected_color = Color::fromHex(v); }},
|
||||||
{"service_menu.bg_color", [](const std::string& v) { param.service_menu.bg_color = Color::fromHex(v); }},
|
{"service_menu.bg_color", [](const std::string& v) { param.service_menu.bg_color = Color::fromHex(v); }},
|
||||||
|
{"service_menu.window_message.bg_color", [](const std::string& v) { param.service_menu.window_message.bg_color = Color::fromHex(v); }},
|
||||||
|
{"service_menu.window_message.border_color", [](const std::string& v) { param.service_menu.window_message.border_color = Color::fromHex(v); }},
|
||||||
|
{"service_menu.window_message.title_color", [](const std::string& v) { param.service_menu.window_message.title_color = Color::fromHex(v); }},
|
||||||
|
{"service_menu.window_message.text_color", [](const std::string& v) { param.service_menu.window_message.text_color = Color::fromHex(v); }},
|
||||||
{"intro.bg_color", [](const std::string& v) { param.intro.bg_color = Color::fromHex(v); }},
|
{"intro.bg_color", [](const std::string& v) { param.intro.bg_color = Color::fromHex(v); }},
|
||||||
{"intro.card_color", [](const std::string& v) { param.intro.card_color = Color::fromHex(v); }},
|
{"intro.card_color", [](const std::string& v) { param.intro.card_color = Color::fromHex(v); }},
|
||||||
{"intro.shadow_color", [](const std::string& v) { param.intro.shadow_color = Color::fromHex(v); }},
|
{"intro.shadow_color", [](const std::string& v) { param.intro.shadow_color = Color::fromHex(v); }},
|
||||||
{"debug.color", [](const std::string& v) { param.debug.color = Color::fromHex(v); }},
|
{"debug.color", [](const std::string& v) { param.debug.color = Color::fromHex(v); }},
|
||||||
{"resource.color", [](const std::string& v) { param.resource.color = Color::fromHex(v); }}};
|
{"resource.color", [](const std::string& v) { param.resource.color = Color::fromHex(v); }},
|
||||||
|
{"game.item_text_outline_color", [](const std::string& v) { param.game.item_text_outline_color = Color::fromHex(v); }},
|
||||||
|
{"player.default_shirt[0].darkest", [](const std::string& v) { param.player.default_shirt[0].darkest = Color::fromHex(v); }},
|
||||||
|
{"player.default_shirt[0].dark", [](const std::string& v) { param.player.default_shirt[0].dark = Color::fromHex(v); }},
|
||||||
|
{"player.default_shirt[0].base", [](const std::string& v) { param.player.default_shirt[0].base = Color::fromHex(v); }},
|
||||||
|
{"player.default_shirt[0].light", [](const std::string& v) { param.player.default_shirt[0].light = Color::fromHex(v); }},
|
||||||
|
{"player.default_shirt[1].darkest", [](const std::string& v) { param.player.default_shirt[1].darkest = Color::fromHex(v); }},
|
||||||
|
{"player.default_shirt[1].dark", [](const std::string& v) { param.player.default_shirt[1].dark = Color::fromHex(v); }},
|
||||||
|
{"player.default_shirt[1].base", [](const std::string& v) { param.player.default_shirt[1].base = Color::fromHex(v); }},
|
||||||
|
{"player.default_shirt[1].light", [](const std::string& v) { param.player.default_shirt[1].light = Color::fromHex(v); }},
|
||||||
|
{"player.one_coffee_shirt[0].darkest", [](const std::string& v) { param.player.one_coffee_shirt[0].darkest = Color::fromHex(v); }},
|
||||||
|
{"player.one_coffee_shirt[0].dark", [](const std::string& v) { param.player.one_coffee_shirt[0].dark = Color::fromHex(v); }},
|
||||||
|
{"player.one_coffee_shirt[0].base", [](const std::string& v) { param.player.one_coffee_shirt[0].base = Color::fromHex(v); }},
|
||||||
|
{"player.one_coffee_shirt[0].light", [](const std::string& v) { param.player.one_coffee_shirt[0].light = Color::fromHex(v); }},
|
||||||
|
{"player.one_coffee_shirt[1].darkest", [](const std::string& v) { param.player.one_coffee_shirt[1].darkest = Color::fromHex(v); }},
|
||||||
|
{"player.one_coffee_shirt[1].dark", [](const std::string& v) { param.player.one_coffee_shirt[1].dark = Color::fromHex(v); }},
|
||||||
|
{"player.one_coffee_shirt[1].base", [](const std::string& v) { param.player.one_coffee_shirt[1].base = Color::fromHex(v); }},
|
||||||
|
{"player.one_coffee_shirt[1].light", [](const std::string& v) { param.player.one_coffee_shirt[1].light = Color::fromHex(v); }},
|
||||||
|
{"player.two_coffee_shirt[0].darkest", [](const std::string& v) { param.player.two_coffee_shirt[0].darkest = Color::fromHex(v); }},
|
||||||
|
{"player.two_coffee_shirt[0].dark", [](const std::string& v) { param.player.two_coffee_shirt[0].dark = Color::fromHex(v); }},
|
||||||
|
{"player.two_coffee_shirt[0].base", [](const std::string& v) { param.player.two_coffee_shirt[0].base = Color::fromHex(v); }},
|
||||||
|
{"player.two_coffee_shirt[0].light", [](const std::string& v) { param.player.two_coffee_shirt[0].light = Color::fromHex(v); }},
|
||||||
|
{"player.two_coffee_shirt[1].darkest", [](const std::string& v) { param.player.two_coffee_shirt[1].darkest = Color::fromHex(v); }},
|
||||||
|
{"player.two_coffee_shirt[1].dark", [](const std::string& v) { param.player.two_coffee_shirt[1].dark = Color::fromHex(v); }},
|
||||||
|
{"player.two_coffee_shirt[1].base", [](const std::string& v) { param.player.two_coffee_shirt[1].base = Color::fromHex(v); }},
|
||||||
|
{"player.two_coffee_shirt[1].light", [](const std::string& v) { param.player.two_coffee_shirt[1].light = Color::fromHex(v); }},
|
||||||
|
{"player.outline_color[0]", [](const std::string& v) { param.player.outline_color[0] = Color::fromHex(v); }},
|
||||||
|
{"player.outline_color[1]", [](const std::string& v) { param.player.outline_color[1] = Color::fromHex(v); }}};
|
||||||
|
|
||||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> BOOL_PARAMS = {
|
static const std::unordered_map<std::string, std::function<void(const std::string&)>> BOOL_PARAMS = {
|
||||||
{"game.hit_stop", [](const std::string& v) { param.game.hit_stop = stringToBool(v); }},
|
{"game.hit_stop", [](const std::string& v) { param.game.hit_stop = stringToBool(v); }},
|
||||||
@@ -197,15 +179,67 @@ auto setParams(const std::string& var, const std::string& value) -> bool {
|
|||||||
{"balloon.settings[2].vel", [](const std::string& v) { param.balloon.settings.at(2).vel = std::stof(v); }},
|
{"balloon.settings[2].vel", [](const std::string& v) { param.balloon.settings.at(2).vel = std::stof(v); }},
|
||||||
{"balloon.settings[2].grav", [](const std::string& v) { param.balloon.settings.at(2).grav = std::stof(v); }},
|
{"balloon.settings[2].grav", [](const std::string& v) { param.balloon.settings.at(2).grav = std::stof(v); }},
|
||||||
{"balloon.settings[3].vel", [](const std::string& v) { param.balloon.settings.at(3).vel = std::stof(v); }},
|
{"balloon.settings[3].vel", [](const std::string& v) { param.balloon.settings.at(3).vel = std::stof(v); }},
|
||||||
{"balloon.settings[3].grav", [](const std::string& v) { param.balloon.settings.at(3).grav = std::stof(v); }}};
|
{"balloon.settings[3].grav", [](const std::string& v) { param.balloon.settings.at(3).grav = std::stof(v); }},
|
||||||
|
{"tabe.min_spawn_time", [](const std::string& v) { param.tabe.min_spawn_time = std::stof(v); }},
|
||||||
|
{"tabe.max_spawn_time", [](const std::string& v) { param.tabe.max_spawn_time = std::stof(v); }},
|
||||||
|
{"service_menu.window_message.padding", [](const std::string& v) { param.service_menu.window_message.padding = std::stof(v); }},
|
||||||
|
{"service_menu.window_message.line_spacing", [](const std::string& v) { param.service_menu.window_message.line_spacing = std::stof(v); }},
|
||||||
|
{"service_menu.window_message.title_separator_spacing", [](const std::string& v) { param.service_menu.window_message.title_separator_spacing = std::stof(v); }},
|
||||||
|
{"service_menu.window_message.min_width", [](const std::string& v) { param.service_menu.window_message.min_width = std::stof(v); }},
|
||||||
|
{"service_menu.window_message.min_height", [](const std::string& v) { param.service_menu.window_message.min_height = std::stof(v); }},
|
||||||
|
{"service_menu.window_message.max_width_ratio", [](const std::string& v) { param.service_menu.window_message.max_width_ratio = std::stof(v); }},
|
||||||
|
{"service_menu.window_message.max_height_ratio", [](const std::string& v) { param.service_menu.window_message.max_height_ratio = std::stof(v); }},
|
||||||
|
{"service_menu.window_message.text_safety_margin", [](const std::string& v) { param.service_menu.window_message.text_safety_margin = std::stof(v); }},
|
||||||
|
{"service_menu.window_message.animation_duration", [](const std::string& v) { param.service_menu.window_message.animation_duration = std::stof(v); }}};
|
||||||
|
|
||||||
|
static const std::unordered_map<std::string, std::function<void(const std::string&)>> INT_PARAMS_EXTRA = {};
|
||||||
|
|
||||||
|
// Colores válidos para globos
|
||||||
|
static const std::unordered_map<std::string, bool> VALID_BALLOON_COLORS = {
|
||||||
|
{"blue", true},
|
||||||
|
{"orange", true},
|
||||||
|
{"red", true},
|
||||||
|
{"green", true}};
|
||||||
|
|
||||||
|
auto validateBalloonColor = [](const std::string& color) -> bool {
|
||||||
|
return VALID_BALLOON_COLORS.find(color) != VALID_BALLOON_COLORS.end();
|
||||||
|
};
|
||||||
|
|
||||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> STRING_PARAMS = {
|
static const std::unordered_map<std::string, std::function<void(const std::string&)>> STRING_PARAMS = {
|
||||||
{"balloon.color[0]", [](const std::string& v) { param.balloon.color.at(0) = v; }},
|
{"balloon.color[0]", [validateBalloonColor](const std::string& v) {
|
||||||
{"balloon.color[1]", [](const std::string& v) { param.balloon.color.at(1) = v; }},
|
if (!validateBalloonColor(v)) {
|
||||||
{"balloon.color[2]", [](const std::string& v) { param.balloon.color.at(2) = v; }},
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'blue' por defecto.", v.c_str());
|
||||||
{"balloon.color[3]", [](const std::string& v) { param.balloon.color.at(3) = v; }}};
|
param.balloon.color.at(0) = "blue";
|
||||||
|
} else {
|
||||||
|
param.balloon.color.at(0) = v;
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
{"balloon.color[1]", [validateBalloonColor](const std::string& v) {
|
||||||
|
if (!validateBalloonColor(v)) {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'orange' por defecto.", v.c_str());
|
||||||
|
param.balloon.color.at(1) = "orange";
|
||||||
|
} else {
|
||||||
|
param.balloon.color.at(1) = v;
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
{"balloon.color[2]", [validateBalloonColor](const std::string& v) {
|
||||||
|
if (!validateBalloonColor(v)) {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'red' por defecto.", v.c_str());
|
||||||
|
param.balloon.color.at(2) = "red";
|
||||||
|
} else {
|
||||||
|
param.balloon.color.at(2) = v;
|
||||||
|
}
|
||||||
|
}},
|
||||||
|
{"balloon.color[3]", [validateBalloonColor](const std::string& v) {
|
||||||
|
if (!validateBalloonColor(v)) {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'green' por defecto.", v.c_str());
|
||||||
|
param.balloon.color.at(3) = "green";
|
||||||
|
} else {
|
||||||
|
param.balloon.color.at(3) = v;
|
||||||
|
}
|
||||||
|
}}};
|
||||||
|
|
||||||
// Intentar cada mapa de parámetros
|
// Lambda para intentar cada mapa de parámetros
|
||||||
auto try_map = [&](const auto& param_map) -> bool {
|
auto try_map = [&](const auto& param_map) -> bool {
|
||||||
auto it = param_map.find(var);
|
auto it = param_map.find(var);
|
||||||
if (it != param_map.end()) {
|
if (it != param_map.end()) {
|
||||||
@@ -215,6 +249,7 @@ auto setParams(const std::string& var, const std::string& value) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Intentar con todos los mapas
|
||||||
if (try_map(INT_PARAMS) || try_map(COLOR_PARAMS) || try_map(BOOL_PARAMS) ||
|
if (try_map(INT_PARAMS) || try_map(COLOR_PARAMS) || try_map(BOOL_PARAMS) ||
|
||||||
try_map(FLOAT_PARAMS) || try_map(STRING_PARAMS)) {
|
try_map(FLOAT_PARAMS) || try_map(STRING_PARAMS)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -223,39 +258,20 @@ auto setParams(const std::string& var, const std::string& value) -> bool {
|
|||||||
// Casos especiales que necesitan lógica personalizada
|
// Casos especiales que necesitan lógica personalizada
|
||||||
if (var == "notification.pos_h") {
|
if (var == "notification.pos_h") {
|
||||||
if (value == "LEFT") {
|
if (value == "LEFT") {
|
||||||
param.notification.pos_h = NotifyPosition::LEFT;
|
param.notification.pos_h = Notifier::Position::LEFT;
|
||||||
} else if (value == "MIDDLE") {
|
} else if (value == "MIDDLE") {
|
||||||
param.notification.pos_h = NotifyPosition::MIDDLE;
|
param.notification.pos_h = Notifier::Position::MIDDLE;
|
||||||
} else {
|
} else {
|
||||||
param.notification.pos_h = NotifyPosition::RIGHT;
|
param.notification.pos_h = Notifier::Position::RIGHT;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (var == "notification.pos_v") {
|
if (var == "notification.pos_v") {
|
||||||
param.notification.pos_v = value == "TOP" ? NotifyPosition::TOP : NotifyPosition::BOTTOM;
|
param.notification.pos_v = value == "TOP" ? Notifier::Position::TOP : Notifier::Position::BOTTOM;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // Parámetro no encontrado
|
return false; // Parámetro no encontrado
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
// Calcula variables a partir de otras variables
|
|
||||||
void precalculateZones() {
|
|
||||||
// playArea
|
|
||||||
param.game.play_area.center_x = param.game.play_area.rect.w / 2;
|
|
||||||
param.game.play_area.first_quarter_x = param.game.play_area.rect.w / 4;
|
|
||||||
param.game.play_area.third_quarter_x = param.game.play_area.rect.w / 4 * 3;
|
|
||||||
param.game.play_area.center_y = param.game.play_area.rect.h / 2;
|
|
||||||
param.game.play_area.first_quarter_y = param.game.play_area.rect.h / 4;
|
|
||||||
param.game.play_area.third_quarter_y = param.game.play_area.rect.h / 4 * 3;
|
|
||||||
|
|
||||||
// gameArea
|
|
||||||
param.game.game_area.rect = {0, 0, param.game.width, param.game.height};
|
|
||||||
param.game.game_area.center_x = param.game.game_area.rect.w / 2;
|
|
||||||
param.game.game_area.first_quarter_x = param.game.game_area.rect.w / 4;
|
|
||||||
param.game.game_area.third_quarter_x = param.game.game_area.rect.w / 4 * 3;
|
|
||||||
param.game.game_area.center_y = param.game.game_area.rect.h / 2;
|
|
||||||
param.game.game_area.first_quarter_y = param.game.game_area.rect.h / 4;
|
|
||||||
param.game.game_area.third_quarter_y = param.game.game_area.rect.h / 4 * 3;
|
|
||||||
}
|
|
||||||
273
source/param.h
@@ -5,134 +5,255 @@
|
|||||||
#include <array> // Para array
|
#include <array> // Para array
|
||||||
#include <string> // Para basic_string, string
|
#include <string> // Para basic_string, string
|
||||||
|
|
||||||
#include "color.h" // Para Color, NotifyPosition (ptr only), Zone
|
#include "color.h" // Para Color, Zone
|
||||||
|
#include "defaults.h" // Para los valores por defecto
|
||||||
|
#include "ui/notifier.h" // Para Notifier::Position
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
// --- Parámetros del juego ---
|
// --- Parámetros del juego ---
|
||||||
struct ParamGame {
|
struct ParamGame {
|
||||||
float width; // Ancho de la resolución nativa del juego
|
float width = GameDefaults::Game::WIDTH;
|
||||||
float height; // Alto de la resolución nativa del juego
|
float height = GameDefaults::Game::HEIGHT;
|
||||||
float item_size; // Tamaño de los ítems del juego
|
float item_size = GameDefaults::Game::ITEM_SIZE;
|
||||||
Zone play_area; // Rectángulo con la posición de la zona de juego
|
Zone play_area{}; // Se inicializa en el constructor de Param
|
||||||
Zone game_area; // Rectángulo con las dimensiones del juego
|
Zone game_area{}; // Se inicializa en el constructor de Param
|
||||||
int name_entry_idle_time; // Segundos para introducir el nombre al finalizar la partida si no se pulsa nada
|
int name_entry_idle_time = GameDefaults::Game::NAME_ENTRY_IDLE_TIME;
|
||||||
int name_entry_total_time; // Segundos totales para introducir el nombre al finalizar la partida
|
int name_entry_total_time = GameDefaults::Game::NAME_ENTRY_TOTAL_TIME;
|
||||||
Uint32 speed; // Velocidad a la que transcurre el juego
|
Uint32 speed = 15; // Este valor no estaba en el archivo de configuración
|
||||||
bool hit_stop; // Indica si debe haber un paro cuando el jugador es golpeado por un globo
|
bool hit_stop = GameDefaults::Game::HIT_STOP;
|
||||||
Uint32 hit_stop_ms; // Cantidad de milisegundos que dura el hit_stop
|
Uint32 hit_stop_ms = GameDefaults::Game::HIT_STOP_MS;
|
||||||
|
Color item_text_outline_color;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Parámetros del fade ---
|
// --- Parámetros del fade ---
|
||||||
struct ParamFade {
|
struct ParamFade {
|
||||||
Color color; // Color del fade
|
Color color = Color::fromHex(GameDefaults::Fade::COLOR);
|
||||||
float num_squares_width; // Cantidad total de cuadraditos en horizontal para el FadeType::RANDOM_SQUARE
|
float num_squares_width = GameDefaults::Fade::NUM_SQUARES_WIDTH;
|
||||||
float num_squares_height; // Cantidad total de cuadraditos en vertical para el FadeType::RANDOM_SQUARE
|
float num_squares_height = GameDefaults::Fade::NUM_SQUARES_HEIGHT;
|
||||||
int random_squares_delay; // Duración entre cada pintado de cuadrados
|
int random_squares_duration_ms = GameDefaults::Fade::RANDOM_SQUARES_DURATION_MS;
|
||||||
int random_squares_mult; // Cantidad de cuadrados que se pintarán cada vez
|
int post_duration_ms = GameDefaults::Fade::POST_DURATION_MS;
|
||||||
int post_duration; // Duración final del fade
|
float venetian_size = GameDefaults::Fade::VENETIAN_SIZE;
|
||||||
float venetian_size; // Altura de los rectángulos para FadeType::VENETIAN
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Parámetros de la pantalla de título ---
|
// --- Parámetros de la pantalla de título ---
|
||||||
struct ParamTitle {
|
struct ParamTitle {
|
||||||
int press_start_position; // Posición del texto para empezar a jugar
|
int press_start_position = GameDefaults::Title::PRESS_START_POSITION;
|
||||||
int title_duration; // Tiempo de inactividad del título
|
int title_duration = GameDefaults::Title::DURATION;
|
||||||
int arcade_edition_position; // Posición del bitmap "Arcade Edition"
|
int arcade_edition_position = GameDefaults::Title::ARCADE_EDITION_POSITION;
|
||||||
int title_c_c_position; // Posición del bitmap "Coffee Crisis"
|
int title_c_c_position = GameDefaults::Title::TITLE_C_C_POSITION;
|
||||||
Color bg_color; // Color para los tiles de fondo
|
Color bg_color = Color::fromHex(GameDefaults::Title::BG_COLOR);
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Parámetros del fondo ---
|
// --- Parámetros del fondo ---
|
||||||
struct ParamBackground {
|
struct ParamBackground {
|
||||||
Color attenuate_color; // Color para atenuar el fondo
|
Color attenuate_color = Color::fromHex(GameDefaults::Background::ATTENUATE_COLOR);
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Parámetros de los globos ---
|
// --- Parámetros de los globos ---
|
||||||
struct ParamBalloon {
|
struct ParamBalloon {
|
||||||
struct Settings {
|
struct Settings {
|
||||||
float grav; // Aceleración en el eje Y. Modifica la velocidad
|
float grav;
|
||||||
float vel; // Velocidad inicial al rebotar contra el suelo
|
float vel;
|
||||||
|
|
||||||
// Constructor
|
// Constructor por defecto
|
||||||
explicit Settings(float grav_val = 0.0F, float vel_val = 0.0F)
|
constexpr Settings(float grav_val = 0.0F, float vel_val = 0.0F)
|
||||||
: grav(grav_val), vel(vel_val) {}
|
: grav(grav_val),
|
||||||
|
vel(vel_val) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::array<Settings, 4> settings;
|
// Inicialización con los valores por defecto desde GameDefaults
|
||||||
std::array<std::string, 4> color;
|
std::array<Settings, 4> settings = {{Settings(GameDefaults::Balloon::SETTINGS[0].grav, GameDefaults::Balloon::SETTINGS[0].vel),
|
||||||
bool bouncing_sound; // Indica si los globos hacer sonido al rebotar
|
Settings(GameDefaults::Balloon::SETTINGS[1].grav, GameDefaults::Balloon::SETTINGS[1].vel),
|
||||||
|
Settings(GameDefaults::Balloon::SETTINGS[2].grav, GameDefaults::Balloon::SETTINGS[2].vel),
|
||||||
|
Settings(GameDefaults::Balloon::SETTINGS[3].grav, GameDefaults::Balloon::SETTINGS[3].vel)}};
|
||||||
|
|
||||||
|
std::array<std::string, 4> color = {{GameDefaults::Balloon::COLORS[0],
|
||||||
|
GameDefaults::Balloon::COLORS[1],
|
||||||
|
GameDefaults::Balloon::COLORS[2],
|
||||||
|
GameDefaults::Balloon::COLORS[3]}};
|
||||||
|
|
||||||
|
bool bouncing_sound = GameDefaults::Balloon::BOUNCING_SOUND;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Parámetros de las notificaciones ---
|
// --- Parámetros de las notificaciones ---
|
||||||
struct ParamNotification {
|
struct ParamNotification {
|
||||||
NotifyPosition pos_h; // Ubicación horizontal de las notificaciones en pantalla
|
Notifier::Position pos_h = GameDefaults::Notification::POS_H;
|
||||||
NotifyPosition pos_v; // Ubicación vertical de las notificaciones en pantalla
|
Notifier::Position pos_v = GameDefaults::Notification::POS_V;
|
||||||
bool sound; // Indica si las notificaciones suenan
|
bool sound = GameDefaults::Notification::SOUND;
|
||||||
Color color; // Color de las notificaciones
|
Color color = Color::fromHex(GameDefaults::Notification::COLOR);
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Parámetros del marcador ---
|
// --- Parámetros del marcador ---
|
||||||
struct ParamScoreboard {
|
struct ParamScoreboard {
|
||||||
SDL_FRect rect; // Posición y tamaño del marcador
|
SDL_FRect rect = {
|
||||||
bool separator_autocolor; // El separado establece su color de forma automatica
|
GameDefaults::Scoreboard::RECT_X,
|
||||||
Color separator_color; // Color del separador si se pone de forma manual
|
GameDefaults::Scoreboard::RECT_Y,
|
||||||
Color easy_color; // Color del marcador segun la dificultad
|
GameDefaults::Scoreboard::RECT_W,
|
||||||
Color normal_color; // Color del marcador segun la dificultad
|
GameDefaults::Scoreboard::RECT_H};
|
||||||
Color hard_color; // Color del marcador segun la dificultad
|
bool separator_autocolor = GameDefaults::Scoreboard::SEPARATOR_AUTOCOLOR;
|
||||||
bool text_autocolor; // El texto establece su color de forma automatica
|
Color separator_color = Color::fromHex(GameDefaults::Scoreboard::SEPARATOR_COLOR);
|
||||||
Color text_color1; // Color del texto
|
Color easy_color = Color::fromHex(GameDefaults::Scoreboard::EASY_COLOR);
|
||||||
Color text_color2; // Color del texto
|
Color normal_color = Color::fromHex(GameDefaults::Scoreboard::NORMAL_COLOR);
|
||||||
int skip_countdown_value; // Valor a partir del cual se puede saltar la cuenta atras
|
Color hard_color = Color::fromHex(GameDefaults::Scoreboard::HARD_COLOR);
|
||||||
|
bool text_autocolor = GameDefaults::Scoreboard::TEXT_AUTOCOLOR;
|
||||||
|
Color text_color1 = Color::fromHex(GameDefaults::Scoreboard::TEXT_COLOR1);
|
||||||
|
Color text_color2 = Color::fromHex(GameDefaults::Scoreboard::TEXT_COLOR2);
|
||||||
|
int skip_countdown_value = GameDefaults::Scoreboard::SKIP_COUNTDOWN_VALUE;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Parámetros del menú de servicio ---
|
// --- Parámetros del menú de servicio ---
|
||||||
struct ParamServiceMenu {
|
struct ParamServiceMenu {
|
||||||
Color title_color;
|
Color title_color = Color::fromHex(GameDefaults::ServiceMenu::TITLE_COLOR);
|
||||||
Color text_color;
|
Color text_color = Color::fromHex(GameDefaults::ServiceMenu::TEXT_COLOR);
|
||||||
Color selected_color;
|
Color selected_color = Color::fromHex(GameDefaults::ServiceMenu::SELECTED_COLOR);
|
||||||
Color bg_color;
|
Color bg_color = Color::fromHex(GameDefaults::ServiceMenu::BG_COLOR);
|
||||||
bool drop_shadow;
|
bool drop_shadow = GameDefaults::ServiceMenu::DROP_SHADOW;
|
||||||
|
|
||||||
|
// Configuración para ventanas de mensaje
|
||||||
|
struct WindowMessage {
|
||||||
|
Color bg_color = Color::fromHex(GameDefaults::ServiceMenu::WindowMessage::BG_COLOR);
|
||||||
|
Color border_color = Color::fromHex(GameDefaults::ServiceMenu::WindowMessage::BORDER_COLOR);
|
||||||
|
Color title_color = Color::fromHex(GameDefaults::ServiceMenu::WindowMessage::TITLE_COLOR);
|
||||||
|
Color text_color = Color::fromHex(GameDefaults::ServiceMenu::WindowMessage::TEXT_COLOR);
|
||||||
|
float padding = GameDefaults::ServiceMenu::WindowMessage::PADDING;
|
||||||
|
float line_spacing = GameDefaults::ServiceMenu::WindowMessage::LINE_SPACING;
|
||||||
|
float title_separator_spacing = GameDefaults::ServiceMenu::WindowMessage::TITLE_SEPARATOR_SPACING;
|
||||||
|
float min_width = GameDefaults::ServiceMenu::WindowMessage::MIN_WIDTH;
|
||||||
|
float min_height = GameDefaults::ServiceMenu::WindowMessage::MIN_HEIGHT;
|
||||||
|
float max_width_ratio = GameDefaults::ServiceMenu::WindowMessage::MAX_WIDTH_RATIO;
|
||||||
|
float max_height_ratio = GameDefaults::ServiceMenu::WindowMessage::MAX_HEIGHT_RATIO;
|
||||||
|
float text_safety_margin = GameDefaults::ServiceMenu::WindowMessage::TEXT_SAFETY_MARGIN;
|
||||||
|
float animation_duration = GameDefaults::ServiceMenu::WindowMessage::ANIMATION_DURATION;
|
||||||
|
} window_message;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Parámetros de la intro ---
|
// --- Parámetros de la intro ---
|
||||||
struct ParamIntro {
|
struct ParamIntro {
|
||||||
Color bg_color;
|
Color bg_color = Color::fromHex(GameDefaults::Intro::BG_COLOR);
|
||||||
Color card_color;
|
Color card_color = Color::fromHex(GameDefaults::Intro::CARD_COLOR);
|
||||||
Color shadow_color;
|
Color shadow_color = Color::fromHex(GameDefaults::Intro::SHADOW_COLOR);
|
||||||
int text_distance_from_bottom;
|
int text_distance_from_bottom = GameDefaults::Intro::TEXT_DISTANCE_FROM_BOTTOM;
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Parámetros para Debug ---
|
// --- Parámetros para Debug ---
|
||||||
struct ParamDebug {
|
struct ParamDebug {
|
||||||
Color color;
|
Color color = Color::fromHex(GameDefaults::Debug::COLOR);
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Parámetros para Resource ---
|
// --- Parámetros para Resource ---
|
||||||
struct ParamResource {
|
struct ParamResource {
|
||||||
Color color;
|
Color color = Color::fromHex(GameDefaults::Resource::COLOR);
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Estructura principal para almacenar todos los parámetros del juego ---
|
// --- Parámetros para Tabe ---
|
||||||
|
struct ParamTabe {
|
||||||
|
float min_spawn_time = GameDefaults::Tabe::MIN_SPAWN_TIME;
|
||||||
|
float max_spawn_time = GameDefaults::Tabe::MAX_SPAWN_TIME;
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- Parámetros del Jugador ---
|
||||||
|
struct ParamPlayer {
|
||||||
|
// Configuración de camisetas del jugador
|
||||||
|
struct Shirt {
|
||||||
|
Color darkest; // Tono más oscuro - bordes y contornos
|
||||||
|
Color dark; // Tono oscuro - sombras
|
||||||
|
Color base; // Tono principal - color base de la camiseta
|
||||||
|
Color light; // Tono claro - zonas iluminadas/highlights
|
||||||
|
|
||||||
|
// Constructor por defecto
|
||||||
|
Shirt() = default;
|
||||||
|
|
||||||
|
// Constructor con tonalidades específicas
|
||||||
|
Shirt(const Color& darkest_tone, const Color& dark_tone, const Color& base_tone, const Color& light_tone)
|
||||||
|
: darkest(darkest_tone),
|
||||||
|
dark(dark_tone),
|
||||||
|
base(base_tone),
|
||||||
|
light(light_tone) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Inicialización con valores por defecto
|
||||||
|
const Shirt default_player0_shirt = Shirt(
|
||||||
|
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER0_DARKEST),
|
||||||
|
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER0_DARK),
|
||||||
|
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER0_BASE),
|
||||||
|
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER0_LIGHT));
|
||||||
|
|
||||||
|
const Shirt default_player1_shirt = Shirt(
|
||||||
|
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER1_DARKEST),
|
||||||
|
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER1_DARK),
|
||||||
|
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER1_BASE),
|
||||||
|
Color::fromHex(GameDefaults::Player::DefaultShirt::PLAYER1_LIGHT));
|
||||||
|
|
||||||
|
std::array<Shirt, 2> default_shirt = {default_player0_shirt, default_player1_shirt};
|
||||||
|
|
||||||
|
const Shirt one_coffee_player0_shirt = Shirt(
|
||||||
|
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER0_DARKEST),
|
||||||
|
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER0_DARK),
|
||||||
|
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER0_BASE),
|
||||||
|
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER0_LIGHT));
|
||||||
|
|
||||||
|
const Shirt one_coffee_player1_shirt = Shirt(
|
||||||
|
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER1_DARKEST),
|
||||||
|
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER1_DARK),
|
||||||
|
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER1_BASE),
|
||||||
|
Color::fromHex(GameDefaults::Player::OneCoffeeShirt::PLAYER1_LIGHT));
|
||||||
|
|
||||||
|
std::array<Shirt, 2> one_coffee_shirt = {one_coffee_player0_shirt, one_coffee_player1_shirt};
|
||||||
|
|
||||||
|
const Shirt two_coffee_player0_shirt = Shirt(
|
||||||
|
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER0_DARKEST),
|
||||||
|
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER0_DARK),
|
||||||
|
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER0_BASE),
|
||||||
|
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER0_LIGHT));
|
||||||
|
|
||||||
|
const Shirt two_coffee_player1_shirt = Shirt(
|
||||||
|
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER1_DARKEST),
|
||||||
|
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER1_DARK),
|
||||||
|
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER1_BASE),
|
||||||
|
Color::fromHex(GameDefaults::Player::TwoCoffeeShirt::PLAYER1_LIGHT));
|
||||||
|
|
||||||
|
std::array<Shirt, 2> two_coffee_shirt = {two_coffee_player0_shirt, two_coffee_player1_shirt};
|
||||||
|
|
||||||
|
const Color outline_player0_color = Color::fromHex(GameDefaults::Player::OutlineColor::PLAYER0);
|
||||||
|
const Color outline_player1_color = Color::fromHex(GameDefaults::Player::OutlineColor::PLAYER1);
|
||||||
|
std::array<Color, 2> outline_color = {outline_player0_color, outline_player1_color};
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- Estructura Param: almacena todos los parámetros del juego ---
|
||||||
struct Param {
|
struct Param {
|
||||||
ParamGame game; // Parámetros del juego
|
ParamGame game;
|
||||||
ParamFade fade; // Parámetros del fade
|
ParamFade fade;
|
||||||
ParamScoreboard scoreboard; // Rectángulo del marcador
|
ParamScoreboard scoreboard;
|
||||||
ParamTitle title; // Parámetros de la pantalla de título
|
ParamTitle title;
|
||||||
ParamBackground background; // Parámetros del fondo
|
ParamBackground background;
|
||||||
ParamBalloon balloon; // Parámetros de los globos
|
ParamBalloon balloon;
|
||||||
ParamNotification notification; // Parámetros de las notificaciones
|
ParamNotification notification;
|
||||||
ParamServiceMenu service_menu; // Parámetros del menú de servicio
|
ParamServiceMenu service_menu;
|
||||||
ParamIntro intro; // Parámetros de la intro
|
ParamIntro intro;
|
||||||
ParamDebug debug; // Parámetros para Debug
|
ParamDebug debug;
|
||||||
ParamResource resource; // Parámetros para Resource
|
ParamResource resource;
|
||||||
|
ParamTabe tabe;
|
||||||
|
ParamPlayer player;
|
||||||
|
|
||||||
// Constructor
|
// Constructor que inicializa las zonas que dependen de otros valores
|
||||||
Param()
|
Param() {
|
||||||
: game(), fade(), scoreboard(), title(), background(), balloon(), notification(), service_menu(), intro(), debug(), resource() {}
|
// Inicializar play_area usando los valores por defecto
|
||||||
|
game.play_area.rect = {
|
||||||
|
.x = GameDefaults::Game::PLAY_AREA_X,
|
||||||
|
.y = GameDefaults::Game::PLAY_AREA_Y,
|
||||||
|
.w = GameDefaults::Game::PLAY_AREA_W,
|
||||||
|
.h = GameDefaults::Game::PLAY_AREA_H};
|
||||||
|
|
||||||
|
// Las zonas calculadas se inicializarán en precalculateZones()
|
||||||
|
precalculateZones();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Función pública para recalcular zonas (necesaria después de cambiar parámetros)
|
||||||
|
void precalculateZones();
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Variable global con los parámetros del juego ---
|
// --- Variables ---
|
||||||
extern Param param;
|
extern Param param; // Variable global con los parámetros del juego
|
||||||
|
|
||||||
// --- Funciones globales ---
|
// --- Funciones ---
|
||||||
void loadParamsFromFile(const std::string &file_path); // Establece valores para los parámetros a partir de un fichero de texto
|
void loadParamsFromFile(const std::string& file_path); // Carga parámetros desde archivo
|
||||||
@@ -11,7 +11,7 @@ auto createPath(float start, float end, PathType type, float fixed_pos, int step
|
|||||||
|
|
||||||
for (int i = 0; i < steps; ++i) {
|
for (int i = 0; i < steps; ++i) {
|
||||||
double t = static_cast<double>(i) / (steps - 1);
|
double t = static_cast<double>(i) / (steps - 1);
|
||||||
double value = start + (end - start) * easing_function(t);
|
double value = start + ((end - start) * easing_function(t));
|
||||||
|
|
||||||
if ((start > 0 && end < 0) || (start < 0 && end > 0)) {
|
if ((start > 0 && end < 0) || (start < 0 && end > 0)) {
|
||||||
value = start + (end > 0 ? 1 : -1) * std::abs(end - start) * easing_function(t);
|
value = start + (end > 0 ? 1 : -1) * std::abs(end - start) * easing_function(t);
|
||||||
@@ -56,7 +56,7 @@ void PathSprite::addPath(Path path, bool centered) {
|
|||||||
|
|
||||||
switch (path_centered) {
|
switch (path_centered) {
|
||||||
case PathCentered::ON_X: {
|
case PathCentered::ON_X: {
|
||||||
const int X = path.spots.back().x - pos_.w / 2;
|
const int X = path.spots.back().x - (pos_.w / 2);
|
||||||
for (auto &spot : path.spots) {
|
for (auto &spot : path.spots) {
|
||||||
spot.x = X;
|
spot.x = X;
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ void PathSprite::addPath(Path path, bool centered) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PathCentered::ON_Y: {
|
case PathCentered::ON_Y: {
|
||||||
const int Y = path.spots.back().y - pos_.h / 2;
|
const int Y = path.spots.back().y - (pos_.h / 2);
|
||||||
for (auto &spot : path.spots) {
|
for (auto &spot : path.spots) {
|
||||||
spot.y = Y;
|
spot.y = Y;
|
||||||
}
|
}
|
||||||
@@ -83,8 +83,8 @@ void PathSprite::addPath(int start, int end, PathType type, int fixed_pos, int s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Añade un recorrido
|
// Añade un recorrido
|
||||||
void PathSprite::addPath(std::vector<SDL_FPoint> spots, int waiting_counter) {
|
void PathSprite::addPath(const std::vector<SDL_FPoint> &spots, int waiting_counter) {
|
||||||
paths_.emplace_back(std::move(spots), waiting_counter);
|
paths_.emplace_back(spots, waiting_counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Habilita el objeto
|
// Habilita el objeto
|
||||||
|
|||||||
@@ -4,27 +4,27 @@
|
|||||||
|
|
||||||
#include <functional> // Para std::function
|
#include <functional> // Para std::function
|
||||||
#include <memory> // Para shared_ptr
|
#include <memory> // Para shared_ptr
|
||||||
#include <vector> // Para vector
|
#include <utility>
|
||||||
|
#include <vector> // Para vector
|
||||||
|
|
||||||
#include "sprite.h" // Para Sprite
|
#include "sprite.h" // Para Sprite
|
||||||
|
|
||||||
class Texture;
|
class Texture;
|
||||||
|
|
||||||
// --- Tipos de recorrido ---
|
// --- Enums ---
|
||||||
enum class PathType {
|
enum class PathType { // Tipos de recorrido
|
||||||
VERTICAL,
|
VERTICAL,
|
||||||
HORIZONTAL,
|
HORIZONTAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Centrado del recorrido ---
|
enum class PathCentered { // Centrado del recorrido
|
||||||
enum class PathCentered {
|
|
||||||
ON_X,
|
ON_X,
|
||||||
ON_Y,
|
ON_Y,
|
||||||
NONE,
|
NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Estructura Path: define un recorrido para el sprite ---
|
// --- Estructuras ---
|
||||||
struct Path {
|
struct Path { // Define un recorrido para el sprite
|
||||||
std::vector<SDL_FPoint> spots; // Puntos por los que se desplazará el sprite
|
std::vector<SDL_FPoint> spots; // Puntos por los que se desplazará el sprite
|
||||||
int waiting_counter; // Tiempo de espera una vez en el destino
|
int waiting_counter; // Tiempo de espera una vez en el destino
|
||||||
bool on_destination = false; // Indica si ha llegado al destino
|
bool on_destination = false; // Indica si ha llegado al destino
|
||||||
@@ -33,18 +33,19 @@ struct Path {
|
|||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
Path(const std::vector<SDL_FPoint> &spots_init, int waiting_counter_init)
|
Path(const std::vector<SDL_FPoint> &spots_init, int waiting_counter_init)
|
||||||
: spots(spots_init), waiting_counter(waiting_counter_init) {}
|
: spots(spots_init),
|
||||||
|
waiting_counter(waiting_counter_init) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Devuelve un vector con los puntos que conforman la ruta
|
// --- Funciones ---
|
||||||
auto createPath(float start, float end, PathType type, float fixed_pos, int steps, const std::function<double(double)> &easing_function) -> std::vector<SDL_FPoint>;
|
auto createPath(float start, float end, PathType type, float fixed_pos, int steps, const std::function<double(double)> &easing_function) -> std::vector<SDL_FPoint>; // Devuelve un vector con los puntos que conforman la ruta
|
||||||
|
|
||||||
// --- Clase PathSprite: Sprite que sigue uno o varios recorridos ---
|
// --- Clase PathSprite: Sprite que sigue uno o varios recorridos ---
|
||||||
class PathSprite : public Sprite {
|
class PathSprite : public Sprite {
|
||||||
public:
|
public:
|
||||||
// --- Constructor y destructor ---
|
// --- Constructor y destructor ---
|
||||||
explicit PathSprite(std::shared_ptr<Texture> texture)
|
explicit PathSprite(std::shared_ptr<Texture> texture)
|
||||||
: Sprite(texture) {}
|
: Sprite(std::move(texture)) {}
|
||||||
~PathSprite() override = default;
|
~PathSprite() override = default;
|
||||||
|
|
||||||
// --- Métodos principales ---
|
// --- Métodos principales ---
|
||||||
@@ -53,7 +54,7 @@ class PathSprite : public Sprite {
|
|||||||
|
|
||||||
// --- Gestión de recorridos ---
|
// --- Gestión de recorridos ---
|
||||||
void addPath(Path path, bool centered = false); // Añade un recorrido (Path)
|
void addPath(Path path, bool centered = false); // Añade un recorrido (Path)
|
||||||
void addPath(std::vector<SDL_FPoint> spots, int waiting_counter = 0); // Añade un recorrido a partir de puntos
|
void addPath(const std::vector<SDL_FPoint> &spots, int waiting_counter = 0); // Añade un recorrido a partir de puntos
|
||||||
void addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easing_function, int waiting_counter = 0); // Añade un recorrido generado
|
void addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easing_function, int waiting_counter = 0); // Añade un recorrido generado
|
||||||
|
|
||||||
// --- Estado y control ---
|
// --- Estado y control ---
|
||||||
|
|||||||
@@ -5,18 +5,18 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
// Clase dedicada para manejar el sistema de pausa
|
// --- Clase PauseManager: maneja el sistema de pausa del juego ---
|
||||||
class PauseManager {
|
class PauseManager {
|
||||||
public:
|
public:
|
||||||
// Enum encapsulado dentro de la clase
|
// --- Enums ---
|
||||||
enum class Source : uint8_t {
|
enum class Source : uint8_t { // Fuentes de pausa
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
PLAYER = 1 << 0, // 0001
|
PLAYER = 1 << 0, // 0001
|
||||||
SERVICE_MENU = 1 << 1, // 0010
|
SERVICE_MENU = 1 << 1, // 0010
|
||||||
FOCUS_LOST = 1 << 2 // 0100
|
FOCUS_LOST = 1 << 2 // 0100
|
||||||
};
|
};
|
||||||
|
|
||||||
// Operadores para trabajar con las banderas (funciones friend)
|
// --- Operadores friend ---
|
||||||
friend auto operator|(Source a, Source b) -> Source {
|
friend auto operator|(Source a, Source b) -> Source {
|
||||||
return static_cast<Source>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
|
return static_cast<Source>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
|
||||||
}
|
}
|
||||||
@@ -42,27 +42,12 @@ class PauseManager {
|
|||||||
return a = a & b;
|
return a = a & b;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
// --- Constructor y destructor ---
|
||||||
Source flags_ = Source::NONE;
|
explicit PauseManager(std::function<void(bool)> callback = nullptr) // Constructor con callback opcional
|
||||||
std::function<void(bool)> on_pause_changed_callback_;
|
|
||||||
|
|
||||||
[[nodiscard]] auto hasFlag(Source flag) const -> bool {
|
|
||||||
return (flags_ & flag) != Source::NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void notifyPauseChanged() {
|
|
||||||
if (on_pause_changed_callback_) {
|
|
||||||
on_pause_changed_callback_(isPaused());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Constructor con callback opcional
|
|
||||||
explicit PauseManager(std::function<void(bool)> callback = nullptr)
|
|
||||||
: on_pause_changed_callback_(std::move(callback)) {}
|
: on_pause_changed_callback_(std::move(callback)) {}
|
||||||
|
|
||||||
// Establece/quita una fuente de pausa específica
|
// --- Métodos principales ---
|
||||||
void setFlag(Source source, bool enable) {
|
void setFlag(Source source, bool enable) { // Establece/quita una fuente de pausa específica
|
||||||
bool was_paused = isPaused();
|
bool was_paused = isPaused();
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
@@ -76,33 +61,29 @@ class PauseManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Métodos específicos para cada fuente
|
// --- Métodos específicos para cada fuente ---
|
||||||
void setPlayerPause(bool enable) { setFlag(Source::PLAYER, enable); }
|
void setPlayerPause(bool enable) { setFlag(Source::PLAYER, enable); }
|
||||||
void setServiceMenuPause(bool enable) { setFlag(Source::SERVICE_MENU, enable); }
|
void setServiceMenuPause(bool enable) { setFlag(Source::SERVICE_MENU, enable); }
|
||||||
void setFocusLossPause(bool enable) { setFlag(Source::FOCUS_LOST, enable); }
|
void setFocusLossPause(bool enable) { setFlag(Source::FOCUS_LOST, enable); }
|
||||||
|
|
||||||
// Toggle para el jugador (más común)
|
void togglePlayerPause() { setPlayerPause(!isPlayerPaused()); } // Toggle para el jugador (más común)
|
||||||
void togglePlayerPause() { setPlayerPause(!isPlayerPaused()); }
|
|
||||||
|
|
||||||
// Getters
|
// --- Getters ---
|
||||||
[[nodiscard]] auto isPaused() const -> bool { return flags_ != Source::NONE; }
|
[[nodiscard]] auto isPaused() const -> bool { return flags_ != Source::NONE; }
|
||||||
[[nodiscard]] auto isPlayerPaused() const -> bool { return hasFlag(Source::PLAYER); }
|
[[nodiscard]] auto isPlayerPaused() const -> bool { return hasFlag(Source::PLAYER); }
|
||||||
[[nodiscard]] auto isServiceMenuPaused() const -> bool { return hasFlag(Source::SERVICE_MENU); }
|
[[nodiscard]] auto isServiceMenuPaused() const -> bool { return hasFlag(Source::SERVICE_MENU); }
|
||||||
[[nodiscard]] auto isFocusLossPaused() const -> bool { return hasFlag(Source::FOCUS_LOST); }
|
[[nodiscard]] auto isFocusLossPaused() const -> bool { return hasFlag(Source::FOCUS_LOST); }
|
||||||
|
|
||||||
// Obtiene las banderas actuales
|
[[nodiscard]] auto getFlags() const -> Source { return flags_; } // Obtiene las banderas actuales
|
||||||
[[nodiscard]] auto getFlags() const -> Source { return flags_; }
|
|
||||||
|
|
||||||
// Limpia todas las pausas (útil para reset)
|
// --- Métodos de utilidad ---
|
||||||
void clearAll() {
|
void clearAll() { // Limpia todas las pausas (útil para reset)
|
||||||
if (isPaused()) {
|
if (isPaused()) {
|
||||||
flags_ = Source::NONE;
|
flags_ = Source::NONE;
|
||||||
notifyPauseChanged();
|
notifyPauseChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] auto getStatusString() const -> std::string { // Método para debug
|
||||||
// Método para debug
|
|
||||||
[[nodiscard]] auto getStatusString() const -> std::string {
|
|
||||||
if (flags_ == Source::NONE) {
|
if (flags_ == Source::NONE) {
|
||||||
return "Active";
|
return "Active";
|
||||||
}
|
}
|
||||||
@@ -133,9 +114,22 @@ class PauseManager {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
void setCallback(std::function<void(bool)> callback) { // Permite cambiar el callback en runtime
|
||||||
|
on_pause_changed_callback_ = std::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
// Permite cambiar el callback en runtime
|
private:
|
||||||
void setCallback(std::function<void(bool)> callback) {
|
// --- Variables ---
|
||||||
on_pause_changed_callback_ = callback;
|
Source flags_ = Source::NONE;
|
||||||
|
std::function<void(bool)> on_pause_changed_callback_;
|
||||||
|
|
||||||
|
// --- Métodos internos ---
|
||||||
|
[[nodiscard]] auto hasFlag(Source flag) const -> bool {
|
||||||
|
return (flags_ & flag) != Source::NONE;
|
||||||
|
}
|
||||||
|
void notifyPauseChanged() {
|
||||||
|
if (on_pause_changed_callback_) {
|
||||||
|
on_pause_changed_callback_(isPaused());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -75,9 +75,6 @@ void Player::init() {
|
|||||||
// Establece la posición del sprite
|
// Establece la posición del sprite
|
||||||
player_sprite_->clear();
|
player_sprite_->clear();
|
||||||
shiftSprite();
|
shiftSprite();
|
||||||
|
|
||||||
// Selecciona un frame para pintar
|
|
||||||
// player_sprite_->setCurrentAnimation("stand");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actua en consecuencia de la entrada recibida
|
// Actua en consecuencia de la entrada recibida
|
||||||
@@ -202,7 +199,7 @@ void Player::handlePlayingMovement() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Player::handleRecoverMovement() {
|
void Player::handleRecoverMovement() {
|
||||||
if (player_sprite_->getCurrentAnimationFrame() == 10) { playSound("voice_brbrbr.wav"); }
|
if (player_sprite_->getCurrentAnimationFrame() == 10) { playSound("voice_recover.wav"); }
|
||||||
if (player_sprite_->animationIsCompleted()) { setPlayingState(State::RESPAWNING); }
|
if (player_sprite_->animationIsCompleted()) { setPlayingState(State::RESPAWNING); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,8 +225,6 @@ void Player::handleRollingGroundCollision() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// const float VEL_Y = player_sprite_->getVelY();
|
|
||||||
// if (VEL_Y >= 0.0F && VEL_Y < 2.0F) {
|
|
||||||
if (player_sprite_->getVelY() < 2.0F) {
|
if (player_sprite_->getVelY() < 2.0F) {
|
||||||
handleRollingStop();
|
handleRollingStop();
|
||||||
} else {
|
} else {
|
||||||
@@ -600,6 +595,14 @@ void Player::update() {
|
|||||||
updateShowingName();
|
updateShowingName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::passShowingName() {
|
||||||
|
if (game_completed_) {
|
||||||
|
setPlayingState(State::LEAVING_SCREEN);
|
||||||
|
} else {
|
||||||
|
setPlayingState(State::CONTINUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Incrementa la puntuación del jugador
|
// Incrementa la puntuación del jugador
|
||||||
void Player::addScore(int score, int lowest_hi_score_entry) {
|
void Player::addScore(int score, int lowest_hi_score_entry) {
|
||||||
if (isPlaying()) {
|
if (isPlaying()) {
|
||||||
@@ -639,6 +642,9 @@ void Player::setPlayingState(State state) {
|
|||||||
|
|
||||||
switch (playing_state_) {
|
switch (playing_state_) {
|
||||||
case State::RECOVER: {
|
case State::RECOVER: {
|
||||||
|
score_ = 0; // Pon los puntos a cero para que no se vea en el marcador
|
||||||
|
score_multiplier_ = 1.0F;
|
||||||
|
setScoreboardMode(Scoreboard::Mode::SCORE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case State::RESPAWNING: {
|
case State::RESPAWNING: {
|
||||||
@@ -651,7 +657,7 @@ void Player::setPlayingState(State state) {
|
|||||||
init();
|
init();
|
||||||
setInvulnerable(true);
|
setInvulnerable(true);
|
||||||
setScoreboardMode(Scoreboard::Mode::SCORE);
|
setScoreboardMode(Scoreboard::Mode::SCORE);
|
||||||
stage_info_->canCollectPower();
|
stage_info_->enablePowerCollection();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case State::CONTINUE: {
|
case State::CONTINUE: {
|
||||||
@@ -793,15 +799,30 @@ void Player::setInvulnerable(bool value) {
|
|||||||
|
|
||||||
// Monitoriza el estado
|
// Monitoriza el estado
|
||||||
void Player::updateInvulnerable() {
|
void Player::updateInvulnerable() {
|
||||||
if (playing_state_ == State::PLAYING) {
|
if (playing_state_ == State::PLAYING && invulnerable_) {
|
||||||
if (invulnerable_) {
|
if (invulnerable_counter_ > 0) {
|
||||||
if (invulnerable_counter_ > 0) {
|
--invulnerable_counter_;
|
||||||
--invulnerable_counter_;
|
|
||||||
invulnerable_counter_ % 8 > 3 ? player_sprite_->setActiveTexture(coffees_) : player_sprite_->setActiveTexture(3);
|
// Frecuencia fija de parpadeo (como el original)
|
||||||
} else {
|
constexpr int blink_speed = 8;
|
||||||
setInvulnerable(false);
|
|
||||||
player_sprite_->setActiveTexture(coffees_);
|
// Calcula proporción decreciente: menos textura blanca hacia el final
|
||||||
|
// Al inicio: 50-50, hacia el final: 70-30 (menos blanco)
|
||||||
|
float progress = 1.0f - (static_cast<float>(invulnerable_counter_) / INVULNERABLE_COUNTER);
|
||||||
|
int white_frames = static_cast<int>((0.5f - progress * 0.2f) * blink_speed);
|
||||||
|
|
||||||
|
// Alterna entre texturas con proporción variable
|
||||||
|
bool should_show_invulnerable = (invulnerable_counter_ % blink_speed) < white_frames;
|
||||||
|
size_t target_texture = should_show_invulnerable ? INVULNERABLE_TEXTURE : coffees_;
|
||||||
|
|
||||||
|
// Solo cambia textura si es diferente (optimización)
|
||||||
|
if (player_sprite_->getActiveTexture() != target_texture) {
|
||||||
|
player_sprite_->setActiveTexture(target_texture);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Fin de invulnerabilidad
|
||||||
|
setInvulnerable(false);
|
||||||
|
player_sprite_->setActiveTexture(coffees_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,15 +24,14 @@ class Player {
|
|||||||
static constexpr int WIDTH = 32; // Anchura
|
static constexpr int WIDTH = 32; // Anchura
|
||||||
static constexpr int HEIGHT = 32; // Altura
|
static constexpr int HEIGHT = 32; // Altura
|
||||||
|
|
||||||
// --- Id para los jugadores ---
|
// --- Enums ---
|
||||||
enum class Id : int {
|
enum class Id : int {
|
||||||
NO_PLAYER = -1,
|
NO_PLAYER = -1, // Sin jugador
|
||||||
BOTH_PLAYERS = 0,
|
BOTH_PLAYERS = 0, // Ambos jugadores
|
||||||
PLAYER1 = 1,
|
PLAYER1 = 1, // Jugador 1
|
||||||
PLAYER2 = 2
|
PLAYER2 = 2 // Jugador 2
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Estados posibles del jugador ---
|
|
||||||
enum class State {
|
enum class State {
|
||||||
// Estados de movimiento
|
// Estados de movimiento
|
||||||
WALKING_LEFT, // Caminando hacia la izquierda
|
WALKING_LEFT, // Caminando hacia la izquierda
|
||||||
@@ -76,17 +75,18 @@ class Player {
|
|||||||
RESPAWNING, // Tras continuar y dar las gracias, otorga inmunidad y vuelve al juego
|
RESPAWNING, // Tras continuar y dar las gracias, otorga inmunidad y vuelve al juego
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --- Estructuras ---
|
||||||
struct Config {
|
struct Config {
|
||||||
Id id;
|
Id id; // Identificador del jugador
|
||||||
float x;
|
float x; // Posición X inicial
|
||||||
int y;
|
int y; // Posición Y inicial
|
||||||
bool demo;
|
bool demo; // Modo demo
|
||||||
SDL_FRect *play_area; // Usamos puntero para mantener la referencia
|
SDL_FRect *play_area; // Área de juego (puntero para mantener referencia)
|
||||||
std::vector<std::shared_ptr<Texture>> texture;
|
std::vector<std::shared_ptr<Texture>> texture; // Texturas del jugador
|
||||||
std::vector<std::vector<std::string>> animations;
|
std::vector<std::vector<std::string>> animations; // Animaciones del jugador
|
||||||
Table *hi_score_table; // También como puntero para referencia
|
Table *hi_score_table; // Tabla de puntuaciones (puntero para referencia)
|
||||||
int *glowing_entry; // Puntero para mantener la referencia
|
int *glowing_entry; // Entrada brillante (puntero para mantener referencia)
|
||||||
IStageInfo *stage_info; // Puntero para el gestor de pantallas
|
IStageInfo *stage_info; // Gestor de pantallas (puntero)
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Constructor y destructor ---
|
// --- Constructor y destructor ---
|
||||||
@@ -170,7 +170,7 @@ class Player {
|
|||||||
[[nodiscard]] static auto getWidth() -> int { return WIDTH; }
|
[[nodiscard]] static auto getWidth() -> int { return WIDTH; }
|
||||||
[[nodiscard]] auto getPlayingState() const -> State { return playing_state_; }
|
[[nodiscard]] auto getPlayingState() const -> State { return playing_state_; }
|
||||||
[[nodiscard]] auto getName() const -> const std::string & { return name_; }
|
[[nodiscard]] auto getName() const -> const std::string & { return name_; }
|
||||||
[[nodiscard]] auto get1CC() const -> bool { return game_completed_ && credits_used_ == 1; }
|
[[nodiscard]] auto get1CC() const -> bool { return game_completed_ && credits_used_ <= 1; }
|
||||||
[[nodiscard]] auto getEnterNamePositionOverflow() const -> bool { return enter_name_ ? enter_name_->getPositionOverflow() : false; }
|
[[nodiscard]] auto getEnterNamePositionOverflow() const -> bool { return enter_name_ ? enter_name_->getPositionOverflow() : false; }
|
||||||
|
|
||||||
// Setters inline
|
// Setters inline
|
||||||
@@ -184,21 +184,23 @@ class Player {
|
|||||||
void setScoreBoardPanel(Scoreboard::Id panel) { scoreboard_panel_ = panel; }
|
void setScoreBoardPanel(Scoreboard::Id panel) { scoreboard_panel_ = panel; }
|
||||||
void setScoreMultiplier(float value) { score_multiplier_ = value; }
|
void setScoreMultiplier(float value) { score_multiplier_ = value; }
|
||||||
void setWalkingState(State state) { walking_state_ = state; }
|
void setWalkingState(State state) { walking_state_ = state; }
|
||||||
|
|
||||||
void addCredit();
|
void addCredit();
|
||||||
void setGamepad(std::shared_ptr<Input::Gamepad> gamepad) { gamepad_ = gamepad; }
|
void passShowingName();
|
||||||
|
void setGamepad(std::shared_ptr<Input::Gamepad> gamepad) { gamepad_ = std::move(gamepad); }
|
||||||
[[nodiscard]] auto getGamepad() const -> std::shared_ptr<Input::Gamepad> { return gamepad_; }
|
[[nodiscard]] auto getGamepad() const -> std::shared_ptr<Input::Gamepad> { return gamepad_; }
|
||||||
void setUsesKeyboard(bool value) { uses_keyboard_ = value; }
|
void setUsesKeyboard(bool value) { uses_keyboard_ = value; }
|
||||||
[[nodiscard]] auto getUsesKeyboard() const -> bool { return uses_keyboard_; }
|
[[nodiscard]] auto getUsesKeyboard() const -> bool { return uses_keyboard_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// --- Constantes ---
|
// --- Constantes ---
|
||||||
static constexpr int POWERUP_COUNTER = 1500; // Duración del estado PowerUp
|
static constexpr int POWERUP_COUNTER = 1500; // Duración del estado PowerUp
|
||||||
static constexpr int INVULNERABLE_COUNTER = 200; // Duración del estado invulnerable
|
static constexpr int INVULNERABLE_COUNTER = 200; // Duración del estado invulnerable
|
||||||
static constexpr float BASE_SPEED = 1.5F; // Velocidad base del jugador
|
static constexpr size_t INVULNERABLE_TEXTURE = 3; // Textura usada durante invulnerabilidad
|
||||||
static constexpr int COOLING_DURATION = 50;
|
static constexpr float BASE_SPEED = 1.5F; // Velocidad base del jugador
|
||||||
static constexpr int COOLING_COMPLETE = 0;
|
static constexpr int COOLING_DURATION = 50; // Duración del enfriamiento tras disparar
|
||||||
static constexpr int WAITING_COUNTER = 1000;
|
static constexpr int COOLING_COMPLETE = 0; // Valor que indica enfriamiento completado
|
||||||
|
static constexpr int WAITING_COUNTER = 1000; // Tiempo de espera en estado de espera
|
||||||
|
|
||||||
// --- Objetos y punteros ---
|
// --- Objetos y punteros ---
|
||||||
std::unique_ptr<AnimatedSprite> player_sprite_; // Sprite para dibujar el jugador
|
std::unique_ptr<AnimatedSprite> player_sprite_; // Sprite para dibujar el jugador
|
||||||
@@ -208,25 +210,25 @@ class Player {
|
|||||||
Table *hi_score_table_ = nullptr; // Tabla de máximas puntuaciones
|
Table *hi_score_table_ = nullptr; // Tabla de máximas puntuaciones
|
||||||
int *glowing_entry_ = nullptr; // Entrada de la tabla de puntuaciones para hacerla brillar
|
int *glowing_entry_ = nullptr; // Entrada de la tabla de puntuaciones para hacerla brillar
|
||||||
IStageInfo *stage_info_; // Informacion de la pantalla actual
|
IStageInfo *stage_info_; // Informacion de la pantalla actual
|
||||||
std::string name_; // Nombre del jugador
|
|
||||||
std::string last_enter_name_; // Último nombre introducido en la tabla de puntuaciones
|
|
||||||
|
|
||||||
// --- Estructuras y enums ---
|
// --- Variables de estado ---
|
||||||
SDL_FRect play_area_; // Rectángulo con la zona de juego
|
SDL_FRect play_area_; // Rectángulo con la zona de juego
|
||||||
Circle collider_ = Circle(0, 0, 9); // Círculo de colisión del jugador
|
Circle collider_ = Circle(0, 0, 9); // Círculo de colisión del jugador
|
||||||
|
std::string name_; // Nombre del jugador
|
||||||
|
std::string last_enter_name_; // Último nombre introducido en la tabla de puntuaciones
|
||||||
Scoreboard::Id scoreboard_panel_ = Scoreboard::Id::LEFT; // Panel del marcador asociado al jugador
|
Scoreboard::Id scoreboard_panel_ = Scoreboard::Id::LEFT; // Panel del marcador asociado al jugador
|
||||||
Id id_; // Identificador para el jugador
|
Id id_; // Identificador para el jugador
|
||||||
State walking_state_ = State::WALKING_STOP; // Estado del jugador al moverse
|
State walking_state_ = State::WALKING_STOP; // Estado del jugador al moverse
|
||||||
State firing_state_ = State::FIRING_NONE; // Estado del jugador al disparar
|
State firing_state_ = State::FIRING_NONE; // Estado del jugador al disparar
|
||||||
State playing_state_ = State::WAITING; // Estado del jugador en el juego
|
State playing_state_ = State::WAITING; // Estado del jugador en el juego
|
||||||
|
|
||||||
// --- Variables float ---
|
Uint32 continue_ticks_ = 0; // Variable para poder cambiar el contador de continue en función del tiempo
|
||||||
float pos_x_ = 0.0F; // Posición en el eje X
|
Uint32 name_entry_ticks_ = 0; // Variable para poder cambiar el contador de poner nombre en función del tiempo
|
||||||
float default_pos_x_; // Posición inicial para el jugador
|
Uint32 showing_name_ticks_ = 0; // Tiempo en el que se entra al estado SHOWING_NAME
|
||||||
float vel_x_ = 0.0F; // Cantidad de píxeles a desplazarse en el eje X
|
float pos_x_ = 0.0F; // Posición en el eje X
|
||||||
float score_multiplier_ = 1.0F; // Multiplicador de puntos
|
float default_pos_x_; // Posición inicial para el jugador
|
||||||
|
float vel_x_ = 0.0F; // Cantidad de píxeles a desplazarse en el eje X
|
||||||
// --- Variables int ---
|
float score_multiplier_ = 1.0F; // Multiplicador de puntos
|
||||||
int pos_y_ = 0; // Posición en el eje Y
|
int pos_y_ = 0; // Posición en el eje Y
|
||||||
int default_pos_y_; // Posición inicial para el jugador
|
int default_pos_y_; // Posición inicial para el jugador
|
||||||
int vel_y_ = 0; // Cantidad de píxeles a desplazarse en el eje Y
|
int vel_y_ = 0; // Cantidad de píxeles a desplazarse en el eje Y
|
||||||
@@ -246,20 +248,13 @@ class Player {
|
|||||||
int step_counter_ = 0; // Cuenta los pasos para los estados en los que camina automáticamente
|
int step_counter_ = 0; // Cuenta los pasos para los estados en los que camina automáticamente
|
||||||
int credits_used_ = 0; // Indica el número de veces que ha continuado
|
int credits_used_ = 0; // Indica el número de veces que ha continuado
|
||||||
int waiting_counter_ = 0; // Contador para el estado de espera
|
int waiting_counter_ = 0; // Contador para el estado de espera
|
||||||
|
bool qualifies_for_high_score_ = false; // Indica si tiene una puntuación que le permite entrar en la tabla de records
|
||||||
// --- Variables Uint32 ---
|
bool invulnerable_ = true; // Indica si el jugador es invulnerable
|
||||||
Uint32 continue_ticks_ = 0; // Variable para poder cambiar el contador de continue en función del tiempo
|
bool extra_hit_ = false; // Indica si el jugador tiene un toque extra
|
||||||
Uint32 name_entry_ticks_ = 0; // Variable para poder cambiar el contador de poner nombre en función del tiempo
|
bool power_up_ = false; // Indica si el jugador tiene activo el modo PowerUp
|
||||||
Uint32 showing_name_ticks_ = 0; // Tiempo en el que se entra al estado SHOWING_NAME
|
bool demo_ = false; // Para que el jugador sepa si está en el modo demostración
|
||||||
|
bool game_completed_ = false; // Indica si ha completado el juego
|
||||||
// --- Flags booleanas ---
|
bool uses_keyboard_ = false; // Indica si usa el teclado como dispositivo de control
|
||||||
bool qualifies_for_high_score_ = false; // Indica si tiene una puntuación que le permite entrar en la tabla de records
|
|
||||||
bool invulnerable_ = true; // Indica si el jugador es invulnerable
|
|
||||||
bool extra_hit_ = false; // Indica si el jugador tiene un toque extra
|
|
||||||
bool power_up_ = false; // Indica si el jugador tiene activo el modo PowerUp
|
|
||||||
bool demo_ = false; // Para que el jugador sepa si está en el modo demostración
|
|
||||||
bool game_completed_ = false; // Indica si ha completado el juego
|
|
||||||
bool uses_keyboard_ = false; // Indica si usa el teclado como dispositivo de control
|
|
||||||
|
|
||||||
// --- Métodos internos ---
|
// --- Métodos internos ---
|
||||||
void shiftColliders(); // Actualiza el círculo de colisión a la posición del jugador
|
void shiftColliders(); // Actualiza el círculo de colisión a la posición del jugador
|
||||||
|
|||||||
@@ -2,25 +2,58 @@
|
|||||||
|
|
||||||
#include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory, SDL_LogError, SDL_SetRenderDrawColor, SDL_EventType, SDL_PollEvent, SDL_RenderFillRect, SDL_RenderRect, SDLK_ESCAPE, SDL_Event
|
#include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory, SDL_LogError, SDL_SetRenderDrawColor, SDL_EventType, SDL_PollEvent, SDL_RenderFillRect, SDL_RenderRect, SDLK_ESCAPE, SDL_Event
|
||||||
|
|
||||||
#include <algorithm> // Para find_if, max, find
|
#include <algorithm> // Para find_if, max, find
|
||||||
#include <array> // Para array
|
#include <array> // Para array
|
||||||
#include <cstdlib> // Para exit
|
#include <cstdlib> // Para exit, getenv
|
||||||
#include <stdexcept> // Para runtime_error
|
#include <filesystem> // Para filesystem::remove, filesystem::exists
|
||||||
#include <utility> // Para move
|
#include <fstream> // Para ofstream
|
||||||
|
#include <stdexcept> // Para runtime_error
|
||||||
|
#include <utility> // Para move
|
||||||
|
|
||||||
#include "asset.h" // Para Asset
|
#include "asset.h" // Para Asset
|
||||||
#include "color.h" // Para Color
|
#include "color.h" // Para Color
|
||||||
#ifndef NO_AUDIO
|
#ifndef NO_AUDIO
|
||||||
#include "external/jail_audio.h" // Para JA_LoadMusic, JA_LoadSound, JA_DeleteMusic, JA_DeleteSound
|
#include "external/jail_audio.h" // Para JA_LoadMusic, JA_LoadSound, JA_DeleteMusic, JA_DeleteSound
|
||||||
#endif
|
#endif
|
||||||
#include "lang.h" // Para getText
|
#include "lang.h" // Para getText
|
||||||
#include "param.h" // Para Param, param, ParamResource, ParamGame
|
#include "param.h" // Para Param, param, ParamResource, ParamGame
|
||||||
#include "screen.h" // Para Screen
|
#include "resource_helper.h" // Para ResourceHelper
|
||||||
#include "text.h" // Para Text
|
#include "screen.h" // Para Screen
|
||||||
|
#include "text.h" // Para Text
|
||||||
|
|
||||||
struct JA_Music_t; // lines 11-11
|
struct JA_Music_t; // lines 11-11
|
||||||
struct JA_Sound_t; // lines 12-12
|
struct JA_Sound_t; // lines 12-12
|
||||||
|
|
||||||
|
// Helper para cargar archivos de audio desde pack o filesystem
|
||||||
|
namespace {
|
||||||
|
std::string createTempAudioFile(const std::string &file_path, std::vector<std::string> &temp_files_tracker) {
|
||||||
|
auto resource_data = ResourceHelper::loadFile(file_path);
|
||||||
|
if (!resource_data.empty()) {
|
||||||
|
// Crear archivo temporal
|
||||||
|
std::string temp_dir;
|
||||||
|
#ifdef _WIN32
|
||||||
|
temp_dir = std::getenv("TEMP") ? std::getenv("TEMP") : "C:\\temp";
|
||||||
|
#else
|
||||||
|
temp_dir = "/tmp";
|
||||||
|
#endif
|
||||||
|
std::string temp_path = temp_dir + "/ccae_audio_" + std::to_string(std::hash<std::string>{}(file_path));
|
||||||
|
std::ofstream temp_file(temp_path, std::ios::binary);
|
||||||
|
if (!temp_file) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot create temp file %s", temp_path.c_str());
|
||||||
|
return file_path;
|
||||||
|
}
|
||||||
|
temp_file.write(reinterpret_cast<const char *>(resource_data.data()), resource_data.size());
|
||||||
|
temp_file.close();
|
||||||
|
|
||||||
|
// Agregar a la lista de archivos temporales para limpieza posterior
|
||||||
|
temp_files_tracker.push_back(temp_path);
|
||||||
|
|
||||||
|
return temp_path;
|
||||||
|
}
|
||||||
|
return file_path; // Usar ruta original si no está en pack
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
// Declaraciones de funciones que necesitas implementar en otros archivos
|
// Declaraciones de funciones que necesitas implementar en otros archivos
|
||||||
|
|
||||||
// Singleton
|
// Singleton
|
||||||
@@ -42,7 +75,8 @@ auto Resource::get() -> Resource * { return Resource::instance; }
|
|||||||
|
|
||||||
// Constructor con modo de carga
|
// Constructor con modo de carga
|
||||||
Resource::Resource(LoadingMode mode)
|
Resource::Resource(LoadingMode mode)
|
||||||
: loading_mode_(mode), loading_text_(nullptr) {
|
: loading_mode_(mode),
|
||||||
|
loading_text_(nullptr) {
|
||||||
if (loading_mode_ == LoadingMode::PRELOAD) {
|
if (loading_mode_ == LoadingMode::PRELOAD) {
|
||||||
loading_text_ = Screen::get()->getText();
|
loading_text_ = Screen::get()->getText();
|
||||||
load();
|
load();
|
||||||
@@ -55,6 +89,7 @@ Resource::Resource(LoadingMode mode)
|
|||||||
|
|
||||||
// Destructor
|
// Destructor
|
||||||
Resource::~Resource() {
|
Resource::~Resource() {
|
||||||
|
cleanupTempAudioFiles();
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +115,7 @@ void Resource::loadTextFilesQuiet() {
|
|||||||
for (const auto &l : list) {
|
for (const auto &l : list) {
|
||||||
auto name = getFileName(l);
|
auto name = getFileName(l);
|
||||||
// Buscar en nuestra lista y cargar directamente
|
// Buscar en nuestra lista y cargar directamente
|
||||||
auto it = std::find_if(text_files_.begin(), text_files_.end(), [&name](const auto &t) { return t.name == name; });
|
auto it = std::ranges::find_if(text_files_, [&name](const auto &t) { return t.name == name; });
|
||||||
if (it != text_files_.end()) {
|
if (it != text_files_.end()) {
|
||||||
it->text_file = Text::loadFile(l);
|
it->text_file = Text::loadFile(l);
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Text file loaded: %s", name.c_str());
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Text file loaded: %s", name.c_str());
|
||||||
@@ -109,9 +144,9 @@ void Resource::loadEssentialTextures() {
|
|||||||
for (const auto &file : texture_list) {
|
for (const auto &file : texture_list) {
|
||||||
auto name = getFileName(file);
|
auto name = getFileName(file);
|
||||||
// Solo cargar texturas esenciales
|
// Solo cargar texturas esenciales
|
||||||
if (std::find(ESSENTIAL_TEXTURES.begin(), ESSENTIAL_TEXTURES.end(), name) != ESSENTIAL_TEXTURES.end()) {
|
if (std::ranges::find(ESSENTIAL_TEXTURES, name) != ESSENTIAL_TEXTURES.end()) {
|
||||||
// Buscar en nuestra lista y cargar
|
// Buscar en nuestra lista y cargar
|
||||||
auto it = std::find_if(textures_.begin(), textures_.end(), [&name](const auto &t) { return t.name == name; });
|
auto it = std::ranges::find_if(textures_, [&name](const auto &t) { return t.name == name; });
|
||||||
if (it != textures_.end()) {
|
if (it != textures_.end()) {
|
||||||
it->texture = std::make_shared<Texture>(Screen::get()->getRenderer(), file);
|
it->texture = std::make_shared<Texture>(Screen::get()->getRenderer(), file);
|
||||||
}
|
}
|
||||||
@@ -186,7 +221,7 @@ void Resource::initResourceLists() {
|
|||||||
|
|
||||||
// Obtiene el sonido a partir de un nombre (con carga perezosa)
|
// Obtiene el sonido a partir de un nombre (con carga perezosa)
|
||||||
auto Resource::getSound(const std::string &name) -> JA_Sound_t * {
|
auto Resource::getSound(const std::string &name) -> JA_Sound_t * {
|
||||||
auto it = std::find_if(sounds_.begin(), sounds_.end(), [&name](const auto &s) { return s.name == name; });
|
auto it = std::ranges::find_if(sounds_, [&name](const auto &s) { return s.name == name; });
|
||||||
|
|
||||||
if (it != sounds_.end()) {
|
if (it != sounds_.end()) {
|
||||||
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
||||||
@@ -202,7 +237,7 @@ auto Resource::getSound(const std::string &name) -> JA_Sound_t * {
|
|||||||
|
|
||||||
// Obtiene la música a partir de un nombre (con carga perezosa)
|
// Obtiene la música a partir de un nombre (con carga perezosa)
|
||||||
auto Resource::getMusic(const std::string &name) -> JA_Music_t * {
|
auto Resource::getMusic(const std::string &name) -> JA_Music_t * {
|
||||||
auto it = std::find_if(musics_.begin(), musics_.end(), [&name](const auto &m) { return m.name == name; });
|
auto it = std::ranges::find_if(musics_, [&name](const auto &m) { return m.name == name; });
|
||||||
|
|
||||||
if (it != musics_.end()) {
|
if (it != musics_.end()) {
|
||||||
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
||||||
@@ -218,7 +253,7 @@ auto Resource::getMusic(const std::string &name) -> JA_Music_t * {
|
|||||||
|
|
||||||
// Obtiene la textura a partir de un nombre (con carga perezosa)
|
// Obtiene la textura a partir de un nombre (con carga perezosa)
|
||||||
auto Resource::getTexture(const std::string &name) -> std::shared_ptr<Texture> {
|
auto Resource::getTexture(const std::string &name) -> std::shared_ptr<Texture> {
|
||||||
auto it = std::find_if(textures_.begin(), textures_.end(), [&name](const auto &t) { return t.name == name; });
|
auto it = std::ranges::find_if(textures_, [&name](const auto &t) { return t.name == name; });
|
||||||
|
|
||||||
if (it != textures_.end()) {
|
if (it != textures_.end()) {
|
||||||
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
||||||
@@ -234,7 +269,7 @@ auto Resource::getTexture(const std::string &name) -> std::shared_ptr<Texture> {
|
|||||||
|
|
||||||
// Obtiene el fichero de texto a partir de un nombre (con carga perezosa)
|
// Obtiene el fichero de texto a partir de un nombre (con carga perezosa)
|
||||||
auto Resource::getTextFile(const std::string &name) -> std::shared_ptr<Text::File> {
|
auto Resource::getTextFile(const std::string &name) -> std::shared_ptr<Text::File> {
|
||||||
auto it = std::find_if(text_files_.begin(), text_files_.end(), [&name](const auto &t) { return t.name == name; });
|
auto it = std::ranges::find_if(text_files_, [&name](const auto &t) { return t.name == name; });
|
||||||
|
|
||||||
if (it != text_files_.end()) {
|
if (it != text_files_.end()) {
|
||||||
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
||||||
@@ -250,7 +285,7 @@ auto Resource::getTextFile(const std::string &name) -> std::shared_ptr<Text::Fil
|
|||||||
|
|
||||||
// Obtiene el objeto de texto a partir de un nombre (con carga perezosa)
|
// Obtiene el objeto de texto a partir de un nombre (con carga perezosa)
|
||||||
auto Resource::getText(const std::string &name) -> std::shared_ptr<Text> {
|
auto Resource::getText(const std::string &name) -> std::shared_ptr<Text> {
|
||||||
auto it = std::find_if(texts_.begin(), texts_.end(), [&name](const auto &t) { return t.name == name; });
|
auto it = std::ranges::find_if(texts_, [&name](const auto &t) { return t.name == name; });
|
||||||
|
|
||||||
if (it != texts_.end()) {
|
if (it != texts_.end()) {
|
||||||
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
||||||
@@ -266,7 +301,7 @@ auto Resource::getText(const std::string &name) -> std::shared_ptr<Text> {
|
|||||||
|
|
||||||
// Obtiene la animación a partir de un nombre (con carga perezosa)
|
// Obtiene la animación a partir de un nombre (con carga perezosa)
|
||||||
auto Resource::getAnimation(const std::string &name) -> AnimationsFileBuffer & {
|
auto Resource::getAnimation(const std::string &name) -> AnimationsFileBuffer & {
|
||||||
auto it = std::find_if(animations_.begin(), animations_.end(), [&name](const auto &a) { return a.name == name; });
|
auto it = std::ranges::find_if(animations_, [&name](const auto &a) { return a.name == name; });
|
||||||
|
|
||||||
if (it != animations_.end()) {
|
if (it != animations_.end()) {
|
||||||
// Si está en modo lazy y no se ha cargado aún (vector vacío), lo carga ahora
|
// Si está en modo lazy y no se ha cargado aún (vector vacío), lo carga ahora
|
||||||
@@ -293,7 +328,8 @@ auto Resource::loadSoundLazy(const std::string &name) -> JA_Sound_t * {
|
|||||||
auto sound_list = Asset::get()->getListByType(Asset::Type::SOUND);
|
auto sound_list = Asset::get()->getListByType(Asset::Type::SOUND);
|
||||||
for (const auto &file : sound_list) {
|
for (const auto &file : sound_list) {
|
||||||
if (getFileName(file) == name) {
|
if (getFileName(file) == name) {
|
||||||
return JA_LoadSound(file.c_str());
|
std::string audio_path = createTempAudioFile(file, Resource::get()->temp_audio_files_);
|
||||||
|
return JA_LoadSound(audio_path.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -306,7 +342,8 @@ auto Resource::loadMusicLazy(const std::string &name) -> JA_Music_t * {
|
|||||||
auto music_list = Asset::get()->getListByType(Asset::Type::MUSIC);
|
auto music_list = Asset::get()->getListByType(Asset::Type::MUSIC);
|
||||||
for (const auto &file : music_list) {
|
for (const auto &file : music_list) {
|
||||||
if (getFileName(file) == name) {
|
if (getFileName(file) == name) {
|
||||||
return JA_LoadMusic(file.c_str());
|
std::string audio_path = createTempAudioFile(file, Resource::get()->temp_audio_files_);
|
||||||
|
return JA_LoadMusic(audio_path.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -346,18 +383,18 @@ auto Resource::loadTextLazy(const std::string &name) -> std::shared_ptr<Text> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const std::vector<TextMapping> TEXT_MAPPINGS = {
|
const std::vector<TextMapping> TEXT_MAPPINGS = {
|
||||||
{"04b_25", "04b_25.png", "04b_25.txt"},
|
{.key = "04b_25", .texture_file = "04b_25.png", .text_file = "04b_25.txt"},
|
||||||
{"04b_25_2x", "04b_25_2x.png", "04b_25_2x.txt"},
|
{.key = "04b_25_2x", .texture_file = "04b_25_2x.png", .text_file = "04b_25_2x.txt"},
|
||||||
{"04b_25_metal", "04b_25_metal.png", "04b_25.txt"},
|
{.key = "04b_25_metal", .texture_file = "04b_25_metal.png", .text_file = "04b_25.txt"},
|
||||||
{"04b_25_grey", "04b_25_grey.png", "04b_25.txt"},
|
{.key = "04b_25_grey", .texture_file = "04b_25_grey.png", .text_file = "04b_25.txt"},
|
||||||
{"04b_25_flat", "04b_25_flat.png", "04b_25.txt"},
|
{.key = "04b_25_flat", .texture_file = "04b_25_flat.png", .text_file = "04b_25.txt"},
|
||||||
{"04b_25_reversed", "04b_25_reversed.png", "04b_25.txt"},
|
{.key = "04b_25_reversed", .texture_file = "04b_25_reversed.png", .text_file = "04b_25.txt"},
|
||||||
{"04b_25_flat_2x", "04b_25_flat_2x.png", "04b_25_2x.txt"},
|
{.key = "04b_25_flat_2x", .texture_file = "04b_25_flat_2x.png", .text_file = "04b_25_2x.txt"},
|
||||||
{"04b_25_reversed_2x", "04b_25_reversed_2x.png", "04b_25_2x.txt"},
|
{.key = "04b_25_reversed_2x", .texture_file = "04b_25_reversed_2x.png", .text_file = "04b_25_2x.txt"},
|
||||||
{"8bithud", "8bithud.png", "8bithud.txt"},
|
{.key = "8bithud", .texture_file = "8bithud.png", .text_file = "8bithud.txt"},
|
||||||
{"aseprite", "aseprite.png", "aseprite.txt"},
|
{.key = "aseprite", .texture_file = "aseprite.png", .text_file = "aseprite.txt"},
|
||||||
{"smb2", "smb2.png", "smb2.txt"},
|
{.key = "smb2", .texture_file = "smb2.png", .text_file = "smb2.txt"},
|
||||||
{"smb2_grad", "smb2_grad.png", "smb2.txt"}};
|
{.key = "smb2_grad", .texture_file = "smb2_grad.png", .text_file = "smb2.txt"}};
|
||||||
|
|
||||||
for (const auto &mapping : TEXT_MAPPINGS) {
|
for (const auto &mapping : TEXT_MAPPINGS) {
|
||||||
if (mapping.key == name) {
|
if (mapping.key == name) {
|
||||||
@@ -448,7 +485,8 @@ void Resource::loadSounds() {
|
|||||||
auto name = getFileName(l);
|
auto name = getFileName(l);
|
||||||
updateLoadingProgress(name);
|
updateLoadingProgress(name);
|
||||||
#ifndef NO_AUDIO
|
#ifndef NO_AUDIO
|
||||||
sounds_.emplace_back(name, JA_LoadSound(l.c_str()));
|
std::string audio_path = createTempAudioFile(l, temp_audio_files_);
|
||||||
|
sounds_.emplace_back(name, JA_LoadSound(audio_path.c_str()));
|
||||||
#else
|
#else
|
||||||
sounds_.emplace_back(name, nullptr);
|
sounds_.emplace_back(name, nullptr);
|
||||||
#endif
|
#endif
|
||||||
@@ -466,7 +504,8 @@ void Resource::loadMusics() {
|
|||||||
auto name = getFileName(l);
|
auto name = getFileName(l);
|
||||||
updateLoadingProgress(name);
|
updateLoadingProgress(name);
|
||||||
#ifndef NO_AUDIO
|
#ifndef NO_AUDIO
|
||||||
musics_.emplace_back(name, JA_LoadMusic(l.c_str()));
|
std::string audio_path = createTempAudioFile(l, temp_audio_files_);
|
||||||
|
musics_.emplace_back(name, JA_LoadMusic(audio_path.c_str()));
|
||||||
#else
|
#else
|
||||||
musics_.emplace_back(name, nullptr);
|
musics_.emplace_back(name, nullptr);
|
||||||
#endif
|
#endif
|
||||||
@@ -537,10 +576,13 @@ void Resource::createPlayerTextures() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::vector<PlayerConfig> players = {
|
std::vector<PlayerConfig> players = {
|
||||||
{"player1.gif", {"player1_coffee1.pal", "player1_coffee2.pal", "player1_invencible.pal"}, "player1"},
|
{.base_texture = "player1.gif", .palette_files = {"player1_coffee1.pal", "player1_coffee2.pal", "player1_invencible.pal"}, .name_prefix = "player1"},
|
||||||
{"player2.gif", {"player2_coffee1.pal", "player2_coffee2.pal", "player2_invencible.pal"}, "player2"}};
|
{.base_texture = "player2.gif", .palette_files = {"player2_coffee1.pal", "player2_coffee2.pal", "player2_invencible.pal"}, .name_prefix = "player2"}};
|
||||||
|
|
||||||
|
// Bucle principal
|
||||||
|
for (size_t player_idx = 0; player_idx < players.size(); ++player_idx) {
|
||||||
|
const auto &player = players[player_idx]; // Obtenemos el jugador actual
|
||||||
|
|
||||||
for (const auto &player : players) {
|
|
||||||
// Encontrar el archivo original de la textura
|
// Encontrar el archivo original de la textura
|
||||||
std::string texture_file_path;
|
std::string texture_file_path;
|
||||||
auto texture_list = Asset::get()->getListByType(Asset::Type::BITMAP);
|
auto texture_list = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||||
@@ -551,29 +593,52 @@ void Resource::createPlayerTextures() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Crear variante con paleta original (pal0) - usar la textura ya cargada
|
// Crear las 4 texturas con sus respectivas paletas
|
||||||
auto base_texture = getTexture(player.base_texture);
|
for (int palette_idx = 0; palette_idx < 4; ++palette_idx) {
|
||||||
std::string pal0_name = player.name_prefix + "_pal0";
|
std::shared_ptr<Texture> texture;
|
||||||
textures_.emplace_back(pal0_name, base_texture);
|
|
||||||
printWithDots("Player Texture : ", pal0_name, "[ DONE ]");
|
|
||||||
|
|
||||||
// Crear variantes con paletas adicionales - CADA UNA DESDE EL ARCHIVO
|
if (palette_idx == 0) {
|
||||||
for (size_t i = 0; i < player.palette_files.size(); ++i) {
|
// Textura 0 - usar la ya cargada y modificar solo paleta 0 (default_shirt)
|
||||||
// Crear textura completamente nueva desde el archivo
|
texture = getTexture(player.base_texture);
|
||||||
auto texture_copy = std::make_shared<Texture>(Screen::get()->getRenderer(), texture_file_path);
|
texture->setPaletteColor(0, 16, param.player.default_shirt[player_idx].darkest.TO_UINT32());
|
||||||
|
texture->setPaletteColor(0, 17, param.player.default_shirt[player_idx].dark.TO_UINT32());
|
||||||
|
texture->setPaletteColor(0, 18, param.player.default_shirt[player_idx].base.TO_UINT32());
|
||||||
|
texture->setPaletteColor(0, 19, param.player.default_shirt[player_idx].light.TO_UINT32());
|
||||||
|
texture->setPaletteColor(0, 56, param.player.outline_color[player_idx].TO_UINT32());
|
||||||
|
} else {
|
||||||
|
// Crear textura nueva desde archivo usando ResourceHelper
|
||||||
|
texture = std::make_shared<Texture>(Screen::get()->getRenderer(), texture_file_path);
|
||||||
|
|
||||||
// Añadir todas las paletas
|
// Añadir todas las paletas
|
||||||
texture_copy->addPaletteFromPalFile(Asset::get()->get(player.palette_files[0]));
|
texture->addPaletteFromPalFile(Asset::get()->get(player.palette_files[0]));
|
||||||
texture_copy->addPaletteFromPalFile(Asset::get()->get(player.palette_files[1]));
|
texture->addPaletteFromPalFile(Asset::get()->get(player.palette_files[1]));
|
||||||
texture_copy->addPaletteFromPalFile(Asset::get()->get(player.palette_files[2]));
|
texture->addPaletteFromPalFile(Asset::get()->get(player.palette_files[2]));
|
||||||
|
|
||||||
// Cambiar a la paleta específica (índice i+1 porque 0 es la original)
|
if (palette_idx == 1) {
|
||||||
texture_copy->setPalette(i + 1);
|
// Textura 1 - modificar solo paleta 1 (one_coffee_shirt)
|
||||||
|
texture->setPaletteColor(1, 16, param.player.one_coffee_shirt[player_idx].darkest.TO_UINT32());
|
||||||
|
texture->setPaletteColor(1, 17, param.player.one_coffee_shirt[player_idx].dark.TO_UINT32());
|
||||||
|
texture->setPaletteColor(1, 18, param.player.one_coffee_shirt[player_idx].base.TO_UINT32());
|
||||||
|
texture->setPaletteColor(1, 19, param.player.one_coffee_shirt[player_idx].light.TO_UINT32());
|
||||||
|
texture->setPaletteColor(1, 56, param.player.outline_color[player_idx].TO_UINT32());
|
||||||
|
} else if (palette_idx == 2) {
|
||||||
|
// Textura 2 - modificar solo paleta 2 (two_coffee_shirt)
|
||||||
|
texture->setPaletteColor(2, 16, param.player.two_coffee_shirt[player_idx].darkest.TO_UINT32());
|
||||||
|
texture->setPaletteColor(2, 17, param.player.two_coffee_shirt[player_idx].dark.TO_UINT32());
|
||||||
|
texture->setPaletteColor(2, 18, param.player.two_coffee_shirt[player_idx].base.TO_UINT32());
|
||||||
|
texture->setPaletteColor(2, 19, param.player.two_coffee_shirt[player_idx].light.TO_UINT32());
|
||||||
|
texture->setPaletteColor(2, 56, param.player.outline_color[player_idx].TO_UINT32());
|
||||||
|
}
|
||||||
|
// Textura 3 (palette_idx == 3) - no modificar nada, usar colores originales
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asignar la paleta correspondiente
|
||||||
|
texture->setPalette(palette_idx);
|
||||||
|
|
||||||
// Guardar con nombre específico
|
// Guardar con nombre específico
|
||||||
std::string variant_name = player.name_prefix + "_pal" + std::to_string(i + 1);
|
std::string texture_name = player.name_prefix + "_pal" + std::to_string(palette_idx);
|
||||||
textures_.emplace_back(variant_name, texture_copy);
|
textures_.emplace_back(texture_name, texture);
|
||||||
printWithDots("Player Texture : ", variant_name, "[ DONE ]");
|
printWithDots("Player Texture : ", texture_name, "[ DONE ]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -585,13 +650,14 @@ void Resource::createTextTextures() {
|
|||||||
std::string text;
|
std::string text;
|
||||||
|
|
||||||
NameAndText(std::string name_init, std::string text_init)
|
NameAndText(std::string name_init, std::string text_init)
|
||||||
: name(std::move(name_init)), text(std::move(text_init)) {}
|
: name(std::move(name_init)),
|
||||||
|
text(std::move(text_init)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> CREATING TEXTURES");
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> CREATING TEXTURES");
|
||||||
|
|
||||||
// Texturas de tamaño normal
|
// Texturas de tamaño normal con outline
|
||||||
std::vector<NameAndText> strings = {
|
std::vector<NameAndText> strings1 = {
|
||||||
{"game_text_1000_points", "1.000"},
|
{"game_text_1000_points", "1.000"},
|
||||||
{"game_text_2500_points", "2.500"},
|
{"game_text_2500_points", "2.500"},
|
||||||
{"game_text_5000_points", "5.000"},
|
{"game_text_5000_points", "5.000"},
|
||||||
@@ -600,23 +666,23 @@ void Resource::createTextTextures() {
|
|||||||
{"game_text_stop", Lang::getText("[GAME_TEXT] 6")},
|
{"game_text_stop", Lang::getText("[GAME_TEXT] 6")},
|
||||||
{"game_text_1000000_points", Lang::getText("[GAME_TEXT] 8")}};
|
{"game_text_1000000_points", Lang::getText("[GAME_TEXT] 8")}};
|
||||||
|
|
||||||
auto text = getText("04b_25");
|
auto text1 = getText("04b_25_enhanced");
|
||||||
for (const auto &s : strings) {
|
for (const auto &s : strings1) {
|
||||||
textures_.emplace_back(s.name, text->writeToTexture(s.text, 1, -2));
|
textures_.emplace_back(s.name, text1->writeDXToTexture(Text::STROKE, s.text, -2, Colors::NO_COLOR_MOD, 1, param.game.item_text_outline_color));
|
||||||
printWithDots("Texture : ", s.name, "[ DONE ]");
|
printWithDots("Texture : ", s.name, "[ DONE ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Texturas de tamaño doble
|
// Texturas de tamaño doble
|
||||||
std::vector<NameAndText> strings2_x = {
|
std::vector<NameAndText> strings2 = {
|
||||||
{"game_text_100000_points", "100.000"},
|
{"game_text_100000_points", "100.000"},
|
||||||
{"game_text_get_ready", Lang::getText("[GAME_TEXT] 7")},
|
{"game_text_get_ready", Lang::getText("[GAME_TEXT] 7")},
|
||||||
{"game_text_last_stage", Lang::getText("[GAME_TEXT] 3")},
|
{"game_text_last_stage", Lang::getText("[GAME_TEXT] 3")},
|
||||||
{"game_text_congratulations", Lang::getText("[GAME_TEXT] 1")},
|
{"game_text_congratulations", Lang::getText("[GAME_TEXT] 1")},
|
||||||
{"game_text_game_over", "Game Over"}};
|
{"game_text_game_over", "Game Over"}};
|
||||||
|
|
||||||
auto text2 = getText("04b_25_2x");
|
auto text2 = getText("04b_25_2x_enhanced");
|
||||||
for (const auto &s : strings2_x) {
|
for (const auto &s : strings2) {
|
||||||
textures_.emplace_back(s.name, text2->writeToTexture(s.text, 1, -4));
|
textures_.emplace_back(s.name, text2->writeDXToTexture(Text::STROKE, s.text, -4, Colors::NO_COLOR_MOD, 1, param.game.item_text_outline_color));
|
||||||
printWithDots("Texture : ", s.name, "[ DONE ]");
|
printWithDots("Texture : ", s.name, "[ DONE ]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -627,16 +693,23 @@ void Resource::createText() {
|
|||||||
std::string key;
|
std::string key;
|
||||||
std::string texture_file;
|
std::string texture_file;
|
||||||
std::string text_file;
|
std::string text_file;
|
||||||
|
std::string white_texture_file; // Textura blanca opcional
|
||||||
|
|
||||||
ResourceInfo(std::string k, std::string t_file, std::string txt_file)
|
ResourceInfo(std::string k, std::string t_file, std::string txt_file, std::string w_file = "")
|
||||||
: key(std::move(k)), texture_file(std::move(t_file)), text_file(std::move(txt_file)) {}
|
: key(std::move(k)),
|
||||||
|
texture_file(std::move(t_file)),
|
||||||
|
text_file(std::move(txt_file)),
|
||||||
|
white_texture_file(std::move(w_file)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> CREATING TEXT OBJECTS");
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> CREATING TEXT OBJECTS");
|
||||||
|
|
||||||
std::vector<ResourceInfo> resources = {
|
std::vector<ResourceInfo> resources = {
|
||||||
{"04b_25", "04b_25.png", "04b_25.txt"},
|
{"04b_25", "04b_25.png", "04b_25.txt"},
|
||||||
|
{"04b_25_enhanced", "04b_25.png", "04b_25.txt", "04b_25_white.png"}, // Nueva fuente con textura blanca
|
||||||
|
{"04b_25_white", "04b_25_white.png", "04b_25.txt"},
|
||||||
{"04b_25_2x", "04b_25_2x.png", "04b_25_2x.txt"},
|
{"04b_25_2x", "04b_25_2x.png", "04b_25_2x.txt"},
|
||||||
|
{"04b_25_2x_enhanced", "04b_25_2x.png", "04b_25_2x.txt", "04b_25_2x_white.png"}, // Nueva fuente con textura blanca
|
||||||
{"04b_25_metal", "04b_25_metal.png", "04b_25.txt"},
|
{"04b_25_metal", "04b_25_metal.png", "04b_25.txt"},
|
||||||
{"04b_25_grey", "04b_25_grey.png", "04b_25.txt"},
|
{"04b_25_grey", "04b_25_grey.png", "04b_25.txt"},
|
||||||
{"04b_25_flat", "04b_25_flat.png", "04b_25.txt"},
|
{"04b_25_flat", "04b_25_flat.png", "04b_25.txt"},
|
||||||
@@ -649,7 +722,13 @@ void Resource::createText() {
|
|||||||
{"smb2_grad", "smb2_grad.png", "smb2.txt"}};
|
{"smb2_grad", "smb2_grad.png", "smb2.txt"}};
|
||||||
|
|
||||||
for (const auto &resource : resources) {
|
for (const auto &resource : resources) {
|
||||||
texts_.emplace_back(resource.key, std::make_shared<Text>(getTexture(resource.texture_file), getTextFile(resource.text_file)));
|
if (!resource.white_texture_file.empty()) {
|
||||||
|
// Crear texto con textura blanca
|
||||||
|
texts_.emplace_back(resource.key, std::make_shared<Text>(getTexture(resource.texture_file), getTexture(resource.white_texture_file), getTextFile(resource.text_file)));
|
||||||
|
} else {
|
||||||
|
// Crear texto normal
|
||||||
|
texts_.emplace_back(resource.key, std::make_shared<Text>(getTexture(resource.texture_file), getTextFile(resource.text_file)));
|
||||||
|
}
|
||||||
printWithDots("Text : ", resource.key, "[ DONE ]");
|
printWithDots("Text : ", resource.key, "[ DONE ]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -770,15 +849,15 @@ void Resource::initProgressBar() {
|
|||||||
const float BAR_Y_POSITION = param.game.height - BAR_HEIGHT - Y_PADDING;
|
const float BAR_Y_POSITION = param.game.height - BAR_HEIGHT - Y_PADDING;
|
||||||
|
|
||||||
const float WIRED_BAR_WIDTH = param.game.width - (X_PADDING * 2);
|
const float WIRED_BAR_WIDTH = param.game.width - (X_PADDING * 2);
|
||||||
loading_wired_rect_ = {X_PADDING, BAR_Y_POSITION, WIRED_BAR_WIDTH, BAR_HEIGHT};
|
loading_wired_rect_ = {.x = X_PADDING, .y = BAR_Y_POSITION, .w = WIRED_BAR_WIDTH, .h = BAR_HEIGHT};
|
||||||
|
|
||||||
const float FULL_BAR_WIDTH = WIRED_BAR_WIDTH * loading_count_.getPercentage();
|
const float FULL_BAR_WIDTH = WIRED_BAR_WIDTH * loading_count_.getPercentage();
|
||||||
loading_full_rect_ = {X_PADDING, BAR_Y_POSITION, FULL_BAR_WIDTH, BAR_HEIGHT};
|
loading_full_rect_ = {.x = X_PADDING, .y = BAR_Y_POSITION, .w = FULL_BAR_WIDTH, .h = BAR_HEIGHT};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualiza el progreso de carga, muestra la barra y procesa eventos
|
// Actualiza el progreso de carga, muestra la barra y procesa eventos
|
||||||
void Resource::updateLoadingProgress(std::string name) {
|
void Resource::updateLoadingProgress(std::string name) {
|
||||||
loading_resource_name_ = name;
|
loading_resource_name_ = std::move(name);
|
||||||
loading_count_.increase();
|
loading_count_.increase();
|
||||||
updateProgressBar();
|
updateProgressBar();
|
||||||
renderProgress();
|
renderProgress();
|
||||||
@@ -789,3 +868,18 @@ void Resource::updateLoadingProgress(std::string name) {
|
|||||||
void Resource::updateProgressBar() {
|
void Resource::updateProgressBar() {
|
||||||
loading_full_rect_.w = loading_wired_rect_.w * loading_count_.getPercentage();
|
loading_full_rect_.w = loading_wired_rect_.w * loading_count_.getPercentage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Limpia archivos temporales de audio
|
||||||
|
void Resource::cleanupTempAudioFiles() {
|
||||||
|
for (const auto &temp_path : temp_audio_files_) {
|
||||||
|
try {
|
||||||
|
if (std::filesystem::exists(temp_path)) {
|
||||||
|
std::filesystem::remove(temp_path);
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Removed temp audio file: %s", temp_path.c_str());
|
||||||
|
}
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to remove temp audio file %s: %s", temp_path.c_str(), e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
temp_audio_files_.clear();
|
||||||
|
}
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ class Resource {
|
|||||||
JA_Sound_t *sound; // Objeto con el sonido
|
JA_Sound_t *sound; // Objeto con el sonido
|
||||||
|
|
||||||
ResourceSound(std::string name, JA_Sound_t *sound = nullptr)
|
ResourceSound(std::string name, JA_Sound_t *sound = nullptr)
|
||||||
: name(std::move(name)), sound(sound) {}
|
: name(std::move(name)),
|
||||||
|
sound(sound) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ResourceMusic {
|
struct ResourceMusic {
|
||||||
@@ -60,7 +61,8 @@ class Resource {
|
|||||||
JA_Music_t *music; // Objeto con la música
|
JA_Music_t *music; // Objeto con la música
|
||||||
|
|
||||||
ResourceMusic(std::string name, JA_Music_t *music = nullptr)
|
ResourceMusic(std::string name, JA_Music_t *music = nullptr)
|
||||||
: name(std::move(name)), music(music) {}
|
: name(std::move(name)),
|
||||||
|
music(music) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ResourceTexture {
|
struct ResourceTexture {
|
||||||
@@ -68,7 +70,8 @@ class Resource {
|
|||||||
std::shared_ptr<Texture> texture; // Objeto con la textura
|
std::shared_ptr<Texture> texture; // Objeto con la textura
|
||||||
|
|
||||||
ResourceTexture(std::string name, std::shared_ptr<Texture> texture = nullptr)
|
ResourceTexture(std::string name, std::shared_ptr<Texture> texture = nullptr)
|
||||||
: name(std::move(name)), texture(std::move(texture)) {}
|
: name(std::move(name)),
|
||||||
|
texture(std::move(texture)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ResourceTextFile {
|
struct ResourceTextFile {
|
||||||
@@ -76,7 +79,8 @@ class Resource {
|
|||||||
std::shared_ptr<Text::File> text_file; // Objeto con los descriptores de la fuente de texto
|
std::shared_ptr<Text::File> text_file; // Objeto con los descriptores de la fuente de texto
|
||||||
|
|
||||||
ResourceTextFile(std::string name, std::shared_ptr<Text::File> text_file = nullptr)
|
ResourceTextFile(std::string name, std::shared_ptr<Text::File> text_file = nullptr)
|
||||||
: name(std::move(name)), text_file(std::move(text_file)) {}
|
: name(std::move(name)),
|
||||||
|
text_file(std::move(text_file)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ResourceText {
|
struct ResourceText {
|
||||||
@@ -84,7 +88,8 @@ class Resource {
|
|||||||
std::shared_ptr<Text> text; // Objeto de texto
|
std::shared_ptr<Text> text; // Objeto de texto
|
||||||
|
|
||||||
ResourceText(std::string name, std::shared_ptr<Text> text = nullptr)
|
ResourceText(std::string name, std::shared_ptr<Text> text = nullptr)
|
||||||
: name(std::move(name)), text(std::move(text)) {}
|
: name(std::move(name)),
|
||||||
|
text(std::move(text)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ResourceAnimation {
|
struct ResourceAnimation {
|
||||||
@@ -92,7 +97,8 @@ class Resource {
|
|||||||
AnimationsFileBuffer animation; // Objeto con las animaciones
|
AnimationsFileBuffer animation; // Objeto con las animaciones
|
||||||
|
|
||||||
ResourceAnimation(std::string name, AnimationsFileBuffer animation = {})
|
ResourceAnimation(std::string name, AnimationsFileBuffer animation = {})
|
||||||
: name(std::move(name)), animation(std::move(animation)) {}
|
: name(std::move(name)),
|
||||||
|
animation(std::move(animation)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Estructura para el progreso de carga ---
|
// --- Estructura para el progreso de carga ---
|
||||||
@@ -100,8 +106,12 @@ class Resource {
|
|||||||
size_t total; // Número total de recursos
|
size_t total; // Número total de recursos
|
||||||
size_t loaded; // Número de recursos cargados
|
size_t loaded; // Número de recursos cargados
|
||||||
|
|
||||||
ResourceCount() : total(0), loaded(0) {}
|
ResourceCount()
|
||||||
ResourceCount(size_t total) : total(total), loaded(0) {}
|
: total(0),
|
||||||
|
loaded(0) {}
|
||||||
|
ResourceCount(size_t total)
|
||||||
|
: total(total),
|
||||||
|
loaded(0) {}
|
||||||
|
|
||||||
void add(size_t amount) { loaded += amount; }
|
void add(size_t amount) { loaded += amount; }
|
||||||
void increase() { loaded++; }
|
void increase() { loaded++; }
|
||||||
@@ -129,6 +139,9 @@ class Resource {
|
|||||||
SDL_FRect loading_wired_rect_;
|
SDL_FRect loading_wired_rect_;
|
||||||
SDL_FRect loading_full_rect_;
|
SDL_FRect loading_full_rect_;
|
||||||
|
|
||||||
|
// --- Archivos temporales ---
|
||||||
|
std::vector<std::string> temp_audio_files_; // Rutas de archivos temporales de audio para limpieza
|
||||||
|
|
||||||
// --- Métodos internos de carga y gestión ---
|
// --- Métodos internos de carga y gestión ---
|
||||||
void loadSounds(); // Carga los sonidos
|
void loadSounds(); // Carga los sonidos
|
||||||
void loadMusics(); // Carga las músicas
|
void loadMusics(); // Carga las músicas
|
||||||
@@ -140,14 +153,14 @@ class Resource {
|
|||||||
void loadEssentialResources(); // Carga recursos esenciales en modo lazy
|
void loadEssentialResources(); // Carga recursos esenciales en modo lazy
|
||||||
void loadEssentialTextures(); // Carga solo las texturas esenciales (fuentes)
|
void loadEssentialTextures(); // Carga solo las texturas esenciales (fuentes)
|
||||||
void loadTextFilesQuiet(); // Carga ficheros de texto sin mostrar progreso (para modo lazy)
|
void loadTextFilesQuiet(); // Carga ficheros de texto sin mostrar progreso (para modo lazy)
|
||||||
// void addPalettes(); // Añade paletas a las texturas
|
void createPlayerTextures(); // Crea las texturas de jugadores con todas sus variantes de paleta
|
||||||
void createPlayerTextures(); // Crea las texturas de jugadores con todas sus variantes de paleta
|
void createTextTextures(); // Crea las texturas a partir de los datos cargados
|
||||||
void createTextTextures(); // Crea las texturas a partir de los datos cargados
|
void createText(); // Crea los objetos de texto
|
||||||
void createText(); // Crea los objetos de texto
|
void clear(); // Vacía todos los vectores de recursos
|
||||||
void clear(); // Vacía todos los vectores de recursos
|
void load(); // Carga todos los recursos
|
||||||
void load(); // Carga todos los recursos
|
void clearSounds(); // Vacía el vector de sonidos
|
||||||
void clearSounds(); // Vacía el vector de sonidos
|
void clearMusics(); // Vacía el vector de músicas
|
||||||
void clearMusics(); // Vacía el vector de músicas
|
void cleanupTempAudioFiles(); // Limpia archivos temporales de audio
|
||||||
|
|
||||||
// --- Métodos para carga perezosa ---
|
// --- Métodos para carga perezosa ---
|
||||||
void initResourceLists(); // Inicializa las listas de recursos sin cargar el contenido
|
void initResourceLists(); // Inicializa las listas de recursos sin cargar el contenido
|
||||||
|
|||||||
96
source/resource_helper.cpp
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
#include "resource_helper.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace ResourceHelper {
|
||||||
|
static bool resource_system_initialized = false;
|
||||||
|
|
||||||
|
bool initializeResourceSystem(const std::string& pack_file) {
|
||||||
|
auto& loader = ResourceLoader::getInstance();
|
||||||
|
resource_system_initialized = loader.initialize(pack_file, true);
|
||||||
|
|
||||||
|
if (resource_system_initialized) {
|
||||||
|
std::cout << "Resource system initialized with pack: " << pack_file << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "Resource system using fallback mode (filesystem only)" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // Always return true as fallback is acceptable
|
||||||
|
}
|
||||||
|
|
||||||
|
void shutdownResourceSystem() {
|
||||||
|
if (resource_system_initialized) {
|
||||||
|
ResourceLoader::getInstance().shutdown();
|
||||||
|
resource_system_initialized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> loadFile(const std::string& filepath) {
|
||||||
|
if (resource_system_initialized && shouldUseResourcePack(filepath)) {
|
||||||
|
auto& loader = ResourceLoader::getInstance();
|
||||||
|
std::string pack_path = getPackPath(filepath);
|
||||||
|
|
||||||
|
auto data = loader.loadResource(pack_path);
|
||||||
|
if (!data.empty()) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback a filesystem
|
||||||
|
std::ifstream file(filepath, std::ios::binary | std::ios::ate);
|
||||||
|
if (!file) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::streamsize fileSize = file.tellg();
|
||||||
|
file.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
std::vector<uint8_t> data(fileSize);
|
||||||
|
if (!file.read(reinterpret_cast<char*>(data.data()), fileSize)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shouldUseResourcePack(const std::string& filepath) {
|
||||||
|
// Archivos que NO van al pack:
|
||||||
|
// - config/ (ahora está fuera de data/)
|
||||||
|
// - archivos absolutos del sistema
|
||||||
|
|
||||||
|
if (filepath.find("config/") != std::string::npos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si contiene "data/" es candidato para el pack
|
||||||
|
if (filepath.find("data/") != std::string::npos) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getPackPath(const std::string& asset_path) {
|
||||||
|
std::string pack_path = asset_path;
|
||||||
|
|
||||||
|
// Normalizar separadores de path a '/'
|
||||||
|
std::replace(pack_path.begin(), pack_path.end(), '\\', '/');
|
||||||
|
|
||||||
|
// Remover prefijo "data/" si existe
|
||||||
|
size_t data_pos = pack_path.find("data/");
|
||||||
|
if (data_pos != std::string::npos) {
|
||||||
|
pack_path = pack_path.substr(data_pos + 5); // +5 para saltar "data/"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remover cualquier prefijo de path absoluto
|
||||||
|
size_t last_data = pack_path.rfind("data/");
|
||||||
|
if (last_data != std::string::npos) {
|
||||||
|
pack_path = pack_path.substr(last_data + 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pack_path;
|
||||||
|
}
|
||||||
|
} // namespace ResourceHelper
|
||||||
47
source/resource_helper.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "resource_loader.h"
|
||||||
|
|
||||||
|
// Helper functions para integrar ResourceLoader con el sistema existente
|
||||||
|
namespace ResourceHelper {
|
||||||
|
// Inicializa ResourceLoader (llamar al inicio del programa)
|
||||||
|
bool initializeResourceSystem(const std::string& pack_file = "resources.pack");
|
||||||
|
|
||||||
|
// Cierra ResourceLoader
|
||||||
|
void shutdownResourceSystem();
|
||||||
|
|
||||||
|
// Carga un archivo usando ResourceLoader o fallback a filesystem
|
||||||
|
std::vector<uint8_t> loadFile(const std::string& filepath);
|
||||||
|
|
||||||
|
// Verifica si un archivo debería cargarse del pack vs filesystem
|
||||||
|
bool shouldUseResourcePack(const std::string& filepath);
|
||||||
|
|
||||||
|
// Convierte ruta Asset a ruta relativa para ResourceLoader
|
||||||
|
std::string getPackPath(const std::string& asset_path);
|
||||||
|
|
||||||
|
// Wrappea la carga de archivos para mantener compatibilidad
|
||||||
|
template <typename T>
|
||||||
|
T* loadResourceFile(const std::string& asset_path, T* (*loader_func)(const char*)) {
|
||||||
|
auto data = loadFile(asset_path);
|
||||||
|
if (data.empty()) {
|
||||||
|
return loader_func(asset_path.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crear archivo temporal para funciones que esperan path
|
||||||
|
std::string temp_path = "/tmp/ccae_" + std::to_string(std::hash<std::string>{}(asset_path));
|
||||||
|
std::ofstream temp_file(temp_path, std::ios::binary);
|
||||||
|
temp_file.write(reinterpret_cast<const char*>(data.data()), data.size());
|
||||||
|
temp_file.close();
|
||||||
|
|
||||||
|
T* result = loader_func(temp_path.c_str());
|
||||||
|
std::filesystem::remove(temp_path);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} // namespace ResourceHelper
|
||||||
135
source/resource_loader.cpp
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
#include "resource_loader.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
std::unique_ptr<ResourceLoader> ResourceLoader::instance = nullptr;
|
||||||
|
|
||||||
|
ResourceLoader::ResourceLoader()
|
||||||
|
: resourcePack(nullptr),
|
||||||
|
fallbackToFiles(true) {}
|
||||||
|
|
||||||
|
ResourceLoader& ResourceLoader::getInstance() {
|
||||||
|
if (!instance) {
|
||||||
|
instance = std::unique_ptr<ResourceLoader>(new ResourceLoader());
|
||||||
|
}
|
||||||
|
return *instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceLoader::~ResourceLoader() {
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ResourceLoader::initialize(const std::string& packFile, bool enableFallback) {
|
||||||
|
shutdown();
|
||||||
|
|
||||||
|
fallbackToFiles = enableFallback;
|
||||||
|
packPath = packFile;
|
||||||
|
|
||||||
|
if (std::filesystem::exists(packFile)) {
|
||||||
|
resourcePack = new ResourcePack();
|
||||||
|
if (resourcePack->loadPack(packFile)) {
|
||||||
|
std::cout << "Resource pack loaded successfully: " << packFile << std::endl;
|
||||||
|
std::cout << "Resources available: " << resourcePack->getResourceCount() << std::endl;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
delete resourcePack;
|
||||||
|
resourcePack = nullptr;
|
||||||
|
std::cerr << "Failed to load resource pack: " << packFile << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fallbackToFiles) {
|
||||||
|
std::cout << "Using fallback mode: loading resources from data/ directory" << std::endl;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "Resource pack not found and fallback disabled: " << packFile << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceLoader::shutdown() {
|
||||||
|
if (resourcePack) {
|
||||||
|
delete resourcePack;
|
||||||
|
resourcePack = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> ResourceLoader::loadResource(const std::string& filename) {
|
||||||
|
if (resourcePack && resourcePack->hasResource(filename)) {
|
||||||
|
return resourcePack->getResource(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fallbackToFiles) {
|
||||||
|
return loadFromFile(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "Resource not found: " << filename << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ResourceLoader::resourceExists(const std::string& filename) {
|
||||||
|
if (resourcePack && resourcePack->hasResource(filename)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fallbackToFiles) {
|
||||||
|
std::string fullPath = getDataPath(filename);
|
||||||
|
return std::filesystem::exists(fullPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> ResourceLoader::loadFromFile(const std::string& filename) {
|
||||||
|
std::string fullPath = getDataPath(filename);
|
||||||
|
|
||||||
|
std::ifstream file(fullPath, std::ios::binary | std::ios::ate);
|
||||||
|
if (!file) {
|
||||||
|
std::cerr << "Error: Could not open file: " << fullPath << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::streamsize fileSize = file.tellg();
|
||||||
|
file.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
std::vector<uint8_t> data(fileSize);
|
||||||
|
if (!file.read(reinterpret_cast<char*>(data.data()), fileSize)) {
|
||||||
|
std::cerr << "Error: Could not read file: " << fullPath << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ResourceLoader::getDataPath(const std::string& filename) {
|
||||||
|
return "data/" + filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ResourceLoader::getLoadedResourceCount() const {
|
||||||
|
if (resourcePack) {
|
||||||
|
return resourcePack->getResourceCount();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ResourceLoader::getAvailableResources() const {
|
||||||
|
if (resourcePack) {
|
||||||
|
return resourcePack->getResourceList();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> result;
|
||||||
|
if (fallbackToFiles && std::filesystem::exists("data")) {
|
||||||
|
for (const auto& entry : std::filesystem::recursive_directory_iterator("data")) {
|
||||||
|
if (entry.is_regular_file()) {
|
||||||
|
std::string filename = std::filesystem::relative(entry.path(), "data").string();
|
||||||
|
std::replace(filename.begin(), filename.end(), '\\', '/');
|
||||||
|
result.push_back(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||