Compare commits
47 Commits
2025-08-10
...
2025-08-17
| Author | SHA1 | Date | |
|---|---|---|---|
| 2819b3628e | |||
| 1e9e664012 | |||
| 0c8b39cee7 | |||
| d7b3af5ab8 | |||
| 5e5227305f | |||
| 3fc15a9512 | |||
| e774e0e8ad | |||
| a95776e6c7 | |||
| 0428ff26d5 | |||
| fc3e2deb1f | |||
| 65ca17f938 | |||
| ff2a51a507 | |||
| fe0083abd4 | |||
| 1c058694fd | |||
| cb0c3266d5 | |||
| 8ddc5d94f1 | |||
| b359a73d50 | |||
| 142603db71 | |||
| 1ec272f017 | |||
| 327987447d | |||
| ada5025c65 | |||
| 1ced698093 | |||
| 2a4c47a6ca | |||
| 6102504d32 | |||
| a123b3aa93 | |||
| 81d486f2d3 | |||
| 0c10898bdc | |||
| a3cd404545 | |||
| 5c708fc60a | |||
| 960ee367df | |||
| a7519fc372 | |||
| a983269080 | |||
| 3964503f1c | |||
| 8fcb7d1eb5 | |||
| 3e68afa4be | |||
| ca6edcccc0 | |||
| a388005968 | |||
| ea7628259a | |||
| a13e024934 | |||
| 4cc5102d70 | |||
| b2139d8e06 | |||
| ea3e704d34 | |||
| d5ab5748a7 | |||
| e950eb335d | |||
| e667063767 | |||
| 3534e4cc54 | |||
| 685b04c840 |
@@ -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
|
||||
|
||||
15
.clang-tidy
@@ -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
|
||||
|
||||
171
Makefile
@@ -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
|
||||
@@ -120,20 +135,24 @@ 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}
|
||||
@@ -149,23 +168,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
|
||||
@@ -202,6 +225,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 +238,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)"
|
||||
|
||||
@@ -245,18 +273,117 @@ 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 data "$(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)"
|
||||
|
||||
@@ -275,11 +402,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
|
||||
|
||||
@@ -294,6 +423,32 @@ anbernic:
|
||||
|
||||
# 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
|
||||
@@ -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,36 @@ DATA|${SYSTEM_FOLDER}/controllers.json|optional,absolute
|
||||
DATA|${SYSTEM_FOLDER}/score.bin|optional,absolute
|
||||
|
||||
# Archivos de configuración del juego
|
||||
DATA|${PREFIX}/data/config/formations.txt
|
||||
DATA|${PREFIX}/data/config/gamecontrollerdb.txt
|
||||
DATA|${PREFIX}/data/config/param_320x240.txt
|
||||
DATA|${PREFIX}/data/config/param_320x256.txt
|
||||
DATA|${PREFIX}/data/config/param_red.txt
|
||||
DATA|${PREFIX}/data/config/pools.txt
|
||||
DATA|${PREFIX}/data/config/stages.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
|
||||
|
||||
# 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 +58,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 +121,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
|
||||
@@ -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
|
||||
|
||||
@@ -1,26 +1,29 @@
|
||||
## --- 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
|
||||
# Coffee Crisis Arcade Edition - Fichero de parametros
|
||||
# Formato: PARAMETRO VALOR
|
||||
|
||||
## --- 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)
|
||||
# --- 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
|
||||
|
||||
## --- SCOREBOARD ---
|
||||
# --- 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
|
||||
@@ -35,17 +38,17 @@ scoreboard.text_color1 FFFFFF # Color principal del texto del marcad
|
||||
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 ---
|
||||
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 ---
|
||||
background.attenuate_color FFFFFF00 # Color de atenuación del fondo (RGBA hexadecimal)
|
||||
|
||||
## --- BALLOONS ---
|
||||
# --- 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
|
||||
@@ -62,28 +65,87 @@ balloon.color[3] green # Color del globo que rebota
|
||||
|
||||
balloon.bouncing_sound false # Indica si los globos hacer sonido al rebotar
|
||||
|
||||
## --- NOTIFICATION ---
|
||||
# --- 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 ---
|
||||
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.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.bg_color 000F00F5 # Color de fondo del menú de servicio (RGBA hexadecimal)
|
||||
service_menu.drop_shadow false # ¿El menú de servicio tiene sombra?
|
||||
|
||||
## --- INTRO ---
|
||||
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 ---
|
||||
debug.color 00FFFF # Color para elementos de depuración
|
||||
|
||||
## --- RESOURCE ---
|
||||
# --- RESOURCE ---
|
||||
resource.color FFFFFF # Color de recurso 1
|
||||
resource.color FFFFFF # Color de recurso 2
|
||||
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
|
||||
@@ -1,26 +1,29 @@
|
||||
## --- 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
|
||||
# Coffee Crisis Arcade Edition - Fichero de parametros
|
||||
# Formato: PARAMETRO VALOR
|
||||
|
||||
## --- 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)
|
||||
# --- 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
|
||||
|
||||
## --- SCOREBOARD ---
|
||||
# --- 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
|
||||
@@ -35,17 +38,17 @@ scoreboard.text_color1 FFFFFF # Color principal del texto del marcad
|
||||
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 ---
|
||||
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 ---
|
||||
background.attenuate_color FFFFFF00 # Color de atenuación del fondo (RGBA hexadecimal)
|
||||
|
||||
## --- BALLOONS ---
|
||||
# --- 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
|
||||
@@ -62,28 +65,86 @@ balloon.color[3] green # Color del globo que rebota
|
||||
|
||||
balloon.bouncing_sound false # Indica si los globos hacer sonido al rebotar
|
||||
|
||||
## --- NOTIFICATION ---
|
||||
# --- 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 ---
|
||||
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
|
||||
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)
|
||||
|
||||
## --- DEBUG ---
|
||||
# --- 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 recurso 1
|
||||
resource.color FFFFFF # Color de recurso 2
|
||||
# --- 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
data/config/param_red.txt
Normal file
@@ -0,0 +1,150 @@
|
||||
# Coffee Crisis Arcade Edition - Fichero de parametros - RED THEME
|
||||
# Formato: PARAMETRO VALOR
|
||||
|
||||
# --- GAME ---
|
||||
game.item_size 20 # Tamaño de los items del juego (en píxeles)
|
||||
game.item_text_outline_color FFB8B8F0 # Color del outline del texto de los items (RGBA hex) - Rojo claro
|
||||
game.width 320 # Ancho de la resolución nativa del juego (en píxeles)
|
||||
game.height 256 # Alto de la resolución nativa del juego (en píxeles)
|
||||
game.play_area.rect.x 0 # Posición X de la zona jugable
|
||||
game.play_area.rect.y 0 # Posición Y de la zona jugable
|
||||
game.play_area.rect.w 320 # Ancho de la zona jugable
|
||||
game.play_area.rect.h 216 # Alto de la zona jugable
|
||||
game.name_entry_idle_time 10 # Segundos para introducir el nombre al finalizar la partida si no se pulsa nada
|
||||
game.name_entry_total_time 60 # Segundos totales para introducir el nombre al finalizar la partida
|
||||
game.hit_stop false # Indica si debe haber un paro cuando el jugador es golpeado por un globo
|
||||
game.hit_stop_ms 500 # Cantidad de milisegundos que dura el hit_stop
|
||||
|
||||
# --- FADE ---
|
||||
fade.color 5C1F1F # Color hexadecimal para el efecto de fundido - Rojo oscuro
|
||||
fade.num_squares_width 64 # Número de cuadrados en el eje X para el fundido
|
||||
fade.num_squares_height 48 # Número de cuadrados en el eje Y para el fundido
|
||||
fade.random_squares_duration_ms 1200 # Duración del fade en milisegundos
|
||||
fade.post_duration_ms 500 # Duración tras el fundido en milisegundos
|
||||
fade.venetian_size 12 # Tamaño de las bandas para el efecto veneciano (en píxeles)
|
||||
|
||||
# --- SCOREBOARD ---
|
||||
scoreboard.rect.x 0 # Posición X del marcador
|
||||
scoreboard.rect.y 216 # Posición Y del marcador
|
||||
scoreboard.rect.w 320 # Ancho del marcador
|
||||
scoreboard.rect.h 40 # Alto del marcador
|
||||
scoreboard.separator_autocolor true # ¿El separador usa color automático?
|
||||
scoreboard.separator_color 2B0D0D # Color del separador - Rojo muy oscuro
|
||||
scoreboard.easy_color 8B4A2F # Color para la dificultad fácil - Marrón rojizo
|
||||
scoreboard.normal_color 6B2F2F # Color para la dificultad normal - Rojo medio
|
||||
scoreboard.hard_color A73030 # Color para la dificultad difícil - Rojo fuerte
|
||||
scoreboard.text_autocolor true # ¿El texto usa color automático?
|
||||
scoreboard.text_color1 FFE6E6 # Color principal del texto del marcador - Blanco rosado
|
||||
scoreboard.text_color2 FFE6E6 # Color secundario del texto del marcador - Blanco rosado
|
||||
scoreboard.skip_countdown_value 8 # Valor para saltar la cuenta atrás (segundos)
|
||||
|
||||
# --- TITLE ---
|
||||
title.press_start_position 180 # Posición Y del texto "Press Start"
|
||||
title.title_duration 800 # Duración de la pantalla de título (frames)
|
||||
title.arcade_edition_position 123 # Posición Y del subtítulo "Arcade Edition"
|
||||
title.title_c_c_position 80 # Posición Y del título principal
|
||||
title.bg_color 8B4A3A # Color de fondo en la sección titulo - Marrón rojizo
|
||||
|
||||
# --- BACKGROUND ---
|
||||
background.attenuate_color FF4A3A40 # Color de atenuación del fondo (RGBA hexadecimal) - Blanco rosado
|
||||
|
||||
# --- BALLOONS ---
|
||||
balloon.settings[0].vel 2.75f # Velocidad inicial del globo 1
|
||||
balloon.settings[0].grav 0.09f # Gravedad aplicada al globo 1
|
||||
balloon.settings[1].vel 3.70f # Velocidad inicial del globo 2
|
||||
balloon.settings[1].grav 0.10f # Gravedad aplicada al globo 2
|
||||
balloon.settings[2].vel 4.70f # Velocidad inicial del globo 3
|
||||
balloon.settings[2].grav 0.10f # Gravedad aplicada al globo 3
|
||||
balloon.settings[3].vel 5.45f # Velocidad inicial del globo 4
|
||||
balloon.settings[3].grav 0.10f # Gravedad aplicada al globo 4
|
||||
|
||||
balloon.color[0] orange # Color de creación del globo normal
|
||||
balloon.color[1] red # Color del globo normal
|
||||
balloon.color[2] blue # Color de creación del globo que rebota
|
||||
balloon.color[3] green # Color del globo que rebota
|
||||
|
||||
balloon.bouncing_sound false # Indica si los globos hacer sonido al rebotar
|
||||
|
||||
# --- NOTIFICATION ---
|
||||
notification.pos_v TOP # Posición vertical de la notificación (TOP/BOTTOM)
|
||||
notification.pos_h LEFT # Posición horizontal de la notificación (LEFT/RIGHT)
|
||||
notification.sound false # ¿La notificación reproduce sonido?
|
||||
notification.color 4D1A1A # Color de fondo de la notificación - Rojo oscuro
|
||||
|
||||
# --- SERVICE MENU ---
|
||||
service_menu.title_color FF9966 # Color del título del menú de servicio - Naranja claro
|
||||
service_menu.text_color FFE6E6 # Color del texto del menú de servicio - Blanco rosado
|
||||
service_menu.selected_color FFB366 # Color de la opción seleccionada - Naranja dorado
|
||||
service_menu.bg_color 331A0AF5 # Color de fondo del menú de servicio - Marrón rojizo oscuro con alpha
|
||||
service_menu.drop_shadow false # ¿El menú de servicio tiene sombra?
|
||||
|
||||
service_menu.window_message.bg_color 4D1A1AF0 # Color de fondo de ventanas - Rojo oscuro con alpha
|
||||
service_menu.window_message.border_color CC6633FF # Color del borde de ventanas - Naranja rojizo
|
||||
service_menu.window_message.title_color CC6633FF # Color del título en ventanas - Naranja rojizo
|
||||
service_menu.window_message.text_color FFE6E6FF # Color del texto en ventanas - Blanco rosado
|
||||
service_menu.window_message.padding 15.0f # Espaciado interno de ventanas de mensaje (píxeles)
|
||||
service_menu.window_message.line_spacing 5.0f # Espaciado entre líneas de texto (píxeles)
|
||||
service_menu.window_message.title_separator_spacing 20.0f # Espaciado entre título y contenido (píxeles)
|
||||
service_menu.window_message.min_width 200.0f # Ancho mínimo de ventanas de mensaje (píxeles)
|
||||
service_menu.window_message.min_height 32.0f # Alto mínimo de ventanas de mensaje (píxeles)
|
||||
service_menu.window_message.max_width_ratio 0.8f # Ratio máximo de ancho respecto a pantalla (0.0-1.0)
|
||||
service_menu.window_message.max_height_ratio 0.8f # Ratio máximo de alto respecto a pantalla (0.0-1.0)
|
||||
service_menu.window_message.text_safety_margin 15.0f # Margen de seguridad para el texto (píxeles)
|
||||
service_menu.window_message.animation_duration 0.3f # Duración de animaciones de ventanas (segundos)
|
||||
|
||||
# --- INTRO ---
|
||||
intro.bg_color B8664D # Color de fondo de la intro - Naranja tierra
|
||||
intro.card_color FFE6CC # Color de las tarjetas en la intro - Crema rojizo
|
||||
intro.shadow_color 66000080 # Color de la sombra de las tarjetas - Rojo muy oscuro con alpha
|
||||
intro.text_distance_from_bottom 48 # Posición del texto desde la parte inferior
|
||||
|
||||
# --- DEBUG ---
|
||||
debug.color FF6666 # Color para elementos de depuración - Rojo claro
|
||||
|
||||
# --- RESOURCE ---
|
||||
resource.color FFE6E6 # Color de recursos - Blanco rosado
|
||||
|
||||
# --- TABE ---
|
||||
tabe.min_spawn_time 2.0f # Tiempo mínimo en segundos para que aparezca el Tabe
|
||||
tabe.max_spawn_time 3.0f # Tiempo máximo en segundos para que aparezca el Tabe
|
||||
|
||||
# --- PLAYER ---
|
||||
# Jugador 1 - Camiseta por defecto (tonos rojos)
|
||||
player.default_shirt[0].darkest B33030FF # Tono más oscuro - Rojo fuerte
|
||||
player.default_shirt[0].dark CC4040FF # Tono oscuro - Rojo medio
|
||||
player.default_shirt[0].base E65050FF # Tono principal - Rojo claro
|
||||
player.default_shirt[0].light FF6666FF # Tono claro - Rojo muy claro
|
||||
|
||||
# Jugador 2 - Camiseta por defecto (tonos naranjas)
|
||||
player.default_shirt[1].darkest B36030FF # Tono más oscuro - Naranja oscuro
|
||||
player.default_shirt[1].dark CC7540FF # Tono oscuro - Naranja medio
|
||||
player.default_shirt[1].base E68A50FF # Tono principal - Naranja claro
|
||||
player.default_shirt[1].light FF9966FF # Tono claro - Naranja muy claro
|
||||
|
||||
# Jugador 1 - Camiseta con 1 café (tonos rojizos más intensos)
|
||||
player.one_coffee_shirt[0].darkest 8B2635FF # Tono más oscuro - Rojo granate
|
||||
player.one_coffee_shirt[0].dark A53040FF # Tono oscuro - Rojo granate claro
|
||||
player.one_coffee_shirt[0].base BF3A50FF # Tono principal - Rojo vibrante
|
||||
player.one_coffee_shirt[0].light D94460FF # Tono claro - Rojo vibrante claro
|
||||
|
||||
# Jugador 1 - Camiseta con 2 cafés (tonos naranja dorado)
|
||||
player.two_coffee_shirt[0].darkest CC6600FF # Tono más oscuro - Naranja dorado oscuro
|
||||
player.two_coffee_shirt[0].dark E6750AFF # Tono oscuro - Naranja dorado
|
||||
player.two_coffee_shirt[0].base FF8514FF # Tono principal - Naranja dorado claro
|
||||
player.two_coffee_shirt[0].light FF991EFF # Tono claro - Naranja dorado muy claro
|
||||
|
||||
# Jugador 2 - Camiseta con 1 café (tonos terracotas)
|
||||
player.one_coffee_shirt[1].darkest A0472DFF # Tono más oscuro - Terracota oscuro
|
||||
player.one_coffee_shirt[1].dark B8553AFF # Tono oscuro - Terracota medio
|
||||
player.one_coffee_shirt[1].base D06347FF # Tono principal - Terracota claro
|
||||
player.one_coffee_shirt[1].light E87154FF # Tono claro - Terracota muy claro
|
||||
|
||||
# Jugador 2 - Camiseta con 2 cafés (tonos naranjas cálidos)
|
||||
player.two_coffee_shirt[1].darkest CC5500FF # Tono más oscuro - Naranja intenso
|
||||
player.two_coffee_shirt[1].dark E66600FF # Tono oscuro - Naranja fuerte
|
||||
player.two_coffee_shirt[1].base FF7700FF # Tono principal - Naranja brillante
|
||||
player.two_coffee_shirt[1].light FF8800FF # Tono claro - Naranja muy brillante
|
||||
|
||||
# Colores de contorno de los jugadores
|
||||
player.outline_color[0] 994D33FF # Color del contorno del Jugador 1 - Marrón rojizo
|
||||
player.outline_color[1] 664433FF # Color del contorno del Jugador 2 - Marrón tierra
|
||||
@@ -1,4 +1,4 @@
|
||||
# Archivo de configuración de pools de formaciones de globos
|
||||
# Coffee Crisis Arcade Edition - Archivo de configuración de pools de formaciones de globos
|
||||
# Formato: POOL: <id> FORMATIONS: <id1>, <id2>, <id3>, ...
|
||||
# Los IDs de formación pueden repetirse
|
||||
# Los pools no necesitan estar ordenados ni ser consecutivos
|
||||
|
||||
19
data/config/stages.txt
Normal 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
|
||||
BIN
data/font/04b_25_white.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
@@ -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]
|
||||
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 16 KiB |
@@ -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",
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
|
||||
@@ -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
BIN
data/sound/voice_credit_thankyou.wav
Normal file
BIN
data/sound/voice_recover.wav
Normal file
BIN
define_buttons.o
Normal file
15
linux_utils/generate_compile_commands_json.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 🏁 Ruta base del proyecto
|
||||
BASE_DIR="/home/sergio/gitea/coffee_crisis_arcade_edition"
|
||||
|
||||
# 📁 Ruta al build
|
||||
BUILD_DIR="$BASE_DIR/build"
|
||||
|
||||
# 📄 Archivo de mapping personalizado
|
||||
MAPPING_FILE="$BASE_DIR/linux_utils/sdl3_mapping.imp"
|
||||
|
||||
# 📦 Generar compile_commands.json
|
||||
echo "🔧 Generando compile_commands.json..."
|
||||
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -S "$BASE_DIR" -B "$BUILD_DIR"
|
||||
|
||||
44
linux_utils/run_clang-tidy.sh
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script para ejecutar clang-tidy en múltiples directorios
|
||||
# Uso: ./run_clang-tidy.sh
|
||||
|
||||
# Lista de rutas donde ejecutar clang-tidy
|
||||
PATHS=(
|
||||
"/home/sergio/gitea/coffee_crisis_arcade_edition/source"
|
||||
"/home/sergio/gitea/coffee_crisis_arcade_edition/source/sections"
|
||||
"/home/sergio/gitea/coffee_crisis_arcade_edition/source/ui"
|
||||
)
|
||||
|
||||
# Ruta del directorio build (relativa desde donde se ejecuta el script)
|
||||
BUILD_DIR="/home/sergio/gitea/coffee_crisis_arcade_edition/build/"
|
||||
|
||||
# Función para procesar un directorio
|
||||
process_directory() {
|
||||
local dir="$1"
|
||||
|
||||
echo "=== Procesando directorio: $dir ==="
|
||||
|
||||
# Verificar que el directorio existe
|
||||
if [[ ! -d "$dir" ]]; then
|
||||
echo "Error: El directorio $dir no existe"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Cambiar al directorio y ejecutar find con -maxdepth 1 para un solo nivel
|
||||
cd "$dir" || return 1
|
||||
|
||||
# Buscar archivos .cpp, .h, .hpp solo en el nivel actual (no subdirectorios)
|
||||
find . -maxdepth 1 \( -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \) | \
|
||||
xargs -P4 -I{} bash -c 'echo "Procesando: {}"; clang-tidy {} -p '"$BUILD_DIR"' --fix'
|
||||
|
||||
echo "=== Completado: $dir ==="
|
||||
echo
|
||||
}
|
||||
|
||||
# Procesar cada directorio en la lista
|
||||
for path in "${PATHS[@]}"; do
|
||||
process_directory "$path"
|
||||
done
|
||||
|
||||
echo "¡Proceso completado para todos los directorios!"
|
||||
150
release/create_icons.py
Normal 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()
|
||||
BIN
release/icon.ico
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 128 KiB |
BIN
release/icon.png
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 438 KiB |
@@ -35,7 +35,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 +45,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 +101,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 +176,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 +230,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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -92,7 +92,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
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
#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
|
||||
|
||||
// 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 ---
|
||||
@@ -38,9 +38,9 @@ class Asset {
|
||||
[[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 +49,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
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
132
source/color.cpp
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>& {
|
||||
|
||||
@@ -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
|
||||
@@ -124,9 +124,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);
|
||||
}
|
||||
@@ -188,7 +188,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 +321,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';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ namespace Lang {
|
||||
enum class Code : int;
|
||||
}
|
||||
|
||||
// --- Clase Director: gestor principal de la aplicación ---
|
||||
class Director {
|
||||
public:
|
||||
// --- Constructor y destructor ---
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
};
|
||||
483
source/fade.cpp
@@ -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) {
|
||||
|
||||
111
source/fade.h
@@ -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
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
65
source/hit.h
@@ -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
|
||||
};
|
||||
|
||||
105
source/input.cpp
@@ -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;
|
||||
});
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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é
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
114
source/options.h
@@ -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
|
||||
|
||||
248
source/param.cpp
@@ -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
|
||||
267
source/param.h
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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 ---
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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");
|
||||
}
|
||||
101
source/player.h
@@ -12,6 +12,7 @@
|
||||
#include "input.h" // Para Input
|
||||
#include "manage_hiscore_table.h" // Para Table
|
||||
#include "scoreboard.h" // Para Scoreboard
|
||||
#include "stage_interface.h" // Para IStageInfo
|
||||
#include "utils.h" // Para Circle
|
||||
|
||||
class Texture;
|
||||
@@ -23,15 +24,14 @@ class Player {
|
||||
static constexpr int WIDTH = 32; // Anchura
|
||||
static constexpr int HEIGHT = 32; // Altura
|
||||
|
||||
// --- Id para los jugadores ---
|
||||
// --- Enums ---
|
||||
enum class Id : int {
|
||||
NO_PLAYER = -1,
|
||||
BOTH_PLAYERS = 0,
|
||||
PLAYER1 = 1,
|
||||
PLAYER2 = 2
|
||||
NO_PLAYER = -1, // Sin jugador
|
||||
BOTH_PLAYERS = 0, // Ambos jugadores
|
||||
PLAYER1 = 1, // Jugador 1
|
||||
PLAYER2 = 2 // Jugador 2
|
||||
};
|
||||
|
||||
// --- Estados posibles del jugador ---
|
||||
enum class State {
|
||||
// Estados de movimiento
|
||||
WALKING_LEFT, // Caminando hacia la izquierda
|
||||
@@ -71,19 +71,22 @@ class Player {
|
||||
CREDITS, // Estado para mostrar los créditos del juego
|
||||
TITLE_ANIMATION, // Animacion para el titulo
|
||||
TITLE_HIDDEN, // Animacion para el titulo
|
||||
RESPAWNING, // Tras continuar y volver al juego
|
||||
RECOVER, // Al aceptar continuar
|
||||
RESPAWNING, // Tras continuar y dar las gracias, otorga inmunidad y vuelve al juego
|
||||
};
|
||||
|
||||
// --- Estructuras ---
|
||||
struct Config {
|
||||
Id id;
|
||||
float x;
|
||||
int y;
|
||||
bool demo;
|
||||
SDL_FRect *play_area; // Usamos puntero para mantener la referencia
|
||||
std::vector<std::shared_ptr<Texture>> texture;
|
||||
std::vector<std::vector<std::string>> animations;
|
||||
Table *hi_score_table; // También como puntero para referencia
|
||||
int *glowing_entry; // Puntero para mantener la referencia
|
||||
Id id; // Identificador del jugador
|
||||
float x; // Posición X inicial
|
||||
int y; // Posición Y inicial
|
||||
bool demo; // Modo demo
|
||||
SDL_FRect *play_area; // Área de juego (puntero para mantener referencia)
|
||||
std::vector<std::shared_ptr<Texture>> texture; // Texturas del jugador
|
||||
std::vector<std::vector<std::string>> animations; // Animaciones del jugador
|
||||
Table *hi_score_table; // Tabla de puntuaciones (puntero para referencia)
|
||||
int *glowing_entry; // Entrada brillante (puntero para mantener referencia)
|
||||
IStageInfo *stage_info; // Gestor de pantallas (puntero)
|
||||
};
|
||||
|
||||
// --- Constructor y destructor ---
|
||||
@@ -111,9 +114,9 @@ class Player {
|
||||
void updateCooldown(); // Actualiza el cooldown de disparo
|
||||
|
||||
// --- Puntuación y marcador ---
|
||||
void addScore(int score, int last_hi_score_entry); // Añade puntos
|
||||
void incScoreMultiplier(); // Incrementa el multiplicador
|
||||
void decScoreMultiplier(); // Decrementa el multiplicador
|
||||
void addScore(int score, int lowest_hi_score_entry); // Añade puntos
|
||||
void incScoreMultiplier(); // Incrementa el multiplicador
|
||||
void decScoreMultiplier(); // Decrementa el multiplicador
|
||||
|
||||
// --- Estados de juego ---
|
||||
void setPlayingState(State state); // Cambia el estado de juego
|
||||
@@ -181,21 +184,22 @@ class Player {
|
||||
void setScoreBoardPanel(Scoreboard::Id panel) { scoreboard_panel_ = panel; }
|
||||
void setScoreMultiplier(float value) { score_multiplier_ = value; }
|
||||
void setWalkingState(State state) { walking_state_ = state; }
|
||||
void addCredit() { ++credits_used_; }
|
||||
|
||||
void setGamepad(std::shared_ptr<Input::Gamepad> gamepad) { gamepad_ = gamepad; }
|
||||
void addCredit();
|
||||
void setGamepad(std::shared_ptr<Input::Gamepad> gamepad) { gamepad_ = std::move(gamepad); }
|
||||
[[nodiscard]] auto getGamepad() const -> std::shared_ptr<Input::Gamepad> { return gamepad_; }
|
||||
void setUsesKeyboard(bool value) { uses_keyboard_ = value; }
|
||||
[[nodiscard]] auto getUsesKeyboard() const -> bool { return uses_keyboard_; }
|
||||
|
||||
private:
|
||||
// --- Constantes ---
|
||||
static constexpr int POWERUP_COUNTER = 1500; // Duración del estado PowerUp
|
||||
static constexpr int INVULNERABLE_COUNTER = 200; // Duración del estado invulnerable
|
||||
static constexpr float BASE_SPEED = 1.5F; // Velocidad base del jugador
|
||||
static constexpr int COOLING_DURATION = 50;
|
||||
static constexpr int COOLING_COMPLETE = 0;
|
||||
static constexpr int WAITING_COUNTER = 1000;
|
||||
static constexpr int POWERUP_COUNTER = 1500; // Duración del estado PowerUp
|
||||
static constexpr int INVULNERABLE_COUNTER = 200; // Duración del estado invulnerable
|
||||
static constexpr size_t INVULNERABLE_TEXTURE = 3; // Textura usada durante invulnerabilidad
|
||||
static constexpr float BASE_SPEED = 1.5F; // Velocidad base del jugador
|
||||
static constexpr int COOLING_DURATION = 50; // Duración del enfriamiento tras disparar
|
||||
static constexpr int COOLING_COMPLETE = 0; // Valor que indica enfriamiento completado
|
||||
static constexpr int WAITING_COUNTER = 1000; // Tiempo de espera en estado de espera
|
||||
|
||||
// --- Objetos y punteros ---
|
||||
std::unique_ptr<AnimatedSprite> player_sprite_; // Sprite para dibujar el jugador
|
||||
@@ -204,25 +208,26 @@ class Player {
|
||||
std::shared_ptr<Input::Gamepad> gamepad_ = nullptr; // Dispositivo asociado
|
||||
Table *hi_score_table_ = nullptr; // Tabla de máximas puntuaciones
|
||||
int *glowing_entry_ = nullptr; // Entrada de la tabla de puntuaciones para hacerla brillar
|
||||
std::string name_; // Nombre del jugador
|
||||
std::string last_enter_name_; // Último nombre introducido en la tabla de puntuaciones
|
||||
IStageInfo *stage_info_; // Informacion de la pantalla actual
|
||||
|
||||
// --- Estructuras y enums ---
|
||||
// --- Variables de estado ---
|
||||
SDL_FRect play_area_; // Rectángulo con la zona de juego
|
||||
Circle collider_ = Circle(0, 0, 9); // Círculo de colisión del jugador
|
||||
std::string name_; // Nombre del jugador
|
||||
std::string last_enter_name_; // Último nombre introducido en la tabla de puntuaciones
|
||||
Scoreboard::Id scoreboard_panel_ = Scoreboard::Id::LEFT; // Panel del marcador asociado al jugador
|
||||
Id id_; // Identificador para el jugador
|
||||
State walking_state_ = State::WALKING_STOP; // Estado del jugador al moverse
|
||||
State firing_state_ = State::FIRING_NONE; // Estado del jugador al disparar
|
||||
State playing_state_ = State::WAITING; // Estado del jugador en el juego
|
||||
|
||||
// --- Variables float ---
|
||||
float pos_x_ = 0.0F; // Posición en el eje X
|
||||
float default_pos_x_; // Posición inicial para el jugador
|
||||
float vel_x_ = 0.0F; // Cantidad de píxeles a desplazarse en el eje X
|
||||
float score_multiplier_ = 1.0F; // Multiplicador de puntos
|
||||
|
||||
// --- Variables int ---
|
||||
Uint32 continue_ticks_ = 0; // Variable para poder cambiar el contador de continue en función del tiempo
|
||||
Uint32 name_entry_ticks_ = 0; // Variable para poder cambiar el contador de poner nombre en función del tiempo
|
||||
Uint32 showing_name_ticks_ = 0; // Tiempo en el que se entra al estado SHOWING_NAME
|
||||
float pos_x_ = 0.0F; // Posición en el eje X
|
||||
float default_pos_x_; // Posición inicial para el jugador
|
||||
float vel_x_ = 0.0F; // Cantidad de píxeles a desplazarse en el eje X
|
||||
float score_multiplier_ = 1.0F; // Multiplicador de puntos
|
||||
int pos_y_ = 0; // Posición en el eje Y
|
||||
int default_pos_y_; // Posición inicial para el jugador
|
||||
int vel_y_ = 0; // Cantidad de píxeles a desplazarse en el eje Y
|
||||
@@ -242,20 +247,13 @@ class Player {
|
||||
int step_counter_ = 0; // Cuenta los pasos para los estados en los que camina automáticamente
|
||||
int credits_used_ = 0; // Indica el número de veces que ha continuado
|
||||
int waiting_counter_ = 0; // Contador para el estado de espera
|
||||
|
||||
// --- Variables Uint32 ---
|
||||
Uint32 continue_ticks_ = 0; // Variable para poder cambiar el contador de continue en función del tiempo
|
||||
Uint32 name_entry_ticks_ = 0; // Variable para poder cambiar el contador de poner nombre en función del tiempo
|
||||
Uint32 showing_name_ticks_ = 0; // Tiempo en el que se entra al estado SHOWING_NAME
|
||||
|
||||
// --- Flags booleanas ---
|
||||
bool qualifies_for_high_score_ = false; // Indica si tiene una puntuación que le permite entrar en la tabla de records
|
||||
bool invulnerable_ = true; // Indica si el jugador es invulnerable
|
||||
bool extra_hit_ = false; // Indica si el jugador tiene un toque extra
|
||||
bool power_up_ = false; // Indica si el jugador tiene activo el modo PowerUp
|
||||
bool demo_ = false; // Para que el jugador sepa si está en el modo demostración
|
||||
bool game_completed_ = false; // Indica si ha completado el juego
|
||||
bool uses_keyboard_ = false; // Indica si usa el teclado como dispositivo de control
|
||||
bool qualifies_for_high_score_ = false; // Indica si tiene una puntuación que le permite entrar en la tabla de records
|
||||
bool invulnerable_ = true; // Indica si el jugador es invulnerable
|
||||
bool extra_hit_ = false; // Indica si el jugador tiene un toque extra
|
||||
bool power_up_ = false; // Indica si el jugador tiene activo el modo PowerUp
|
||||
bool demo_ = false; // Para que el jugador sepa si está en el modo demostración
|
||||
bool game_completed_ = false; // Indica si ha completado el juego
|
||||
bool uses_keyboard_ = false; // Indica si usa el teclado como dispositivo de control
|
||||
|
||||
// --- Métodos internos ---
|
||||
void shiftColliders(); // Actualiza el círculo de colisión a la posición del jugador
|
||||
@@ -277,6 +275,7 @@ class Player {
|
||||
void transitionToCooling(); // Cambia el estado actual al de enfriamiento (por ejemplo, tras una ráfaga o sobrecalentamiento)
|
||||
void completeCooling(); // Finaliza el proceso de enfriamiento y restablece el estado listo para disparar
|
||||
void handlePlayingMovement(); // Gestiona el movimiento del personaje u objeto durante el estado de juego activo
|
||||
void handleRecoverMovement(); // Comprueba si ha acabado la animación
|
||||
void handleRollingMovement(); // Actualiza la lógica de movimiento de "rodar" (posiblemente tras impacto o acción especial)
|
||||
void handleRollingBoundaryCollision(); // Detecta y maneja colisiones del objeto rodante con los límites de la pantalla
|
||||
void handleRollingGroundCollision(); // Gestiona la interacción del objeto rodante con el suelo (rebotes, frenado, etc.)
|
||||
|
||||
@@ -80,7 +80,7 @@ void Resource::loadTextFilesQuiet() {
|
||||
for (const auto &l : list) {
|
||||
auto name = getFileName(l);
|
||||
// Buscar en nuestra lista y cargar directamente
|
||||
auto it = std::find_if(text_files_.begin(), text_files_.end(), [&name](const auto &t) { return t.name == name; });
|
||||
auto it = std::ranges::find_if(text_files_, [&name](const auto &t) { return t.name == name; });
|
||||
if (it != text_files_.end()) {
|
||||
it->text_file = Text::loadFile(l);
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Text file loaded: %s", name.c_str());
|
||||
@@ -109,9 +109,9 @@ void Resource::loadEssentialTextures() {
|
||||
for (const auto &file : texture_list) {
|
||||
auto name = getFileName(file);
|
||||
// Solo cargar texturas esenciales
|
||||
if (std::find(ESSENTIAL_TEXTURES.begin(), ESSENTIAL_TEXTURES.end(), name) != ESSENTIAL_TEXTURES.end()) {
|
||||
if (std::ranges::find(ESSENTIAL_TEXTURES, name) != ESSENTIAL_TEXTURES.end()) {
|
||||
// Buscar en nuestra lista y cargar
|
||||
auto it = std::find_if(textures_.begin(), textures_.end(), [&name](const auto &t) { return t.name == name; });
|
||||
auto it = std::ranges::find_if(textures_, [&name](const auto &t) { return t.name == name; });
|
||||
if (it != textures_.end()) {
|
||||
it->texture = std::make_shared<Texture>(Screen::get()->getRenderer(), file);
|
||||
}
|
||||
@@ -186,7 +186,7 @@ void Resource::initResourceLists() {
|
||||
|
||||
// Obtiene el sonido a partir de un nombre (con carga perezosa)
|
||||
auto Resource::getSound(const std::string &name) -> JA_Sound_t * {
|
||||
auto it = std::find_if(sounds_.begin(), sounds_.end(), [&name](const auto &s) { return s.name == name; });
|
||||
auto it = std::ranges::find_if(sounds_, [&name](const auto &s) { return s.name == name; });
|
||||
|
||||
if (it != sounds_.end()) {
|
||||
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
||||
@@ -202,7 +202,7 @@ auto Resource::getSound(const std::string &name) -> JA_Sound_t * {
|
||||
|
||||
// Obtiene la música a partir de un nombre (con carga perezosa)
|
||||
auto Resource::getMusic(const std::string &name) -> JA_Music_t * {
|
||||
auto it = std::find_if(musics_.begin(), musics_.end(), [&name](const auto &m) { return m.name == name; });
|
||||
auto it = std::ranges::find_if(musics_, [&name](const auto &m) { return m.name == name; });
|
||||
|
||||
if (it != musics_.end()) {
|
||||
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
||||
@@ -218,7 +218,7 @@ auto Resource::getMusic(const std::string &name) -> JA_Music_t * {
|
||||
|
||||
// Obtiene la textura a partir de un nombre (con carga perezosa)
|
||||
auto Resource::getTexture(const std::string &name) -> std::shared_ptr<Texture> {
|
||||
auto it = std::find_if(textures_.begin(), textures_.end(), [&name](const auto &t) { return t.name == name; });
|
||||
auto it = std::ranges::find_if(textures_, [&name](const auto &t) { return t.name == name; });
|
||||
|
||||
if (it != textures_.end()) {
|
||||
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
||||
@@ -234,7 +234,7 @@ auto Resource::getTexture(const std::string &name) -> std::shared_ptr<Texture> {
|
||||
|
||||
// Obtiene el fichero de texto a partir de un nombre (con carga perezosa)
|
||||
auto Resource::getTextFile(const std::string &name) -> std::shared_ptr<Text::File> {
|
||||
auto it = std::find_if(text_files_.begin(), text_files_.end(), [&name](const auto &t) { return t.name == name; });
|
||||
auto it = std::ranges::find_if(text_files_, [&name](const auto &t) { return t.name == name; });
|
||||
|
||||
if (it != text_files_.end()) {
|
||||
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
||||
@@ -250,7 +250,7 @@ auto Resource::getTextFile(const std::string &name) -> std::shared_ptr<Text::Fil
|
||||
|
||||
// Obtiene el objeto de texto a partir de un nombre (con carga perezosa)
|
||||
auto Resource::getText(const std::string &name) -> std::shared_ptr<Text> {
|
||||
auto it = std::find_if(texts_.begin(), texts_.end(), [&name](const auto &t) { return t.name == name; });
|
||||
auto it = std::ranges::find_if(texts_, [&name](const auto &t) { return t.name == name; });
|
||||
|
||||
if (it != texts_.end()) {
|
||||
// Si está en modo lazy y no se ha cargado aún, lo carga ahora
|
||||
@@ -266,7 +266,7 @@ auto Resource::getText(const std::string &name) -> std::shared_ptr<Text> {
|
||||
|
||||
// Obtiene la animación a partir de un nombre (con carga perezosa)
|
||||
auto Resource::getAnimation(const std::string &name) -> AnimationsFileBuffer & {
|
||||
auto it = std::find_if(animations_.begin(), animations_.end(), [&name](const auto &a) { return a.name == name; });
|
||||
auto it = std::ranges::find_if(animations_, [&name](const auto &a) { return a.name == name; });
|
||||
|
||||
if (it != animations_.end()) {
|
||||
// Si está en modo lazy y no se ha cargado aún (vector vacío), lo carga ahora
|
||||
@@ -346,18 +346,18 @@ auto Resource::loadTextLazy(const std::string &name) -> std::shared_ptr<Text> {
|
||||
};
|
||||
|
||||
const std::vector<TextMapping> TEXT_MAPPINGS = {
|
||||
{"04b_25", "04b_25.png", "04b_25.txt"},
|
||||
{"04b_25_2x", "04b_25_2x.png", "04b_25_2x.txt"},
|
||||
{"04b_25_metal", "04b_25_metal.png", "04b_25.txt"},
|
||||
{"04b_25_grey", "04b_25_grey.png", "04b_25.txt"},
|
||||
{"04b_25_flat", "04b_25_flat.png", "04b_25.txt"},
|
||||
{"04b_25_reversed", "04b_25_reversed.png", "04b_25.txt"},
|
||||
{"04b_25_flat_2x", "04b_25_flat_2x.png", "04b_25_2x.txt"},
|
||||
{"04b_25_reversed_2x", "04b_25_reversed_2x.png", "04b_25_2x.txt"},
|
||||
{"8bithud", "8bithud.png", "8bithud.txt"},
|
||||
{"aseprite", "aseprite.png", "aseprite.txt"},
|
||||
{"smb2", "smb2.png", "smb2.txt"},
|
||||
{"smb2_grad", "smb2_grad.png", "smb2.txt"}};
|
||||
{.key = "04b_25", .texture_file = "04b_25.png", .text_file = "04b_25.txt"},
|
||||
{.key = "04b_25_2x", .texture_file = "04b_25_2x.png", .text_file = "04b_25_2x.txt"},
|
||||
{.key = "04b_25_metal", .texture_file = "04b_25_metal.png", .text_file = "04b_25.txt"},
|
||||
{.key = "04b_25_grey", .texture_file = "04b_25_grey.png", .text_file = "04b_25.txt"},
|
||||
{.key = "04b_25_flat", .texture_file = "04b_25_flat.png", .text_file = "04b_25.txt"},
|
||||
{.key = "04b_25_reversed", .texture_file = "04b_25_reversed.png", .text_file = "04b_25.txt"},
|
||||
{.key = "04b_25_flat_2x", .texture_file = "04b_25_flat_2x.png", .text_file = "04b_25_2x.txt"},
|
||||
{.key = "04b_25_reversed_2x", .texture_file = "04b_25_reversed_2x.png", .text_file = "04b_25_2x.txt"},
|
||||
{.key = "8bithud", .texture_file = "8bithud.png", .text_file = "8bithud.txt"},
|
||||
{.key = "aseprite", .texture_file = "aseprite.png", .text_file = "aseprite.txt"},
|
||||
{.key = "smb2", .texture_file = "smb2.png", .text_file = "smb2.txt"},
|
||||
{.key = "smb2_grad", .texture_file = "smb2_grad.png", .text_file = "smb2.txt"}};
|
||||
|
||||
for (const auto &mapping : TEXT_MAPPINGS) {
|
||||
if (mapping.key == name) {
|
||||
@@ -537,10 +537,13 @@ void Resource::createPlayerTextures() {
|
||||
};
|
||||
|
||||
std::vector<PlayerConfig> players = {
|
||||
{"player1.gif", {"player1_coffee1.pal", "player1_coffee2.pal", "player1_invencible.pal"}, "player1"},
|
||||
{"player2.gif", {"player2_coffee1.pal", "player2_coffee2.pal", "player2_invencible.pal"}, "player2"}};
|
||||
{.base_texture = "player1.gif", .palette_files = {"player1_coffee1.pal", "player1_coffee2.pal", "player1_invencible.pal"}, .name_prefix = "player1"},
|
||||
{.base_texture = "player2.gif", .palette_files = {"player2_coffee1.pal", "player2_coffee2.pal", "player2_invencible.pal"}, .name_prefix = "player2"}};
|
||||
|
||||
// Bucle principal
|
||||
for (size_t player_idx = 0; player_idx < players.size(); ++player_idx) {
|
||||
const auto &player = players[player_idx]; // Obtenemos el jugador actual
|
||||
|
||||
for (const auto &player : players) {
|
||||
// Encontrar el archivo original de la textura
|
||||
std::string texture_file_path;
|
||||
auto texture_list = Asset::get()->getListByType(Asset::Type::BITMAP);
|
||||
@@ -551,29 +554,52 @@ void Resource::createPlayerTextures() {
|
||||
}
|
||||
}
|
||||
|
||||
// Crear variante con paleta original (pal0) - usar la textura ya cargada
|
||||
auto base_texture = getTexture(player.base_texture);
|
||||
std::string pal0_name = player.name_prefix + "_pal0";
|
||||
textures_.emplace_back(pal0_name, base_texture);
|
||||
printWithDots("Player Texture : ", pal0_name, "[ DONE ]");
|
||||
// Crear las 4 texturas con sus respectivas paletas
|
||||
for (int palette_idx = 0; palette_idx < 4; ++palette_idx) {
|
||||
std::shared_ptr<Texture> texture;
|
||||
|
||||
// Crear variantes con paletas adicionales - CADA UNA DESDE EL ARCHIVO
|
||||
for (size_t i = 0; i < player.palette_files.size(); ++i) {
|
||||
// Crear textura completamente nueva desde el archivo
|
||||
auto texture_copy = std::make_shared<Texture>(Screen::get()->getRenderer(), texture_file_path);
|
||||
if (palette_idx == 0) {
|
||||
// Textura 0 - usar la ya cargada y modificar solo paleta 0 (default_shirt)
|
||||
texture = getTexture(player.base_texture);
|
||||
texture->setPaletteColor(0, 16, param.player.default_shirt[player_idx].darkest.TO_UINT32());
|
||||
texture->setPaletteColor(0, 17, param.player.default_shirt[player_idx].dark.TO_UINT32());
|
||||
texture->setPaletteColor(0, 18, param.player.default_shirt[player_idx].base.TO_UINT32());
|
||||
texture->setPaletteColor(0, 19, param.player.default_shirt[player_idx].light.TO_UINT32());
|
||||
texture->setPaletteColor(0, 56, param.player.outline_color[player_idx].TO_UINT32());
|
||||
} else {
|
||||
// Crear textura nueva desde archivo
|
||||
texture = std::make_shared<Texture>(Screen::get()->getRenderer(), texture_file_path);
|
||||
|
||||
// Añadir todas las paletas
|
||||
texture_copy->addPaletteFromPalFile(Asset::get()->get(player.palette_files[0]));
|
||||
texture_copy->addPaletteFromPalFile(Asset::get()->get(player.palette_files[1]));
|
||||
texture_copy->addPaletteFromPalFile(Asset::get()->get(player.palette_files[2]));
|
||||
// Añadir todas las paletas
|
||||
texture->addPaletteFromPalFile(Asset::get()->get(player.palette_files[0]));
|
||||
texture->addPaletteFromPalFile(Asset::get()->get(player.palette_files[1]));
|
||||
texture->addPaletteFromPalFile(Asset::get()->get(player.palette_files[2]));
|
||||
|
||||
// Cambiar a la paleta específica (índice i+1 porque 0 es la original)
|
||||
texture_copy->setPalette(i + 1);
|
||||
if (palette_idx == 1) {
|
||||
// Textura 1 - modificar solo paleta 1 (one_coffee_shirt)
|
||||
texture->setPaletteColor(1, 16, param.player.one_coffee_shirt[player_idx].darkest.TO_UINT32());
|
||||
texture->setPaletteColor(1, 17, param.player.one_coffee_shirt[player_idx].dark.TO_UINT32());
|
||||
texture->setPaletteColor(1, 18, param.player.one_coffee_shirt[player_idx].base.TO_UINT32());
|
||||
texture->setPaletteColor(1, 19, param.player.one_coffee_shirt[player_idx].light.TO_UINT32());
|
||||
texture->setPaletteColor(1, 56, param.player.outline_color[player_idx].TO_UINT32());
|
||||
} else if (palette_idx == 2) {
|
||||
// Textura 2 - modificar solo paleta 2 (two_coffee_shirt)
|
||||
texture->setPaletteColor(2, 16, param.player.two_coffee_shirt[player_idx].darkest.TO_UINT32());
|
||||
texture->setPaletteColor(2, 17, param.player.two_coffee_shirt[player_idx].dark.TO_UINT32());
|
||||
texture->setPaletteColor(2, 18, param.player.two_coffee_shirt[player_idx].base.TO_UINT32());
|
||||
texture->setPaletteColor(2, 19, param.player.two_coffee_shirt[player_idx].light.TO_UINT32());
|
||||
texture->setPaletteColor(2, 56, param.player.outline_color[player_idx].TO_UINT32());
|
||||
}
|
||||
// Textura 3 (palette_idx == 3) - no modificar nada, usar colores originales
|
||||
}
|
||||
|
||||
// Asignar la paleta correspondiente
|
||||
texture->setPalette(palette_idx);
|
||||
|
||||
// Guardar con nombre específico
|
||||
std::string variant_name = player.name_prefix + "_pal" + std::to_string(i + 1);
|
||||
textures_.emplace_back(variant_name, texture_copy);
|
||||
printWithDots("Player Texture : ", variant_name, "[ DONE ]");
|
||||
std::string texture_name = player.name_prefix + "_pal" + std::to_string(palette_idx);
|
||||
textures_.emplace_back(texture_name, texture);
|
||||
printWithDots("Player Texture : ", texture_name, "[ DONE ]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -590,33 +616,42 @@ void Resource::createTextTextures() {
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> CREATING TEXTURES");
|
||||
|
||||
// Texturas de tamaño normal
|
||||
std::vector<NameAndText> strings = {
|
||||
// Texturas de tamaño normal con outline
|
||||
std::vector<NameAndText> strings1 = {
|
||||
{"game_text_1000_points", "1.000"},
|
||||
{"game_text_2500_points", "2.500"},
|
||||
{"game_text_5000_points", "5.000"},
|
||||
{"game_text_powerup", Lang::getText("[GAME_TEXT] 4")},
|
||||
{"game_text_one_hit", Lang::getText("[GAME_TEXT] 5")},
|
||||
{"game_text_stop", Lang::getText("[GAME_TEXT] 6")},
|
||||
{"game_text_stop", Lang::getText("[GAME_TEXT] 6")}};
|
||||
|
||||
auto text1 = getText("04b_25_enhanced");
|
||||
for (const auto &s : strings1) {
|
||||
textures_.emplace_back(s.name, text1->writeDXToTexture(Text::STROKE, s.text, -2, Colors::NO_COLOR_MOD, 1, param.game.item_text_outline_color));
|
||||
printWithDots("Texture : ", s.name, "[ DONE ]");
|
||||
}
|
||||
|
||||
// Texturas de tamaño normal
|
||||
std::vector<NameAndText> strings2 = {
|
||||
{"game_text_1000000_points", Lang::getText("[GAME_TEXT] 8")}};
|
||||
|
||||
auto text = getText("04b_25");
|
||||
for (const auto &s : strings) {
|
||||
textures_.emplace_back(s.name, text->writeToTexture(s.text, 1, -2));
|
||||
auto text2 = getText("04b_25");
|
||||
for (const auto &s : strings2) {
|
||||
textures_.emplace_back(s.name, text2->writeDXToTexture(Text::STROKE, s.text, -2, Colors::NO_COLOR_MOD, 1, param.game.item_text_outline_color));
|
||||
printWithDots("Texture : ", s.name, "[ DONE ]");
|
||||
}
|
||||
|
||||
// Texturas de tamaño doble
|
||||
std::vector<NameAndText> strings2_x = {
|
||||
std::vector<NameAndText> strings3 = {
|
||||
{"game_text_100000_points", "100.000"},
|
||||
{"game_text_get_ready", Lang::getText("[GAME_TEXT] 7")},
|
||||
{"game_text_last_stage", Lang::getText("[GAME_TEXT] 3")},
|
||||
{"game_text_congratulations", Lang::getText("[GAME_TEXT] 1")},
|
||||
{"game_text_game_over", "Game Over"}};
|
||||
|
||||
auto text2 = getText("04b_25_2x");
|
||||
for (const auto &s : strings2_x) {
|
||||
textures_.emplace_back(s.name, text2->writeToTexture(s.text, 1, -4));
|
||||
auto text3 = getText("04b_25_2x");
|
||||
for (const auto &s : strings3) {
|
||||
textures_.emplace_back(s.name, text3->writeToTexture(s.text, 1, -4));
|
||||
printWithDots("Texture : ", s.name, "[ DONE ]");
|
||||
}
|
||||
}
|
||||
@@ -627,15 +662,18 @@ void Resource::createText() {
|
||||
std::string key;
|
||||
std::string texture_file;
|
||||
std::string text_file;
|
||||
std::string white_texture_file; // Textura blanca opcional
|
||||
|
||||
ResourceInfo(std::string k, std::string t_file, std::string txt_file)
|
||||
: key(std::move(k)), texture_file(std::move(t_file)), text_file(std::move(txt_file)) {}
|
||||
ResourceInfo(std::string k, std::string t_file, std::string txt_file, std::string w_file = "")
|
||||
: key(std::move(k)), texture_file(std::move(t_file)), text_file(std::move(txt_file)), white_texture_file(std::move(w_file)) {}
|
||||
};
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> CREATING TEXT OBJECTS");
|
||||
|
||||
std::vector<ResourceInfo> resources = {
|
||||
{"04b_25", "04b_25.png", "04b_25.txt"},
|
||||
{"04b_25_enhanced", "04b_25.png", "04b_25.txt", "04b_25_white.png"}, // Nueva fuente con textura blanca
|
||||
{"04b_25_white", "04b_25_white.png", "04b_25.txt"},
|
||||
{"04b_25_2x", "04b_25_2x.png", "04b_25_2x.txt"},
|
||||
{"04b_25_metal", "04b_25_metal.png", "04b_25.txt"},
|
||||
{"04b_25_grey", "04b_25_grey.png", "04b_25.txt"},
|
||||
@@ -649,7 +687,13 @@ void Resource::createText() {
|
||||
{"smb2_grad", "smb2_grad.png", "smb2.txt"}};
|
||||
|
||||
for (const auto &resource : resources) {
|
||||
texts_.emplace_back(resource.key, std::make_shared<Text>(getTexture(resource.texture_file), getTextFile(resource.text_file)));
|
||||
if (!resource.white_texture_file.empty()) {
|
||||
// Crear texto con textura blanca
|
||||
texts_.emplace_back(resource.key, std::make_shared<Text>(getTexture(resource.texture_file), getTexture(resource.white_texture_file), getTextFile(resource.text_file)));
|
||||
} else {
|
||||
// Crear texto normal
|
||||
texts_.emplace_back(resource.key, std::make_shared<Text>(getTexture(resource.texture_file), getTextFile(resource.text_file)));
|
||||
}
|
||||
printWithDots("Text : ", resource.key, "[ DONE ]");
|
||||
}
|
||||
}
|
||||
@@ -770,15 +814,15 @@ void Resource::initProgressBar() {
|
||||
const float BAR_Y_POSITION = param.game.height - BAR_HEIGHT - Y_PADDING;
|
||||
|
||||
const float WIRED_BAR_WIDTH = param.game.width - (X_PADDING * 2);
|
||||
loading_wired_rect_ = {X_PADDING, BAR_Y_POSITION, WIRED_BAR_WIDTH, BAR_HEIGHT};
|
||||
loading_wired_rect_ = {.x = X_PADDING, .y = BAR_Y_POSITION, .w = WIRED_BAR_WIDTH, .h = BAR_HEIGHT};
|
||||
|
||||
const float FULL_BAR_WIDTH = WIRED_BAR_WIDTH * loading_count_.getPercentage();
|
||||
loading_full_rect_ = {X_PADDING, BAR_Y_POSITION, FULL_BAR_WIDTH, BAR_HEIGHT};
|
||||
loading_full_rect_ = {.x = X_PADDING, .y = BAR_Y_POSITION, .w = FULL_BAR_WIDTH, .h = BAR_HEIGHT};
|
||||
}
|
||||
|
||||
// Actualiza el progreso de carga, muestra la barra y procesa eventos
|
||||
void Resource::updateLoadingProgress(std::string name) {
|
||||
loading_resource_name_ = name;
|
||||
loading_resource_name_ = std::move(name);
|
||||
loading_count_.increase();
|
||||
updateProgressBar();
|
||||
renderProgress();
|
||||
|
||||
@@ -140,14 +140,13 @@ class Resource {
|
||||
void loadEssentialResources(); // Carga recursos esenciales en modo lazy
|
||||
void loadEssentialTextures(); // Carga solo las texturas esenciales (fuentes)
|
||||
void loadTextFilesQuiet(); // Carga ficheros de texto sin mostrar progreso (para modo lazy)
|
||||
// void addPalettes(); // Añade paletas a las texturas
|
||||
void createPlayerTextures(); // Crea las texturas de jugadores con todas sus variantes de paleta
|
||||
void createTextTextures(); // Crea las texturas a partir de los datos cargados
|
||||
void createText(); // Crea los objetos de texto
|
||||
void clear(); // Vacía todos los vectores de recursos
|
||||
void load(); // Carga todos los recursos
|
||||
void clearSounds(); // Vacía el vector de sonidos
|
||||
void clearMusics(); // Vacía el vector de músicas
|
||||
void createPlayerTextures(); // Crea las texturas de jugadores con todas sus variantes de paleta
|
||||
void createTextTextures(); // Crea las texturas a partir de los datos cargados
|
||||
void createText(); // Crea los objetos de texto
|
||||
void clear(); // Vacía todos los vectores de recursos
|
||||
void load(); // Carga todos los recursos
|
||||
void clearSounds(); // Vacía el vector de sonidos
|
||||
void clearMusics(); // Vacía el vector de músicas
|
||||
|
||||
// --- Métodos para carga perezosa ---
|
||||
void initResourceLists(); // Inicializa las listas de recursos sin cargar el contenido
|
||||
|
||||
@@ -241,7 +241,7 @@ void Scoreboard::renderGameOverMode() {
|
||||
|
||||
void Scoreboard::renderStageInfoMode() {
|
||||
// STAGE
|
||||
text_scoreboard_->writeDX(Text::CENTER | Text::COLOR, slot4_1_.x, slot4_1_.y, Lang::getText("[SCOREBOARD] 5") + std::to_string(stage_), 1, text_color1_);
|
||||
text_scoreboard_->writeDX(Text::CENTER | Text::COLOR, slot4_1_.x, slot4_1_.y, Lang::getText("[SCOREBOARD] 5") + " " + std::to_string(stage_), 1, text_color1_);
|
||||
|
||||
// POWERMETER
|
||||
power_meter_sprite_->setSpriteClip(0, 0, 40, 7);
|
||||
@@ -309,10 +309,7 @@ void Scoreboard::renderShowNameMode(size_t panel_index) {
|
||||
text_scoreboard_->writeDX(Text::CENTER | Text::COLOR, slot4_3_.x, slot4_3_.y, Lang::getText("[SCOREBOARD] 11"), 1, text_color1_);
|
||||
|
||||
/* TEXTO CENTRADO */
|
||||
text_scoreboard_->writeDX(Text::CENTER | Text::COLOR, slot4_4_.x, slot4_4_.y, record_name_.at(panel_index), 1, getColorLikeKnightRider(name_colors_, loop_counter_ / 5));
|
||||
|
||||
/* TEXTO A LA IZQUIERDA */
|
||||
// text_scoreboard_->writeColored(enter_name_pos_.x, enter_name_pos_.y, record_name_.at(panelIndex), getColorLikeKnightRider(name_colors_, loop_counter_ / 5));
|
||||
text_scoreboard_->writeDX(Text::CENTER | Text::COLOR, slot4_4_.x, slot4_4_.y, record_name_.at(panel_index), 1, Colors::getColorLikeKnightRider(name_colors_, loop_counter_ / 5));
|
||||
}
|
||||
|
||||
void Scoreboard::renderGameCompletedMode(size_t panel_index) {
|
||||
@@ -376,14 +373,14 @@ void Scoreboard::recalculateAnchors() {
|
||||
const float COL = PANEL_WIDTH / 2;
|
||||
|
||||
// Slots de 4
|
||||
slot4_1_ = {COL, ROW1};
|
||||
slot4_2_ = {COL, ROW2};
|
||||
slot4_3_ = {COL, ROW3};
|
||||
slot4_4_ = {COL, ROW4};
|
||||
slot4_1_ = {.x = COL, .y = ROW1};
|
||||
slot4_2_ = {.x = COL, .y = ROW2};
|
||||
slot4_3_ = {.x = COL, .y = ROW3};
|
||||
slot4_4_ = {.x = COL, .y = ROW4};
|
||||
|
||||
// Primer cuadrado para poner el nombre de record
|
||||
const int ENTER_NAME_LENGHT = text_scoreboard_->length(std::string(NAME_SIZE, 'A'));
|
||||
enter_name_pos_.x = COL - (ENTER_NAME_LENGHT / 2);
|
||||
const int ENTER_NAME_LENGTH = text_scoreboard_->length(std::string(NAME_SIZE, 'A'));
|
||||
enter_name_pos_.x = COL - (ENTER_NAME_LENGTH / 2);
|
||||
enter_name_pos_.y = ROW4;
|
||||
|
||||
// Recoloca los sprites
|
||||
|
||||
@@ -38,7 +38,7 @@ class Scoreboard {
|
||||
NUM_MODES,
|
||||
};
|
||||
|
||||
// --- Structs ---
|
||||
// --- Estructuras ---
|
||||
struct Panel {
|
||||
Mode mode; // Modo en el que se encuentra el panel
|
||||
SDL_FRect pos; // Posición donde dibujar el panel dentro del marcador
|
||||
@@ -80,22 +80,21 @@ class Scoreboard {
|
||||
// --- Variables de estado ---
|
||||
std::array<std::string, static_cast<int>(Id::SIZE)> name_ = {}; // Nombre de cada jugador
|
||||
std::array<std::string, static_cast<int>(Id::SIZE)> record_name_ = {}; // Nombre introducido para la tabla de records
|
||||
std::array<Panel, static_cast<int>(Id::SIZE)> panel_ = {}; // Lista con todos los paneles del marcador
|
||||
std::vector<Color> name_colors_; // Colores para destacar el nombre una vez introducido
|
||||
std::string hi_score_name_; // Nombre del jugador con la máxima puntuación
|
||||
SDL_FRect rect_ = {0, 0, 320, 40}; // Posición y dimensiones del marcador
|
||||
Color color_; // Color del marcador
|
||||
std::array<size_t, static_cast<int>(Id::SIZE)> selector_pos_ = {}; // Posición del selector de letra para introducir el nombre
|
||||
std::array<int, static_cast<int>(Id::SIZE)> score_ = {}; // Puntuación de los jugadores
|
||||
std::array<float, static_cast<int>(Id::SIZE)> mult_ = {}; // Multiplicador de los jugadores
|
||||
std::array<int, static_cast<int>(Id::SIZE)> continue_counter_ = {}; // Tiempo para continuar de los jugadores
|
||||
std::array<Panel, static_cast<int>(Id::SIZE)> panel_ = {}; // Lista con todos los paneles del marcador
|
||||
|
||||
int stage_ = 1; // Número de fase actual
|
||||
int hi_score_ = 0; // Máxima puntuación
|
||||
float power_ = 0; // Poder actual de la fase
|
||||
std::string hi_score_name_; // Nombre del jugador con la máxima puntuación
|
||||
Color color_; // Color del marcador
|
||||
SDL_FRect rect_ = {0, 0, 320, 40}; // Posición y dimensiones del marcador
|
||||
Uint64 ticks_ = SDL_GetTicks(); // Variable donde almacenar el valor de SDL_GetTicks()
|
||||
int time_counter_ = 0; // Contador de segundos
|
||||
int loop_counter_ = 0; // Contador de bucle
|
||||
std::vector<Color> name_colors_; // Colores para destacar el nombre una vez introducido
|
||||
std::array<float, static_cast<int>(Id::SIZE)> mult_ = {}; // Multiplicador de los jugadores
|
||||
Uint64 ticks_ = SDL_GetTicks(); // Variable donde almacenar el valor de SDL_GetTicks()
|
||||
int stage_ = 1; // Número de fase actual
|
||||
int hi_score_ = 0; // Máxima puntuación
|
||||
int time_counter_ = 0; // Contador de segundos
|
||||
int loop_counter_ = 0; // Contador de bucle
|
||||
float power_ = 0; // Poder actual de la fase
|
||||
|
||||
// --- Variables de aspecto ---
|
||||
Color text_color1_, text_color2_; // Colores para los marcadores del texto;
|
||||
@@ -126,10 +125,10 @@ class Scoreboard {
|
||||
void renderShowNameMode(size_t panel_index);
|
||||
void renderGameCompletedMode(size_t panel_index);
|
||||
|
||||
// --- Constructor y destructor privados (singleton) ---
|
||||
Scoreboard();
|
||||
~Scoreboard();
|
||||
// --- Constructores y destructor privados (singleton) ---
|
||||
Scoreboard(); // Constructor privado
|
||||
~Scoreboard(); // Destructor privado
|
||||
|
||||
// --- Singleton ---
|
||||
static Scoreboard *instance;
|
||||
// --- Instancia singleton ---
|
||||
static Scoreboard *instance; // Instancia única de Scoreboard
|
||||
};
|
||||
|
||||
@@ -12,7 +12,7 @@ class Notifier;
|
||||
class ServiceMenu;
|
||||
class Text;
|
||||
|
||||
// Clase Screen: gestiona la ventana, el renderizador y los efectos visuales globales
|
||||
// --- Clase Screen: gestiona la ventana, el renderizador y los efectos visuales globales (singleton) ---
|
||||
class Screen {
|
||||
public:
|
||||
// --- Métodos de singleton ---
|
||||
@@ -38,8 +38,8 @@ class Screen {
|
||||
void initShaders(); // Inicializa los shaders
|
||||
|
||||
// --- Efectos visuales ---
|
||||
void shake(int desp = 2, int delay = 3, int lenght = 8) { shake_effect_.enable(src_rect_, dst_rect_, desp, delay, lenght); } // Agita la pantalla
|
||||
void flash(Color color, int lenght = 10, int delay = 0) { flash_effect_ = FlashEffect(true, lenght, delay, color); } // Pone la pantalla de color
|
||||
void shake(int desp = 2, int delay = 3, int length = 8) { shake_effect_.enable(src_rect_, dst_rect_, desp, delay, length); } // Agita la pantalla
|
||||
void flash(Color color, int length = 10, int delay = 0) { flash_effect_ = FlashEffect(true, length, delay, color); } // Pone la pantalla de color
|
||||
void toggleShaders(); // Alterna entre activar y desactivar los shaders
|
||||
void toggleIntegerScale(); // Alterna entre activar y desactivar el escalado entero
|
||||
void toggleVSync(); // Alterna entre activar y desactivar el V-Sync
|
||||
@@ -62,9 +62,9 @@ class Screen {
|
||||
|
||||
private:
|
||||
// --- Constantes ---
|
||||
static constexpr int WINDOWS_DECORATIONS = 35;
|
||||
static constexpr int WINDOWS_DECORATIONS = 35; // Decoraciones de la ventana
|
||||
|
||||
// --- Estructuras internas ---
|
||||
// --- Estructuras privadas ---
|
||||
struct FPS {
|
||||
Uint32 ticks{0}; // Tiempo en milisegundos desde que se comenzó a contar.
|
||||
int frame_count{0}; // Número acumulado de frames en el intervalo.
|
||||
@@ -85,16 +85,16 @@ class Screen {
|
||||
// Efecto de flash en pantalla: pinta la pantalla de un color durante unos frames
|
||||
struct FlashEffect {
|
||||
bool enabled; // Indica si el efecto está activo
|
||||
int lenght; // Duración total del efecto en frames
|
||||
int length; // Duración total del efecto en frames
|
||||
int delay; // Retraso antes de mostrar el flash
|
||||
int counter; // Contador de frames restantes
|
||||
Color color; // Color del flash
|
||||
|
||||
explicit FlashEffect(bool enabled = false, int lenght = 0, int delay = 0, Color color = Color(0xFF, 0xFF, 0xFF))
|
||||
: enabled(enabled), lenght(lenght), delay(delay), counter(lenght), color(color) {}
|
||||
explicit FlashEffect(bool enabled = false, int length = 0, int delay = 0, Color color = Color(0xFF, 0xFF, 0xFF))
|
||||
: enabled(enabled), length(length), delay(delay), counter(length), color(color) {}
|
||||
|
||||
void update() { (enabled && counter > 0) ? counter-- : static_cast<int>(enabled = false); }
|
||||
[[nodiscard]] auto isRendarable() const -> bool { return enabled && counter < lenght - delay; }
|
||||
[[nodiscard]] auto isRendarable() const -> bool { return enabled && counter < length - delay; }
|
||||
};
|
||||
|
||||
// Efecto de sacudida/agitación de pantalla: mueve la imagen para simular un temblor
|
||||
@@ -102,17 +102,17 @@ class Screen {
|
||||
int desp; // Desplazamiento máximo de la sacudida (en píxeles)
|
||||
int delay; // Frames entre cada movimiento de sacudida
|
||||
int counter; // Contador de frames para el siguiente movimiento
|
||||
int lenght; // Duración total del efecto en frames
|
||||
int length; // Duración total del efecto en frames
|
||||
int remaining; // Frames restantes de sacudida
|
||||
int original_pos; // Posición original de la imagen (x)
|
||||
int original_width; // Ancho original de la imagen
|
||||
bool enabled; // Indica si el efecto está activo
|
||||
|
||||
explicit ShakeEffect(bool en = false, int dp = 2, int dl = 3, int cnt = 0, int len = 8, int rem = 0, int orig_pos = 0, int orig_width = 800)
|
||||
: desp(dp), delay(dl), counter(cnt), lenght(len), remaining(rem), original_pos(orig_pos), original_width(orig_width), enabled(en) {}
|
||||
: desp(dp), delay(dl), counter(cnt), length(len), remaining(rem), original_pos(orig_pos), original_width(orig_width), enabled(en) {}
|
||||
|
||||
// Activa el efecto de sacudida y guarda la posición y tamaño originales
|
||||
void enable(SDL_FRect &src_rect, SDL_FRect &dst_rect, int new_desp = -1, int new_delay = -1, int new_lenght = -1) {
|
||||
void enable(SDL_FRect &src_rect, SDL_FRect &dst_rect, int new_desp = -1, int new_delay = -1, int new_length = -1) {
|
||||
if (!enabled) {
|
||||
enabled = true;
|
||||
original_pos = src_rect.x;
|
||||
@@ -125,14 +125,14 @@ class Screen {
|
||||
if (new_delay != -1) {
|
||||
delay = new_delay;
|
||||
}
|
||||
if (new_lenght != -1) {
|
||||
lenght = new_lenght;
|
||||
if (new_length != -1) {
|
||||
length = new_length;
|
||||
}
|
||||
|
||||
src_rect.w -= desp;
|
||||
dst_rect.w = src_rect.w;
|
||||
}
|
||||
remaining = lenght;
|
||||
remaining = length;
|
||||
counter = delay;
|
||||
}
|
||||
|
||||
@@ -170,21 +170,19 @@ class Screen {
|
||||
|
||||
#endif
|
||||
|
||||
// --- Singleton ---
|
||||
static Screen *instance;
|
||||
|
||||
// --- Objetos y punteros ---
|
||||
SDL_Window *window_; // Ventana de la aplicación
|
||||
SDL_Renderer *renderer_; // El renderizador de la ventana
|
||||
SDL_Texture *game_canvas_; // Textura donde se dibuja todo antes de volcarse al renderizador
|
||||
ServiceMenu *service_menu_; // Objeto para mostrar el menú de servicio
|
||||
Notifier *notifier_; // Objeto para mostrar las notificaciones por pantalla
|
||||
SDL_Window *window_; // Ventana de la aplicación
|
||||
SDL_Renderer *renderer_; // El renderizador de la ventana
|
||||
SDL_Texture *game_canvas_; // Textura donde se dibuja todo antes de volcarse al renderizador
|
||||
ServiceMenu *service_menu_; // Objeto para mostrar el menú de servicio
|
||||
Notifier *notifier_; // Objeto para mostrar las notificaciones por pantalla
|
||||
std::shared_ptr<Text> text_; // Objeto para escribir texto en pantalla
|
||||
|
||||
// --- Variables de estado ---
|
||||
SDL_FRect src_rect_; // Coordenadas de origen para dibujar la textura del juego
|
||||
SDL_FRect dst_rect_; // Coordenadas destino para dibujar la textura del juego
|
||||
FPS fps_; // Gestión de frames por segundo
|
||||
std::string shader_source_; // Almacena el contenido del archivo GLSL
|
||||
FPS fps_; // Gestión de frames por segundo
|
||||
FlashEffect flash_effect_; // Efecto de flash en pantalla
|
||||
ShakeEffect shake_effect_; // Efecto de agitar la pantalla
|
||||
bool attenuate_effect_ = false; // Indica si la pantalla ha de estar atenuada
|
||||
@@ -192,9 +190,6 @@ class Screen {
|
||||
Debug debug_info_; // Información de debug
|
||||
#endif
|
||||
|
||||
// --- Texto ---
|
||||
std::shared_ptr<Text> text_; // Objeto para escribir texto en pantalla
|
||||
|
||||
// --- Métodos internos ---
|
||||
auto initSDLVideo() -> bool; // Arranca SDL VIDEO y crea la ventana
|
||||
void renderFlash(); // Dibuja el efecto de flash en la pantalla
|
||||
@@ -208,7 +203,10 @@ class Screen {
|
||||
void renderAttenuate(); // Atenúa la pantalla
|
||||
void createText(); // Crea el objeto de texto
|
||||
|
||||
// --- Constructores y destructor ---
|
||||
Screen();
|
||||
~Screen();
|
||||
// --- Constructores y destructor privados (singleton) ---
|
||||
Screen(); // Constructor privado
|
||||
~Screen(); // Destructor privado
|
||||
|
||||
// --- Instancia singleton ---
|
||||
static Screen *instance; // Instancia única de Screen
|
||||
};
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "audio.h" // Para Audio
|
||||
#include "balloon_manager.h" // Para BalloonManager
|
||||
#include "color.h" // Para Zone, SHADOW_TEXT_COLOR, NO_TEXT_COLOR, Color
|
||||
#include "color.h" // Para Zone, Colors::SHADOW_TEXT, Colors::NO_COLOR_MOD, Color
|
||||
#include "fade.h" // Para Fade, FadeType, FadeMode
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
@@ -35,12 +35,7 @@ constexpr std::string_view TEXT_COPYRIGHT = "@2020,2025 JailDesigner";
|
||||
|
||||
// Constructor
|
||||
Credits::Credits()
|
||||
: balloon_manager_(std::make_unique<BalloonManager>()),
|
||||
tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::DIAGONAL)),
|
||||
fade_in_(std::make_unique<Fade>()),
|
||||
fade_out_(std::make_unique<Fade>()),
|
||||
text_texture_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
|
||||
canvas_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)) {
|
||||
: balloon_manager_(std::make_unique<BalloonManager>(nullptr)), tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::DIAGONAL)), fade_in_(std::make_unique<Fade>()), fade_out_(std::make_unique<Fade>()), text_texture_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, static_cast<int>(param.game.width), static_cast<int>(param.game.height))), canvas_(SDL_CreateTexture(Screen::get()->getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, static_cast<int>(param.game.width), static_cast<int>(param.game.height))) {
|
||||
if (text_texture_ == nullptr) {
|
||||
throw std::runtime_error("Failed to create SDL texture for text.");
|
||||
}
|
||||
@@ -48,13 +43,13 @@ Credits::Credits()
|
||||
balloon_manager_->setPlayArea(play_area_);
|
||||
|
||||
fade_in_->setColor(param.fade.color);
|
||||
fade_in_->setType(FadeType::FULLSCREEN);
|
||||
fade_in_->setType(Fade::Type::FULLSCREEN);
|
||||
fade_in_->setPostDuration(50);
|
||||
fade_in_->setMode(FadeMode::IN);
|
||||
fade_in_->setMode(Fade::Mode::IN);
|
||||
fade_in_->activate();
|
||||
|
||||
fade_out_->setColor(0, 0, 0);
|
||||
fade_out_->setType(FadeType::FULLSCREEN);
|
||||
fade_out_->setType(Fade::Type::FULLSCREEN);
|
||||
fade_out_->setPostDuration(400);
|
||||
|
||||
updateRedRect();
|
||||
@@ -63,7 +58,7 @@ Credits::Credits()
|
||||
initPlayers();
|
||||
SDL_SetTextureBlendMode(text_texture_, SDL_BLENDMODE_BLEND);
|
||||
fillTextTexture();
|
||||
steps_ = std::abs((top_black_rect_.h - param.game.game_area.center_y - 1) + ((left_black_rect_.w - param.game.game_area.center_x) / 4));
|
||||
steps_ = static_cast<int>(std::abs((top_black_rect_.h - param.game.game_area.center_y - 1) + ((left_black_rect_.w - param.game.game_area.center_x) / 4)));
|
||||
}
|
||||
|
||||
// Destructor
|
||||
@@ -124,7 +119,7 @@ void Credits::render() {
|
||||
void Credits::checkEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
GlobalEvents::check(event);
|
||||
GlobalEvents::handle(event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,58 +165,60 @@ void Credits::fillTextTexture() {
|
||||
|
||||
const int SPACE_POST_TITLE = 3 + text->getCharacterSize();
|
||||
const int SPACE_PRE_TITLE = text->getCharacterSize() * 4;
|
||||
const int TEXTS_HEIGHT = 1 * text->getCharacterSize() + 8 * SPACE_POST_TITLE + 3 * SPACE_PRE_TITLE;
|
||||
credits_rect_dst_.h = credits_rect_src_.h = TEXTS_HEIGHT;
|
||||
const int TEXTS_HEIGHT = (1 * text->getCharacterSize()) + (8 * SPACE_POST_TITLE) + (3 * SPACE_PRE_TITLE);
|
||||
const int POS_X = static_cast<int>(param.game.game_area.center_x);
|
||||
credits_rect_dst_.h = credits_rect_src_.h = static_cast<float>(TEXTS_HEIGHT);
|
||||
auto text_style = Text::Style(Text::CENTER | Text::SHADOW, Colors::NO_COLOR_MOD, Colors::SHADOW_TEXT);
|
||||
|
||||
// PROGRAMMED_AND_DESIGNED_BY
|
||||
int y = 0;
|
||||
text_grad->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(0), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text_grad->writeStyle(POS_X, y, TEXTS.at(0), text_style);
|
||||
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(4), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(4), text_style);
|
||||
|
||||
// PIXELART_DRAWN_BY
|
||||
y += SPACE_PRE_TITLE;
|
||||
text_grad->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(1), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text_grad->writeStyle(POS_X, y, TEXTS.at(1), text_style);
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(4), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(4), text_style);
|
||||
|
||||
// MUSIC_COMPOSED_BY
|
||||
y += SPACE_PRE_TITLE;
|
||||
text_grad->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(2), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text_grad->writeStyle(POS_X, y, TEXTS.at(2), text_style);
|
||||
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(5), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(5), text_style);
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(6), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(6), text_style);
|
||||
|
||||
// SOUND_EFFECTS
|
||||
y += SPACE_PRE_TITLE;
|
||||
text_grad->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(3), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text_grad->writeStyle(POS_X, y, TEXTS.at(3), text_style);
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(7), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(7), text_style);
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(8), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(8), text_style);
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(9), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(9), text_style);
|
||||
y += SPACE_POST_TITLE;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, TEXTS.at(10), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeStyle(POS_X, y, TEXTS.at(10), text_style);
|
||||
|
||||
// Mini logo
|
||||
y += SPACE_PRE_TITLE;
|
||||
mini_logo_rect_src_.y = y;
|
||||
mini_logo_rect_src_.y = static_cast<float>(y);
|
||||
auto mini_logo_sprite = std::make_unique<Sprite>(Resource::get()->getTexture("logo_jailgames_mini.png"));
|
||||
mini_logo_sprite->setPosition(1 + param.game.game_area.center_x - mini_logo_sprite->getWidth() / 2, 1 + y);
|
||||
Resource::get()->getTexture("logo_jailgames_mini.png")->setColor(SHADOW_TEXT_COLOR.r, SHADOW_TEXT_COLOR.g, SHADOW_TEXT_COLOR.b);
|
||||
mini_logo_sprite->setPosition(1 + POS_X - (mini_logo_sprite->getWidth() / 2), 1 + y);
|
||||
Resource::get()->getTexture("logo_jailgames_mini.png")->setColor(Colors::SHADOW_TEXT.r, Colors::SHADOW_TEXT.g, Colors::SHADOW_TEXT.b);
|
||||
mini_logo_sprite->render();
|
||||
|
||||
mini_logo_sprite->setPosition(param.game.game_area.center_x - mini_logo_sprite->getWidth() / 2, y);
|
||||
mini_logo_sprite->setPosition(POS_X - (mini_logo_sprite->getWidth() / 2), y);
|
||||
Resource::get()->getTexture("logo_jailgames_mini.png")->setColor(255, 255, 255);
|
||||
mini_logo_sprite->render();
|
||||
|
||||
// Texto con el copyright
|
||||
y += mini_logo_sprite->getHeight() + 3;
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, param.game.game_area.center_x, y, std::string(TEXT_COPYRIGHT), 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR);
|
||||
text->writeDX(Text::CENTER | Text::SHADOW, POS_X, y, std::string(TEXT_COPYRIGHT), 1, Colors::NO_COLOR_MOD, 1, Colors::SHADOW_TEXT);
|
||||
|
||||
// Resetea el renderizador
|
||||
SDL_SetRenderTarget(Screen::get()->getRenderer(), nullptr);
|
||||
@@ -258,7 +255,6 @@ void Credits::fillCanvas() {
|
||||
SDL_RenderFillRect(Screen::get()->getRenderer(), &right_black_rect_);
|
||||
|
||||
// Dibuja el rectangulo rojo
|
||||
// SDL_SetRenderDrawColor(Screen::get()->getRenderer(), 0xFF, 0, 0, 0xFF);
|
||||
const Color COLOR = color_.LIGHTEN();
|
||||
SDL_SetRenderDrawColor(Screen::get()->getRenderer(), COLOR.r, COLOR.g, COLOR.b, 0xFF);
|
||||
SDL_RenderRect(Screen::get()->getRenderer(), &border_rect_);
|
||||
@@ -385,7 +381,7 @@ void Credits::initPlayers() {
|
||||
players_.back()->setPlayingState(Player::State::CREDITS);
|
||||
|
||||
// Registra los jugadores en Options
|
||||
for (auto player : players_) {
|
||||
for (const auto &player : players_) {
|
||||
Options::keyboard.addPlayer(player);
|
||||
Options::gamepad_manager.addPlayer(player);
|
||||
}
|
||||
@@ -474,9 +470,6 @@ void Credits::resetVolume() const {
|
||||
|
||||
// Cambia el color del fondo
|
||||
void Credits::cycleColors() {
|
||||
// constexpr int UPPER_LIMIT = 255; // Límite superior
|
||||
// constexpr int LOWER_LIMIT = 80; // Límite inferior
|
||||
|
||||
constexpr int UPPER_LIMIT = 140; // Límite superior
|
||||
constexpr int LOWER_LIMIT = 30; // Límite inferior
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "balloon.h" // Para Balloon
|
||||
#include "balloon_manager.h" // Para BalloonManager
|
||||
#include "bullet.h" // Para Bullet, BulletType, BulletMoveStatus
|
||||
#include "color.h" // Para Color, FLASH_COLOR
|
||||
#include "color.h" // Para Color, Colors::FLASH
|
||||
#include "difficulty.h" // Para Code
|
||||
#include "fade.h" // Para Fade, FadeType, FadeMode
|
||||
#include "global_events.h" // Para check
|
||||
@@ -42,32 +42,23 @@
|
||||
#include "texture.h" // Para Texture
|
||||
#include "ui/service_menu.h" // Para ServiceMenu
|
||||
#ifdef _DEBUG
|
||||
#include <iostream> // Para Notifier
|
||||
#include <iostream> // Para std::cout
|
||||
|
||||
#include "ui/notifier.h" // Para Notifier
|
||||
#endif
|
||||
|
||||
// Constructor
|
||||
Game::Game(Player::Id player_id, int current_stage, bool demo)
|
||||
: renderer_(Screen::get()->getRenderer()),
|
||||
screen_(Screen::get()),
|
||||
input_(Input::get()),
|
||||
background_(std::make_unique<Background>()),
|
||||
canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.play_area.rect.w, param.game.play_area.rect.h)),
|
||||
pause_manager_(std::make_unique<PauseManager>([this](bool is_paused) { onPauseStateChanged(is_paused); })),
|
||||
fade_in_(std::make_unique<Fade>()),
|
||||
fade_out_(std::make_unique<Fade>()),
|
||||
balloon_manager_(std::make_unique<BalloonManager>()),
|
||||
tabe_(std::make_unique<Tabe>()),
|
||||
hit_(Hit(Resource::get()->getTexture("hit.png"))) {
|
||||
: renderer_(Screen::get()->getRenderer()), screen_(Screen::get()), input_(Input::get()), canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.play_area.rect.w, param.game.play_area.rect.h)), pause_manager_(std::make_unique<PauseManager>([this](bool is_paused) { onPauseStateChanged(is_paused); })), stage_manager_(std::make_unique<StageManager>()), balloon_manager_(std::make_unique<BalloonManager>(stage_manager_.get())), background_(std::make_unique<Background>(stage_manager_->getPowerNeededToReachStage(stage_manager_->getTotalStages() - 1))), fade_in_(std::make_unique<Fade>()), fade_out_(std::make_unique<Fade>()), tabe_(std::make_unique<Tabe>()), hit_(Hit(Resource::get()->getTexture("hit.png"))) {
|
||||
// Pasa variables
|
||||
demo_.enabled = demo;
|
||||
|
||||
// Otras variables
|
||||
Section::name = Section::Name::GAME;
|
||||
Section::options = Section::Options::NONE;
|
||||
Stage::init();
|
||||
Stage::number = current_stage;
|
||||
stage_manager_->initialize(Asset::get()->get("stages.txt"));
|
||||
stage_manager_->setPowerChangeCallback([this](int amount) { background_->incrementProgress(amount); });
|
||||
stage_manager_->jumpToStage(current_stage);
|
||||
|
||||
// Asigna texturas y animaciones
|
||||
setResources();
|
||||
@@ -77,15 +68,15 @@ Game::Game(Player::Id player_id, int current_stage, bool demo)
|
||||
scoreboard_ = Scoreboard::get();
|
||||
|
||||
fade_in_->setColor(param.fade.color);
|
||||
fade_in_->setPreDuration(demo_.enabled ? 80 : 0);
|
||||
fade_in_->setPreDuration(demo_.enabled ? 500 : 0);
|
||||
fade_in_->setPostDuration(0);
|
||||
fade_in_->setType(FadeType::RANDOM_SQUARE);
|
||||
fade_in_->setMode(FadeMode::IN);
|
||||
fade_in_->setType(Fade::Type::RANDOM_SQUARE2);
|
||||
fade_in_->setMode(Fade::Mode::IN);
|
||||
fade_in_->activate();
|
||||
|
||||
fade_out_->setColor(param.fade.color);
|
||||
fade_out_->setPostDuration(param.fade.post_duration);
|
||||
fade_out_->setType(FadeType::VENETIAN);
|
||||
fade_out_->setPostDuration(param.fade.post_duration_ms);
|
||||
fade_out_->setType(Fade::Type::VENETIAN);
|
||||
|
||||
background_->setPos(param.game.play_area.rect);
|
||||
|
||||
@@ -99,7 +90,6 @@ Game::Game(Player::Id player_id, int current_stage, bool demo)
|
||||
initDifficultyVars();
|
||||
initDemo(player_id);
|
||||
initPaths();
|
||||
setTotalPower();
|
||||
|
||||
// Registra callbacks
|
||||
ServiceMenu::get()->setStateChangeCallback([this](bool is_active) {
|
||||
@@ -108,15 +98,6 @@ Game::Game(Player::Id player_id, int current_stage, bool demo)
|
||||
pause_manager_->setServiceMenuPause(is_active);
|
||||
}
|
||||
});
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Si se empieza en una fase que no es la primera
|
||||
if (!demo_.enabled) {
|
||||
for (int i = 0; i < Stage::number; ++i) {
|
||||
Stage::total_power += Stage::get(i).power_to_complete;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Game::~Game() {
|
||||
@@ -238,7 +219,8 @@ void Game::updatePlayers() {
|
||||
handlePlayerCollision(player, balloon);
|
||||
|
||||
if (demo_.enabled && allPlayersAreNotPlaying()) {
|
||||
fade_out_->setType(FadeType::RANDOM_SQUARE);
|
||||
fade_out_->setType(Fade::Type::RANDOM_SQUARE2);
|
||||
fade_out_->setPostDuration(500);
|
||||
fade_out_->activate();
|
||||
}
|
||||
}
|
||||
@@ -262,33 +244,60 @@ void Game::renderPlayers() {
|
||||
|
||||
// Comprueba si hay cambio de fase y actualiza las variables
|
||||
void Game::updateStage() {
|
||||
if (Stage::power >= Stage::get(Stage::number).power_to_complete) {
|
||||
// Cambio de fase
|
||||
Stage::power = Stage::get(Stage::number).power_to_complete - Stage::power;
|
||||
++Stage::number;
|
||||
playSound("stage_change.wav");
|
||||
balloon_manager_->resetBalloonSpeed();
|
||||
screen_->flash(FLASH_COLOR, 3);
|
||||
screen_->shake();
|
||||
if (!stage_manager_->isCurrentStageCompleted()) {
|
||||
return; // No hay cambio de fase
|
||||
}
|
||||
|
||||
// Escribe el texto por pantalla
|
||||
if (Stage::number < 10) {
|
||||
std::vector<Path> paths = {paths_.at(2), paths_.at(3)};
|
||||
if (Stage::number == 9) {
|
||||
createMessage(paths, Resource::get()->getTexture("game_text_last_stage"));
|
||||
} else {
|
||||
auto text = Resource::get()->getText("04b_25_2x");
|
||||
const std::string CAPTION = Lang::getText("[GAME_TEXT] 2") + std::to_string(10 - Stage::number) + Lang::getText("[GAME_TEXT] 2A");
|
||||
createMessage(paths, text->writeToTexture(CAPTION, 1, -4));
|
||||
}
|
||||
}
|
||||
// Calcular poder sobrante antes de avanzar
|
||||
int power_overflow = 0;
|
||||
auto current_stage = stage_manager_->getCurrentStage();
|
||||
if (current_stage.has_value()) {
|
||||
int current_power = stage_manager_->getCurrentPower();
|
||||
int power_needed = current_stage->getPowerToComplete();
|
||||
power_overflow = current_power - power_needed; // Poder que sobra
|
||||
}
|
||||
|
||||
// Modifica el color de fondo al llegar a la Fase 10
|
||||
if (Stage::number == 9) {
|
||||
background_->setColor(Color(0xdd, 0x19, 0x1d).DARKEN());
|
||||
background_->setAlpha(96);
|
||||
// Intentar avanzar a la siguiente fase
|
||||
if (!stage_manager_->advanceToNextStage()) {
|
||||
// No se pudo avanzar (probablemente juego completado)
|
||||
return;
|
||||
}
|
||||
|
||||
// Aplicar el poder sobrante a la nueva fase
|
||||
if (power_overflow > 0) {
|
||||
stage_manager_->addPower(power_overflow);
|
||||
}
|
||||
|
||||
// Efectos de cambio de fase
|
||||
playSound("stage_change.wav");
|
||||
balloon_manager_->resetBalloonSpeed();
|
||||
screen_->flash(Colors::FLASH, 3);
|
||||
screen_->shake();
|
||||
|
||||
// Obtener datos de la nueva fase
|
||||
size_t current_stage_index = stage_manager_->getCurrentStageIndex();
|
||||
size_t total_stages = stage_manager_->getTotalStages();
|
||||
|
||||
// Escribir texto por pantalla
|
||||
if (current_stage_index < total_stages) { // No es la última fase
|
||||
std::vector<Path> paths = {paths_.at(2), paths_.at(3)};
|
||||
|
||||
if (current_stage_index == total_stages - 1) { // Penúltima fase (será la última)
|
||||
createMessage(paths, Resource::get()->getTexture("game_text_last_stage"));
|
||||
} else {
|
||||
auto text = Resource::get()->getText("04b_25_2x");
|
||||
const std::string CAPTION = Lang::getText("[GAME_TEXT] 2") +
|
||||
std::to_string(total_stages - current_stage_index) +
|
||||
Lang::getText("[GAME_TEXT] 2A");
|
||||
createMessage(paths, text->writeToTexture(CAPTION, 1, -4));
|
||||
}
|
||||
}
|
||||
|
||||
// Modificar color de fondo en la última fase
|
||||
if (current_stage_index == total_stages - 1) { // Última fase
|
||||
background_->setColor(Color(0xdd, 0x19, 0x1d).DARKEN());
|
||||
background_->setAlpha(96);
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el estado de fin de la partida
|
||||
@@ -330,11 +339,9 @@ void Game::updateGameStateGameOver() {
|
||||
|
||||
if (fade_out_->hasEnded()) {
|
||||
if (game_completed_counter_ > 0) {
|
||||
// Los jugadores han completado el juego
|
||||
Section::name = Section::Name::CREDITS;
|
||||
Section::name = Section::Name::CREDITS; // Los jugadores han completado el juego
|
||||
} else {
|
||||
// La partida ha terminado con la derrota de los jugadores
|
||||
Section::name = Section::Name::HI_SCORE_TABLE;
|
||||
Section::name = Section::Name::HI_SCORE_TABLE; // La partida ha terminado con la derrota de los jugadores
|
||||
}
|
||||
Section::options = Section::Options::HI_SCORE_AFTER_PLAYING;
|
||||
if (Options::audio.enabled) {
|
||||
@@ -362,13 +369,11 @@ void Game::updateGameStateCompleted() {
|
||||
|
||||
// Para la música y elimina todos los globos e items
|
||||
if (game_completed_counter_ == 0) {
|
||||
stopMusic();
|
||||
Stage::number = 9; // Deja el valor dentro de los limites
|
||||
stopMusic(); // Detiene la música
|
||||
balloon_manager_->destroyAllBalloons(); // Destruye a todos los globos
|
||||
playSound("power_ball_explosion.wav");
|
||||
destroyAllItems(); // Destruye todos los items
|
||||
Stage::power = 0; // Vuelve a dejar el poder a cero, por lo que hubiera podido subir al destruir todos los globos
|
||||
background_->setAlpha(0); // Elimina el tono rojo de las últimas pantallas
|
||||
playSound("power_ball_explosion.wav"); // Sonido de destruir todos los globos
|
||||
destroyAllItems(); // Destruye todos los items
|
||||
background_->setAlpha(0); // Elimina el tono rojo de las últimas pantallas
|
||||
}
|
||||
|
||||
// Comienza las celebraciones
|
||||
@@ -409,8 +414,9 @@ void Game::updateGameStateCompleted() {
|
||||
|
||||
// Comprueba el estado del juego
|
||||
void Game::checkState() {
|
||||
if (state_ != State::COMPLETED && Stage::number == 10) {
|
||||
if (state_ != State::COMPLETED && stage_manager_->isGameCompleted()) {
|
||||
setState(State::COMPLETED);
|
||||
background_->setState(Background::State::COMPLETED);
|
||||
}
|
||||
|
||||
if (state_ != State::GAME_OVER && allPlayersAreGameOver()) {
|
||||
@@ -450,35 +456,35 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player) {
|
||||
switch (item->getType()) {
|
||||
case ItemType::DISK: {
|
||||
player->addScore(1000, Options::settings.hi_score_table.back().score);
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(0)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(0)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(0));
|
||||
playSound("item_pickup.wav");
|
||||
break;
|
||||
}
|
||||
case ItemType::GAVINA: {
|
||||
player->addScore(2500, Options::settings.hi_score_table.back().score);
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(1)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(1)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(1));
|
||||
playSound("item_pickup.wav");
|
||||
break;
|
||||
}
|
||||
case ItemType::PACMAR: {
|
||||
player->addScore(5000, Options::settings.hi_score_table.back().score);
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(2)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(2)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(2));
|
||||
playSound("item_pickup.wav");
|
||||
break;
|
||||
}
|
||||
case ItemType::DEBIAN: {
|
||||
player->addScore(100000, Options::settings.hi_score_table.back().score);
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(6)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(6)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(6));
|
||||
playSound("debian_pickup.wav");
|
||||
break;
|
||||
}
|
||||
case ItemType::CLOCK: {
|
||||
enableTimeStopItem();
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(5)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(5)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(5));
|
||||
playSound("item_pickup.wav");
|
||||
break;
|
||||
@@ -486,11 +492,11 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player) {
|
||||
case ItemType::COFFEE: {
|
||||
if (player->getCoffees() == 2) {
|
||||
player->addScore(5000, Options::settings.hi_score_table.back().score);
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(2)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(2)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(2));
|
||||
} else {
|
||||
player->giveExtraHit();
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(4)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(4)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(4));
|
||||
}
|
||||
playSound("voice_coffee.wav");
|
||||
@@ -499,7 +505,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player) {
|
||||
case ItemType::COFFEE_MACHINE: {
|
||||
player->setPowerUp();
|
||||
coffee_machine_enabled_ = false;
|
||||
const auto X = item->getPosX() + (item->getWidth() - game_text_textures_.at(3)->getWidth()) / 2;
|
||||
const auto X = item->getPosX() + ((item->getWidth() - game_text_textures_.at(3)->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(3));
|
||||
playSound("voice_power_up.wav");
|
||||
break;
|
||||
@@ -523,17 +529,17 @@ void Game::checkBulletCollision() {
|
||||
}
|
||||
|
||||
if (checkBulletTabeCollision(bullet)) {
|
||||
break; // Exit early if bullet hit Tabe
|
||||
break;
|
||||
}
|
||||
|
||||
if (checkBulletBalloonCollision(bullet)) {
|
||||
break; // Exit early if bullet hit balloon
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Maneja la colisión entre bala y Tabe
|
||||
auto Game::checkBulletTabeCollision(std::shared_ptr<Bullet> bullet) -> bool {
|
||||
auto Game::checkBulletTabeCollision(const std::shared_ptr<Bullet> &bullet) -> bool {
|
||||
if (!tabe_->isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
@@ -565,7 +571,7 @@ void Game::handleTabeHitEffects() {
|
||||
}
|
||||
|
||||
// Maneja la colisión entre bala y globos
|
||||
auto Game::checkBulletBalloonCollision(std::shared_ptr<Bullet> bullet) -> bool {
|
||||
auto Game::checkBulletBalloonCollision(const std::shared_ptr<Bullet> &bullet) -> bool {
|
||||
for (auto &balloon : balloon_manager_->getBalloons()) {
|
||||
if (!balloon->isEnabled() || balloon->isInvulnerable()) {
|
||||
continue;
|
||||
@@ -582,7 +588,7 @@ auto Game::checkBulletBalloonCollision(std::shared_ptr<Bullet> bullet) -> bool {
|
||||
}
|
||||
|
||||
// Procesa el impacto en un globo
|
||||
void Game::processBalloonHit(std::shared_ptr<Bullet> bullet, std::shared_ptr<Balloon> balloon) {
|
||||
void Game::processBalloonHit(const std::shared_ptr<Bullet> &bullet, const std::shared_ptr<Balloon> &balloon) {
|
||||
auto player = getPlayer(bullet->getOwner());
|
||||
|
||||
handleItemDrop(balloon, player);
|
||||
@@ -592,7 +598,7 @@ void Game::processBalloonHit(std::shared_ptr<Bullet> bullet, std::shared_ptr<Bal
|
||||
}
|
||||
|
||||
// Maneja la caída de items cuando se destruye un globo
|
||||
void Game::handleItemDrop(std::shared_ptr<Balloon> balloon, std::shared_ptr<Player> player) {
|
||||
void Game::handleItemDrop(const std::shared_ptr<Balloon> &balloon, const std::shared_ptr<Player> &player) {
|
||||
const auto DROPPED_ITEM = dropItem();
|
||||
if (DROPPED_ITEM == ItemType::NONE || demo_.recording) {
|
||||
return;
|
||||
@@ -607,14 +613,13 @@ void Game::handleItemDrop(std::shared_ptr<Balloon> balloon, std::shared_ptr<Play
|
||||
}
|
||||
|
||||
// Maneja la destrucción del globo y puntuación
|
||||
void Game::handleBalloonDestruction(std::shared_ptr<Balloon> balloon, std::shared_ptr<Player> player) {
|
||||
evaluateAndSetMenace();
|
||||
|
||||
void Game::handleBalloonDestruction(std::shared_ptr<Balloon> balloon, const std::shared_ptr<Player> &player) {
|
||||
if (player->isPlaying()) {
|
||||
auto const SCORE = balloon_manager_->popBalloon(balloon) * player->getScoreMultiplier() * difficulty_score_multiplier_;
|
||||
auto const SCORE = balloon_manager_->popBalloon(std::move(balloon)) * player->getScoreMultiplier() * difficulty_score_multiplier_;
|
||||
player->addScore(SCORE, Options::settings.hi_score_table.back().score);
|
||||
player->incScoreMultiplier();
|
||||
}
|
||||
setMenace();
|
||||
updateHiScore();
|
||||
}
|
||||
|
||||
@@ -743,7 +748,7 @@ void Game::freeItems() {
|
||||
}
|
||||
|
||||
// Crea un objeto PathSprite
|
||||
void Game::createItemText(int x, std::shared_ptr<Texture> texture) {
|
||||
void Game::createItemText(int x, const std::shared_ptr<Texture> &texture) {
|
||||
path_sprites_.emplace_back(std::make_unique<PathSprite>(texture));
|
||||
|
||||
const auto W = texture->getWidth();
|
||||
@@ -766,7 +771,7 @@ void Game::createItemText(int x, std::shared_ptr<Texture> texture) {
|
||||
}
|
||||
|
||||
// Crea un objeto PathSprite
|
||||
void Game::createMessage(const std::vector<Path> &paths, std::shared_ptr<Texture> texture) {
|
||||
void Game::createMessage(const std::vector<Path> &paths, const std::shared_ptr<Texture> &texture) {
|
||||
path_sprites_.emplace_back(std::make_unique<PathSprite>(texture));
|
||||
|
||||
// Inicializa
|
||||
@@ -852,15 +857,14 @@ void Game::renderPathSprites() {
|
||||
// Acciones a realizar cuando el jugador colisiona con un globo
|
||||
void Game::handlePlayerCollision(std::shared_ptr<Player> &player, std::shared_ptr<Balloon> &balloon) {
|
||||
if (!player->isPlaying() || player->isInvulnerable()) {
|
||||
// Si no está jugando o tiene inmunidad, no hace nada
|
||||
return;
|
||||
return; // Si no está jugando o tiene inmunidad, no hace nada
|
||||
}
|
||||
|
||||
// Si tiene cafes
|
||||
if (player->hasExtraHit()) {
|
||||
// Lo pierde
|
||||
player->removeExtraHit();
|
||||
throwCoffee(player->getPosX() + (player->getWidth() / 2), player->getPosY() + (player->getHeight() / 2));
|
||||
throwCoffee(player->getPosX() + (Player::WIDTH / 2), player->getPosY() + (Player::HEIGHT / 2));
|
||||
playSound("coffee_out.wav");
|
||||
screen_->shake();
|
||||
} else {
|
||||
@@ -876,7 +880,7 @@ void Game::handlePlayerCollision(std::shared_ptr<Player> &player, std::shared_pt
|
||||
player->setPlayingState(Player::State::ROLLING);
|
||||
sendPlayerToTheBack(player);
|
||||
if (allPlayersAreNotPlaying()) {
|
||||
Stage::power_can_be_added = false; // No se puede subir poder de fase si no hay nadie jugando
|
||||
stage_manager_->disablePowerCollection();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -961,47 +965,25 @@ void Game::updateGameStates() {
|
||||
|
||||
// Actualiza el fondo
|
||||
void Game::updateBackground() {
|
||||
// Si el juego está completado, se reduce la velocidad de las nubes
|
||||
if (state_ == State::COMPLETED) {
|
||||
Stage::total_power = (Stage::total_power > 200) ? (Stage::total_power - 25) : 200;
|
||||
}
|
||||
|
||||
// Calcula la velocidad en función de los globos explotados y el total de globos a explotar para acabar el juego
|
||||
constexpr float CLOUDS_INITIAL_SPEED = 0.05F;
|
||||
constexpr float CLOUDS_FINAL_SPEED = 2.00F - CLOUDS_INITIAL_SPEED;
|
||||
const float CLOUDS_SPEED = (-CLOUDS_INITIAL_SPEED) + (-CLOUDS_FINAL_SPEED * (static_cast<float>(Stage::total_power) / total_power_to_complete_game_));
|
||||
background_->setCloudsSpeed(CLOUDS_SPEED);
|
||||
|
||||
// Calcula la transición de los diferentes fondos
|
||||
constexpr float NUM = 1525.0F; // total_power_to_complete div 4
|
||||
const float GRADIENT_NUMBER = std::min(Stage::total_power / NUM, 3.0F);
|
||||
const float PERCENT = GRADIENT_NUMBER - static_cast<int>(GRADIENT_NUMBER);
|
||||
background_->setGradientNumber(static_cast<int>(GRADIENT_NUMBER));
|
||||
background_->setTransition(PERCENT);
|
||||
|
||||
// Calcula la posición del sol
|
||||
constexpr float SUN_FINAL_POWER = NUM * 2;
|
||||
background_->setSunProgression(Stage::total_power / SUN_FINAL_POWER);
|
||||
background_->setMoonProgression(Stage::total_power / static_cast<float>(total_power_to_complete_game_));
|
||||
|
||||
// Actualiza el objeto
|
||||
background_->update();
|
||||
}
|
||||
|
||||
// Dibuja los elementos de la zona de juego en su textura
|
||||
void Game::fillCanvas() {
|
||||
// Dibujamos el contenido de la zona de juego en su textura
|
||||
// Dibuja el contenido de la zona de juego en su textura
|
||||
auto *temp = SDL_GetRenderTarget(renderer_);
|
||||
SDL_SetRenderTarget(renderer_, canvas_);
|
||||
|
||||
// Dibuja los objetos
|
||||
background_->render();
|
||||
renderPlayers();
|
||||
renderSmartSprites();
|
||||
renderItems();
|
||||
|
||||
balloon_manager_->render();
|
||||
renderSmartSprites(); // El cafe que sale cuando te golpean
|
||||
renderItems();
|
||||
tabe_->render();
|
||||
renderBullets();
|
||||
renderPlayers();
|
||||
|
||||
renderPathSprites();
|
||||
|
||||
// Deja el renderizador apuntando donde estaba
|
||||
@@ -1029,7 +1011,7 @@ void Game::run() {
|
||||
checkInput();
|
||||
#endif
|
||||
update();
|
||||
checkEvents(); // Tiene que ir antes del render
|
||||
handleEvents(); // Tiene que ir antes del render
|
||||
render();
|
||||
}
|
||||
}
|
||||
@@ -1041,7 +1023,7 @@ void Game::initPaths() {
|
||||
const auto &texture = Resource::get()->getTexture("game_text_get_ready");
|
||||
const auto W = texture->getWidth();
|
||||
const int X0 = -W;
|
||||
const int X1 = param.game.play_area.center_x - W / 2;
|
||||
const int X1 = param.game.play_area.center_x - (W / 2);
|
||||
const int X2 = param.game.play_area.rect.w;
|
||||
const int Y = param.game.play_area.center_y;
|
||||
paths_.emplace_back(createPath(X0, X1, PathType::HORIZONTAL, Y, 80, easeOutQuint), 20);
|
||||
@@ -1053,7 +1035,7 @@ void Game::initPaths() {
|
||||
const auto &texture = Resource::get()->getTexture("game_text_last_stage");
|
||||
const auto H = texture->getHeight();
|
||||
const int Y0 = param.game.play_area.rect.h - H;
|
||||
const int Y1 = param.game.play_area.center_y - H / 2;
|
||||
const int Y1 = param.game.play_area.center_y - (H / 2);
|
||||
const int Y2 = -H;
|
||||
const int X = param.game.play_area.center_x;
|
||||
paths_.emplace_back(createPath(Y0, Y1, PathType::VERTICAL, X, 80, easeOutQuint), 20);
|
||||
@@ -1066,9 +1048,9 @@ void Game::initPaths() {
|
||||
const auto W = texture->getWidth();
|
||||
const auto H = texture->getHeight();
|
||||
const int X0 = -W;
|
||||
const int X1 = param.game.play_area.center_x - W / 2;
|
||||
const int X1 = param.game.play_area.center_x - (W / 2);
|
||||
const int X2 = param.game.play_area.rect.w;
|
||||
const int Y = param.game.play_area.center_y - H / 2 - 20;
|
||||
const int Y = param.game.play_area.center_y - (H / 2) - 20;
|
||||
paths_.emplace_back(createPath(X0, X1, PathType::HORIZONTAL, Y, 80, easeOutQuint), 400);
|
||||
paths_.emplace_back(createPath(X1, X2, PathType::HORIZONTAL, Y, 80, easeInQuint), 0);
|
||||
}
|
||||
@@ -1079,9 +1061,9 @@ void Game::initPaths() {
|
||||
const auto W = texture->getWidth();
|
||||
const auto H = texture->getHeight();
|
||||
const int X0 = param.game.play_area.rect.w;
|
||||
const int X1 = param.game.play_area.center_x - W / 2;
|
||||
const int X1 = param.game.play_area.center_x - (W / 2);
|
||||
const int X2 = -W;
|
||||
const int Y = param.game.play_area.center_y + H / 2 - 20;
|
||||
const int Y = param.game.play_area.center_y + (H / 2) - 20;
|
||||
paths_.emplace_back(createPath(X0, X1, PathType::HORIZONTAL, Y, 80, easeOutQuint), 400);
|
||||
paths_.emplace_back(createPath(X1, X2, PathType::HORIZONTAL, Y, 80, easeInQuint), 0);
|
||||
}
|
||||
@@ -1090,7 +1072,7 @@ void Game::initPaths() {
|
||||
// Actualiza las variables de ayuda
|
||||
void Game::updateHelper() {
|
||||
// Solo ofrece ayuda cuando la amenaza es elevada
|
||||
if (menace_current_ > 15) {
|
||||
if (menace_ > 15) {
|
||||
helper_.need_coffee = true;
|
||||
helper_.need_coffee_machine = true;
|
||||
for (const auto &player : players_) {
|
||||
@@ -1135,7 +1117,7 @@ auto Game::allPlayersAreNotPlaying() -> bool {
|
||||
}
|
||||
|
||||
// Comprueba los eventos que hay en cola
|
||||
void Game::checkEvents() {
|
||||
void Game::handleEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
@@ -1152,9 +1134,9 @@ void Game::checkEvents() {
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
checkDebugEvents(event);
|
||||
handleDebugEvents(event);
|
||||
#endif
|
||||
GlobalEvents::check(event);
|
||||
GlobalEvents::handle(event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1166,12 +1148,11 @@ void Game::updateScoreboard() {
|
||||
}
|
||||
|
||||
// Resto de marcador
|
||||
scoreboard_->setStage(Stage::number + 1);
|
||||
scoreboard_->setPower((float)Stage::power / (float)Stage::get(Stage::number).power_to_complete);
|
||||
scoreboard_->setStage(stage_manager_->getCurrentStageIndex() + 1);
|
||||
scoreboard_->setPower(stage_manager_->getCurrentStageProgressFraction());
|
||||
scoreboard_->setHiScore(hi_score_.score);
|
||||
scoreboard_->setHiScoreName(hi_score_.name);
|
||||
|
||||
// Lógica del marcador
|
||||
scoreboard_->update();
|
||||
}
|
||||
|
||||
@@ -1250,7 +1231,7 @@ void Game::checkInput() {
|
||||
// Verifica si alguno de los controladores ha solicitado una pausa y actualiza el estado de pausa del juego.
|
||||
void Game::checkPauseInput() {
|
||||
// Comprueba los mandos
|
||||
for (auto gamepad : input_->getGamepads()) {
|
||||
for (const auto &gamepad : input_->getGamepads()) {
|
||||
if (input_->checkAction(Input::Action::PAUSE, Input::DO_NOT_ALLOW_REPEAT, Input::DO_NOT_CHECK_KEYBOARD, gamepad)) {
|
||||
pause_manager_->togglePlayerPause();
|
||||
return;
|
||||
@@ -1313,7 +1294,7 @@ void Game::handleFireInput(const std::shared_ptr<Player> &player, BulletType bul
|
||||
switch (bullet_type) {
|
||||
case BulletType::UP:
|
||||
player->setInput(Input::Action::FIRE_CENTER);
|
||||
bullet.x = 2 + player->getPosX() + (player->getWidth() - Bullet::WIDTH) / 2;
|
||||
bullet.x = 2 + player->getPosX() + (Player::WIDTH - Bullet::WIDTH) / 2;
|
||||
bullet.y = player->getPosY() - (Bullet::HEIGHT / 2);
|
||||
break;
|
||||
case BulletType::LEFT:
|
||||
@@ -1323,7 +1304,7 @@ void Game::handleFireInput(const std::shared_ptr<Player> &player, BulletType bul
|
||||
break;
|
||||
case BulletType::RIGHT:
|
||||
player->setInput(Input::Action::FIRE_RIGHT);
|
||||
bullet.x = player->getPosX() + player->getWidth() - (Bullet::WIDTH / 2);
|
||||
bullet.x = player->getPosX() + Player::WIDTH - (Bullet::WIDTH / 2);
|
||||
bullet.y = player->getPosY();
|
||||
break;
|
||||
default:
|
||||
@@ -1411,7 +1392,7 @@ void Game::handleFireInputs(const std::shared_ptr<Player> &player, bool autofire
|
||||
// Maneja la continuación del jugador cuando no está jugando, permitiendo que continúe si se pulsa el botón de inicio.
|
||||
void Game::handlePlayerContinueInput(const std::shared_ptr<Player> &player) {
|
||||
if (input_->checkAction(Input::Action::START, Input::DO_NOT_ALLOW_REPEAT, player->getUsesKeyboard(), player->getGamepad())) {
|
||||
player->setPlayingState(Player::State::RESPAWNING);
|
||||
player->setPlayingState(Player::State::RECOVER);
|
||||
player->addCredit();
|
||||
sendPlayerToTheFront(player);
|
||||
}
|
||||
@@ -1488,12 +1469,7 @@ void Game::initDemo(Player::Id player_id) {
|
||||
constexpr auto NUM_DEMOS = 3;
|
||||
const auto DEMO = rand() % NUM_DEMOS;
|
||||
constexpr std::array<int, NUM_DEMOS> STAGES = {0, 3, 5};
|
||||
Stage::number = STAGES[DEMO];
|
||||
}
|
||||
|
||||
// Actualiza el numero de globos explotados según la fase del modo demostración
|
||||
for (int i = 0; i < Stage::number; ++i) {
|
||||
Stage::total_power += Stage::get(i).power_to_complete;
|
||||
stage_manager_->jumpToStage(STAGES.at(DEMO));
|
||||
}
|
||||
|
||||
// Activa o no al otro jugador
|
||||
@@ -1505,8 +1481,10 @@ void Game::initDemo(Player::Id player_id) {
|
||||
|
||||
// Asigna cafes a los jugadores
|
||||
for (auto &player : players_) {
|
||||
for (int i = 0; i < rand() % 3; ++i) {
|
||||
player->giveExtraHit();
|
||||
if (player->isPlaying()) {
|
||||
for (int i = 0; i < rand() % 3; ++i) {
|
||||
player->giveExtraHit();
|
||||
}
|
||||
}
|
||||
|
||||
player->setInvulnerable(true);
|
||||
@@ -1529,14 +1507,6 @@ void Game::initDemo(Player::Id player_id) {
|
||||
demo_.counter = 0;
|
||||
}
|
||||
|
||||
// Calcula el poder total necesario para completar el juego
|
||||
void Game::setTotalPower() {
|
||||
total_power_to_complete_game_ = 0;
|
||||
for (const auto &stage : Stage::stages) {
|
||||
total_power_to_complete_game_ += stage.power_to_complete;
|
||||
}
|
||||
}
|
||||
|
||||
// Inicializa el marcador
|
||||
void Game::initScoreboard() {
|
||||
scoreboard_->setPos(param.scoreboard.rect);
|
||||
@@ -1596,6 +1566,7 @@ void Game::initPlayers(Player::Id player_id) {
|
||||
config_player1.animations = player_animations_;
|
||||
config_player1.hi_score_table = &Options::settings.hi_score_table;
|
||||
config_player1.glowing_entry = &Options::settings.glowing_entries.at(static_cast<int>(Player::Id::PLAYER1) - 1);
|
||||
config_player1.stage_info = stage_manager_.get();
|
||||
|
||||
auto player1 = std::make_unique<Player>(config_player1);
|
||||
player1->setScoreBoardPanel(Scoreboard::Id::LEFT);
|
||||
@@ -1616,6 +1587,7 @@ void Game::initPlayers(Player::Id player_id) {
|
||||
config_player2.animations = player_animations_;
|
||||
config_player2.hi_score_table = &Options::settings.hi_score_table;
|
||||
config_player2.glowing_entry = &Options::settings.glowing_entries.at(static_cast<int>(Player::Id::PLAYER2) - 1);
|
||||
config_player2.stage_info = stage_manager_.get();
|
||||
|
||||
auto player2 = std::make_unique<Player>(config_player2);
|
||||
player2->setScoreBoardPanel(Scoreboard::Id::RIGHT);
|
||||
@@ -1638,7 +1610,7 @@ void Game::initPlayers(Player::Id player_id) {
|
||||
}
|
||||
|
||||
// Registra los jugadores en Options
|
||||
for (auto player : players_) {
|
||||
for (const auto &player : players_) {
|
||||
Options::keyboard.addPlayer(player);
|
||||
Options::gamepad_manager.addPlayer(player);
|
||||
}
|
||||
@@ -1682,7 +1654,8 @@ void Game::updateDemo() {
|
||||
|
||||
// Activa el fundido antes de acabar con los datos de la demo
|
||||
if (demo_.counter == TOTAL_DEMO_DATA - 200) {
|
||||
fade_out_->setType(FadeType::RANDOM_SQUARE);
|
||||
fade_out_->setType(Fade::Type::RANDOM_SQUARE2);
|
||||
fade_out_->setPostDuration(param.fade.post_duration_ms);
|
||||
fade_out_->activate();
|
||||
}
|
||||
|
||||
@@ -1720,7 +1693,7 @@ void Game::updateGameStateFadeIn() {
|
||||
if (fade_in_->hasEnded()) {
|
||||
setState(State::ENTERING_PLAYER);
|
||||
balloon_manager_->createTwoBigBalloons();
|
||||
evaluateAndSetMenace();
|
||||
setMenace();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1755,7 +1728,7 @@ void Game::updateGameStateShowingGetReadyMessage() {
|
||||
void Game::updateGameStatePlaying() {
|
||||
#ifdef _DEBUG
|
||||
if (auto_pop_balloons_) {
|
||||
Stage::addPower(5);
|
||||
stage_manager_->addPower(5);
|
||||
}
|
||||
#endif
|
||||
updatePlayers();
|
||||
@@ -1789,25 +1762,31 @@ void Game::cleanVectors() {
|
||||
|
||||
// Gestiona el nivel de amenaza
|
||||
void Game::updateMenace() {
|
||||
if (state_ == State::PLAYING) {
|
||||
const auto STAGE = Stage::get(Stage::number);
|
||||
const float PERCENT = Stage::power / STAGE.power_to_complete;
|
||||
const int DIFFERENCE = STAGE.max_menace - STAGE.min_menace;
|
||||
if (state_ != State::PLAYING) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Aumenta el nivel de amenaza en función de la puntuación
|
||||
menace_threshold_ = STAGE.min_menace + (DIFFERENCE * PERCENT);
|
||||
auto current_stage = stage_manager_->getCurrentStage();
|
||||
if (!current_stage.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Si el nivel de amenza es inferior al umbral
|
||||
if (menace_current_ < menace_threshold_) {
|
||||
balloon_manager_->deployRandomFormation(Stage::number); // Crea una formación aleatoria de globos
|
||||
evaluateAndSetMenace(); // Recalcula el nivel de amenaza con el nuevo globo
|
||||
}
|
||||
const auto &stage = current_stage.value();
|
||||
const double FRACTION = stage_manager_->getCurrentStageProgressFraction();
|
||||
const int DIFFERENCE = stage.getMaxMenace() - stage.getMinMenace();
|
||||
|
||||
// Aumenta el nivel de amenaza en función del progreso de la fase
|
||||
menace_threshold_ = stage.getMinMenace() + (DIFFERENCE * FRACTION);
|
||||
|
||||
if (menace_ < menace_threshold_) {
|
||||
balloon_manager_->deployRandomFormation(stage_manager_->getCurrentStageIndex());
|
||||
setMenace();
|
||||
}
|
||||
}
|
||||
|
||||
// Calcula y establece el valor de amenaza en funcion de los globos activos
|
||||
void Game::evaluateAndSetMenace() {
|
||||
menace_current_ = balloon_manager_->getMenace();
|
||||
void Game::setMenace() {
|
||||
menace_ = balloon_manager_->getMenace();
|
||||
}
|
||||
|
||||
// Actualiza la velocidad de los globos en funcion del poder acumulado de la fase
|
||||
@@ -1816,7 +1795,7 @@ void Game::checkAndUpdateBalloonSpeed() {
|
||||
return;
|
||||
}
|
||||
|
||||
const float PERCENT = static_cast<float>(Stage::power) / Stage::get(Stage::number).power_to_complete;
|
||||
const float PERCENT = stage_manager_->getCurrentStageProgressFraction();
|
||||
constexpr std::array<float, 4> THRESHOLDS = {0.2F, 0.4F, 0.6F, 0.8F};
|
||||
|
||||
for (size_t i = 0; i < std::size(THRESHOLDS); ++i) {
|
||||
@@ -1890,14 +1869,13 @@ void Game::onPauseStateChanged(bool is_paused) {
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Comprueba los eventos en el modo DEBUG
|
||||
void Game::checkDebugEvents(const SDL_Event &event) {
|
||||
void Game::handleDebugEvents(const SDL_Event &event) {
|
||||
static int formation_id_ = 0;
|
||||
if (event.type == SDL_EVENT_KEY_DOWN && static_cast<int>(event.key.repeat) == 0) {
|
||||
switch (event.key.key) {
|
||||
case SDLK_1: // Crea una powerball
|
||||
{
|
||||
// balloon_manager_->createPowerBall();
|
||||
// throwCoffee(players_.at(0)->getPosX() + (players_.at(0)->getWidth() / 2), players_.at(0)->getPosY() + (players_.at(0)->getHeight() / 2));
|
||||
balloon_manager_->createPowerBall();
|
||||
break;
|
||||
}
|
||||
case SDLK_2: // Activa o desactiva la aparición de globos
|
||||
@@ -1925,7 +1903,7 @@ void Game::checkDebugEvents(const SDL_Event &event) {
|
||||
}
|
||||
case SDLK_5: // 5.000
|
||||
{
|
||||
const int X = players_.at(0)->getPosX() + (players_.at(0)->getWidth() - game_text_textures_[3]->getWidth()) / 2;
|
||||
const int X = players_.at(0)->getPosX() + ((Player::WIDTH - game_text_textures_[3]->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(2));
|
||||
break;
|
||||
}
|
||||
@@ -1936,7 +1914,7 @@ void Game::checkDebugEvents(const SDL_Event &event) {
|
||||
}
|
||||
case SDLK_7: // 100.000
|
||||
{
|
||||
const int X = players_.at(0)->getPosX() + (players_.at(0)->getWidth() - game_text_textures_[3]->getWidth()) / 2;
|
||||
const int X = players_.at(0)->getPosX() + ((Player::WIDTH - game_text_textures_[3]->getWidth()) / 2);
|
||||
createItemText(X, game_text_textures_.at(6));
|
||||
break;
|
||||
}
|
||||
@@ -1957,14 +1935,14 @@ void Game::checkDebugEvents(const SDL_Event &event) {
|
||||
++formation_id_;
|
||||
balloon_manager_->destroyAllBalloons();
|
||||
balloon_manager_->deployFormation(formation_id_);
|
||||
std::cout << formation_id_ << std::endl;
|
||||
std::cout << formation_id_ << '\n';
|
||||
break;
|
||||
}
|
||||
case SDLK_KP_MINUS: {
|
||||
--formation_id_;
|
||||
balloon_manager_->destroyAllBalloons();
|
||||
balloon_manager_->deployFormation(formation_id_);
|
||||
std::cout << formation_id_ << std::endl;
|
||||
std::cout << formation_id_ << '\n';
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "path_sprite.h" // Para PathSprite, Path
|
||||
#include "player.h" // Para Player
|
||||
#include "smart_sprite.h" // Para SmartSprite
|
||||
#include "stage.h" // Para StageManager
|
||||
#include "utils.h" // Para Demo
|
||||
|
||||
class Background;
|
||||
@@ -32,29 +33,29 @@ namespace Difficulty {
|
||||
enum class Code;
|
||||
} // namespace Difficulty
|
||||
|
||||
// Clase Game
|
||||
// --- Clase Game: gestor principal del juego ---
|
||||
class Game {
|
||||
public:
|
||||
// --- Constantes ---
|
||||
static constexpr bool DEMO_OFF = false;
|
||||
static constexpr bool DEMO_ON = true;
|
||||
static constexpr bool DEMO_OFF = false; // Modo demo desactivado
|
||||
static constexpr bool DEMO_ON = true; // Modo demo activado
|
||||
|
||||
// --- Constructor y destructor ---
|
||||
Game(Player::Id player_id, int current_stage, bool demo);
|
||||
~Game();
|
||||
Game(Player::Id player_id, int current_stage, bool demo); // Constructor principal
|
||||
~Game(); // Destructor
|
||||
|
||||
// --- Bucle principal ---
|
||||
void run();
|
||||
void run(); // Ejecuta el bucle principal del juego
|
||||
|
||||
private:
|
||||
// --- Tipos internos ---
|
||||
// --- Enums ---
|
||||
enum class State {
|
||||
FADE_IN,
|
||||
ENTERING_PLAYER,
|
||||
SHOWING_GET_READY_MESSAGE,
|
||||
PLAYING,
|
||||
COMPLETED,
|
||||
GAME_OVER,
|
||||
FADE_IN, // Transición de entrada
|
||||
ENTERING_PLAYER, // Jugador entrando
|
||||
SHOWING_GET_READY_MESSAGE, // Mostrando mensaje de preparado
|
||||
PLAYING, // Jugando
|
||||
COMPLETED, // Juego completado
|
||||
GAME_OVER, // Fin del juego
|
||||
};
|
||||
|
||||
// --- Constantes internas ---
|
||||
@@ -100,8 +101,6 @@ class Game {
|
||||
Input *input_; // Manejador de entrada
|
||||
Scoreboard *scoreboard_; // Objeto para dibujar el marcador
|
||||
|
||||
std::unique_ptr<Background> background_; // Objeto para dibujar el fondo del juego
|
||||
|
||||
SDL_Texture *canvas_; // Textura para dibujar la zona de juego
|
||||
|
||||
std::vector<std::shared_ptr<Player>> players_; // Vector con los jugadores
|
||||
@@ -119,9 +118,11 @@ class Game {
|
||||
std::vector<std::vector<std::string>> player_animations_; // Vector con las animaciones del jugador
|
||||
|
||||
std::unique_ptr<PauseManager> pause_manager_; // Objeto para gestionar la pausa
|
||||
std::unique_ptr<StageManager> stage_manager_; // Objeto para gestionar las fases
|
||||
std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos
|
||||
std::unique_ptr<Background> background_; // Objeto para dibujar el fondo del juego
|
||||
std::unique_ptr<Fade> fade_in_; // Objeto para renderizar fades
|
||||
std::unique_ptr<Fade> fade_out_; // Objeto para renderizar fades
|
||||
std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos
|
||||
std::unique_ptr<Tabe> tabe_; // Objeto para gestionar el Tabe Volaor
|
||||
std::vector<Path> paths_; // Vector con los recorridos precalculados almacenados
|
||||
|
||||
@@ -141,8 +142,7 @@ class Game {
|
||||
int game_completed_counter_ = 0; // Contador para el tramo final, cuando se ha completado la partida y ya no aparecen más globos
|
||||
int game_over_counter_ = GAME_OVER_COUNTER; // Contador para el estado de fin de partida
|
||||
int time_stopped_counter_ = 0; // Temporizador para llevar la cuenta del tiempo detenido
|
||||
int total_power_to_complete_game_; // La suma del poder necesario para completar todas las fases
|
||||
int menace_current_ = 0; // Nivel de amenaza actual
|
||||
int menace_ = 0; // Nivel de amenaza actual
|
||||
int menace_threshold_ = 0; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el número de globos
|
||||
State state_ = State::FADE_IN; // Estado
|
||||
std::vector<std::shared_ptr<Player>> players_to_put_at_back_;
|
||||
@@ -156,7 +156,7 @@ class Game {
|
||||
// --- Ciclo principal del juego ---
|
||||
void update(); // Actualiza la lógica principal del juego
|
||||
void render(); // Renderiza todos los elementos del juego
|
||||
void checkEvents(); // Procesa los eventos del sistema en cola
|
||||
void handleEvents(); // Procesa los eventos del sistema en cola
|
||||
void checkState(); // Verifica y actualiza el estado actual del juego
|
||||
void setState(State state); // Cambia el estado del juego
|
||||
void cleanVectors(); // Limpia vectores de elementos deshabilitados
|
||||
@@ -216,9 +216,9 @@ class Game {
|
||||
void freeBullets(); // Libera memoria del vector de balas
|
||||
|
||||
// --- Colisiones específicas de balas ---
|
||||
auto checkBulletTabeCollision(std::shared_ptr<Bullet> bullet) -> bool; // Detecta colisión bala-Tabe
|
||||
auto checkBulletBalloonCollision(std::shared_ptr<Bullet> bullet) -> bool; // Detecta colisión bala-globo
|
||||
void processBalloonHit(std::shared_ptr<Bullet> bullet, std::shared_ptr<Balloon> balloon); // Procesa impacto en globo
|
||||
auto checkBulletTabeCollision(const std::shared_ptr<Bullet> &bullet) -> bool; // Detecta colisión bala-Tabe
|
||||
auto checkBulletBalloonCollision(const std::shared_ptr<Bullet> &bullet) -> bool; // Detecta colisión bala-globo
|
||||
void processBalloonHit(const std::shared_ptr<Bullet> &bullet, const std::shared_ptr<Balloon> &balloon); // Procesa impacto en globo
|
||||
|
||||
// --- Sistema de ítems y power-ups ---
|
||||
void updateItems(); // Actualiza posición y estado de todos los ítems
|
||||
@@ -235,7 +235,7 @@ class Game {
|
||||
void throwCoffee(int x, int y); // Crea efecto de café arrojado al ser golpeado
|
||||
|
||||
// --- Gestión de caída de ítems ---
|
||||
void handleItemDrop(std::shared_ptr<Balloon> balloon, std::shared_ptr<Player> player); // Gestiona caída de ítem desde globo
|
||||
void handleItemDrop(const std::shared_ptr<Balloon> &balloon, const std::shared_ptr<Player> &player); // Gestiona caída de ítem desde globo
|
||||
|
||||
// --- Sprites inteligentes (smartsprites) ---
|
||||
void updateSmartSprites(); // Actualiza todos los sprites con lógica propia
|
||||
@@ -249,22 +249,21 @@ class Game {
|
||||
void initPaths(); // Inicializa rutas predefinidas para animaciones
|
||||
|
||||
// --- Creación de sprites especiales ---
|
||||
void createItemText(int x, std::shared_ptr<Texture> texture); // Crea texto animado para ítems
|
||||
void createMessage(const std::vector<Path> &paths, std::shared_ptr<Texture> texture); // Crea mensaje con animación por ruta
|
||||
void createItemText(int x, const std::shared_ptr<Texture> &texture); // Crea texto animado para ítems
|
||||
void createMessage(const std::vector<Path> &paths, const std::shared_ptr<Texture> &texture); // Crea mensaje con animación por ruta
|
||||
|
||||
// --- Sistema de globos y enemigos ---
|
||||
void handleBalloonDestruction(std::shared_ptr<Balloon> balloon, std::shared_ptr<Player> player); // Procesa destrucción de globo
|
||||
void handleTabeHitEffects(); // Gestiona efectos al golpear a Tabe
|
||||
void checkAndUpdateBalloonSpeed(); // Ajusta velocidad de globos según progreso
|
||||
void handleBalloonDestruction(std::shared_ptr<Balloon> balloon, const std::shared_ptr<Player> &player); // Procesa destrucción de globo
|
||||
void handleTabeHitEffects(); // Gestiona efectos al golpear a Tabe
|
||||
void checkAndUpdateBalloonSpeed(); // Ajusta velocidad de globos según progreso
|
||||
|
||||
// --- Gestión de fases y progresión ---
|
||||
void updateStage(); // Verifica y actualiza cambio de fase
|
||||
void setTotalPower(); // Calcula poder total necesario para completar el juego
|
||||
void initDifficultyVars(); // Inicializa variables de dificultad
|
||||
|
||||
// --- Sistema de amenaza ---
|
||||
void updateMenace(); // Gestiona el nivel de amenaza del juego
|
||||
void evaluateAndSetMenace(); // Calcula y establece amenaza según globos activos
|
||||
void updateMenace(); // Gestiona el nivel de amenaza del juego
|
||||
void setMenace(); // Calcula y establece amenaza según globos activos
|
||||
|
||||
// --- Puntuación y marcador ---
|
||||
void updateHiScore(); // Actualiza el récord máximo si es necesario
|
||||
@@ -300,6 +299,6 @@ class Game {
|
||||
|
||||
// --- Depuración (solo en modo DEBUG) ---
|
||||
#ifdef _DEBUG
|
||||
void checkDebugEvents(const SDL_Event &event); // Comprueba los eventos en el modo DEBUG
|
||||
void handleDebugEvents(const SDL_Event &event); // Comprueba los eventos en el modo DEBUG
|
||||
#endif
|
||||
};
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "audio.h" // Para Audio
|
||||
#include "background.h" // Para Background
|
||||
#include "color.h" // Para Color, easeOutQuint, NO_TEXT_COLOR
|
||||
#include "color.h" // Para Color, easeOutQuint, Colors::NO_COLOR_MOD
|
||||
#include "fade.h" // Para Fade, FadeMode, FadeType
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
@@ -29,15 +29,7 @@
|
||||
|
||||
// Constructor
|
||||
HiScoreTable::HiScoreTable()
|
||||
: renderer_(Screen::get()->getRenderer()),
|
||||
backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
|
||||
fade_(std::make_unique<Fade>()),
|
||||
background_(std::make_unique<Background>()),
|
||||
|
||||
ticks_(0),
|
||||
view_area_(SDL_FRect{0, 0, param.game.width, param.game.height}),
|
||||
fade_mode_(FadeMode::IN),
|
||||
background_fade_color_(Color(0, 0, 0)) {
|
||||
: renderer_(Screen::get()->getRenderer()), backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), fade_(std::make_unique<Fade>()), background_(std::make_unique<Background>()), ticks_(0), view_area_(SDL_FRect{0, 0, param.game.width, param.game.height}), fade_mode_(Fade::Mode::IN), background_fade_color_(Color(0, 0, 0)) {
|
||||
// Inicializa el resto
|
||||
Section::name = Section::Name::HI_SCORE_TABLE;
|
||||
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
|
||||
@@ -108,7 +100,7 @@ void HiScoreTable::fillTexture() {
|
||||
void HiScoreTable::checkEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
GlobalEvents::check(event);
|
||||
GlobalEvents::handle(event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,13 +125,13 @@ void HiScoreTable::run() {
|
||||
void HiScoreTable::updateFade() {
|
||||
fade_->update();
|
||||
|
||||
if (fade_->hasEnded() && fade_mode_ == FadeMode::IN) {
|
||||
if (fade_->hasEnded() && fade_mode_ == Fade::Mode::IN) {
|
||||
fade_->reset();
|
||||
fade_mode_ = FadeMode::OUT;
|
||||
fade_mode_ = Fade::Mode::OUT;
|
||||
fade_->setMode(fade_mode_);
|
||||
}
|
||||
|
||||
if (fade_->hasEnded() && fade_mode_ == FadeMode::OUT) {
|
||||
if (fade_->hasEnded() && fade_mode_ == Fade::Mode::OUT) {
|
||||
Section::name = (Section::options == Section::Options::HI_SCORE_AFTER_PLAYING)
|
||||
? Section::Name::TITLE
|
||||
: Section::Name::INSTRUCTIONS;
|
||||
@@ -178,11 +170,11 @@ void HiScoreTable::createSprites() {
|
||||
float backbuffer_height;
|
||||
SDL_GetTextureSize(backbuffer_, &backbuffer_width, &backbuffer_height);
|
||||
|
||||
constexpr int ENTRY_LENGHT = 22;
|
||||
constexpr int ENTRY_LENGTH = 22;
|
||||
constexpr int MAX_NAMES = 10;
|
||||
const int SPACE_BETWEEN_HEADER = entry_text->getCharacterSize() * 4;
|
||||
const int SPACE_BETWEEN_LINES = entry_text->getCharacterSize() * 2;
|
||||
const int SIZE = SPACE_BETWEEN_HEADER + SPACE_BETWEEN_LINES * (MAX_NAMES - 1) + entry_text->getCharacterSize();
|
||||
const int SIZE = SPACE_BETWEEN_HEADER + (SPACE_BETWEEN_LINES * (MAX_NAMES - 1)) + entry_text->getCharacterSize();
|
||||
const int FIRST_LINE = (param.game.height - SIZE) / 2;
|
||||
|
||||
// Crea el sprite para el texto de cabecera
|
||||
@@ -191,13 +183,13 @@ void HiScoreTable::createSprites() {
|
||||
|
||||
// Crea los sprites para las entradas en la tabla de puntuaciones
|
||||
const int ANIMATION = rand() % 4;
|
||||
const std::string SAMPLE_LINE(ENTRY_LENGHT + 3, ' ');
|
||||
auto sample_entry = std::make_unique<Sprite>(entry_text->writeDXToTexture(Text::SHADOW, SAMPLE_LINE, 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR));
|
||||
const std::string SAMPLE_LINE(ENTRY_LENGTH + 3, ' ');
|
||||
auto sample_entry = std::make_unique<Sprite>(entry_text->writeDXToTexture(Text::SHADOW, SAMPLE_LINE, 1, Colors::NO_COLOR_MOD, 1, Colors::SHADOW_TEXT));
|
||||
const auto ENTRY_WIDTH = sample_entry->getWidth();
|
||||
for (int i = 0; i < MAX_NAMES; ++i) {
|
||||
const auto TABLE_POSITION = format(i + 1) + ". ";
|
||||
const auto SCORE = format(Options::settings.hi_score_table.at(i).score);
|
||||
const auto NUM_DOTS = ENTRY_LENGHT - Options::settings.hi_score_table.at(i).name.size() - SCORE.size();
|
||||
const auto NUM_DOTS = ENTRY_LENGTH - Options::settings.hi_score_table.at(i).name.size() - SCORE.size();
|
||||
const auto *const ONE_CC = Options::settings.hi_score_table.at(i).one_credit_complete ? " }" : "";
|
||||
std::string dots;
|
||||
for (int j = 0; j < (int)NUM_DOTS; ++j) {
|
||||
@@ -205,7 +197,7 @@ void HiScoreTable::createSprites() {
|
||||
}
|
||||
const auto LINE = TABLE_POSITION + Options::settings.hi_score_table.at(i).name + dots + SCORE + ONE_CC;
|
||||
|
||||
entry_names_.emplace_back(std::make_shared<PathSprite>(entry_text->writeDXToTexture(Text::SHADOW, LINE, 1, NO_TEXT_COLOR, 1, SHADOW_TEXT_COLOR)));
|
||||
entry_names_.emplace_back(std::make_shared<PathSprite>(entry_text->writeDXToTexture(Text::SHADOW, LINE, 1, Colors::NO_COLOR_MOD, 1, Colors::SHADOW_TEXT)));
|
||||
const int DEFAULT_POS_X = (backbuffer_width - ENTRY_WIDTH) / 2;
|
||||
const int POS_X = (i < 9) ? DEFAULT_POS_X : DEFAULT_POS_X - entry_text->getCharacterSize();
|
||||
const int POS_Y = (i * SPACE_BETWEEN_LINES) + FIRST_LINE + SPACE_BETWEEN_HEADER;
|
||||
@@ -272,14 +264,15 @@ void HiScoreTable::updateSprites() {
|
||||
// Inicializa el fade
|
||||
void HiScoreTable::initFade() {
|
||||
fade_->setColor(param.fade.color);
|
||||
fade_->setType(FadeType::RANDOM_SQUARE);
|
||||
fade_->setPostDuration(param.fade.post_duration);
|
||||
fade_->setType(Fade::Type::RANDOM_SQUARE2);
|
||||
fade_->setPostDuration(param.fade.post_duration_ms);
|
||||
fade_->setMode(fade_mode_);
|
||||
fade_->activate();
|
||||
}
|
||||
|
||||
// Inicializa el fondo
|
||||
void HiScoreTable::initBackground() {
|
||||
background_->setManualMode(true);
|
||||
background_->setPos(param.game.game_area.rect);
|
||||
background_->setCloudsSpeed(-0.1F);
|
||||
|
||||
@@ -291,7 +284,7 @@ void HiScoreTable::initBackground() {
|
||||
background_->setTransition(0.0F);
|
||||
background_->setSunProgression(1.0F);
|
||||
background_->setMoonProgression(0.0F);
|
||||
background_fade_color_ = GREEN_SKY_COLOR;
|
||||
background_fade_color_ = Colors::GREEN_SKY;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -301,7 +294,7 @@ void HiScoreTable::initBackground() {
|
||||
background_->setTransition(0.0F);
|
||||
background_->setSunProgression(0.65F);
|
||||
background_->setMoonProgression(0.0F);
|
||||
background_fade_color_ = PINK_SKY_COLOR;
|
||||
background_fade_color_ = Colors::PINK_SKY;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -311,7 +304,7 @@ void HiScoreTable::initBackground() {
|
||||
background_->setTransition(0.0F);
|
||||
background_->setSunProgression(0.0F);
|
||||
background_->setMoonProgression(0.0F);
|
||||
background_fade_color_ = BLUE_SKY_COLOR;
|
||||
background_fade_color_ = Colors::BLUE_SKY;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -322,7 +315,7 @@ void HiScoreTable::initBackground() {
|
||||
|
||||
// Obtiene un color del vector de colores de entradas
|
||||
auto HiScoreTable::getEntryColor(int counter) -> Color {
|
||||
int cycle_length = entry_colors_.size() * 2 - 2;
|
||||
int cycle_length = (entry_colors_.size() * 2) - 2;
|
||||
size_t n = counter % cycle_length;
|
||||
|
||||
size_t index;
|
||||
|
||||
@@ -7,24 +7,19 @@
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "color.h" // Para Color
|
||||
#include "fade.h" // Para Fade
|
||||
#include "path_sprite.h" // Para Path, PathSprite (ptr only)
|
||||
|
||||
class Background;
|
||||
class Fade;
|
||||
class Sprite;
|
||||
enum class FadeMode : Uint8;
|
||||
|
||||
/*
|
||||
Esta clase gestiona un estado del programa. Se encarga de mostrar la tabla con las puntuaciones
|
||||
más altas. Para ello utiliza un objeto que se encarga de pintar el fondo y una textura
|
||||
sobre la que escribe las puntuaciones. Esta textura se recorre modificando la ventana de vista
|
||||
para dar el efecto de que la textura se mueve sobre la pantalla.
|
||||
|
||||
Para mejorar la legibilidad de los textos, el objeto que dibuja el fondo es capaz de modificar
|
||||
su atenuación.
|
||||
*/
|
||||
|
||||
// Clase HiScoreTable
|
||||
// --- Clase HiScoreTable: muestra la tabla de puntuaciones más altas ---
|
||||
// Esta clase gestiona un estado del programa. Se encarga de mostrar la tabla con las puntuaciones
|
||||
// más altas. Para ello utiliza un objeto que se encarga de pintar el fondo y una textura
|
||||
// sobre la que escribe las puntuaciones. Esta textura se recorre modificando la ventana de vista
|
||||
// para dar el efecto de que la textura se mueve sobre la pantalla.
|
||||
// Para mejorar la legibilidad de los textos, el objeto que dibuja el fondo es capaz de modificar
|
||||
// su atenuación.
|
||||
class HiScoreTable {
|
||||
public:
|
||||
// --- Constructor y destructor ---
|
||||
@@ -52,7 +47,7 @@ class HiScoreTable {
|
||||
Uint16 counter_ = 0; // Contador
|
||||
Uint64 ticks_; // Contador de ticks para ajustar la velocidad del programa
|
||||
SDL_FRect view_area_; // Parte de la textura que se muestra en pantalla
|
||||
FadeMode fade_mode_; // Modo de fade a utilizar
|
||||
Fade::Mode fade_mode_; // Modo de fade a utilizar
|
||||
Color background_fade_color_; // Color de atenuación del fondo
|
||||
std::vector<Color> entry_colors_; // Colores para destacar las entradas en la tabla
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "audio.h" // Para Audio
|
||||
#include "color.h" // Para Color, SHADOW_TEXT_COLOR, Zone, NO_TEXT_C...
|
||||
#include "color.h" // Para Color, Colors::SHADOW_TEXT, Zone, NO_TEXT_C...
|
||||
#include "fade.h" // Para Fade, FadeMode, FadeType
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
@@ -26,12 +26,7 @@
|
||||
|
||||
// Constructor
|
||||
Instructions::Instructions()
|
||||
: renderer_(Screen::get()->getRenderer()),
|
||||
texture_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
|
||||
backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)),
|
||||
text_(Resource::get()->getText("smb2")),
|
||||
tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::STATIC)),
|
||||
fade_(std::make_unique<Fade>()) {
|
||||
: renderer_(Screen::get()->getRenderer()), texture_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), backbuffer_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.width, param.game.height)), text_(Resource::get()->getText("smb2")), tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::STATIC)), fade_(std::make_unique<Fade>()) {
|
||||
// Configura las texturas
|
||||
SDL_SetTextureBlendMode(backbuffer_, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetTextureBlendMode(texture_, SDL_BLENDMODE_BLEND);
|
||||
@@ -43,9 +38,9 @@ Instructions::Instructions()
|
||||
// Inicializa objetos
|
||||
tiled_bg_->setColor(param.title.bg_color);
|
||||
fade_->setColor(param.fade.color);
|
||||
fade_->setType(FadeType::FULLSCREEN);
|
||||
fade_->setPostDuration(param.fade.post_duration);
|
||||
fade_->setMode(FadeMode::IN);
|
||||
fade_->setType(Fade::Type::FULLSCREEN);
|
||||
fade_->setPostDuration(param.fade.post_duration_ms);
|
||||
fade_->setMode(Fade::Mode::IN);
|
||||
fade_->activate();
|
||||
|
||||
// Inicializa las líneas con un retraso progresivo de 50 ms
|
||||
@@ -137,7 +132,7 @@ void Instructions::fillTexture() {
|
||||
const int FIRST_LINE = (param.game.height - SIZE) / 2;
|
||||
|
||||
// Calcula cual es el texto más largo de las descripciones de los items
|
||||
int lenght = 0;
|
||||
int length = 0;
|
||||
const std::array<std::string, 5> ITEM_DESCRIPTIONS = {
|
||||
Lang::getText("[INSTRUCTIONS] 07"),
|
||||
Lang::getText("[INSTRUCTIONS] 08"),
|
||||
@@ -146,32 +141,32 @@ void Instructions::fillTexture() {
|
||||
Lang::getText("[INSTRUCTIONS] 11")};
|
||||
for (const auto &desc : ITEM_DESCRIPTIONS) {
|
||||
const int L = text_->length(desc);
|
||||
lenght = L > lenght ? L : lenght;
|
||||
length = L > length ? L : length;
|
||||
}
|
||||
const int ANCHOR_ITEM = (param.game.width - (lenght + X_OFFSET)) / 2;
|
||||
const int ANCHOR_ITEM = (param.game.width - (length + X_OFFSET)) / 2;
|
||||
|
||||
auto caption_style = Text::Style(Text::CENTER | Text::COLOR | Text::SHADOW, ORANGE_TEXT_COLOR, SHADOW_TEXT_COLOR);
|
||||
auto text_style = Text::Style(Text::CENTER | Text::COLOR | Text::SHADOW, NO_TEXT_COLOR, SHADOW_TEXT_COLOR);
|
||||
auto caption_style = Text::Style(Text::CENTER | Text::COLOR | Text::SHADOW, Colors::ORANGE_TEXT, Colors::SHADOW_TEXT);
|
||||
auto text_style = Text::Style(Text::CENTER | Text::COLOR | Text::SHADOW, Colors::NO_COLOR_MOD, Colors::SHADOW_TEXT);
|
||||
|
||||
// Escribe el texto de las instrucciones
|
||||
text_->writeStyle(param.game.game_area.center_x, FIRST_LINE, Lang::getText("[INSTRUCTIONS] 01"), caption_style);
|
||||
|
||||
const int ANCHOR1 = FIRST_LINE + SPACE_POST_HEADER;
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + SPACE_BETWEEN_LINES * 0, Lang::getText("[INSTRUCTIONS] 02"), text_style);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + SPACE_BETWEEN_LINES * 1, Lang::getText("[INSTRUCTIONS] 03"), text_style);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + SPACE_NEW_PARAGRAPH + SPACE_BETWEEN_LINES * 2, Lang::getText("[INSTRUCTIONS] 04"), text_style);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + SPACE_NEW_PARAGRAPH + SPACE_BETWEEN_LINES * 3, Lang::getText("[INSTRUCTIONS] 05"), text_style);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + (SPACE_BETWEEN_LINES * 0), Lang::getText("[INSTRUCTIONS] 02"), text_style);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + (SPACE_BETWEEN_LINES * 1), Lang::getText("[INSTRUCTIONS] 03"), text_style);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + SPACE_NEW_PARAGRAPH + (SPACE_BETWEEN_LINES * 2), Lang::getText("[INSTRUCTIONS] 04"), text_style);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR1 + SPACE_NEW_PARAGRAPH + (SPACE_BETWEEN_LINES * 3), Lang::getText("[INSTRUCTIONS] 05"), text_style);
|
||||
|
||||
// Escribe el texto de los objetos y sus puntos
|
||||
const int ANCHOR2 = ANCHOR1 + SPACE_PRE_HEADER + SPACE_NEW_PARAGRAPH + SPACE_BETWEEN_LINES * 3;
|
||||
const int ANCHOR2 = ANCHOR1 + SPACE_PRE_HEADER + SPACE_NEW_PARAGRAPH + (SPACE_BETWEEN_LINES * 3);
|
||||
text_->writeStyle(param.game.game_area.center_x, ANCHOR2, Lang::getText("[INSTRUCTIONS] 06"), caption_style);
|
||||
|
||||
const int ANCHOR3 = ANCHOR2 + SPACE_POST_HEADER;
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + SPACE_BETWEEN_ITEM_LINES * 0, Lang::getText("[INSTRUCTIONS] 07"), SHADOW_TEXT_COLOR);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + SPACE_BETWEEN_ITEM_LINES * 1, Lang::getText("[INSTRUCTIONS] 08"), SHADOW_TEXT_COLOR);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + SPACE_BETWEEN_ITEM_LINES * 2, Lang::getText("[INSTRUCTIONS] 09"), SHADOW_TEXT_COLOR);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + SPACE_BETWEEN_ITEM_LINES * 3, Lang::getText("[INSTRUCTIONS] 10"), SHADOW_TEXT_COLOR);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + SPACE_BETWEEN_ITEM_LINES * 4, Lang::getText("[INSTRUCTIONS] 11"), SHADOW_TEXT_COLOR);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + (SPACE_BETWEEN_ITEM_LINES * 0), Lang::getText("[INSTRUCTIONS] 07"), Colors::SHADOW_TEXT);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + (SPACE_BETWEEN_ITEM_LINES * 1), Lang::getText("[INSTRUCTIONS] 08"), Colors::SHADOW_TEXT);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + (SPACE_BETWEEN_ITEM_LINES * 2), Lang::getText("[INSTRUCTIONS] 09"), Colors::SHADOW_TEXT);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + (SPACE_BETWEEN_ITEM_LINES * 3), Lang::getText("[INSTRUCTIONS] 10"), Colors::SHADOW_TEXT);
|
||||
text_->writeShadowed(ANCHOR_ITEM + X_OFFSET, ANCHOR3 + (SPACE_BETWEEN_ITEM_LINES * 4), Lang::getText("[INSTRUCTIONS] 11"), Colors::SHADOW_TEXT);
|
||||
|
||||
// Deja el renderizador como estaba
|
||||
SDL_SetRenderTarget(renderer_, temp);
|
||||
@@ -245,7 +240,7 @@ void Instructions::render() {
|
||||
void Instructions::checkEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
GlobalEvents::check(event);
|
||||
GlobalEvents::handle(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||