66 Commits

Author SHA1 Message Date
7250073d60 actualitzat LICENSE 2025-08-19 16:45:00 +02:00
dfa06870e4 actualitzat makefile per a linux 2025-08-19 16:42:40 +02:00
81f3a25143 afegit makefile per a macos 2025-08-19 16:39:39 +02:00
5aca95f3d2 neteja de temporals al acabar 2025-08-19 16:29:52 +02:00
7b193605e6 refet makefile i eliminades *.dll 2025-08-19 14:09:11 +02:00
089a5b15d7 actualitzat Makefile per a windows 2025-08-19 14:01:32 +02:00
e6a14ca57d eliminat el log del codi 2025-08-19 13:55:22 +02:00
467d609c28 debug 2025-08-19 13:50:11 +02:00
e03c798000 afegits logs peer a la carrega de musica i sons 2025-08-19 13:46:07 +02:00
52d76b7338 arreglos pa NO integrar jail_audio en ResourceHelper 2025-08-19 13:36:03 +02:00
83ee9c2649 integrat animated_sprite amb ResourceHelper 2025-08-19 13:25:12 +02:00
43788bb01a faltaven mes integracions de texture amb ResourceHelper 2025-08-19 13:22:38 +02:00
58cf78e1e3 integracions de texture.cpp amb ResourceHelper 2025-08-19 13:13:27 +02:00
6bf8490776 integrades mes clases amb ResourceHelper
mogudes les dades de la demo a resource.pack
2025-08-19 13:08:37 +02:00
8cfe28922c integrat Text amb ResourceHelper 2025-08-19 12:45:53 +02:00
63990c75c2 modificat texture.cpp per a gastar ResourceHelper 2025-08-19 12:41:08 +02:00
94dca528ab fix assets.txt 2025-08-19 10:13:12 +02:00
4b6b89ceb2 integrat Asset amb ResourceHelper 2025-08-19 10:06:52 +02:00
ed077c1da5 treballant en resources.pack 2025-08-19 09:46:19 +02:00
2819b3628e el fitxer de parametres es guarda en options/config.txt 2025-08-17 21:42:26 +02:00
1e9e664012 creat param_red.txt
afegides guardes en setParams
2025-08-17 21:29:49 +02:00
0c8b39cee7 els items ja no tenen vel_x = 0 2025-08-17 20:42:55 +02:00
d7b3af5ab8 en el modo demo asignava cafes al jugador que no jugava i eixia saludant amb la camisa que no toca 2025-08-17 20:22:53 +02:00
5e5227305f arreglat bug en el estat pre del fade 2025-08-17 20:17:55 +02:00
3fc15a9512 afegit el fade RANDOM_SQAURE2
canviat els timings del fade a milisegons
2025-08-17 19:34:48 +02:00
e774e0e8ad modificat el efecte de invulnerabilitat per a que vaja menguant 2025-08-17 17:21:03 +02:00
a95776e6c7 retocat el audio de recover 2025-08-17 17:01:49 +02:00
0428ff26d5 options.h ara gasta defaults.h 2025-08-17 16:28:30 +02:00
fc3e2deb1f Item fix: alguns items es quedaven engantxats en la part de dalt 2025-08-17 16:18:48 +02:00
65ca17f938 afegit i parametritzat outline per als textos dels items 2025-08-17 16:07:16 +02:00
ff2a51a507 noves coses chules en la clase text 2025-08-17 14:25:17 +02:00
fe0083abd4 afagit a param el color de la camiseta per defecte 2025-08-17 13:25:10 +02:00
1c058694fd afegit a param el color de outline dels jugadors 2025-08-17 12:58:20 +02:00
cb0c3266d5 proposta 1 de versio RC2 2025-08-17 10:54:45 +02:00
8ddc5d94f1 clang-tidy 2025-08-17 10:20:41 +02:00
b359a73d50 He tornat a deixar el progres del fondo que fa tope en la ultima fase, no en el final del joc 2025-08-17 08:20:38 +02:00
142603db71 hi_score_table: faltava posar el fondo en modo manual
game: redefinides les prioritats de dibuixat -> jugadors altra volta al front
2025-08-17 08:08:48 +02:00
1ec272f017 . 2025-08-17 01:10:57 +02:00
327987447d passant linters a vore si trobe variables sense inicialitzar 2025-08-17 00:23:59 +02:00
ada5025c65 claude: arreglos d'estil 2025-08-16 19:48:32 +02:00
1ced698093 ja guarda la configuració del mando amb els boto-triggers 2025-08-16 18:13:55 +02:00
2a4c47a6ca ja permet mapejar botons tipo trigger 2025-08-16 18:03:32 +02:00
6102504d32 parametrizats els colors de les camisetes dels jugadors quan pillen café 2025-08-16 13:12:22 +02:00
a123b3aa93 afegit window_message a param 2025-08-16 11:24:28 +02:00
81d486f2d3 afegit defaults.h amb els valors per defecte de Param 2025-08-16 10:29:30 +02:00
0c10898bdc Tabe: afegit a Param 2025-08-16 09:54:34 +02:00
a3cd404545 retocs en els fitxers de configuració 2025-08-16 09:44:06 +02:00
5c708fc60a eliminat codi mort 2025-08-16 09:33:40 +02:00
960ee367df fix: els globos apareixien un frame mal situats al crearse desde un pare 2025-08-15 13:09:07 +02:00
a7519fc372 afegit AnimatedSprite::getCurrentAnimationFrame()
fix: player2.gif faltava el outline
noves veus i arreglo d'altres
style: fitxer de config
2025-08-15 11:09:17 +02:00
a983269080 animacions noves de recuperació per als jugadors 2025-08-15 06:38:52 +02:00
3964503f1c game fix: la velocitat dels globos dins de la fase actual muntava al primer globo explotat
game fix: al trencar una powerball ja no eixien mes globos
style: renombrades variables i funcions
2025-08-14 20:41:44 +02:00
8fcb7d1eb5 eliminat un warning en systemes unix 2025-08-14 18:05:36 +02:00
3e68afa4be game.cpp: llevat codi comentat mort de feia temps 2025-08-14 13:58:24 +02:00
ca6edcccc0 Afegida animacioneta pa quan continues 2025-08-14 12:55:29 +02:00
a388005968 Afegit lletreret de "gracies" al continuar 2025-08-14 12:37:39 +02:00
ea7628259a la IA havia trencat el recorregut de la lluna 2025-08-14 12:20:34 +02:00
a13e024934 fix: la IA havia trencat el indicador de fases restants 2025-08-14 11:36:29 +02:00
4cc5102d70 Stage ja carrega desde fitxer la informació de les fases 2025-08-14 11:14:54 +02:00
b2139d8e06 treballant en Background i Stage 2025-08-14 09:53:01 +02:00
ea3e704d34 posant ordre en Stage i Background 2025-08-13 14:04:24 +02:00
d5ab5748a7 actualitzat makefile per a linux desktop 2025-08-11 21:39:43 +02:00
e950eb335d YE! ACTUALIZAT MAKEFILE PA WINDOWS ALTRA VOLTA. PUTA IA 2025-08-11 20:30:59 +02:00
e667063767 actualitzat makefile per a linux 2025-08-11 20:28:16 +02:00
3534e4cc54 actualitzat makefile per a windows 2025-08-11 20:27:40 +02:00
685b04c840 afegits nous iconos per a la aplicació
afegit script en python per a crear els iconos
2025-08-11 19:12:17 +02:00
161 changed files with 6358 additions and 2960 deletions

View File

@@ -6,7 +6,14 @@ BreakBeforeBraces: Attach # Llaves en la misma línea
AllowShortIfStatementsOnASingleLine: true
AllowShortBlocksOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AlignOperands: false
AlignOperands: DontAlign
AlignAfterOpenBracket: DontAlign
BinPackArguments: false
BinPackParameters: false
ContinuationIndentWidth: 4
ConstructorInitializerIndentWidth: 4
IndentWrappedFunctionNames: false
Cpp11BracedListStyle: true
BreakConstructorInitializers: BeforeComma
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false

View File

@@ -1,8 +1,21 @@
Checks: >
readability-*,
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-magic-numbers
-readability-magic-numbers,
-bugprone-narrowing-conversions,
-performance-enum-size,
-performance-inefficient-string-concatenation,
-bugprone-integer-division,
-bugprone-easily-swappable-parameters,
WarningsAsErrors: '*'
# Solo incluir archivos de tu código fuente

View File

