Compare commits

111 Commits

Author SHA1 Message Date
b9e26aa755 corregit: flags estatics en credits.cpp i title.cpp 2025-09-26 23:48:08 +02:00
b2afef2226 corregit: flags estatics en hiscore_tale.cpp 2025-09-26 23:40:37 +02:00
c400aa96c0 corregit: flags estatics en game.cpp 2025-09-26 23:36:49 +02:00
8818954dcd afegit define rapidet per a renderer metal basic en macos 2025-09-26 22:45:14 +02:00
b92e5df98b nou: sonidos de bala diferent per a cada jugador 2025-09-26 20:48:22 +02:00
83871273ec nou: bales de colors diferents per a cada jugador 2025-09-26 20:37:00 +02:00
0459b39366 screen.cpp: getDisplayInfo()
resource.cpp: afegida info del display en la pantalla de carrega
2025-09-26 19:42:39 +02:00
5bb0ff19bc corregit: asset::checkFile() fallava desde fora del directori 2025-09-26 19:16:25 +02:00
a867b3cf4d integrat empaquetador de recursos en el makefile 2025-09-26 18:16:48 +02:00
8a6ce8e66d organitzat player.h 2025-09-26 17:37:29 +02:00
a40f04a739 nou: musiqueta i veu per al game over i timings ajustats 2025-09-26 17:20:35 +02:00
0c670fd344 novetat: canvi de color de les bales quan queda poc powerUp 2025-09-26 14:13:52 +02:00
35f4bf690c corregit: bug en Audio::fadeOutMusic quan la musica no es reproduia en bucle 2025-09-25 21:21:39 +02:00
abeaf47f96 corregit: timing de les celebracions del final 2025-09-25 19:48:58 +02:00
6498c35628 corregit audio i timing del game over 2025-09-25 19:36:40 +02:00
d1c6af02db corregit: la musica del joc soles sonava la primera volta 2025-09-25 19:19:46 +02:00
5edef17d84 nou: musica al completar el joc 2025-09-25 19:10:46 +02:00
e4532fcef2 nou: ruidet per a quan acabes de posar el nom 2025-09-25 18:18:39 +02:00
7a8d66c29d nou: quan arribes a la maxima puntuació, posa un lletreret 2025-09-25 17:52:49 +02:00
54292c9f8f fix: warning de override 2025-09-25 16:58:01 +02:00
3897553704 eliminat el vector precalculat en tiled_bg per al moviment circular 2025-09-25 08:08:29 +02:00
308f5c20fb corregit en background.cpp la desaceleració final, millorada amb funció de suavitzat i arreglades les velocitats dels nuvols que no variaven amb el pas del joc 2025-09-24 21:54:38 +02:00
987dcd0205 fix: el audio del logo.cpp soles sonava la primera volta 2025-09-24 20:54:45 +02:00
d56f23544c corregit menu_renderer.cpp, de vegades es modificava el ample del menu al canviar les opcions 2025-09-24 20:46:07 +02:00
c79a846b29 migrat service_menu.cpp a deltaTime 2025-09-24 19:34:08 +02:00
ad39d55e79 style: static auto *const SCREEN = Screen::get(); 2025-09-24 18:57:10 +02:00
853ef426f0 corregit el START PROMPT en title.cpp que no resetejava el contador de parpadeig 2025-09-24 18:51:36 +02:00
cadf7de3d8 tiled_bg.cpp, afegit changeSpeedTo() 2025-09-24 18:44:37 +02:00
ec65ff9acb corregit audio de timeStopItem 2025-09-24 18:26:39 +02:00
d077374883 migrat a deltaTime screen.cpp i notifier.cpp 2025-09-24 18:08:50 +02:00
40a2b2cc00 afegit TODO per al proxim dia 2025-09-24 14:02:30 +02:00
b3f3f151da corregits alguns parametres de ms a s 2025-09-24 13:56:12 +02:00
3fdd61655a corregit throwCoffee() i el rolling del jugador 2025-09-24 13:24:05 +02:00
504727b95f corregit del delay entre formacions 2025-09-24 13:09:54 +02:00
ff5446fcdf corregit createItemText() 2025-09-24 12:41:41 +02:00
545eb70082 corregida la creacio de globos 2025-09-24 12:37:21 +02:00
232a23a5dd corregida velocitat_y en createChild() 2025-09-24 11:42:48 +02:00
c9a29e26dd revisant la seccio game: bales, items e inici 2025-09-24 11:37:23 +02:00
2977869ab5 revisat tabe.cpp, item.cpp i game.cpp 2025-09-24 09:37:23 +02:00
6a223b68ba revisant title.cpp (falla el jugador) 2025-09-23 14:13:48 +02:00
3fafff026b revisat balloon_formationc.cpp i credits.cpp 2025-09-23 14:03:07 +02:00
159528adc9 revisat credits.cpp, player.cpp, balloon.cpp i balloon_manager.cpp 2025-09-23 13:42:09 +02:00
6c8f231b34 revisat instructions.cpp 2025-09-23 12:10:16 +02:00
c5d6d77ebf revisat hiscore_table.cpp 2025-09-23 11:24:29 +02:00
5e73327b2f revisat intro.cpp, path_sprite i writer.cpp 2025-09-23 11:13:15 +02:00
720d286dcf revisat logo.cpp 2025-09-23 09:11:29 +02:00
dd13a2bd7c revisat background, game_logo, smart sprite, tiled_bg 2025-09-23 09:00:00 +02:00
1a6ef79466 revisat moving i animated sprite 2025-09-23 08:29:29 +02:00
8f83a1d13e magic numbers: moving_sprite.cpp i game_logo.cpp 2025-09-22 13:57:58 +02:00
9edfe6877f magic numbers: item.cpp 2025-09-22 13:14:23 +02:00
91b26631c6 magic numbers: bullet.cpp 2025-09-22 12:14:09 +02:00
331a690b78 fix: balloon_manager.cpp conflicto al crear los globos y detener el tiempo 2025-09-22 10:13:12 +02:00
5e3946e28b fix: no inicialitzava be animated_sprite 2025-09-22 10:03:38 +02:00
d4a0189dc8 arreglant balloon.cpp per a deltaTime pur 2025-09-19 14:15:44 +02:00
568b941990 eliminats metodes frame-based obsolets 2025-09-19 09:56:25 +02:00
49a3989ecf magic numbers: game.cpp 2025-09-19 09:11:10 +02:00
af7cb01ead magic numbers: game.cpp 2025-09-19 07:33:27 +02:00
5c82916650 magic numbers: game.cpp i player.cpp 2025-09-18 14:17:54 +02:00
0c0518adac magic numbers: game.cpp i player.cpp (en progres) 2025-09-18 13:15:43 +02:00
cb7b290818 magic numbers: game.cpp 2025-09-17 14:20:13 +02:00
ae30c9b34f magic numbers: title.cpp 2025-09-17 13:53:31 +02:00
9acd9aa631 magic numbers: intro.cpp 2025-09-17 13:25:16 +02:00
577510ff8c magic numbers: logo.cpp 2025-09-17 13:01:43 +02:00
66566913f6 delta-time: game.cpp (funciona pero va un poc massa ràpid) 2025-09-16 22:56:00 +02:00
3e6cc9dfab delta-time: explosions.cpp 2025-09-16 22:43:16 +02:00
a15e29344f delta-time: balloon.cpp
delta-time: balloon_manager.cpp
delta-time: credits.cpp
2025-09-16 22:38:48 +02:00
a96a17e11b delta-time: tabe.cpp 2025-09-16 20:29:35 +02:00
e0f6a424a9 delta-time: bullet.cpp 2025-09-16 20:26:22 +02:00
49e30f947a delta-time: title.cpp 2025-09-16 20:23:10 +02:00
470a07d28c delta-time: player.cpp 2025-09-16 19:21:44 +02:00
65716fce20 delta-time: tiled_bg.cpp 2025-09-16 17:35:03 +02:00
dfa66b0e95 delta-time: game_logo.cpp
delta-time: smart_sprite.cpp
2025-09-16 17:19:05 +02:00
3d9ffe356e Elimina .claude 2025-09-16 17:18:39 +02:00
19768cb72b delta-time: animated_sprite.cpp 2025-09-16 16:51:31 +02:00
26e0fd7247 delta-time: moving_sprite.cpp 2025-09-16 16:37:39 +02:00
e2fd470ad3 migració a delta time 2025-09-16 12:23:02 +02:00
a72ae0a5fc migració a delta time 2025-09-16 12:06:49 +02:00
7579594c22 migració a delta time 2025-09-16 10:48:22 +02:00
6c702e7e23 Logo: convertit per a usar delta time 2025-09-16 08:40:41 +02:00
fb9c78eb49 warning: balloon_manager.cpp varios ordres de inicialització mal 2025-08-27 10:27:18 +02:00
62f65cbd5a warning: balloon_manager.cpp varios ordres de inicialització mal 2025-08-27 10:19:30 +02:00
057d3dcfee bug fix: en la tabla de puntuacions, no apareix la estreleta al completar el joc amb 1CC
bug fix: posant nom al completar el joc, si "passes" el mostrar el nom, mata al jugador en lloc de fer que se'n vaja

Resol #92 i #98
2025-08-26 08:21:33 +02:00
c85336a4d0 fix: el tabe podia spawnejar-se en la seqüencia final.
Resol #89
2025-08-24 18:54:20 +02:00
e4702e4e24 bug fix: Audio::fadeOutMusic no ha de fer fade si la musica no sona 2025-08-24 17:39:07 +02:00
928335576c corregida la llista de inicialització en clang-format
creat Balloon::Config per a inicialitzar globos
2025-08-24 17:16:49 +02:00
fe950e6f17 bug fix: en el modo demo la powerball feia ruido.
Resol #84
2025-08-24 14:57:08 +02:00
6e81b6e60c Merge branch 'main' of https://gitea.sustancia.synology.me/jaildesigner/coffee_crisis_arcade_edition 2025-08-24 14:37:32 +02:00
74f6fe3501 Afegit outline al text 2x
corregit el marcador durant el Player::State::RECOVER
2025-08-24 14:37:30 +02:00
dfdb679054 Merge branch 'main' of https://gitea.sustancia.synology.me/JailDesigner/coffee_crisis_arcade_edition 2025-08-24 10:51:10 +02:00
26ed479306 delete 2025-08-24 10:51:07 +02:00
32e9da55ef Afegit so de service_menu_back
Retocats els audios de service menu
Afegit so a ENTER NAME
Arreglos visuals a ENTER NAME
2025-08-23 21:06:20 +02:00
610083578e style: eliminat soroll de drop item amb maquina de café
Quan ix una maquina de café ja no se sent el so de drop item
per a millorar l'experiència sonora del joc.

Resol #91
2025-08-23 20:05:16 +02:00
7250073d60 actualitzat LICENSE 2025-08-19 16:45:00 +02:00
dfa06870e4 actualitzat makefile per a linux 2025-08-19 16:42:40 +02:00
81f3a25143 afegit makefile per a macos 2025-08-19 16:39:39 +02:00
5aca95f3d2 neteja de temporals al acabar 2025-08-19 16:29:52 +02:00
7b193605e6 refet makefile i eliminades *.dll 2025-08-19 14:09:11 +02:00
089a5b15d7 actualitzat Makefile per a windows 2025-08-19 14:01:32 +02:00
e6a14ca57d eliminat el log del codi 2025-08-19 13:55:22 +02:00
467d609c28 debug 2025-08-19 13:50:11 +02:00
e03c798000 afegits logs peer a la carrega de musica i sons 2025-08-19 13:46:07 +02:00
52d76b7338 arreglos pa NO integrar jail_audio en ResourceHelper 2025-08-19 13:36:03 +02:00
83ee9c2649 integrat animated_sprite amb ResourceHelper 2025-08-19 13:25:12 +02:00
43788bb01a faltaven mes integracions de texture amb ResourceHelper 2025-08-19 13:22:38 +02:00
58cf78e1e3 integracions de texture.cpp amb ResourceHelper 2025-08-19 13:13:27 +02:00
6bf8490776 integrades mes clases amb ResourceHelper
mogudes les dades de la demo a resource.pack
2025-08-19 13:08:37 +02:00
8cfe28922c integrat Text amb ResourceHelper 2025-08-19 12:45:53 +02:00
63990c75c2 modificat texture.cpp per a gastar ResourceHelper 2025-08-19 12:41:08 +02:00
94dca528ab fix assets.txt 2025-08-19 10:13:12 +02:00
4b6b89ceb2 integrat Asset amb ResourceHelper 2025-08-19 10:06:52 +02:00
ed077c1da5 treballant en resources.pack 2025-08-19 09:46:19 +02:00
160 changed files with 5565 additions and 2748 deletions

View File

@@ -14,6 +14,8 @@ ContinuationIndentWidth: 4
ConstructorInitializerIndentWidth: 4 ConstructorInitializerIndentWidth: 4
IndentWrappedFunctionNames: false IndentWrappedFunctionNames: false
Cpp11BracedListStyle: true Cpp11BracedListStyle: true
BreakConstructorInitializers: BeforeComma BreakConstructorInitializers: BeforeColon
AllowAllConstructorInitializersOnNextLine: false
PackConstructorInitializers: Never
AllowAllArgumentsOnNextLine: false AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: false

2
.gitignore vendored
View File

@@ -1,4 +1,5 @@
.vscode .vscode
.claude
build/ build/
data/config/config.txt data/config/config.txt
*.DS_Store *.DS_Store
@@ -17,3 +18,4 @@ debug.txt
cppcheck-result* cppcheck-result*
desktop.ini desktop.ini
ccae_release/ ccae_release/
resources.pack

View File

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

22
LICENSE
View File

@@ -1 +1,21 @@
GNU General Public License v3.0 only Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
Copyright (c) 2025 Coffee Crisis Arcade Edition
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
You are free to:
- Share — copy and redistribute the material in any medium or format
- Adapt — remix, transform, and build upon the material
Under the following terms:
- Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
- NonCommercial — You may not use the material for commercial purposes.
- ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
To view a copy of this license, visit:
https://creativecommons.org/licenses/by-nc-sa/4.0/
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -3,6 +3,7 @@ DIR_ROOT := $(dir $(abspath $(MAKEFILE_LIST)))
DIR_SOURCES := $(addsuffix /, $(DIR_ROOT)source) DIR_SOURCES := $(addsuffix /, $(DIR_ROOT)source)
DIR_BIN := $(addsuffix /, $(DIR_ROOT)) DIR_BIN := $(addsuffix /, $(DIR_ROOT))
DIR_BUILD := $(addsuffix /, $(DIR_ROOT)build) DIR_BUILD := $(addsuffix /, $(DIR_ROOT)build)
DIR_TOOLS := $(addsuffix /, $(DIR_ROOT)tools)
# Variables # Variables
TARGET_NAME := coffee_crisis_arcade_edition TARGET_NAME := coffee_crisis_arcade_edition
@@ -12,6 +13,17 @@ RELEASE_FOLDER := ccae_release
RELEASE_FILE := $(RELEASE_FOLDER)/$(TARGET_NAME) RELEASE_FILE := $(RELEASE_FOLDER)/$(TARGET_NAME)
RESOURCE_FILE := release/coffee.res RESOURCE_FILE := release/coffee.res
# Variables para herramienta de empaquetado
ifeq ($(OS),Windows_NT)
PACK_TOOL := $(DIR_TOOLS)pack_resources.exe
PACK_CXX := $(CXX)
else
PACK_TOOL := $(DIR_TOOLS)pack_resources
PACK_CXX := $(CXX)
endif
PACK_SOURCES := $(DIR_TOOLS)pack_resources.cpp $(DIR_SOURCES)resource_pack.cpp
PACK_INCLUDES := -I$(DIR_ROOT)
# Versión automática basada en la fecha actual (específica por SO) # Versión automática basada en la fecha actual (específica por SO)
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
VERSION := $(shell powershell -Command "Get-Date -Format 'yyyy-MM-dd'") VERSION := $(shell powershell -Command "Get-Date -Format 'yyyy-MM-dd'")
@@ -71,6 +83,9 @@ APP_SOURCES := \
source/path_sprite.cpp \ source/path_sprite.cpp \
source/player.cpp \ source/player.cpp \
source/resource.cpp \ source/resource.cpp \
source/resource_helper.cpp \
source/resource_loader.cpp \
source/resource_pack.cpp \
source/scoreboard.cpp \ source/scoreboard.cpp \
source/screen.cpp \ source/screen.cpp \
source/sections/credits.cpp \ source/sections/credits.cpp \
@@ -104,7 +119,7 @@ INCLUDES := -Isource -Isource/external
# Variables según el sistema operativo # Variables según el sistema operativo
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
FixPath = $(subst /,\\,$1) FixPath = $(subst /,\\,$1)
CXXFLAGS := -std=c++20 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows -DWINDOWS_BUILD CXXFLAGS := -std=c++20 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -static-libgcc -Wl,-Bstatic -lpthread -Wl,-Bdynamic -Wl,-subsystem,windows -DWINDOWS_BUILD
CXXFLAGS_DEBUG := -std=c++20 -Wall -g -D_DEBUG -DWINDOWS_BUILD CXXFLAGS_DEBUG := -std=c++20 -Wall -g -D_DEBUG -DWINDOWS_BUILD
LDFLAGS := -lmingw32 -lws2_32 -lSDL3 -lopengl32 LDFLAGS := -lmingw32 -lws2_32 -lSDL3 -lopengl32
RM := del /Q RM := del /Q
@@ -132,6 +147,19 @@ else
endif endif
endif endif
# Reglas para herramienta de empaquetado y resources.pack
$(PACK_TOOL): $(PACK_SOURCES)
@echo "Compilando herramienta de empaquetado..."
$(PACK_CXX) -std=c++17 -Wall -Os $(PACK_INCLUDES) $(PACK_SOURCES) -o $(PACK_TOOL)
@echo "✓ Herramienta de empaquetado lista: $(PACK_TOOL)"
pack_tool: $(PACK_TOOL)
resources.pack: $(PACK_TOOL)
@echo "Generando resources.pack desde directorio data/..."
$(PACK_TOOL) data resources.pack
@echo "✓ resources.pack generado exitosamente"
# Reglas para compilación # Reglas para compilación
windows: windows:
@echo off @echo off
@@ -150,7 +178,7 @@ windows_debug:
@echo Compilando version debug para Windows: "$(APP_NAME)_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" $(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(WIN_TARGET_FILE)_debug.exe"
windows_release: windows_release: resources.pack
@echo off @echo off
@echo Creando release para Windows - Version: $(VERSION) @echo Creando release para Windows - Version: $(VERSION)
@@ -158,8 +186,9 @@ windows_release:
powershell if (Test-Path "$(RELEASE_FOLDER)") {Remove-Item "$(RELEASE_FOLDER)" -Recurse -Force} powershell if (Test-Path "$(RELEASE_FOLDER)") {Remove-Item "$(RELEASE_FOLDER)" -Recurse -Force}
powershell if (-not (Test-Path "$(RELEASE_FOLDER)")) {New-Item "$(RELEASE_FOLDER)" -ItemType Directory} powershell if (-not (Test-Path "$(RELEASE_FOLDER)")) {New-Item "$(RELEASE_FOLDER)" -ItemType Directory}
# Copia la carpeta 'data' # Copia la carpeta 'config' y el archivo 'resources.pack'
powershell Copy-Item -Path "data" -Destination "$(RELEASE_FOLDER)" -recurse -Force powershell Copy-Item -Path "config" -Destination "$(RELEASE_FOLDER)" -recurse -Force
powershell Copy-Item -Path "resources.pack" -Destination "$(RELEASE_FOLDER)"
# Copia los ficheros que estan en la raíz del proyecto # Copia los ficheros que estan en la raíz del proyecto
powershell Copy-Item "LICENSE" -Destination "$(RELEASE_FOLDER)" powershell Copy-Item "LICENSE" -Destination "$(RELEASE_FOLDER)"
@@ -187,7 +216,7 @@ macos_debug:
@echo "Compilando version debug para macOS: $(TARGET_NAME)_debug" @echo "Compilando version debug para macOS: $(TARGET_NAME)_debug"
$(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug" $(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
macos_release: macos_release: resources.pack
@echo "Creando release para macOS - Version: $(VERSION)" @echo "Creando release para macOS - Version: $(VERSION)"
# Elimina datos de compilaciones anteriores # Elimina datos de compilaciones anteriores
$(RMDIR) "$(RELEASE_FOLDER)" $(RMDIR) "$(RELEASE_FOLDER)"
@@ -203,7 +232,8 @@ macos_release:
$(MKDIR) Frameworks $(MKDIR) Frameworks
# Copia carpetas y ficheros # Copia carpetas y ficheros
cp -R data "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources" cp -R config "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
cp resources.pack "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
cp -R release/frameworks/SDL3.xcframework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks" cp -R release/frameworks/SDL3.xcframework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
cp -R release/frameworks/SDL3.xcframework Frameworks cp -R release/frameworks/SDL3.xcframework Frameworks
cp release/*.icns "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources" cp release/*.icns "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
@@ -253,7 +283,7 @@ linux_debug:
@echo "Compilando version debug para Linux: $(TARGET_NAME)_debug" @echo "Compilando version debug para Linux: $(TARGET_NAME)_debug"
$(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug" $(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
linux_release: linux_release: resources.pack
@echo "Creando release para Linux - Version: $(VERSION)" @echo "Creando release para Linux - Version: $(VERSION)"
# Elimina carpetas previas # Elimina carpetas previas
$(RMDIR) "$(RELEASE_FOLDER)" $(RMDIR) "$(RELEASE_FOLDER)"
@@ -262,7 +292,8 @@ linux_release:
$(MKDIR) "$(RELEASE_FOLDER)" $(MKDIR) "$(RELEASE_FOLDER)"
# Copia ficheros # Copia ficheros
cp -R data "$(RELEASE_FOLDER)" cp -R config "$(RELEASE_FOLDER)"
cp resources.pack "$(RELEASE_FOLDER)"
cp LICENSE "$(RELEASE_FOLDER)" cp LICENSE "$(RELEASE_FOLDER)"
cp README.md "$(RELEASE_FOLDER)" cp README.md "$(RELEASE_FOLDER)"
@@ -278,7 +309,7 @@ linux_release:
# Elimina la carpeta temporal # Elimina la carpeta temporal
$(RMDIR) "$(RELEASE_FOLDER)" $(RMDIR) "$(RELEASE_FOLDER)"
linux_release_desktop: linux_release_desktop: resources.pack
@echo "Creando release con integracion desktop para Linux - Version: $(VERSION)" @echo "Creando release con integracion desktop para Linux - Version: $(VERSION)"
# Elimina carpetas previas # Elimina carpetas previas
$(RMDIR) "$(RELEASE_FOLDER)" $(RMDIR) "$(RELEASE_FOLDER)"
@@ -291,7 +322,8 @@ linux_release_desktop:
$(MKDIR) "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)" $(MKDIR) "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)"
# Copia ficheros del juego # Copia ficheros del juego
cp -R data "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)/" cp -R config "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)/"
cp resources.pack "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)/"
cp LICENSE "$(RELEASE_FOLDER)/$(TARGET_NAME)/" cp LICENSE "$(RELEASE_FOLDER)/$(TARGET_NAME)/"
cp README.md "$(RELEASE_FOLDER)/$(TARGET_NAME)/" cp README.md "$(RELEASE_FOLDER)/$(TARGET_NAME)/"
@@ -382,7 +414,7 @@ raspi_debug:
@echo "Compilando version debug para Raspberry Pi: $(TARGET_NAME)_debug" @echo "Compilando version debug para Raspberry Pi: $(TARGET_NAME)_debug"
$(CXX) $(APP_SOURCES) $(INCLUDES) -DVERBOSE -DDEBUG $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug" $(CXX) $(APP_SOURCES) $(INCLUDES) -DVERBOSE -DDEBUG $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
raspi_release: raspi_release: resources.pack
@echo "Creando release para Raspberry Pi - Version: $(VERSION)" @echo "Creando release para Raspberry Pi - Version: $(VERSION)"
# Elimina carpetas previas # Elimina carpetas previas
$(RMDIR) "$(RELEASE_FOLDER)" $(RMDIR) "$(RELEASE_FOLDER)"
@@ -391,7 +423,8 @@ raspi_release:
$(MKDIR) "$(RELEASE_FOLDER)" $(MKDIR) "$(RELEASE_FOLDER)"
# Copia ficheros # Copia ficheros
cp -R data "$(RELEASE_FOLDER)" cp -R config "$(RELEASE_FOLDER)"
cp resources.pack "$(RELEASE_FOLDER)"
cp LICENSE "$(RELEASE_FOLDER)" cp LICENSE "$(RELEASE_FOLDER)"
cp README.md "$(RELEASE_FOLDER)" cp README.md "$(RELEASE_FOLDER)"
@@ -407,7 +440,7 @@ raspi_release:
# Elimina la carpeta temporal # Elimina la carpeta temporal
$(RMDIR) "$(RELEASE_FOLDER)" $(RMDIR) "$(RELEASE_FOLDER)"
anbernic: anbernic: resources.pack
@echo "Compilando para Anbernic: $(TARGET_NAME)" @echo "Compilando para Anbernic: $(TARGET_NAME)"
# Elimina carpetas previas # Elimina carpetas previas
$(RMDIR) "$(RELEASE_FOLDER)"_anbernic $(RMDIR) "$(RELEASE_FOLDER)"_anbernic
@@ -416,7 +449,8 @@ anbernic:
$(MKDIR) "$(RELEASE_FOLDER)"_anbernic $(MKDIR) "$(RELEASE_FOLDER)"_anbernic
# Copia ficheros # Copia ficheros
cp -R data "$(RELEASE_FOLDER)"_anbernic cp -R config "$(RELEASE_FOLDER)"_anbernic
cp resources.pack "$(RELEASE_FOLDER)"_anbernic
# Compila # Compila
$(CXX) $(APP_SOURCES) $(INCLUDES) -DANBERNIC -DNO_SHADERS -DARCADE -DVERBOSE $(CXXFLAGS) $(LDFLAGS) -o $(RELEASE_FOLDER)_anbernic/$(TARGET_NAME) $(CXX) $(APP_SOURCES) $(INCLUDES) -DANBERNIC -DNO_SHADERS -DARCADE -DVERBOSE $(CXXFLAGS) $(LDFLAGS) -o $(RELEASE_FOLDER)_anbernic/$(TARGET_NAME)
@@ -448,7 +482,9 @@ help:
@echo " raspi_release - Crear release completo para Raspberry Pi" @echo " raspi_release - Crear release completo para Raspberry Pi"
@echo " anbernic - Compilar para Anbernic" @echo " anbernic - Compilar para Anbernic"
@echo " no_audio - Compilar sin sistema de audio" @echo " no_audio - Compilar sin sistema de audio"
@echo " pack_tool - Compilar herramienta de empaquetado"
@echo " resources.pack - Generar pack de recursos desde data/"
@echo " show_version - Mostrar version actual ($(VERSION))" @echo " show_version - Mostrar version actual ($(VERSION))"
@echo " help - Mostrar esta ayuda" @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 .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 pack_tool

61
TODO.md Normal file
View File

@@ -0,0 +1,61 @@
# TODO
## Tareas pendientes
- [ ] Revisar todas las variables static de los métodos para ver si se resetean correctamente
## Mejoras arquitecturales (refactoring)
### Eliminar variables static locales y usar patrones profesionales:
**Opción 1: Máquina de Estados**
```cpp
class GameCompletedState {
bool start_celebrations_done = false;
bool end_celebrations_done = false;
float timer = 0.0f;
public:
void reset() {
start_celebrations_done = false;
end_celebrations_done = false;
timer = 0.0f;
}
void update(float deltaTime) {
timer += deltaTime;
// lógica aquí
}
};
```
**Opción 2: Sistema de Eventos/Callbacks**
```cpp
// Al entrar en COMPLETED state
eventSystem.scheduleEvent(6.0f, []{ startCelebrations(); });
eventSystem.scheduleEvent(14.0f, []{ endCelebrations(); });
```
**Opción 3: Flags como miembros privados**
```cpp
class Game {
private:
struct GameOverState {
bool game_over_triggered = false;
bool start_celebrations_triggered = false;
bool end_celebrations_triggered = false;
void reset() {
game_over_triggered = false;
start_celebrations_triggered = false;
end_celebrations_triggered = false;
}
} game_over_state_;
};
```
**Ventajas:**
- Más fáciles de testear
- Más fáciles de debugear
- Más fáciles de entender y mantener
- No tienen "estado oculto"

View File

@@ -9,17 +9,20 @@ DATA|${SYSTEM_FOLDER}/controllers.json|optional,absolute
DATA|${SYSTEM_FOLDER}/score.bin|optional,absolute DATA|${SYSTEM_FOLDER}/score.bin|optional,absolute
# Archivos de configuración del juego # Archivos de configuración del juego
DATA|${PREFIX}/data/config/formations.txt DATA|${PREFIX}/config/formations.txt
DATA|${PREFIX}/data/config/gamecontrollerdb.txt DATA|${PREFIX}/config/gamecontrollerdb.txt
DATA|${PREFIX}/data/config/param_320x240.txt DATA|${PREFIX}/config/param_320x240.txt
DATA|${PREFIX}/data/config/param_320x256.txt DATA|${PREFIX}/config/param_320x256.txt
DATA|${PREFIX}/data/config/param_red.txt DATA|${PREFIX}/config/param_red.txt
DATA|${PREFIX}/data/config/pools.txt DATA|${PREFIX}/config/pools.txt
DATA|${PREFIX}/data/config/stages.txt DATA|${PREFIX}/config/stages.txt
DEMODATA|${PREFIX}/data/config/demo1.bin
DEMODATA|${PREFIX}/data/config/demo2.bin # Archivos con los datos de la demo
DEMODATA|${PREFIX}/data/demo/demo1.bin
DEMODATA|${PREFIX}/data/demo/demo2.bin
# Música # Música
MUSIC|${PREFIX}/data/music/congratulations.ogg
MUSIC|${PREFIX}/data/music/credits.ogg MUSIC|${PREFIX}/data/music/credits.ogg
MUSIC|${PREFIX}/data/music/intro.ogg MUSIC|${PREFIX}/data/music/intro.ogg
MUSIC|${PREFIX}/data/music/playing.ogg MUSIC|${PREFIX}/data/music/playing.ogg
@@ -34,7 +37,8 @@ SOUND|${PREFIX}/data/sound/balloon_pop0.wav
SOUND|${PREFIX}/data/sound/balloon_pop1.wav SOUND|${PREFIX}/data/sound/balloon_pop1.wav
SOUND|${PREFIX}/data/sound/balloon_pop2.wav SOUND|${PREFIX}/data/sound/balloon_pop2.wav
SOUND|${PREFIX}/data/sound/balloon_pop3.wav SOUND|${PREFIX}/data/sound/balloon_pop3.wav
SOUND|${PREFIX}/data/sound/bullet.wav SOUND|${PREFIX}/data/sound/bullet1p.wav
SOUND|${PREFIX}/data/sound/bullet2p.wav
SOUND|${PREFIX}/data/sound/clock.wav SOUND|${PREFIX}/data/sound/clock.wav
SOUND|${PREFIX}/data/sound/coffee_out.wav SOUND|${PREFIX}/data/sound/coffee_out.wav
SOUND|${PREFIX}/data/sound/continue_clock.wav SOUND|${PREFIX}/data/sound/continue_clock.wav
@@ -46,10 +50,12 @@ SOUND|${PREFIX}/data/sound/item_drop.wav
SOUND|${PREFIX}/data/sound/item_pickup.wav SOUND|${PREFIX}/data/sound/item_pickup.wav
SOUND|${PREFIX}/data/sound/jump.wav SOUND|${PREFIX}/data/sound/jump.wav
SOUND|${PREFIX}/data/sound/logo.wav SOUND|${PREFIX}/data/sound/logo.wav
SOUND|${PREFIX}/data/sound/name_input_accept.wav
SOUND|${PREFIX}/data/sound/notify.wav SOUND|${PREFIX}/data/sound/notify.wav
SOUND|${PREFIX}/data/sound/player_collision.wav SOUND|${PREFIX}/data/sound/player_collision.wav
SOUND|${PREFIX}/data/sound/power_ball_explosion.wav SOUND|${PREFIX}/data/sound/power_ball_explosion.wav
SOUND|${PREFIX}/data/sound/service_menu_adjust.wav SOUND|${PREFIX}/data/sound/service_menu_adjust.wav
SOUND|${PREFIX}/data/sound/service_menu_back.wav
SOUND|${PREFIX}/data/sound/service_menu_move.wav SOUND|${PREFIX}/data/sound/service_menu_move.wav
SOUND|${PREFIX}/data/sound/service_menu_select.wav SOUND|${PREFIX}/data/sound/service_menu_select.wav
SOUND|${PREFIX}/data/sound/stage_change.wav SOUND|${PREFIX}/data/sound/stage_change.wav
@@ -59,6 +65,7 @@ SOUND|${PREFIX}/data/sound/title.wav
SOUND|${PREFIX}/data/sound/voice_aw_aw_aw.wav SOUND|${PREFIX}/data/sound/voice_aw_aw_aw.wav
SOUND|${PREFIX}/data/sound/voice_coffee.wav SOUND|${PREFIX}/data/sound/voice_coffee.wav
SOUND|${PREFIX}/data/sound/voice_credit_thankyou.wav SOUND|${PREFIX}/data/sound/voice_credit_thankyou.wav
SOUND|${PREFIX}/data/sound/voice_game_over.wav
SOUND|${PREFIX}/data/sound/voice_get_ready.wav SOUND|${PREFIX}/data/sound/voice_get_ready.wav
SOUND|${PREFIX}/data/sound/voice_no.wav SOUND|${PREFIX}/data/sound/voice_no.wav
SOUND|${PREFIX}/data/sound/voice_power_up.wav SOUND|${PREFIX}/data/sound/voice_power_up.wav
@@ -172,6 +179,7 @@ BITMAP|${PREFIX}/data/gfx/player/hit.png
# Fuentes de texto # Fuentes de texto
BITMAP|${PREFIX}/data/font/04b_25_2x.png BITMAP|${PREFIX}/data/font/04b_25_2x.png
BITMAP|${PREFIX}/data/font/04b_25_2x_white.png
BITMAP|${PREFIX}/data/font/04b_25_flat_2x.png BITMAP|${PREFIX}/data/font/04b_25_flat_2x.png
BITMAP|${PREFIX}/data/font/04b_25_flat.png BITMAP|${PREFIX}/data/font/04b_25_flat.png
BITMAP|${PREFIX}/data/font/04b_25_grey.png BITMAP|${PREFIX}/data/font/04b_25_grey.png

277
config/formations.txt Normal file
View File

@@ -0,0 +1,277 @@
# 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
# X3_25, X3_75, DEFAULT_POS_Y
# SMALL, MEDIUM, LARGE, EXTRALARGE
# RIGHT, LEFT
formation: 0
# Dos enemigos BALLOON3 uno a cada extremo
X3_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, EXTRALARGE, 0.0000
X3_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, EXTRALARGE, 0.0000
formation: 1
# Dos enemigos BALLOON3 uno a cada cuarto. Ambos van hacia el centro
X3_25, 0, DEFAULT_POS_Y, RIGHT, BALLOON, EXTRALARGE, 0.0000
X3_75, 0, DEFAULT_POS_Y, LEFT, BALLOON, EXTRALARGE, 0.0000
formation: 2
# Cuatro enemigos BALLOON1 uno detrás del otro. A la izquierda y hacia el centro
X1_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0.5000
X1_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0.3333
X1_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0.1667
X1_0, 3, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0.0000
formation: 3
# Cuatro enemigos BALLOON1 uno detrás del otro. A la derecha y hacia el centro
X1_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0.5000
X1_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0.3333
X1_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0.1667
X1_100, -3, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0.0000
formation: 4
# Tres enemigos BALLOON2. 0, 25, 50. Hacia la derecha
X2_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.3333
X2_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.1667
X2_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.0000
formation: 5
# Tres enemigos BALLOON2. 50, 75, 100. Hacia la izquierda
X2_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.3333
X2_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.1667
X2_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.0000
formation: 6
# Tres enemigos BALLOON2. 0, 0, 0. Hacia la derecha
X2_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.3333
X2_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.1667
X2_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.0000
formation: 7
# Tres enemigos BALLOON2. 100, 100, 100. Hacia la izquierda
X2_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.3333
X2_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.1667
X2_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.0000
formation: 8
# Seis enemigos BALLOON0. 0, 0, 0, 0, 0, 0. Hacia la derecha
X0_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.8333
X0_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.6667
X0_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.5000
X0_0, 3, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.3333
X0_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.1667
X0_0, 5, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.0000
formation: 9
# Seis enemigos BALLOON0. 100, 100, 100, 100, 100, 100. Hacia la izquierda
X0_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.8333
X0_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.6667
X0_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.5000
X0_100, -3, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.3333
X0_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.1667
X0_100, -5, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.0000
formation: 10
# Tres enemigos BALLOON3 seguidos desde la izquierda. Hacia la derecha
X3_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, EXTRALARGE, 0.5000
X3_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, EXTRALARGE, 0.2500
X3_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, EXTRALARGE, 0.0000
formation: 11
# Tres enemigos BALLOON3 seguidos desde la derecha. Hacia la izquierda
X3_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, EXTRALARGE, 0.5000
X3_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, EXTRALARGE, 0.2500
X3_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, EXTRALARGE, 0.0000
formation: 12
# Seis enemigos BALLOON1 uno detrás del otro. A la izquierda y hacia el centro
X1_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0.8333
X1_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0.6667
X1_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0.5000
X1_0, 3, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0.3333
X1_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0.1667
X1_0, 5, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0.0000
formation: 13
# Seis enemigos BALLOON1 uno detrás del otro. A la derecha y hacia el centro
X1_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0.8333
X1_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0.6667
X1_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0.5000
X1_100, -3, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0.3333
X1_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0.1667
X1_100, -5, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0.0000
formation: 14
# Cinco enemigos BALLOON2. Hacia la derecha. Separados
X2_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.6667
X2_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.5000
X2_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.3333
X2_0, 6, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.1667
X2_0, 8, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.0000
formation: 15
# Cinco enemigos BALLOON2. Hacia la izquierda. Separados
X2_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.6667
X2_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.5000
X2_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.3333
X2_100, -6, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.1667
X2_100, -8, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.0000
formation: 16
# Cinco enemigos BALLOON2. Hacia la derecha. Juntos
X2_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.6667
X2_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.5000
X2_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.3333
X2_0, 3, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.1667
X2_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.0000
formation: 17
# Cinco enemigos BALLOON2. Hacia la izquierda. Juntos
X2_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.6667
X2_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.5000
X2_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.3333
X2_100, -3, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.1667
X2_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.0000
formation: 18
# Doce enemigos BALLOON0. Hacia la derecha. Juntos
X0_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 1.8333
X0_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 1.6667
X0_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 1.5000
X0_0, 3, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 1.3333
X0_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 1.1667
X0_0, 5, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 1.0000
X0_0, 6, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.8333
X0_0, 7, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.6667
X0_0, 8, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.5000
X0_0, 9, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.3333
X0_0, 10, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.1667
X0_0, 11, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.0000
formation: 19
# Doce enemigos BALLOON0. Hacia la izquierda. Juntos
X0_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 1.8333
X0_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 1.6667
X0_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 1.5000
X0_100, -3, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 1.3333
X0_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 1.1667
X0_100, -5, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 1.0000
X0_100, -6, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.8333
X0_100, -7, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.6667
X0_100, -8, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.5000
X0_100, -9, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.3333
X0_100, -10, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.1667
X0_100, -11, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.0000
formation: 20
# Cuatro enemigos BALLOON3 seguidos desde la izquierda/derecha. Simétricos
X3_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, EXTRALARGE, 0.0000
X3_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, EXTRALARGE, 0.0000
X3_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, EXTRALARGE, 0.0000
X3_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, EXTRALARGE, 0.0000
formation: 21
# Diez enemigos BALLOON1 uno detrás del otro. Izquierda/derecha. Simétricos
X1_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0.2000
X1_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0.1500
X1_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0.1000
X1_0, 3, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0.0500
X1_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0.0000
X1_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0.2000
X1_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0.1500
X1_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0.1000
X1_100, -3, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0.0500
X1_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0.0000
formation: 22
# Diez enemigos BALLOON2. Hacia la derecha/izquierda. Separados. Simétricos
X2_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.6667
X2_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.5000
X2_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.3333
X2_0, 6, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.1667
X2_0, 8, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.0000
X2_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.6667
X2_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.5000
X2_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.3333
X2_100, -6, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.1667
X2_100, -8, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.0000
formation: 23
# Diez enemigos BALLOON2. Hacia la derecha. Juntos. Simétricos
X2_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.6667
X2_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.5000
X2_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.3333
X2_0, 3, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.1667
X2_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0.0000
X2_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.6667
X2_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.5000
X2_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.3333
X2_100, -3, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.1667
X2_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0.0000
formation: 24
# Treinta enemigos BALLOON0. Del centro hacia los extremos. Juntos. Simétricos
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.0000
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.0833
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.1667
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.2500
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.3333
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.4167
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.5000
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.5833
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.6667
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.7500
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.8333
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.9167
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 1.0000
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 1.0833
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 1.1667
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.0000
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.0833
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.1667
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.2500
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.3333
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.4167
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.5000
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.5833
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.6667
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.7500
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.8333
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.9167
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 1.0000
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 1.0833
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 1.1667
formation: 25
# Treinta enemigos BALLOON0. Del centro hacia adentro. Juntos. Simétricos
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 1.1667
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 1.0833
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 1.0000
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.9167
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.8333
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.7500
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.6667
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.5833
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.5000
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.4167
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.3333
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.2500
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.1667
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.0833
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0.0000
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 1.1667
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 1.0833
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 1.0000
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.9167
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.8333
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.7500
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.6667
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.5833
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.5000
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.4167
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.3333
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.2500
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.1667
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.0833
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0.0000

View File

@@ -40,7 +40,7 @@ scoreboard.skip_countdown_value 8 # Valor para saltar la cuenta atrás (
# --- TITLE --- # --- TITLE ---
title.press_start_position 180 # Posición Y del texto "Press Start" 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.title_duration 14 # Duración de la pantalla de título (segundos)
title.arcade_edition_position 123 # Posición Y del subtítulo "Arcade Edition" 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.title_c_c_position 80 # Posición Y del título principal
title.bg_color 41526F # Color de fondo en la sección titulo title.bg_color 41526F # Color de fondo en la sección titulo
@@ -48,15 +48,15 @@ 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) background.attenuate_color FFFFFF00 # Color de atenuación del fondo (RGBA hexadecimal)
# --- BALLOONS --- # --- BALLOONS --- (deltaTime en segundos: vel en pixels/s, grav en pixels/s²)
balloon.settings[0].vel 2.75f # Velocidad inicial del globo 1 balloon.settings[0].vel 165.0f # Velocidad inicial del globo 1 (pixels/s)
balloon.settings[0].grav 0.09f # Gravedad aplicada al globo 1 balloon.settings[0].grav 320.0f # Gravedad aplicada al globo 1 (pixels/s²)
balloon.settings[1].vel 3.70f # Velocidad inicial del globo 2 balloon.settings[1].vel 222.0f # Velocidad inicial del globo 2 (pixels/s)
balloon.settings[1].grav 0.10f # Gravedad aplicada al globo 2 balloon.settings[1].grav 360.0f # Gravedad aplicada al globo 2 (pixels/s²)
balloon.settings[2].vel 4.70f # Velocidad inicial del globo 3 balloon.settings[2].vel 282.0f # Velocidad inicial del globo 3 (pixels/s)
balloon.settings[2].grav 0.10f # Gravedad aplicada al globo 3 balloon.settings[2].grav 360.0f # Gravedad aplicada al globo 3 (pixels/s²)
balloon.settings[3].vel 5.45f # Velocidad inicial del globo 4 balloon.settings[3].vel 327.0f # Velocidad inicial del globo 4 (pixels/s)
balloon.settings[3].grav 0.10f # Gravedad aplicada al globo 4 balloon.settings[3].grav 360.0f # Gravedad aplicada al globo 4 (pixels/s²)
balloon.color[0] blue # Color de creación del globo normal balloon.color[0] blue # Color de creación del globo normal
balloon.color[1] orange # Color del globo normal balloon.color[1] orange # Color del globo normal

View File

@@ -40,7 +40,7 @@ scoreboard.skip_countdown_value 8 # Valor para saltar la cuenta atrás (
# --- TITLE --- # --- TITLE ---
title.press_start_position 180 # Posición Y del texto "Press Start" 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.title_duration 14 # Duración de la pantalla de título (segundos)
title.arcade_edition_position 123 # Posición Y del subtítulo "Arcade Edition" 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.title_c_c_position 80 # Posición Y del título principal
title.bg_color 41526F # Color de fondo en la sección titulo title.bg_color 41526F # Color de fondo en la sección titulo
@@ -48,15 +48,15 @@ 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) background.attenuate_color FFFFFF00 # Color de atenuación del fondo (RGBA hexadecimal)
# --- BALLOONS --- # --- BALLOONS --- (deltaTime en segundos: vel en pixels/s, grav en pixels/s²)
balloon.settings[0].vel 2.75f # Velocidad inicial del globo 1 balloon.settings[0].vel 165.0f # Velocidad inicial del globo 1 (pixels/s)
balloon.settings[0].grav 0.09f # Gravedad aplicada al globo 1 balloon.settings[0].grav 320.0f # Gravedad aplicada al globo 1 (pixels/s²)
balloon.settings[1].vel 3.70f # Velocidad inicial del globo 2 balloon.settings[1].vel 222.0f # Velocidad inicial del globo 2 (pixels/s)
balloon.settings[1].grav 0.10f # Gravedad aplicada al globo 2 balloon.settings[1].grav 360.0f # Gravedad aplicada al globo 2 (pixels/s²)
balloon.settings[2].vel 4.70f # Velocidad inicial del globo 3 balloon.settings[2].vel 282.0f # Velocidad inicial del globo 3 (pixels/s)
balloon.settings[2].grav 0.10f # Gravedad aplicada al globo 3 balloon.settings[2].grav 360.0f # Gravedad aplicada al globo 3 (pixels/s²)
balloon.settings[3].vel 5.45f # Velocidad inicial del globo 4 balloon.settings[3].vel 327.0f # Velocidad inicial del globo 4 (pixels/s)
balloon.settings[3].grav 0.10f # Gravedad aplicada al globo 4 balloon.settings[3].grav 360.0f # Gravedad aplicada al globo 4 (pixels/s²)
balloon.color[0] blue # Color de creación del globo normal balloon.color[0] blue # Color de creación del globo normal
balloon.color[1] orange # Color del globo normal balloon.color[1] orange # Color del globo normal

View File

@@ -1,277 +0,0 @@
# 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
# X3_25, X3_75, DEFAULT_POS_Y
# SMALL, MEDIUM, LARGE, EXTRALARGE
# RIGHT, LEFT
formation: 0
# Dos enemigos BALLOON3 uno a cada extremo
X3_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, EXTRALARGE, 0
X3_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, EXTRALARGE, 0
formation: 1
# Dos enemigos BALLOON3 uno a cada cuarto. Ambos van hacia el centro
X3_25, 0, DEFAULT_POS_Y, RIGHT, BALLOON, EXTRALARGE, 0
X3_75, 0, DEFAULT_POS_Y, LEFT, BALLOON, EXTRALARGE, 0
formation: 2
# Cuatro enemigos BALLOON1 uno detrás del otro. A la izquierda y hacia el centro
X1_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 30
X1_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 20
X1_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 10
X1_0, 3, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0
formation: 3
# Cuatro enemigos BALLOON1 uno detrás del otro. A la derecha y hacia el centro
X1_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 30
X1_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 20
X1_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 10
X1_100, -3, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0
formation: 4
# Tres enemigos BALLOON2. 0, 25, 50. Hacia la derecha
X2_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 20
X2_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 10
X2_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0
formation: 5
# Tres enemigos BALLOON2. 50, 75, 100. Hacia la izquierda
X2_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 20
X2_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 10
X2_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0
formation: 6
# Tres enemigos BALLOON2. 0, 0, 0. Hacia la derecha
X2_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 20
X2_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 10
X2_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0
formation: 7
# Tres enemigos BALLOON2. 100, 100, 100. Hacia la izquierda
X2_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 20
X2_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 10
X2_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0
formation: 8
# Seis enemigos BALLOON0. 0, 0, 0, 0, 0, 0. Hacia la derecha
X0_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 50
X0_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 40
X0_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 30
X0_0, 3, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 20
X0_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 10
X0_0, 5, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0
formation: 9
# Seis enemigos BALLOON0. 100, 100, 100, 100, 100, 100. Hacia la izquierda
X0_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 50
X0_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 40
X0_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 30
X0_100, -3, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 20
X0_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 10
X0_100, -5, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0
formation: 10
# Tres enemigos BALLOON3 seguidos desde la izquierda. Hacia la derecha
X3_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, EXTRALARGE, 30
X3_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, EXTRALARGE, 15
X3_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, EXTRALARGE, 0
formation: 11
# Tres enemigos BALLOON3 seguidos desde la derecha. Hacia la izquierda
X3_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, EXTRALARGE, 30
X3_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, EXTRALARGE, 15
X3_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, EXTRALARGE, 0
formation: 12
# Seis enemigos BALLOON1 uno detrás del otro. A la izquierda y hacia el centro
X1_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 50
X1_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 40
X1_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 30
X1_0, 3, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 20
X1_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 10
X1_0, 5, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0
formation: 13
# Seis enemigos BALLOON1 uno detrás del otro. A la derecha y hacia el centro
X1_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 50
X1_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 40
X1_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 30
X1_100, -3, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 20
X1_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 10
X1_100, -5, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0
formation: 14
# Cinco enemigos BALLOON2. Hacia la derecha. Separados
X2_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 40
X2_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 30
X2_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 20
X2_0, 6, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 10
X2_0, 8, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0
formation: 15
# Cinco enemigos BALLOON2. Hacia la izquierda. Separados
X2_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 40
X2_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 30
X2_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 20
X2_100, -6, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 10
X2_100, -8, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0
formation: 16
# Cinco enemigos BALLOON2. Hacia la derecha. Juntos
X2_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 40
X2_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 30
X2_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 20
X2_0, 3, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 10
X2_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0
formation: 17
# Cinco enemigos BALLOON2. Hacia la izquierda. Juntos
X2_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 40
X2_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 30
X2_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 20
X2_100, -3, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 10
X2_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0
formation: 18
# Doce enemigos BALLOON0. Hacia la derecha. Juntos
X0_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 110
X0_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 100
X0_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 90
X0_0, 3, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 80
X0_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 70
X0_0, 5, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 60
X0_0, 6, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 50
X0_0, 7, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 40
X0_0, 8, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 30
X0_0, 9, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 20
X0_0, 10, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 10
X0_0, 11, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0
formation: 19
# Doce enemigos BALLOON0. Hacia la izquierda. Juntos
X0_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 110
X0_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 100
X0_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 90
X0_100, -3, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 80
X0_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 70
X0_100, -5, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 60
X0_100, -6, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 50
X0_100, -7, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 40
X0_100, -8, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 30
X0_100, -9, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 20
X0_100, -10, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 10
X0_100, -11, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0
formation: 20
# Cuatro enemigos BALLOON3 seguidos desde la izquierda/derecha. Simétricos
X3_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, EXTRALARGE, 0
X3_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, EXTRALARGE, 0
X3_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, EXTRALARGE, 0
X3_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, EXTRALARGE, 0
formation: 21
# Diez enemigos BALLOON1 uno detrás del otro. Izquierda/derecha. Simétricos
X1_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 12
X1_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 9
X1_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 6
X1_0, 3, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 3
X1_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, MEDIUM, 0
X1_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 12
X1_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 9
X1_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 6
X1_100, -3, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 3
X1_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, MEDIUM, 0
formation: 22
# Diez enemigos BALLOON2. Hacia la derecha/izquierda. Separados. Simétricos
X2_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 40
X2_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 30
X2_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 20
X2_0, 6, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 10
X2_0, 8, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0
X2_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 40
X2_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 30
X2_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 20
X2_100, -6, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 10
X2_100, -8, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0
formation: 23
# Diez enemigos BALLOON2. Hacia la derecha. Juntos. Simétricos
X2_0, 0, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 40
X2_0, 1, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 30
X2_0, 2, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 20
X2_0, 3, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 10
X2_0, 4, DEFAULT_POS_Y, RIGHT, BALLOON, LARGE, 0
X2_100, 0, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 40
X2_100, -1, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 30
X2_100, -2, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 20
X2_100, -3, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 10
X2_100, -4, DEFAULT_POS_Y, LEFT, BALLOON, LARGE, 0
formation: 24
# Treinta enemigos BALLOON0. Del centro hacia los extremos. Juntos. Simétricos
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 5
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 10
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 15
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 20
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 25
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 30
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 35
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 40
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 45
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 50
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 55
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 60
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 65
X0_50, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 70
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 5
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 10
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 15
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 20
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 25
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 30
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 35
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 40
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 45
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 50
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 55
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 60
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 65
X0_50, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 70
formation: 25
# Treinta enemigos BALLOON0. Del centro hacia adentro. Juntos. Simétricos
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 70
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 65
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 60
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 55
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 50
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 45
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 40
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 35
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 30
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 25
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 20
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 15
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 10
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 5
X0_50 + 20, 0, DEFAULT_POS_Y, LEFT, BALLOON, SMALL, 0
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 70
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 65
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 60
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 55
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 50
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 45
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 40
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 35
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 30
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 25
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 20
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 15
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 10
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 5
X0_50 - 20, 0, DEFAULT_POS_Y, RIGHT, BALLOON, SMALL, 0

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 872 B

After

Width:  |  Height:  |  Size: 882 B

View File

@@ -3,28 +3,28 @@ frame_height=10
[animation] [animation]
name=orange name=orange
speed=10 speed=0.1667
loop=0 loop=0
frames=0,1,2,3,4,5,6,7,8,9 frames=0,1,2,3,4,5,6,7,8,9
[/animation] [/animation]
[animation] [animation]
name=blue name=blue
speed=20 speed=0.3333
loop=0 loop=0
frames=10,11,12,13,14,15,16,17,18,19 frames=10,11,12,13,14,15,16,17,18,19
[/animation] [/animation]
[animation] [animation]
name=green name=green
speed=10 speed=0.1667
loop=0 loop=0
frames=20,21,22,23,24,25,26,27,28,29 frames=20,21,22,23,24,25,26,27,28,29
[/animation] [/animation]
[animation] [animation]
name=red name=red
speed=20 speed=0.3333
loop=0 loop=0
frames=30,31,32,33,34,35,36,37,38,39 frames=30,31,32,33,34,35,36,37,38,39
[/animation] [/animation]

View File

@@ -3,28 +3,28 @@ frame_height=16
[animation] [animation]
name=orange name=orange
speed=10 speed=0.1667
loop=0 loop=0
frames=0,1,2,3,4,5,6,7,8,9 frames=0,1,2,3,4,5,6,7,8,9
[/animation] [/animation]
[animation] [animation]
name=blue name=blue
speed=20 speed=0.3333
loop=0 loop=0
frames=10,11,12,13,14,15,16,17,18,19 frames=10,11,12,13,14,15,16,17,18,19
[/animation] [/animation]
[animation] [animation]
name=green name=green
speed=10 speed=0.1667
loop=0 loop=0
frames=20,21,22,23,24,25,26,27,28,29 frames=20,21,22,23,24,25,26,27,28,29
[/animation] [/animation]
[animation] [animation]
name=red name=red
speed=20 speed=0.3333
loop=0 loop=0
frames=30,31,32,33,34,35,36,37,38,39 frames=30,31,32,33,34,35,36,37,38,39
[/animation] [/animation]

View File

@@ -3,28 +3,28 @@ frame_height=26
[animation] [animation]
name=orange name=orange
speed=10 speed=0.1667
loop=0 loop=0
frames=0,1,2,3,4,5,6,7,8,9 frames=0,1,2,3,4,5,6,7,8,9
[/animation] [/animation]
[animation] [animation]
name=blue name=blue
speed=20 speed=0.3333
loop=0 loop=0
frames=10,11,12,13,14,15,16,17,18,19 frames=10,11,12,13,14,15,16,17,18,19
[/animation] [/animation]
[animation] [animation]
name=green name=green
speed=10 speed=0.1667
loop=0 loop=0
frames=20,21,22,23,24,25,26,27,28,29 frames=20,21,22,23,24,25,26,27,28,29
[/animation] [/animation]
[animation] [animation]
name=red name=red
speed=20 speed=0.3333
loop=0 loop=0
frames=30,31,32,33,34,35,36,37,38,39 frames=30,31,32,33,34,35,36,37,38,39
[/animation] [/animation]

View File

@@ -3,28 +3,28 @@ frame_height=48
[animation] [animation]
name=orange name=orange
speed=10 speed=0.1667
loop=0 loop=0
frames=0,1,2,3,4,5,6,7,8,9 frames=0,1,2,3,4,5,6,7,8,9
[/animation] [/animation]
[animation] [animation]
name=blue name=blue
speed=20 speed=0.3333
loop=0 loop=0
frames=10,11,12,13,14,15,16,17,18,19 frames=10,11,12,13,14,15,16,17,18,19
[/animation] [/animation]
[animation] [animation]
name=green name=green
speed=10 speed=0.1667
loop=0 loop=0
frames=20,21,22,23,24,25,26,27,28,29 frames=20,21,22,23,24,25,26,27,28,29
[/animation] [/animation]
[animation] [animation]
name=red name=red
speed=20 speed=0.3333
loop=0 loop=0
frames=30,31,32,33,34,35,36,37,38,39 frames=30,31,32,33,34,35,36,37,38,39
[/animation] [/animation]

View File

@@ -3,7 +3,7 @@ frame_height=10
[animation] [animation]
name=default name=default
speed=5 speed=0.0833
loop=-1 loop=-1
frames=0,1,2,3,4,5,6,7,8,9 frames=0,1,2,3,4,5,6,7,8,9
[/animation] [/animation]

View File

@@ -3,7 +3,7 @@ frame_height=16
[animation] [animation]
name=default name=default
speed=5 speed=0.0833
loop=-1 loop=-1
frames=0,1,2,3,4,5,6,7,8,9 frames=0,1,2,3,4,5,6,7,8,9
[/animation] [/animation]

View File

@@ -3,7 +3,7 @@ frame_height=26
[animation] [animation]
name=default name=default
speed=5 speed=0.0833
loop=-1 loop=-1
frames=0,1,2,3,4,5,6,7,8,9 frames=0,1,2,3,4,5,6,7,8,9
[/animation] [/animation]

View File

@@ -3,7 +3,7 @@ frame_height=48
[animation] [animation]
name=default name=default
speed=5 speed=0.0833
loop=-1 loop=-1
frames=0,1,2,3,4,5,6,7,8,9 frames=0,1,2,3,4,5,6,7,8,9
[/animation] [/animation]

View File

@@ -3,7 +3,7 @@ frame_height=49
[animation] [animation]
name=powerball name=powerball
speed=10 speed=0.0167
loop=-1 loop=-1
frames=1 frames=1
[/animation] [/animation]

View File

@@ -2,43 +2,85 @@ frame_width=12
frame_height=12 frame_height=12
[animation] [animation]
name=normal_up name=yellow_up
speed=5 speed=20
loop=0 loop=-1
frames=0,1,2 frames=0
[/animation] [/animation]
[animation] [animation]
name=normal_left name=yellow_left
speed=5 speed=20
loop=0 loop=-1
frames=3,4,5,5,4,3 frames=1
[/animation] [/animation]
[animation] [animation]
name=normal_right name=yellow_right
speed=5 speed=20
loop=0 loop=-1
frames=6,7,8,8,7,6 frames=2
[/animation] [/animation]
[animation] [animation]
name=powered_up name=green_up
speed=5 speed=20
loop=0 loop=-1
frames=9,10,11,11,10,9 frames=3
[/animation] [/animation]
[animation] [animation]
name=powered_left name=green_left
speed=5 speed=20
loop=0 loop=-1
frames=12,13,14,14,13,12 frames=4
[/animation] [/animation]
[animation] [animation]
name=powered_right name=green_right
speed=5 speed=20
loop=0 loop=-1
frames=15,16,17,17,26,15 frames=5
[/animation]
[animation]
name=red_up
speed=20
loop=-1
frames=6
[/animation]
[animation]
name=red_left
speed=20
loop=-1
frames=7
[/animation]
[animation]
name=red_right
speed=20
loop=-1
frames=8
[/animation]
[animation]
name=purple_up
speed=20
loop=-1
frames=9
[/animation]
[animation]
name=purple_left
speed=20
loop=-1
frames=10
[/animation]
[animation]
name=purple_right
speed=20
loop=-1
frames=11
[/animation] [/animation]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -3,7 +3,7 @@ frame_height=20
[animation] [animation]
name=default name=default
speed=8 speed=0.1333
loop=0 loop=0
frames=0,0,1 frames=0,0,1
[/animation] [/animation]

View File

@@ -3,7 +3,7 @@ frame_height=20
[animation] [animation]
name=default name=default
speed=8 speed=0.1333
loop=0 loop=0
frames=0,0,1 frames=0,0,1
[/animation] [/animation]

View File

@@ -3,7 +3,7 @@ frame_height=39
[animation] [animation]
name=default name=default
speed=6 speed=0.1
loop=0 loop=0
frames=0,1,2,3,4,5,6,7,8 frames=0,1,2,3,4,5,6,7,8
[/animation] [/animation]

View File

@@ -3,7 +3,7 @@ frame_height=20
[animation] [animation]
name=default name=default
speed=8 speed=0.1333
loop=0 loop=0
frames=0,0,1 frames=0,0,1
[/animation] [/animation]

View File

@@ -3,7 +3,7 @@ frame_height=20
[animation] [animation]
name=default name=default
speed=8 speed=0.1333
loop=0 loop=0
frames=0,0,1 frames=0,0,1
[/animation] [/animation]

View File

@@ -3,7 +3,7 @@ frame_height=20
[animation] [animation]
name=default name=default
speed=8 speed=0.1333
loop=0 loop=0
frames=0,0,1 frames=0,0,1
[/animation] [/animation]

View File

@@ -3,7 +3,7 @@ frame_height=20
[animation] [animation]
name=default name=default
speed=8 speed=0.1333
loop=0 loop=0
frames=0,0,1 frames=0,0,1
[/animation] [/animation]

View File

@@ -3,133 +3,133 @@ frame_height=32
[animation] [animation]
name=walk name=walk
speed=5 speed=0.0833
loop=0 loop=0
frames=0,1,2,3 frames=0,1,2,3
[/animation] [/animation]
[animation] [animation]
name=stand name=stand
speed=10 speed=0.167
loop=0 loop=0
frames=4,5,6,7 frames=4,5,6,7
[/animation] [/animation]
[animation] [animation]
name=walk-fire-side name=walk-fire-side
speed=5 speed=0.0833
loop=0 loop=0
frames=8,9,10,11 frames=8,9,10,11
[/animation] [/animation]
[animation] [animation]
name=walk-recoil-side name=walk-recoil-side
speed=5 speed=0.0833
loop=0 loop=0
frames=12,13,14,15 frames=12,13,14,15
[/animation] [/animation]
[animation] [animation]
name=walk-cool-side name=walk-cool-side
speed=5 speed=0.0833
loop=0 loop=0
frames=16,17,18,19 frames=16,17,18,19
[/animation] [/animation]
[animation] [animation]
name=stand-fire-side name=stand-fire-side
speed=5 speed=0.0833
loop=0 loop=0
frames=20 frames=20
[/animation] [/animation]
[animation] [animation]
name=stand-recoil-side name=stand-recoil-side
speed=5 speed=0.0833
loop=0 loop=0
frames=21 frames=21
[/animation] [/animation]
[animation] [animation]
name=stand-cool-side name=stand-cool-side
speed=5 speed=0.0833
loop=0 loop=0
frames=22 frames=22
[/animation] [/animation]
[animation] [animation]
name=walk-fire-center name=walk-fire-center
speed=5 speed=0.0833
loop=0 loop=0
frames=23,24,25,26 frames=23,24,25,26
[/animation] [/animation]
[animation] [animation]
name=walk-recoil-center name=walk-recoil-center
speed=5 speed=0.0833
loop=0 loop=0
frames=27,28,29,30 frames=27,28,29,30
[/animation] [/animation]
[animation] [animation]
name=walk-cool-center name=walk-cool-center
speed=5 speed=0.0833
loop=0 loop=0
frames=31,32,33,34 frames=31,32,33,34
[/animation] [/animation]
[animation] [animation]
name=stand-fire-center name=stand-fire-center
speed=5 speed=0.0833
loop=0 loop=0
frames=35 frames=35
[/animation] [/animation]
[animation] [animation]
name=stand-recoil-center name=stand-recoil-center
speed=5 speed=0.0833
loop=0 loop=0
frames=36 frames=36
[/animation] [/animation]
[animation] [animation]
name=stand-cool-center name=stand-cool-center
speed=5 speed=0.0833
loop=0 loop=0
frames=37 frames=37
[/animation] [/animation]
[animation] [animation]
name=rolling name=rolling
speed=10 speed=0.167
loop=0 loop=0
frames=38,39,40,41 frames=38,39,40,41
[/animation] [/animation]
[animation] [animation]
name=celebration name=celebration
speed=10 speed=0.167
loop=-1 loop=0
frames=42,42,42,42,42,42,43,44,45,46,46,46,46,46,46,45,45,45,46,46,46,45,45,45,44,43,42,42,42 frames=42,42,42,42,42,42,43,44,45,46,46,46,46,46,46,45,45,45,46,46,46,45,45,45,44,43,42,42,42
[/animation] [/animation]
[animation] [animation]
name=dizzy name=dizzy
speed=5 speed=0.0833
loop=0 loop=0
frames=47,48,49,50,51,52,53 frames=47,48,49,50,51,52,53
[/animation] [/animation]
[animation] [animation]
name=recover name=recover
speed=3 speed=0.05
loop=-1 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 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]
[animation] [animation]
name=hello name=hello
speed=3 speed=0.05
loop=-1 loop=-1
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 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] [/animation]

View File

@@ -3,7 +3,7 @@ frame_height=44
[animation] [animation]
name=default name=default
speed=5 speed=0.0833
loop=0 loop=0
frames=0,1,2,3 frames=0,1,2,3
[/animation] [/animation]

View File

@@ -3,14 +3,14 @@ frame_height=32
[animation] [animation]
name=fly name=fly
speed=2 speed=0.0333
loop=0 loop=0
frames=0,1 frames=0,1
[/animation] [/animation]
[animation] [animation]
name=hit name=hit
speed=2 speed=0.0333
loop=0 loop=0
frames=2,3 frames=2,3
[/animation] [/animation]

View File

@@ -3,7 +3,7 @@ frame_height=16
[animation] [animation]
name=default name=default
speed=8 speed=0.1333
loop=-1 loop=-1
frames=0,1,2,3,4,5,6 frames=0,1,2,3,4,5,6
[/animation] [/animation]

View File

@@ -27,6 +27,7 @@
"[GAME_TEXT] 7": "Endavant!", "[GAME_TEXT] 7": "Endavant!",
"[GAME_TEXT] 8": "1.000.000 de punts!", "[GAME_TEXT] 8": "1.000.000 de punts!",
"[GAME_TEXT] THANK_YOU": "Gracies!", "[GAME_TEXT] THANK_YOU": "Gracies!",
"[GAME_TEXT] NEW_RECORD": "Nou record!",
"[HIGHSCORE_TABLE] CAPTION": "Millors puntuacions", "[HIGHSCORE_TABLE] CAPTION": "Millors puntuacions",

View File

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

View File

@@ -26,6 +26,7 @@
"[GAME_TEXT] 7": "Adelante!", "[GAME_TEXT] 7": "Adelante!",
"[GAME_TEXT] 8": "1.000.000 de puntos!", "[GAME_TEXT] 8": "1.000.000 de puntos!",
"[GAME_TEXT] THANK_YOU": "Gracias!", "[GAME_TEXT] THANK_YOU": "Gracias!",
"[GAME_TEXT] NEW_RECORD": "Nuevo record!",
"[HIGHSCORE_TABLE] CAPTION": "Mejores puntuaciones", "[HIGHSCORE_TABLE] CAPTION": "Mejores puntuaciones",

Binary file not shown.

BIN
data/sound/bullet2p.wav Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

43
development_guidelines.md Normal file
View File

@@ -0,0 +1,43 @@
# Directrices de Desarrollo - Coffee Crisis Arcade Edition
## Directrices Principales Confirmadas
### 1. **Sistema Temporal**
- **TODO migrado de frame based a time based**
- **Delta time en segundos (float)**
- **Unidades de tiempo: SOLO segundos** (no frames, no milisegundos)
### 2. **Contadores y Timers**
- **CRECIENTES**: para sistemas con múltiples eventos temporales (timeline)
- Patrón: `elapsed_time += deltaTime; if (elapsed_time >= EVENT_TIME) { /* acción */ }`
- **DECRECIENTES**: para contadores con diferentes valores de inicialización
- Patrón: `timer -= deltaTime; if (timer <= 0.0f) { /* acción */ timer = DURATION; }`
### 3. **Números Mágicos**
- **Definidos en constantes**
- **Preferencia**: cabecera de la clase
- **Excepción**: si es algo local a un método específico
## Problemas Pendientes de Reparación (game.cpp)
### ❌ PENDIENTES
1. **param.fade.post_duration_ms verification** (líneas 89, 1671)
2. **setRotateSpeed verification** (línea 797)
3. **TOTAL_DEMO_DATA - 200 magic number** (línea 1669)
4. **Comprehensive magic number search** - Buscar 100, 150, 200, 250, 300, 400, 500, 1000
### 4. **Velocidades y Aceleraciones**
- **Velocidades**: pixels/segundo
- **Aceleraciones**: pixels/segundo²
### 5. **Documentación de Conversiones**
- **Comentarios explicativos** en cambios críticos de timing
- Documentar conversiones frame→tiempo en el código
### 6. **Patrón de Constantes**
- Crear constantes para valores repetidos (evitar duplicación)
- Nombres descriptivos para constantes de tiempo
---
**Estado**: Directrices completas confirmadas

BIN
input.o

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -9,22 +9,44 @@
#include <stdexcept> // Para runtime_error #include <stdexcept> // Para runtime_error
#include <utility> // Para pair #include <utility> // Para pair
#include "resource_helper.h" // Para ResourceHelper
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "utils.h" // Para printWithDots #include "utils.h" // Para printWithDots
// Carga las animaciones en un vector(Animations) desde un fichero // Carga las animaciones en un vector(Animations) desde un fichero
auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffer { auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffer {
std::ifstream file(file_path); // Intentar cargar desde ResourceHelper primero
auto resource_data = ResourceHelper::loadFile(file_path);
std::istringstream stream;
bool using_resource_data = false;
if (!resource_data.empty()) {
std::string content(resource_data.begin(), resource_data.end());
stream.str(content);
using_resource_data = true;
}
// Fallback a archivo directo
std::ifstream file;
if (!using_resource_data) {
file.open(file_path);
if (!file) { if (!file) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str()); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str());
throw std::runtime_error("Fichero no encontrado: " + file_path); throw std::runtime_error("Fichero no encontrado: " + file_path);
} }
}
std::istream& input_stream = using_resource_data ? stream : static_cast<std::istream&>(file);
printWithDots("Animation : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]"); printWithDots("Animation : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]");
std::vector<std::string> buffer; std::vector<std::string> buffer;
std::string line; std::string line;
while (std::getline(file, line)) { while (std::getline(input_stream, line)) {
// Eliminar caracteres de retorno de carro (\r) al final de la línea
if (!line.empty() && line.back() == '\r') {
line.pop_back();
}
if (!line.empty()) { if (!line.empty()) {
buffer.push_back(line); buffer.push_back(line);
} }
@@ -64,33 +86,33 @@ auto AnimatedSprite::getAnimationIndex(const std::string& name) -> int {
return -1; return -1;
} }
// Calcula el frame correspondiente a la animación // Calcula el frame correspondiente a la animación (time-based)
void AnimatedSprite::animate() { void AnimatedSprite::animate(float deltaTime) {
if (animations_[current_animation_].speed == 0 || animations_[current_animation_].paused) { if (animations_[current_animation_].speed == 0 || animations_[current_animation_].paused) {
return; return;
} }
// Calcula el frame actual a partir del contador // Acumular tiempo transcurrido
animations_[current_animation_].current_frame = animations_[current_animation_].counter / animations_[current_animation_].speed; animations_[current_animation_].time_accumulator += deltaTime;
// Si alcanza el final de la animación, reinicia el contador de la animación // Verificar si es momento de cambiar frame
// en función de la variable loop y coloca el nuevo frame if (animations_[current_animation_].time_accumulator >= animations_[current_animation_].speed) {
animations_[current_animation_].time_accumulator -= animations_[current_animation_].speed;
animations_[current_animation_].current_frame++;
// Si alcanza el final de la animación
if (animations_[current_animation_].current_frame >= animations_[current_animation_].frames.size()) { if (animations_[current_animation_].current_frame >= animations_[current_animation_].frames.size()) {
if (animations_[current_animation_].loop == -1) { // Si no hay loop, deja el último frame if (animations_[current_animation_].loop == -1) { // Si no hay loop, deja el último frame
animations_[current_animation_].current_frame = animations_[current_animation_].frames.size(); animations_[current_animation_].current_frame = animations_[current_animation_].frames.size() - 1;
animations_[current_animation_].completed = true; animations_[current_animation_].completed = true;
} else { // Si hay loop, vuelve al frame indicado } else { // Si hay loop, vuelve al frame indicado
animations_[current_animation_].counter = 0; animations_[current_animation_].time_accumulator = 0.0f;
animations_[current_animation_].current_frame = animations_[current_animation_].loop; animations_[current_animation_].current_frame = animations_[current_animation_].loop;
} }
} }
// En caso contrario
else {
// Escoge el frame correspondiente de la animación
updateSpriteClip();
// Incrementa el contador de la animacion // Actualizar el sprite clip
animations_[current_animation_].counter++; updateSpriteClip();
} }
} }
@@ -107,11 +129,11 @@ void AnimatedSprite::setCurrentAnimation(const std::string& name, bool reset) {
current_animation_ = NEW_ANIMATION; current_animation_ = NEW_ANIMATION;
if (reset) { if (reset) {
animations_[current_animation_].current_frame = 0; animations_[current_animation_].current_frame = 0;
animations_[current_animation_].counter = 0; animations_[current_animation_].time_accumulator = 0.0f;
animations_[current_animation_].completed = false; animations_[current_animation_].completed = false;
} else { } else {
animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size() - 1); animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size() - 1);
animations_[current_animation_].counter = animations_[OLD_ANIMATION].counter; animations_[current_animation_].time_accumulator = animations_[OLD_ANIMATION].time_accumulator;
animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed; animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed;
} }
updateSpriteClip(); updateSpriteClip();
@@ -126,27 +148,27 @@ void AnimatedSprite::setCurrentAnimation(int index, bool reset) {
current_animation_ = NEW_ANIMATION; current_animation_ = NEW_ANIMATION;
if (reset) { if (reset) {
animations_[current_animation_].current_frame = 0; animations_[current_animation_].current_frame = 0;
animations_[current_animation_].counter = 0; animations_[current_animation_].time_accumulator = 0.0f;
animations_[current_animation_].completed = false; animations_[current_animation_].completed = false;
} else { } else {
animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size()); animations_[current_animation_].current_frame = std::min(animations_[OLD_ANIMATION].current_frame, animations_[current_animation_].frames.size());
animations_[current_animation_].counter = animations_[OLD_ANIMATION].counter; animations_[current_animation_].time_accumulator = animations_[OLD_ANIMATION].time_accumulator;
animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed; animations_[current_animation_].completed = animations_[OLD_ANIMATION].completed;
} }
updateSpriteClip(); updateSpriteClip();
} }
} }
// Actualiza las variables del objeto // Actualiza las variables del objeto (time-based)
void AnimatedSprite::update() { void AnimatedSprite::update(float deltaTime) {
animate(); animate(deltaTime);
MovingSprite::update(); MovingSprite::update(deltaTime);
} }
// Reinicia la animación // Reinicia la animación
void AnimatedSprite::resetAnimation() { void AnimatedSprite::resetAnimation() {
animations_[current_animation_].current_frame = 0; animations_[current_animation_].current_frame = 0;
animations_[current_animation_].counter = 0; animations_[current_animation_].time_accumulator = 0.0f;
animations_[current_animation_].completed = false; animations_[current_animation_].completed = false;
animations_[current_animation_].paused = false; animations_[current_animation_].paused = false;
updateSpriteClip(); updateSpriteClip();
@@ -172,6 +194,12 @@ void AnimatedSprite::loadFromAnimationsFileBuffer(const AnimationsFileBuffer& so
// Pone un valor por defecto // Pone un valor por defecto
setWidth(config.frame_width); setWidth(config.frame_width);
setHeight(config.frame_height); setHeight(config.frame_height);
// Establece el primer frame inmediatamente si hay animaciones
if (!animations_.empty()) {
current_animation_ = 0;
updateSpriteClip();
}
} }
// Procesa una línea de configuración // Procesa una línea de configuración
@@ -241,7 +269,7 @@ void AnimatedSprite::processAnimationParameter(const std::string& line, Animatio
if (key == "name") { if (key == "name") {
animation.name = value; animation.name = value;
} else if (key == "speed") { } else if (key == "speed") {
animation.speed = std::stoi(value); animation.speed = std::stof(value);
} else if (key == "loop") { } else if (key == "loop") {
animation.loop = std::stoi(value); animation.loop = std::stoi(value);
} else if (key == "frames") { } else if (key == "frames") {
@@ -268,7 +296,7 @@ void AnimatedSprite::parseFramesParameter(const std::string& frames_str, Animati
} }
// Establece la velocidad de la animación // Establece la velocidad de la animación
void AnimatedSprite::setAnimationSpeed(size_t value) { void AnimatedSprite::setAnimationSpeed(float value) {
animations_[current_animation_].speed = value; animations_[current_animation_].speed = value;
} }

View File

@@ -17,15 +17,15 @@ class Texture;
// --- Estructuras --- // --- Estructuras ---
struct Animation { struct Animation {
static constexpr int DEFAULT_SPEED = 5; static constexpr float DEFAULT_SPEED = 80.0F;
std::string name; // Nombre de la animación std::string name; // Nombre de la animación
std::vector<SDL_FRect> frames; // Frames que componen la animación std::vector<SDL_FRect> frames; // Frames que componen la animación
int speed{DEFAULT_SPEED}; // Velocidad de reproducción float speed{DEFAULT_SPEED}; // Velocidad de reproducción (ms entre frames)
int loop{0}; // Frame de vuelta al terminar (-1 para no repetir) int loop{0}; // Frame de vuelta al terminar (-1 para no repetir)
bool completed{false}; // Indica si la animación ha finalizado bool completed{false}; // Indica si la animación ha finalizado
size_t current_frame{0}; // Frame actual en reproducción size_t current_frame{0}; // Frame actual en reproducción
int counter{0}; // Contador para la animación float time_accumulator{0.0f}; // Acumulador de tiempo para animaciones time-based
bool paused{false}; // La animación no avanza bool paused{false}; // La animación no avanza
Animation() = default; Animation() = default;
@@ -50,18 +50,19 @@ class AnimatedSprite : public MovingSprite {
// --- Constructores y destructor --- // --- Constructores y destructor ---
AnimatedSprite(std::shared_ptr<Texture> texture, const std::string& file_path); AnimatedSprite(std::shared_ptr<Texture> texture, const std::string& file_path);
AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer& animations); AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer& animations);
explicit AnimatedSprite(std::shared_ptr<Texture> texture) : MovingSprite(std::move(texture)) {} explicit AnimatedSprite(std::shared_ptr<Texture> texture)
: MovingSprite(std::move(texture)) {}
~AnimatedSprite() override = default; ~AnimatedSprite() override = default;
// --- Métodos principales --- // --- Métodos principales ---
void update() override; // Actualiza la animación void update(float deltaTime) override; // Actualiza la animación (time-based)
// --- Control de animaciones --- // --- Control de animaciones ---
void setCurrentAnimation(const std::string& name = "default", bool reset = true); // Establece la animación por nombre 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 setCurrentAnimation(int index = 0, bool reset = true); // Establece la animación por índice
void resetAnimation(); // Reinicia la animación actual void resetAnimation(); // Reinicia la animación actual
void setAnimationSpeed(size_t value); // Establece la velocidad de la animación void setAnimationSpeed(float 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 auto getAnimationSpeed() const -> float { 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 animtionPause() { animations_[current_animation_].paused = true; } // Detiene la animación
void animationResume() { animations_[current_animation_].paused = false; } // Reanuda 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 auto getCurrentAnimationFrame() const -> size_t { return animations_[current_animation_].current_frame; } // Obtiene el numero de frame de la animación actual
@@ -77,7 +78,7 @@ class AnimatedSprite : public MovingSprite {
int current_animation_ = 0; // Índice de la animación activa int current_animation_ = 0; // Índice de la animación activa
// --- Métodos internos --- // --- Métodos internos ---
void animate(); // Calcula el frame correspondiente a la animación void animate(float deltaTime); // Calcula el frame correspondiente a la animación (time-based)
void loadFromAnimationsFileBuffer(const AnimationsFileBuffer& source); // Carga la animación desde un vector de cadenas void loadFromAnimationsFileBuffer(const AnimationsFileBuffer& source); // Carga la animación desde un vector de cadenas
void processConfigLine(const std::string& line, AnimationConfig& config); // Procesa una línea de configuración void processConfigLine(const std::string& line, AnimationConfig& config); // Procesa una línea de configuración
void updateFrameCalculations(AnimationConfig& config); // Actualiza los cálculos basados en las dimensiones del frame void updateFrameCalculations(AnimationConfig& config); // Actualiza los cálculos basados en las dimensiones del frame

View File

@@ -4,10 +4,12 @@
#include <cstddef> // Para size_t #include <cstddef> // Para size_t
#include <exception> // Para exception #include <exception> // Para exception
#include <filesystem> // Para std::filesystem
#include <fstream> // Para basic_istream, basic_ifstream, ifstream, istringstream #include <fstream> // Para basic_istream, basic_ifstream, ifstream, istringstream
#include <sstream> // Para basic_istringstream #include <sstream> // Para basic_istringstream
#include <stdexcept> // Para runtime_error #include <stdexcept> // Para runtime_error
#include "resource_helper.h" // Para ResourceHelper
#include "utils.h" // Para getFileName #include "utils.h" // Para getFileName
// Singleton // Singleton
@@ -139,6 +141,17 @@ auto Asset::get(const std::string &filename) const -> std::string {
return ""; return "";
} }
// Carga datos del archivo usando ResourceHelper
auto Asset::loadData(const std::string &filename) const -> std::vector<uint8_t> {
auto it = file_list_.find(filename);
if (it != file_list_.end()) {
return ResourceHelper::loadFile(it->second.file);
}
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found for data loading", filename.c_str());
return {};
}
// Verifica si un recurso existe // Verifica si un recurso existe
auto Asset::exists(const std::string &filename) const -> bool { auto Asset::exists(const std::string &filename) const -> bool {
return file_list_.find(filename) != file_list_.end(); return file_list_.find(filename) != file_list_.end();
@@ -193,19 +206,29 @@ auto Asset::check() const -> bool {
} }
// Comprueba que existe un fichero // Comprueba que existe un fichero
auto Asset::checkFile(const std::string &path) -> bool { auto Asset::checkFile(const std::string &path) const -> bool {
// Construir ruta del pack usando executable_path_
std::string pack_path = executable_path_ + "resources.pack";
bool pack_exists = std::filesystem::exists(pack_path);
if (pack_exists) {
// MODO PACK: Usar ResourceHelper (igual que la carga real)
auto data = ResourceHelper::loadFile(path);
return !data.empty();
} else {
// MODO FILESYSTEM: Verificación directa (modo desarrollo)
std::ifstream file(path); std::ifstream file(path);
bool success = file.good(); bool success = file.good();
file.close(); file.close();
if (!success) { if (!success) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Checking file: %s [ ERROR ]", "Error: Could not open file: %s", path.c_str());
getFileName(path).c_str());
} }
return success; return success;
} }
}
// Parsea string a Type // Parsea string a Type
auto Asset::parseAssetType(const std::string &type_str) -> Type { auto Asset::parseAssetType(const std::string &type_str) -> Type {

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <cstdint> // Para uint8_t
#include <string> // Para string #include <string> // Para string
#include <unordered_map> // Para unordered_map #include <unordered_map> // Para unordered_map
#include <utility> // Para move #include <utility> // Para move
@@ -33,6 +34,7 @@ class Asset {
void add(const std::string &file_path, Type type, bool required = true, bool absolute = false); void add(const std::string &file_path, Type type, bool required = true, bool absolute = false);
void loadFromFile(const std::string &config_file_path, const std::string &prefix = "", const std::string &system_folder = ""); // Con soporte para variables void loadFromFile(const std::string &config_file_path, const std::string &prefix = "", const std::string &system_folder = ""); // Con soporte para variables
[[nodiscard]] auto get(const std::string &filename) const -> std::string; // Mantener nombre original [[nodiscard]] auto get(const std::string &filename) const -> std::string; // Mantener nombre original
[[nodiscard]] auto loadData(const std::string &filename) const -> std::vector<uint8_t>; // Carga datos del archivo
[[nodiscard]] auto check() const -> bool; [[nodiscard]] auto check() const -> bool;
[[nodiscard]] auto getListByType(Type type) const -> std::vector<std::string>; [[nodiscard]] auto getListByType(Type type) const -> std::vector<std::string>;
[[nodiscard]] auto exists(const std::string &filename) const -> bool; // Nueva función para verificar existencia [[nodiscard]] auto exists(const std::string &filename) const -> bool; // Nueva función para verificar existencia
@@ -45,7 +47,9 @@ class Asset {
bool required; // Indica si el archivo es obligatorio bool required; // Indica si el archivo es obligatorio
Item(std::string path, Type asset_type, bool is_required) Item(std::string path, Type asset_type, bool is_required)
: file(std::move(path)), type(asset_type), required(is_required) {} : file(std::move(path)),
type(asset_type),
required(is_required) {}
}; };
// --- Variables internas --- // --- Variables internas ---
@@ -53,7 +57,7 @@ class Asset {
std::string executable_path_; // Ruta del ejecutable std::string executable_path_; // Ruta del ejecutable
// --- Métodos internos --- // --- Métodos internos ---
[[nodiscard]] static auto checkFile(const std::string &path) -> bool; // Verifica si un archivo existe [[nodiscard]] auto checkFile(const std::string &path) const -> bool; // Verifica si un archivo existe
[[nodiscard]] static auto getTypeName(Type type) -> std::string; // Obtiene el nombre del tipo [[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 [[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 void addToMap(const std::string &file_path, Type type, bool required, bool absolute); // Añade archivo al mapa

106
source/asset_integrated.cpp Normal file
View File

@@ -0,0 +1,106 @@
#include "asset_integrated.h"
#include <filesystem>
#include <fstream>
#include <iostream>
bool AssetIntegrated::resource_pack_enabled_ = false;
void AssetIntegrated::initWithResourcePack(const std::string &executable_path,
const std::string &resource_pack_path) {
// Inicializar Asset normal
Asset::init(executable_path);
// Inicializar ResourceLoader
auto &loader = ResourceLoader::getInstance();
if (loader.initialize(resource_pack_path, true)) {
resource_pack_enabled_ = true;
std::cout << "Asset system initialized with resource pack: " << resource_pack_path << std::endl;
} else {
resource_pack_enabled_ = false;
std::cout << "Asset system initialized in fallback mode (filesystem)" << std::endl;
}
}
std::vector<uint8_t> AssetIntegrated::loadFile(const std::string &filename) {
if (shouldUseResourcePack(filename) && resource_pack_enabled_) {
// Intentar cargar del pack de recursos
auto &loader = ResourceLoader::getInstance();
// Convertir ruta completa a ruta relativa para el pack
std::string relativePath = filename;
// Si la ruta contiene "data/", extraer la parte relativa
size_t dataPos = filename.find("data/");
if (dataPos != std::string::npos) {
relativePath = filename.substr(dataPos + 5); // +5 para saltar "data/"
}
auto data = loader.loadResource(relativePath);
if (!data.empty()) {
return data;
}
}
// Fallback: cargar del filesystem
std::ifstream file(filename, std::ios::binary | std::ios::ate);
if (!file) {
std::cerr << "Error: Could not open file: " << filename << std::endl;
return {};
}
std::streamsize fileSize = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<uint8_t> data(fileSize);
if (!file.read(reinterpret_cast<char *>(data.data()), fileSize)) {
std::cerr << "Error: Could not read file: " << filename << std::endl;
return {};
}
return data;
}
bool AssetIntegrated::fileExists(const std::string &filename) const {
if (shouldUseResourcePack(filename) && resource_pack_enabled_) {
auto &loader = ResourceLoader::getInstance();
// Convertir ruta completa a ruta relativa para el pack
std::string relativePath = filename;
size_t dataPos = filename.find("data/");
if (dataPos != std::string::npos) {
relativePath = filename.substr(dataPos + 5);
}
if (loader.resourceExists(relativePath)) {
return true;
}
}
// Verificar en filesystem
return std::filesystem::exists(filename);
}
std::string AssetIntegrated::getSystemPath(const std::string &filename) const {
// Los archivos de sistema/config siempre van al filesystem
return filename;
}
bool AssetIntegrated::shouldUseResourcePack(const std::string &filepath) const {
// Los archivos que NO van al pack:
// - Archivos de config/ (ahora están fuera de data/)
// - Archivos con absolute=true en assets.txt
// - Archivos de sistema (${SYSTEM_FOLDER})
if (filepath.find("/config/") != std::string::npos ||
filepath.find("config/") == 0) {
return false;
}
if (filepath.find("/data/") != std::string::npos ||
filepath.find("data/") == 0) {
return true;
}
return false;
}

29
source/asset_integrated.h Normal file
View File

@@ -0,0 +1,29 @@
#pragma once
#include <memory>
#include "asset.h"
#include "resource_loader.h"
// Extensión de Asset que integra ResourceLoader
class AssetIntegrated : public Asset {
public:
// Inicializa Asset con ResourceLoader
static void initWithResourcePack(const std::string &executable_path,
const std::string &resource_pack_path = "resources.pack");
// Carga un archivo usando ResourceLoader como primera opción
std::vector<uint8_t> loadFile(const std::string &filename);
// Verifica si un archivo existe (pack o filesystem)
bool fileExists(const std::string &filename) const;
// Obtiene la ruta completa para archivos del sistema/config
std::string getSystemPath(const std::string &filename) const;
private:
static bool resource_pack_enabled_;
// Determina si un archivo debe cargarse del pack o del filesystem
bool shouldUseResourcePack(const std::string &filepath) const;
};

View File

@@ -100,13 +100,33 @@ void Audio::stopAllSounds() const {
// Realiza un fundido de salida de la música // Realiza un fundido de salida de la música
void Audio::fadeOutMusic(int milliseconds) const { void Audio::fadeOutMusic(int milliseconds) const {
if (music_enabled_) { if (music_enabled_ && getRealMusicState() == MusicState::PLAYING) {
#ifndef NO_AUDIO #ifndef NO_AUDIO
JA_FadeOutMusic(milliseconds); JA_FadeOutMusic(milliseconds);
#endif #endif
} }
} }
// Consulta directamente el estado real de la música en jailaudio
auto Audio::getRealMusicState() const -> MusicState {
#ifndef NO_AUDIO
JA_Music_state ja_state = JA_GetMusicState();
switch (ja_state) {
case JA_MUSIC_PLAYING:
return MusicState::PLAYING;
case JA_MUSIC_PAUSED:
return MusicState::PAUSED;
case JA_MUSIC_STOPPED:
case JA_MUSIC_INVALID:
case JA_MUSIC_DISABLED:
default:
return MusicState::STOPPED;
}
#else
return MusicState::STOPPED;
#endif
}
// Establece el volumen de los sonidos // Establece el volumen de los sonidos
void Audio::setSoundVolume(int sound_volume, Group group) const { void Audio::setSoundVolume(int sound_volume, Group group) const {
if (sound_enabled_) { if (sound_enabled_) {

View File

@@ -13,6 +13,12 @@ class Audio {
INTERFACE = 1 // Sonidos de la interfaz INTERFACE = 1 // Sonidos de la interfaz
}; };
enum class MusicState {
PLAYING, // Reproduciendo música
PAUSED, // Música pausada
STOPPED, // Música detenida
};
// --- Constantes --- // --- Constantes ---
static constexpr int MAX_VOLUME = 100; // Volumen máximo static constexpr int MAX_VOLUME = 100; // Volumen máximo
static constexpr int MIN_VOLUME = 0; // Volumen mínimo static constexpr int MIN_VOLUME = 0; // Volumen mínimo
@@ -60,14 +66,15 @@ class Audio {
void setSoundVolume(int volume, Group group = Group::ALL) const; // Ajustar volumen de efectos void setSoundVolume(int volume, Group group = Group::ALL) const; // Ajustar volumen de efectos
void setMusicVolume(int volume) const; // Ajustar volumen de música void setMusicVolume(int volume) const; // Ajustar volumen de música
private: // --- Getters para debug ---
// --- Enums privados --- bool isEnabled() const { return enabled_; }
enum class MusicState { bool isSoundEnabled() const { return sound_enabled_; }
PLAYING, // Reproduciendo música bool isMusicEnabled() const { return music_enabled_; }
PAUSED, // Música pausada MusicState getMusicState() const { return music_.state; }
STOPPED, // Música detenida MusicState getRealMusicState() const; // Consulta directamente a jailaudio
}; const std::string& getCurrentMusicName() const { return music_.name; }
private:
// --- Estructuras privadas --- // --- Estructuras privadas ---
struct Music { struct Music {
MusicState state; // Estado actual de la música (reproduciendo, detenido, en pausa) MusicState state; // Estado actual de la música (reproduciendo, detenido, en pausa)
@@ -75,11 +82,15 @@ class Audio {
bool loop; // Indica si la última pista de música se debe reproducir en bucle bool loop; // Indica si la última pista de música se debe reproducir en bucle
// Constructor para inicializar la música con valores predeterminados // Constructor para inicializar la música con valores predeterminados
Music() : state(MusicState::STOPPED), loop(false) {} Music()
: state(MusicState::STOPPED),
loop(false) {}
// Constructor para inicializar con valores específicos // Constructor para inicializar con valores específicos
Music(MusicState init_state, std::string init_name, bool init_loop) Music(MusicState init_state, std::string init_name, bool init_loop)
: state(init_state), name(std::move(init_name)), loop(init_loop) {} : state(init_state),
name(std::move(init_name)),
loop(init_loop) {}
}; };
// --- Variables de estado --- // --- Variables de estado ---

View File

@@ -13,6 +13,7 @@
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "utils.h" // Para funciones de easing
// Constructor // Constructor
Background::Background(float total_progress_to_complete) Background::Background(float total_progress_to_complete)
@@ -29,6 +30,7 @@ Background::Background(float total_progress_to_complete)
total_progress_to_complete_(total_progress_to_complete), total_progress_to_complete_(total_progress_to_complete),
progress_per_stage_(total_progress_to_complete_ / STAGES), progress_per_stage_(total_progress_to_complete_ / STAGES),
sun_completion_progress_(total_progress_to_complete_ * SUN_COMPLETION_FACTOR), sun_completion_progress_(total_progress_to_complete_ * SUN_COMPLETION_FACTOR),
minimum_completed_progress_(total_progress_to_complete_ * MINIMUM_COMPLETED_PROGRESS_PERCENTAGE),
rect_(SDL_FRect{0, 0, static_cast<float>(gradients_texture_->getWidth() / 2), static_cast<float>(gradients_texture_->getHeight() / 2)}), rect_(SDL_FRect{0, 0, static_cast<float>(gradients_texture_->getWidth() / 2), static_cast<float>(gradients_texture_->getHeight() / 2)}),
src_rect_({.x = 0, .y = 0, .w = 320, .h = 240}), src_rect_({.x = 0, .y = 0, .w = 320, .h = 240}),
@@ -93,20 +95,21 @@ void Background::initializeSprites() {
// Configura las propiedades iniciales de los sprites // Configura las propiedades iniciales de los sprites
void Background::initializeSpriteProperties() { void Background::initializeSpriteProperties() {
constexpr float TOP_CLOUDS_SPEED = 0.1F; // Velocidades iniciales que coinciden con updateCloudsSpeed() cuando progress=0
constexpr float BOTTOM_CLOUDS_SPEED = 0.05F; constexpr float INITIAL_TOP_CLOUDS_SPEED_PX_PER_S = 0.05F * 60.0F; // 3.0 píxeles/segundo (coincide con CLOUDS_INITIAL_SPEED)
constexpr float INITIAL_BOTTOM_CLOUDS_SPEED_PX_PER_S = 0.05F * 60.0F / 2.0F; // 1.5 píxeles/segundo (mitad de velocidad)
top_clouds_sprite_a_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight()); 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_a_->setVelX(-INITIAL_TOP_CLOUDS_SPEED_PX_PER_S);
top_clouds_sprite_b_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight()); top_clouds_sprite_b_->setSpriteClip(0, 0, top_clouds_texture_->getWidth(), top_clouds_texture_->getHeight());
top_clouds_sprite_b_->setVelX(-TOP_CLOUDS_SPEED); top_clouds_sprite_b_->setVelX(-INITIAL_TOP_CLOUDS_SPEED_PX_PER_S);
bottom_clouds_sprite_a_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight()); 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_a_->setVelX(-INITIAL_BOTTOM_CLOUDS_SPEED_PX_PER_S);
bottom_clouds_sprite_b_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight()); bottom_clouds_sprite_b_->setSpriteClip(0, 0, bottom_clouds_texture_->getWidth(), bottom_clouds_texture_->getHeight());
bottom_clouds_sprite_b_->setVelX(-BOTTOM_CLOUDS_SPEED); bottom_clouds_sprite_b_->setVelX(-INITIAL_BOTTOM_CLOUDS_SPEED_PX_PER_S);
buildings_sprite_->setY(base_ - buildings_sprite_->getHeight()); buildings_sprite_->setY(base_ - buildings_sprite_->getHeight());
grass_sprite_->setY(base_ - grass_sprite_->getHeight()); grass_sprite_->setY(base_ - grass_sprite_->getHeight());
@@ -126,20 +129,24 @@ void Background::initializeTextures() {
} }
// Actualiza la lógica del objeto // Actualiza la lógica del objeto
void Background::update() { void Background::update(float delta_time) {
// Actualiza la progresión y calcula transiciones // Actualiza la progresión y calcula transiciones
if (!manual_mode_) { if (!manual_mode_) {
updateProgression(); updateProgression(delta_time);
} }
// Actualiza el valor de alpha // Actualiza el valor de alpha
updateAlphaColorTexture(); updateAlphaColorTexture();
// Actualiza las nubes // Actualiza las nubes
updateClouds(); updateClouds(delta_time);
// Calcula el frame de la hierba // Actualiza timer de hierba
grass_sprite_->setSpriteClip(0, (10 * (counter_ / 20 % 2)), 320, 10); grass_timer_ += delta_time;
// Calcula el frame de la hierba (alterna cada GRASS_FRAME_DURATION ms)
int grass_frame = static_cast<int>(grass_timer_ / GRASS_FRAME_DURATION) % 2;
grass_sprite_->setSpriteClip(0, (10 * grass_frame), 320, 10);
// Calcula el valor de alpha // Calcula el valor de alpha
alpha_ = std::max((255 - (int)(255 * transition_)), 0); alpha_ = std::max((255 - (int)(255 * transition_)), 0);
@@ -148,9 +155,6 @@ void Background::update() {
sun_sprite_->setPosition(sun_path_.at(sun_index_)); sun_sprite_->setPosition(sun_path_.at(sun_index_));
moon_sprite_->setPosition(moon_path_.at(moon_index_)); moon_sprite_->setPosition(moon_path_.at(moon_index_));
// Incrementa el contador
++counter_;
// Compone todos los elementos del fondo en la textura // Compone todos los elementos del fondo en la textura
fillCanvas(); fillCanvas();
} }
@@ -182,6 +186,12 @@ void Background::setProgress(float absolute_progress) {
// Cambia el estado del fondo // Cambia el estado del fondo
void Background::setState(State new_state) { void Background::setState(State new_state) {
// Si entra en estado completado, inicializar variables de transición
if (new_state == State::COMPLETED && state_ != State::COMPLETED) {
completion_initial_progress_ = progress_;
completion_transition_timer_ = 0.0f;
}
state_ = new_state; state_ = new_state;
} }
@@ -196,6 +206,10 @@ void Background::reset() {
sun_index_ = 0; sun_index_ = 0;
moon_index_ = 0; moon_index_ = 0;
// Resetear variables de transición de completado
completion_transition_timer_ = 0.0f;
completion_initial_progress_ = 0.0f;
// Notifica el cambio si hay callback // Notifica el cambio si hay callback
if (progress_callback_ && progress_ != old_progress) { if (progress_callback_ && progress_ != old_progress) {
progress_callback_(progress_); progress_callback_(progress_);
@@ -252,13 +266,24 @@ void Background::setMoonProgression(float progress) {
} }
// Actualiza la progresión y calcula las transiciones // Actualiza la progresión y calcula las transiciones
void Background::updateProgression() { void Background::updateProgression(float delta_time) {
// Si el juego está completado, reduce la progresión gradualmente // Si el juego está completado, hacer transición suave con easing
if (state_ == State::COMPLETED) { if (state_ == State::COMPLETED) {
if (progress_ > MINIMUM_COMPLETED_PROGRESS) { completion_transition_timer_ += delta_time;
progress_ -= COMPLETED_REDUCTION_RATE;
// Calcular progreso normalizado de la transición (0.0 a 1.0)
float t = std::min(completion_transition_timer_ / COMPLETION_TRANSITION_DURATION_S, 1.0f);
if (t < 1.0f) {
// Usar easeOutCubic para transición suave (rápido al inicio, lento al final)
float eased_t = easeOutCubic(static_cast<double>(t));
// Interpolación desde progreso inicial hasta mínimo
float progress_range = completion_initial_progress_ - minimum_completed_progress_;
progress_ = completion_initial_progress_ - (progress_range * eased_t);
} else { } else {
progress_ = MINIMUM_COMPLETED_PROGRESS; // Transición completada, fijar al valor mínimo
progress_ = minimum_completed_progress_;
} }
} }
@@ -283,18 +308,19 @@ void Background::updateProgression() {
// Actualiza la velocidad de las nubes según el estado y progresión // Actualiza la velocidad de las nubes según el estado y progresión
void Background::updateCloudsSpeed() { void Background::updateCloudsSpeed() {
// Cálculo de velocidad según progreso // Cálculo de velocidad según progreso (convertido de frame-based a time-based)
constexpr float CLOUDS_INITIAL_SPEED = 0.05F; constexpr float CLOUDS_INITIAL_SPEED_PX_PER_S = 0.05F * 60.0F; // 3.0 píxeles/segundo (era 0.05 px/frame @ 60fps)
constexpr float CLOUDS_FINAL_SPEED = 2.00F - CLOUDS_INITIAL_SPEED; constexpr float CLOUDS_TOTAL_SPEED_PX_PER_S = 2.00F * 60.0F; // 120.0 píxeles/segundo (era 2.00 px/frame @ 60fps)
constexpr float CLOUDS_FINAL_SPEED_RANGE_PX_PER_S = CLOUDS_TOTAL_SPEED_PX_PER_S - CLOUDS_INITIAL_SPEED_PX_PER_S; // 117.0 píxeles/segundo
// Velocidad base según progreso (de -0.05 a -2.00) // Velocidad base según progreso (de -3.0 a -120.0 píxeles/segundo, igual que la versión original)
float base_clouds_speed = (-CLOUDS_INITIAL_SPEED) + float base_clouds_speed = (-CLOUDS_INITIAL_SPEED_PX_PER_S) +
(-CLOUDS_FINAL_SPEED * (progress_ / total_progress_to_complete_)); (-CLOUDS_FINAL_SPEED_RANGE_PX_PER_S * (progress_ / total_progress_to_complete_));
// En estado completado, las nubes se ralentizan gradualmente // En estado completado, las nubes se ralentizan gradualmente
if (state_ == State::COMPLETED) { if (state_ == State::COMPLETED) {
float completion_factor = (progress_ - MINIMUM_COMPLETED_PROGRESS) / float completion_factor = (progress_ - minimum_completed_progress_) /
(total_progress_to_complete_ - MINIMUM_COMPLETED_PROGRESS); (total_progress_to_complete_ - minimum_completed_progress_);
completion_factor = std::max(0.1F, completion_factor); completion_factor = std::max(0.1F, completion_factor);
base_clouds_speed *= completion_factor; base_clouds_speed *= completion_factor;
} }
@@ -314,12 +340,12 @@ void Background::updateCloudsSpeed() {
} }
// Actualiza las nubes // Actualiza las nubes
void Background::updateClouds() { void Background::updateClouds(float deltaTime) {
// Mueve las nubes // Mueve las nubes
top_clouds_sprite_a_->update(); top_clouds_sprite_a_->update(deltaTime);
top_clouds_sprite_b_->update(); top_clouds_sprite_b_->update(deltaTime);
bottom_clouds_sprite_a_->update(); bottom_clouds_sprite_a_->update(deltaTime);
bottom_clouds_sprite_b_->update(); bottom_clouds_sprite_b_->update(deltaTime);
// Calcula el offset de las nubes // Calcula el offset de las nubes
if (top_clouds_sprite_a_->getPosX() < -top_clouds_sprite_a_->getWidth()) { if (top_clouds_sprite_a_->getPosX() < -top_clouds_sprite_a_->getWidth()) {

View File

@@ -31,7 +31,7 @@ class Background {
~Background(); // Destructor ~Background(); // Destructor
// --- Métodos principales --- // --- Métodos principales ---
void update(); // Actualiza la lógica del objeto void update(float delta_time); // Actualiza la lógica del objeto
void render(); // Dibuja el objeto void render(); // Dibuja el objeto
void reset(); // Reinicia la progresión void reset(); // Reinicia la progresión
@@ -61,9 +61,9 @@ class Background {
private: private:
// --- Constantes --- // --- Constantes ---
static constexpr size_t STAGES = 4; // Número de etapas 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_PERCENTAGE = 0.05F; // Porcentaje mínimo completado (10%)
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 static constexpr float SUN_COMPLETION_FACTOR = 0.5F; // Factor de completado del sol
static constexpr float COMPLETION_TRANSITION_DURATION_S = 3.0F; // Duración de la transición de completado en segundos
// --- Objetos y punteros --- // --- Objetos y punteros ---
SDL_Renderer *renderer_; // Renderizador de la ventana SDL_Renderer *renderer_; // Renderizador de la ventana
@@ -90,6 +90,7 @@ class Background {
const float total_progress_to_complete_; // Progreso total para completar const float total_progress_to_complete_; // Progreso total para completar
const float progress_per_stage_; // Progreso por etapa const float progress_per_stage_; // Progreso por etapa
const float sun_completion_progress_; // Progreso de completado del sol const float sun_completion_progress_; // Progreso de completado del sol
const float minimum_completed_progress_; // Progreso mínimo calculado dinámicamente
ProgressCallback progress_callback_; // Callback para notificar cambios de progreso ProgressCallback progress_callback_; // Callback para notificar cambios de progreso
// --- Variables de estado --- // --- Variables de estado ---
@@ -107,7 +108,8 @@ class Background {
float clouds_speed_ = 0; // Velocidad de las nubes float clouds_speed_ = 0; // Velocidad de las nubes
float transition_ = 0; // Porcentaje de transición float transition_ = 0; // Porcentaje de transición
size_t gradient_number_ = 0; // Índice de fondo degradado size_t gradient_number_ = 0; // Índice de fondo degradado
size_t counter_ = 0; // Contador interno float grass_timer_ = 0.0f; // Timer para animación de hierba (ms)
static constexpr float GRASS_FRAME_DURATION = 333.34f; // Duración por frame de hierba (20 frames * 16.67ms)
size_t alpha_color_texture_ = 0; // Transparencia de atenuación size_t alpha_color_texture_ = 0; // Transparencia de atenuación
size_t previous_alpha_color_texture_ = 0; // Transparencia anterior size_t previous_alpha_color_texture_ = 0; // Transparencia anterior
size_t sun_index_ = 0; // Índice del recorrido del sol size_t sun_index_ = 0; // Índice del recorrido del sol
@@ -116,20 +118,24 @@ class Background {
Uint8 alpha_ = 0; // Transparencia entre fases Uint8 alpha_ = 0; // Transparencia entre fases
bool manual_mode_ = false; // Si está en modo manual bool manual_mode_ = false; // Si está en modo manual
// --- Variables para transición suave de completado ---
float completion_transition_timer_ = 0.0f; // Timer para la transición de completado
float completion_initial_progress_ = 0.0f; // Progreso inicial al entrar en estado completado
// --- Métodos internos --- // --- Métodos internos ---
void initializePaths(); // Inicializa las rutas del sol y la luna void initializePaths(); // Inicializa las rutas del sol y la luna
void initializeRects(); // Inicializa los rectángulos de gradientes y nubes void initializeRects(); // Inicializa los rectángulos de gradientes y nubes
void initializeSprites(); // Crea los sprites void initializeSprites(); // Crea los sprites
void initializeSpriteProperties(); // Configura las propiedades iniciales de los sprites void initializeSpriteProperties(); // Configura las propiedades iniciales de los sprites
void initializeTextures(); // Inicializa las texturas de renderizado void initializeTextures(); // Inicializa las texturas de renderizado
void updateProgression(); // Actualiza la progresión y calcula transiciones void updateProgression(float delta_time); // Actualiza la progresión y calcula transiciones
void updateCloudsSpeed(); // Actualiza la velocidad de las nubes según el estado void updateCloudsSpeed(); // Actualiza la velocidad de las nubes según el estado
void renderGradient(); // Dibuja el gradiente de fondo void renderGradient(); // Dibuja el gradiente de fondo
void renderTopClouds(); // Dibuja las nubes superiores void renderTopClouds(); // Dibuja las nubes superiores
void renderBottomClouds(); // Dibuja las nubes inferiores void renderBottomClouds(); // Dibuja las nubes inferiores
void fillCanvas(); // Compone todos los elementos en la textura void fillCanvas(); // Compone todos los elementos en la textura
void updateAlphaColorTexture(); // Actualiza el alpha de la textura de atenuación void updateAlphaColorTexture(); // Actualiza el alpha de la textura de atenuación
void updateClouds(); // Actualiza el movimiento de las nubes void updateClouds(float deltaTime); // Actualiza el movimiento de las nubes (time-based)
void createSunPath(); // Precalcula el recorrido del sol void createSunPath(); // Precalcula el recorrido del sol
void createMoonPath(); // Precalcula el recorrido de la luna void createMoonPath(); // Precalcula el recorrido de la luna
}; };

View File

@@ -11,24 +11,25 @@
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
// Constructor // Constructor
Balloon::Balloon(float x, float y, Type type, Size size, float vel_x, float speed, Uint16 creation_timer, SDL_FRect play_area, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation) Balloon::Balloon(const Config& config)
: sprite_(std::make_unique<AnimatedSprite>(texture, animation)), : sprite_(std::make_unique<AnimatedSprite>(config.texture, config.animation)),
x_(x), x_(config.x),
y_(y), y_(config.y),
vx_(vel_x), vx_(config.vel_x),
being_created_(creation_timer > 0), being_created_(config.creation_counter > 0),
invulnerable_(creation_timer > 0), invulnerable_(config.creation_counter > 0),
stopped_(creation_timer > 0), stopped_(config.creation_counter > 0),
creation_counter_(creation_timer), creation_counter_(config.creation_counter),
creation_counter_ini_(creation_timer), creation_counter_ini_(config.creation_counter),
type_(type), type_(config.type),
size_(size), size_(config.size),
speed_(speed), game_tempo_(config.game_tempo),
play_area_(play_area) { play_area_(config.play_area),
sound_(config.sound) {
switch (type_) { switch (type_) {
case Type::BALLOON: { case Type::BALLOON: {
vy_ = 0; vy_ = 0;
max_vy_ = 3.0F; max_vy_ = 3.0F * 60.0F; // Convert from frames to seconds (180 pixels/s)
const int INDEX = static_cast<int>(size_); const int INDEX = static_cast<int>(size_);
gravity_ = param.balloon.settings.at(INDEX).grav; gravity_ = param.balloon.settings.at(INDEX).grav;
@@ -37,9 +38,8 @@ Balloon::Balloon(float x, float y, Type type, Size size, float vel_x, float spee
power_ = POWER.at(INDEX); power_ = POWER.at(INDEX);
menace_ = MENACE.at(INDEX); menace_ = MENACE.at(INDEX);
score_ = SCORE.at(INDEX); score_ = SCORE.at(INDEX);
bouncing_sound_ = BOUNCING_SOUND.at(INDEX); sound_.bouncing_file = BOUNCING_SOUND.at(INDEX);
popping_sound_ = POPPING_SOUND.at(INDEX); sound_.popping_file = POPPING_SOUND.at(INDEX);
break; break;
} }
@@ -52,27 +52,25 @@ Balloon::Balloon(float x, float y, Type type, Size size, float vel_x, float spee
power_ = POWER.at(INDEX); power_ = POWER.at(INDEX);
menace_ = MENACE.at(INDEX); menace_ = MENACE.at(INDEX);
score_ = SCORE.at(INDEX); score_ = SCORE.at(INDEX);
bouncing_sound_ = BOUNCING_SOUND.at(INDEX); sound_.bouncing_file = BOUNCING_SOUND.at(INDEX);
popping_sound_ = POPPING_SOUND.at(INDEX); sound_.popping_file = POPPING_SOUND.at(INDEX);
break; break;
} }
case Type::POWERBALL: { case Type::POWERBALL: {
constexpr int INDEX = 3; constexpr int INDEX = 3;
h_ = w_ = WIDTH.at(4); h_ = w_ = WIDTH.at(4);
bouncing_sound_ = BOUNCING_SOUND.at(3); sound_.bouncing_file = BOUNCING_SOUND.at(3);
popping_sound_ = "power_ball_explosion.wav"; sound_.popping_file = "power_ball_explosion.wav";
power_ = score_ = menace_ = 0; power_ = score_ = menace_ = 0;
vy_ = 0; vy_ = 0;
max_vy_ = 3.0F; max_vy_ = 3.0F * 60.0F; // Convert from frames to seconds (180 pixels/s)
gravity_ = param.balloon.settings.at(INDEX).grav; gravity_ = param.balloon.settings.at(INDEX).grav;
default_vy_ = param.balloon.settings.at(INDEX).vel; default_vy_ = param.balloon.settings.at(INDEX).vel;
sprite_->setRotate(creation_timer <= 0); sprite_->setRotate(config.creation_counter <= 0);
sprite_->setRotateAmount(vx_ > 0.0F ? 2.0 : -2.0); sprite_->setRotateAmount(vx_ > 0.0F ? 120.0 : -120.0); // Convert from 2 degrees/frame to 120 degrees/second
break; break;
} }
@@ -91,6 +89,12 @@ Balloon::Balloon(float x, float y, Type type, Size size, float vel_x, float spee
// Establece la animación a usar // Establece la animación a usar
setAnimation(); setAnimation();
// Si no se está creando (creation_counter = 0), asegurar estado activo
if (!being_created_) {
start();
setInvulnerable(false);
}
} }
// Centra el globo en la posición X // Centra el globo en la posición X
@@ -137,19 +141,20 @@ void Balloon::render() {
} }
} }
// Actualiza la posición y estados del globo // Actualiza la posición y estados del globo (time-based)
void Balloon::move() { void Balloon::move(float deltaTime) {
if (isStopped()) { if (isStopped()) {
return; return;
} }
handleHorizontalMovement(); handleHorizontalMovement(deltaTime);
handleVerticalMovement(); handleVerticalMovement(deltaTime);
applyGravity(); applyGravity(deltaTime);
} }
void Balloon::handleHorizontalMovement() { void Balloon::handleHorizontalMovement(float deltaTime) {
x_ += vx_ * speed_; // DeltaTime en segundos: velocidad (pixels/s) * tempo * tiempo (s)
x_ += vx_ * game_tempo_ * deltaTime;
const int CLIP = 2; const int CLIP = 2;
const float MIN_X = play_area_.x - CLIP; const float MIN_X = play_area_.x - CLIP;
@@ -160,8 +165,9 @@ void Balloon::handleHorizontalMovement() {
} }
} }
void Balloon::handleVerticalMovement() { void Balloon::handleVerticalMovement(float deltaTime) {
y_ += vy_ * speed_; // DeltaTime en segundos: velocidad (pixels/s) * tempo * tiempo (s)
y_ += vy_ * game_tempo_ * deltaTime;
if (shouldCheckTopCollision()) { if (shouldCheckTopCollision()) {
handleTopCollision(); handleTopCollision();
@@ -216,41 +222,37 @@ void Balloon::handleBottomCollision() {
} }
} }
void Balloon::applyGravity() { void Balloon::applyGravity(float deltaTime) {
/* // DeltaTime en segundos: aceleración (pixels/s²) * tempo * tiempo (s)
Para aplicar la gravedad, el diseño original la aplicaba en cada iteración del bucle vy_ += gravity_ * game_tempo_ * deltaTime;
Al añadir el modificador de velocidad se reduce la distancia que recorre el objeto y por
tanto recibe mas gravedad. Para solucionarlo se va a aplicar la gravedad cuando se haya
recorrido una distancia igual a la velocidad en Y, que era el cálculo inicial
*/
travel_y_ += speed_;
if (travel_y_ >= 1.0F) {
travel_y_ -= 1.0F;
vy_ += gravity_;
}
} }
void Balloon::playBouncingSound() { void Balloon::playBouncingSound() {
if (bouncing_sound_enabled_) { if (sound_.enabled && sound_.bouncing_enabled) {
playSound(bouncing_sound_); Audio::get()->playSound(sound_.bouncing_file);
} }
} }
// Actualiza al globo a su posicion, animación y controla los contadores void Balloon::playPoppingSound() {
void Balloon::update() { if (sound_.enabled && sound_.poping_enabled) {
move(); Audio::get()->playSound(sound_.popping_file);
updateState(); }
}
// Actualiza al globo a su posicion, animación y controla los contadores (time-based)
void Balloon::update(float deltaTime) {
move(deltaTime);
updateState(deltaTime);
updateBounceEffect(); updateBounceEffect();
shiftSprite(); shiftSprite();
shiftColliders(); shiftColliders();
sprite_->update(); sprite_->update(deltaTime);
++counter_; // Contador interno con deltaTime en segundos
counter_ += deltaTime;
} }
// Actualiza los estados del globo // Actualiza los estados del globo (time-based)
void Balloon::updateState() { void Balloon::updateState(float deltaTime) {
// Si se está creando // Si se está creando
if (isBeingCreated()) { if (isBeingCreated()) {
// Actualiza el valor de las variables // Actualiza el valor de las variables
@@ -259,9 +261,14 @@ void Balloon::updateState() {
if (creation_counter_ > 0) { if (creation_counter_ > 0) {
// Desplaza lentamente el globo hacia abajo y hacia un lado // Desplaza lentamente el globo hacia abajo y hacia un lado
if (creation_counter_ % 10 == 0) { // Cada 10/60 segundos (equivalente a 10 frames a 60fps)
movement_accumulator_ += deltaTime;
constexpr float MOVEMENT_INTERVAL_S = 10.0f / 60.0f; // 10 frames = ~0.167s
if (movement_accumulator_ >= MOVEMENT_INTERVAL_S) {
movement_accumulator_ -= MOVEMENT_INTERVAL_S;
y_++; y_++;
x_ += vx_; x_ += vx_ / 60.0f; // Convierte de pixels/segundo a pixels/frame para movimiento discreto
// Comprueba no se salga por los laterales // Comprueba no se salga por los laterales
const int MIN_X = play_area_.x; const int MIN_X = play_area_.x;
@@ -269,11 +276,12 @@ void Balloon::updateState() {
if (x_ < MIN_X || x_ > MAX_X) { if (x_ < MIN_X || x_ > MAX_X) {
// Corrige y cambia el sentido de la velocidad // Corrige y cambia el sentido de la velocidad
x_ -= vx_; x_ -= vx_ / 60.0f;
vx_ = -vx_; vx_ = -vx_;
} }
} }
--creation_counter_; creation_counter_ -= deltaTime;
if (creation_counter_ < 0) creation_counter_ = 0;
} }
else { else {
@@ -307,11 +315,14 @@ void Balloon::setAnimation() {
} }
// Establece el frame de animación // Establece el frame de animación
std::string chosen_animation;
if (use_reversed_colors_) { if (use_reversed_colors_) {
sprite_->setCurrentAnimation(creating_animation); chosen_animation = creating_animation;
} else { } else {
sprite_->setCurrentAnimation(isBeingCreated() ? creating_animation : normal_animation); chosen_animation = isBeingCreated() ? creating_animation : normal_animation;
} }
sprite_->setCurrentAnimation(chosen_animation);
} }
// Detiene el globo // Detiene el globo
@@ -368,23 +379,8 @@ void Balloon::useNormalColor() {
setAnimation(); setAnimation();
} }
// Reproduce sonido
void Balloon::playSound(const std::string &name) const {
if (!sound_enabled_) {
return;
}
static auto *audio_ = Audio::get();
audio_->playSound(name);
}
// Explota el globo // Explota el globo
void Balloon::pop(bool should_sound) { void Balloon::pop(bool should_sound) {
if (should_sound) { if (should_sound) { playPoppingSound(); }
if (poping_sound_enabled_) {
playSound(popping_sound_);
}
}
enabled_ = false; enabled_ = false;
} }

View File

@@ -25,15 +25,23 @@ class Balloon {
static constexpr std::array<int, 5> WIDTH = {10, 16, 26, 48, 49}; static constexpr std::array<int, 5> WIDTH = {10, 16, 26, 48, 49};
static constexpr std::array<std::string_view, 4> BOUNCING_SOUND = { static constexpr std::array<std::string_view, 4> BOUNCING_SOUND = {
"balloon_bounce0.wav", "balloon_bounce1.wav", "balloon_bounce2.wav", "balloon_bounce3.wav"}; "balloon_bounce0.wav",
"balloon_bounce1.wav",
"balloon_bounce2.wav",
"balloon_bounce3.wav"};
static constexpr std::array<std::string_view, 4> POPPING_SOUND = { static constexpr std::array<std::string_view, 4> POPPING_SOUND = {
"balloon_pop0.wav", "balloon_pop1.wav", "balloon_pop2.wav", "balloon_pop3.wav"}; "balloon_pop0.wav",
"balloon_pop1.wav",
"balloon_pop2.wav",
"balloon_pop3.wav"};
static constexpr float VELX_POSITIVE = 0.7F; // Velocidades horizontales en pixels/segundo (convertidas desde 0.7 pixels/frame a 60fps)
static constexpr float VELX_NEGATIVE = -0.7F; static constexpr float VELX_POSITIVE = 0.7F * 60.0F; // 42 pixels/segundo
static constexpr float VELX_NEGATIVE = -0.7F * 60.0F; // -42 pixels/segundo
static constexpr std::array<float, 5> SPEED = {0.60F, 0.70F, 0.80F, 0.90F, 1.00F}; // Multiplicadores de tempo del juego (sin cambios, son puros multiplicadores)
static constexpr std::array<float, 5> GAME_TEMPO = {0.60F, 0.70F, 0.80F, 0.90F, 1.00F};
static constexpr int POWERBALL_SCREENPOWER_MINIMUM = 10; static constexpr int POWERBALL_SCREENPOWER_MINIMUM = 10;
static constexpr int POWERBALL_COUNTER = 8; static constexpr int POWERBALL_COUNTER = 8;
@@ -52,25 +60,39 @@ class Balloon {
POWERBALL = 2, // Globo de poder POWERBALL = 2, // Globo de poder
}; };
// --- Estructura para manejo de sonido ---
struct Sound {
std::string bouncing_file; // Archivo de sonido al rebotar
std::string popping_file; // Archivo de sonido al explotar
bool bouncing_enabled = false; // Si debe sonar el globo al rebotar
bool poping_enabled = true; // Si debe sonar el globo al explotar
bool enabled = true; // Indica si los globos deben hacer algun sonido
};
// --- Estructura de configuración para inicialización ---
struct Config {
float x = 0.0F;
float y = 0.0F;
Type type = Type::BALLOON;
Size size = Size::EXTRALARGE;
float vel_x = VELX_POSITIVE;
float game_tempo = GAME_TEMPO.at(0);
float creation_counter = 0.0f;
SDL_FRect play_area = {.x = 0.0F, .y = 0.0F, .w = 0.0F, .h = 0.0F};
std::shared_ptr<Texture> texture = nullptr;
std::vector<std::string> animation;
Sound sound;
};
// --- Constructores y destructor --- // --- Constructores y destructor ---
Balloon( Balloon(const Config& config);
float x,
float y,
Type type,
Size size,
float vel_x,
float speed,
Uint16 creation_timer,
SDL_FRect play_area,
const std::shared_ptr<Texture>& texture,
const std::vector<std::string>& animation);
~Balloon() = default; ~Balloon() = default;
// --- Métodos principales --- // --- Métodos principales ---
void alignTo(int x); // Centra el globo en la posición X void alignTo(int x); // Centra el globo en la posición X
void render(); // Pinta el globo en la pantalla void render(); // Pinta el globo en la pantalla
void move(); // Actualiza la posición y estados del globo void move(float deltaTime); // Actualiza la posición y estados del globo (time-based)
void update(); // Actualiza el globo (posición, animación, contadores) void update(float deltaTime); // Actualiza el globo (posición, animación, contadores) (time-based)
void stop(); // Detiene el globo void stop(); // Detiene el globo
void start(); // Pone el globo en movimiento void start(); // Pone el globo en movimiento
void pop(bool should_sound = false); // Explota el globo void pop(bool should_sound = false); // Explota el globo
@@ -100,11 +122,11 @@ class Balloon {
// --- Setters --- // --- Setters ---
void setVelY(float vel_y) { vy_ = vel_y; } void setVelY(float vel_y) { vy_ = vel_y; }
void setSpeed(float speed) { speed_ = speed; } void setGameTempo(float tempo) { game_tempo_ = tempo; }
void setInvulnerable(bool value) { invulnerable_ = value; } void setInvulnerable(bool value) { invulnerable_ = value; }
void setBouncingSound(bool value) { bouncing_sound_enabled_ = value; } void setBouncingSound(bool value) { sound_.bouncing_enabled = value; }
void setPoppingSound(bool value) { poping_sound_enabled_ = value; } void setPoppingSound(bool value) { sound_.poping_enabled = value; }
void setSound(bool value) { sound_enabled_ = value; } void setSound(bool value) { sound_.enabled = value; }
private: private:
// --- Estructura para el efecto de rebote --- // --- Estructura para el efecto de rebote ---
@@ -114,10 +136,28 @@ class Balloon {
// Tablas de valores predefinidos para el efecto de rebote // Tablas de valores predefinidos para el efecto de rebote
static constexpr std::array<float, BOUNCE_FRAMES> HORIZONTAL_ZOOM_VALUES = { static constexpr std::array<float, BOUNCE_FRAMES> HORIZONTAL_ZOOM_VALUES = {
1.10F, 1.05F, 1.00F, 0.95F, 0.90F, 0.95F, 1.00F, 1.02F, 1.05F, 1.02F}; 1.10F,
1.05F,
1.00F,
0.95F,
0.90F,
0.95F,
1.00F,
1.02F,
1.05F,
1.02F};
static constexpr std::array<float, BOUNCE_FRAMES> VERTICAL_ZOOM_VALUES = { static constexpr std::array<float, BOUNCE_FRAMES> VERTICAL_ZOOM_VALUES = {
0.90F, 0.95F, 1.00F, 1.05F, 1.10F, 1.05F, 1.00F, 0.98F, 0.95F, 0.98F}; 0.90F,
0.95F,
1.00F,
1.05F,
1.10F,
1.05F,
1.00F,
0.98F,
0.95F,
0.98F};
// Estado del efecto // Estado del efecto
bool enabled_ = false; // Si el efecto está activo bool enabled_ = false; // Si el efecto está activo
@@ -218,22 +258,18 @@ class Balloon {
bool stopped_; // Si el globo está parado bool stopped_; // Si el globo está parado
bool use_reversed_colors_ = false; // Si se usa el color alternativo bool use_reversed_colors_ = false; // Si se usa el color alternativo
Circle collider_; // Círculo de colisión Circle collider_; // Círculo de colisión
Uint16 creation_counter_; // Temporizador de creación float creation_counter_; // Temporizador de creación
Uint16 creation_counter_ini_; // Valor inicial del temporizador de creación float creation_counter_ini_; // Valor inicial del temporizador de creación
Uint16 score_; // Puntos al destruir el globo Uint16 score_; // Puntos al destruir el globo
Type type_; // Tipo de globo Type type_; // Tipo de globo
Size size_; // Tamaño de globo Size size_; // Tamaño de globo
Uint8 menace_; // Amenaza que genera el globo Uint8 menace_; // Amenaza que genera el globo
Uint32 counter_ = 0; // Contador interno Uint32 counter_ = 0; // Contador interno
float travel_y_ = 1.0F; // Distancia a recorrer en Y antes de aplicar gravedad float game_tempo_; // Multiplicador de tempo del juego
float speed_; // Velocidad del globo float movement_accumulator_ = 0.0f; // Acumulador para movimiento durante creación (deltaTime)
Uint8 power_; // Poder que alberga el globo Uint8 power_; // Poder que alberga el globo
SDL_FRect play_area_; // Zona de movimiento del globo SDL_FRect play_area_; // Zona de movimiento del globo
std::string bouncing_sound_; // Archivo de sonido al rebotar Sound sound_; // Configuración de sonido del globo
std::string popping_sound_; // Archivo de sonido al explotar
bool bouncing_sound_enabled_ = false; // Si debe sonar el globo al rebotar
bool poping_sound_enabled_ = true; // Si debe sonar el globo al explotar
bool sound_enabled_ = true; // Indica si los globos deben hacer algun sonido
BounceEffect bounce_effect_; // Efecto de rebote BounceEffect bounce_effect_; // Efecto de rebote
// --- Posicionamiento y transformación --- // --- Posicionamiento y transformación ---
@@ -242,13 +278,13 @@ class Balloon {
// --- Animación y sonido --- // --- Animación y sonido ---
void setAnimation(); // Establece la animación correspondiente void setAnimation(); // Establece la animación correspondiente
void playSound(const std::string& name) const; // Reproduce un sonido por nombre
void playBouncingSound(); // Reproduce el sonido de rebote void playBouncingSound(); // Reproduce el sonido de rebote
void playPoppingSound(); // Reproduce el sonido de reventar
// --- Movimiento y física --- // --- Movimiento y física ---
void handleHorizontalMovement(); // Maneja el movimiento horizontal void handleHorizontalMovement(float deltaTime); // Maneja el movimiento horizontal (time-based)
void handleVerticalMovement(); // Maneja el movimiento vertical void handleVerticalMovement(float deltaTime); // Maneja el movimiento vertical (time-based)
void applyGravity(); // Aplica la gravedad al objeto void applyGravity(float deltaTime); // Aplica la gravedad al objeto (time-based)
// --- Rebote --- // --- Rebote ---
void enableBounceEffect(); // Activa el efecto de rebote void enableBounceEffect(); // Activa el efecto de rebote
@@ -263,5 +299,5 @@ class Balloon {
void handleBottomCollision(); // Maneja la colisión inferior void handleBottomCollision(); // Maneja la colisión inferior
// --- Lógica de estado --- // --- Lógica de estado ---
void updateState(); // Actualiza los estados del globo void updateState(float deltaTime); // Actualiza los estados del globo (time-based)
}; };

View File

@@ -155,7 +155,7 @@ auto BalloonFormations::parseBalloonLine(const std::string& line, const std::map
return std::nullopt; return std::nullopt;
} }
int creation_time = DEFAULT_CREATION_TIME + evaluateExpression(tokens.at(6), variables); float creation_time = CREATION_TIME + evaluateExpression(tokens.at(6), variables); // Base time + offset from formations.txt
return SpawnParams(x + offset, y, vel_x, type, size, creation_time); return SpawnParams(x + offset, y, vel_x, type, size, creation_time);
} catch (const std::exception&) { } catch (const std::exception&) {
@@ -168,7 +168,7 @@ auto BalloonFormations::evaluateExpression(const std::string& expr, const std::m
// Si es un número directo // Si es un número directo
if ((std::isdigit(trimmed_expr.at(0)) != 0) || (trimmed_expr.at(0) == '-' && trimmed_expr.length() > 1)) { if ((std::isdigit(trimmed_expr.at(0)) != 0) || (trimmed_expr.at(0) == '-' && trimmed_expr.length() > 1)) {
return std::stoi(trimmed_expr); return std::stof(trimmed_expr);
} }
// Si es una variable simple // Si es una variable simple
@@ -205,7 +205,7 @@ auto BalloonFormations::evaluateSimpleExpression(const std::string& expr, const
} }
// Si no se encuentra operador, intentar como variable o número // Si no se encuentra operador, intentar como variable o número
return variables.find(expr) != variables.end() ? variables.at(expr) : std::stoi(expr); return variables.find(expr) != variables.end() ? variables.at(expr) : std::stof(expr);
} }
auto BalloonFormations::trim(const std::string& str) -> std::string { auto BalloonFormations::trim(const std::string& str) -> std::string {
@@ -235,10 +235,10 @@ void BalloonFormations::createFloaterVariants() {
#ifdef _DEBUG #ifdef _DEBUG
void BalloonFormations::addTestFormation() { void BalloonFormations::addTestFormation() {
std::vector<SpawnParams> test_params = { std::vector<SpawnParams> test_params = {
{10, -BLOCK, 0, Balloon::Type::FLOATER, Balloon::Size::SMALL, 200}, {10, -BLOCK, 0, Balloon::Type::FLOATER, Balloon::Size::SMALL, 3.334f}, // 200 frames ÷ 60fps = 3.334s
{50, -BLOCK, 0, Balloon::Type::FLOATER, Balloon::Size::MEDIUM, 200}, {50, -BLOCK, 0, Balloon::Type::FLOATER, Balloon::Size::MEDIUM, 3.334f}, // 200 frames ÷ 60fps = 3.334s
{90, -BLOCK, 0, Balloon::Type::FLOATER, Balloon::Size::LARGE, 200}, {90, -BLOCK, 0, Balloon::Type::FLOATER, Balloon::Size::LARGE, 3.334f}, // 200 frames ÷ 60fps = 3.334s
{140, -BLOCK, 0, Balloon::Type::FLOATER, Balloon::Size::EXTRALARGE, 200}}; {140, -BLOCK, 0, Balloon::Type::FLOATER, Balloon::Size::EXTRALARGE, 3.334f}}; // 200 frames ÷ 60fps = 3.334s
formations_.at(99) = Formation(test_params); formations_.at(99) = Formation(test_params);
} }

View File

@@ -15,19 +15,24 @@ class BalloonFormations {
public: public:
// --- Estructuras --- // --- Estructuras ---
struct SpawnParams { struct SpawnParams {
int x = 0; // Posición en el eje X donde crear el globo float x = 0; // Posición en el eje X donde crear el globo
int y = 0; // Posición en el eje Y donde crear el globo float y = 0; // Posición en el eje Y donde crear el globo
float vel_x = 0.0F; // Velocidad inicial en el eje X float vel_x = 0.0F; // Velocidad inicial en el eje X
Balloon::Type type = Balloon::Type::BALLOON; // Tipo de globo Balloon::Type type = Balloon::Type::BALLOON; // Tipo de globo
Balloon::Size size = Balloon::Size::SMALL; // Tamaño de globo Balloon::Size size = Balloon::Size::SMALL; // Tamaño de globo
int creation_counter = 0; // Temporizador para la creación del globo float creation_counter = 0.0f; // Temporizador para la creación del globo
// Constructor por defecto // Constructor por defecto
SpawnParams() = default; SpawnParams() = default;
// Constructor con parámetros // Constructor con parámetros
SpawnParams(int x, int y, float vel_x, Balloon::Type type, Balloon::Size size, int creation_counter) SpawnParams(float x, float y, float vel_x, Balloon::Type type, Balloon::Size size, float creation_counter)
: x(x), y(y), vel_x(vel_x), type(type), size(size), creation_counter(creation_counter) {} : x(x),
y(y),
vel_x(vel_x),
type(type),
size(size),
creation_counter(creation_counter) {}
}; };
struct Formation { struct Formation {
@@ -77,7 +82,8 @@ class BalloonFormations {
private: private:
// --- Constantes --- // --- Constantes ---
static constexpr int BALLOON_SPAWN_HEIGHT = 208; // Altura desde el suelo en la que aparecen los globos static constexpr int BALLOON_SPAWN_HEIGHT = 208; // Altura desde el suelo en la que aparecen los globos
static constexpr int DEFAULT_CREATION_TIME = 200; // Tiempo base de creación de los globos para las formaciones static constexpr float CREATION_TIME = 5.0f; // Tiempo base de creación de los globos en segundos (300 frames ÷ 60fps = 5.0s)
static constexpr float DEFAULT_CREATION_TIME = 3.334f; // Tiempo base de creación de los globos en segundos (200 frames ÷ 60fps = 3.334s)
// --- Variables --- // --- Variables ---
std::vector<Formation> formations_; // Vector con todas las formaciones disponibles std::vector<Formation> formations_; // Vector con todas las formaciones disponibles

View File

@@ -17,7 +17,9 @@
// Constructor // Constructor
BalloonManager::BalloonManager(IStageInfo *stage_info) BalloonManager::BalloonManager(IStageInfo *stage_info)
: explosions_(std::make_unique<Explosions>()), balloon_formations_(std::make_unique<BalloonFormations>()), stage_info_(stage_info) { init(); } : explosions_(std::make_unique<Explosions>()),
balloon_formations_(std::make_unique<BalloonFormations>()),
stage_info_(stage_info) { init(); }
// Inicializa // Inicializa
void BalloonManager::init() { void BalloonManager::init() {
@@ -60,13 +62,13 @@ void BalloonManager::init() {
explosions_->addTexture(3, explosions_textures_.at(3), explosions_animations_.at(3)); explosions_->addTexture(3, explosions_textures_.at(3), explosions_animations_.at(3));
} }
// Actualiza // Actualiza (time-based)
void BalloonManager::update() { void BalloonManager::update(float deltaTime) {
for (const auto &balloon : balloons_) { for (const auto &balloon : balloons_) {
balloon->update(); balloon->update(deltaTime);
} }
updateBalloonDeployCounter(); updateBalloonDeployCounter(deltaTime);
explosions_->update(); explosions_->update(deltaTime);
} }
// Renderiza los objetos // Renderiza los objetos
@@ -79,12 +81,12 @@ void BalloonManager::render() {
// Crea una formación de globos // Crea una formación de globos
void BalloonManager::deployRandomFormation(int stage) { void BalloonManager::deployRandomFormation(int stage) {
// Solo despliega una formación enemiga si ha pasado cierto tiempo desde la última // Solo despliega una formación enemiga si el timer ha llegado a cero
if (balloon_deploy_counter_ == 0) { if (balloon_deploy_counter_ <= 0.0f) {
// En este punto se decide entre crear una powerball o una formación enemiga // En este punto se decide entre crear una powerball o una formación enemiga
if ((rand() % 100 < 15) && (canPowerBallBeCreated())) { if ((rand() % 100 < 15) && (canPowerBallBeCreated())) {
createPowerBall(); // Crea una powerball createPowerBall(); // Crea una powerball
balloon_deploy_counter_ = 10; // Da un poco de margen para que se creen mas globos balloon_deploy_counter_ = POWERBALL_DEPLOY_DELAY; // Resetea con pequeño retraso
} else { } else {
// Decrementa el contador de despliegues de globos necesarios para la siguiente PowerBall // Decrementa el contador de despliegues de globos necesarios para la siguiente PowerBall
if (power_ball_counter_ > 0) { if (power_ball_counter_ > 0) {
@@ -105,11 +107,19 @@ void BalloonManager::deployRandomFormation(int stage) {
// Crea los globos de la formación // Crea los globos de la formación
const auto BALLOONS = balloon_formations_->getFormationFromPool(stage, formation_id).balloons; const auto BALLOONS = balloon_formations_->getFormationFromPool(stage, formation_id).balloons;
for (auto balloon : BALLOONS) { for (auto balloon : BALLOONS) {
createBalloon(balloon.x, balloon.y, balloon.type, balloon.size, balloon.vel_x, balloon_speed_, (creation_time_enabled_) ? balloon.creation_counter : 0); Balloon::Config config = {
.x = balloon.x,
.y = balloon.y,
.type = balloon.type,
.size = balloon.size,
.vel_x = balloon.vel_x,
.game_tempo = balloon_speed_,
.creation_counter = creation_time_enabled_ ? balloon.creation_counter : 0.0f};
createBalloon(config);
} }
// Reinicia el contador para el próximo despliegue // Reinicia el timer para el próximo despliegue
balloon_deploy_counter_ = DEFAULT_BALLOON_DEPLOY_COUNTER; balloon_deploy_counter_ = DEFAULT_BALLOON_DEPLOY_DELAY;
} }
} }
} }
@@ -118,15 +128,31 @@ void BalloonManager::deployRandomFormation(int stage) {
void BalloonManager::deployFormation(int formation_id) { void BalloonManager::deployFormation(int formation_id) {
const auto BALLOONS = balloon_formations_->getFormation(formation_id).balloons; const auto BALLOONS = balloon_formations_->getFormation(formation_id).balloons;
for (auto balloon : BALLOONS) { for (auto balloon : BALLOONS) {
createBalloon(balloon.x, balloon.y, balloon.type, balloon.size, balloon.vel_x, balloon_speed_, balloon.creation_counter); Balloon::Config config = {
.x = balloon.x,
.y = balloon.y,
.type = balloon.type,
.size = balloon.size,
.vel_x = balloon.vel_x,
.game_tempo = balloon_speed_,
.creation_counter = balloon.creation_counter};
createBalloon(config);
} }
} }
// Crea una formación de globos específica a una altura determinada // Crea una formación de globos específica a una altura determinada
void BalloonManager::deployFormation(int formation_id, int y) { void BalloonManager::deployFormation(int formation_id, float y) {
const auto BALLOONS = balloon_formations_->getFormation(formation_id).balloons; const auto BALLOONS = balloon_formations_->getFormation(formation_id).balloons;
for (auto balloon : BALLOONS) { for (auto balloon : BALLOONS) {
createBalloon(balloon.x, y, balloon.type, balloon.size, balloon.vel_x, balloon_speed_, balloon.creation_counter); Balloon::Config config = {
.x = balloon.x,
.y = y,
.type = balloon.type,
.size = balloon.size,
.vel_x = balloon.vel_x,
.game_tempo = balloon_speed_,
.creation_counter = balloon.creation_counter};
createBalloon(config);
} }
} }
@@ -136,11 +162,10 @@ void BalloonManager::freeBalloons() {
balloons_.erase(result.begin(), balloons_.end()); balloons_.erase(result.begin(), balloons_.end());
} }
// Actualiza la variable enemyDeployCounter // Actualiza el timer de despliegue de globos (time-based)
void BalloonManager::updateBalloonDeployCounter() { void BalloonManager::updateBalloonDeployCounter(float deltaTime) {
if (balloon_deploy_counter_ > 0) { // DeltaTime en segundos - timer decrementa hasta llegar a cero
--balloon_deploy_counter_; balloon_deploy_counter_ -= deltaTime;
}
} }
// Indica si se puede crear una powerball // Indica si se puede crear una powerball
@@ -152,13 +177,16 @@ auto BalloonManager::calculateScreenPower() -> int {
} }
// Crea un globo nuevo en el vector de globos // Crea un globo nuevo en el vector de globos
auto BalloonManager::createBalloon(float x, int y, Balloon::Type type, Balloon::Size size, float velx, float speed, int creation_timer) -> std::shared_ptr<Balloon> { auto BalloonManager::createBalloon(Balloon::Config config) -> std::shared_ptr<Balloon> {
if (can_deploy_balloons_) { if (can_deploy_balloons_) {
const int INDEX = static_cast<int>(size); const int INDEX = static_cast<int>(config.size);
balloons_.emplace_back(std::make_shared<Balloon>(x, y, type, size, velx, speed, creation_timer, play_area_, balloon_textures_.at(INDEX), balloon_animations_.at(INDEX))); config.play_area = play_area_;
balloons_.back()->setSound(sound_enabled_); config.texture = balloon_textures_.at(INDEX);
balloons_.back()->setBouncingSound(bouncing_sound_enabled_); config.animation = balloon_animations_.at(INDEX);
balloons_.back()->setPoppingSound(poping_sound_enabled_); config.sound.enabled = sound_enabled_;
config.sound.bouncing_enabled = bouncing_sound_enabled_;
config.sound.poping_enabled = poping_sound_enabled_;
balloons_.emplace_back(std::make_shared<Balloon>(config));
return balloons_.back(); return balloons_.back();
} }
@@ -169,22 +197,28 @@ auto BalloonManager::createBalloon(float x, int y, Balloon::Type type, Balloon::
void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction) { void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction) {
if (can_deploy_balloons_) { if (can_deploy_balloons_) {
// Calcula parametros // Calcula parametros
const float VX = direction == "LEFT" ? Balloon::VELX_NEGATIVE : Balloon::VELX_POSITIVE;
const auto SIZE = static_cast<Balloon::Size>(static_cast<int>(balloon->getSize()) - 1);
const int PARENT_HEIGHT = balloon->getHeight(); const int PARENT_HEIGHT = balloon->getHeight();
const int CHILD_HEIGHT = Balloon::WIDTH.at(static_cast<int>(balloon->getSize()) - 1); const int CHILD_HEIGHT = Balloon::WIDTH.at(static_cast<int>(balloon->getSize()) - 1);
const int CHILD_WIDTH = CHILD_HEIGHT; const int CHILD_WIDTH = CHILD_HEIGHT;
const float Y = balloon->getPosY() + ((PARENT_HEIGHT - CHILD_HEIGHT) / 2);
float x = direction == "LEFT" ? balloon->getPosX() + (balloon->getWidth() / 3) : balloon->getPosX() + (2 * (balloon->getWidth() / 3)); const float X = direction == "LEFT" ? balloon->getPosX() + (balloon->getWidth() / 3) : balloon->getPosX() + (2 * (balloon->getWidth() / 3));
const float MIN_X = play_area_.x; const float MIN_X = play_area_.x;
const float MAX_X = play_area_.w - CHILD_WIDTH; const float MAX_X = play_area_.w - CHILD_WIDTH;
x = std::clamp(x - (CHILD_WIDTH / 2), MIN_X, MAX_X);
Balloon::Config config = {
.x = std::clamp(X - (CHILD_WIDTH / 2), MIN_X, MAX_X),
.y = balloon->getPosY() + ((PARENT_HEIGHT - CHILD_HEIGHT) / 2),
.size = static_cast<Balloon::Size>(static_cast<int>(balloon->getSize()) - 1),
.vel_x = direction == "LEFT" ? Balloon::VELX_NEGATIVE : Balloon::VELX_POSITIVE,
.game_tempo = balloon_speed_,
.creation_counter = 0};
// Crea el globo // Crea el globo
auto b = createBalloon(x, Y, balloon->getType(), SIZE, VX, balloon_speed_, 0); auto b = createBalloon(config);
// Establece parametros // Establece parametros (deltaTime en segundos - velocidades en pixels/segundo)
b->setVelY(b->getType() == Balloon::Type::BALLOON ? -2.50F : Balloon::VELX_NEGATIVE * 2.0F); constexpr float VEL_Y_BALLOON_PER_S = -150.0F; // -2.50 pixels/frame convertido a pixels/segundo (-2.50 * 60 = -150)
b->setVelY(b->getType() == Balloon::Type::BALLOON ? VEL_Y_BALLOON_PER_S : Balloon::VELX_NEGATIVE * 2.0F);
// Herencia de estados // Herencia de estados
if (balloon->isStopped()) { b->stop(); } if (balloon->isStopped()) { b->stop(); }
@@ -196,18 +230,32 @@ void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon> &balloon,
void BalloonManager::createPowerBall() { void BalloonManager::createPowerBall() {
if (can_deploy_balloons_) { if (can_deploy_balloons_) {
constexpr int VALUES = 6; constexpr int VALUES = 6;
constexpr float POS_Y = -Balloon::WIDTH.at(4); const int LUCK = rand() % VALUES;
constexpr int CREATION_TIME = 0;
const float LEFT = param.game.play_area.rect.x; const float LEFT = param.game.play_area.rect.x;
const float CENTER = param.game.play_area.center_x - (Balloon::WIDTH.at(4) / 2); const float CENTER = param.game.play_area.center_x - (Balloon::WIDTH.at(4) / 2);
const float RIGHT = param.game.play_area.rect.w - Balloon::WIDTH.at(4); const float RIGHT = param.game.play_area.rect.w - Balloon::WIDTH.at(4);
const int LUCK = rand() % VALUES;
const std::array<float, VALUES> POS_X = {LEFT, LEFT, CENTER, CENTER, RIGHT, RIGHT}; const std::array<float, VALUES> POS_X = {LEFT, LEFT, CENTER, CENTER, RIGHT, RIGHT};
const std::array<float, VALUES> VEL_X = {Balloon::VELX_POSITIVE, Balloon::VELX_POSITIVE, Balloon::VELX_POSITIVE, Balloon::VELX_NEGATIVE, Balloon::VELX_NEGATIVE, Balloon::VELX_NEGATIVE}; const std::array<float, VALUES> VEL_X = {Balloon::VELX_POSITIVE, Balloon::VELX_POSITIVE, Balloon::VELX_POSITIVE, Balloon::VELX_NEGATIVE, Balloon::VELX_NEGATIVE, Balloon::VELX_NEGATIVE};
balloons_.emplace_back(std::make_unique<Balloon>(POS_X[LUCK], POS_Y, Balloon::Type::POWERBALL, Balloon::Size::EXTRALARGE, VEL_X[LUCK], balloon_speed_, CREATION_TIME, play_area_, balloon_textures_[4], balloon_animations_[4])); Balloon::Config config = {
.x = POS_X.at(LUCK),
.y = -Balloon::WIDTH.at(4),
.type = Balloon::Type::POWERBALL,
.size = Balloon::Size::EXTRALARGE,
.vel_x = VEL_X.at(LUCK),
.game_tempo = balloon_speed_,
.creation_counter = 0,
.play_area = play_area_,
.texture = balloon_textures_.at(4),
.animation = balloon_animations_.at(4),
.sound = {
.bouncing_enabled = bouncing_sound_enabled_,
.poping_enabled = poping_sound_enabled_,
.enabled = sound_enabled_}};
balloons_.emplace_back(std::make_unique<Balloon>(config));
balloons_.back()->setInvulnerable(true); balloons_.back()->setInvulnerable(true);
power_ball_enabled_ = true; power_ball_enabled_ = true;
@@ -219,7 +267,7 @@ void BalloonManager::createPowerBall() {
void BalloonManager::setBalloonSpeed(float speed) { void BalloonManager::setBalloonSpeed(float speed) {
balloon_speed_ = speed; balloon_speed_ = speed;
for (auto &balloon : balloons_) { for (auto &balloon : balloons_) {
balloon->setSpeed(speed); balloon->setGameTempo(speed);
} }
} }
@@ -232,7 +280,7 @@ auto BalloonManager::popBalloon(const std::shared_ptr<Balloon> &balloon) -> int
balloon->pop(true); balloon->pop(true);
score = destroyAllBalloons(); score = destroyAllBalloons();
power_ball_enabled_ = false; power_ball_enabled_ = false;
balloon_deploy_counter_ = 20; balloon_deploy_counter_ = BALLOON_POP_DELAY; // Resetea con retraso
} else { } else {
score = balloon->getScore(); score = balloon->getScore();
if (balloon->getSize() != Balloon::Size::SMALL) { if (balloon->getSize() != Balloon::Size::SMALL) {
@@ -288,8 +336,8 @@ auto BalloonManager::destroyAllBalloons() -> int {
score += destroyBalloon(balloon); score += destroyBalloon(balloon);
} }
balloon_deploy_counter_ = 300; balloon_deploy_counter_ = DEFAULT_BALLOON_DEPLOY_DELAY;
Screen::get()->flash(Colors::FLASH, 3); Screen::get()->flash(Colors::FLASH, 0.05F);
Screen::get()->shake(); Screen::get()->shake();
return score; return score;
@@ -298,9 +346,11 @@ auto BalloonManager::destroyAllBalloons() -> int {
// Detiene todos los globos // Detiene todos los globos
void BalloonManager::stopAllBalloons() { void BalloonManager::stopAllBalloons() {
for (auto &balloon : balloons_) { for (auto &balloon : balloons_) {
if (!balloon->isBeingCreated()) {
balloon->stop(); balloon->stop();
} }
} }
}
// Pone en marcha todos los globos // Pone en marcha todos los globos
void BalloonManager::startAllBalloons() { void BalloonManager::startAllBalloons() {
@@ -332,19 +382,6 @@ void BalloonManager::createTwoBigBalloons() {
deployFormation(1); deployFormation(1);
} }
// Crea una disposición de globos aleatoria
void BalloonManager::createRandomBalloons() {
const int NUM_BALLOONS = 2 + (rand() % 4);
for (int i = 0; i < NUM_BALLOONS; ++i) {
const float X = param.game.game_area.rect.x + (rand() % static_cast<int>(param.game.game_area.rect.w)) - Balloon::WIDTH.at(3);
const int Y = param.game.game_area.rect.y + (rand() % 50);
const auto SIZE = static_cast<Balloon::Size>(rand() % 4);
const float VEL_X = (rand() % 2 == 0) ? Balloon::VELX_POSITIVE : Balloon::VELX_NEGATIVE;
const int CREATION_COUNTER = 0;
createBalloon(X, Y, Balloon::Type::BALLOON, SIZE, VEL_X, balloon_speed_, CREATION_COUNTER);
}
}
// Obtiene el nivel de ameza actual generado por los globos // Obtiene el nivel de ameza actual generado por los globos
auto BalloonManager::getMenace() -> int { auto BalloonManager::getMenace() -> int {
return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon) { return sum + (balloon->isEnabled() ? balloon->getMenace() : 0); }); return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon) { return sum + (balloon->isEnabled() ? balloon->getMenace() : 0); });

View File

@@ -28,7 +28,7 @@ class BalloonManager {
~BalloonManager() = default; ~BalloonManager() = default;
// --- Métodos principales --- // --- Métodos principales ---
void update(); // Actualiza el estado de los globos void update(float deltaTime); // Actualiza el estado de los globos (time-based)
void render(); // Renderiza los globos en pantalla void render(); // Renderiza los globos en pantalla
// --- Gestión de globos --- // --- Gestión de globos ---
@@ -37,20 +37,19 @@ class BalloonManager {
// --- Creación de formaciones enemigas --- // --- Creación de formaciones enemigas ---
void deployRandomFormation(int stage); // Crea una formación de globos aleatoria void deployRandomFormation(int stage); // Crea una formación de globos aleatoria
void deployFormation(int formation_id); // Crea una formación específica void deployFormation(int formation_id); // Crea una formación específica
void deployFormation(int formation_id, int y); // Crea una formación específica con coordenadas void deployFormation(int formation_id, float y); // Crea una formación específica con coordenadas
// --- Creación de globos --- // --- Creación de globos ---
auto createBalloon(float x, int y, Balloon::Type type, Balloon::Size size, float velx, float speed, int creation_timer) -> std::shared_ptr<Balloon>; // Crea un nuevo globo auto createBalloon(Balloon::Config config) -> std::shared_ptr<Balloon>; // Crea un nuevo globo
void createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction); // Crea un globo a partir de otro void createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction); // Crea un globo a partir de otro
void createPowerBall(); // Crea una PowerBall void createPowerBall(); // Crea una PowerBall
void createTwoBigBalloons(); // Crea dos globos grandes void createTwoBigBalloons(); // Crea dos globos grandes
void createRandomBalloons(); // Crea una disposición aleatoria de globos
// --- Control de velocidad y despliegue --- // --- Control de velocidad y despliegue ---
void setBalloonSpeed(float speed); // Ajusta la velocidad de los globos void setBalloonSpeed(float speed); // Ajusta la velocidad de los globos
void setDefaultBalloonSpeed(float speed) { default_balloon_speed_ = speed; }; // Establece la velocidad base void setDefaultBalloonSpeed(float speed) { default_balloon_speed_ = speed; }; // Establece la velocidad base
void resetBalloonSpeed() { setBalloonSpeed(default_balloon_speed_); }; // Restablece la velocidad de los globos void resetBalloonSpeed() { setBalloonSpeed(default_balloon_speed_); }; // Restablece la velocidad de los globos
void updateBalloonDeployCounter(); // Actualiza el contador de despliegue void updateBalloonDeployCounter(float deltaTime); // Actualiza el contador de despliegue (time-based)
auto canPowerBallBeCreated() -> bool; // Indica si se puede crear una PowerBall auto canPowerBallBeCreated() -> bool; // Indica si se puede crear una PowerBall
auto calculateScreenPower() -> int; // Calcula el poder de los globos en pantalla auto calculateScreenPower() -> int; // Calcula el poder de los globos en pantalla
@@ -83,7 +82,9 @@ class BalloonManager {
private: private:
// --- Constantes --- // --- Constantes ---
static const int DEFAULT_BALLOON_DEPLOY_COUNTER = 300; static constexpr float DEFAULT_BALLOON_DEPLOY_DELAY = 5.0f; // 300 frames = 5 segundos
static constexpr float POWERBALL_DEPLOY_DELAY = 0.167f; // 10 frames = 0.167 segundos
static constexpr float BALLOON_POP_DELAY = 0.333f; // 20 frames = 0.333 segundos
// --- Objetos y punteros --- // --- Objetos y punteros ---
Balloons balloons_; // Vector con los globos activos Balloons balloons_; // Vector con los globos activos
@@ -97,9 +98,9 @@ class BalloonManager {
// --- Variables de estado --- // --- Variables de estado ---
SDL_FRect play_area_ = param.game.play_area.rect; SDL_FRect play_area_ = param.game.play_area.rect;
float balloon_speed_ = Balloon::SPEED.at(0); float balloon_speed_ = Balloon::GAME_TEMPO.at(0);
float default_balloon_speed_ = Balloon::SPEED.at(0); float default_balloon_speed_ = Balloon::GAME_TEMPO.at(0);
int balloon_deploy_counter_ = 0; float balloon_deploy_counter_ = 0;
int power_ball_counter_ = 0; int power_ball_counter_ = 0;
int last_balloon_deploy_ = 0; int last_balloon_deploy_ = 0;
bool power_ball_enabled_ = false; bool power_ball_enabled_ = false;

View File

@@ -4,46 +4,64 @@
#include <string> // Para char_traits, basic_string, operator+, string #include <string> // Para char_traits, basic_string, operator+, string
#include "param.h" // Para Param, ParamGame, param #include "param.h" // Para Param, ParamGame, param
#include "player.h" // Para Player::Id
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
// Constructor // Constructor
Bullet::Bullet(float x, float y, BulletType bullet_type, bool powered, Player::Id owner) Bullet::Bullet(float x, float y, Type type, Color color, int owner)
: sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("bullet.png"), Resource::get()->getAnimation("bullet.ani"))), : sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("bullet.png"), Resource::get()->getAnimation("bullet.ani"))),
bullet_type_(bullet_type), type_(type),
owner_(owner), owner_(owner),
pos_x_(x), pos_x_(x),
pos_y_(y) { pos_y_(y) {
vel_x_ = calculateVelocity(bullet_type_); vel_x_ = calculateVelocity(type_);
sprite_->setCurrentAnimation(buildAnimationString(bullet_type_, powered)); sprite_->setCurrentAnimation(buildAnimationString(type_, color));
collider_.r = WIDTH / 2; collider_.r = WIDTH / 2;
shiftColliders(); shiftColliders();
} }
// Calcula la velocidad horizontal de la bala basada en su tipo // Calcula la velocidad horizontal de la bala basada en su tipo
auto Bullet::calculateVelocity(BulletType bullet_type) -> float { auto Bullet::calculateVelocity(Type type) -> float {
switch (bullet_type) { switch (type) {
case BulletType::LEFT: case Type::LEFT:
return VEL_X_LEFT; return VEL_X_LEFT;
case BulletType::RIGHT: case Type::RIGHT:
return VEL_X_RIGHT; return VEL_X_RIGHT;
default: default:
return VEL_X_CENTER; return VEL_X_CENTER;
} }
} }
// Construye el string de animación basado en el tipo de bala y si está potenciada // Construye el string de animación basado en el tipo de bala y color específico
auto Bullet::buildAnimationString(BulletType bullet_type, bool powered) -> std::string { auto Bullet::buildAnimationString(Type type, Color color) -> std::string {
std::string animation_string = powered ? "powered_" : "normal_"; std::string animation_string;
switch (bullet_type) { // Mapear color a string específico
case BulletType::UP: switch (color) {
case Color::YELLOW:
animation_string = "yellow_";
break;
case Color::GREEN:
animation_string = "green_";
break;
case Color::RED:
animation_string = "red_";
break;
case Color::PURPLE:
animation_string = "purple_";
break;
}
// Añadir dirección
switch (type) {
case Type::UP:
animation_string += "up"; animation_string += "up";
break; break;
case BulletType::LEFT: case Type::LEFT:
animation_string += "left"; animation_string += "left";
break; break;
case BulletType::RIGHT: case Type::RIGHT:
animation_string += "right"; animation_string += "right";
break; break;
default: default:
@@ -53,48 +71,48 @@ auto Bullet::buildAnimationString(BulletType bullet_type, bool powered) -> std::
return animation_string; return animation_string;
} }
// Implementación de render (llama al render del sprite_) // Implementación de render
void Bullet::render() { void Bullet::render() {
if (bullet_type_ != BulletType::NONE) { if (type_ != Type::NONE) {
sprite_->render(); sprite_->render();
} }
} }
// Actualiza el estado del objeto // Actualiza el estado del objeto
auto Bullet::update() -> BulletMoveStatus { auto Bullet::update(float deltaTime) -> MoveStatus {
sprite_->update(); sprite_->update(deltaTime);
return move(); return move(deltaTime);
} }
// Implementación del movimiento usando BulletMoveStatus // Implementación del movimiento usando MoveStatus
auto Bullet::move() -> BulletMoveStatus { auto Bullet::move(float deltaTime) -> MoveStatus {
pos_x_ += vel_x_; pos_x_ += vel_x_ * deltaTime;
if (pos_x_ < param.game.play_area.rect.x - WIDTH || pos_x_ > param.game.play_area.rect.w) { if (pos_x_ < param.game.play_area.rect.x - WIDTH || pos_x_ > param.game.play_area.rect.w) {
disable(); disable();
return BulletMoveStatus::OUT; return MoveStatus::OUT;
} }
pos_y_ += VEL_Y; pos_y_ += VEL_Y * deltaTime;
if (pos_y_ < param.game.play_area.rect.y - HEIGHT) { if (pos_y_ < param.game.play_area.rect.y - HEIGHT) {
disable(); disable();
return BulletMoveStatus::OUT; return MoveStatus::OUT;
} }
shiftSprite(); shiftSprite();
shiftColliders(); shiftColliders();
return BulletMoveStatus::OK; return MoveStatus::OK;
} }
auto Bullet::isEnabled() const -> bool { auto Bullet::isEnabled() const -> bool {
return bullet_type_ != BulletType::NONE; return type_ != Type::NONE;
} }
void Bullet::disable() { void Bullet::disable() {
bullet_type_ = BulletType::NONE; type_ = Type::NONE;
} }
auto Bullet::getOwner() const -> Player::Id { auto Bullet::getOwner() const -> int {
return owner_; return owner_;
} }

View File

@@ -6,22 +6,8 @@
#include <string> // Para string #include <string> // Para string
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
#include "player.h" // Para Player
#include "utils.h" // Para Circle #include "utils.h" // Para Circle
// --- Enums ---
enum class BulletType : Uint8 {
UP, // Bala hacia arriba
LEFT, // Bala hacia la izquierda
RIGHT, // Bala hacia la derecha
NONE // Sin bala
};
enum class BulletMoveStatus : Uint8 {
OK = 0, // Movimiento normal
OUT = 1 // Fuera de los límites
};
// --- Clase Bullet: representa una bala del jugador --- // --- Clase Bullet: representa una bala del jugador ---
class Bullet { class Bullet {
public: public:
@@ -29,25 +15,45 @@ class Bullet {
static constexpr float WIDTH = 12.0F; // Anchura de la bala static constexpr float WIDTH = 12.0F; // Anchura de la bala
static constexpr float HEIGHT = 12.0F; // Altura de la bala static constexpr float HEIGHT = 12.0F; // Altura de la bala
// --- Enums ---
enum class Type : Uint8 {
UP, // Bala hacia arriba
LEFT, // Bala hacia la izquierda
RIGHT, // Bala hacia la derecha
NONE // Sin bala
};
enum class MoveStatus : Uint8 {
OK = 0, // Movimiento normal
OUT = 1 // Fuera de los límites
};
enum class Color : Uint8 {
YELLOW,
GREEN,
RED,
PURPLE
};
// --- Constructor y destructor --- // --- Constructor y destructor ---
Bullet(float x, float y, BulletType bullet_type, bool powered, Player::Id owner); // Constructor principal Bullet(float x, float y, Type type, Color color, int owner); // Constructor principal
~Bullet() = default; // Destructor ~Bullet() = default; // Destructor
// --- Métodos principales --- // --- Métodos principales ---
void render(); // Dibuja la bala en pantalla void render(); // Dibuja la bala en pantalla
auto update() -> BulletMoveStatus; // Actualiza el estado del objeto auto update(float deltaTime) -> MoveStatus; // Actualiza el estado del objeto (time-based)
void disable(); // Desactiva la bala void disable(); // Desactiva la bala
// --- Getters --- // --- Getters ---
[[nodiscard]] auto isEnabled() const -> bool; // Comprueba si está activa [[nodiscard]] auto isEnabled() const -> bool; // Comprueba si está activa
[[nodiscard]] auto getOwner() const -> Player::Id; // Devuelve el identificador del dueño [[nodiscard]] auto getOwner() const -> int; // Devuelve el identificador del dueño
auto getCollider() -> Circle&; // Devuelve el círculo de colisión auto getCollider() -> Circle&; // Devuelve el círculo de colisión
private: private:
// --- Constantes --- // --- Constantes ---
static constexpr float VEL_Y = -3.0F; // Velocidad vertical static constexpr float VEL_Y = -180.0F; // Velocidad vertical (pixels/segundo) - era -0.18F pixels/ms
static constexpr float VEL_X_LEFT = -2.0F; // Velocidad izquierda static constexpr float VEL_X_LEFT = -120.0F; // Velocidad izquierda (pixels/segundo) - era -0.12F pixels/ms
static constexpr float VEL_X_RIGHT = 2.0F; // Velocidad derecha static constexpr float VEL_X_RIGHT = 120.0F; // Velocidad derecha (pixels/segundo) - era 0.12F pixels/ms
static constexpr float VEL_X_CENTER = 0.0F; // Velocidad central static constexpr float VEL_X_CENTER = 0.0F; // Velocidad central
// --- Objetos y punteros --- // --- Objetos y punteros ---
@@ -55,8 +61,8 @@ class Bullet {
// --- Variables de estado --- // --- Variables de estado ---
Circle collider_; // Círculo de colisión Circle collider_; // Círculo de colisión
BulletType bullet_type_; // Tipo de bala Type type_; // Tipo de bala
Player::Id owner_; // Identificador del dueño int owner_; // Identificador del jugador
float pos_x_; // Posición en el eje X float pos_x_; // Posición en el eje X
float pos_y_; // Posición en el eje Y float pos_y_; // Posición en el eje Y
float vel_x_; // Velocidad en el eje X float vel_x_; // Velocidad en el eje X
@@ -64,7 +70,7 @@ class Bullet {
// --- Métodos internos --- // --- Métodos internos ---
void shiftColliders(); // Ajusta el círculo de colisión void shiftColliders(); // Ajusta el círculo de colisión
void shiftSprite(); // Ajusta el sprite void shiftSprite(); // Ajusta el sprite
auto move() -> BulletMoveStatus; // Mueve la bala y devuelve su estado auto move(float deltaTime) -> MoveStatus; // Mueve la bala y devuelve su estado (time-based)
static auto calculateVelocity(BulletType bullet_type) -> float; // Calcula la velocidad horizontal de la bala static auto calculateVelocity(Type 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 static auto buildAnimationString(Type type, Color color) -> std::string; // Construye el string de animación
}; };

View File

@@ -183,4 +183,4 @@ namespace Colors {
return result; return result;
} }
} } // namespace Colors

View File

@@ -36,10 +36,17 @@ struct Color {
Uint8 r, g, b, a; Uint8 r, g, b, a;
constexpr Color() : r(MIN_COLOR_VALUE), g(MIN_COLOR_VALUE), b(MIN_COLOR_VALUE), a(DEFAULT_ALPHA) {} constexpr Color()
: r(MIN_COLOR_VALUE),
g(MIN_COLOR_VALUE),
b(MIN_COLOR_VALUE),
a(DEFAULT_ALPHA) {}
explicit constexpr Color(Uint8 red, Uint8 green, Uint8 blue, Uint8 alpha = DEFAULT_ALPHA) explicit constexpr Color(Uint8 red, Uint8 green, Uint8 blue, Uint8 alpha = DEFAULT_ALPHA)
: r(red), g(green), b(blue), a(alpha) {} : r(red),
g(green),
b(blue),
a(alpha) {}
[[nodiscard]] constexpr auto INVERSE() const -> Color { [[nodiscard]] constexpr auto INVERSE() const -> Color {
return Color(MAX_COLOR_VALUE - r, MAX_COLOR_VALUE - g, MAX_COLOR_VALUE - b, a); return Color(MAX_COLOR_VALUE - r, MAX_COLOR_VALUE - g, MAX_COLOR_VALUE - b, a);
@@ -129,4 +136,4 @@ namespace Colors {
// --- Funciones --- // --- Funciones ---
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color; auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color;
auto generateMirroredCycle(Color base, ColorCycleStyle style = ColorCycleStyle::SUBTLE_PULSE) -> Cycle; auto generateMirroredCycle(Color base, ColorCycleStyle style = ColorCycleStyle::SUBTLE_PULSE) -> Cycle;
} } // namespace Colors

View File

@@ -58,7 +58,7 @@ constexpr int SKIP_COUNTDOWN_VALUE = 8;
// --- TITLE --- // --- TITLE ---
namespace Title { namespace Title {
constexpr int PRESS_START_POSITION = 180; constexpr int PRESS_START_POSITION = 180;
constexpr int DURATION = 800; constexpr float DURATION_S = 14.0F;
constexpr int ARCADE_EDITION_POSITION = 123; constexpr int ARCADE_EDITION_POSITION = 123;
constexpr int TITLE_C_C_POSITION = 80; constexpr int TITLE_C_C_POSITION = 80;
constexpr const char* BG_COLOR = "41526F"; constexpr const char* BG_COLOR = "41526F";
@@ -76,14 +76,16 @@ struct BalloonSettings {
float vel; float vel;
float grav; float grav;
constexpr BalloonSettings(float v, float g) constexpr BalloonSettings(float v, float g)
: vel(v), grav(g) {} : vel(v),
grav(g) {}
}; };
// Valores para deltaTime en segundos: vel en pixels/s, grav en pixels/s² (aceleración)
constexpr std::array<BalloonSettings, 4> SETTINGS = {{ constexpr std::array<BalloonSettings, 4> SETTINGS = {{
BalloonSettings(2.75F, 0.09F), // Globo 0 BalloonSettings(165.0F, 320.0F), // Globo 0: vel=165 pixels/s, grav=320 pixels/s²
BalloonSettings(3.70F, 0.10F), // Globo 1 BalloonSettings(222.0F, 360.0F), // Globo 1: vel=222 pixels/s, grav=360 pixels/s²
BalloonSettings(4.70F, 0.10F), // Globo 2 BalloonSettings(282.0F, 360.0F), // Globo 2: vel=282 pixels/s, grav=360 pixels/s²
BalloonSettings(5.45F, 0.10F) // Globo 3 BalloonSettings(327.0F, 360.0F) // Globo 3: vel=327 pixels/s, grav=360 pixels/s²
}}; }};
constexpr std::array<const char*, 4> COLORS = { constexpr std::array<const char*, 4> COLORS = {

View File

@@ -39,22 +39,22 @@ void DefineButtons::render() {
} }
} }
void DefineButtons::update() { void DefineButtons::update(float delta_time) {
if (!enabled_) { if (!enabled_) {
return; return;
} }
// Actualizar la ventana siempre // Actualizar la ventana siempre
if (window_message_) { if (window_message_) {
window_message_->update(); window_message_->update(delta_time);
} }
// Manejar la secuencia de cierre si ya terminamos // Manejar la secuencia de cierre si ya terminamos
if (finished_ && message_shown_) { if (finished_ && message_shown_) {
message_timer_++; message_timer_ += delta_time;
// Después del delay, iniciar animación de cierre (solo una vez) // Después del delay, iniciar animación de cierre (solo una vez)
if (message_timer_ > MESSAGE_DISPLAY_FRAMES && !closing_) { if (message_timer_ >= MESSAGE_DISPLAY_DURATION_S && !closing_) {
if (window_message_) { if (window_message_) {
window_message_->hide(); // Iniciar animación de cierre window_message_->hide(); // Iniciar animación de cierre
} }
@@ -234,7 +234,7 @@ void DefineButtons::checkEnd() {
// Solo marcar que ya mostramos el mensaje // Solo marcar que ya mostramos el mensaje
message_shown_ = true; message_shown_ = true;
message_timer_ = 0; message_timer_ = 0.0f;
} }
} }

View File

@@ -25,7 +25,9 @@ class DefineButtons {
int button; int button;
Button(std::string label, Input::Action action, int button) Button(std::string label, Input::Action action, int button)
: label(std::move(label)), action(action), button(button) {} : label(std::move(label)),
action(action),
button(button) {}
}; };
// --- Constructor y destructor --- // --- Constructor y destructor ---
@@ -34,7 +36,7 @@ class DefineButtons {
// --- Métodos principales --- // --- Métodos principales ---
void render(); void render();
void update(); void update(float delta_time);
void handleEvents(const SDL_Event &event); void handleEvents(const SDL_Event &event);
auto enable(Options::Gamepad *options_gamepad) -> bool; auto enable(Options::Gamepad *options_gamepad) -> bool;
void disable(); void disable();
@@ -46,7 +48,7 @@ class DefineButtons {
private: private:
// --- Constantes --- // --- Constantes ---
static constexpr size_t MESSAGE_DISPLAY_FRAMES = 120; // Cuánto tiempo mostrar el mensaje (en frames) ~2 segundos a 60fps static constexpr float MESSAGE_DISPLAY_DURATION_S = 2.0f; // Cuánto tiempo mostrar el mensaje en segundos
// --- Objetos y punteros --- // --- Objetos y punteros ---
Input *input_ = nullptr; // Entrada del usuario Input *input_ = nullptr; // Entrada del usuario
@@ -57,7 +59,7 @@ class DefineButtons {
std::vector<Button> buttons_; // Lista de botones std::vector<Button> buttons_; // Lista de botones
std::vector<std::string> controller_names_; // Nombres de los controladores std::vector<std::string> controller_names_; // Nombres de los controladores
size_t index_button_ = 0; // Índice del botón seleccionado size_t index_button_ = 0; // Índice del botón seleccionado
size_t message_timer_ = 0; // Contador de frames para el mensaje float message_timer_ = 0.0f; // Timer en segundos para el mensaje
bool enabled_ = false; // Flag para indicar si está activo bool enabled_ = false; // Flag para indicar si está activo
bool finished_ = false; // Flag para indicar si ha terminado bool finished_ = false; // Flag para indicar si ha terminado
bool closing_ = false; // Flag para indicar que está cerrando bool closing_ = false; // Flag para indicar que está cerrando

View File

@@ -20,6 +20,7 @@
#include "param.h" // Para loadParamsFromFile #include "param.h" // Para loadParamsFromFile
#include "player.h" // Para Player #include "player.h" // Para Player
#include "resource.h" // Para Resource #include "resource.h" // Para Resource
#include "resource_helper.h" // Para ResourceHelper
#include "screen.h" // Para Screen #include "screen.h" // Para Screen
#include "section.hpp" // Para Name, Options, name, options, AttractMode, attract_mode #include "section.hpp" // Para Name, Options, name, options, AttractMode, attract_mode
#include "sections/credits.h" // Para Credits #include "sections/credits.h" // Para Credits
@@ -77,6 +78,12 @@ Director::~Director() {
void Director::init() { void Director::init() {
// Configuración inicial de parametros // Configuración inicial de parametros
Asset::init(executable_path_); // Inicializa el sistema de gestión de archivos Asset::init(executable_path_); // Inicializa el sistema de gestión de archivos
#ifdef MACOS_BUNDLE
ResourceHelper::initializeResourceSystem(executable_path_ + "../Resources/resources.pack");
#else
ResourceHelper::initializeResourceSystem(executable_path_ + "resources.pack");
#endif
loadAssets(); // Crea el índice de archivos loadAssets(); // Crea el índice de archivos
Input::init(Asset::get()->get("gamecontrollerdb.txt"), Asset::get()->get("controllers.json")); // Carga configuración de controles Input::init(Asset::get()->get("gamecontrollerdb.txt"), Asset::get()->get("controllers.json")); // Carga configuración de controles
Options::setConfigFile(Asset::get()->get("config.txt")); // Establece el fichero de configuración Options::setConfigFile(Asset::get()->get("config.txt")); // Establece el fichero de configuración
@@ -154,7 +161,7 @@ void Director::loadAssets() {
#endif #endif
// Cargar la configuración de assets (también aplicar el prefijo al archivo de configuración) // Cargar la configuración de assets (también aplicar el prefijo al archivo de configuración)
std::string config_path = executable_path_ + PREFIX + "/data/config/assets.txt"; std::string config_path = executable_path_ + PREFIX + "/config/assets.txt";
Asset::get()->loadFromFile(config_path, PREFIX, system_folder_); Asset::get()->loadFromFile(config_path, PREFIX, system_folder_);
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Assets configuration loaded successfully"); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Assets configuration loaded successfully");
@@ -167,8 +174,14 @@ void Director::loadAssets() {
// Comprueba los parametros del programa // Comprueba los parametros del programa
void Director::checkProgramArguments(int argc, std::span<char *> argv) { void Director::checkProgramArguments(int argc, std::span<char *> argv) {
// Establece la ruta del programa // Obtener la ruta absoluta del ejecutable
executable_path_ = getPath(argv[0]); std::filesystem::path exe_path = std::filesystem::absolute(argv[0]);
executable_path_ = exe_path.parent_path().string();
// Asegurar que termine con separador de directorio
if (!executable_path_.empty() && executable_path_.back() != '/' && executable_path_.back() != '\\') {
executable_path_ += "/";
}
// Comprueba el resto de parámetros // Comprueba el resto de parámetros
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {

View File

@@ -45,7 +45,10 @@ void EnterName::incPosition() {
} else if (position_ > 0) // No es necesario verificar position_ < MAX_NAME_LENGTH } else if (position_ > 0) // No es necesario verificar position_ < MAX_NAME_LENGTH
{ {
// Copiamos el índice del carácter anterior si es posible. // Copiamos el índice del carácter anterior si es posible.
character_index_[position_] = character_index_[position_ - 1]; // character_index_[position_] = character_index_[position_ - 1];
// Ponemos el caracter "espacio"
character_index_[position_] = 0;
} else { } else {
// Si position_ es 0, inicializamos el carácter actual. // Si position_ es 0, inicializamos el carácter actual.
character_index_[position_] = 0; character_index_[position_] = 0;
@@ -144,12 +147,19 @@ auto EnterName::findIndex(char character) const -> int {
// Devuelve un nombre al azar // Devuelve un nombre al azar
auto EnterName::getRandomName() -> std::string { auto EnterName::getRandomName() -> std::string {
static constexpr std::array<std::string_view, 8> NAMES = { static constexpr std::array<std::string_view, 8> NAMES = {
"BAL1", "TABE", "DOC", "MON", "SAM1", "JORDI", "JDES", "PEPE"}; "BAL1",
"TABE",
"DOC",
"MON",
"SAM1",
"JORDI",
"JDES",
"PEPE"};
return std::string(NAMES[rand() % NAMES.size()]); return std::string(NAMES[rand() % NAMES.size()]);
} }
// Obtiene el nombre final introducido // Obtiene el nombre final introducido
auto EnterName::getFinalName() -> std::string { auto EnterName::getFinalName() -> std::string {
auto name = trim(name_.substr(0, position_)); auto name = trim(name_.substr(0, position_ + 1)); // Devuelve el texto intruducido incluyendo el del selector
if (name.empty()) { if (name.empty()) {
name = getRandomName(); name = getRandomName();
} }

View File

@@ -6,10 +6,10 @@
class Texture; // lines 4-4 class Texture; // lines 4-4
// Actualiza la lógica de la clase // Actualiza la lógica de la clase (time-based)
void Explosions::update() { void Explosions::update(float deltaTime) {
for (auto &explosion : explosions_) { for (auto &explosion : explosions_) {
explosion->update(); explosion->update(deltaTime);
} }
// Vacia el vector de elementos finalizados // Vacia el vector de elementos finalizados

View File

@@ -16,7 +16,9 @@ struct ExplosionTexture {
std::vector<std::string> animation; // Animación para la textura std::vector<std::string> animation; // Animación para la textura
ExplosionTexture(int sz, std::shared_ptr<Texture> tex, const std::vector<std::string> &anim) ExplosionTexture(int sz, std::shared_ptr<Texture> tex, const std::vector<std::string> &anim)
: size(sz), texture(std::move(tex)), animation(anim) {} : size(sz),
texture(std::move(tex)),
animation(anim) {}
}; };
// --- Clase Explosions: gestor de explosiones --- // --- Clase Explosions: gestor de explosiones ---
@@ -27,7 +29,7 @@ class Explosions {
~Explosions() = default; // Destructor por defecto ~Explosions() = default; // Destructor por defecto
// --- Métodos principales --- // --- Métodos principales ---
void update(); // Actualiza la lógica de la clase void update(float deltaTime); // Actualiza la lógica de la clase (time-based)
void render(); // Dibuja el objeto en pantalla void render(); // Dibuja el objeto en pantalla
// --- Configuración --- // --- Configuración ---

View File

@@ -82,6 +82,11 @@ void Fade::update() {
} }
} }
// Compatibilidad delta-time (ignora el parámetro ya que usa SDL_GetTicks)
void Fade::update(float delta_time) {
update(); // Llama al método original
}
void Fade::updatePreState() { void Fade::updatePreState() {
// Sistema basado en tiempo únicamente // Sistema basado en tiempo únicamente
Uint32 elapsed_time = SDL_GetTicks() - pre_start_time_; Uint32 elapsed_time = SDL_GetTicks() - pre_start_time_;

View File

@@ -39,7 +39,8 @@ class Fade {
// --- Métodos principales --- // --- Métodos principales ---
void reset(); // Resetea variables para reutilizar el fade void reset(); // Resetea variables para reutilizar el fade
void render(); // Dibuja la transición en pantalla void render(); // Dibuja la transición en pantalla
void update(); // Actualiza el estado interno void update(); // Actualiza el estado interno (ya usa tiempo real)
void update(float delta_time); // Compatibilidad delta-time (ignora el parámetro)
void activate(); // Activa el fade void activate(); // Activa el fade
// --- Configuración --- // --- Configuración ---
@@ -47,8 +48,8 @@ class Fade {
void setColor(Color color); // Establece el color del fade void setColor(Color color); // Establece el color del fade
void setType(Type type) { type_ = type; } // Establece el tipo de fade void setType(Type type) { type_ = type; } // Establece el tipo de fade
void setMode(Mode mode) { mode_ = mode; } // Establece el modo 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 setPostDuration(int milliseconds) { post_duration_ = milliseconds; } // Duración posterior al fade en milisegundos
void setPreDuration(int value) { pre_duration_ = value; } // Duración previa al fade en milisegundos void setPreDuration(int milliseconds) { pre_duration_ = milliseconds; } // Duración previa al fade en milisegundos
// --- Getters --- // --- Getters ---
[[nodiscard]] auto getValue() const -> int { return value_; } [[nodiscard]] auto getValue() const -> int { return value_; }

View File

@@ -15,8 +15,9 @@
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
constexpr int ZOOM_FACTOR = 5; constexpr int ZOOM_FACTOR = 5;
constexpr int FLASH_DELAY = 3; constexpr float FLASH_DELAY_S = 0.05f; // 3 frames → 0.05s
constexpr int FLASH_LENGTH = FLASH_DELAY + 3; constexpr float FLASH_DURATION_S = 0.1f; // 6 frames → 0.1s (3 + 3)
constexpr Color FLASH_COLOR = Color(0xFF, 0xFF, 0xFF); // Color blanco para el flash
// Constructor // Constructor
GameLogo::GameLogo(int x, int y) GameLogo::GameLogo(int x, int y)
@@ -45,6 +46,7 @@ void GameLogo::init() {
arcade_edition_status_ = Status::DISABLED; arcade_edition_status_ = Status::DISABLED;
shake_.init(1, 2, 8, XP); shake_.init(1, 2, 8, XP);
zoom_ = 3.0F * ZOOM_FACTOR; zoom_ = 3.0F * ZOOM_FACTOR;
post_finished_timer_ = 0.0f;
// Inicializa el bitmap de 'Coffee' // Inicializa el bitmap de 'Coffee'
coffee_sprite_->setPosX(XP); coffee_sprite_->setPosX(XP);
@@ -52,44 +54,44 @@ void GameLogo::init() {
coffee_sprite_->setWidth(coffee_texture_->getWidth()); coffee_sprite_->setWidth(coffee_texture_->getWidth());
coffee_sprite_->setHeight(coffee_texture_->getHeight()); coffee_sprite_->setHeight(coffee_texture_->getHeight());
coffee_sprite_->setVelX(0.0F); coffee_sprite_->setVelX(0.0F);
coffee_sprite_->setVelY(2.5F); coffee_sprite_->setVelY(COFFEE_VEL_Y);
coffee_sprite_->setAccelX(0.0F); coffee_sprite_->setAccelX(0.0F);
coffee_sprite_->setAccelY(0.1F); coffee_sprite_->setAccelY(COFFEE_ACCEL_Y);
coffee_sprite_->setSpriteClip(0, 0, coffee_texture_->getWidth(), coffee_texture_->getHeight()); coffee_sprite_->setSpriteClip(0, 0, coffee_texture_->getWidth(), coffee_texture_->getHeight());
coffee_sprite_->setEnabled(true); coffee_sprite_->setEnabled(true);
coffee_sprite_->setFinishedCounter(0); coffee_sprite_->setFinishedDelay(0.0f);
coffee_sprite_->setDestX(XP); coffee_sprite_->setDestX(XP);
coffee_sprite_->setDestY(y_ - coffee_texture_->getHeight()); coffee_sprite_->setDestY(y_ - coffee_texture_->getHeight());
// Inicializa el bitmap de 'Crisis' // Inicializa el bitmap de 'Crisis'
crisis_sprite_->setPosX(XP + 15); crisis_sprite_->setPosX(XP + CRISIS_OFFSET_X);
crisis_sprite_->setPosY(y_ + DESP); crisis_sprite_->setPosY(y_ + DESP);
crisis_sprite_->setWidth(crisis_texture_->getWidth()); crisis_sprite_->setWidth(crisis_texture_->getWidth());
crisis_sprite_->setHeight(crisis_texture_->getHeight()); crisis_sprite_->setHeight(crisis_texture_->getHeight());
crisis_sprite_->setVelX(0.0F); crisis_sprite_->setVelX(0.0F);
crisis_sprite_->setVelY(-2.5F); crisis_sprite_->setVelY(CRISIS_VEL_Y);
crisis_sprite_->setAccelX(0.0F); crisis_sprite_->setAccelX(0.0F);
crisis_sprite_->setAccelY(-0.1F); crisis_sprite_->setAccelY(CRISIS_ACCEL_Y);
crisis_sprite_->setSpriteClip(0, 0, crisis_texture_->getWidth(), crisis_texture_->getHeight()); crisis_sprite_->setSpriteClip(0, 0, crisis_texture_->getWidth(), crisis_texture_->getHeight());
crisis_sprite_->setEnabled(true); crisis_sprite_->setEnabled(true);
crisis_sprite_->setFinishedCounter(0); crisis_sprite_->setFinishedDelay(0.0f);
crisis_sprite_->setDestX(XP + 15); crisis_sprite_->setDestX(XP + CRISIS_OFFSET_X);
crisis_sprite_->setDestY(y_); crisis_sprite_->setDestY(y_);
// Inicializa el bitmap de 'DustRight' // Inicializa el bitmap de 'DustRight'
dust_right_sprite_->resetAnimation(); dust_right_sprite_->resetAnimation();
dust_right_sprite_->setPosX(coffee_sprite_->getPosX() + coffee_sprite_->getWidth()); dust_right_sprite_->setPosX(coffee_sprite_->getPosX() + coffee_sprite_->getWidth());
dust_right_sprite_->setPosY(y_); dust_right_sprite_->setPosY(y_);
dust_right_sprite_->setWidth(16); dust_right_sprite_->setWidth(DUST_SIZE);
dust_right_sprite_->setHeight(16); dust_right_sprite_->setHeight(DUST_SIZE);
dust_right_sprite_->setFlip(SDL_FLIP_HORIZONTAL); dust_right_sprite_->setFlip(SDL_FLIP_HORIZONTAL);
// Inicializa el bitmap de 'DustLeft' // Inicializa el bitmap de 'DustLeft'
dust_left_sprite_->resetAnimation(); dust_left_sprite_->resetAnimation();
dust_left_sprite_->setPosX(coffee_sprite_->getPosX() - 16); dust_left_sprite_->setPosX(coffee_sprite_->getPosX() - DUST_SIZE);
dust_left_sprite_->setPosY(y_); dust_left_sprite_->setPosY(y_);
dust_left_sprite_->setWidth(16); dust_left_sprite_->setWidth(DUST_SIZE);
dust_left_sprite_->setHeight(16); dust_left_sprite_->setHeight(DUST_SIZE);
// Inicializa el bitmap de 'Arcade Edition' // Inicializa el bitmap de 'Arcade Edition'
arcade_edition_sprite_->setZoom(zoom_); arcade_edition_sprite_->setZoom(zoom_);
@@ -112,45 +114,45 @@ void GameLogo::render() {
} }
} }
// Actualiza la lógica de la clase // Actualiza la lógica de la clase (time-based)
void GameLogo::update() { void GameLogo::update(float deltaTime) {
updateCoffeeCrisis(); updateCoffeeCrisis(deltaTime);
updateArcadeEdition(); updateArcadeEdition(deltaTime);
updatePostFinishedCounter(); updatePostFinishedCounter(deltaTime);
} }
void GameLogo::updateCoffeeCrisis() { void GameLogo::updateCoffeeCrisis(float deltaTime) {
switch (coffee_crisis_status_) { switch (coffee_crisis_status_) {
case Status::MOVING: case Status::MOVING:
handleCoffeeCrisisMoving(); handleCoffeeCrisisMoving(deltaTime);
break; break;
case Status::SHAKING: case Status::SHAKING:
handleCoffeeCrisisShaking(); handleCoffeeCrisisShaking(deltaTime);
break; break;
case Status::FINISHED: case Status::FINISHED:
handleCoffeeCrisisFinished(); handleCoffeeCrisisFinished(deltaTime);
break; break;
default: default:
break; break;
} }
} }
void GameLogo::updateArcadeEdition() { void GameLogo::updateArcadeEdition(float deltaTime) {
switch (arcade_edition_status_) { switch (arcade_edition_status_) {
case Status::MOVING: case Status::MOVING:
handleArcadeEditionMoving(); handleArcadeEditionMoving(deltaTime);
break; break;
case Status::SHAKING: case Status::SHAKING:
handleArcadeEditionShaking(); handleArcadeEditionShaking(deltaTime);
break; break;
default: default:
break; break;
} }
} }
void GameLogo::handleCoffeeCrisisMoving() { void GameLogo::handleCoffeeCrisisMoving(float deltaTime) {
coffee_sprite_->update(); coffee_sprite_->update(deltaTime);
crisis_sprite_->update(); crisis_sprite_->update(deltaTime);
if (coffee_sprite_->hasFinished() && crisis_sprite_->hasFinished()) { if (coffee_sprite_->hasFinished() && crisis_sprite_->hasFinished()) {
coffee_crisis_status_ = Status::SHAKING; coffee_crisis_status_ = Status::SHAKING;
@@ -158,22 +160,23 @@ void GameLogo::handleCoffeeCrisisMoving() {
} }
} }
void GameLogo::handleCoffeeCrisisShaking() { void GameLogo::handleCoffeeCrisisShaking(float deltaTime) {
if (shake_.remaining > 0) { if (shake_.remaining > 0) {
processShakeEffect(coffee_sprite_.get(), crisis_sprite_.get()); processShakeEffect(coffee_sprite_.get(), crisis_sprite_.get(), deltaTime);
} else { } else {
finishCoffeeCrisisShaking(); finishCoffeeCrisisShaking();
} }
updateDustSprites(); updateDustSprites(deltaTime);
} }
void GameLogo::handleCoffeeCrisisFinished() { void GameLogo::handleCoffeeCrisisFinished(float deltaTime) {
updateDustSprites(); updateDustSprites(deltaTime);
} }
void GameLogo::handleArcadeEditionMoving() { void GameLogo::handleArcadeEditionMoving(float deltaTime) {
zoom_ -= 0.1F * ZOOM_FACTOR; // DeltaTime en segundos: decremento por segundo
zoom_ -= (ZOOM_DECREMENT_PER_S * ZOOM_FACTOR) * deltaTime;
arcade_edition_sprite_->setZoom(zoom_); arcade_edition_sprite_->setZoom(zoom_);
if (zoom_ <= 1.0F) { if (zoom_ <= 1.0F) {
@@ -181,34 +184,38 @@ void GameLogo::handleArcadeEditionMoving() {
} }
} }
void GameLogo::handleArcadeEditionShaking() { void GameLogo::handleArcadeEditionShaking(float deltaTime) {
if (shake_.remaining > 0) { if (shake_.remaining > 0) {
processArcadeEditionShake(); processArcadeEditionShake(deltaTime);
} else { } else {
arcade_edition_sprite_->setX(shake_.origin); arcade_edition_sprite_->setX(shake_.origin);
arcade_edition_status_ = Status::FINISHED; arcade_edition_status_ = Status::FINISHED;
} }
} }
void GameLogo::processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite) {
if (shake_.counter > 0) { void GameLogo::processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite, float deltaTime) {
shake_.counter--; shake_.time_accumulator += deltaTime;
} else {
shake_.counter = shake_.delay; if (shake_.time_accumulator >= SHAKE_DELAY_S) {
shake_.time_accumulator -= SHAKE_DELAY_S;
const auto DISPLACEMENT = calculateShakeDisplacement(); const auto DISPLACEMENT = calculateShakeDisplacement();
primary_sprite->setPosX(shake_.origin + DISPLACEMENT); primary_sprite->setPosX(shake_.origin + DISPLACEMENT);
if (secondary_sprite != nullptr) { if (secondary_sprite != nullptr) {
secondary_sprite->setPosX(shake_.origin + DISPLACEMENT + 15); secondary_sprite->setPosX(shake_.origin + DISPLACEMENT + CRISIS_OFFSET_X);
} }
shake_.remaining--; shake_.remaining--;
} }
} }
void GameLogo::processArcadeEditionShake() { void GameLogo::processArcadeEditionShake(float deltaTime) {
if (shake_.counter > 0) { // Delay fijo en segundos (shake_.delay era frames, ahora usamos constante)
shake_.counter--; float delayTime = SHAKE_DELAY_S;
} else {
shake_.counter = shake_.delay; shake_.time_accumulator += deltaTime;
if (shake_.time_accumulator >= delayTime) {
shake_.time_accumulator -= delayTime;
const auto DISPLACEMENT = calculateShakeDisplacement(); const auto DISPLACEMENT = calculateShakeDisplacement();
arcade_edition_sprite_->setX(shake_.origin + DISPLACEMENT); arcade_edition_sprite_->setX(shake_.origin + DISPLACEMENT);
shake_.remaining--; shake_.remaining--;
@@ -221,7 +228,7 @@ auto GameLogo::calculateShakeDisplacement() const -> int {
void GameLogo::finishCoffeeCrisisShaking() { void GameLogo::finishCoffeeCrisisShaking() {
coffee_sprite_->setPosX(shake_.origin); coffee_sprite_->setPosX(shake_.origin);
crisis_sprite_->setPosX(shake_.origin + 15); crisis_sprite_->setPosX(shake_.origin + CRISIS_OFFSET_X);
coffee_crisis_status_ = Status::FINISHED; coffee_crisis_status_ = Status::FINISHED;
arcade_edition_status_ = Status::MOVING; arcade_edition_status_ = Status::MOVING;
} }
@@ -236,20 +243,20 @@ void GameLogo::finishArcadeEditionMoving() {
void GameLogo::playTitleEffects() { void GameLogo::playTitleEffects() {
Audio::get()->playSound("title.wav"); Audio::get()->playSound("title.wav");
Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGTH, FLASH_DELAY); Screen::get()->flash(FLASH_COLOR, FLASH_DURATION_S, FLASH_DELAY_S);
Screen::get()->shake(); Screen::get()->shake();
} }
void GameLogo::updateDustSprites() { void GameLogo::updateDustSprites(float deltaTime) {
dust_right_sprite_->update(); dust_right_sprite_->update(deltaTime);
dust_left_sprite_->update(); dust_left_sprite_->update(deltaTime);
} }
void GameLogo::updatePostFinishedCounter() { void GameLogo::updatePostFinishedCounter(float deltaTime) {
if (coffee_crisis_status_ == Status::FINISHED && if (coffee_crisis_status_ == Status::FINISHED &&
arcade_edition_status_ == Status::FINISHED && arcade_edition_status_ == Status::FINISHED) {
post_finished_counter_ > 0) {
--post_finished_counter_; post_finished_timer_ += deltaTime;
} }
} }
@@ -261,7 +268,7 @@ void GameLogo::enable() {
// Indica si ha terminado la animación // Indica si ha terminado la animación
auto GameLogo::hasFinished() const -> bool { auto GameLogo::hasFinished() const -> bool {
return post_finished_counter_ == 0; return post_finished_timer_ >= post_finished_delay_s_;
} }
// Calcula el desplazamiento vertical inicial // Calcula el desplazamiento vertical inicial

View File

@@ -11,13 +11,24 @@ class Texture;
// --- Clase GameLogo: gestor del logo del juego --- // --- Clase GameLogo: gestor del logo del juego ---
class GameLogo { class GameLogo {
public: public:
// --- Constantes ---
static constexpr float COFFEE_VEL_Y = 0.15F * 1000.0F; // Velocidad Y de coffee sprite (pixels/s) - 0.15F * 1000 = 150 pixels/s
static constexpr float COFFEE_ACCEL_Y = 0.00036F * 1000000.0F; // Aceleración Y de coffee sprite (pixels/s²) - 0.00036F * 1000000 = 360 pixels/s²
static constexpr float CRISIS_VEL_Y = -0.15F * 1000.0F; // Velocidad Y de crisis sprite (pixels/s) - -0.15F * 1000 = -150 pixels/s
static constexpr float CRISIS_ACCEL_Y = -0.00036F * 1000000.0F; // Aceleración Y de crisis sprite (pixels/s²) - -0.00036F * 1000000 = -360 pixels/s²
static constexpr int CRISIS_OFFSET_X = 15; // Desplazamiento X de crisis sprite
static constexpr int DUST_SIZE = 16; // Tamaño de dust sprites
static constexpr float ZOOM_DECREMENT_PER_S = 0.006F * 1000.0F; // Decremento de zoom por segundo (0.006F * 1000 = 6.0F per second)
static constexpr float SHAKE_DELAY_S = 33.34F / 1000.0F; // Delay de shake en segundos (33.34ms / 1000 = 0.03334s)
static constexpr float POST_FINISHED_FRAME_TIME_S = 16.67F / 1000.0F; // Tiempo entre decrementos del counter (16.67ms / 1000 = 0.01667s)
// --- Constructores y destructor --- // --- Constructores y destructor ---
GameLogo(int x, int y); GameLogo(int x, int y);
~GameLogo() = default; ~GameLogo() = default;
// --- Métodos principales --- // --- Métodos principales ---
void render(); // Pinta la clase en pantalla void render(); // Pinta la clase en pantalla
void update(); // Actualiza la lógica de la clase void update(float deltaTime); // Actualiza la lógica de la clase (time-based)
void enable(); // Activa la clase void enable(); // Activa la clase
// --- Getters --- // --- Getters ---
@@ -35,15 +46,21 @@ class GameLogo {
// --- Estructuras privadas --- // --- Estructuras privadas ---
struct Shake { struct Shake {
int desp = 1; // Pixels de desplazamiento para agitar la pantalla en el eje x int desp = 1; // Pixels de desplazamiento para agitar la pantalla en el eje x
int delay = 2; // Retraso entre cada desplazamiento de la pantalla al agitarse int delay = 2; // Retraso entre cada desplazamiento de la pantalla al agitarse (frame-based)
int length = 8; // Cantidad de desplazamientos a realizar int length = 8; // Cantidad de desplazamientos a realizar
int remaining = length; // Cantidad de desplazamientos pendientes a realizar int remaining = length; // Cantidad de desplazamientos pendientes a realizar
int counter = delay; // Contador para el retraso int counter = delay; // Contador para el retraso (frame-based)
float time_accumulator = 0.0f; // Acumulador de tiempo para deltaTime
int origin = 0; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento int origin = 0; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
Shake() = default; Shake() = default;
Shake(int d, int de, int l, int o) Shake(int d, int de, int l, int o)
: desp(d), delay(de), length(l), remaining(l), counter(de), origin(o) {} : desp(d),
delay(de),
length(l),
remaining(l),
counter(de),
origin(o) {}
void init(int d, int de, int l, int o) { void init(int d, int de, int l, int o) {
desp = d; desp = d;
@@ -51,6 +68,7 @@ class GameLogo {
length = l; length = l;
remaining = l; remaining = l;
counter = de; counter = de;
time_accumulator = 0.0f;
origin = o; origin = o;
} }
}; };
@@ -74,32 +92,34 @@ class GameLogo {
float x_; // Posición X del logo float x_; // Posición X del logo
float y_; // Posición Y del logo float y_; // Posición Y del logo
float zoom_ = 1.0F; // Zoom aplicado al texto "ARCADE EDITION" float zoom_ = 1.0F; // Zoom aplicado al texto "ARCADE EDITION"
int post_finished_counter_ = 1; // Contador final tras animaciones float post_finished_delay_s_ = POST_FINISHED_FRAME_TIME_S; // Retraso final tras animaciones (s)
float post_finished_timer_ = 0.0f; // Timer acumulado para retraso final (s)
// --- Inicialización --- // --- Inicialización ---
void init(); // Inicializa las variables void init(); // Inicializa las variables
[[nodiscard]] auto getInitialVerticalDesp() const -> int; // Calcula el desplazamiento vertical inicial [[nodiscard]] auto getInitialVerticalDesp() const -> int; // Calcula el desplazamiento vertical inicial
// --- Actualización de estados específicos --- // --- Actualización de estados específicos ---
void updateCoffeeCrisis(); // Actualiza el estado de "Coffee Crisis" void updateCoffeeCrisis(float deltaTime); // Actualiza el estado de "Coffee Crisis" (time-based)
void updateArcadeEdition(); // Actualiza el estado de "Arcade Edition" void updateArcadeEdition(float deltaTime); // Actualiza el estado de "Arcade Edition" (time-based)
void updatePostFinishedCounter(); // Actualiza el contador tras finalizar una animación void updatePostFinishedCounter(float deltaTime); // Actualiza el contador tras finalizar una animación (time-based)
// --- Efectos visuales: movimiento y sacudidas --- // --- Efectos visuales: movimiento y sacudidas ---
void handleCoffeeCrisisMoving(); // Maneja el movimiento de "Coffee Crisis" void handleCoffeeCrisisMoving(float deltaTime); // Maneja el movimiento de "Coffee Crisis" (time-based)
void handleCoffeeCrisisShaking(); // Maneja la sacudida de "Coffee Crisis" void handleCoffeeCrisisShaking(float deltaTime); // Maneja la sacudida de "Coffee Crisis" (time-based)
void handleArcadeEditionMoving(); // Maneja el movimiento de "Arcade Edition" void handleArcadeEditionMoving(float deltaTime); // Maneja el movimiento de "Arcade Edition" (time-based)
void handleArcadeEditionShaking(); // Maneja la sacudida de "Arcade Edition" void handleArcadeEditionShaking(float deltaTime); // Maneja la sacudida de "Arcade Edition" (time-based)
void processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite = nullptr); // Procesa el efecto de sacudida en sprites void processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite = nullptr); // Procesa el efecto de sacudida en sprites (frame-based)
void processArcadeEditionShake(); // Procesa la sacudida específica de "Arcade Edition" void processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite, float deltaTime); // Procesa el efecto de sacudida en sprites (time-based)
void processArcadeEditionShake(float deltaTime); // Procesa la sacudida específica de "Arcade Edition" (time-based)
[[nodiscard]] auto calculateShakeDisplacement() const -> int; // Calcula el desplazamiento de la sacudida [[nodiscard]] auto calculateShakeDisplacement() const -> int; // Calcula el desplazamiento de la sacudida
// --- Gestión de finalización de efectos --- // --- Gestión de finalización de efectos ---
void handleCoffeeCrisisFinished(); // Maneja el final de la animación "Coffee Crisis" void handleCoffeeCrisisFinished(float deltaTime); // Maneja el final de la animación "Coffee Crisis" (time-based)
void finishCoffeeCrisisShaking(); // Finaliza la sacudida de "Coffee Crisis" void finishCoffeeCrisisShaking(); // Finaliza la sacudida de "Coffee Crisis"
void finishArcadeEditionMoving(); // Finaliza el movimiento de "Arcade Edition" void finishArcadeEditionMoving(); // Finaliza el movimiento de "Arcade Edition"
// --- Utilidades --- // --- Utilidades ---
static void playTitleEffects(); // Reproduce efectos visuales/sonoros del título static void playTitleEffects(); // Reproduce efectos visuales/sonoros del título
void updateDustSprites(); // Actualiza los sprites de polvo void updateDustSprites(float deltaTime); // Actualiza los sprites de polvo (time-based)
}; };

View File

@@ -32,7 +32,9 @@ class Input {
bool just_pressed; // Se acaba de pulsar en este fotograma bool just_pressed; // Se acaba de pulsar en este fotograma
KeyState(Uint8 scancode = 0, bool is_held = false, bool just_pressed = false) KeyState(Uint8 scancode = 0, bool is_held = false, bool just_pressed = false)
: scancode(scancode), is_held(is_held), just_pressed(just_pressed) {} : scancode(scancode),
is_held(is_held),
just_pressed(just_pressed) {}
}; };
struct ButtonState { struct ButtonState {
@@ -43,7 +45,10 @@ class Input {
bool trigger_active{false}; // Estado del trigger como botón digital bool trigger_active{false}; // Estado del trigger como botón digital
ButtonState(int btn = static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID), bool is_held = false, bool just_pressed = false, bool axis_act = false) ButtonState(int btn = static_cast<int>(SDL_GAMEPAD_BUTTON_INVALID), bool is_held = false, bool just_pressed = false, bool axis_act = false)
: button(btn), is_held(is_held), just_pressed(just_pressed), axis_active(axis_act) {} : button(btn),
is_held(is_held),
just_pressed(just_pressed),
axis_active(axis_act) {}
}; };
struct Keyboard { struct Keyboard {

View File

@@ -1,6 +1,7 @@
#include "item.h" #include "item.h"
#include <algorithm> // Para clamp #include <algorithm> // Para clamp
#include <cmath> // Para fmod
#include <cstdlib> // Para rand #include <cstdlib> // Para rand
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
@@ -9,16 +10,18 @@
class Texture; // lines 6-6 class Texture; // lines 6-6
Item::Item(ItemType type, float x, float y, SDL_FRect &play_area, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation) Item::Item(ItemType type, float x, float y, SDL_FRect &play_area, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation)
: sprite_(std::make_unique<AnimatedSprite>(texture, animation)), play_area_(play_area), type_(type) { : sprite_(std::make_unique<AnimatedSprite>(texture, animation)),
play_area_(play_area),
type_(type) {
switch (type) { switch (type) {
case ItemType::COFFEE_MACHINE: { case ItemType::COFFEE_MACHINE: {
width_ = COFFEE_MACHINE_WIDTH; width_ = COFFEE_MACHINE_WIDTH;
height_ = COFFEE_MACHINE_HEIGHT; height_ = COFFEE_MACHINE_HEIGHT;
pos_x_ = getCoffeeMachineSpawn(x, width_, play_area_.w); pos_x_ = getCoffeeMachineSpawn(x, width_, play_area_.w);
pos_y_ = y; pos_y_ = y;
vel_x_ = ((rand() % 3) - 1) * 0.5F; vel_x_ = ((rand() % 3) - 1) * COFFEE_MACHINE_VEL_X_FACTOR;
vel_y_ = -0.1F; vel_y_ = COFFEE_MACHINE_VEL_Y;
accel_y_ = 0.1F; accel_y_ = COFFEE_MACHINE_ACCEL_Y;
collider_.r = 10; collider_.r = 10;
break; break;
} }
@@ -31,13 +34,13 @@ Item::Item(ItemType type, float x, float y, SDL_FRect &play_area, const std::sha
const int direction = rand() % 6; const int direction = rand() % 6;
if (direction < 3) { if (direction < 3) {
// Velocidades negativas: -1.0, -0.66, -0.33 // Velocidades negativas: -1.0, -0.66, -0.33
vel_x_ = -1.0F + (direction * 0.33F); vel_x_ = -ITEM_VEL_X_BASE + (direction * ITEM_VEL_X_STEP);
} else { } else {
// Velocidades positivas: 0.33, 0.66, 1.0 // Velocidades positivas: 0.33, 0.66, 1.0
vel_x_ = 0.33F + ((direction - 3) * 0.33F); vel_x_ = ITEM_VEL_X_STEP + ((direction - 3) * ITEM_VEL_X_STEP);
} }
vel_y_ = -4.0F; vel_y_ = ITEM_VEL_Y;
accel_y_ = 0.2F; accel_y_ = ITEM_ACCEL_Y;
collider_.r = width_ / 2; collider_.r = width_ / 2;
break; break;
} }
@@ -64,24 +67,34 @@ void Item::alignTo(int x) {
void Item::render() { void Item::render() {
if (enabled_) { if (enabled_) {
if (time_to_live_ > 200) { // Muestra normalmente hasta los últimos ~3.3 segundos
constexpr float BLINK_START_S = LIFETIME_DURATION_S - 3.33f;
if (lifetime_timer_ < BLINK_START_S) {
sprite_->render(); sprite_->render();
} else if (time_to_live_ % 20 > 10) { } else {
// Efecto de parpadeo en los últimos segundos (cada ~0.33 segundos)
constexpr float BLINK_INTERVAL_S = 0.33f;
const float phase = fmod(lifetime_timer_, BLINK_INTERVAL_S);
const float half_interval = BLINK_INTERVAL_S / 2.0f;
if (phase < half_interval) {
sprite_->render(); sprite_->render();
} }
} }
} }
}
void Item::move() { void Item::move(float deltaTime) {
floor_collision_ = false; floor_collision_ = false;
// Calcula la nueva posición // Calcula la nueva posición usando deltaTime (velocidad en pixels/segundo)
pos_x_ += vel_x_; pos_x_ += vel_x_ * deltaTime;
pos_y_ += vel_y_; pos_y_ += vel_y_ * deltaTime;
// Aplica las aceleraciones a la velocidad // Aplica las aceleraciones a la velocidad usando deltaTime (aceleración en pixels/segundo²)
vel_x_ += accel_x_; vel_x_ += accel_x_ * deltaTime;
vel_y_ += accel_y_; vel_y_ += accel_y_ * deltaTime;
// Comprueba los laterales de la zona de juego // Comprueba los laterales de la zona de juego
const float MIN_X = param.game.play_area.rect.x; const float MIN_X = param.game.play_area.rect.x;
@@ -111,24 +124,24 @@ void Item::move() {
case ItemType::COFFEE_MACHINE: case ItemType::COFFEE_MACHINE:
// La máquina de café es mas pesada y tiene una fisica diferente, ademas hace ruido // La máquina de café es mas pesada y tiene una fisica diferente, ademas hace ruido
floor_collision_ = true; floor_collision_ = true;
if (vel_y_ < 1.0F) { if (std::abs(vel_y_) < BOUNCE_VEL_THRESHOLD) {
// Si la velocidad vertical es baja, detiene el objeto // Si la velocidad vertical es baja, detiene el objeto
vel_y_ = vel_x_ = accel_x_ = accel_y_ = 0; vel_y_ = vel_x_ = accel_x_ = accel_y_ = 0;
} else { } else {
// Si la velocidad vertical es alta, el objeto rebota y pierde velocidad // Si la velocidad vertical es alta, el objeto rebota y pierde velocidad
vel_y_ *= -0.20F; vel_y_ *= COFFEE_BOUNCE_DAMPING;
vel_x_ *= 0.75F; vel_x_ *= HORIZONTAL_DAMPING;
} }
break; break;
default: default:
// Si no es una máquina de café // Si no es una máquina de café
if (vel_y_ < 1.0F) { if (std::abs(vel_y_) < BOUNCE_VEL_THRESHOLD) {
// Si la velocidad vertical es baja, detiene el objeto // Si la velocidad vertical es baja, detiene el objeto
vel_y_ = vel_x_ = accel_x_ = accel_y_ = 0; vel_y_ = vel_x_ = accel_x_ = accel_y_ = 0;
} else { } else {
// Si la velocidad vertical es alta, el objeto rebota y pierde velocidad // Si la velocidad vertical es alta, el objeto rebota y pierde velocidad
vel_y_ *= -0.5F; vel_y_ *= ITEM_BOUNCE_DAMPING;
vel_x_ *= 0.75F; vel_x_ *= HORIZONTAL_DAMPING;
} }
break; break;
} }
@@ -141,16 +154,15 @@ void Item::move() {
void Item::disable() { enabled_ = false; } void Item::disable() { enabled_ = false; }
void Item::update() { void Item::update(float deltaTime) {
move(); move(deltaTime);
sprite_->update(); sprite_->update(deltaTime);
updateTimeToLive(); updateTimeToLive(deltaTime);
} }
void Item::updateTimeToLive() { void Item::updateTimeToLive(float deltaTime) {
if (time_to_live_ > 0) { lifetime_timer_ += deltaTime;
time_to_live_--; if (lifetime_timer_ >= LIFETIME_DURATION_S) {
} else {
disable(); disable();
} }
} }

View File

@@ -29,6 +29,24 @@ class Item {
// --- Constantes --- // --- Constantes ---
static constexpr int COFFEE_MACHINE_WIDTH = 30; // Anchura de la máquina de café 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é static constexpr int COFFEE_MACHINE_HEIGHT = 39; // Altura de la máquina de café
static constexpr float LIFETIME_DURATION_S = 10.0f; // Duración de vida del ítem en segundos
// Velocidades base (pixels/segundo) - Coffee Machine
static constexpr float COFFEE_MACHINE_VEL_X_FACTOR = 30.0F; // Factor para velocidad X de máquina de café (0.5*60fps)
static constexpr float COFFEE_MACHINE_VEL_Y = -6.0F; // Velocidad Y inicial de máquina de café (-0.1*60fps)
static constexpr float COFFEE_MACHINE_ACCEL_Y = 360.0F; // Aceleración Y de máquina de café (0.1*60²fps = 360 pixels/segundo²)
// Velocidades base (pixels/segundo) - Items normales
static constexpr float ITEM_VEL_X_BASE = 60.0F; // Velocidad X base para items (1.0F*60fps)
static constexpr float ITEM_VEL_X_STEP = 20.0F; // Incremento de velocidad X (0.33F*60fps)
static constexpr float ITEM_VEL_Y = -240.0F; // Velocidad Y inicial de items (-4.0F*60fps)
static constexpr float ITEM_ACCEL_Y = 720.0F; // Aceleración Y de items (0.2*60²fps = 720 pixels/segundo²)
// Constantes de física de rebote
static constexpr float BOUNCE_VEL_THRESHOLD = 60.0F; // Umbral de velocidad para parar (1.0F*60fps)
static constexpr float COFFEE_BOUNCE_DAMPING = -0.20F; // Factor de rebote Y para máquina de café
static constexpr float ITEM_BOUNCE_DAMPING = -0.5F; // Factor de rebote Y para items normales
static constexpr float HORIZONTAL_DAMPING = 0.75F; // Factor de amortiguación horizontal
// --- Constructor y destructor --- // --- 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(ItemType type, float x, float y, SDL_FRect &play_area, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation); // Constructor principal
@@ -38,7 +56,7 @@ class Item {
void alignTo(int x); // Centra el objeto en la posición X indicada void alignTo(int x); // Centra el objeto en la posición X indicada
void render(); // Renderiza el objeto en pantalla void render(); // Renderiza el objeto en pantalla
void disable(); // Desactiva el objeto void disable(); // Desactiva el objeto
void update(); // Actualiza la posición, animación y contadores void update(float deltaTime); // Actualiza la posición, animación y contadores (time-based)
// --- Getters --- // --- Getters ---
[[nodiscard]] auto getPosX() const -> float { return pos_x_; } // Obtiene la posición X [[nodiscard]] auto getPosX() const -> float { return pos_x_; } // Obtiene la posición X
@@ -66,14 +84,14 @@ class Item {
float accel_y_; // Aceleración en el eje Y float accel_y_; // Aceleración en el eje Y
int width_; // Ancho del objeto int width_; // Ancho del objeto
int height_; // Alto del objeto int height_; // Alto del objeto
Uint16 time_to_live_ = 600; // Tiempo que el objeto está presente float lifetime_timer_ = 0.0f; // Acumulador de tiempo de vida del ítem (segundos)
bool floor_collision_ = false; // Indica si el objeto colisiona con el suelo bool floor_collision_ = false; // Indica si el objeto colisiona con el suelo
bool enabled_ = true; // Indica si el objeto está habilitado bool enabled_ = true; // Indica si el objeto está habilitado
// --- Métodos internos --- // --- Métodos internos ---
void shiftColliders(); // Alinea el círculo de colisión con la posición del objeto 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 shiftSprite(); // Coloca el sprite en la posición del objeto
void move(); // Actualiza la posición y estados del objeto void move(float deltaTime); // Actualiza la posición y estados del objeto (time-based)
void updateTimeToLive(); // Actualiza el contador de tiempo de vida void updateTimeToLive(float deltaTime); // Actualiza el contador de tiempo de vida (time-based)
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é static auto getCoffeeMachineSpawn(int player_x, int item_width, int area_width, int margin = 2) -> int; // Calcula la zona de aparición de la máquina de café
}; };

View File

@@ -11,6 +11,7 @@
#include "difficulty.h" // Para Difficulty #include "difficulty.h" // Para Difficulty
#include "external/json.hpp" // Para basic_json, iteration_proxy_value, oper... #include "external/json.hpp" // Para basic_json, iteration_proxy_value, oper...
#include "options.h" // Para SettingsOpt... #include "options.h" // Para SettingsOpt...
#include "resource_helper.h" // Para ResourceHelper
using json = nlohmann::json; using json = nlohmann::json;
@@ -27,14 +28,24 @@ std::vector<Language> languages = {
auto loadFromFile(const std::string &file_path) -> bool { auto loadFromFile(const std::string &file_path) -> bool {
texts.clear(); texts.clear();
// Intentar cargar desde ResourceHelper primero
auto resource_data = ResourceHelper::loadFile(file_path);
try {
json j;
if (!resource_data.empty()) {
// Cargar desde datos del pack
std::string content(resource_data.begin(), resource_data.end());
j = json::parse(content);
} else {
// Fallback a filesystem directo
std::ifstream rfile(file_path); std::ifstream rfile(file_path);
if (!rfile.is_open()) { if (!rfile.is_open()) {
return false; return false;
} }
try {
json j;
rfile >> j; rfile >> j;
}
for (const auto &el : j.items()) { for (const auto &el : j.items()) {
texts[el.key()] = el.value(); texts[el.key()] = el.value();

View File

@@ -19,7 +19,9 @@ struct Language {
std::string file_name; // Nombre del fichero con los textos std::string file_name; // Nombre del fichero con los textos
Language(Code c, std::string n, std::string fn) Language(Code c, std::string n, std::string fn)
: code(c), name(std::move(n)), file_name(std::move(fn)) {} : code(c),
name(std::move(n)),
file_name(std::move(fn)) {}
}; };
// --- Funciones --- // --- Funciones ---

View File

@@ -24,6 +24,32 @@ void ManageHiScoreTable::clear() {
table_.emplace_back("PACMQ", 200); table_.emplace_back("PACMQ", 200);
table_.emplace_back("PELEC", 100); table_.emplace_back("PELEC", 100);
/*
table_.emplace_back("BRY", 1000);
table_.emplace_back("USUFO", 500);
table_.emplace_back("GLUCA", 100);
table_.emplace_back("PARRA", 50);
table_.emplace_back("CAGAM", 10);
table_.emplace_back("PEPE", 5);
table_.emplace_back("ROSIT", 4);
table_.emplace_back("SAM", 3);
table_.emplace_back("PACMQ", 2);
table_.emplace_back("PELEC", 1);
*/
/*
table_.emplace_back("BRY", 5000000);
table_.emplace_back("USUFO", 5000000);
table_.emplace_back("GLUCA", 5000000);
table_.emplace_back("PARRA", 5000000);
table_.emplace_back("CAGAM", 5000000);
table_.emplace_back("PEPE", 5000000);
table_.emplace_back("ROSIT", 5000000);
table_.emplace_back("SAM", 5000000);
table_.emplace_back("PACMQ", 5000000);
table_.emplace_back("PELEC", 5000000);
*/
sort(); sort();
} }

View File

@@ -10,8 +10,10 @@ struct HiScoreEntry {
bool one_credit_complete; // Indica si se ha conseguido 1CC bool one_credit_complete; // Indica si se ha conseguido 1CC
// Constructor // Constructor
explicit HiScoreEntry(const std::string &n = "", int s = 0, bool occ = false) explicit HiScoreEntry(const std::string &name = "", int score = 0, bool one_credit_complete = false)
: name(n.substr(0, 6)), score(s), one_credit_complete(occ) {} : name(name.substr(0, 6)),
score(score),
one_credit_complete(one_credit_complete) {}
}; };
// --- Tipos --- // --- Tipos ---

View File

@@ -53,42 +53,41 @@ void MovingSprite::stop() {
flip_ = SDL_FLIP_NONE; // Establece como se ha de voltear el sprite flip_ = SDL_FLIP_NONE; // Establece como se ha de voltear el sprite
} }
// Mueve el sprite // Mueve el sprite (time-based)
void MovingSprite::move() { void MovingSprite::move(float deltaTime) {
x_ += vx_; // DeltaTime puro: velocidad (pixels/ms) * tiempo (ms)
y_ += vy_; x_ += vx_ * deltaTime;
y_ += vy_ * deltaTime;
vx_ += ax_; // Aceleración (pixels/ms²) * tiempo (ms)
vy_ += ay_; vx_ += ax_ * deltaTime;
vy_ += ay_ * deltaTime;
pos_.x = static_cast<int>(x_); pos_.x = static_cast<int>(x_);
pos_.y = static_cast<int>(y_); pos_.y = static_cast<int>(y_);
} }
// Actualiza las variables internas del objeto // Actualiza las variables internas del objeto (time-based)
void MovingSprite::update() { void MovingSprite::update(float deltaTime) {
move(); move(deltaTime);
rotate(); rotate(deltaTime);
} }
// Muestra el sprite por pantalla // Muestra el sprite por pantalla
void MovingSprite::render() { getTexture()->render(pos_.x, pos_.y, &sprite_clip_, horizontal_zoom_, vertical_zoom_, rotate_.angle, &rotate_.center, flip_); } void MovingSprite::render() {
getTexture()->render(pos_.x, pos_.y, &sprite_clip_, horizontal_zoom_, vertical_zoom_, rotate_.angle, &rotate_.center, flip_);
// Establece la rotacion
void MovingSprite::rotate() {
if (rotate_.enabled) {
++rotate_.counter;
if (rotate_.counter % rotate_.speed == 0) {
updateAngle();
rotate_.counter = 0;
} }
// Establece la rotacion (time-based)
void MovingSprite::rotate(float deltaTime) {
if (rotate_.enabled) {
rotate_.angle += rotate_.amount * deltaTime;
} }
} }
// Activa o desactiva el efecto de rotación // Activa o desactiva el efecto de rotación
void MovingSprite::setRotate(bool enable) { void MovingSprite::setRotate(bool enable) {
rotate_.enabled = enable; rotate_.enabled = enable;
rotate_.counter = 0;
} }
// Establece la posición y_ el tamaño del objeto // Establece la posición y_ el tamaño del objeto

View File

@@ -15,7 +15,6 @@ class MovingSprite : public Sprite {
// --- Estructuras --- // --- Estructuras ---
struct Rotate { struct Rotate {
bool enabled{false}; // Indica si ha de rotar bool enabled{false}; // Indica si ha de rotar
int counter{0}; // Contador
int speed{1}; // Velocidad de giro int speed{1}; // Velocidad de giro
double angle{0.0}; // Ángulo para dibujarlo double angle{0.0}; // Ángulo para dibujarlo
float amount{0.0F}; // Cantidad de grados a girar en cada iteración float amount{0.0F}; // Cantidad de grados a girar en cada iteración
@@ -29,7 +28,7 @@ class MovingSprite : public Sprite {
~MovingSprite() override = default; ~MovingSprite() override = default;
// --- Métodos principales --- // --- Métodos principales ---
virtual void update(); // Actualiza las variables internas del objeto virtual void update(float deltaTime); // Actualiza las variables internas del objeto (time-based)
void clear() override; // Reinicia todas las variables a cero void clear() override; // Reinicia todas las variables a cero
void stop(); // Elimina el movimiento del sprite void stop(); // Elimina el movimiento del sprite
void render() override; // Muestra el sprite por pantalla void render() override; // Muestra el sprite por pantalla
@@ -79,6 +78,6 @@ class MovingSprite : public Sprite {
// --- Métodos internos --- // --- Métodos internos ---
void updateAngle() { rotate_.angle += rotate_.amount; } // Incrementa el valor del ángulo void updateAngle() { rotate_.angle += rotate_.amount; } // Incrementa el valor del ángulo
void move(); // Mueve el sprite según velocidad y aceleración void move(float deltaTime); // Mueve el sprite según velocidad y aceleración (time-based)
void rotate(); // Rota el sprite según los parámetros de rotación void rotate(float deltaTime); // Rota el sprite según los parámetros de rotación (time-based)
}; };

View File

@@ -106,7 +106,6 @@ auto setParams(const std::string& var, const std::string& value) -> bool {
{"scoreboard.rect.h", [](const std::string& v) { param.scoreboard.rect.h = std::stoi(v); }}, {"scoreboard.rect.h", [](const std::string& v) { param.scoreboard.rect.h = std::stoi(v); }},
{"scoreboard.skip_countdown_value", [](const std::string& v) { param.scoreboard.skip_countdown_value = std::stoi(v); }}, {"scoreboard.skip_countdown_value", [](const std::string& v) { param.scoreboard.skip_countdown_value = std::stoi(v); }},
{"title.press_start_position", [](const std::string& v) { param.title.press_start_position = std::stoi(v); }}, {"title.press_start_position", [](const std::string& v) { param.title.press_start_position = std::stoi(v); }},
{"title.title_duration", [](const std::string& v) { param.title.title_duration = std::stoi(v); }},
{"title.arcade_edition_position", [](const std::string& v) { param.title.arcade_edition_position = std::stoi(v); }}, {"title.arcade_edition_position", [](const std::string& v) { param.title.arcade_edition_position = std::stoi(v); }},
{"title.title_c_c_position", [](const std::string& v) { param.title.title_c_c_position = std::stoi(v); }}, {"title.title_c_c_position", [](const std::string& v) { param.title.title_c_c_position = std::stoi(v); }},
{"intro.text_distance_from_bottom", [](const std::string& v) { param.intro.text_distance_from_bottom = std::stoi(v); }}}; {"intro.text_distance_from_bottom", [](const std::string& v) { param.intro.text_distance_from_bottom = std::stoi(v); }}};
@@ -182,6 +181,7 @@ auto setParams(const std::string& var, const std::string& value) -> bool {
{"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.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); }}, {"tabe.max_spawn_time", [](const std::string& v) { param.tabe.max_spawn_time = std::stof(v); }},
{"title.title_duration", [](const std::string& v) { param.title.title_duration = 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.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.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.title_separator_spacing", [](const std::string& v) { param.service_menu.window_message.title_separator_spacing = std::stof(v); }},
@@ -196,8 +196,10 @@ auto setParams(const std::string& var, const std::string& value) -> bool {
// Colores válidos para globos // Colores válidos para globos
static const std::unordered_map<std::string, bool> VALID_BALLOON_COLORS = { static const std::unordered_map<std::string, bool> VALID_BALLOON_COLORS = {
{"blue", true}, {"orange", true}, {"red", true}, {"green", true} {"blue", true},
}; {"orange", true},
{"red", true},
{"green", true}};
auto validateBalloonColor = [](const std::string& color) -> bool { auto validateBalloonColor = [](const std::string& color) -> bool {
return VALID_BALLOON_COLORS.find(color) != VALID_BALLOON_COLORS.end(); return VALID_BALLOON_COLORS.find(color) != VALID_BALLOON_COLORS.end();

View File

@@ -38,7 +38,7 @@ struct ParamFade {
// --- Parámetros de la pantalla de título --- // --- Parámetros de la pantalla de título ---
struct ParamTitle { struct ParamTitle {
int press_start_position = GameDefaults::Title::PRESS_START_POSITION; int press_start_position = GameDefaults::Title::PRESS_START_POSITION;
int title_duration = GameDefaults::Title::DURATION; float title_duration = GameDefaults::Title::DURATION_S;
int arcade_edition_position = GameDefaults::Title::ARCADE_EDITION_POSITION; int arcade_edition_position = GameDefaults::Title::ARCADE_EDITION_POSITION;
int title_c_c_position = GameDefaults::Title::TITLE_C_C_POSITION; int title_c_c_position = GameDefaults::Title::TITLE_C_C_POSITION;
Color bg_color = Color::fromHex(GameDefaults::Title::BG_COLOR); Color bg_color = Color::fromHex(GameDefaults::Title::BG_COLOR);
@@ -57,7 +57,8 @@ struct ParamBalloon {
// Constructor por defecto // Constructor por defecto
constexpr Settings(float grav_val = 0.0F, float vel_val = 0.0F) constexpr Settings(float grav_val = 0.0F, float vel_val = 0.0F)
: grav(grav_val), vel(vel_val) {} : grav(grav_val),
vel(vel_val) {}
}; };
// Inicialización con los valores por defecto desde GameDefaults // Inicialización con los valores por defecto desde GameDefaults
@@ -164,7 +165,10 @@ struct ParamPlayer {
// Constructor con tonalidades específicas // Constructor con tonalidades específicas
Shirt(const Color& darkest_tone, const Color& dark_tone, const Color& base_tone, const Color& light_tone) 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) {} : darkest(darkest_tone),
dark(dark_tone),
base(base_tone),
light(light_tone) {}
}; };
// Inicialización con valores por defecto // Inicialización con valores por defecto

View File

@@ -4,6 +4,12 @@
#include <functional> // Para function #include <functional> // Para function
#include <utility> // Para move #include <utility> // Para move
// Constructor para paths por puntos (convertido a segundos)
Path::Path(const std::vector<SDL_FPoint> &spots_init, float waiting_time_s_init)
: spots(spots_init), is_point_path(true) {
waiting_time_s = waiting_time_s_init;
}
// Devuelve un vector con los puntos que conforman la ruta // 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> { auto createPath(float start, float end, PathType type, float fixed_pos, int steps, const std::function<double(double)> &easing_function) -> std::vector<SDL_FPoint> {
std::vector<SDL_FPoint> v; std::vector<SDL_FPoint> v;
@@ -33,9 +39,9 @@ auto createPath(float start, float end, PathType type, float fixed_pos, int step
} }
// Actualiza la posición y comprueba si ha llegado a su destino // Actualiza la posición y comprueba si ha llegado a su destino
void PathSprite::update() { void PathSprite::update(float delta_time) {
if (enabled_ && !has_finished_) { if (enabled_ && !has_finished_) {
moveThroughCurrentPath(); moveThroughCurrentPath(delta_time);
goToNextPathOrDie(); goToNextPathOrDie();
} }
} }
@@ -77,14 +83,14 @@ void PathSprite::addPath(Path path, bool centered) {
} }
} }
// Añade un recorrido // Añade un recorrido generado (en segundos)
void PathSprite::addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easing_function, int waiting_counter) { void PathSprite::addPath(float start, float end, PathType type, float fixed_pos, float duration_s, const std::function<double(double)> &easing_function, float waiting_time_s) {
paths_.emplace_back(createPath(start, end, type, fixed_pos, steps, easing_function), waiting_counter); paths_.emplace_back(start, end, type, fixed_pos, duration_s, waiting_time_s, easing_function);
} }
// Añade un recorrido // Añade un recorrido por puntos (en segundos)
void PathSprite::addPath(const std::vector<SDL_FPoint> &spots, int waiting_counter) { void PathSprite::addPath(const std::vector<SDL_FPoint> &spots, float waiting_time_s) {
paths_.emplace_back(spots, waiting_counter); paths_.emplace_back(spots, waiting_time_s);
} }
// Habilita el objeto // Habilita el objeto
@@ -95,21 +101,32 @@ void PathSprite::enable() {
enabled_ = true; enabled_ = true;
// Establece la posición // Establece la posición inicial
auto &path = paths_.at(current_path_); auto &path = paths_.at(current_path_);
if (path.is_point_path) {
const auto &p = path.spots.at(path.counter); const auto &p = path.spots.at(path.counter);
setPosition(p); setPosition(p);
} else {
// Para paths generados, establecer posición inicial
SDL_FPoint initial_pos;
if (path.type == PathType::HORIZONTAL) {
initial_pos = {path.start_pos, path.fixed_pos};
} else {
initial_pos = {path.fixed_pos, path.start_pos};
}
setPosition(initial_pos);
}
} }
// Coloca el sprite en los diferentes puntos del recorrido // Coloca el sprite en los diferentes puntos del recorrido
void PathSprite::moveThroughCurrentPath() { void PathSprite::moveThroughCurrentPath(float delta_time) {
auto &path = paths_.at(current_path_); auto &path = paths_.at(current_path_);
// Establece la posición if (path.is_point_path) {
// Lógica para paths por puntos (compatibilidad)
const auto &p = path.spots.at(path.counter); const auto &p = path.spots.at(path.counter);
setPosition(p); setPosition(p);
// Comprobar si ha terminado el recorrido
if (!path.on_destination) { if (!path.on_destination) {
++path.counter; ++path.counter;
if (path.counter >= static_cast<int>(path.spots.size())) { if (path.counter >= static_cast<int>(path.spots.size())) {
@@ -118,12 +135,44 @@ void PathSprite::moveThroughCurrentPath() {
} }
} }
// Comprobar si ha terminado la espera
if (path.on_destination) { if (path.on_destination) {
if (path.waiting_counter == 0) { path.waiting_elapsed += delta_time;
if (path.waiting_elapsed >= path.waiting_time_s) {
path.finished = true; path.finished = true;
}
}
} else { } else {
--path.waiting_counter; // Lógica para paths generados en tiempo real
if (!path.on_destination) {
path.elapsed_time += delta_time;
// Calcular progreso (0.0 a 1.0)
float progress = path.elapsed_time / path.duration_s;
if (progress >= 1.0f) {
progress = 1.0f;
path.on_destination = true;
}
// Aplicar función de easing
double eased_progress = path.easing_function(progress);
// Calcular posición actual
float current_pos = path.start_pos + (path.end_pos - path.start_pos) * static_cast<float>(eased_progress);
// Establecer posición según el tipo
SDL_FPoint position;
if (path.type == PathType::HORIZONTAL) {
position = {current_pos, path.fixed_pos};
} else {
position = {path.fixed_pos, current_pos};
}
setPosition(position);
} else {
// Esperar en destino
path.waiting_elapsed += delta_time;
if (path.waiting_elapsed >= path.waiting_time_s) {
path.finished = true;
}
} }
} }
} }

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