@@ -28,6 +28,9 @@ set(APP_SOURCES
source/main.cpp
source/param.cpp
source/resource.cpp
source/resource_helper.cpp
source/resource_loader.cpp
source/resource_pack.cpp
source/screen.cpp
source/text.cpp
source/writer.cpp

22
LICENSE
View File

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

194
Makefile
View File

@@ -11,7 +11,22 @@ APP_NAME := Coffee Crisis Arcade Edition
RELEASE_FOLDER := ccae_release
RELEASE_FILE := $(RELEASE_FOLDER)/$(TARGET_NAME)
RESOURCE_FILE := release/coffee.res
VERSION := 2025-08-10
# Versión automática basada en la fecha actual (específica por SO)
ifeq ($(OS),Windows_NT)
VERSION := $(shell powershell -Command "Get-Date -Format 'yyyy-MM-dd'")
else
VERSION := $(shell date +%Y-%m-%d)
endif
# Variables específicas para Windows (usando APP_NAME)
ifeq ($(OS),Windows_NT)
WIN_TARGET_FILE := $(DIR_BIN)$(APP_NAME)
WIN_RELEASE_FILE := $(RELEASE_FOLDER)/$(APP_NAME)
else
WIN_TARGET_FILE := $(TARGET_FILE)
WIN_RELEASE_FILE := $(RELEASE_FILE)
endif
# Nombres para los ficheros de lanzamiento
WINDOWS_RELEASE := $(TARGET_NAME)-$(VERSION)-win32-x64.zip
@@ -56,6 +71,9 @@ APP_SOURCES := \
source/path_sprite.cpp \
source/player.cpp \
source/resource.cpp \
source/resource_helper.cpp \
source/resource_loader.cpp \
source/resource_pack.cpp \
source/scoreboard.cpp \
source/screen.cpp \
source/sections/credits.cpp \
@@ -89,7 +107,7 @@ INCLUDES := -Isource -Isource/external
# Variables según el sistema operativo
ifeq ($(OS),Windows_NT)
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
LDFLAGS := -lmingw32 -lws2_32 -lSDL3 -lopengl32
RM := del /Q
@@ -120,27 +138,32 @@ endif
# Reglas para compilación
windows:
@echo off
@echo Compilando para Windows con nombre: "$(APP_NAME).exe"
windres release/coffee.rc -O coff -o $(RESOURCE_FILE)
$(CXX) $(APP_SOURCES) $(RESOURCE_FILE) $(INCLUDES) $(CXXFLAGS) $(LDFLAGS) -o "$(TARGET_FILE).exe"
strip -s -R .comment -R .gnu.version "$(TARGET_FILE).exe" --strip-unneeded
$(CXX) $(APP_SOURCES) $(RESOURCE_FILE) $(INCLUDES) $(CXXFLAGS) $(LDFLAGS) -o "$(WIN_TARGET_FILE).exe"
strip -s -R .comment -R .gnu.version "$(WIN_TARGET_FILE).exe" --strip-unneeded
windows_rec:
@echo off
$(CXX) $(APP_SOURCES) $(INCLUDES) -DRECORDING $(CXXFLAGS) $(LDFLAGS) -o "$(TARGET_FILE)_rec.exe"
@echo Compilando version de grabacion para Windows: "$(APP_NAME)_rec.exe"
$(CXX) $(APP_SOURCES) $(INCLUDES) -DRECORDING $(CXXFLAGS) $(LDFLAGS) -o "$(WIN_TARGET_FILE)_rec.exe"
windows_debug:
@echo off
$(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug.exe"
@echo Compilando version debug para Windows: "$(APP_NAME)_debug.exe"
$(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(WIN_TARGET_FILE)_debug.exe"
windows_release:
@echo off
@echo Creando release para Windows - Version: $(VERSION)
# Crea carpeta temporal 'RELEASE_FOLDER'
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}
# Copia la carpeta 'data'
powershell Copy-Item -Path "data" -Destination "$(RELEASE_FOLDER)" -recurse -Force
# Copia la carpeta 'config' y el archivo 'resources.pack'
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
powershell Copy-Item "LICENSE" -Destination "$(RELEASE_FOLDER)"
@@ -149,23 +172,27 @@ windows_release:
# Compila
windres release/coffee.rc -O coff -o $(RESOURCE_FILE)
$(CXX) $(APP_SOURCES) $(RESOURCE_FILE) $(INCLUDES) $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FILE).exe"
strip -s -R .comment -R .gnu.version "$(RELEASE_FILE).exe" --strip-unneeded
$(CXX) $(APP_SOURCES) $(RESOURCE_FILE) $(INCLUDES) $(CXXFLAGS) $(LDFLAGS) -o "$(WIN_RELEASE_FILE).exe"
strip -s -R .comment -R .gnu.version "$(WIN_RELEASE_FILE).exe" --strip-unneeded
# Crea el fichero .zip
powershell if (Test-Path "$(WINDOWS_RELEASE)") {Remove-Item "$(WINDOWS_RELEASE)"}
powershell Compress-Archive -Path "$(RELEASE_FOLDER)"/* -DestinationPath "$(WINDOWS_RELEASE)"
@echo Release creado: $(WINDOWS_RELEASE)
# Elimina la carpeta temporal 'RELEASE_FOLDER'
powershell if (Test-Path "$(RELEASE_FOLDER)") {Remove-Item "$(RELEASE_FOLDER)" -Recurse -Force}
macos:
@echo "Compilando para macOS: $(TARGET_NAME)"
$(CXX) $(APP_SOURCES) $(INCLUDES) $(CXXFLAGS) $(LDFLAGS) -o "$(TARGET_FILE)"
macos_debug:
@echo "Compilando version debug para macOS: $(TARGET_NAME)_debug"
$(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
macos_release:
@echo "Creando release para macOS - Version: $(VERSION)"
# Elimina datos de compilaciones anteriores
$(RMDIR) "$(RELEASE_FOLDER)"
$(RMDIR) Frameworks
@@ -180,7 +207,8 @@ macos_release:
$(MKDIR) Frameworks
# 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 Frameworks
cp release/*.icns "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
@@ -202,6 +230,7 @@ ifdef ENABLE_MACOS_X86_64
hdiutil create tmp.dmg -ov -volname "$(APP_NAME)" -fs HFS+ -srcfolder "$(RELEASE_FOLDER)"
hdiutil convert tmp.dmg -format UDZO -o "$(MACOS_INTEL_RELEASE)"
$(RMFILE) tmp.dmg
@echo "Release Intel creado: $(MACOS_INTEL_RELEASE)"
endif
# Compila la versión para procesadores Apple Silicon
@@ -214,19 +243,23 @@ endif
hdiutil create tmp.dmg -ov -volname "$(APP_NAME)" -fs HFS+ -srcfolder "$(RELEASE_FOLDER)"
hdiutil convert tmp.dmg -format UDZO -o "$(MACOS_APPLE_SILICON_RELEASE)"
$(RMFILE) tmp.dmg
@echo "Release Apple Silicon creado: $(MACOS_APPLE_SILICON_RELEASE)"
# Elimina las carpetas temporales
$(RMDIR) Frameworks
$(RMDIR) "$(RELEASE_FOLDER)"
linux:
@echo "Compilando para Linux: $(TARGET_NAME)"
$(CXX) $(APP_SOURCES) $(INCLUDES) $(CXXFLAGS) $(LDFLAGS) -o "$(TARGET_FILE)"
strip -s -R .comment -R .gnu.version "$(TARGET_FILE)" --strip-unneeded
linux_debug:
@echo "Compilando version debug para Linux: $(TARGET_NAME)_debug"
$(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
linux_release:
@echo "Creando release para Linux - Version: $(VERSION)"
# Elimina carpetas previas
$(RMDIR) "$(RELEASE_FOLDER)"
@@ -234,7 +267,8 @@ linux_release:
$(MKDIR) "$(RELEASE_FOLDER)"
# Copia ficheros
cp -R data "$(RELEASE_FOLDER)"
cp -R config "$(RELEASE_FOLDER)"
cp resources.pack "$(RELEASE_FOLDER)"
cp LICENSE "$(RELEASE_FOLDER)"
cp README.md "$(RELEASE_FOLDER)"
@@ -245,18 +279,118 @@ linux_release:
# Empaqueta ficheros
$(RMFILE) "$(LINUX_RELEASE)"
tar -czvf "$(LINUX_RELEASE)" -C "$(RELEASE_FOLDER)" .
@echo "Release creado: $(LINUX_RELEASE)"
# Elimina la carpeta temporal
$(RMDIR) "$(RELEASE_FOLDER)"
linux_release_desktop:
@echo "Creando release con integracion desktop para Linux - Version: $(VERSION)"
# Elimina carpetas previas
$(RMDIR) "$(RELEASE_FOLDER)"
# Crea la estructura de directorios estándar para Linux
$(MKDIR) "$(RELEASE_FOLDER)/$(TARGET_NAME)"
$(MKDIR) "$(RELEASE_FOLDER)/$(TARGET_NAME)/bin"
$(MKDIR) "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/applications"
$(MKDIR) "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/icons/hicolor/256x256/apps"
$(MKDIR) "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)"
# Copia ficheros del juego
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 README.md "$(RELEASE_FOLDER)/$(TARGET_NAME)/"
# Compila el ejecutable
$(CXX) $(APP_SOURCES) $(INCLUDES) $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FOLDER)/$(TARGET_NAME)/bin/$(TARGET_NAME)"
strip -s -R .comment -R .gnu.version "$(RELEASE_FOLDER)/$(TARGET_NAME)/bin/$(TARGET_NAME)" --strip-unneeded
# Crea el archivo .desktop
@echo '[Desktop Entry]' > "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/applications/$(TARGET_NAME).desktop"
@echo 'Version=1.0' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/applications/$(TARGET_NAME).desktop"
@echo 'Type=Application' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/applications/$(TARGET_NAME).desktop"
@echo 'Name=$(APP_NAME)' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/applications/$(TARGET_NAME).desktop"
@echo 'Comment=Arcade action game - defend Earth from alien invasion!' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/applications/$(TARGET_NAME).desktop"
@echo 'Exec=/opt/$(TARGET_NAME)/bin/$(TARGET_NAME)' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/applications/$(TARGET_NAME).desktop"
@echo 'Icon=$(TARGET_NAME)' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/applications/$(TARGET_NAME).desktop"
@echo 'Path=/opt/$(TARGET_NAME)/share/$(TARGET_NAME)' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/applications/$(TARGET_NAME).desktop"
@echo 'Terminal=false' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/applications/$(TARGET_NAME).desktop"
@echo 'StartupNotify=true' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/applications/$(TARGET_NAME).desktop"
@echo 'Categories=Game;ArcadeGame;' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/applications/$(TARGET_NAME).desktop"
@echo 'Keywords=arcade;action;shooter;retro;' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/applications/$(TARGET_NAME).desktop"
# Copia el icono (si existe) y lo redimensiona si es necesario
@if [ -f "release/icon.png" ]; then \
if command -v magick >/dev/null 2>&1; then \
magick "release/icon.png" -resize 256x256 "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/icons/hicolor/256x256/apps/$(TARGET_NAME).png"; \
echo "Icono redimensionado de release/icon.png (usando ImageMagick)"; \
elif command -v convert >/dev/null 2>&1; then \
convert "release/icon.png" -resize 256x256 "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/icons/hicolor/256x256/apps/$(TARGET_NAME).png"; \
echo "Icono redimensionado de release/icon.png (usando ImageMagick legacy)"; \
elif command -v ffmpeg >/dev/null 2>&1; then \
ffmpeg -i "release/icon.png" -vf scale=256:256 "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/icons/hicolor/256x256/apps/$(TARGET_NAME).png" -y -loglevel quiet; \
echo "Icono redimensionado de release/icon.png (usando ffmpeg)"; \
else \
cp "release/icon.png" "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/icons/hicolor/256x256/apps/$(TARGET_NAME).png"; \
echo "Icono copiado sin redimensionar (instalar ImageMagick o ffmpeg para redimensionado automatico)"; \
fi; \
elif [ -f "release/coffee.png" ]; then \
cp "release/coffee.png" "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/icons/hicolor/256x256/apps/$(TARGET_NAME).png"; \
echo "Icono copiado desde release/coffee.png"; \
else \
echo "Advertencia: No se encontró release/icon.png ni release/coffee.png - crear icono manualmente"; \
fi
# Crea script de instalación
@echo '#!/bin/bash' > "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
@echo 'echo "Instalando $(APP_NAME)..."' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
@echo 'sudo mkdir -p /opt/$(TARGET_NAME)' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
@echo 'sudo cp -R bin /opt/$(TARGET_NAME)/' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
@echo 'sudo cp -R share /opt/$(TARGET_NAME)/' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
@echo 'sudo cp LICENSE /opt/$(TARGET_NAME)/' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
@echo 'sudo cp README.md /opt/$(TARGET_NAME)/' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
@echo 'sudo mkdir -p /usr/share/applications' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
@echo 'sudo mkdir -p /usr/share/icons/hicolor/256x256/apps' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
@echo 'sudo cp /opt/$(TARGET_NAME)/share/applications/$(TARGET_NAME).desktop /usr/share/applications/' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
@echo 'sudo cp /opt/$(TARGET_NAME)/share/icons/hicolor/256x256/apps/$(TARGET_NAME).png /usr/share/icons/hicolor/256x256/apps/' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
@echo 'sudo update-desktop-database /usr/share/applications 2>/dev/null || true' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
@echo 'sudo gtk-update-icon-cache /usr/share/icons/hicolor 2>/dev/null || true' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
@echo 'echo "$(APP_NAME) instalado correctamente!"' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
@echo 'echo "Ya puedes encontrarlo en el menu de aplicaciones en la categoria Juegos."' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
chmod +x "$(RELEASE_FOLDER)/$(TARGET_NAME)/install.sh"
# Crea script de desinstalación
@echo '#!/bin/bash' > "$(RELEASE_FOLDER)/$(TARGET_NAME)/uninstall.sh"
@echo 'echo "Desinstalando $(APP_NAME)..."' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/uninstall.sh"
@echo 'sudo rm -rf /opt/$(TARGET_NAME)' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/uninstall.sh"
@echo 'sudo rm -f /usr/share/applications/$(TARGET_NAME).desktop' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/uninstall.sh"
@echo 'sudo rm -f /usr/share/icons/hicolor/256x256/apps/$(TARGET_NAME).png' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/uninstall.sh"
@echo 'sudo update-desktop-database /usr/share/applications 2>/dev/null || true' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/uninstall.sh"
@echo 'sudo gtk-update-icon-cache /usr/share/icons/hicolor 2>/dev/null || true' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/uninstall.sh"
@echo 'echo "$(APP_NAME) desinstalado correctamente."' >> "$(RELEASE_FOLDER)/$(TARGET_NAME)/uninstall.sh"
chmod +x "$(RELEASE_FOLDER)/$(TARGET_NAME)/uninstall.sh"
# Empaqueta ficheros
$(RMFILE) "$(TARGET_NAME)-$(VERSION)-linux-desktop.tar.gz"
tar -czvf "$(TARGET_NAME)-$(VERSION)-linux-desktop.tar.gz" -C "$(RELEASE_FOLDER)" .
@echo "Release con integracion desktop creado: $(TARGET_NAME)-$(VERSION)-linux-desktop.tar.gz"
@echo "Para instalar: extraer y ejecutar ./$(TARGET_NAME)/install.sh"
# Elimina la carpeta temporal
$(RMDIR) "$(RELEASE_FOLDER)"
raspi:
@echo "Compilando para Raspberry Pi: $(TARGET_NAME)"
$(CXX) $(APP_SOURCES) $(INCLUDES) -DVERBOSE $(CXXFLAGS) $(LDFLAGS) -o $(TARGET_FILE)
strip -s -R .comment -R .gnu.version $(TARGET_FILE) --strip-unneeded
raspi_debug:
@echo "Compilando version debug para Raspberry Pi: $(TARGET_NAME)_debug"
$(CXX) $(APP_SOURCES) $(INCLUDES) -DVERBOSE -DDEBUG $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
raspi_release:
@echo "Creando release para Raspberry Pi - Version: $(VERSION)"
# Elimina carpetas previas
$(RMDIR) "$(RELEASE_FOLDER)"
@@ -264,7 +398,8 @@ raspi_release:
$(MKDIR) "$(RELEASE_FOLDER)"
# Copia ficheros
cp -R data "$(RELEASE_FOLDER)"
cp -R config "$(RELEASE_FOLDER)"
cp resources.pack "$(RELEASE_FOLDER)"
cp LICENSE "$(RELEASE_FOLDER)"
cp README.md "$(RELEASE_FOLDER)"
@@ -275,11 +410,13 @@ raspi_release:
# Empaqueta ficheros
$(RMFILE) "$(RASPI_RELEASE)"
tar -czvf "$(RASPI_RELEASE)" -C "$(RELEASE_FOLDER)" .
@echo "Release creado: $(RASPI_RELEASE)"
# Elimina la carpeta temporal
$(RMDIR) "$(RELEASE_FOLDER)"
anbernic:
@echo "Compilando para Anbernic: $(TARGET_NAME)"
# Elimina carpetas previas
$(RMDIR) "$(RELEASE_FOLDER)"_anbernic
@@ -287,13 +424,40 @@ anbernic:
$(MKDIR) "$(RELEASE_FOLDER)"_anbernic
# Copia ficheros
cp -R data "$(RELEASE_FOLDER)"_anbernic
cp -R config "$(RELEASE_FOLDER)"_anbernic
cp resources.pack "$(RELEASE_FOLDER)"_anbernic
# Compila
$(CXX) $(APP_SOURCES) $(INCLUDES) -DANBERNIC -DNO_SHADERS -DARCADE -DVERBOSE $(CXXFLAGS) $(LDFLAGS) -o $(RELEASE_FOLDER)_anbernic/$(TARGET_NAME)
# Opción para deshabilitar audio (equivalente a la opción DISABLE_AUDIO de CMake)
no_audio:
@echo "Compilando sin audio: $(TARGET_NAME)_no_audio"
$(CXX) $(filter-out source/external/jail_audio.cpp,$(APP_SOURCES)) $(INCLUDES) -DNO_AUDIO $(CXXFLAGS) $(LDFLAGS) -o "$(TARGET_FILE)_no_audio"
.PHONY: windows windows_rec windows_debug windows_release macos macos_debug macos_release linux linux_debug linux_release raspi raspi_debug raspi_release anbernic no_audio
# Regla para mostrar la versión actual
show_version:
@echo "Version actual: $(VERSION)"
# Regla de ayuda
help:
@echo "Makefile para Coffee Crisis Arcade Edition"
@echo "Comandos disponibles:"
@echo " windows - Compilar para Windows"
@echo " windows_debug - Compilar debug para Windows"
@echo " windows_release - Crear release completo para Windows"
@echo " linux - Compilar para Linux"
@echo " linux_debug - Compilar debug para Linux"
@echo " linux_release - Crear release basico para Linux"
@echo " linux_release_desktop - Crear release con integracion desktop para Linux"
@echo " macos - Compilar para macOS"
@echo " macos_debug - Compilar debug para macOS"
@echo " macos_release - Crear release completo para macOS"
@echo " raspi - Compilar para Raspberry Pi"
@echo " raspi_release - Crear release completo para Raspberry Pi"
@echo " anbernic - Compilar para Anbernic"
@echo " no_audio - Compilar sin sistema de audio"
@echo " show_version - Mostrar version actual ($(VERSION))"
@echo " help - Mostrar esta ayuda"
.PHONY: windows windows_rec windows_debug windows_release macos macos_debug macos_release linux linux_debug linux_release linux_release_desktop raspi raspi_debug raspi_release anbernic no_audio show_version help

View File

@@ -1,4 +1,4 @@
# Coffee Crisis - Asset Configuration
# Coffee Crisis Arcade Edition - Asset Configuration
# Formato: TIPO|RUTA [|OPCIONES]
# Opciones: optional, absolute (separadas por comas)
# Variables: ${PREFIX}, ${SYSTEM_FOLDER}
@@ -9,33 +9,38 @@ DATA|${SYSTEM_FOLDER}/controllers.json|optional,absolute
DATA|${SYSTEM_FOLDER}/score.bin|optional,absolute
# Archivos de configuración del juego
DATA|${PREFIX}/data/config/param_320x240.txt
DATA|${PREFIX}/data/config/param_320x256.txt
DEMODATA|${PREFIX}/data/config/demo1.bin
DEMODATA|${PREFIX}/data/config/demo2.bin
DATA|${PREFIX}/data/config/gamecontrollerdb.txt
DATA|${PREFIX}/data/config/formations.txt
DATA|${PREFIX}/data/config/pools.txt
DATA|${PREFIX}/config/formations.txt
DATA|${PREFIX}/config/gamecontrollerdb.txt
DATA|${PREFIX}/config/param_320x240.txt
DATA|${PREFIX}/config/param_320x256.txt
DATA|${PREFIX}/config/param_red.txt
DATA|${PREFIX}/config/pools.txt
DATA|${PREFIX}/config/stages.txt
# Archivos con los datos de la demo
DEMODATA|${PREFIX}/data/demo/demo1.bin
DEMODATA|${PREFIX}/data/demo/demo2.bin
# Música
MUSIC|${PREFIX}/data/music/credits.ogg
MUSIC|${PREFIX}/data/music/intro.ogg
MUSIC|${PREFIX}/data/music/playing.ogg
MUSIC|${PREFIX}/data/music/title.ogg
MUSIC|${PREFIX}/data/music/credits.ogg
# Sonidos
SOUND|${PREFIX}/data/sound/balloon_pop0.wav
SOUND|${PREFIX}/data/sound/balloon_pop1.wav
SOUND|${PREFIX}/data/sound/balloon_pop2.wav
SOUND|${PREFIX}/data/sound/balloon_pop3.wav
SOUND|${PREFIX}/data/sound/balloon_bounce0.wav
SOUND|${PREFIX}/data/sound/balloon_bounce1.wav
SOUND|${PREFIX}/data/sound/balloon_bounce2.wav
SOUND|${PREFIX}/data/sound/balloon_bounce3.wav
SOUND|${PREFIX}/data/sound/balloon_pop0.wav
SOUND|${PREFIX}/data/sound/balloon_pop1.wav
SOUND|${PREFIX}/data/sound/balloon_pop2.wav
SOUND|${PREFIX}/data/sound/balloon_pop3.wav
SOUND|${PREFIX}/data/sound/bullet.wav
SOUND|${PREFIX}/data/sound/clock.wav
SOUND|${PREFIX}/data/sound/coffee_out.wav
SOUND|${PREFIX}/data/sound/continue_clock.wav
SOUND|${PREFIX}/data/sound/credit.wav
SOUND|${PREFIX}/data/sound/debian_drop.wav
SOUND|${PREFIX}/data/sound/debian_pickup.wav
SOUND|${PREFIX}/data/sound/hi_score_achieved.wav
@@ -55,57 +60,59 @@ SOUND|${PREFIX}/data/sound/tabe.wav
SOUND|${PREFIX}/data/sound/title.wav
SOUND|${PREFIX}/data/sound/voice_aw_aw_aw.wav
SOUND|${PREFIX}/data/sound/voice_coffee.wav
SOUND|${PREFIX}/data/sound/voice_credit_thankyou.wav
SOUND|${PREFIX}/data/sound/voice_get_ready.wav
SOUND|${PREFIX}/data/sound/voice_no.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/walk.wav
# Shaders
DATA|${PREFIX}/data/shaders/crtpi_256.glsl
DATA|${PREFIX}/data/shaders/crtpi_240.glsl
DATA|${PREFIX}/data/shaders/crtpi_256.glsl
# Texturas - Balloons
BITMAP|${PREFIX}/data/gfx/balloon/balloon0.png
ANIMATION|${PREFIX}/data/gfx/balloon/balloon0.ani
BITMAP|${PREFIX}/data/gfx/balloon/balloon1.png
ANIMATION|${PREFIX}/data/gfx/balloon/balloon1.ani
BITMAP|${PREFIX}/data/gfx/balloon/balloon2.png
ANIMATION|${PREFIX}/data/gfx/balloon/balloon2.ani
BITMAP|${PREFIX}/data/gfx/balloon/balloon3.png
ANIMATION|${PREFIX}/data/gfx/balloon/balloon3.ani
BITMAP|${PREFIX}/data/gfx/balloon/balloon0.png
BITMAP|${PREFIX}/data/gfx/balloon/balloon1.png
BITMAP|${PREFIX}/data/gfx/balloon/balloon2.png
BITMAP|${PREFIX}/data/gfx/balloon/balloon3.png
# Texturas - Explosiones
BITMAP|${PREFIX}/data/gfx/balloon/explosion0.png
ANIMATION|${PREFIX}/data/gfx/balloon/explosion0.ani
BITMAP|${PREFIX}/data/gfx/balloon/explosion1.png
ANIMATION|${PREFIX}/data/gfx/balloon/explosion1.ani
BITMAP|${PREFIX}/data/gfx/balloon/explosion2.png
ANIMATION|${PREFIX}/data/gfx/balloon/explosion2.ani
BITMAP|${PREFIX}/data/gfx/balloon/explosion3.png
ANIMATION|${PREFIX}/data/gfx/balloon/explosion3.ani
BITMAP|${PREFIX}/data/gfx/balloon/explosion0.png
BITMAP|${PREFIX}/data/gfx/balloon/explosion1.png
BITMAP|${PREFIX}/data/gfx/balloon/explosion2.png
BITMAP|${PREFIX}/data/gfx/balloon/explosion3.png
# Texturas - Power Ball
BITMAP|${PREFIX}/data/gfx/balloon/powerball.png
ANIMATION|${PREFIX}/data/gfx/balloon/powerball.ani
BITMAP|${PREFIX}/data/gfx/balloon/powerball.png
# Texturas - Bala
BITMAP|${PREFIX}/data/gfx/bullet/bullet.png
ANIMATION|${PREFIX}/data/gfx/bullet/bullet.ani
BITMAP|${PREFIX}/data/gfx/bullet/bullet.png
# Texturas - Tabe
BITMAP|${PREFIX}/data/gfx/tabe/tabe.png
ANIMATION|${PREFIX}/data/gfx/tabe/tabe.ani
BITMAP|${PREFIX}/data/gfx/tabe/tabe.png
# Texturas - Juego
BITMAP|${PREFIX}/data/gfx/game/game_buildings.png
BITMAP|${PREFIX}/data/gfx/game/game_clouds1.png
BITMAP|${PREFIX}/data/gfx/game/game_clouds2.png
BITMAP|${PREFIX}/data/gfx/game/game_grass.png
BITMAP|${PREFIX}/data/gfx/game/game_moon.png
BITMAP|${PREFIX}/data/gfx/game/game_power_meter.png
BITMAP|${PREFIX}/data/gfx/game/game_sky_colors.png
BITMAP|${PREFIX}/data/gfx/game/game_sun.png
BITMAP|${PREFIX}/data/gfx/game/game_moon.png
# Texturas - Intro
BITMAP|${PREFIX}/data/gfx/intro/intro1.png
@@ -116,75 +123,76 @@ BITMAP|${PREFIX}/data/gfx/intro/intro5.png
BITMAP|${PREFIX}/data/gfx/intro/intro6.png
# Texturas - Logo
BITMAP|${PREFIX}/data/gfx/logo/logo_jailgames.png
BITMAP|${PREFIX}/data/gfx/logo/logo_jailgames_mini.png
BITMAP|${PREFIX}/data/gfx/logo/logo_jailgames.png
BITMAP|${PREFIX}/data/gfx/logo/logo_since_1998.png
# Texturas - Items
BITMAP|${PREFIX}/data/gfx/item/item_points1_disk.png
ANIMATION|${PREFIX}/data/gfx/item/item_clock.ani
ANIMATION|${PREFIX}/data/gfx/item/item_coffee_machine.ani
ANIMATION|${PREFIX}/data/gfx/item/item_coffee.ani
ANIMATION|${PREFIX}/data/gfx/item/item_debian.ani
ANIMATION|${PREFIX}/data/gfx/item/item_points1_disk.ani
BITMAP|${PREFIX}/data/gfx/item/item_points2_gavina.png
ANIMATION|${PREFIX}/data/gfx/item/item_points2_gavina.ani
BITMAP|${PREFIX}/data/gfx/item/item_points3_pacmar.png
ANIMATION|${PREFIX}/data/gfx/item/item_points3_pacmar.ani
BITMAP|${PREFIX}/data/gfx/item/item_clock.png
ANIMATION|${PREFIX}/data/gfx/item/item_clock.ani
BITMAP|${PREFIX}/data/gfx/item/item_coffee.png
ANIMATION|${PREFIX}/data/gfx/item/item_coffee.ani
BITMAP|${PREFIX}/data/gfx/item/item_debian.png
ANIMATION|${PREFIX}/data/gfx/item/item_debian.ani
BITMAP|${PREFIX}/data/gfx/item/item_coffee_machine.png
ANIMATION|${PREFIX}/data/gfx/item/item_coffee_machine.ani
BITMAP|${PREFIX}/data/gfx/item/item_coffee.png
BITMAP|${PREFIX}/data/gfx/item/item_debian.png
BITMAP|${PREFIX}/data/gfx/item/item_points1_disk.png
BITMAP|${PREFIX}/data/gfx/item/item_points2_gavina.png
BITMAP|${PREFIX}/data/gfx/item/item_points3_pacmar.png
# Texturas - Titulo
ANIMATION|${PREFIX}/data/gfx/title/title_dust.ani
BITMAP|${PREFIX}/data/gfx/title/title_arcade_edition.png
BITMAP|${PREFIX}/data/gfx/title/title_bg_tile.png
BITMAP|${PREFIX}/data/gfx/title/title_coffee.png
BITMAP|${PREFIX}/data/gfx/title/title_crisis.png
BITMAP|${PREFIX}/data/gfx/title/title_arcade_edition.png
BITMAP|${PREFIX}/data/gfx/title/title_dust.png
ANIMATION|${PREFIX}/data/gfx/title/title_dust.ani
# Texturas - Jugador 1
BITMAP|${PREFIX}/data/gfx/player/player1_power.png
BITMAP|${PREFIX}/data/gfx/player/player1.gif
PALETTE|${PREFIX}/data/gfx/player/player1_coffee1.pal
PALETTE|${PREFIX}/data/gfx/player/player1_coffee2.pal
PALETTE|${PREFIX}/data/gfx/player/player1_invencible.pal
BITMAP|${PREFIX}/data/gfx/player/player1_power.png
# Texturas - Jugador 2
BITMAP|${PREFIX}/data/gfx/player/player2_power.png
BITMAP|${PREFIX}/data/gfx/player/player2.gif
PALETTE|${PREFIX}/data/gfx/player/player2_coffee1.pal
PALETTE|${PREFIX}/data/gfx/player/player2_coffee2.pal
PALETTE|${PREFIX}/data/gfx/player/player2_invencible.pal
BITMAP|${PREFIX}/data/gfx/player/player2_power.png
# Animaciones del jugador
ANIMATION|${PREFIX}/data/gfx/player/player.ani
ANIMATION|${PREFIX}/data/gfx/player/player_power.ani
ANIMATION|${PREFIX}/data/gfx/player/player.ani
# Texturas - Golpe del jugador
BITMAP|${PREFIX}/data/gfx/player/hit.png
# Fuentes de texto
BITMAP|${PREFIX}/data/font/8bithud.png
FONT|${PREFIX}/data/font/8bithud.txt
BITMAP|${PREFIX}/data/font/aseprite.png
FONT|${PREFIX}/data/font/aseprite.txt
BITMAP|${PREFIX}/data/font/smb2.png
BITMAP|${PREFIX}/data/font/smb2_grad.png
FONT|${PREFIX}/data/font/smb2.txt
BITMAP|${PREFIX}/data/font/04b_25.png
FONT|${PREFIX}/data/font/04b_25.txt
BITMAP|${PREFIX}/data/font/04b_25_2x.png
FONT|${PREFIX}/data/font/04b_25_2x.txt
BITMAP|${PREFIX}/data/font/04b_25_metal.png
BITMAP|${PREFIX}/data/font/04b_25_grey.png
BITMAP|${PREFIX}/data/font/04b_25_flat.png
BITMAP|${PREFIX}/data/font/04b_25_reversed.png
BITMAP|${PREFIX}/data/font/04b_25_flat_2x.png
BITMAP|${PREFIX}/data/font/04b_25_flat.png
BITMAP|${PREFIX}/data/font/04b_25_grey.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.png
BITMAP|${PREFIX}/data/font/04b_25_white.png
BITMAP|${PREFIX}/data/font/04b_25.png
BITMAP|${PREFIX}/data/font/8bithud.png
BITMAP|${PREFIX}/data/font/aseprite.png
BITMAP|${PREFIX}/data/font/smb2_grad.png
BITMAP|${PREFIX}/data/font/smb2.png
FONT|${PREFIX}/data/font/04b_25_2x.txt
FONT|${PREFIX}/data/font/04b_25.txt
FONT|${PREFIX}/data/font/8bithud.txt
FONT|${PREFIX}/data/font/aseprite.txt
FONT|${PREFIX}/data/font/smb2.txt
# Idiomas
LANG|${PREFIX}/data/lang/es_ES.json
LANG|${PREFIX}/data/lang/ba_BA.json
LANG|${PREFIX}/data/lang/en_UK.json
LANG|${PREFIX}/data/lang/ba_BA.json
LANG|${PREFIX}/data/lang/es_ES.json

View File

@@ -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
# Variables disponibles:
# 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
View 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
View 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
View 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

View File

@@ -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>, ...
# Los IDs de formación pueden repetirse
# Los pools no necesitan estar ordenados ni ser consecutivos

19
config/stages.txt Normal file
View File

@@ -0,0 +1,19 @@
# Coffee Crisis Arcade Edition - Archivo de configuración de fases
# Formato: power_to_complete,min_menace,max_menace,name
# Líneas que empiezan con # son comentarios y se ignoran
# Fases iniciales - Tutorial y aprendizaje
200, 11, 19, Tutorial
300, 15, 23, Primeros pasos
# Fases intermedias - Incremento de dificultad
400, 19, 27, Intensificación
400, 19, 27, Persistencia
400, 23, 31, Desafío medio
400, 23, 31, Resistencia
# Fases avanzadas - Desafío final
600, 27, 35, Aproximación final
600, 27, 35, Penúltimo obstáculo
700, 31, 39, Clímax
950, 35, 47, Maestría

View File

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

View File

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

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

BIN
data/font/04b_25_white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -120,9 +120,16 @@ loop=0
frames=47,48,49,50,51,52,53
[/animation]
[animation]
name=recover
speed=3
loop=-1
frames=54,54,54,54,55,56,57,58,58,58,59,60,61,58,59,60,61,58,59,60,61,62,62,62,62
[/animation]
[animation]
name=hello
speed=3
loop=-1
frames=54,55,56,57,58,59,60,61,62,63,64,64,64,64,64,64,64,64,64,64,64,64,64,65,66,67,68,69,70,71,72,73,73,72,71,70,70,71,72,73,73,72,71,70,70,71,72,73,73,72,71,70,70,71,72,73,73,72,71,70,69,68,67,66,65,64,63,62,61,60,59,58,57,56,55,54
frames=63,64,65,66,67,68,69,70,71,72,73,73,73,73,73,73,73,73,73,73,73,73,73,74,75,76,77,78,79,80,81,82,82,81,80,79,79,80,81,82,82,81,80,79,79,80,81,82,82,81,80,79,79,80,81,82,82,81,80,79,78,77,76,75,74,73,72,71,70,69,68,67,66,65,64,63
[/animation]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -26,6 +26,7 @@
"[GAME_TEXT] 6": "Temps!",
"[GAME_TEXT] 7": "Endavant!",
"[GAME_TEXT] 8": "1.000.000 de punts!",
"[GAME_TEXT] THANK_YOU": "Gracies!",
"[HIGHSCORE_TABLE] CAPTION": "Millors puntuacions",

View File

@@ -25,6 +25,7 @@
"[GAME_TEXT] 6": "Stop!",
"[GAME_TEXT] 7": "Get Ready!",
"[GAME_TEXT] 8": "1,000,000 points!",
"[GAME_TEXT] THANK_YOU": "Thank you!",
"[HIGHSCORE_TABLE] CAPTION": "Best scores",

View File

@@ -25,6 +25,7 @@
"[GAME_TEXT] 6": "Tiempo!",
"[GAME_TEXT] 7": "Adelante!",
"[GAME_TEXT] 8": "1.000.000 de puntos!",
"[GAME_TEXT] THANK_YOU": "Gracias!",
"[HIGHSCORE_TABLE] CAPTION": "Mejores puntuaciones",

BIN
data/sound/credit.wav Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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
View 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!"

Binary file not shown.

150
release/create_icons.py Normal file
View File

@@ -0,0 +1,150 @@
#!/usr/bin/env python3
import os
import sys
import shutil
import subprocess
from pathlib import Path
def check_dependencies():
"""Verifica que ImageMagick esté instalado"""
try:
subprocess.run(['magick', '--version'], capture_output=True, check=True)
except (subprocess.CalledProcessError, FileNotFoundError):
print("Error: ImageMagick no está instalado o no se encuentra en el PATH")
print("Instala ImageMagick desde: https://imagemagick.org/script/download.php")
sys.exit(1)
# Verificar iconutil solo en macOS
if sys.platform == 'darwin':
try:
# iconutil no tiene --version, mejor usar which o probar con -h
result = subprocess.run(['which', 'iconutil'], capture_output=True, check=True)
if result.returncode == 0:
print("✓ iconutil disponible - se crearán archivos .ico e .icns")
except (subprocess.CalledProcessError, FileNotFoundError):
print("Error: iconutil no está disponible (solo funciona en macOS)")
print("Solo se creará el archivo .ico")
else:
print(" Sistema no-macOS detectado - solo se creará archivo .ico")
def create_icons(input_file):
"""Crea archivos .icns e .ico a partir de un PNG"""
# Verificar que el archivo existe
if not os.path.isfile(input_file):
print(f"Error: El archivo {input_file} no existe.")
return False
# Obtener información del archivo
file_path = Path(input_file)
file_dir = file_path.parent
file_name = file_path.stem # Nombre sin extensión
file_extension = file_path.suffix
if file_extension.lower() not in ['.png', '.jpg', '.jpeg', '.bmp', '.tiff']:
print(f"Advertencia: {file_extension} puede no ser compatible. Se recomienda usar PNG.")
# Crear archivo .ico usando el método simplificado
ico_output = file_dir / f"{file_name}.ico"
try:
print(f"Creando {ico_output}...")
subprocess.run([
'magick', str(input_file),
'-define', 'icon:auto-resize=256,128,64,48,32,16',
str(ico_output)
], check=True)
print(f"✓ Archivo .ico creado: {ico_output}")
except subprocess.CalledProcessError as e:
print(f"Error creando archivo .ico: {e}")
return False
# Crear archivo .icns (solo en macOS)
if sys.platform == 'darwin':
try:
# Crear carpeta temporal para iconset
temp_folder = file_dir / "icon.iconset"
# Eliminar carpeta temporal si existe
if temp_folder.exists():
shutil.rmtree(temp_folder)
# Crear carpeta temporal
temp_folder.mkdir(parents=True)
# Definir los tamaños y nombres de archivo para .icns
icon_sizes = [
(16, "icon_16x16.png"),
(32, "icon_16x16@2x.png"),
(32, "icon_32x32.png"),
(64, "icon_32x32@2x.png"),
(128, "icon_128x128.png"),
(256, "icon_128x128@2x.png"),
(256, "icon_256x256.png"),
(512, "icon_256x256@2x.png"),
(512, "icon_512x512.png"),
(1024, "icon_512x512@2x.png")
]
print("Generando imágenes para .icns...")
# Crear cada tamaño de imagen
for size, output_name in icon_sizes:
output_path = temp_folder / output_name
subprocess.run([
'magick', str(input_file),
'-resize', f'{size}x{size}',
str(output_path)
], check=True)
# Crear archivo .icns usando iconutil
icns_output = file_dir / f"{file_name}.icns"
print(f"Creando {icns_output}...")
subprocess.run([
'iconutil', '-c', 'icns',
str(temp_folder),
'-o', str(icns_output)
], check=True)
# Limpiar carpeta temporal
if temp_folder.exists():
shutil.rmtree(temp_folder)
print(f"✓ Archivo .icns creado: {icns_output}")
except subprocess.CalledProcessError as e:
print(f"Error creando archivo .icns: {e}")
# Limpiar carpeta temporal en caso de error
if temp_folder.exists():
shutil.rmtree(temp_folder)
return False
else:
print(" Archivo .icns no creado (solo disponible en macOS)")
return True
def main():
"""Función principal"""
# Verificar argumentos
if len(sys.argv) != 2:
print(f"Uso: {sys.argv[0]} ARCHIVO")
print("Ejemplo: python3 create_icons.py imagen.png")
sys.exit(0)
input_file = sys.argv[1]
# Verificar dependencias
check_dependencies()
# Crear iconos
if create_icons(input_file):
print("\n✅ Proceso completado exitosamente")
else:
print("\n❌ El proceso falló")
sys.exit(1)
if __name__ == "__main__":
main()

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 438 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
resources.pack Normal file

Binary file not shown.

View File

@@ -10,21 +10,39 @@
#include <utility> // Para pair
#include "texture.h" // Para Texture
#include "resource_helper.h" // Para ResourceHelper
#include "utils.h" // Para printWithDots
// Carga las animaciones en un vector(Animations) desde un fichero
auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffer {
std::ifstream file(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);
// Intentar cargar desde ResourceHelper primero
auto resource_data = ResourceHelper::loadFile(file_path);
std::istringstream stream;
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 ]");
std::vector<std::string> buffer;
std::string line;
while (std::getline(file, line)) {
while (std::getline(input_stream, line)) {
if (!line.empty()) {
buffer.push_back(line);
}
@@ -35,7 +53,7 @@ auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffe
// Constructor
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const std::string& file_path)
: MovingSprite(texture) {
: MovingSprite(std::move(texture)) {
// Carga las animaciones
if (!file_path.empty()) {
auto buffer = loadAnimationsFromFile(file_path);
@@ -45,14 +63,14 @@ AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const std::stri
// Constructor
AnimatedSprite::AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer& animations)
: MovingSprite(texture) {
: MovingSprite(std::move(texture)) {
if (!animations.empty()) {
loadFromAnimationsFileBuffer(animations);
}
}
// Obtiene el índice de la animación a partir del nombre
auto AnimatedSprite::getIndex(const std::string& name) -> int {
auto AnimatedSprite::getAnimationIndex(const std::string& name) -> int {
auto iterator = animation_indices_.find(name);
if (iterator != animation_indices_.end()) {
// Si se encuentra la animación en el mapa, devuelve su índice
@@ -101,7 +119,7 @@ auto AnimatedSprite::animationIsCompleted() -> bool {
// Establece la animacion actual
void AnimatedSprite::setCurrentAnimation(const std::string& name, bool reset) {
const auto NEW_ANIMATION = getIndex(name);
const auto NEW_ANIMATION = getAnimationIndex(name);
if (current_animation_ != NEW_ANIMATION) {
const auto OLD_ANIMATION = current_animation_;
current_animation_ = NEW_ANIMATION;
@@ -176,7 +194,7 @@ void AnimatedSprite::loadFromAnimationsFileBuffer(const AnimationsFileBuffer& so
// Procesa una línea de configuración
void AnimatedSprite::processConfigLine(const std::string& line, AnimationConfig& config) {
size_t pos = line.find("=");
size_t pos = line.find('=');
if (pos == std::string::npos) {
return;
}
@@ -230,7 +248,7 @@ auto AnimatedSprite::processAnimationBlock(const AnimationsFileBuffer& source, s
// Procesa un parámetro individual de animación
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) {
return;
}

View File

@@ -7,14 +7,15 @@
#include <memory> // Para allocator, shared_ptr
#include <string> // Para string, hash
#include <unordered_map> // Para unordered_map
#include <vector> // Para vector
#include <utility>
#include <vector> // Para vector
#include "moving_sprite.h" // Para MovingSprite
// Declaración adelantada
class Texture;
// Estructura de Animación
// --- Estructuras ---
struct Animation {
static constexpr int DEFAULT_SPEED = 5;
@@ -37,44 +38,43 @@ struct AnimationConfig {
int max_tiles = 1;
};
// Alias de tipo para buffer de animaciones
using AnimationsFileBuffer = std::vector<std::string>;
// --- Tipos ---
using AnimationsFileBuffer = std::vector<std::string>; // Buffer de animaciones
// Carga las animaciones desde un fichero en un vector de strings
auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffer;
// --- Funciones ---
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 {
public:
// --- Constructores y destructor ---
AnimatedSprite(std::shared_ptr<Texture> texture, const std::string& file_path);
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;
// --- Métodos principales ---
void update() override; // Actualiza la animación
// --- Control de animaciones ---
void setCurrentAnimation(const std::string& name = "default", bool reset = true); // Establece la animación por nombre
void setCurrentAnimation(int index = 0, bool reset = true); // Establece la animación por índice
void resetAnimation(); // Reinicia la animación actual
void setAnimationSpeed(size_t value); // Establece la velocidad de la animación
auto getAnimationSpeed() const -> size_t { return animations_[current_animation_].speed; } // Obtiene la velocidad de la animación actual
void animtionPause() { animations_[current_animation_].paused = true; } // Detiene la animación
void animationResume() { animations_[current_animation_].paused = false; } // Reanuda la animación
void setCurrentAnimation(const std::string& name = "default", bool reset = true); // Establece la animación por nombre
void setCurrentAnimation(int index = 0, bool reset = true); // Establece la animación por índice
void resetAnimation(); // Reinicia la animación actual
void setAnimationSpeed(size_t value); // Establece la velocidad de la animación
auto getAnimationSpeed() const -> size_t { return animations_[current_animation_].speed; } // Obtiene la velocidad de la animación actual
void animtionPause() { animations_[current_animation_].paused = true; } // Detiene la animación
void animationResume() { animations_[current_animation_].paused = false; } // Reanuda la animación
auto getCurrentAnimationFrame() const -> size_t { return animations_[current_animation_].current_frame; } // Obtiene el numero de frame de la animación actual
// --- Consultas ---
auto animationIsCompleted() -> bool; // Comprueba si la animación ha terminado
auto getIndex(const std::string& name) -> int; // Obtiene el índice de una animación por nombre
auto animationIsCompleted() -> bool; // Comprueba si la animación ha terminado
auto getAnimationIndex(const std::string& name) -> int; // Obtiene el índice de una animación por nombre
protected:
// --- Datos de animación ---
std::vector<Animation> animations_; // Vector de animaciones disponibles
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_;
// --- Variables de estado ---
std::vector<Animation> animations_; // Vector de animaciones disponibles
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
// --- Métodos internos ---
void animate(); // Calcula el frame correspondiente a la animación

View File

@@ -9,6 +9,7 @@
#include <stdexcept> // Para runtime_error
#include "utils.h" // Para getFileName
#include "resource_helper.h" // Para ResourceHelper
// Singleton
Asset *Asset::instance = nullptr;
@@ -92,7 +93,7 @@ void Asset::loadFromFile(const std::string &config_file_path, const std::string
}
try {
std::string type_str = parts[0];
const std::string &type_str = parts[0];
std::string path = parts[1];
// Valores por defecto
@@ -139,6 +140,17 @@ auto Asset::get(const std::string &filename) const -> std::string {
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
auto Asset::exists(const std::string &filename) const -> bool {
return file_list_.find(filename) != file_list_.end();
@@ -194,9 +206,16 @@ auto Asset::check() const -> bool {
// Comprueba que existe un fichero
auto Asset::checkFile(const std::string &path) -> bool {
std::ifstream file(path);
bool success = file.good();
file.close();
// Intentar primero con ResourceHelper
auto data = ResourceHelper::loadFile(path);
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) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,

View File

@@ -1,25 +1,26 @@
#pragma once
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <string> // Para string
#include <unordered_map> // Para unordered_map
#include <utility> // Para move
#include <vector> // Para vector
#include <cstdint> // Para uint8_t
// Clase Asset: gestor optimizado de recursos (singleton)
// --- Clase Asset: gestor optimizado de recursos (singleton) ---
class Asset {
public:
// Tipos de recursos
// --- Enums ---
enum class Type : int {
BITMAP,
MUSIC,
SOUND,
FONT,
LANG,
DATA,
DEMODATA,
ANIMATION,
PALETTE,
SIZE,
BITMAP, // Imágenes
MUSIC, // Música
SOUND, // Sonidos
FONT, // Fuentes
LANG, // Idiomas
DATA, // Datos
DEMODATA, // Datos de demo
ANIMATION, // Animaciones
PALETTE, // Paletas
SIZE, // Tamaño
};
// --- Métodos de singleton ---
@@ -33,14 +34,15 @@ class Asset {
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
[[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 getListByType(Type type) const -> std::vector<std::string>;
[[nodiscard]] auto exists(const std::string &filename) const -> bool; // Nueva función para verificar existencia
private:
// --- Estructura interna para almacenar información de cada recurso ---
// --- Estructuras privadas ---
struct Item {
std::string file; // Ruta completa del archivo (mantener nombre original)
std::string file; // Ruta completa del archivo
Type type; // Tipo de recurso
bool required; // Indica si el archivo es obligatorio
@@ -49,21 +51,22 @@ class Asset {
};
// --- 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
// --- Métodos internos ---
[[nodiscard]] static auto checkFile(const std::string &path) -> bool;
[[nodiscard]] static auto getTypeName(Type type) -> std::string;
[[nodiscard]] static auto parseAssetType(const std::string &type_str) -> Type;
void addToMap(const std::string &file_path, Type type, bool required, bool absolute);
[[nodiscard]] static auto replaceVariables(const std::string &path, const std::string &prefix, const std::string &system_folder) -> std::string;
static auto parseOptions(const std::string &options, bool &required, bool &absolute) -> void;
[[nodiscard]] static auto checkFile(const std::string &path) -> bool; // Verifica si un archivo existe
[[nodiscard]] static auto getTypeName(Type type) -> std::string; // Obtiene el nombre del tipo
[[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); // Añade archivo al mapa
[[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; // Parsea opciones
// --- Patrón Singleton ---
explicit Asset(std::string executable_path)
// --- Constructores y destructor privados (singleton) ---
explicit Asset(std::string executable_path) // Constructor privado
: executable_path_(std::move(executable_path)) {}
~Asset() = default;
~Asset() = default; // Destructor privado
static Asset *instance;
// --- Instancia singleton ---
static Asset *instance; // Instancia única de Asset
};

105
source/asset_integrated.cpp Normal file
View File

@@ -0,0 +1,105 @@
#include "asset_integrated.h"
#include <filesystem>
#include <iostream>
#include <fstream>
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;
}

28
source/asset_integrated.h Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
#include "asset.h"
#include "resource_loader.h"
#include <memory>
// 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;
};

View File

@@ -3,19 +3,20 @@
#include <string> // Para string
#include <utility> // Para move
// Clase Audio: gestor de audio (singleton)
// --- Clase Audio: gestor de audio (singleton) ---
class Audio {
public:
// --- Enums ---
enum class Group : int {
ALL = -1,
GAME = 0,
INTERFACE = 1
ALL = -1, // Todos los grupos
GAME = 0, // Sonidos del juego
INTERFACE = 1 // Sonidos de la interfaz
};
// --- Constantes ---
static constexpr int MAX_VOLUME = 100;
static constexpr int MIN_VOLUME = 0;
static constexpr int FREQUENCY = 48000;
static constexpr int MAX_VOLUME = 100; // Volumen máximo
static constexpr int MIN_VOLUME = 0; // Volumen mínimo
static constexpr int FREQUENCY = 48000; // Frecuencia de audio
// --- Métodos de singleton ---
static void init(); // Inicializa el objeto Audio
@@ -60,12 +61,14 @@ class Audio {
void setMusicVolume(int volume) const; // Ajustar volumen de música
private:
// --- Enums privados ---
enum class MusicState {
PLAYING,
PAUSED,
STOPPED,
PLAYING, // Reproduciendo música
PAUSED, // Música pausada
STOPPED, // Música detenida
};
// --- Estructuras privadas ---
struct Music {
MusicState state; // Estado actual de la música (reproduciendo, detenido, en pausa)
std::string name; // Última pista de música reproducida
@@ -79,20 +82,19 @@ class Audio {
: state(init_state), name(std::move(init_name)), loop(init_loop) {}
};
Music music_;
// --- Variables de Estado ---
// --- Variables de estado ---
Music music_; // Estado de la música
bool enabled_ = true; // Estado general del audio
bool sound_enabled_ = true; // Estado de los efectos de sonido
bool music_enabled_ = true; // Estado de la música
// --- Inicializa SDL Audio ---
void initSDLAudio();
// --- Métodos internos ---
void initSDLAudio(); // Inicializa SDL Audio
// --- Patrón Singleton ---
// --- Constructores y destructor privados (singleton) ---
Audio(); // Constructor privado
~Audio(); // Destructor privado
// --- Singleton ---
static Audio *instance;
// --- Instancia singleton ---
static Audio *instance; // Instancia única de Audio
};

View File

@@ -5,6 +5,7 @@
#include <algorithm> // Para clamp, max
#include <cmath> // Para M_PI, cos, sin
#include <utility>
#include "moving_sprite.h" // Para MovingSprite
#include "param.h" // Para Param, ParamBackground, param
@@ -14,7 +15,7 @@
#include "texture.h" // Para Texture
// Constructor
Background::Background()
Background::Background(float total_progress_to_complete)
: renderer_(Screen::get()->getRenderer()),
buildings_texture_(Resource::get()->getTexture("game_buildings.png")),
@@ -25,84 +26,23 @@ Background::Background()
sun_texture_(Resource::get()->getTexture("game_sun.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)}),
src_rect_({0, 0, 320, 240}),
dst_rect_({0, 0, 320, 240}),
base_(rect_.h),
src_rect_({.x = 0, .y = 0, .w = 320, .h = 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)),
alpha_color_text_(param.background.attenuate_color.a),
alpha_color_text_temp_(param.background.attenuate_color.a)
{
// Precalcula rutas
createSunPath();
createMoonPath();
// Inicializa variables
{
gradient_rect_[0] = {0, 0, rect_.w, rect_.h};
gradient_rect_[1] = {rect_.w, 0, rect_.w, rect_.h};
gradient_rect_[2] = {0, rect_.h, rect_.w, rect_.h};
gradient_rect_[3] = {rect_.w, rect_.h, rect_.w, rect_.h};
const float TOP_CLOUDS_TEXTURE_HEIGHT = top_clouds_texture_->getHeight() / 4;
const float BOTTOM_CLOUDS_TEXTURE_HEIGHT = bottom_clouds_texture_->getHeight() / 4;
for (int i = 0; i < 4; ++i) {
top_clouds_rect_[i] = {0, i * TOP_CLOUDS_TEXTURE_HEIGHT, static_cast<float>(top_clouds_texture_->getWidth()), 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};
}
}
// Crea los sprites
{
const float TOP_CLOUDS_Y = base_ - 165;
const float BOTTOM_CLOUDS_Y = base_ - 101;
top_clouds_sprite_a_ = std::make_unique<MovingSprite>(top_clouds_texture_, (SDL_FRect){0, TOP_CLOUDS_Y, rect_.w, static_cast<float>(top_clouds_texture_->getHeight())});
top_clouds_sprite_b_ = std::make_unique<MovingSprite>(top_clouds_texture_, (SDL_FRect){rect_.w, TOP_CLOUDS_Y, rect_.w, static_cast<float>(top_clouds_texture_->getHeight())});
bottom_clouds_sprite_a_ = std::make_unique<MovingSprite>(bottom_clouds_texture_, (SDL_FRect){0, BOTTOM_CLOUDS_Y, rect_.w, static_cast<float>(bottom_clouds_texture_->getHeight())});
bottom_clouds_sprite_b_ = std::make_unique<MovingSprite>(bottom_clouds_texture_, (SDL_FRect){rect_.w, BOTTOM_CLOUDS_Y, rect_.w, static_cast<float>(bottom_clouds_texture_->getHeight())});
buildings_sprite_ = std::make_unique<Sprite>(buildings_texture_);
gradient_sprite_ = std::make_unique<Sprite>(gradients_texture_, 0, 0, rect_.w, rect_.h);
grass_sprite_ = std::make_unique<Sprite>(grass_texture_, 0, 0, grass_texture_->getWidth(), grass_texture_->getHeight() / 2);
sun_sprite_ = std::make_unique<Sprite>(sun_texture_);
moon_sprite_ = std::make_unique<Sprite>(moon_texture_);
}
// Inicializa objetos
{
constexpr float TOP_CLOUDS_SPEED = 0.1F;
constexpr float BOTTOM_CLOUDS_SPEED = 0.05F;
top_clouds_sprite_a_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight());
top_clouds_sprite_a_->setVelX(-TOP_CLOUDS_SPEED);
top_clouds_sprite_b_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight());
top_clouds_sprite_b_->setVelX(-TOP_CLOUDS_SPEED);
bottom_clouds_sprite_a_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight());
bottom_clouds_sprite_a_->setVelX(-BOTTOM_CLOUDS_SPEED);
bottom_clouds_sprite_b_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight());
bottom_clouds_sprite_b_->setVelX(-BOTTOM_CLOUDS_SPEED);
buildings_sprite_->setY(base_ - buildings_sprite_->getHeight());
grass_sprite_->setY(base_ - grass_sprite_->getHeight());
sun_sprite_->setPosition(sun_path_.front());
moon_sprite_->setPosition(moon_path_.front());
}
// Crea la textura para componer el fondo
canvas_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h);
SDL_SetTextureBlendMode(canvas_, SDL_BLENDMODE_BLEND);
// Crea la textura para atenuar el fondo
color_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h);
SDL_SetTextureBlendMode(color_texture_, SDL_BLENDMODE_BLEND);
setColor(attenuate_color_);
SDL_SetTextureAlphaMod(color_texture_, alpha_color_text_);
alpha_color_texture_(param.background.attenuate_color.a),
previous_alpha_color_texture_(param.background.attenuate_color.a),
base_(rect_.h) {
initializePaths();
initializeRects();
initializeSprites();
initializeSpriteProperties();
initializeTextures();
}
// Destructor
@@ -111,9 +51,88 @@ Background::~Background() {
SDL_DestroyTexture(color_texture_);
}
// Inicializa las rutas del sol y la luna
void Background::initializePaths() {
createSunPath();
createMoonPath();
}
// Inicializa los rectángulos de gradientes y nubes
void Background::initializeRects() {
gradient_rect_[0] = {.x = 0, .y = 0, .w = rect_.w, .h = rect_.h};
gradient_rect_[1] = {.x = rect_.w, .y = 0, .w = rect_.w, .h = rect_.h};
gradient_rect_[2] = {.x = 0, .y = rect_.h, .w = rect_.w, .h = 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 BOTTOM_CLOUDS_TEXTURE_HEIGHT = bottom_clouds_texture_->getHeight() / 4;
for (int i = 0; i < 4; ++i) {
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] = {.x = 0, .y = i * BOTTOM_CLOUDS_TEXTURE_HEIGHT, .w = static_cast<float>(bottom_clouds_texture_->getWidth()), .h = BOTTOM_CLOUDS_TEXTURE_HEIGHT};
}
}
// Crea los sprites
void Background::initializeSprites() {
const float TOP_CLOUDS_Y = base_ - 165;
const float BOTTOM_CLOUDS_Y = base_ - 101;
top_clouds_sprite_a_ = std::make_unique<MovingSprite>(top_clouds_texture_, (SDL_FRect){0, TOP_CLOUDS_Y, rect_.w, static_cast<float>(top_clouds_texture_->getHeight())});
top_clouds_sprite_b_ = std::make_unique<MovingSprite>(top_clouds_texture_, (SDL_FRect){rect_.w, TOP_CLOUDS_Y, rect_.w, static_cast<float>(top_clouds_texture_->getHeight())});
bottom_clouds_sprite_a_ = std::make_unique<MovingSprite>(bottom_clouds_texture_, (SDL_FRect){0, BOTTOM_CLOUDS_Y, rect_.w, static_cast<float>(bottom_clouds_texture_->getHeight())});
bottom_clouds_sprite_b_ = std::make_unique<MovingSprite>(bottom_clouds_texture_, (SDL_FRect){rect_.w, BOTTOM_CLOUDS_Y, rect_.w, static_cast<float>(bottom_clouds_texture_->getHeight())});
buildings_sprite_ = std::make_unique<Sprite>(buildings_texture_);
gradient_sprite_ = std::make_unique<Sprite>(gradients_texture_, 0, 0, rect_.w, rect_.h);
grass_sprite_ = std::make_unique<Sprite>(grass_texture_, 0, 0, grass_texture_->getWidth(), grass_texture_->getHeight() / 2);
sun_sprite_ = std::make_unique<Sprite>(sun_texture_);
moon_sprite_ = std::make_unique<Sprite>(moon_texture_);
}
// Configura las propiedades iniciales de los sprites
void Background::initializeSpriteProperties() {
constexpr float TOP_CLOUDS_SPEED = 0.1F;
constexpr float BOTTOM_CLOUDS_SPEED = 0.05F;
top_clouds_sprite_a_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight());
top_clouds_sprite_a_->setVelX(-TOP_CLOUDS_SPEED);
top_clouds_sprite_b_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight());
top_clouds_sprite_b_->setVelX(-TOP_CLOUDS_SPEED);
bottom_clouds_sprite_a_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight());
bottom_clouds_sprite_a_->setVelX(-BOTTOM_CLOUDS_SPEED);
bottom_clouds_sprite_b_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight());
bottom_clouds_sprite_b_->setVelX(-BOTTOM_CLOUDS_SPEED);
buildings_sprite_->setY(base_ - buildings_sprite_->getHeight());
grass_sprite_->setY(base_ - grass_sprite_->getHeight());
sun_sprite_->setPosition(sun_path_.front());
moon_sprite_->setPosition(moon_path_.front());
}
// Inicializa las texturas de renderizado
void Background::initializeTextures() {
canvas_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h);
SDL_SetTextureBlendMode(canvas_, SDL_BLENDMODE_BLEND);
color_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, rect_.w, rect_.h);
SDL_SetTextureBlendMode(color_texture_, SDL_BLENDMODE_BLEND);
setColor(attenuate_color_);
SDL_SetTextureAlphaMod(color_texture_, alpha_color_texture_);
}
// Actualiza la lógica del objeto
void Background::update() {
// Actualiza el valor de alpha_
// Actualiza la progresión y calcula transiciones
if (!manual_mode_) {
updateProgression();
}
// Actualiza el valor de alpha
updateAlphaColorTexture();
// Actualiza las nubes
@@ -122,10 +141,10 @@ void Background::update() {
// Calcula el frame de la hierba
grass_sprite_->setSpriteClip(0, (10 * (counter_ / 20 % 2)), 320, 10);
// Calcula el valor de alpha_
// Calcula el valor de alpha
alpha_ = std::max((255 - (int)(255 * transition_)), 0);
// Mueve el sol
// Mueve el sol y la luna según la progresión
sun_sprite_->setPosition(sun_path_.at(sun_index_));
moon_sprite_->setPosition(moon_path_.at(moon_index_));
@@ -136,6 +155,190 @@ void Background::update() {
fillCanvas();
}
// Incrementa la progresión interna
void Background::incrementProgress(float amount) {
if (state_ == State::NORMAL) {
float old_progress = progress_;
progress_ += amount;
progress_ = std::min(progress_, total_progress_to_complete_);
// Notifica el cambio si hay callback y el progreso cambió
if (progress_callback_ && progress_ != old_progress) {
progress_callback_(progress_);
}
}
}
// Establece la progresión absoluta
void Background::setProgress(float absolute_progress) {
float old_progress = progress_;
progress_ = std::clamp(absolute_progress, 0.0F, total_progress_to_complete_);
// Notifica el cambio si hay callback y el progreso cambió
if (progress_callback_ && progress_ != old_progress) {
progress_callback_(progress_);
}
}
// Cambia el estado del fondo
void Background::setState(State new_state) {
state_ = new_state;
}
// Reinicia la progresión
void Background::reset() {
float old_progress = progress_;
progress_ = 0.0F;
state_ = State::NORMAL;
manual_mode_ = false;
gradient_number_ = 0;
transition_ = 0.0F;
sun_index_ = 0;
moon_index_ = 0;
// Notifica el cambio si hay callback
if (progress_callback_ && progress_ != old_progress) {
progress_callback_(progress_);
}
}
// Activa/desactiva el modo manual
void Background::setManualMode(bool manual) {
manual_mode_ = manual;
}
// Establece callback para sincronización automática
void Background::setProgressCallback(ProgressCallback callback) {
progress_callback_ = std::move(callback);
}
// Elimina el callback
void Background::removeProgressCallback() {
progress_callback_ = nullptr;
}
// Ajusta la velocidad de las nubes
void Background::setCloudsSpeed(float value) {
clouds_speed_ = value;
// En modo manual, aplicar la velocidad directamente
// Las nubes inferiores van a la mitad de velocidad que las superiores
top_clouds_sprite_a_->setVelX(value);
top_clouds_sprite_b_->setVelX(value);
bottom_clouds_sprite_a_->setVelX(value / 2.0F);
bottom_clouds_sprite_b_->setVelX(value / 2.0F);
}
// Establece el degradado de fondo
void Background::setGradientNumber(int value) {
gradient_number_ = value % STAGES;
}
// Ajusta la transición entre texturas
void Background::setTransition(float value) {
transition_ = std::clamp(value, 0.0F, 1.0F);
}
// Establece la posición del sol
void Background::setSunProgression(float progress) {
progress = std::clamp(progress, 0.0F, 1.0F);
sun_index_ = static_cast<size_t>(progress * (sun_path_.size() - 1));
}
// Establece la posición de la luna
void Background::setMoonProgression(float progress) {
progress = std::clamp(progress, 0.0F, 1.0F);
moon_index_ = static_cast<size_t>(progress * (moon_path_.size() - 1));
}
// Actualiza la progresión y calcula las transiciones
void Background::updateProgression() {
// Si el juego está completado, reduce la progresión gradualmente
if (state_ == State::COMPLETED) {
if (progress_ > MINIMUM_COMPLETED_PROGRESS) {
progress_ -= COMPLETED_REDUCTION_RATE;
} else {
progress_ = MINIMUM_COMPLETED_PROGRESS;
}
}
// Calcula la transición de los diferentes fondos
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);
gradient_number_ = static_cast<size_t>(GRADIENT_NUMBER_FLOAT);
transition_ = PERCENT;
// Calcula la posición del sol
const float SUN_PROGRESSION = std::min(progress_ / sun_completion_progress_, 1.0F);
sun_index_ = static_cast<size_t>(SUN_PROGRESSION * (sun_path_.size() - 1));
// Calcula la posición de la luna
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));
// Actualiza la velocidad de las nubes
updateCloudsSpeed();
}
// Actualiza la velocidad de las nubes según el estado y progresión
void Background::updateCloudsSpeed() {
// Cálculo de velocidad según progreso
constexpr float CLOUDS_INITIAL_SPEED = 0.05F;
constexpr float CLOUDS_FINAL_SPEED = 2.00F - CLOUDS_INITIAL_SPEED;
// Velocidad base según progreso (de -0.05 a -2.00)
float base_clouds_speed = (-CLOUDS_INITIAL_SPEED) +
(-CLOUDS_FINAL_SPEED * (progress_ / total_progress_to_complete_));
// En estado completado, las nubes se ralentizan gradualmente
if (state_ == State::COMPLETED) {
float completion_factor = (progress_ - MINIMUM_COMPLETED_PROGRESS) /
(total_progress_to_complete_ - MINIMUM_COMPLETED_PROGRESS);
completion_factor = std::max(0.1F, completion_factor);
base_clouds_speed *= completion_factor;
}
// Aplicar velocidades diferentes para nubes superiores e inferiores
const float TOP_CLOUDS_SPEED = base_clouds_speed;
const float BOTTOM_CLOUDS_SPEED = base_clouds_speed / 2.0F;
// Aplicar las velocidades a los sprites correspondientes
top_clouds_sprite_a_->setVelX(TOP_CLOUDS_SPEED);
top_clouds_sprite_b_->setVelX(TOP_CLOUDS_SPEED);
bottom_clouds_sprite_a_->setVelX(BOTTOM_CLOUDS_SPEED);
bottom_clouds_sprite_b_->setVelX(BOTTOM_CLOUDS_SPEED);
// Guardar la velocidad principal
clouds_speed_ = TOP_CLOUDS_SPEED;
}
// Actualiza las nubes
void Background::updateClouds() {
// Mueve las nubes
top_clouds_sprite_a_->update();
top_clouds_sprite_b_->update();
bottom_clouds_sprite_a_->update();
bottom_clouds_sprite_b_->update();
// Calcula el offset de las nubes
if (top_clouds_sprite_a_->getPosX() < -top_clouds_sprite_a_->getWidth()) {
top_clouds_sprite_a_->setPosX(top_clouds_sprite_a_->getWidth());
}
if (top_clouds_sprite_b_->getPosX() < -top_clouds_sprite_b_->getWidth()) {
top_clouds_sprite_b_->setPosX(top_clouds_sprite_b_->getWidth());
}
if (bottom_clouds_sprite_a_->getPosX() < -bottom_clouds_sprite_a_->getWidth()) {
bottom_clouds_sprite_a_->setPosX(bottom_clouds_sprite_a_->getWidth());
}
if (bottom_clouds_sprite_b_->getPosX() < -bottom_clouds_sprite_b_->getWidth()) {
bottom_clouds_sprite_b_->setPosX(bottom_clouds_sprite_b_->getWidth());
}
}
// Dibuja el gradiente de fondo
void Background::renderGradient() {
// Dibuja el gradiente de detras
@@ -221,21 +424,6 @@ void Background::render() {
SDL_RenderTexture(renderer_, color_texture_, &src_rect_, &dst_rect_);
}
// Ajusta el valor de la variable
void Background::setCloudsSpeed(float value) {
clouds_speed_ = value;
}
// Ajusta el valor de la variable
void Background::setGradientNumber(int value) {
gradient_number_ = value % 4;
}
// Ajusta el valor de la variable
void Background::setTransition(float value) {
transition_ = std::clamp(value, 0.0F, 1.0F);
}
// Establece la posición del objeto
void Background::setPos(SDL_FRect pos) {
dst_rect_ = pos;
@@ -247,7 +435,7 @@ void Background::setPos(SDL_FRect pos) {
src_rect_.h = pos.h;
}
// Establece el color_ de atenuación
// Establece el color de atenuación
void Background::setColor(Color color) {
attenuate_color_ = color;
@@ -264,52 +452,20 @@ void Background::setColor(Color color) {
// Establece la transparencia de la atenuación
void Background::setAlpha(int alpha) {
// Evita que se asignen valores fuera de rango
alpha_ = std::clamp(alpha, 0, 255);
alpha = std::clamp(alpha, 0, 255);
// Guarda el valor actual y establece el nuevo valor
alpha_color_text_temp_ = alpha_color_text_;
alpha_color_text_ = alpha_;
previous_alpha_color_texture_ = alpha_color_texture_;
alpha_color_texture_ = alpha;
}
// Actualiza el valor de alpha_
// Actualiza el valor de alpha
void Background::updateAlphaColorTexture() {
if (alpha_color_text_ == alpha_color_text_temp_) {
if (alpha_color_texture_ == previous_alpha_color_texture_) {
return;
}
alpha_color_text_ > alpha_color_text_temp_ ? ++alpha_color_text_temp_ : --alpha_color_text_temp_;
SDL_SetTextureAlphaMod(color_texture_, alpha_color_text_temp_);
}
// Actualiza las nubes
void Background::updateClouds() {
// Aplica la velocidad calculada a las nubes
top_clouds_sprite_a_->setVelX(clouds_speed_);
top_clouds_sprite_b_->setVelX(clouds_speed_);
bottom_clouds_sprite_a_->setVelX(clouds_speed_ / 2);
bottom_clouds_sprite_b_->setVelX(clouds_speed_ / 2);
// Mueve las nubes
top_clouds_sprite_a_->update();
top_clouds_sprite_b_->update();
bottom_clouds_sprite_a_->update();
bottom_clouds_sprite_b_->update();
// Calcula el offset de las nubes
if (top_clouds_sprite_a_->getPosX() < -top_clouds_sprite_a_->getWidth()) {
top_clouds_sprite_a_->setPosX(top_clouds_sprite_a_->getWidth());
}
if (top_clouds_sprite_b_->getPosX() < -top_clouds_sprite_b_->getWidth()) {
top_clouds_sprite_b_->setPosX(top_clouds_sprite_b_->getWidth());
}
if (bottom_clouds_sprite_a_->getPosX() < -bottom_clouds_sprite_a_->getWidth()) {
bottom_clouds_sprite_a_->setPosX(bottom_clouds_sprite_a_->getWidth());
}
if (bottom_clouds_sprite_b_->getPosX() < -bottom_clouds_sprite_b_->getWidth()) {
bottom_clouds_sprite_b_->setPosX(bottom_clouds_sprite_b_->getWidth());
}
alpha_color_texture_ > previous_alpha_color_texture_ ? ++previous_alpha_color_texture_ : --previous_alpha_color_texture_;
SDL_SetTextureAlphaMod(color_texture_, previous_alpha_color_texture_);
}
// Precalcula el vector con el recorrido del sol
@@ -323,7 +479,7 @@ void Background::createSunPath() {
const int NUM_STEPS = static_cast<int>((M_PI - M_PI / 2) / STEP) + 1;
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 y = CENTER_Y - (RADIUS * sin(theta));
sun_path_.push_back({x, y});
@@ -343,26 +499,22 @@ void Background::createMoonPath() {
const float CENTER_Y = base_ - 50;
constexpr float RADIUS = 140;
// Generar puntos de la curva desde 0 a 90 grados
constexpr double STEP = 0.01;
const int NUM_STEPS = static_cast<int>((M_PI / 2 - 0) / 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
const int FREEZE_START_INDEX = static_cast<int>(NUM_STEPS * (1.0F - FREEZE_PERCENTAGE));
for (int i = 0; i < NUM_STEPS; ++i) {
double theta = 0 + i * STEP;
double theta = i * STEP;
float x = CENTER_X + (RADIUS * cos(theta));
float y = CENTER_Y - (RADIUS * sin(theta));
moon_path_.push_back({x, y});
if (i >= FREEZE_START_INDEX && !moon_path_.empty()) {
moon_path_.push_back(moon_path_.back()); // Repite el último punto válido
} else {
moon_path_.push_back({x, y});
}
}
}
// Establece la posición del sol
void Background::setSunProgression(float progress) {
progress = std::clamp(progress, 0.0F, 1.0F);
sun_index_ = static_cast<size_t>(progress * (sun_path_.size() - 1));
}
// Establece la posición de la luna
void Background::setMoonProgression(float progress) {
progress = std::clamp(progress, 0.0F, 1.0F);
moon_index_ = static_cast<size_t>(progress * (moon_path_.size() - 1));
}

View File

@@ -2,10 +2,11 @@
#include <SDL3/SDL.h> // Para SDL_FRect, SDL_FPoint, SDL_Texture, SDL_Renderer
#include <array> // Para array
#include <cstddef> // Para size_t
#include <memory> // Para unique_ptr, shared_ptr
#include <vector> // Para vector
#include <array> // Para array
#include <cstddef> // Para size_t
#include <functional> // Para function
#include <memory> // Para unique_ptr, shared_ptr
#include <vector> // Para vector
#include "color.h" // Para Color
@@ -13,102 +14,122 @@ class MovingSprite;
class Sprite;
class Texture;
/*
Esta clase gestiona el fondo que aparece en la sección jugable.
Usa una textura compuesta y una capa superior con un color sólido cuya opacidad es ajustable.
Su área total está definida por "rect", pero solo se pinta la región "srcRect" en la pantalla en "dstRect".
Métodos clave:
- setCloudsSpeed(float value) -> Define la velocidad de las nubes
- setGradientNumber(int value) -> Ajusta el índice del color de cielo
- setTransition(float value) -> Configura la transición entre texturas
- setColor(Color color) -> Aplica un color de atenuación
- setAlpha(int alpha) -> Ajusta la transparencia de la capa de atenuación
*/
// --- Clase Background: gestiona el fondo de la sección jugable ---
class Background {
public:
// Constructor y Destructor
Background();
~Background();
// --- Enums ---
enum class State {
NORMAL, // Progresión normal del día
COMPLETED // Reducción gradual de la actividad
};
// Actualización y renderizado
// --- Tipos ---
using ProgressCallback = std::function<void(float)>; // Callback para sincronización
// --- 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 render(); // Dibuja el objeto
void reset(); // Reinicia la progresión
// Configuración de posición
void setPos(SDL_FRect pos); // Establece la posición del objeto
// --- Configuración ---
void setPos(SDL_FRect pos); // Establece la posición del objeto
void setState(State new_state); // Cambia el estado del fondo
void setProgressCallback(ProgressCallback callback); // Establece callback para sincronización
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 de animaciones y efectos
void setCloudsSpeed(float value); // Ajusta la velocidad de desplazamiento de las nubes
void setGradientNumber(int value); // Establece el degradado de fondo a usar
void setTransition(float value); // Ajusta la transición entre texturas de 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
// Configuración de efectos visuales
void setColor(Color color); // Establece el color de atenuación
void setAlpha(int alpha); // Ajusta la transparencia del fondo
// Configuración del sol y la luna
void setSunProgression(float progress); // Establece la posición del sol
void setMoonProgression(float progress); // Establece la posición de la luna
// --- Getters ---
[[nodiscard]] auto getProgress() const -> float { return progress_; } // Obtiene el progreso actual
[[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
private:
// Objetos y punteros
SDL_Renderer *renderer_; // Renderizador de la ventana
// --- Constantes ---
static constexpr size_t STAGES = 4; // Número de etapas
static constexpr float COMPLETED_REDUCTION_RATE = 25.0F; // Tasa de reducción completada
static constexpr float MINIMUM_COMPLETED_PROGRESS = 200.0F; // Progreso mínimo completado
static constexpr float SUN_COMPLETION_FACTOR = 0.5F; // Factor de completado del sol
// Texturas
std::shared_ptr<Texture> buildings_texture_;
std::shared_ptr<Texture> top_clouds_texture_;
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_;
// --- Objetos y punteros ---
SDL_Renderer *renderer_; // Renderizador de la ventana
SDL_Texture *canvas_; // Textura para componer el fondo
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
// 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_;
// --- Variables de configuración ---
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
// Buffers de renderizado
SDL_Texture *canvas_; // Textura para componer el fondo
SDL_Texture *color_texture_; // Textura para atenuar el fondo
// --- Variables de estado ---
std::vector<SDL_FPoint> sun_path_; // Recorrido del sol
std::vector<SDL_FPoint> moon_path_; // Recorrido de la luna
std::array<SDL_FRect, STAGES> gradient_rect_; // Fondos degradados
std::array<SDL_FRect, 4> top_clouds_rect_; // Nubes superiores
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
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
// Variables de control
std::array<SDL_FRect, 4> gradient_rect_;
std::array<SDL_FRect, 4> top_clouds_rect_;
std::array<SDL_FRect, 4> bottom_clouds_rect_;
int gradient_number_ = 0;
int alpha_ = 0;
float clouds_speed_ = 0;
float transition_ = 0;
int counter_ = 0;
SDL_FRect rect_;
SDL_FRect src_rect_;
SDL_FRect dst_rect_;
int base_;
Color attenuate_color_;
int alpha_color_text_;
int alpha_color_text_temp_;
std::vector<SDL_FPoint> sun_path_;
std::vector<SDL_FPoint> moon_path_;
size_t sun_index_ = 0;
size_t moon_index_ = 0;
// Métodos internos
void renderGradient(); // Dibuja el gradiente de fondo
void renderTopClouds(); // Dibuja las nubes superiores
void renderBottomClouds(); // Dibuja las nubes inferiores
void fillCanvas(); // Compone todos los elementos en la textura
void updateAlphaColorTexture(); // Actualiza el alpha de la textura de atenuación
void updateClouds(); // Actualiza el movimiento de las nubes
void createSunPath(); // Precalcula el recorrido del sol
void createMoonPath(); // Precalcula el recorrido de la luna
};
// --- Métodos internos ---
void initializePaths(); // Inicializa las rutas del sol y la luna
void initializeRects(); // Inicializa los rectángulos de gradientes y nubes
void initializeSprites(); // Crea los sprites
void initializeSpriteProperties(); // Configura las propiedades iniciales de los sprites
void initializeTextures(); // Inicializa las texturas de renderizado
void updateProgression(); // Actualiza la progresión y calcula transiciones
void updateCloudsSpeed(); // Actualiza la velocidad de las nubes según el estado
void renderGradient(); // Dibuja el gradiente de fondo
void renderTopClouds(); // Dibuja las nubes superiores
void renderBottomClouds(); // Dibuja las nubes inferiores
void fillCanvas(); // Compone todos los elementos en la textura
void updateAlphaColorTexture(); // Actualiza el alpha de la textura de atenuación
void updateClouds(); // Actualiza el movimiento de las nubes
void createSunPath(); // Precalcula el recorrido del sol
void createMoonPath(); // Precalcula el recorrido de la luna
};

View File

@@ -11,7 +11,7 @@
#include "texture.h" // Para Texture
// 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(float x, float y, Type type, Size size, float vel_x, float speed, Uint16 creation_timer, SDL_FRect play_area, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation)
: sprite_(std::make_unique<AnimatedSprite>(texture, animation)),
x_(x),
y_(y),
@@ -44,7 +44,7 @@ Balloon::Balloon(float x, float y, Type type, Size size, float vel_x, float spee
}
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;
const int INDEX = static_cast<int>(size_);
@@ -95,10 +95,9 @@ Balloon::Balloon(float x, float y, Type type, Size size, float vel_x, float spee
// Centra el globo en la posición X
void Balloon::alignTo(int x) {
x_ = static_cast<float>(x - (w_ / 2));
const int MIN_X = play_area_.x;
const int MAX_X = play_area_.w - w_;
x_ = std::clamp(x_, static_cast<float>(MIN_X), static_cast<float>(MAX_X));
const float MIN_X = play_area_.x;
const float MAX_X = play_area_.w - w_;
x_ = std::clamp(x - (w_ / 2), MIN_X, MAX_X);
}
// Pinta el globo en la pantalla

View File

@@ -38,17 +38,18 @@ class Balloon {
static constexpr int POWERBALL_SCREENPOWER_MINIMUM = 10;
static constexpr int POWERBALL_COUNTER = 8;
// --- Enums ---
enum class Size : Uint8 {
SMALL = 0,
MEDIUM = 1,
LARGE = 2,
EXTRALARGE = 3,
SMALL = 0, // Tamaño pequeño
MEDIUM = 1, // Tamaño mediano
LARGE = 2, // Tamaño grande
EXTRALARGE = 3, // Tamaño extra grande
};
enum class Type : Uint8 {
BALLOON = 0,
FLOATER = 1,
POWERBALL = 2,
BALLOON = 0, // Globo normal
FLOATER = 1, // Globo flotante
POWERBALL = 2, // Globo de poder
};
// --- Constructores y destructor ---
@@ -61,7 +62,7 @@ class Balloon {
float speed,
Uint16 creation_timer,
SDL_FRect play_area,
std::shared_ptr<Texture> texture,
const std::shared_ptr<Texture>& texture,
const std::vector<std::string>& animation);
~Balloon() = default;

View File

@@ -13,7 +13,7 @@
// --- Clase BalloonFormations ---
class BalloonFormations {
public:
// --- Estructuras de datos ---
// --- Estructuras ---
struct SpawnParams {
int 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
@@ -41,8 +41,8 @@ class BalloonFormations {
Formation() = default;
};
// Vector de índices a formaciones
using Pool = std::vector<int>;
// --- Types ---
using Pool = std::vector<int>; // Vector de índices a formaciones
// --- Constructor y destructor ---
BalloonFormations() {
@@ -79,28 +79,20 @@ class BalloonFormations {
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
// --- Datos ---
// --- Variables ---
std::vector<Formation> formations_; // Vector con todas las formaciones disponibles
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 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 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 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 evaluateSimpleExpression(const std::string& expr, const std::map<std::string, float>& variables) -> float;
// --- Utilidades ---
static auto trim(const std::string& str) -> std::string;
// --- Generación de variantes ---
void createFloaterVariants();
void loadDefaultFormations();
void loadDefaultPools(); // Nueva función para pools por defecto

View File

@@ -12,13 +12,12 @@
#include "param.h" // Para Param, ParamGame, param
#include "resource.h" // Para Resource
#include "screen.h" // Para Screen
#include "stage.h" // Para addPower
#include "stage_interface.h" // Para IStageInfo
#include "utils.h"
// Constructor
BalloonManager::BalloonManager()
: explosions_(std::make_unique<Explosions>()),
balloon_formations_(std::make_unique<BalloonFormations>()) { init(); }
BalloonManager::BalloonManager(IStageInfo *stage_info)
: explosions_(std::make_unique<Explosions>()), balloon_formations_(std::make_unique<BalloonFormations>()), stage_info_(stage_info) { init(); }
// Inicializa
void BalloonManager::init() {
@@ -63,7 +62,7 @@ void BalloonManager::init() {
// Actualiza
void BalloonManager::update() {
for (auto balloon : balloons_) {
for (const auto &balloon : balloons_) {
balloon->update();
}
updateBalloonDeployCounter();
@@ -110,7 +109,7 @@ void BalloonManager::deployRandomFormation(int stage) {
}
// Reinicia el contador para el próximo despliegue
balloon_deploy_counter_ = 300;
balloon_deploy_counter_ = DEFAULT_BALLOON_DEPLOY_COUNTER;
}
}
}
@@ -133,8 +132,8 @@ void BalloonManager::deployFormation(int formation_id, int y) {
// Vacia del vector de globos los globos que ya no sirven
void BalloonManager::freeBalloons() {
auto it = std::remove_if(balloons_.begin(), balloons_.end(), [](const auto &balloon) { return !balloon->isEnabled(); });
balloons_.erase(it, balloons_.end());
auto result = std::ranges::remove_if(balloons_, [](const auto &balloon) { return !balloon->isEnabled(); });
balloons_.erase(result.begin(), balloons_.end());
}
// Actualiza la variable enemyDeployCounter
@@ -174,23 +173,22 @@ void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon> &balloon,
const auto SIZE = static_cast<Balloon::Size>(static_cast<int>(balloon->getSize()) - 1);
const int PARENT_HEIGHT = balloon->getHeight();
const int CHILD_HEIGHT = Balloon::WIDTH.at(static_cast<int>(balloon->getSize()) - 1);
const int Y = balloon->getPosY() + (PARENT_HEIGHT - CHILD_HEIGHT) / 2;
const int X = direction == "LEFT" ? balloon->getPosX() + (balloon->getWidth() / 3) : balloon->getPosX() + 2 * (balloon->getWidth() / 3);
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 MIN_X = play_area_.x;
const float MAX_X = play_area_.w - CHILD_WIDTH;
x = std::clamp(x - (CHILD_WIDTH / 2), MIN_X, MAX_X);
// Crea el globo
auto b = createBalloon(0, Y, balloon->getType(), SIZE, VX, balloon_speed_, 0);
auto b = createBalloon(x, Y, balloon->getType(), SIZE, VX, balloon_speed_, 0);
// Establece parametros
b->alignTo(X);
b->setVelY(b->getType() == Balloon::Type::BALLOON ? -2.50F : Balloon::VELX_NEGATIVE * 2.0F);
// Herencia de estados
if (balloon->isStopped()) {
b->stop();
}
if (balloon->isUsingReversedColor()) {
b->useReverseColor();
}
if (balloon->isStopped()) { b->stop(); }
if (balloon->isUsingReversedColor()) { b->useReverseColor(); }
}
}
@@ -226,8 +224,8 @@ void BalloonManager::setBalloonSpeed(float speed) {
}
// Explosiona un globo. Lo destruye y crea otros dos si es el caso
auto BalloonManager::popBalloon(std::shared_ptr<Balloon> balloon) -> int {
Stage::addPower(1);
auto BalloonManager::popBalloon(const std::shared_ptr<Balloon> &balloon) -> int {
stage_info_->addPower(1);
int score = 0;
if (balloon->getType() == Balloon::Type::POWERBALL) {
@@ -274,7 +272,7 @@ auto BalloonManager::destroyBalloon(std::shared_ptr<Balloon> &balloon) -> int {
}
// Aumenta el poder de la fase
Stage::addPower(balloon->getPower());
stage_info_->addPower(balloon->getPower());
// Destruye el globo
explosions_->add(balloon->getPosX(), balloon->getPosY(), static_cast<int>(balloon->getSize()));
@@ -291,7 +289,7 @@ auto BalloonManager::destroyAllBalloons() -> int {
}
balloon_deploy_counter_ = 300;
Screen::get()->flash(FLASH_COLOR, 3);
Screen::get()->flash(Colors::FLASH, 3);
Screen::get()->shake();
return score;
@@ -336,7 +334,7 @@ void BalloonManager::createTwoBigBalloons() {
// Crea una disposición de globos aleatoria
void BalloonManager::createRandomBalloons() {
const int NUM_BALLOONS = 2 + rand() % 4;
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);

View File

@@ -12,39 +12,41 @@
#include "balloon_formations.h" // Para BalloonFormations
#include "explosions.h" // Para Explosions
#include "param.h" // Para Param, ParamGame, param
#include "stage_interface.h" // Para IStageInfo
#include "utils.h" // Para Zone
class Texture;
// --- Types ---
using Balloons = std::vector<std::shared_ptr<Balloon>>;
// Clase BalloonManager
// --- Clase BalloonManager: gestiona todos los globos del juego ---
class BalloonManager {
public:
// Constructor y Destructor
BalloonManager();
// --- Constructor y destructor ---
BalloonManager(IStageInfo *stage_info);
~BalloonManager() = default;
// Actualización y Renderizado
// --- Métodos principales ---
void update(); // Actualiza el estado de los globos
void render(); // Renderiza los globos en pantalla
// Gestión de globos
// --- Gestión de globos ---
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 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
// 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
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 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 setDefaultBalloonSpeed(float speed) { default_balloon_speed_ = speed; }; // Establece la velocidad base
void resetBalloonSpeed() { setBalloonSpeed(default_balloon_speed_); }; // Restablece la velocidad de los globos
@@ -52,58 +54,61 @@ class BalloonManager {
auto canPowerBallBeCreated() -> bool; // Indica si se puede crear una PowerBall
auto calculateScreenPower() -> int; // Calcula el poder de los globos en pantalla
// Manipulación de globos existentes
auto popBalloon(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 destroyAllBalloons() -> int; // Destruye todos los globos
void stopAllBalloons(); // Detiene el movimiento de los globos
void startAllBalloons(); // Reactiva el movimiento de los globos
// --- Manipulación de globos existentes ---
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 destroyAllBalloons() -> int; // Destruye todos los globos
void stopAllBalloons(); // Detiene 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 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 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
// Configuración de juego
// --- Configuración 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 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
[[nodiscard]] auto getBalloonSpeed() const -> float { return balloon_speed_; }
auto getBalloons() -> Balloons & { return balloons_; }
[[nodiscard]] auto getNumBalloons() const -> int { return balloons_.size(); }
private:
Balloons balloons_; // Vector con los globos activos
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>> explosions_textures_; // Texturas de explosiones
// --- Constantes ---
static const int DEFAULT_BALLOON_DEPLOY_COUNTER = 300;
// --- Objetos y punteros ---
Balloons balloons_; // Vector con los globos activos
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>> explosions_textures_; // Texturas de explosiones
std::vector<std::vector<std::string>> balloon_animations_; // Animaciones de los globos
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 default_balloon_speed_ = Balloon::SPEED.at(0);
int balloon_deploy_counter_ = 0;
bool power_ball_enabled_ = false;
int power_ball_counter_ = 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 can_deploy_balloons_ = true;
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
// Metodos privados
// --- Métodos internos ---
void init();
};

View File

@@ -9,10 +9,10 @@
// Constructor
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"))),
pos_x_(x),
pos_y_(y),
bullet_type_(bullet_type),
owner_(owner) {
owner_(owner),
pos_x_(x),
pos_y_(y) {
vel_x_ = calculateVelocity(bullet_type_);
sprite_->setCurrentAnimation(buildAnimationString(bullet_type_, powered));

View File

@@ -9,65 +9,62 @@
#include "player.h" // Para Player
#include "utils.h" // Para Circle
// Tipos de balas
// --- Enums ---
enum class BulletType : Uint8 {
UP,
LEFT,
RIGHT,
NONE
UP, // Bala hacia arriba
LEFT, // Bala hacia la izquierda
RIGHT, // Bala hacia la derecha
NONE // Sin bala
};
// Resultado del movimiento de la bala
enum class BulletMoveStatus : Uint8 {
OK = 0,
OUT = 1
OK = 0, // Movimiento normal
OUT = 1 // Fuera de los límites
};
// Clase Bullet
// --- Clase Bullet: representa una bala del jugador ---
class Bullet {
public:
// Constantes
static constexpr float WIDTH = 12.0F;
static constexpr float HEIGHT = 12.0F;
// --- Constantes ---
static constexpr float WIDTH = 12.0F; // Anchura de la bala
static constexpr float HEIGHT = 12.0F; // Altura de la bala
// Constructor y Destructor
Bullet(float x, float y, BulletType bullet_type, bool powered, Player::Id owner);
~Bullet() = default;
// --- Constructor y destructor ---
Bullet(float x, float y, BulletType bullet_type, bool powered, Player::Id owner); // Constructor principal
~Bullet() = default; // Destructor
// Métodos principales
// --- Métodos principales ---
void render(); // Dibuja la bala en pantalla
auto update() -> BulletMoveStatus; // Actualiza el estado del objeto
void disable(); // Desactiva la bala
// Estado de la bala
[[nodiscard]] auto isEnabled() const -> bool; // Comprueba si está activa
void disable(); // Desactiva la bala
// Getters
// --- Getters ---
[[nodiscard]] auto isEnabled() const -> bool; // Comprueba si está activa
[[nodiscard]] auto getOwner() const -> Player::Id; // Devuelve el identificador del dueño
auto getCollider() -> Circle &; // Devuelve el círculo de colisión
private:
// Constantes
static constexpr float VEL_Y = -3.0F;
static constexpr float VEL_X_LEFT = -2.0F;
static constexpr float VEL_X_RIGHT = 2.0F;
static constexpr float VEL_X_CENTER = 0.0F;
// --- Constantes ---
static constexpr float VEL_Y = -3.0F; // Velocidad vertical
static constexpr float VEL_X_LEFT = -2.0F; // Velocidad izquierda
static constexpr float VEL_X_RIGHT = 2.0F; // Velocidad derecha
static constexpr float VEL_X_CENTER = 0.0F; // Velocidad central
// Propiedades
// --- Objetos y punteros ---
std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos
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
// --- Variables de estado ---
Circle collider_; // Círculo de colisión
BulletType bullet_type_; // Tipo de bala
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 shiftSprite(); // Ajusta el sprite
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 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 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
};

View File

@@ -42,22 +42,8 @@ auto Color::fromHex(const std::string &hex_str) -> Color {
return Color(r, g, b, a);
}
// 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;
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 {
// Implementaciones de métodos estáticos de Color
constexpr auto Color::rgbToHsv(Color color) -> HSV {
float r = color.r / 255.0F;
float g = color.g / 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 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 x = c * (1 - std::abs(std::fmod(hsv.h / 60.0F, 2) - 1));
float m = hsv.v - c;
@@ -128,55 +114,73 @@ constexpr auto hsvToRgb(HSV hsv) -> Color {
static_cast<uint8_t>(roundf((b + m) * 255)));
}
auto generateMirroredCycle(Color base, ColorCycleStyle style) -> ColorCycle {
ColorCycle result{};
HSV base_hsv = rgbToHsv(base);
// Implementaciones del namespace Colors
namespace Colors {
// 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) {
float t = static_cast<float>(i) / (COLOR_CYCLE_SIZE - 1); // 0 → 1
float hue_shift = 0.0F;
float sat_shift = 0.0F;
float val_shift = 0.0F;
switch (style) {
case ColorCycleStyle::SUBTLE_PULSE:
// Solo brillo suave
val_shift = 0.07F * sinf(t * M_PI);
break;
case ColorCycleStyle::HUE_WAVE:
// Oscilación leve de tono
hue_shift = 15.0F * (t - 0.5F) * 2.0F;
val_shift = 0.05F * sinf(t * M_PI);
break;
case ColorCycleStyle::VIBRANT:
// Cambios fuertes en tono y brillo
hue_shift = 35.0F * sinf(t * M_PI);
val_shift = 0.2F * sinf(t * M_PI);
sat_shift = -0.2F * sinf(t * M_PI);
break;
case ColorCycleStyle::DARKEN_GLOW:
// Se oscurece al centro
val_shift = -0.15F * sinf(t * M_PI);
break;
case ColorCycleStyle::LIGHT_FLASH:
// Se ilumina al centro
val_shift = 0.25F * sinf(t * M_PI);
break;
size_t index;
if (n < colors.size()) {
index = n; // Avanza: 0,1,2,3
} else {
index = 2 * (colors.size() - 1) - n; // Retrocede: 2,1
}
HSV adjusted = {
fmodf(base_hsv.h + hue_shift + 360.0F, 360.0F),
fminf(1.0F, fmaxf(0.0F, base_hsv.s + sat_shift)),
fminf(1.0F, fmaxf(0.0F, base_hsv.v + val_shift))};
Color c = hsvToRgb(adjusted);
result[i] = c;
result[2 * COLOR_CYCLE_SIZE - 1 - i] = c; // espejo
return colors[index];
}
return result;
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 sat_shift = 0.0F;
float val_shift = 0.0F;
switch (style) {
case ColorCycleStyle::SUBTLE_PULSE:
// Solo brillo suave
val_shift = 0.07F * sinf(t * M_PI);
break;
case ColorCycleStyle::HUE_WAVE:
// Oscilación leve de tono
hue_shift = 15.0F * (t - 0.5F) * 2.0F;
val_shift = 0.05F * sinf(t * M_PI);
break;
case ColorCycleStyle::VIBRANT:
// Cambios fuertes en tono y brillo
hue_shift = 35.0F * sinf(t * M_PI);
val_shift = 0.2F * sinf(t * M_PI);
sat_shift = -0.2F * sinf(t * M_PI);
break;
case ColorCycleStyle::DARKEN_GLOW:
// Se oscurece al centro
val_shift = -0.15F * sinf(t * M_PI);
break;
case ColorCycleStyle::LIGHT_FLASH:
// Se ilumina al centro
val_shift = 0.25F * sinf(t * M_PI);
break;
}
HSV adjusted = {
.h = fmodf(base_hsv.h + hue_shift + 360.0F, 360.0F),
.s = fminf(1.0F, fmaxf(0.0F, base_hsv.s + sat_shift)),
.v = fminf(1.0F, fmaxf(0.0F, base_hsv.v + val_shift))};
Color c = Color::hsvToRgb(adjusted);
result[i] = c;
result[(2 * CYCLE_SIZE) - 1 - i] = c; // espejo
}
return result;
}
}

View File

@@ -9,12 +9,14 @@
#include <string> // Para string
#include <vector> // Para vector
// --- Constantes ---
constexpr size_t COLOR_CYCLE_SIZE = 6; // Mitad del ciclo espejado
// --- Estructura HSV: define un color en formato HSV ---
struct HSV {
float h; // Matiz (Hue)
float s; // Saturación (Saturation)
float v; // Valor (Value)
};
// --- Estructuras y tipos ---
// Estructura para definir un color RGBA
// --- Estructura Color: define un color RGBA ---
struct Color {
private:
static constexpr int DEFAULT_LIGHTEN_AMOUNT = 50;
@@ -62,6 +64,10 @@ struct Color {
// Método estático para crear Color desde string hexadecimal
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 {
return r == other.r && g == other.g && b == other.b && a == other.a;
}
@@ -81,14 +87,17 @@ struct Color {
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
struct HSV {
float h, s, v;
};
// Estructura para definir el ciclo de color
// --- Enum ColorCycleStyle: define estilos de ciclo de color ---
enum class ColorCycleStyle {
SUBTLE_PULSE, // Variación leve en brillo (por defecto)
HUE_WAVE, // Variación suave en tono (sin verde)
@@ -97,23 +106,27 @@ enum class ColorCycleStyle {
LIGHT_FLASH // Ilumina hacia el centro y regresa
};
// --- Alias ---
using ColorCycle = std::array<Color, 2 * COLOR_CYCLE_SIZE>;
// --- Namespace Colors: constantes y utilidades de color ---
namespace Colors {
// --- Constantes ---
constexpr size_t CYCLE_SIZE = 6; // Mitad del ciclo espejado
// --- Colores predefinidos ---
constexpr Color NO_TEXT_COLOR = Color(0XFF, 0XFF, 0XFF);
constexpr Color SHADOW_TEXT_COLOR = Color(0X43, 0X43, 0X4F);
constexpr Color TITLE_SHADOW_TEXT_COLOR = Color(0x14, 0x87, 0xc4);
constexpr Color ORANGE_TEXT_COLOR = Color(0XFF, 0X7A, 0X00);
// --- Alias ---
using Cycle = std::array<Color, 2 * CYCLE_SIZE>;
constexpr Color FLASH_COLOR = Color(0XFF, 0XFF, 0XFF);
// --- Colores predefinidos ---
constexpr Color NO_COLOR_MOD = Color(0XFF, 0XFF, 0XFF);
constexpr Color SHADOW_TEXT = Color(0X43, 0X43, 0X4F);
constexpr Color TITLE_SHADOW_TEXT = Color(0x14, 0x87, 0xc4);
constexpr Color ORANGE_TEXT = Color(0XFF, 0X7A, 0X00);
constexpr Color BLUE_SKY_COLOR = Color(0X02, 0X88, 0XD1);
constexpr Color PINK_SKY_COLOR = Color(0XFF, 0X6B, 0X97);
constexpr Color GREEN_SKY_COLOR = Color(0X00, 0X79, 0X6B);
constexpr Color FLASH = Color(0XFF, 0XFF, 0XFF);
// --- Funciones ---
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color;
constexpr auto rgbToHsv(Color color) -> HSV;
constexpr auto hsvToRgb(HSV hsv) -> Color;
auto generateMirroredCycle(Color base, ColorCycleStyle style = ColorCycleStyle::SUBTLE_PULSE) -> ColorCycle;
constexpr Color BLUE_SKY = Color(0X02, 0X88, 0XD1);
constexpr Color PINK_SKY = Color(0XFF, 0X6B, 0X97);
constexpr Color GREEN_SKY = Color(0X00, 0X79, 0X6B);
// --- Funciones ---
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color;
auto generateMirroredCycle(Color base, ColorCycleStyle style = ColorCycleStyle::SUBTLE_PULSE) -> Cycle;
}

240
source/defaults.h Normal file
View File

@@ -0,0 +1,240 @@
#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 = false;
// 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

View File

@@ -19,25 +19,12 @@ DefineButtons::DefineButtons()
clearButtons();
auto gamepads = input_->getGamepads();
for (auto gamepad : gamepads) {
for (const auto &gamepad : gamepads) {
controller_names_.emplace_back(Input::getControllerName(gamepad));
}
// Crear la ventana de mensaje
WindowMessage::Config config;
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;
WindowMessage::Config config(param.service_menu.window_message);
auto text_renderer = Resource::get()->getText("04b_25_flat");
window_message_ = std::make_unique<WindowMessage>(
text_renderer,
@@ -85,6 +72,9 @@ void DefineButtons::handleEvents(const SDL_Event &event) {
case SDL_EVENT_GAMEPAD_BUTTON_UP:
checkEnd();
break;
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
doControllerAxisMotion(event.gaxis);
break;
default:
break;
}
@@ -99,6 +89,8 @@ auto DefineButtons::enable(Options::Gamepad *options_gamepad) -> bool {
index_button_ = 0;
message_shown_ = false;
closing_ = false;
l2_was_pressed_ = false;
r2_was_pressed_ = false;
clearButtons();
updateWindowMessage();
@@ -117,6 +109,8 @@ void DefineButtons::disable() {
finished_ = false;
message_shown_ = false;
closing_ = false;
l2_was_pressed_ = false;
r2_was_pressed_ = false;
if (window_message_) {
window_message_->hide();
@@ -132,15 +126,65 @@ void DefineButtons::doControllerButtonDown(const SDL_GamepadButtonEvent &event)
const auto BUTTON = static_cast<SDL_GamepadButton>(event.button);
if (checkButtonNotInUse(BUTTON)) {
buttons_.at(index_button_).button = BUTTON;
buttons_.at(index_button_).button = static_cast<int>(BUTTON);
incIndexButton();
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) {
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);
@@ -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() {
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_UP"), Input::Action::FIRE_CENTER, 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] START"), Input::Action::START, 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] 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, static_cast<int>(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, static_cast<int>(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() {

View File

@@ -15,57 +15,63 @@ namespace Options {
struct Gamepad;
}
// --- Clase DefineButtons: configuración de botones de gamepad ---
class DefineButtons {
public:
// --- Estructuras ---
struct Button {
std::string label;
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) {}
};
// --- Constructor y destructor ---
DefineButtons();
~DefineButtons() = default;
// --- Métodos principales ---
void render();
void update();
void handleEvents(const SDL_Event &event);
auto enable(Options::Gamepad *options_gamepad) -> bool;
void disable();
// --- Getters ---
[[nodiscard]] auto isReadyToClose() const -> bool;
[[nodiscard]] auto isEnabled() const -> bool { return enabled_; }
[[nodiscard]] auto isFinished() const -> bool { return finished_; }
private:
// Constante para cuánto tiempo mostrar el mensaje (en frames)
static constexpr size_t MESSAGE_DISPLAY_FRAMES = 120; // ~2 segundos a 60fps
// --- Constantes ---
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
Options::Gamepad *options_gamepad_ = nullptr; // Opciones del gamepad
std::unique_ptr<WindowMessage> window_message_; // Mensaje de ventana
// Vectores y strings
// --- Variables de estado ---
std::vector<Button> buttons_; // Lista de botones
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
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
// --- Métodos internos ---
void incIndexButton();
void doControllerButtonDown(const SDL_GamepadButtonEvent &event);
void doControllerAxisMotion(const SDL_GamepadAxisEvent &event);
void bindButtons(Options::Gamepad *options_gamepad);
auto checkButtonNotInUse(SDL_GamepadButton button) -> bool;
auto checkTriggerNotInUse(int trigger_button) -> bool;
void clearButtons();
void checkEnd();
void updateWindowMessage();

View File

@@ -8,9 +8,9 @@ static std::vector<Info> difficulties_list;
void init() {
difficulties_list = {
{Code::EASY, "Easy"},
{Code::NORMAL, "Normal"},
{Code::HARD, "Hard"}};
{.code = Code::EASY, .name = "Easy"},
{.code = Code::NORMAL, .name = "Normal"},
{.code = Code::HARD, .name = "Hard"}};
}
auto getDifficulties() -> std::vector<Info>& {

View File

@@ -1,52 +1,28 @@
#pragma once
#include <string>
#include <vector>
#include <string> // Para string
#include <vector> // Para vector
namespace Difficulty {
/**
* @brief Códigos que identifican unívocamente cada nivel de dificultad.
*/
// --- Enums ---
enum class Code {
EASY = 0,
NORMAL = 1,
HARD = 2,
EASY = 0, // Dificultad fácil
NORMAL = 1, // Dificultad normal
HARD = 2, // Dificultad difícil
};
/**
* @brief Estructura que asocia un código de dificultad con su nombre traducible.
*/
// --- Estructuras ---
struct Info {
Code code;
std::string name;
Code code; // Código de dificultad
std::string name; // Nombre traducible
};
// --- Interfaz Pública ---
// --- Funciones ---
void init(); // Inicializa la lista de dificultades con sus valores por defecto
/**
* @brief Inicializa la lista de dificultades con sus valores por defecto.
*/
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;
auto getDifficulties() -> std::vector<Info>&; // Devuelve una referencia al vector de todas las dificultades
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
} // namespace Difficulty

View File

@@ -18,6 +18,7 @@
#include "manage_hiscore_table.h" // Para ManageHiScoreTable
#include "options.h" // Para loadFromFile, saveToFile, Settings, settings, setConfigFile, setControllersFile
#include "param.h" // Para loadParamsFromFile
#include "resource_helper.h" // Para ResourceHelper
#include "player.h" // Para Player
#include "resource.h" // Para Resource
#include "screen.h" // Para Screen
@@ -77,6 +78,12 @@ Director::~Director() {
void Director::init() {
// Configuración inicial de parametros
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
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
@@ -124,9 +131,9 @@ void Director::close() {
void Director::loadParams() {
// Carga los parametros para configurar el juego
#ifdef ANBERNIC
const std::string paramFilePath = asset->get("param_320x240.txt");
const std::string PARAM_FILE_PATH = Asset::get()->get("param_320x240.txt");
#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
loadParamsFromFile(PARAM_FILE_PATH);
}
@@ -154,7 +161,7 @@ void Director::loadAssets() {
#endif
// 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_);
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) {
std::cerr << "Error creando carpeta del sistema: "
<< SystemUtils::resultToString(result) << std::endl;
<< SystemUtils::resultToString(result) << '\n';
exit(EXIT_FAILURE);
}
}
@@ -321,7 +328,7 @@ void Director::shutdownSystem(bool should_shutdown) {
auto result = SystemShutdown::shutdownSystem(5, true); // 5 segundos, forzar apps
if (result != SystemShutdown::ShutdownResult::SUCCESS) {
std::cerr << SystemShutdown::resultToString(result) << std::endl;
std::cerr << SystemShutdown::resultToString(result) << '\n';
}
}
}

View File

@@ -7,6 +7,7 @@ namespace Lang {
enum class Code : int;
}
// --- Clase Director: gestor principal de la aplicación ---
class Director {
public:
// --- Constructor y destructor ---

View File

@@ -42,7 +42,7 @@ void EnterName::incPosition() {
if (position_ >= NAME_SIZE) {
position_ = NAME_SIZE; // Mantenemos en el índice máximo válido.
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.
character_index_[position_] = character_index_[position_ - 1];
@@ -74,7 +74,7 @@ void EnterName::decPosition() {
// 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) {
position_overflow_ = false;
}

View File

@@ -6,10 +6,10 @@
#include "utils.h" // Para trim
// Tamaño máximo del nombre
constexpr size_t NAME_SIZE = 5;
// --- Constantes ---
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 {
public:
EnterName();
@@ -29,11 +29,12 @@ class EnterName {
[[nodiscard]] auto getPositionOverflow() const -> bool { return position_overflow_; } // Indica si la posición excede el límite
private:
// --- Variables de estado ---
std::string character_list_; // Lista de caracteres permitidos
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
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 initCharacterIndex(const std::string &name); // Inicializa índices desde el nombre

View File

@@ -24,7 +24,7 @@ void Explosions::render() {
}
// 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);
}

View File

@@ -1,15 +1,15 @@
#pragma once
#include <memory> // Para unique_ptr, shared_ptr
#include <string> // Para string
#include <utility>
#include <vector> // Para vector
#include <memory> // Para unique_ptr, shared_ptr
#include <string> // Para string
#include <utility> // Para move
#include <vector> // Para vector
#include "animated_sprite.h" // Para AnimatedSprite
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 {
int size; // Tamaño de la explosión
std::shared_ptr<Texture> texture; // Textura para la explosión
@@ -19,35 +19,27 @@ struct ExplosionTexture {
: size(sz), texture(std::move(tex)), animation(anim) {}
};
// Clase Explosions
// --- Clase Explosions: gestor de explosiones ---
class Explosions {
public:
// Constructor y destructor
Explosions() = default;
~Explosions() = default;
// --- Constructor y destructor ---
Explosions() = default; // Constructor por defecto
~Explosions() = default; // Destructor por defecto
// Actualiza la lógica de la clase
void update();
// --- Métodos principales ---
void update(); // Actualiza la lógica de la clase
void render(); // Dibuja el objeto en pantalla
// Dibuja el objeto en pantalla
void render();
// 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);
// --- Configuración ---
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
private:
// Vector con las texturas a utilizar
std::vector<ExplosionTexture> textures_;
// --- Variables de estado ---
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
std::vector<std::unique_ptr<AnimatedSprite>> explosions_;
// Vacia el vector de elementos finalizados
void freeExplosions();
// Busca una textura a partir del tamaño
auto getIndexBySize(int size) -> int;
// --- Métodos internos ---
void freeExplosions(); // Vacía el vector de elementos finalizados
auto getIndexBySize(int size) -> int; // Busca una textura a partir del tamaño
};

View File

@@ -27,32 +27,40 @@ Fade::~Fade() {
// Inicializa las variables
void Fade::init() {
type_ = FadeType::CENTER;
mode_ = FadeMode::OUT;
type_ = Type::CENTER;
mode_ = Mode::OUT;
counter_ = 0;
r_ = 0;
g_ = 0;
b_ = 0;
a_ = 0;
post_duration_ = 0;
post_counter_ = 0;
post_start_time_ = 0;
pre_duration_ = 0;
pre_counter_ = 0;
pre_start_time_ = 0;
num_squares_width_ = param.fade.num_squares_width;
num_squares_height_ = param.fade.num_squares_height;
fade_random_squares_delay_ = param.fade.random_squares_delay;
fade_random_squares_mult_ = param.fade.random_squares_mult;
random_squares_duration_ = param.fade.random_squares_duration_ms; // Usar como duración en ms
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
void Fade::reset() {
state_ = FadeState::NOT_ENABLED;
state_ = State::NOT_ENABLED;
counter_ = 0;
post_start_time_ = 0;
pre_start_time_ = 0;
}
// Pinta una transición en pantalla
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);
}
}
@@ -60,13 +68,13 @@ void Fade::render() {
// Actualiza las variables internas
void Fade::update() {
switch (state_) {
case FadeState::PRE:
case State::PRE:
updatePreState();
break;
case FadeState::FADING:
case State::FADING:
updateFadingState();
break;
case FadeState::POST:
case State::POST:
updatePostState();
break;
default:
@@ -75,25 +83,36 @@ void Fade::update() {
}
void Fade::updatePreState() {
if (pre_counter_ == pre_duration_) {
state_ = FadeState::FADING;
} else {
pre_counter_++;
// Sistema basado en tiempo únicamente
Uint32 elapsed_time = SDL_GetTicks() - pre_start_time_;
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() {
switch (type_) {
case FadeType::FULLSCREEN:
case Type::FULLSCREEN:
updateFullscreenFade();
break;
case FadeType::CENTER:
case Type::CENTER:
updateCenterFade();
break;
case FadeType::RANDOM_SQUARE:
case Type::RANDOM_SQUARE:
updateRandomSquareFade();
break;
case FadeType::VENETIAN:
case Type::RANDOM_SQUARE2:
updateRandomSquare2Fade();
break;
case Type::DIAGONAL:
updateDiagonalFade();
break;
case Type::VENETIAN:
updateVenetianFade();
break;
default:
@@ -102,23 +121,36 @@ void Fade::updateFadingState() {
counter_++;
}
void Fade::changeToPostState() {
state_ = State::POST;
post_start_time_ = SDL_GetTicks();
}
void Fade::updatePostState() {
if (post_counter_ == post_duration_) {
state_ = FadeState::FINISHED;
} else {
post_counter_++;
// Sistema basado en tiempo únicamente
Uint32 elapsed_time = SDL_GetTicks() - post_start_time_;
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() {
// 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_);
// Comprueba si ha terminado
if (counter_ >= 255 / 4) {
state_ = FadeState::POST;
changeToPostState();
}
}
@@ -127,8 +159,8 @@ void Fade::updateCenterFade() {
// Comprueba si ha terminado
if ((counter_ * 4) > param.game.height) {
state_ = FadeState::POST;
a_ = 255;
changeToPostState();
}
}
@@ -151,20 +183,243 @@ void Fade::drawCenterFadeRectangles() {
}
void Fade::updateRandomSquareFade() {
if (counter_ % fade_random_squares_delay_ == 0) {
drawRandomSquares();
}
Uint32 elapsed_time = SDL_GetTicks() - random_squares_start_time_;
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
if (counter_ * fade_random_squares_mult_ / fade_random_squares_delay_ >=
num_squares_width_ * num_squares_height_) {
state_ = FadeState::POST;
if (elapsed_time >= static_cast<Uint32>(random_squares_duration_)) {
changeToPostState();
}
}
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_);
SDL_SetRenderTarget(renderer_, backbuffer_);
@@ -173,13 +428,56 @@ void Fade::drawRandomSquares() {
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
const int INDEX = std::min(counter_ / fade_random_squares_delay_,
(num_squares_width_ * num_squares_height_) - 1);
// Dibuja solo los cuadrados activos
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) {
const int INDEX2 = std::min(INDEX * fade_random_squares_mult_ + i,
static_cast<int>(square_.size()) - 1);
SDL_RenderFillRect(renderer_, &square_[INDEX2]);
SDL_SetRenderDrawBlendMode(renderer_, blend_mode);
SDL_SetRenderTarget(renderer_, temp);
}
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);
@@ -192,7 +490,7 @@ void Fade::updateVenetianFade() {
updateVenetianRectangles();
calculateVenetianProgress();
} else {
state_ = FadeState::POST;
changeToPostState();
}
}
@@ -233,31 +531,30 @@ void Fade::calculateVenetianProgress() {
// Activa el fade
void Fade::activate() {
// Si ya está habilitado, no hay que volverlo a activar
if (state_ != FadeState::NOT_ENABLED) {
if (state_ != State::NOT_ENABLED) {
return;
}
state_ = FadeState::PRE;
state_ = State::PRE;
counter_ = 0;
post_counter_ = 0;
pre_counter_ = 0;
pre_start_time_ = SDL_GetTicks();
switch (type_) {
case FadeType::FULLSCREEN: {
case Type::FULLSCREEN: {
// Pinta el backbuffer_ de color sólido
cleanBackbuffer(r_, g_, b_, 255);
break;
}
case FadeType::CENTER: {
rect1_ = {0, 0, param.game.width, 0};
rect2_ = {0, 0, param.game.width, 0};
case Type::CENTER: {
rect1_ = {.x = 0, .y = 0, .w = param.game.width, .h = 0};
rect2_ = {.x = 0, .y = 0, .w = param.game.width, .h = 0};
a_ = 64;
break;
}
case FadeType::RANDOM_SQUARE: {
rect1_ = {0, 0, static_cast<float>(param.game.width / num_squares_width_), static_cast<float>(param.game.height / num_squares_height_)};
case Type::RANDOM_SQUARE: {
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();
// Añade los cuadrados al vector
@@ -278,26 +575,96 @@ void Fade::activate() {
}
// Limpia la textura
a_ = mode_ == FadeMode::OUT ? 0 : 255;
a_ = mode_ == Mode::OUT ? 0 : 255;
cleanBackbuffer(r_, g_, b_, a_);
// 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;
}
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
a_ = mode_ == FadeMode::OUT ? 0 : 255;
a_ = mode_ == Mode::OUT ? 0 : 255;
cleanBackbuffer(r_, g_, b_, a_);
// Deja el color listo para usar
a_ = mode_ == FadeMode::OUT ? 255 : 0;
a_ = mode_ == Mode::OUT ? 255 : 0;
// Añade los cuadrados al vector
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;
for (int i = 0; i < MAX; ++i) {

View File

@@ -6,31 +6,32 @@
struct Color;
// Tipos 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,
};
// --- Clase Fade: gestor de transiciones de fundido ---
class Fade {
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 ---
Fade();
~Fade();
@@ -42,17 +43,17 @@ class Fade {
void activate(); // Activa el fade
// --- Configuración ---
void setColor(Uint8 r, Uint8 g, Uint8 b);
void setColor(Color color);
void setType(FadeType type) { type_ = type; }
void setMode(FadeMode mode) { mode_ = mode; }
void setPostDuration(int value) { post_duration_ = value; }
void setPreDuration(int value) { pre_duration_ = value; }
void setColor(Uint8 r, Uint8 g, Uint8 b); // Establece el color RGB del fade
void setColor(Color color); // Establece el color del fade
void setType(Type type) { type_ = type; } // Establece el tipo de fade
void setMode(Mode mode) { mode_ = mode; } // Establece el modo de fade
void setPostDuration(int value) { post_duration_ = value; } // Duración posterior al fade en milisegundos
void setPreDuration(int value) { pre_duration_ = value; } // Duración previa al fade en milisegundos
// --- Getters ---
[[nodiscard]] auto getValue() const -> int { return value_; }
[[nodiscard]] auto isEnabled() const -> bool { return state_ != FadeState::NOT_ENABLED; }
[[nodiscard]] auto hasEnded() const -> bool { return state_ == FadeState::FINISHED; }
[[nodiscard]] auto isEnabled() const -> bool { return state_ != State::NOT_ENABLED; }
[[nodiscard]] auto hasEnded() const -> bool { return state_ == State::FINISHED; }
private:
// --- Objetos y punteros ---
@@ -60,28 +61,24 @@ class Fade {
SDL_Texture *backbuffer_; // Backbuffer para efectos
// --- Variables de estado ---
FadeType type_; // Tipo de fade
FadeMode mode_; // Modo de fade
FadeState state_ = FadeState::NOT_ENABLED; // Estado actual
Uint16 counter_; // Contador interno
// --- Parámetros de color y geometría ---
Uint8 r_, g_, b_, a_; // Color del fade
SDL_FRect rect1_, rect2_; // Rectángulos para efectos
// --- Parámetros para RANDOM_SQUARE ---
int num_squares_width_; // Cuadrados en horizontal
int num_squares_height_; // Cuadrados en vertical
std::vector<SDL_FRect> square_; // Vector de cuadrados
int fade_random_squares_delay_; // Delay entre cuadrados
int fade_random_squares_mult_; // Cuadrados por paso
// --- Temporizadores ---
int post_duration_ = 0, post_counter_ = 0;
int pre_duration_ = 0, pre_counter_ = 0;
// --- Valor de progreso ---
int value_ = 0; // Estado del fade (0-100)
std::vector<SDL_FRect> square_; // Vector de cuadrados
std::vector<int> square_age_; // Edad de cada cuadrado (para RANDOM_SQUARE2)
SDL_FRect rect1_, rect2_; // Rectángulos para efectos
Type type_; // Tipo de fade
Mode mode_; // Modo de fade
State state_ = State::NOT_ENABLED; // Estado actual
Uint16 counter_; // Contador interno
Uint8 r_, g_, b_, a_; // Color del fade (RGBA)
int num_squares_width_; // Cuadrados en horizontal
int num_squares_height_; // Cuadrados en vertical
Uint32 random_squares_start_time_; // Tiempo de inicio del fade de cuadrados
int random_squares_duration_; // Duración total en milisegundos
int square_transition_duration_; // Duración de transición de cada cuadrado en ms
int post_duration_ = 0; // Duración posterior en milisegundos
Uint32 post_start_time_ = 0; // Tiempo de inicio del estado POST
int pre_duration_ = 0; // Duración previa en milisegundos
Uint32 pre_start_time_ = 0; // Tiempo de inicio del estado PRE
int value_ = 0; // Estado del fade (0-100)
// --- Inicialización y limpieza ---
void init(); // Inicializa variables
@@ -94,17 +91,23 @@ class Fade {
void updatePreState(); // Actualiza el estado previo al fade
void updateFadingState(); // Actualiza el estado durante el fade
void updatePostState(); // Actualiza el estado posterior al fade
void changeToPostState(); // Cambia al estado POST e inicializa el tiempo
// --- Efectos de fundido (fade) ---
void updateFullscreenFade(); // Actualiza el fundido de pantalla completa
void updateCenterFade(); // Actualiza el fundido desde el centro
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 updateVenetianRectangles(); // Actualiza los rectángulos del efecto veneciano
void calculateVenetianProgress(); // Calcula el progreso del efecto veneciano
// --- Dibujo de efectos visuales ---
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 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
};

View File

@@ -16,7 +16,7 @@
constexpr int ZOOM_FACTOR = 5;
constexpr int FLASH_DELAY = 3;
constexpr int FLASH_LENGHT = FLASH_DELAY + 3;
constexpr int FLASH_LENGTH = FLASH_DELAY + 3;
// Constructor
GameLogo::GameLogo(int x, int y)
@@ -34,7 +34,7 @@ GameLogo::GameLogo(int x, int y)
// Inicializa las variables
void GameLogo::init() {
const auto XP = x_ - coffee_texture_->getWidth() / 2;
const auto XP = x_ - (coffee_texture_->getWidth() / 2);
const auto DESP = getInitialVerticalDesp();
// Configura texturas
@@ -236,7 +236,7 @@ void GameLogo::finishArcadeEditionMoving() {
void GameLogo::playTitleEffects() {
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();
}

View File

@@ -8,7 +8,7 @@
class Texture;
// Clase GameLogo
// --- Clase GameLogo: gestor del logo del juego ---
class GameLogo {
public:
// --- Constructores y destructor ---
@@ -24,30 +24,31 @@ class GameLogo {
[[nodiscard]] auto hasFinished() const -> bool; // Indica si ha terminado la animación
private:
// --- Tipos internos ---
// --- Enums ---
enum class Status {
DISABLED,
MOVING,
SHAKING,
FINISHED,
DISABLED, // Deshabilitado
MOVING, // En movimiento
SHAKING, // Temblando
FINISHED, // Terminado
};
// --- Estructuras privadas ---
struct Shake {
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 lenght = 8; // Cantidad de desplazamientos a realizar
int remaining = lenght; // Cantidad de desplazamientos pendientes a realizar
int length = 8; // Cantidad de desplazamientos a realizar
int remaining = length; // Cantidad de desplazamientos pendientes a realizar
int counter = delay; // Contador para el retraso
int origin = 0; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
Shake() = default;
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) {
desp = d;
delay = de;
lenght = l;
length = l;
remaining = l;
counter = de;
origin = o;
@@ -67,14 +68,13 @@ class GameLogo {
std::unique_ptr<Sprite> arcade_edition_sprite_; // Sprite de "Arcade Edition"
// --- Variables de estado ---
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
Shake shake_; // Efecto de agitación
Status coffee_crisis_status_ = Status::DISABLED; // Estado de "COFFEE CRISIS"
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 ---
void init(); // Inicializa las variables

View File

@@ -8,6 +8,7 @@
#include "external/json.hpp"
#include "input_types.h" // Solo incluimos los tipos compartidos
// --- Estructuras ---
struct GamepadConfig {
std::string name; // Nombre 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 {
public:
// Escribir vector de GamepadConfig a archivo JSON
static auto writeToJson(const GamepadConfigs& configs, const std::string& filename) -> bool {
// --- Métodos estáticos ---
static auto writeToJson(const GamepadConfigs& configs, const std::string& filename) -> bool { // Escribir configuraciones a JSON
try {
nlohmann::json j;
j["gamepads"] = nlohmann::json::array();

View File

@@ -41,7 +41,7 @@ void handleInputEvents(const SDL_Event &event) {
}
// Comprueba los eventos que se pueden producir en cualquier sección del juego
void check(const SDL_Event &event) {
void handle(const SDL_Event &event) {
switch (event.type) {
case SDL_EVENT_QUIT: // Evento de salida de la aplicación
Section::name = Section::Name::QUIT;

View File

@@ -2,7 +2,8 @@
#include <SDL3/SDL.h>
// --- Namespace GlobalEvents: maneja eventos globales del juego ---
namespace GlobalEvents {
// Comprueba los eventos que se pueden producir en cualquier sección del juego
void check(const SDL_Event &event);
// --- Funciones ---
void handle(const SDL_Event &event); // Comprueba los eventos que se pueden producir en cualquier sección del juego
} // namespace GlobalEvents

View File

@@ -1,5 +1,6 @@
#include "global_inputs.h"
#include <algorithm> // Para std::ranges::any_of
#include <functional> // Para function
#include <memory> // Para allocator, shared_ptr
#include <string> // Para operator+, char_traits, string, to_string
@@ -145,11 +146,11 @@ auto checkServiceButton() -> bool {
}
// Mandos
for (auto gamepad : Input::get()->getGamepads()) {
if (Input::get()->checkAction(Input::Action::SERVICE, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
toggleServiceMenu();
return true;
}
if (std::ranges::any_of(Input::get()->getGamepads(), [](const auto& gamepad) {
return Input::get()->checkAction(Input::Action::SERVICE, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad);
})) {
toggleServiceMenu();
return true;
}
return false;
@@ -176,14 +177,13 @@ auto checkSystemInputs() -> bool {
#endif
};
for (const auto& [action, func] : ACTIONS) {
if (Input::get()->checkAction(action, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
func();
return std::ranges::any_of(ACTIONS, [](const auto& pair) {
if (Input::get()->checkAction(pair.first, Input::DO_NOT_ALLOW_REPEAT, Input::CHECK_KEYBOARD)) {
pair.second();
return true;
}
}
return false;
return false;
});
}
// Comprueba el resto de entradas

View File

@@ -1,6 +1,7 @@
#pragma once
// --- Namespace GlobalInputs: gestiona inputs globales del juego ---
namespace GlobalInputs {
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
auto check() -> bool;
// --- Funciones ---
auto check() -> bool; // Comprueba los inputs que se pueden introducir en cualquier sección del juego
} // namespace GlobalInputs

View File

@@ -7,55 +7,44 @@
#include "sprite.h" // Para Sprite
#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 {
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:
// Elimina el constructor por defecto para obligar a pasar una textura
Hit() = delete;
// 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)
// --- Constructor ---
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
: sprite_(std::make_unique<Sprite>(texture)) {}
// Establece la posición del Sprite en el espacio
void setPos(SDL_FPoint position) {
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) {
// --- Métodos principales ---
void create(SDL_FPoint position) { // Crea un "Hit" en la posición especificada
setPos(position);
enable(true);
}
// Dibuja el hit
void render() {
void render() { // Dibuja el hit
if (enabled_) {
sprite_->render();
}
}
// Deshabilita el hit
void disable() {
void disable() { // Deshabilita el hit
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
};

View File

@@ -36,21 +36,21 @@ void Input::bindKey(Action action, SDL_Scancode code) {
}
// 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) {
gamepad->bindings[action].button = button;
}
}
// 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) {
gamepad->bindings[action_target].button = gamepad->bindings[action_source].button;
}
}
// 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_controller = false;
@@ -65,6 +65,10 @@ auto Input::checkAction(Action action, bool repeat, bool check_keyboard, std::sh
if (gamepad != nullptr) {
success_controller = checkAxisInput(action, gamepad, repeat);
if (!success_controller) {
success_controller = checkTriggerInput(action, gamepad, repeat);
}
if (!success_controller) {
if (repeat) { // El usuario quiere saber si está pulsada (estado mantenido)
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
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.
// --- Comprobación del Teclado ---
@@ -118,7 +122,7 @@ auto Input::checkAnyButton(bool repeat) -> bool {
}
// Comprueba los mandos
for (auto gamepad : gamepads_) {
for (const auto &gamepad : gamepads_) {
if (checkAction(bi, repeat, DO_NOT_CHECK_KEYBOARD, gamepad)) {
return true;
}
@@ -132,7 +136,9 @@ auto Input::checkAnyButton(bool repeat) -> bool {
auto Input::gameControllerFound() const -> bool { return !gamepads_.empty(); }
// 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
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
auto Input::getControllerBinding(std::shared_ptr<Gamepad> gamepad, Action action) -> SDL_GamepadButton {
return gamepad->bindings[action].button;
auto Input::getControllerBinding(const std::shared_ptr<Gamepad> &gamepad, Action action) -> SDL_GamepadButton {
return static_cast<SDL_GamepadButton>(gamepad->bindings[action].button);
}
// Convierte un InputAction a std::string
@@ -202,7 +208,7 @@ auto Input::stringToInput(const std::string &name) -> Action {
}
// 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
bool axis_active_now = false;
@@ -243,9 +249,57 @@ auto Input::checkAxisInput(Action action, std::shared_ptr<Gamepad> gamepad, bool
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() {
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) {
binding.second.is_held = false;
binding.second.just_pressed = false;
binding.second.trigger_active = false;
}
}
}
@@ -297,9 +352,9 @@ void Input::update() {
}
// --- MANDOS ---
for (auto gamepad : gamepads_) {
for (const auto &gamepad : gamepads_) {
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
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 {
SDL_Gamepad *pad = SDL_OpenGamepad(device_index);
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 {};
}
auto gamepad = std::make_shared<Gamepad>(pad);
auto name = gamepad->name;
std::cout << "Gamepad connected (" << name << ")" << std::endl;
std::cout << "Gamepad connected (" << name << ")" << '\n';
applyGamepadConfig(gamepad);
saveGamepadConfigFromGamepad(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 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;
});
if (it != gamepads_.end()) {
std::string name = (*it)->name;
std::cout << "Gamepad disconnected (" << name << ")" << std::endl;
std::cout << "Gamepad disconnected (" << name << ")" << '\n';
gamepads_.erase(it);
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 {};
}
void Input::printConnectedGamepads() const {
if (gamepads_.empty()) {
std::cout << "No hay gamepads conectados." << std::endl;
std::cout << "No hay gamepads conectados." << '\n';
return;
}
@@ -359,7 +414,7 @@ void Input::printConnectedGamepads() const {
for (const auto &gamepad : gamepads_) {
std::string name = gamepad->name.empty() ? "Desconocido" : gamepad->name;
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) ---
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;
});
if (config_it != gamepad_configs_.end()) {
// 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) {
if (gamepad->bindings.find(action) != gamepad->bindings.end()) {
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) ---
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;
});
@@ -411,7 +466,7 @@ void Input::saveGamepadConfigFromGamepad(std::shared_ptr<Gamepad> gamepad) {
// Copiar todos los bindings actuales del gamepad
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()) {
@@ -434,7 +489,7 @@ void Input::setGamepadConfigsFile(const std::string &filename) {
// Método para obtener configuración de un gamepad específico (opcional)
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;
});
@@ -443,7 +498,7 @@ auto Input::getGamepadConfig(const std::string &gamepad_name) -> GamepadConfig *
// Método para eliminar configuración de gamepad (opcional)
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;
});

View File

@@ -11,18 +11,19 @@
#include "gamepad_config_manager.h" // Para GamepadConfig (ptr only), GamepadConfigs
#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 {
public:
// --- Constantes ---
static constexpr bool ALLOW_REPEAT = true;
static constexpr bool DO_NOT_ALLOW_REPEAT = false;
static constexpr bool ALLOW_REPEAT = true; // Permite repetición
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;
static constexpr bool DO_NOT_CHECK_KEYBOARD = false;
// Alias para mantener compatibilidad con el código existente
using Action = InputAction;
// --- Tipos ---
using Action = InputAction; // Alias para mantener compatibilidad
// --- Estructuras ---
struct KeyState {
@@ -35,12 +36,13 @@ class Input {
};
struct ButtonState {
SDL_GamepadButton button; // GameControllerButton asociado
bool is_held; // Está pulsada ahora mismo
bool just_pressed; // Se acaba de pulsar en este fotograma
bool axis_active; // Estado del eje
int button; // GameControllerButton asociado
bool is_held; // Está pulsada ahora mismo
bool just_pressed; // Se acaba de pulsar en este fotograma
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) {}
};
@@ -102,23 +104,23 @@ class Input {
path(std::string(SDL_GetGamepadPath(pad))),
bindings{
// Movimiento del jugador
{Action::UP, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_UP)},
{Action::DOWN, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_DOWN)},
{Action::LEFT, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_LEFT)},
{Action::RIGHT, ButtonState(SDL_GAMEPAD_BUTTON_DPAD_RIGHT)},
{Action::UP, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_UP))},
{Action::DOWN, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_DOWN))},
{Action::LEFT, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_LEFT))},
{Action::RIGHT, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_DPAD_RIGHT))},
// Disparo del jugador
{Action::FIRE_LEFT, ButtonState(SDL_GAMEPAD_BUTTON_WEST)},
{Action::FIRE_CENTER, ButtonState(SDL_GAMEPAD_BUTTON_NORTH)},
{Action::FIRE_RIGHT, ButtonState(SDL_GAMEPAD_BUTTON_EAST)},
{Action::FIRE_LEFT, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_WEST))},
{Action::FIRE_CENTER, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_NORTH))},
{Action::FIRE_RIGHT, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_EAST))},
// Interfaz
{Action::START, ButtonState(SDL_GAMEPAD_BUTTON_START)},
{Action::SERVICE, ButtonState(SDL_GAMEPAD_BUTTON_BACK)},
{Action::START, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_START))},
{Action::SERVICE, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_BACK))},
// Menu de servicio
{Action::SM_SELECT, ButtonState(SDL_GAMEPAD_BUTTON_WEST)},
{Action::SM_BACK, ButtonState(SDL_GAMEPAD_BUTTON_NORTH)}} {}
{Action::SM_SELECT, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_WEST))},
{Action::SM_BACK, ButtonState(static_cast<int>(SDL_GAMEPAD_BUTTON_NORTH))}} {}
~Gamepad() {
if (pad != nullptr) {
@@ -128,11 +130,12 @@ class Input {
// Reasigna un botón a una acción
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 ---
static void init(const std::string &game_controller_db_path, const std::string &gamepad_configs_file);
@@ -141,18 +144,18 @@ class Input {
// --- Métodos de configuración de controles ---
void bindKey(Action action, SDL_Scancode code);
static void bindGameControllerButton(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, SDL_GamepadButton button);
static void bindGameControllerButton(const std::shared_ptr<Gamepad> &gamepad, Action action_target, Action action_source);
// --- Métodos de consulta de entrada ---
void update();
auto checkAction(Action action, bool repeat = true, bool check_keyboard = true, std::shared_ptr<Gamepad> gamepad = nullptr) -> bool;
auto checkAnyInput(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, const std::shared_ptr<Gamepad> &gamepad = nullptr) -> bool;
auto checkAnyButton(bool repeat = DO_NOT_ALLOW_REPEAT) -> bool;
// --- Métodos de gestión de mandos ---
[[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>;
[[nodiscard]] auto getNumGamepads() const -> int;
auto getGamepad(SDL_JoystickID id) const -> std::shared_ptr<Gamepad>;
@@ -160,7 +163,7 @@ class Input {
auto getGamepads() const -> const Gamepads & { return gamepads_; }
// --- 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 stringToInput(const std::string &name) -> Action;
@@ -178,6 +181,7 @@ class Input {
private:
// --- Constantes ---
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
// --- Variables internas ---
@@ -189,7 +193,8 @@ class Input {
// --- Métodos internos ---
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 removeGamepad(SDL_JoystickID id) -> std::string;
void addGamepadMappingsFromFile();

View File

@@ -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_DOWN, "DPAD_DOWN"},
{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 = {
{"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_DOWN", SDL_GAMEPAD_BUTTON_DPAD_DOWN},
{"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 = {
{InputAction::SM_SELECT, InputAction::FIRE_LEFT},

View File

@@ -5,8 +5,8 @@
#include <string>
#include <unordered_map>
// Acciones de entrada posibles en el juego
enum class InputAction : int {
// --- Enums ---
enum class InputAction : int { // Acciones de entrada posibles en el juego
// Inputs de movimiento
UP,
DOWN,
@@ -47,9 +47,9 @@ enum class InputAction : int {
SIZE,
};
// Mapas para convertir entre enums y strings
extern const std::unordered_map<InputAction, std::string> ACTION_TO_STRING;
extern const std::unordered_map<std::string, InputAction> STRING_TO_ACTION;
extern const std::unordered_map<SDL_GamepadButton, std::string> BUTTON_TO_STRING;
extern const std::unordered_map<std::string, SDL_GamepadButton> STRING_TO_BUTTON;
extern const std::unordered_map<InputAction, InputAction> ACTION_TO_ACTION;
// --- Variables ---
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; // Mapeo de string a acción
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; // Mapeo de string a botón
extern const std::unordered_map<InputAction, InputAction> ACTION_TO_ACTION; // Mapeo de acción a acción

View File

@@ -8,10 +8,8 @@
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)
: sprite_(std::make_unique<AnimatedSprite>(texture, animation)),
type_(type),
play_area_(play_area) {
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)), play_area_(play_area), type_(type) {
switch (type) {
case ItemType::COFFEE_MACHINE: {
width_ = COFFEE_MACHINE_WIDTH;
@@ -29,7 +27,15 @@ Item::Item(ItemType type, float x, float y, SDL_FRect &play_area, std::shared_pt
height_ = param.game.item_size;
pos_x_ = x;
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;
accel_y_ = 0.2F;
collider_.r = width_ / 2;
@@ -82,9 +88,9 @@ void Item::move() {
const float MAX_X = play_area_.w - width_;
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) {
vel_x_ = -vel_x_;
vel_x_ = -vel_x_; // Invierte la velocidad horizontal
}
// Si colisiona por arriba, rebota (excepto la máquina de café)
@@ -92,8 +98,8 @@ void Item::move() {
// Corrige
pos_y_ = param.game.play_area.rect.y;
// Invierte la velocidad
vel_y_ = -vel_y_;
// Fuerza la velocidad hacia abajo para evitar oscilaciones
vel_y_ = std::abs(vel_y_);
}
// Si colisiona con la parte inferior
@@ -181,17 +187,17 @@ auto Item::getCoffeeMachineSpawn(int player_x, int item_width, int area_width, i
// Ambos lados disponibles, elegir aleatoriamente
if (rand() % 2 == 0) {
// Lado izquierdo
return rand() % (exclude_left - LEFT_BOUND) + LEFT_BOUND;
return (rand() % (exclude_left - LEFT_BOUND)) + LEFT_BOUND;
} // Lado derecho
return rand() % (RIGHT_BOUND - exclude_right) + exclude_right;
return (rand() % (RIGHT_BOUND - exclude_right)) + exclude_right;
}
if (can_spawn_left) {
// Solo lado izquierdo disponible
return rand() % (exclude_left - LEFT_BOUND) + LEFT_BOUND;
return (rand() % (exclude_left - LEFT_BOUND)) + LEFT_BOUND;
}
if (can_spawn_right) {
// 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
// Por ahora, intentar spawn en el extremo más lejano posible
int distance_to_left = abs(player_x - LEFT_BOUND);

View File

@@ -11,8 +11,7 @@
class Texture;
// Tipos de objetos disponibles en el juego.
// Define los diferentes tipos de objetos que pueden existir en el juego.
// --- Enums ---
enum class ItemType : int {
DISK = 1, // Disco
GAVINA = 2, // Gavina
@@ -24,81 +23,57 @@ enum class ItemType : int {
NONE = 8, // Ninguno
};
// Clase Item.
// Representa un objeto en el juego, con sus propiedades y métodos para gestionar su comportamiento.
// --- Clase Item: representa un objeto en el juego ---
class Item {
public:
// Constantes
static constexpr int COFFEE_MACHINE_WIDTH = 30;
static constexpr int COFFEE_MACHINE_HEIGHT = 39;
// --- Constantes ---
static constexpr int COFFEE_MACHINE_WIDTH = 30; // Anchura de la máquina de café
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.
Item(ItemType type, float x, float y, SDL_FRect &play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation);
// --- Constructor y destructor ---
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.
~Item() = default;
// --- Métodos principales ---
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.
void alignTo(int x);
// Renderiza el objeto en pantalla si está habilitado.
// Si el tiempo de vida es mayor que 200, renderiza el sprite.
// Si es menor o igual a 200, renderiza el sprite de forma intermitente.
void render();
// Desactiva el objeto estableciendo su estado enabled_ a false.
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_; }
// --- Getters ---
[[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
[[nodiscard]] auto getWidth() const -> int { return width_; } // Obtiene la anchura
[[nodiscard]] auto getHeight() const -> int { return height_; } // Obtiene la altura
[[nodiscard]] auto getType() const -> ItemType { return type_; } // Obtiene el tipo
[[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
auto getCollider() -> Circle & { return collider_; } // Obtiene el colisionador
private:
// Objetos y punteros
// --- Objetos y punteros ---
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_y_; // Posición Y del objeto
int width_; // Ancho del objeto
int height_; // Alto del objeto
float vel_x_; // Velocidad en el eje X
float vel_y_; // Velocidad en el eje Y
float accel_x_ = 0.0F; // Aceleración en el eje X
float accel_y_; // Aceleración en el eje Y
bool floor_collision_ = false; // Indica si el objeto colisiona con el suelo
ItemType type_; // Tipo de 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
int width_; // Ancho del objeto
int height_; // Alto del objeto
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.
// Actualiza las coordenadas X e Y del colisionador.
void shiftColliders();
// Coloca el sprite en la posición del objeto.
// Actualiza las coordenadas X e Y del sprite.
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;
// --- Métodos internos ---
void shiftColliders(); // Alinea el círculo de colisión con la posición del objeto
void shiftSprite(); // Coloca el sprite en la posición del objeto
void move(); // Actualiza la posición y estados del objeto
void updateTimeToLive(); // Actualiza el contador de tiempo de vida
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é
};

View File

@@ -11,6 +11,7 @@
#include "difficulty.h" // Para Difficulty
#include "external/json.hpp" // Para basic_json, iteration_proxy_value, oper...
#include "options.h" // Para SettingsOpt...
#include "resource_helper.h" // Para ResourceHelper
using json = nlohmann::json;
@@ -27,14 +28,24 @@ std::vector<Language> languages = {
auto loadFromFile(const std::string &file_path) -> bool {
texts.clear();
std::ifstream rfile(file_path);
if (!rfile.is_open()) {
return false;
}
// Intentar cargar desde ResourceHelper primero
auto resource_data = ResourceHelper::loadFile(file_path);
try {
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()) {
texts[el.key()] = el.value();

View File

@@ -1,17 +1,18 @@
#pragma once
#include <string> // Para string, basic_string
#include <utility>
#include <string> // Para string, basic_string
#include <utility> // Para move
// --- Namespace Lang: gestión de idiomas y textos ---
namespace Lang {
// --- Códigos de idioma soportados ---
// --- Enums ---
enum class Code : int {
SPANISH = 0,
VALENCIAN = 1,
ENGLISH = 2
SPANISH = 0, // Español
VALENCIAN = 1, // Valenciano
ENGLISH = 2 // Inglés
};
// --- Estructura que representa un idioma ---
// --- Estructuras ---
struct Language {
Code code; // Código que identifica al idioma
std::string name; // Nombre que identifica el idioma
@@ -21,7 +22,7 @@ struct Language {
: 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 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)

View File

@@ -17,5 +17,5 @@ auto main(int argc, char* argv[]) -> int {
auto director = std::make_unique<Director>(argc, std::span<char*>(argv, argc));
// Bucle principal
return director->run();
return Director::run();
}

View File

@@ -36,9 +36,9 @@ auto ManageHiScoreTable::add(const HiScoreEntry &entry) -> int {
sort();
// Encontrar la posición del nuevo elemento
auto it = std::find_if(table_.begin(), table_.end(), [&](const HiScoreEntry &e) { return e.name == entry.name &&
e.score == entry.score &&
e.one_credit_complete == entry.one_credit_complete; });
auto it = std::ranges::find_if(table_, [&](const HiScoreEntry &e) {
return e.name == entry.name && e.score == entry.score && e.one_credit_complete == entry.one_credit_complete;
});
int position = -1;
if (it != table_.end()) {
@@ -66,7 +66,7 @@ void ManageHiScoreTable::sort() {
auto operator()(const HiScoreEntry &a, const HiScoreEntry &b) const -> bool { return a.score > b.score; }
} 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

View File

@@ -3,15 +3,7 @@
#include <string> // Para std::string
#include <vector> // Para std::vector
/*
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 ---
// --- Estructuras ---
struct HiScoreEntry {
std::string name; // Nombre
int score; // Puntuación
@@ -22,7 +14,8 @@ struct HiScoreEntry {
: name(n.substr(0, 6)), score(s), one_credit_complete(occ) {}
};
using Table = std::vector<HiScoreEntry>;
// --- Tipos ---
using Table = std::vector<HiScoreEntry>; // Tabla de puntuaciones
// --- Clase ManageHiScoreTable ---
class ManageHiScoreTable {
@@ -30,10 +23,10 @@ class ManageHiScoreTable {
// --- Constantes ---
static constexpr int NO_ENTRY = -1;
// Constructor y destructor
explicit ManageHiScoreTable(Table &table)
// --- Constructor y destructor ---
explicit ManageHiScoreTable(Table &table) // Constructor con referencia a tabla
: table_(table) {}
~ManageHiScoreTable() = default;
~ManageHiScoreTable() = default; // Destructor
// --- Métodos públicos ---
void clear(); // Resetea la tabla a los valores por defecto

View File

@@ -2,13 +2,14 @@
#include <SDL3/SDL.h> // Para Uint32, SDL_Event
// --- Namespace Mouse: gestión del ratón ---
namespace Mouse {
// --- Variables de estado del cursor ---
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 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 updateCursorVisibility(); // Actualiza la visibilidad del cursor según la inactividad
} // namespace Mouse

View File

@@ -1,32 +1,32 @@
#include "moving_sprite.h"
#include <utility>
#include "texture.h" // Para Texture
// Constructor
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos, Rotate rotate, float zoom_w, float zoom_h, SDL_FlipMode flip)
: Sprite(texture, pos),
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture, SDL_FRect pos, Rotate rotate, float horizontal_zoom, float vertical_zoom, SDL_FlipMode flip)
: Sprite(std::move(texture), pos),
rotate_(rotate),
flip_(flip),
x_(pos.x),
y_(pos.y),
rotate_(rotate),
horizontal_zoom_(zoom_w),
vertical_zoom_(zoom_h),
flip_(flip) {}
horizontal_zoom_(horizontal_zoom),
vertical_zoom_(vertical_zoom) {}
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),
y_(pos.y),
horizontal_zoom_(1.0F),
vertical_zoom_(1.0F),
flip_(SDL_FLIP_NONE) {}
vertical_zoom_(1.0F) {}
MovingSprite::MovingSprite(std::shared_ptr<Texture> texture)
: Sprite(texture),
: Sprite(std::move(texture)),
flip_(SDL_FLIP_NONE),
horizontal_zoom_(1.0F),
vertical_zoom_(1.0F),
flip_(SDL_FLIP_NONE) { Sprite::clear(); }
vertical_zoom_(1.0F) { Sprite::clear(); }
// Reinicia todas las variables
void MovingSprite::clear() {

View File

@@ -9,23 +9,21 @@
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 {
public:
// --- Estructura para la rotación ---
// --- Estructuras ---
struct Rotate {
bool enabled{false}; // Indica si ha de rotar
int counter{0}; // Contador
int speed{1}; // Velocidad de giro
double angle{0.0}; // Ángulo para dibujarlo
float amount{0.0F}; // Cantidad de grados a girar en cada iteración
SDL_FPoint center; // Centro de rotación
Rotate() : center({0.0F, 0.0F}) {}
bool enabled{false}; // Indica si ha de rotar
int counter{0}; // Contador
int speed{1}; // Velocidad de giro
double angle{0.0}; // Ángulo para dibujarlo
float amount{0.0F}; // Cantidad de grados a girar en cada iteración
SDL_FPoint center{.x = 0.0F, .y = 0.0F}; // Centro de rotación
};
// --- 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);
explicit MovingSprite(std::shared_ptr<Texture> texture);
~MovingSprite() override = default;
@@ -36,58 +34,48 @@ class MovingSprite : public Sprite {
void stop(); // Elimina el movimiento del sprite
void render() override; // Muestra el sprite por pantalla
// --- Getters de posición y movimiento ---
[[nodiscard]] auto getPosX() const -> float { return x_; }
[[nodiscard]] auto getPosY() const -> float { return y_; }
[[nodiscard]] auto getVelX() const -> float { return vx_; }
[[nodiscard]] auto getVelY() const -> float { return vy_; }
[[nodiscard]] auto getAccelX() const -> float { return ax_; }
[[nodiscard]] auto getAccelY() const -> float { return ay_; }
// --- Configuración ---
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
void setVelX(float value) { vx_ = value; } // Establece la velocidad X
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 ---
void setVelX(float value) { vx_ = value; }
void setVelY(float value) { vy_ = value; }
void setAccelX(float value) { ax_ = value; }
void setAccelY(float value) { ay_ = value; }
// --- Rotación ---
[[nodiscard]] auto isRotating() const -> bool { return rotate_.enabled; }
void setHorizontalZoom(float value) { horizontal_zoom_ = value; }
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
// --- Getters ---
[[nodiscard]] auto getPosX() const -> float { return x_; } // Obtiene la posición X
[[nodiscard]] auto getPosY() const -> float { return y_; } // Obtiene la posición Y
[[nodiscard]] auto getVelX() const -> float { return vx_; } // Obtiene la velocidad X
[[nodiscard]] auto getVelY() const -> float { return vy_; } // Obtiene la velocidad Y
[[nodiscard]] auto getAccelX() const -> float { return ax_; } // Obtiene la aceleración X
[[nodiscard]] auto getAccelY() const -> float { return ay_; } // Obtiene la aceleración Y
[[nodiscard]] auto isRotating() const -> bool { return rotate_.enabled; } // Verifica si está rotando
auto getFlip() -> SDL_FlipMode { return flip_; } // Obtiene el flip
protected:
// --- Variables de posición y movimiento ---
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 ---
// --- Variables de estado ---
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 vertical_zoom_; // Zoom aplicado a la altura
SDL_FlipMode flip_; // Indica cómo se voltea el sprite
// --- Métodos internos ---
void updateAngle() { rotate_.angle += rotate_.amount; } // Incrementa el valor del ángulo

View File

@@ -7,6 +7,7 @@
#include <fstream> // Para basic_ostream, operator<<, basic_ostream::operator<<, basic_ofstream, basic_istream, basic_ifstream, ifstream, ofstream
#include <functional> // Para function
#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 <string> // Para char_traits, stoi, operator==, operator<<, allocator, string, basic_string, operator<=>, getline
#include <utility> // Para swap, pair
@@ -65,7 +66,7 @@ auto loadFromFile() -> bool {
std::string line;
while (std::getline(file, line)) {
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()))) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Unknown parameter: %s", line.substr(0, pos).c_str());
}
@@ -101,14 +102,11 @@ auto saveToFile() -> bool {
// Opciones de ventana
file << "## WINDOW\n";
file << "\n";
file << "window.zoom=" << window.zoom << "\n";
// Opciones de video
file << "## VIDEO\n";
file << "\n## VIDEO\n";
file << "## video.scale_mode [" << static_cast<int>(SDL_ScaleMode::SDL_SCALEMODE_NEAREST) << ": nearest, " << static_cast<int>(SDL_ScaleMode::SDL_SCALEMODE_LINEAR) << ": lineal]\n";
file << "\n";
file << "video.fullscreen=" << boolToString(video.fullscreen) << "\n";
file << "video.scale_mode=" << static_cast<int>(video.scale_mode) << "\n";
@@ -117,9 +115,8 @@ auto saveToFile() -> bool {
file << "video.shaders=" << boolToString(video.shaders) << "\n";
// Opciones de audio
file << "\n\n## AUDIO\n";
file << "\n## AUDIO\n";
file << "## volume [0 .. 100]\n";
file << "\n";
file << "audio.enabled=" << boolToString(audio.enabled) << "\n";
file << "audio.volume=" << audio.volume << "\n";
@@ -129,22 +126,22 @@ auto saveToFile() -> bool {
file << "audio.sound.volume=" << audio.sound.volume << "\n";
// Opciones del juego
file << "\n\n## GAME\n";
file << "\n## GAME\n";
file << "## game.language [0: spanish, 1: valencian, 2: english]\n";
file << "## game.difficulty [" << static_cast<int>(Difficulty::Code::EASY) << ": easy, " << static_cast<int>(Difficulty::Code::NORMAL) << ": normal, " << static_cast<int>(Difficulty::Code::HARD) << ": hard]\n";
file << "\n";
file << "game.language=" << static_cast<int>(settings.language) << "\n";
file << "game.difficulty=" << static_cast<int>(settings.difficulty) << "\n";
file << "game.autofire=" << boolToString(settings.autofire) << "\n";
file << "game.shutdown_enabled=" << boolToString(settings.shutdown_enabled) << "\n";
file << "game.params_file=" << settings.params_file << "\n";
// Opciones de mandos
file << "\n\n## CONTROLLERS\n";
file << "\n## CONTROLLERS\n";
gamepad_manager.saveToFile(file);
// Opciones de teclado
file << "\n\n## KEYBOARD\n";
file << "\n## KEYBOARD\n";
file << "keyboard.player=" << static_cast<int>(keyboard.player_id) << "\n";
// Cierra el fichero
@@ -212,6 +209,7 @@ auto set(const std::string& var, const std::string& value) -> bool {
}},
{"game.autofire", [](const auto& val) { settings.autofire = stringToBool(val); }},
{"game.shutdown_enabled", [](const auto& val) { settings.shutdown_enabled = stringToBool(val); }},
{"game.params_file", [](const auto& val) { settings.params_file = val; }},
// Teclado
{"keyboard.player", [](const auto& val) { keyboard.player_id = static_cast<Player::Id>(stoi(val)); }}};
@@ -397,12 +395,10 @@ void GamepadManager::clearUnassignedGamepadSlots() {
auto GamepadManager::isGamepadAssigned(
const std::shared_ptr<Input::Gamepad>& physical_gamepad,
const std::vector<std::shared_ptr<Input::Gamepad>>& assigned_instances) -> bool {
for (const auto& assigned : assigned_instances) {
if (assigned == physical_gamepad) {
return true; // Encontrado, por lo tanto, ya está asignado.
}
}
return false; // No se encontró en la lista.
return std::ranges::any_of(assigned_instances,
[&physical_gamepad](const auto& assigned) {
return assigned == physical_gamepad;
});
}
// Convierte un player id a texto segun Lang
@@ -418,7 +414,7 @@ auto playerIdToString(Player::Id player_id) -> std::string {
}
// 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")) {
return Player::Id::PLAYER1;
}

View File

@@ -11,83 +11,62 @@
#include <stdexcept> // Para out_of_range, invalid_argument
#include <string> // Para char_traits, string, allocator, operator==, swap, operator<<, basic_string, stoi
#include <string_view> // Para string_view
#include <utility> // Para swap
#include <vector> // Para vector
#include "defaults.h" // Para GameDefaults
#include "difficulty.h" // Para Code
#include "input.h" // Para Input
#include "lang.h" // Para Code
#include "manage_hiscore_table.h" // Para ManageHiScoreTable, Table
#include "player.h" // Para Player
// --- Namespace Options: gestión de configuración y opciones del juego ---
namespace Options {
// --- Opciones de ventana ---
// --- Estructuras ---
struct Window {
std::string 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 max_zoom{2}; // 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") {}
std::string caption = GameDefaults::Options::WINDOW_CAPTION; // Texto que aparece en la barra de título de la ventana
int zoom = GameDefaults::Options::WINDOW_ZOOM; // Valor por el que se multiplica el tamaño de la ventana
int max_zoom = GameDefaults::Options::WINDOW_MAX_ZOOM; // Tamaño máximo para que la ventana no sea mayor que la pantalla
};
// --- Opciones de vídeo ---
struct Video {
SDL_ScaleMode scale_mode{SDL_ScaleMode::SDL_SCALEMODE_NEAREST}; // Filtro usado para el escalado de la imagen
bool fullscreen{false}; // Indica si se usa pantalla completa
bool vsync{true}; // Indica si se usa vsync
bool integer_scale{true}; // Indica si se usa escalado entero
bool shaders{false}; // Indica si se usan shaders para los filtros de vídeo
std::string info; // Información sobre el modo de vídeo
// Constructor por defecto con valores iniciales
Video() = default;
SDL_ScaleMode scale_mode = GameDefaults::Options::VIDEO_SCALE_MODE; // Filtro usado para el escalado de la imagen
bool fullscreen = GameDefaults::Options::VIDEO_FULLSCREEN; // Indica si se usa pantalla completa
bool vsync = GameDefaults::Options::VIDEO_VSYNC; // Indica si se usa vsync
bool integer_scale = GameDefaults::Options::VIDEO_INTEGER_SCALE; // Indica si se usa escalado entero
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
};
// --- Opciones de música ---
struct Music {
bool enabled{true}; // Indica si la música suena o no
int volume{100}; // Volumen de la música
// Constructor por defecto
Music() = default;
bool enabled = GameDefaults::Options::MUSIC_ENABLED; // Indica si la música suena o no
int volume = GameDefaults::Options::MUSIC_VOLUME; // Volumen de la música
};
// --- Opciones de sonido ---
struct Sound {
bool enabled{true}; // Indica si los sonidos suenan o no
int volume{100}; // Volumen de los sonidos
// Constructor por defecto
Sound() = default;
bool enabled = GameDefaults::Options::SOUND_ENABLED; // Indica si los sonidos suenan o no
int volume = GameDefaults::Options::SOUND_VOLUME; // Volumen de los sonidos
};
// --- Opciones de audio ---
struct Audio {
Music music; // Opciones para la música
Sound sound; // Opciones para los efectos de sonido
bool enabled{true}; // Indica si el audio está activo o no
int volume{100}; // Volumen general del audio
// Constructor por defecto
Audio() = default;
Music music; // Opciones para la música
Sound sound; // Opciones para los efectos de sonido
bool enabled = GameDefaults::Options::AUDIO_ENABLED; // Indica si el audio está activo o no
int volume = GameDefaults::Options::AUDIO_VOLUME; // Volumen general del audio
};
// --- Opciones de configuración ---
struct Settings {
Difficulty::Code difficulty{Difficulty::Code::NORMAL}; // Dificultad del juego
Lang::Code language{Lang::Code::VALENCIAN}; // Idioma usado en el juego
bool autofire{true}; // Indicador de autofire
bool shutdown_enabled{false}; // Especifica si se puede apagar el sistema
Table hi_score_table; // Tabla de mejores puntuaciones
std::vector<int> glowing_entries; // Ú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 controllers_file; // Ruta al fichero con las configuraciones de los mandos
// Constructor por defecto con valores iniciales
Settings()
: glowing_entries({ManageHiScoreTable::NO_ENTRY, ManageHiScoreTable::NO_ENTRY}) {}
Difficulty::Code difficulty = Difficulty::Code::NORMAL; // Dificultad del juego
Lang::Code language = Lang::Code::VALENCIAN; // Idioma usado en el juego
bool autofire = GameDefaults::Options::SETTINGS_AUTOFIRE; // Indicador de autofire
bool shutdown_enabled = GameDefaults::Options::SETTINGS_SHUTDOWN_ENABLED; // Especifica si se puede apagar el sistema
Table hi_score_table; // Tabla de mejores puntuaciones
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 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
// Reinicia las últimas entradas de puntuación
void clearLastHiScoreEntries() {
@@ -96,7 +75,6 @@ struct Settings {
}
};
// --- Estructura para gamepad individual ---
struct Gamepad {
std::shared_ptr<Input::Gamepad> instance = nullptr; // Referencia al mando
std::string name; // Nombre del mando
@@ -107,7 +85,7 @@ struct Gamepad {
: player_id(custom_player_id) {}
};
// --- Manager para los gamepads ---
// --- Clases ---
class GamepadManager {
public:
void init() {
@@ -144,7 +122,7 @@ class GamepadManager {
const std::string& name) -> bool {
try {
auto& gamepad = getGamepad(player_id);
gamepad.instance = instance;
gamepad.instance = std::move(instance);
gamepad.name = name;
return true;
} catch (const std::exception&) {
@@ -161,7 +139,7 @@ class GamepadManager {
}
void resyncGamepadsWithPlayers() {
for (auto player : players_) {
for (const auto& player : players_) {
switch (player->getId()) {
case Player::Id::PLAYER1:
player->setGamepad(gamepads_[0].instance);
@@ -226,11 +204,11 @@ class GamepadManager {
return false;
}
void addPlayer(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 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
// 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.
@@ -279,8 +257,8 @@ struct Keyboard {
Player::Id player_id = Player::Id::PLAYER1; // Jugador asociado al teclado
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 clearPlayers() { players.clear(); } // Limpia la lista de jugadores
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
// Asigna el teclado a un jugador
void assignTo(Player::Id player_id) {
@@ -291,17 +269,13 @@ struct Keyboard {
}
};
// --- Opciones pendientes de aplicar ---
struct PendingChanges {
Lang::Code new_language{Lang::Code::VALENCIAN}; // Idioma 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
// Constructor por defecto con valores iniciales
PendingChanges() = default;
Lang::Code new_language = Lang::Code::VALENCIAN; // Idioma 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
};
// --- Variables globales ---
// --- Variables ---
extern Window window; // Opciones de la ventana
extern Settings settings; // Opciones del juego
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 PendingChanges pending_changes; // Opciones que se aplican al cerrar
// --- Funciones de configuración ---
// --- Funciones ---
void init(); // Inicializa las opciones del programa
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
@@ -321,7 +295,7 @@ void swapKeyboard();
void swapControllers(); // Intercambia los jugadores asignados a los dos primeros mandos
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 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 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

View File

@@ -10,93 +10,42 @@
#include <unordered_map>
#include "color.h"
#include "ui/notifier.h" // Para Notifier::Position
#include "utils.h"
// Variable global - ahora se inicializa automáticamente con valores por defecto
Param param;
// Calcula variables a partir de otras variables
void precalculateZones();
// Asigna variables a partir de dos cadenas
// Declaraciones de funciones privadas
namespace {
auto setParams(const std::string& var, const std::string& value) -> bool;
}
// Establece valores por defecto a las variables
void initParam() {
// GAME
param.game.width = 320;
param.game.height = 256;
param.game.item_size = 20;
param.game.game_area.rect = {0, 0, param.game.width, param.game.height};
param.game.play_area.rect = {0, 0, param.game.width, 216};
param.game.name_entry_idle_time = 10;
param.game.name_entry_total_time = 60;
param.game.speed = 15;
param.game.hit_stop = true;
param.game.hit_stop_ms = 300;
precalculateZones();
// Implementación del método privado de Param
void Param::precalculateZones() {
// playArea - cálculos basados en el rectángulo actual
game.play_area.center_x = game.play_area.rect.w / 2;
game.play_area.first_quarter_x = game.play_area.rect.w / 4;
game.play_area.third_quarter_x = game.play_area.rect.w / 4 * 3;
game.play_area.center_y = game.play_area.rect.h / 2;
game.play_area.first_quarter_y = game.play_area.rect.h / 4;
game.play_area.third_quarter_y = game.play_area.rect.h / 4 * 3;
// SCOREBOARD
param.scoreboard.rect = {0, 216, param.game.width, 40};
param.scoreboard.separator_autocolor = false;
param.scoreboard.separator_color = Color();
param.scoreboard.easy_color = Color();
param.scoreboard.normal_color = Color();
param.scoreboard.hard_color = Color();
param.scoreboard.text_autocolor = false;
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;
// gameArea - cálculos basados en width y height actuales
game.game_area.rect = {.x = 0, .y = 0, .w = game.width, .h = game.height};
game.game_area.center_x = game.game_area.rect.w / 2;
game.game_area.first_quarter_x = game.game_area.rect.w / 4;
game.game_area.third_quarter_x = game.game_area.rect.w / 4 * 3;
game.game_area.center_y = game.game_area.rect.h / 2;
game.game_area.first_quarter_y = game.game_area.rect.h / 4;
game.game_area.third_quarter_y = game.game_area.rect.h / 4 * 3;
}
// Carga los parámetros desde un archivo
void loadParamsFromFile(const std::string& file_path) {
// Inicializa los parámetros con valores por defecto
initParam();
// Los parámetros ya están inicializados con valores por defecto
// Solo necesitamos abrir el archivo y sobrescribir los valores que aparezcan
// Abre el archivo
std::ifstream file(file_path);
if (!file.is_open()) {
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());
std::string line;
std::string param1;
std::string param2;
std::string param_name;
std::string param_value;
while (std::getline(file, line)) {
// Elimina comentarios
auto comment_pos = line.find('#');
@@ -117,21 +67,23 @@ void loadParamsFromFile(const std::string& file_path) {
// Usa un stream para separar palabras
std::istringstream iss(line);
if (iss >> param1 >> param2) {
if (!setParams(param1, param2)) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Parámetro desconocido: %s", param1.c_str());
if (iss >> param_name >> param_value) {
if (!setParams(param_name, param_value)) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Parámetro desconocido: %s", param_name.c_str());
}
}
}
// Cierra el archivo
file.close();
// Realiza cálculos adicionales después de cargar los parámetros
precalculateZones();
// Recalcula las zonas después de cargar todos los parámetros
param.precalculateZones();
}
// Implementación local de setParams
namespace {
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 = {
{"game.width", [](const std::string& v) { param.game.width = 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); }},
{"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.random_squares_delay", [](const std::string& v) { param.fade.random_squares_delay = std::stoi(v); }},
{"fade.random_squares_mult", [](const std::string& v) { param.fade.random_squares_mult = std::stoi(v); }},
{"fade.post_duration", [](const std::string& v) { param.fade.post_duration = std::stoi(v); }},
{"fade.random_squares_duration_ms", [](const std::string& v) { param.fade.random_squares_duration_ms = std::stoi(v); }},
{"fade.post_duration_ms", [](const std::string& v) { param.fade.post_duration_ms = 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.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.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.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.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); }},
{"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 = {
{"game.hit_stop", [](const std::string& v) { param.game.hit_stop = stringToBool(v); }},
@@ -197,15 +179,65 @@ 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].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].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 = {
{"balloon.color[0]", [](const std::string& v) { param.balloon.color.at(0) = v; }},
{"balloon.color[1]", [](const std::string& v) { param.balloon.color.at(1) = v; }},
{"balloon.color[2]", [](const std::string& v) { param.balloon.color.at(2) = v; }},
{"balloon.color[3]", [](const std::string& v) { param.balloon.color.at(3) = v; }}};
{"balloon.color[0]", [validateBalloonColor](const std::string& v) {
if (!validateBalloonColor(v)) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'blue' por defecto.", v.c_str());
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 it = param_map.find(var);
if (it != param_map.end()) {
@@ -215,6 +247,7 @@ auto setParams(const std::string& var, const std::string& value) -> bool {
return false;
};
// Intentar con todos los mapas
if (try_map(INT_PARAMS) || try_map(COLOR_PARAMS) || try_map(BOOL_PARAMS) ||
try_map(FLOAT_PARAMS) || try_map(STRING_PARAMS)) {
return true;
@@ -223,39 +256,20 @@ auto setParams(const std::string& var, const std::string& value) -> bool {
// Casos especiales que necesitan lógica personalizada
if (var == "notification.pos_h") {
if (value == "LEFT") {
param.notification.pos_h = NotifyPosition::LEFT;
param.notification.pos_h = Notifier::Position::LEFT;
} else if (value == "MIDDLE") {
param.notification.pos_h = NotifyPosition::MIDDLE;
param.notification.pos_h = Notifier::Position::MIDDLE;
} else {
param.notification.pos_h = NotifyPosition::RIGHT;
param.notification.pos_h = Notifier::Position::RIGHT;
}
return true;
}
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 false; // Parámetro no encontrado
}
// 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;
}
} // namespace

View File

@@ -5,134 +5,251 @@
#include <array> // Para array
#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"
// --- Parámetros del juego ---
struct ParamGame {
float width; // Ancho de la resolución nativa del juego
float height; // Alto de la resolución nativa del juego
float item_size; // Tamaño de los ítems del juego
Zone play_area; // Rectángulo con la posición de la zona de juego
Zone game_area; // Rectángulo con las dimensiones del juego
int name_entry_idle_time; // Segundos para introducir el nombre al finalizar la partida si no se pulsa nada
int name_entry_total_time; // Segundos totales para introducir el nombre al finalizar la partida
Uint32 speed; // Velocidad a la que transcurre el juego
bool hit_stop; // Indica si debe haber un paro cuando el jugador es golpeado por un globo
Uint32 hit_stop_ms; // Cantidad de milisegundos que dura el hit_stop
float width = GameDefaults::Game::WIDTH;
float height = GameDefaults::Game::HEIGHT;
float item_size = GameDefaults::Game::ITEM_SIZE;
Zone play_area{}; // Se inicializa en el constructor de Param
Zone game_area{}; // Se inicializa en el constructor de Param
int name_entry_idle_time = GameDefaults::Game::NAME_ENTRY_IDLE_TIME;
int name_entry_total_time = GameDefaults::Game::NAME_ENTRY_TOTAL_TIME;
Uint32 speed = 15; // Este valor no estaba en el archivo de configuración
bool hit_stop = GameDefaults::Game::HIT_STOP;
Uint32 hit_stop_ms = GameDefaults::Game::HIT_STOP_MS;
Color item_text_outline_color;
};
// --- Parámetros del fade ---
struct ParamFade {
Color color; // Color del fade
float num_squares_width; // Cantidad total de cuadraditos en horizontal para el FadeType::RANDOM_SQUARE
float num_squares_height; // Cantidad total de cuadraditos en vertical para el FadeType::RANDOM_SQUARE
int random_squares_delay; // Duración entre cada pintado de cuadrados
int random_squares_mult; // Cantidad de cuadrados que se pintarán cada vez
int post_duration; // Duración final del fade
float venetian_size; // Altura de los rectángulos para FadeType::VENETIAN
Color color = Color::fromHex(GameDefaults::Fade::COLOR);
float num_squares_width = GameDefaults::Fade::NUM_SQUARES_WIDTH;
float num_squares_height = GameDefaults::Fade::NUM_SQUARES_HEIGHT;
int random_squares_duration_ms = GameDefaults::Fade::RANDOM_SQUARES_DURATION_MS;
int post_duration_ms = GameDefaults::Fade::POST_DURATION_MS;
float venetian_size = GameDefaults::Fade::VENETIAN_SIZE;
};
// --- Parámetros de la pantalla de título ---
struct ParamTitle {
int press_start_position; // Posición del texto para empezar a jugar
int title_duration; // Tiempo de inactividad del título
int arcade_edition_position; // Posición del bitmap "Arcade Edition"
int title_c_c_position; // Posición del bitmap "Coffee Crisis"
Color bg_color; // Color para los tiles de fondo
int press_start_position = GameDefaults::Title::PRESS_START_POSITION;
int title_duration = GameDefaults::Title::DURATION;
int arcade_edition_position = GameDefaults::Title::ARCADE_EDITION_POSITION;
int title_c_c_position = GameDefaults::Title::TITLE_C_C_POSITION;
Color bg_color = Color::fromHex(GameDefaults::Title::BG_COLOR);
};
// --- Parámetros del fondo ---
struct ParamBackground {
Color attenuate_color; // Color para atenuar el fondo
Color attenuate_color = Color::fromHex(GameDefaults::Background::ATTENUATE_COLOR);
};
// --- Parámetros de los globos ---
struct ParamBalloon {
struct Settings {
float grav; // Aceleración en el eje Y. Modifica la velocidad
float vel; // Velocidad inicial al rebotar contra el suelo
float grav;
float vel;
// Constructor
explicit Settings(float grav_val = 0.0F, float vel_val = 0.0F)
// Constructor por defecto
constexpr Settings(float grav_val = 0.0F, float vel_val = 0.0F)
: grav(grav_val), vel(vel_val) {}
};
std::array<Settings, 4> settings;
std::array<std::string, 4> color;
bool bouncing_sound; // Indica si los globos hacer sonido al rebotar
// Inicialización con los valores por defecto desde GameDefaults
std::array<Settings, 4> settings = {{Settings(GameDefaults::Balloon::SETTINGS[0].grav, GameDefaults::Balloon::SETTINGS[0].vel),
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 ---
struct ParamNotification {
NotifyPosition pos_h; // Ubicación horizontal de las notificaciones en pantalla
NotifyPosition pos_v; // Ubicación vertical de las notificaciones en pantalla
bool sound; // Indica si las notificaciones suenan
Color color; // Color de las notificaciones
Notifier::Position pos_h = GameDefaults::Notification::POS_H;
Notifier::Position pos_v = GameDefaults::Notification::POS_V;
bool sound = GameDefaults::Notification::SOUND;
Color color = Color::fromHex(GameDefaults::Notification::COLOR);
};
// --- Parámetros del marcador ---
struct ParamScoreboard {
SDL_FRect rect; // Posición y tamaño del marcador
bool separator_autocolor; // El separado establece su color de forma automatica
Color separator_color; // Color del separador si se pone de forma manual
Color easy_color; // Color del marcador segun la dificultad
Color normal_color; // Color del marcador segun la dificultad
Color hard_color; // Color del marcador segun la dificultad
bool text_autocolor; // El texto establece su color de forma automatica
Color text_color1; // Color del texto
Color text_color2; // Color del texto
int skip_countdown_value; // Valor a partir del cual se puede saltar la cuenta atras
SDL_FRect rect = {
GameDefaults::Scoreboard::RECT_X,
GameDefaults::Scoreboard::RECT_Y,
GameDefaults::Scoreboard::RECT_W,
GameDefaults::Scoreboard::RECT_H};
bool separator_autocolor = GameDefaults::Scoreboard::SEPARATOR_AUTOCOLOR;
Color separator_color = Color::fromHex(GameDefaults::Scoreboard::SEPARATOR_COLOR);
Color easy_color = Color::fromHex(GameDefaults::Scoreboard::EASY_COLOR);
Color normal_color = Color::fromHex(GameDefaults::Scoreboard::NORMAL_COLOR);
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 ---
struct ParamServiceMenu {
Color title_color;
Color text_color;
Color selected_color;
Color bg_color;
bool drop_shadow;
Color title_color = Color::fromHex(GameDefaults::ServiceMenu::TITLE_COLOR);
Color text_color = Color::fromHex(GameDefaults::ServiceMenu::TEXT_COLOR);
Color selected_color = Color::fromHex(GameDefaults::ServiceMenu::SELECTED_COLOR);
Color bg_color = Color::fromHex(GameDefaults::ServiceMenu::BG_COLOR);
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 ---
struct ParamIntro {
Color bg_color;
Color card_color;
Color shadow_color;
int text_distance_from_bottom;
Color bg_color = Color::fromHex(GameDefaults::Intro::BG_COLOR);
Color card_color = Color::fromHex(GameDefaults::Intro::CARD_COLOR);
Color shadow_color = Color::fromHex(GameDefaults::Intro::SHADOW_COLOR);
int text_distance_from_bottom = GameDefaults::Intro::TEXT_DISTANCE_FROM_BOTTOM;
};
// --- Parámetros para Debug ---
struct ParamDebug {
Color color;
Color color = Color::fromHex(GameDefaults::Debug::COLOR);
};
// --- Parámetros para Resource ---
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 {
ParamGame game; // Parámetros del juego
ParamFade fade; // Parámetros del fade
ParamScoreboard scoreboard; // Rectángulo del marcador
ParamTitle title; // Parámetros de la pantalla de título
ParamBackground background; // Parámetros del fondo
ParamBalloon balloon; // Parámetros de los globos
ParamNotification notification; // Parámetros de las notificaciones
ParamServiceMenu service_menu; // Parámetros del menú de servicio
ParamIntro intro; // Parámetros de la intro
ParamDebug debug; // Parámetros para Debug
ParamResource resource; // Parámetros para Resource
ParamGame game;
ParamFade fade;
ParamScoreboard scoreboard;
ParamTitle title;
ParamBackground background;
ParamBalloon balloon;
ParamNotification notification;
ParamServiceMenu service_menu;
ParamIntro intro;
ParamDebug debug;
ParamResource resource;
ParamTabe tabe;
ParamPlayer player;
// Constructor
Param()
: game(), fade(), scoreboard(), title(), background(), balloon(), notification(), service_menu(), intro(), debug(), resource() {}
// Constructor que inicializa las zonas que dependen de otros valores
Param() {
// 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 ---
extern Param param;
// --- Variables ---
extern Param param; // Variable global con los parámetros del juego
// --- Funciones globales ---
void loadParamsFromFile(const std::string &file_path); // Establece valores para los parámetros a partir de un fichero de texto
// --- Funciones ---
void loadParamsFromFile(const std::string& file_path); // Carga parámetros desde archivo

View File

@@ -11,7 +11,7 @@ auto createPath(float start, float end, PathType type, float fixed_pos, int step
for (int i = 0; i < steps; ++i) {
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)) {
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) {
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) {
spot.x = X;
}
@@ -64,7 +64,7 @@ void PathSprite::addPath(Path path, bool centered) {
break;
}
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) {
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
void PathSprite::addPath(std::vector<SDL_FPoint> spots, int waiting_counter) {
paths_.emplace_back(std::move(spots), waiting_counter);
void PathSprite::addPath(const std::vector<SDL_FPoint> &spots, int waiting_counter) {
paths_.emplace_back(spots, waiting_counter);
}
// Habilita el objeto

View File

@@ -4,27 +4,27 @@
#include <functional> // Para std::function
#include <memory> // Para shared_ptr
#include <vector> // Para vector
#include <utility>
#include <vector> // Para vector
#include "sprite.h" // Para Sprite
class Texture;
// --- Tipos de recorrido ---
enum class PathType {
// --- Enums ---
enum class PathType { // Tipos de recorrido
VERTICAL,
HORIZONTAL,
};
// --- Centrado del recorrido ---
enum class PathCentered {
enum class PathCentered { // Centrado del recorrido
ON_X,
ON_Y,
NONE,
};
// --- Estructura Path: define un recorrido para el sprite ---
struct Path {
// --- Estructuras ---
struct Path { // Define un recorrido para 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
bool on_destination = false; // Indica si ha llegado al destino
@@ -36,15 +36,15 @@ struct Path {
: spots(spots_init), waiting_counter(waiting_counter_init) {}
};
// Devuelve un vector con los puntos que conforman la ruta
auto createPath(float start, float end, PathType type, float fixed_pos, int steps, const std::function<double(double)> &easing_function) -> std::vector<SDL_FPoint>;
// --- 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>; // Devuelve un vector con los puntos que conforman la ruta
// --- Clase PathSprite: Sprite que sigue uno o varios recorridos ---
class PathSprite : public Sprite {
public:
// --- Constructor y destructor ---
explicit PathSprite(std::shared_ptr<Texture> texture)
: Sprite(texture) {}
: Sprite(std::move(texture)) {}
~PathSprite() override = default;
// --- Métodos principales ---
@@ -53,7 +53,7 @@ class PathSprite : public Sprite {
// --- Gestión de recorridos ---
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
// --- Estado y control ---

View File

@@ -5,18 +5,18 @@
#include <string>
#include <utility>
// Clase dedicada para manejar el sistema de pausa
// --- Clase PauseManager: maneja el sistema de pausa del juego ---
class PauseManager {
public:
// Enum encapsulado dentro de la clase
enum class Source : uint8_t {
// --- Enums ---
enum class Source : uint8_t { // Fuentes de pausa
NONE = 0,
PLAYER = 1 << 0, // 0001
SERVICE_MENU = 1 << 1, // 0010
FOCUS_LOST = 1 << 2 // 0100
};
// Operadores para trabajar con las banderas (funciones friend)
// --- Operadores friend ---
friend auto operator|(Source a, Source b) -> Source {
return static_cast<Source>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
}
@@ -42,27 +42,12 @@ class PauseManager {
return a = a & b;
}
private:
Source flags_ = Source::NONE;
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)
// --- Constructor y destructor ---
explicit PauseManager(std::function<void(bool)> callback = nullptr) // Constructor con callback opcional
: on_pause_changed_callback_(std::move(callback)) {}
// Establece/quita una fuente de pausa específica
void setFlag(Source source, bool enable) {
// --- Métodos principales ---
void setFlag(Source source, bool enable) { // Establece/quita una fuente de pausa específica
bool was_paused = isPaused();
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 setServiceMenuPause(bool enable) { setFlag(Source::SERVICE_MENU, enable); }
void setFocusLossPause(bool enable) { setFlag(Source::FOCUS_LOST, enable); }
// Toggle para el jugador (más común)
void togglePlayerPause() { setPlayerPause(!isPlayerPaused()); }
void togglePlayerPause() { setPlayerPause(!isPlayerPaused()); } // Toggle para el jugador (más común)
// Getters
// --- Getters ---
[[nodiscard]] auto isPaused() const -> bool { return flags_ != Source::NONE; }
[[nodiscard]] auto isPlayerPaused() const -> bool { return hasFlag(Source::PLAYER); }
[[nodiscard]] auto isServiceMenuPaused() const -> bool { return hasFlag(Source::SERVICE_MENU); }
[[nodiscard]] auto isFocusLossPaused() const -> bool { return hasFlag(Source::FOCUS_LOST); }
// Obtiene las banderas actuales
[[nodiscard]] auto getFlags() const -> Source { return flags_; }
[[nodiscard]] auto getFlags() const -> Source { return flags_; } // Obtiene las banderas actuales
// Limpia todas las pausas (útil para reset)
void clearAll() {
// --- Métodos de utilidad ---
void clearAll() { // Limpia todas las pausas (útil para reset)
if (isPaused()) {
flags_ = Source::NONE;
notifyPauseChanged();
}
}
// Método para debug
[[nodiscard]] auto getStatusString() const -> std::string {
[[nodiscard]] auto getStatusString() const -> std::string { // Método para debug
if (flags_ == Source::NONE) {
return "Active";
}
@@ -133,9 +114,22 @@ class PauseManager {
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
void setCallback(std::function<void(bool)> callback) {
on_pause_changed_callback_ = callback;
private:
// --- Variables ---
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());
}
}
};

View File

@@ -14,6 +14,7 @@
#include "param.h" // Para Param, ParamGame, param
#include "scoreboard.h" // Para Scoreboard
#include "stage.h" // Para power_can_be_added
#include "stage_interface.h" // Para IStageInfo
#include "texture.h" // Para Texture
#ifdef _DEBUG
#include <iostream>
@@ -21,16 +22,7 @@
// Constructor
Player::Player(const Config &config)
: player_sprite_(std::make_unique<AnimatedSprite>(config.texture.at(0), config.animations.at(0))),
power_sprite_(std::make_unique<AnimatedSprite>(config.texture.at(4), config.animations.at(1))),
enter_name_(std::make_unique<EnterName>()),
hi_score_table_(config.hi_score_table),
glowing_entry_(config.glowing_entry),
play_area_(*config.play_area),
id_(config.id),
default_pos_x_(config.x),
default_pos_y_(config.y),
demo_(config.demo) {
: player_sprite_(std::make_unique<AnimatedSprite>(config.texture.at(0), config.animations.at(0))), power_sprite_(std::make_unique<AnimatedSprite>(config.texture.at(4), config.animations.at(1))), enter_name_(std::make_unique<EnterName>()), hi_score_table_(config.hi_score_table), glowing_entry_(config.glowing_entry), stage_info_(config.stage_info), play_area_(*config.play_area), id_(config.id), default_pos_x_(config.x), default_pos_y_(config.y), demo_(config.demo) {
// Configura objetos
player_sprite_->addTexture(config.texture.at(1));
player_sprite_->addTexture(config.texture.at(2));
@@ -73,9 +65,6 @@ void Player::init() {
// Establece la posición del sprite
player_sprite_->clear();
shiftSprite();
// Selecciona un frame para pintar
// player_sprite_->setCurrentAnimation("stand");
}
// Actua en consecuencia de la entrada recibida
@@ -179,6 +168,9 @@ void Player::move() {
case State::WAITING:
handleWaitingMovement();
break;
case State::RECOVER:
handleRecoverMovement();
break;
default:
break;
}
@@ -196,6 +188,11 @@ void Player::handlePlayingMovement() {
shiftSprite();
}
void Player::handleRecoverMovement() {
if (player_sprite_->getCurrentAnimationFrame() == 10) { playSound("voice_recover.wav"); }
if (player_sprite_->animationIsCompleted()) { setPlayingState(State::RESPAWNING); }
}
void Player::handleRollingMovement() {
handleRollingBoundaryCollision();
handleRollingGroundCollision();
@@ -218,8 +215,6 @@ void Player::handleRollingGroundCollision() {
return;
}
// const float VEL_Y = player_sprite_->getVelY();
// if (VEL_Y >= 0.0F && VEL_Y < 2.0F) {
if (player_sprite_->getVelY() < 2.0F) {
handleRollingStop();
} else {
@@ -463,6 +458,9 @@ void Player::setAnimation() {
player_sprite_->setFlip(flipMode);
break;
}
case State::RECOVER:
player_sprite_->setCurrentAnimation("recover");
break;
case State::WAITING:
case State::GAME_OVER:
player_sprite_->setCurrentAnimation("hello");
@@ -588,10 +586,10 @@ void Player::update() {
}
// Incrementa la puntuación del jugador
void Player::addScore(int score, int last_hi_score_entry) {
void Player::addScore(int score, int lowest_hi_score_entry) {
if (isPlaying()) {
score_ += score;
qualifies_for_high_score_ = score_ > last_hi_score_entry;
qualifies_for_high_score_ = score_ > lowest_hi_score_entry;
}
}
@@ -625,6 +623,9 @@ void Player::setPlayingState(State state) {
playing_state_ = state;
switch (playing_state_) {
case State::RECOVER: {
break;
}
case State::RESPAWNING: {
playSound("voice_thankyou.wav");
setPlayingState(State::PLAYING);
@@ -635,7 +636,7 @@ void Player::setPlayingState(State state) {
init();
setInvulnerable(true);
setScoreboardMode(Scoreboard::Mode::SCORE);
Stage::power_can_be_added = true;
stage_info_->enablePowerCollection();
break;
}
case State::CONTINUE: {
@@ -690,7 +691,7 @@ void Player::setPlayingState(State state) {
case State::TITLE_ANIMATION: {
// Activa la animación de rodar
player_sprite_->setCurrentAnimation("walk");
playSound("voice_thankyou.wav");
playSound("voice_credit_thankyou.wav");
break;
}
case State::TITLE_HIDDEN: {
@@ -777,15 +778,30 @@ void Player::setInvulnerable(bool value) {
// Monitoriza el estado
void Player::updateInvulnerable() {
if (playing_state_ == State::PLAYING) {
if (invulnerable_) {
if (invulnerable_counter_ > 0) {
--invulnerable_counter_;
invulnerable_counter_ % 8 > 3 ? player_sprite_->setActiveTexture(coffees_) : player_sprite_->setActiveTexture(3);
} else {
setInvulnerable(false);
player_sprite_->setActiveTexture(coffees_);
if (playing_state_ == State::PLAYING && invulnerable_) {
if (invulnerable_counter_ > 0) {
--invulnerable_counter_;
// Frecuencia fija de parpadeo (como el original)
constexpr int blink_speed = 8;
// 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_);
}
}
}
@@ -929,7 +945,6 @@ void Player::playSound(const std::string &name) const {
// Indica si se puede dibujar el objeto
auto Player::isRenderable() const -> bool {
// return !isGameOver() && !isTitleHidden();
return !isTitleHidden();
};
@@ -947,4 +962,9 @@ void Player::addScoreToScoreBoard() const {
}
manager->saveToFile(Asset::get()->get("score.bin"));
}
void Player::addCredit() {
++credits_used_;
playSound("credit.wav");
}

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