Compare commits
99 Commits
2025-08-17
...
35f4bf690c
| Author | SHA1 | Date | |
|---|---|---|---|
| 35f4bf690c | |||
| abeaf47f96 | |||
| 6498c35628 | |||
| d1c6af02db | |||
| 5edef17d84 | |||
| e4532fcef2 | |||
| 7a8d66c29d | |||
| 54292c9f8f | |||
| 3897553704 | |||
| 308f5c20fb | |||
| 987dcd0205 | |||
| d56f23544c | |||
| c79a846b29 | |||
| ad39d55e79 | |||
| 853ef426f0 | |||
| cadf7de3d8 | |||
| ec65ff9acb | |||
| d077374883 | |||
| 40a2b2cc00 | |||
| b3f3f151da | |||
| 3fdd61655a | |||
| 504727b95f | |||
| ff5446fcdf | |||
| 545eb70082 | |||
| 232a23a5dd | |||
| c9a29e26dd | |||
| 2977869ab5 | |||
| 6a223b68ba | |||
| 3fafff026b | |||
| 159528adc9 | |||
| 6c8f231b34 | |||
| c5d6d77ebf | |||
| 5e73327b2f | |||
| 720d286dcf | |||
| dd13a2bd7c | |||
| 1a6ef79466 | |||
| 8f83a1d13e | |||
| 9edfe6877f | |||
| 91b26631c6 | |||
| 331a690b78 | |||
| 5e3946e28b | |||
| d4a0189dc8 | |||
| 568b941990 | |||
| 49a3989ecf | |||
| af7cb01ead | |||
| 5c82916650 | |||
| 0c0518adac | |||
| cb7b290818 | |||
| ae30c9b34f | |||
| 9acd9aa631 | |||
| 577510ff8c | |||
| 66566913f6 | |||
| 3e6cc9dfab | |||
| a15e29344f | |||
| a96a17e11b | |||
| e0f6a424a9 | |||
| 49e30f947a | |||
| 470a07d28c | |||
| 65716fce20 | |||
| dfa66b0e95 | |||
| 3d9ffe356e | |||
| 19768cb72b | |||
| 26e0fd7247 | |||
| e2fd470ad3 | |||
| a72ae0a5fc | |||
| 7579594c22 | |||
| 6c702e7e23 | |||
| fb9c78eb49 | |||
| 62f65cbd5a | |||
| 057d3dcfee | |||
| c85336a4d0 | |||
| e4702e4e24 | |||
| 928335576c | |||
| fe950e6f17 | |||
| 6e81b6e60c | |||
| 74f6fe3501 | |||
| dfdb679054 | |||
| 26ed479306 | |||
| 32e9da55ef | |||
| 610083578e | |||
| 7250073d60 | |||
| dfa06870e4 | |||
| 81f3a25143 | |||
| 5aca95f3d2 | |||
| 7b193605e6 | |||
| 089a5b15d7 | |||
| e6a14ca57d | |||
| 467d609c28 | |||
| e03c798000 | |||
| 52d76b7338 | |||
| 83ee9c2649 | |||
| 43788bb01a | |||
| 58cf78e1e3 | |||
| 6bf8490776 | |||
| 8cfe28922c | |||
| 63990c75c2 | |||
| 94dca528ab | |||
| 4b6b89ceb2 | |||
| ed077c1da5 |
@@ -14,6 +14,8 @@ ContinuationIndentWidth: 4
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
Cpp11BracedListStyle: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
PackConstructorInitializers: Never
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
|
||||
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
.vscode
|
||||
.claude
|
||||
build/
|
||||
data/config/config.txt
|
||||
*.DS_Store
|
||||
|
||||
@@ -28,6 +28,9 @@ set(APP_SOURCES
|
||||
source/main.cpp
|
||||
source/param.cpp
|
||||
source/resource.cpp
|
||||
source/resource_helper.cpp
|
||||
source/resource_loader.cpp
|
||||
source/resource_pack.cpp
|
||||
source/screen.cpp
|
||||
source/text.cpp
|
||||
source/writer.cpp
|
||||
|
||||
22
LICENSE
@@ -1 +1,21 @@
|
||||
GNU General Public License v3.0 only
|
||||
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
|
||||
|
||||
Copyright (c) 2025 Coffee Crisis Arcade Edition
|
||||
|
||||
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
|
||||
|
||||
You are free to:
|
||||
- Share — copy and redistribute the material in any medium or format
|
||||
- Adapt — remix, transform, and build upon the material
|
||||
|
||||
Under the following terms:
|
||||
- Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
|
||||
- NonCommercial — You may not use the material for commercial purposes.
|
||||
- ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
|
||||
|
||||
No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
|
||||
|
||||
To view a copy of this license, visit:
|
||||
https://creativecommons.org/licenses/by-nc-sa/4.0/
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
25
Makefile
@@ -71,6 +71,9 @@ APP_SOURCES := \
|
||||
source/path_sprite.cpp \
|
||||
source/player.cpp \
|
||||
source/resource.cpp \
|
||||
source/resource_helper.cpp \
|
||||
source/resource_loader.cpp \
|
||||
source/resource_pack.cpp \
|
||||
source/scoreboard.cpp \
|
||||
source/screen.cpp \
|
||||
source/sections/credits.cpp \
|
||||
@@ -104,7 +107,7 @@ INCLUDES := -Isource -Isource/external
|
||||
# Variables según el sistema operativo
|
||||
ifeq ($(OS),Windows_NT)
|
||||
FixPath = $(subst /,\\,$1)
|
||||
CXXFLAGS := -std=c++20 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows -DWINDOWS_BUILD
|
||||
CXXFLAGS := -std=c++20 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -static-libgcc -Wl,-Bstatic -lpthread -Wl,-Bdynamic -Wl,-subsystem,windows -DWINDOWS_BUILD
|
||||
CXXFLAGS_DEBUG := -std=c++20 -Wall -g -D_DEBUG -DWINDOWS_BUILD
|
||||
LDFLAGS := -lmingw32 -lws2_32 -lSDL3 -lopengl32
|
||||
RM := del /Q
|
||||
@@ -158,8 +161,9 @@ windows_release:
|
||||
powershell if (Test-Path "$(RELEASE_FOLDER)") {Remove-Item "$(RELEASE_FOLDER)" -Recurse -Force}
|
||||
powershell if (-not (Test-Path "$(RELEASE_FOLDER)")) {New-Item "$(RELEASE_FOLDER)" -ItemType Directory}
|
||||
|
||||
# Copia la carpeta 'data'
|
||||
powershell Copy-Item -Path "data" -Destination "$(RELEASE_FOLDER)" -recurse -Force
|
||||
# Copia la carpeta 'config' y el archivo 'resources.pack'
|
||||
powershell Copy-Item -Path "config" -Destination "$(RELEASE_FOLDER)" -recurse -Force
|
||||
powershell Copy-Item -Path "resources.pack" -Destination "$(RELEASE_FOLDER)"
|
||||
|
||||
# Copia los ficheros que estan en la raíz del proyecto
|
||||
powershell Copy-Item "LICENSE" -Destination "$(RELEASE_FOLDER)"
|
||||
@@ -203,7 +207,8 @@ macos_release:
|
||||
$(MKDIR) Frameworks
|
||||
|
||||
# Copia carpetas y ficheros
|
||||
cp -R data "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||
cp -R config "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||
cp resources.pack "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||
cp -R release/frameworks/SDL3.xcframework "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
|
||||
cp -R release/frameworks/SDL3.xcframework Frameworks
|
||||
cp release/*.icns "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
|
||||
@@ -262,7 +267,8 @@ linux_release:
|
||||
$(MKDIR) "$(RELEASE_FOLDER)"
|
||||
|
||||
# Copia ficheros
|
||||
cp -R data "$(RELEASE_FOLDER)"
|
||||
cp -R config "$(RELEASE_FOLDER)"
|
||||
cp resources.pack "$(RELEASE_FOLDER)"
|
||||
cp LICENSE "$(RELEASE_FOLDER)"
|
||||
cp README.md "$(RELEASE_FOLDER)"
|
||||
|
||||
@@ -291,7 +297,8 @@ linux_release_desktop:
|
||||
$(MKDIR) "$(RELEASE_FOLDER)/$(TARGET_NAME)/share/$(TARGET_NAME)"
|
||||
|
||||
# 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 README.md "$(RELEASE_FOLDER)/$(TARGET_NAME)/"
|
||||
|
||||
@@ -391,7 +398,8 @@ raspi_release:
|
||||
$(MKDIR) "$(RELEASE_FOLDER)"
|
||||
|
||||
# Copia ficheros
|
||||
cp -R data "$(RELEASE_FOLDER)"
|
||||
cp -R config "$(RELEASE_FOLDER)"
|
||||
cp resources.pack "$(RELEASE_FOLDER)"
|
||||
cp LICENSE "$(RELEASE_FOLDER)"
|
||||
cp README.md "$(RELEASE_FOLDER)"
|
||||
|
||||
@@ -416,7 +424,8 @@ anbernic:
|
||||
$(MKDIR) "$(RELEASE_FOLDER)"_anbernic
|
||||
|
||||
# Copia ficheros
|
||||
cp -R data "$(RELEASE_FOLDER)"_anbernic
|
||||
cp -R config "$(RELEASE_FOLDER)"_anbernic
|
||||
cp resources.pack "$(RELEASE_FOLDER)"_anbernic
|
||||
|
||||
# Compila
|
||||
$(CXX) $(APP_SOURCES) $(INCLUDES) -DANBERNIC -DNO_SHADERS -DARCADE -DVERBOSE $(CXXFLAGS) $(LDFLAGS) -o $(RELEASE_FOLDER)_anbernic/$(TARGET_NAME)
|
||||
|
||||
61
TODO.md
Normal 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"
|
||||
@@ -9,17 +9,20 @@ DATA|${SYSTEM_FOLDER}/controllers.json|optional,absolute
|
||||
DATA|${SYSTEM_FOLDER}/score.bin|optional,absolute
|
||||
|
||||
# Archivos de configuración del juego
|
||||
DATA|${PREFIX}/data/config/formations.txt
|
||||
DATA|${PREFIX}/data/config/gamecontrollerdb.txt
|
||||
DATA|${PREFIX}/data/config/param_320x240.txt
|
||||
DATA|${PREFIX}/data/config/param_320x256.txt
|
||||
DATA|${PREFIX}/data/config/param_red.txt
|
||||
DATA|${PREFIX}/data/config/pools.txt
|
||||
DATA|${PREFIX}/data/config/stages.txt
|
||||
DEMODATA|${PREFIX}/data/config/demo1.bin
|
||||
DEMODATA|${PREFIX}/data/config/demo2.bin
|
||||
DATA|${PREFIX}/config/formations.txt
|
||||
DATA|${PREFIX}/config/gamecontrollerdb.txt
|
||||
DATA|${PREFIX}/config/param_320x240.txt
|
||||
DATA|${PREFIX}/config/param_320x256.txt
|
||||
DATA|${PREFIX}/config/param_red.txt
|
||||
DATA|${PREFIX}/config/pools.txt
|
||||
DATA|${PREFIX}/config/stages.txt
|
||||
|
||||
# Archivos con los datos de la demo
|
||||
DEMODATA|${PREFIX}/data/demo/demo1.bin
|
||||
DEMODATA|${PREFIX}/data/demo/demo2.bin
|
||||
|
||||
# Música
|
||||
MUSIC|${PREFIX}/data/music/congratulations.ogg
|
||||
MUSIC|${PREFIX}/data/music/credits.ogg
|
||||
MUSIC|${PREFIX}/data/music/intro.ogg
|
||||
MUSIC|${PREFIX}/data/music/playing.ogg
|
||||
@@ -46,10 +49,12 @@ SOUND|${PREFIX}/data/sound/item_drop.wav
|
||||
SOUND|${PREFIX}/data/sound/item_pickup.wav
|
||||
SOUND|${PREFIX}/data/sound/jump.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/player_collision.wav
|
||||
SOUND|${PREFIX}/data/sound/power_ball_explosion.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_select.wav
|
||||
SOUND|${PREFIX}/data/sound/stage_change.wav
|
||||
@@ -172,6 +177,7 @@ BITMAP|${PREFIX}/data/gfx/player/hit.png
|
||||
|
||||
# Fuentes de texto
|
||||
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.png
|
||||
BITMAP|${PREFIX}/data/font/04b_25_grey.png
|
||||
277
config/formations.txt
Normal 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
|
||||
@@ -39,24 +39,24 @@ scoreboard.text_color2 FFFFFF # Color secundario del texto del marca
|
||||
scoreboard.skip_countdown_value 8 # Valor para saltar la cuenta atrás (segundos)
|
||||
|
||||
# --- TITLE ---
|
||||
title.press_start_position 180 # Posición Y del texto "Press Start"
|
||||
title.title_duration 800 # Duración de la pantalla de título (frames)
|
||||
title.arcade_edition_position 123 # Posición Y del subtítulo "Arcade Edition"
|
||||
title.title_c_c_position 80 # Posición Y del título principal
|
||||
title.bg_color 41526F # Color de fondo en la sección titulo
|
||||
title.press_start_position 180 # Posición Y del texto "Press Start"
|
||||
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.title_c_c_position 80 # Posición Y del título principal
|
||||
title.bg_color 41526F # Color de fondo en la sección titulo
|
||||
|
||||
# --- BACKGROUND ---
|
||||
background.attenuate_color FFFFFF00 # Color de atenuación del fondo (RGBA hexadecimal)
|
||||
|
||||
# --- BALLOONS ---
|
||||
balloon.settings[0].vel 2.75f # Velocidad inicial del globo 1
|
||||
balloon.settings[0].grav 0.09f # Gravedad aplicada al globo 1
|
||||
balloon.settings[1].vel 3.70f # Velocidad inicial del globo 2
|
||||
balloon.settings[1].grav 0.10f # Gravedad aplicada al globo 2
|
||||
balloon.settings[2].vel 4.70f # Velocidad inicial del globo 3
|
||||
balloon.settings[2].grav 0.10f # Gravedad aplicada al globo 3
|
||||
balloon.settings[3].vel 5.45f # Velocidad inicial del globo 4
|
||||
balloon.settings[3].grav 0.10f # Gravedad aplicada al globo 4
|
||||
# --- BALLOONS --- (deltaTime en segundos: vel en pixels/s, grav en pixels/s²)
|
||||
balloon.settings[0].vel 165.0f # Velocidad inicial del globo 1 (pixels/s)
|
||||
balloon.settings[0].grav 320.0f # Gravedad aplicada al globo 1 (pixels/s²)
|
||||
balloon.settings[1].vel 222.0f # Velocidad inicial del globo 2 (pixels/s)
|
||||
balloon.settings[1].grav 360.0f # Gravedad aplicada al globo 2 (pixels/s²)
|
||||
balloon.settings[2].vel 282.0f # Velocidad inicial del globo 3 (pixels/s)
|
||||
balloon.settings[2].grav 360.0f # Gravedad aplicada al globo 3 (pixels/s²)
|
||||
balloon.settings[3].vel 327.0f # Velocidad inicial del globo 4 (pixels/s)
|
||||
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[1] orange # Color del globo normal
|
||||
@@ -39,24 +39,24 @@ scoreboard.text_color2 FFFFFF # Color secundario del texto del marca
|
||||
scoreboard.skip_countdown_value 8 # Valor para saltar la cuenta atrás (segundos)
|
||||
|
||||
# --- TITLE ---
|
||||
title.press_start_position 180 # Posición Y del texto "Press Start"
|
||||
title.title_duration 800 # Duración de la pantalla de título (frames)
|
||||
title.arcade_edition_position 123 # Posición Y del subtítulo "Arcade Edition"
|
||||
title.title_c_c_position 80 # Posición Y del título principal
|
||||
title.bg_color 41526F # Color de fondo en la sección titulo
|
||||
title.press_start_position 180 # Posición Y del texto "Press Start"
|
||||
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.title_c_c_position 80 # Posición Y del título principal
|
||||
title.bg_color 41526F # Color de fondo en la sección titulo
|
||||
|
||||
# --- BACKGROUND ---
|
||||
background.attenuate_color FFFFFF00 # Color de atenuación del fondo (RGBA hexadecimal)
|
||||
|
||||
# --- BALLOONS ---
|
||||
balloon.settings[0].vel 2.75f # Velocidad inicial del globo 1
|
||||
balloon.settings[0].grav 0.09f # Gravedad aplicada al globo 1
|
||||
balloon.settings[1].vel 3.70f # Velocidad inicial del globo 2
|
||||
balloon.settings[1].grav 0.10f # Gravedad aplicada al globo 2
|
||||
balloon.settings[2].vel 4.70f # Velocidad inicial del globo 3
|
||||
balloon.settings[2].grav 0.10f # Gravedad aplicada al globo 3
|
||||
balloon.settings[3].vel 5.45f # Velocidad inicial del globo 4
|
||||
balloon.settings[3].grav 0.10f # Gravedad aplicada al globo 4
|
||||
# --- BALLOONS --- (deltaTime en segundos: vel en pixels/s, grav en pixels/s²)
|
||||
balloon.settings[0].vel 165.0f # Velocidad inicial del globo 1 (pixels/s)
|
||||
balloon.settings[0].grav 320.0f # Gravedad aplicada al globo 1 (pixels/s²)
|
||||
balloon.settings[1].vel 222.0f # Velocidad inicial del globo 2 (pixels/s)
|
||||
balloon.settings[1].grav 360.0f # Gravedad aplicada al globo 2 (pixels/s²)
|
||||
balloon.settings[2].vel 282.0f # Velocidad inicial del globo 3 (pixels/s)
|
||||
balloon.settings[2].grav 360.0f # Gravedad aplicada al globo 3 (pixels/s²)
|
||||
balloon.settings[3].vel 327.0f # Velocidad inicial del globo 4 (pixels/s)
|
||||
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[1] orange # Color del globo normal
|
||||
@@ -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
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
BIN
data/font/04b_25_2x_white.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 872 B After Width: | Height: | Size: 882 B |
@@ -3,28 +3,28 @@ frame_height=10
|
||||
|
||||
[animation]
|
||||
name=orange
|
||||
speed=10
|
||||
speed=0.1667
|
||||
loop=0
|
||||
frames=0,1,2,3,4,5,6,7,8,9
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=blue
|
||||
speed=20
|
||||
speed=0.3333
|
||||
loop=0
|
||||
frames=10,11,12,13,14,15,16,17,18,19
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=green
|
||||
speed=10
|
||||
speed=0.1667
|
||||
loop=0
|
||||
frames=20,21,22,23,24,25,26,27,28,29
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=red
|
||||
speed=20
|
||||
speed=0.3333
|
||||
loop=0
|
||||
frames=30,31,32,33,34,35,36,37,38,39
|
||||
[/animation]
|
||||
@@ -3,28 +3,28 @@ frame_height=16
|
||||
|
||||
[animation]
|
||||
name=orange
|
||||
speed=10
|
||||
speed=0.1667
|
||||
loop=0
|
||||
frames=0,1,2,3,4,5,6,7,8,9
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=blue
|
||||
speed=20
|
||||
speed=0.3333
|
||||
loop=0
|
||||
frames=10,11,12,13,14,15,16,17,18,19
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=green
|
||||
speed=10
|
||||
speed=0.1667
|
||||
loop=0
|
||||
frames=20,21,22,23,24,25,26,27,28,29
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=red
|
||||
speed=20
|
||||
speed=0.3333
|
||||
loop=0
|
||||
frames=30,31,32,33,34,35,36,37,38,39
|
||||
[/animation]
|
||||
@@ -3,28 +3,28 @@ frame_height=26
|
||||
|
||||
[animation]
|
||||
name=orange
|
||||
speed=10
|
||||
speed=0.1667
|
||||
loop=0
|
||||
frames=0,1,2,3,4,5,6,7,8,9
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=blue
|
||||
speed=20
|
||||
speed=0.3333
|
||||
loop=0
|
||||
frames=10,11,12,13,14,15,16,17,18,19
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=green
|
||||
speed=10
|
||||
speed=0.1667
|
||||
loop=0
|
||||
frames=20,21,22,23,24,25,26,27,28,29
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=red
|
||||
speed=20
|
||||
speed=0.3333
|
||||
loop=0
|
||||
frames=30,31,32,33,34,35,36,37,38,39
|
||||
[/animation]
|
||||
@@ -3,28 +3,28 @@ frame_height=48
|
||||
|
||||
[animation]
|
||||
name=orange
|
||||
speed=10
|
||||
speed=0.1667
|
||||
loop=0
|
||||
frames=0,1,2,3,4,5,6,7,8,9
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=blue
|
||||
speed=20
|
||||
speed=0.3333
|
||||
loop=0
|
||||
frames=10,11,12,13,14,15,16,17,18,19
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=green
|
||||
speed=10
|
||||
speed=0.1667
|
||||
loop=0
|
||||
frames=20,21,22,23,24,25,26,27,28,29
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=red
|
||||
speed=20
|
||||
speed=0.3333
|
||||
loop=0
|
||||
frames=30,31,32,33,34,35,36,37,38,39
|
||||
[/animation]
|
||||
@@ -3,7 +3,7 @@ frame_height=10
|
||||
|
||||
[animation]
|
||||
name=default
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=-1
|
||||
frames=0,1,2,3,4,5,6,7,8,9
|
||||
[/animation]
|
||||
@@ -3,7 +3,7 @@ frame_height=16
|
||||
|
||||
[animation]
|
||||
name=default
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=-1
|
||||
frames=0,1,2,3,4,5,6,7,8,9
|
||||
[/animation]
|
||||
@@ -3,7 +3,7 @@ frame_height=26
|
||||
|
||||
[animation]
|
||||
name=default
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=-1
|
||||
frames=0,1,2,3,4,5,6,7,8,9
|
||||
[/animation]
|
||||
@@ -3,7 +3,7 @@ frame_height=48
|
||||
|
||||
[animation]
|
||||
name=default
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=-1
|
||||
frames=0,1,2,3,4,5,6,7,8,9
|
||||
[/animation]
|
||||
@@ -3,7 +3,7 @@ frame_height=49
|
||||
|
||||
[animation]
|
||||
name=powerball
|
||||
speed=10
|
||||
speed=0.0167
|
||||
loop=-1
|
||||
frames=1
|
||||
[/animation]
|
||||
@@ -3,42 +3,42 @@ frame_height=12
|
||||
|
||||
[animation]
|
||||
name=normal_up
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=0,1,2
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=normal_left
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=3,4,5,5,4,3
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=normal_right
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=6,7,8,8,7,6
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=powered_up
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=9,10,11,11,10,9
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=powered_left
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=12,13,14,14,13,12
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=powered_right
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=15,16,17,17,26,15
|
||||
[/animation]
|
||||
@@ -3,7 +3,7 @@ frame_height=20
|
||||
|
||||
[animation]
|
||||
name=default
|
||||
speed=8
|
||||
speed=0.1333
|
||||
loop=0
|
||||
frames=0,0,1
|
||||
[/animation]
|
||||
@@ -3,7 +3,7 @@ frame_height=20
|
||||
|
||||
[animation]
|
||||
name=default
|
||||
speed=8
|
||||
speed=0.1333
|
||||
loop=0
|
||||
frames=0,0,1
|
||||
[/animation]
|
||||
@@ -3,7 +3,7 @@ frame_height=39
|
||||
|
||||
[animation]
|
||||
name=default
|
||||
speed=6
|
||||
speed=0.1
|
||||
loop=0
|
||||
frames=0,1,2,3,4,5,6,7,8
|
||||
[/animation]
|
||||
@@ -3,7 +3,7 @@ frame_height=20
|
||||
|
||||
[animation]
|
||||
name=default
|
||||
speed=8
|
||||
speed=0.1333
|
||||
loop=0
|
||||
frames=0,0,1
|
||||
[/animation]
|
||||
@@ -3,7 +3,7 @@ frame_height=20
|
||||
|
||||
[animation]
|
||||
name=default
|
||||
speed=8
|
||||
speed=0.1333
|
||||
loop=0
|
||||
frames=0,0,1
|
||||
[/animation]
|
||||
@@ -3,7 +3,7 @@ frame_height=20
|
||||
|
||||
[animation]
|
||||
name=default
|
||||
speed=8
|
||||
speed=0.1333
|
||||
loop=0
|
||||
frames=0,0,1
|
||||
[/animation]
|
||||
@@ -3,7 +3,7 @@ frame_height=20
|
||||
|
||||
[animation]
|
||||
name=default
|
||||
speed=8
|
||||
speed=0.1333
|
||||
loop=0
|
||||
frames=0,0,1
|
||||
[/animation]
|
||||
@@ -3,133 +3,133 @@ frame_height=32
|
||||
|
||||
[animation]
|
||||
name=walk
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=0,1,2,3
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=stand
|
||||
speed=10
|
||||
speed=0.167
|
||||
loop=0
|
||||
frames=4,5,6,7
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=walk-fire-side
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=8,9,10,11
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=walk-recoil-side
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=12,13,14,15
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=walk-cool-side
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=16,17,18,19
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=stand-fire-side
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=20
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=stand-recoil-side
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=21
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=stand-cool-side
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=22
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=walk-fire-center
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=23,24,25,26
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=walk-recoil-center
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=27,28,29,30
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=walk-cool-center
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=31,32,33,34
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=stand-fire-center
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=35
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=stand-recoil-center
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=36
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=stand-cool-center
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=37
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=rolling
|
||||
speed=10
|
||||
speed=0.167
|
||||
loop=0
|
||||
frames=38,39,40,41
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=celebration
|
||||
speed=10
|
||||
loop=-1
|
||||
speed=0.167
|
||||
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
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=dizzy
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=47,48,49,50,51,52,53
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=recover
|
||||
speed=3
|
||||
speed=0.05
|
||||
loop=-1
|
||||
frames=54,54,54,54,55,56,57,58,58,58,59,60,61,58,59,60,61,58,59,60,61,62,62,62,62
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=hello
|
||||
speed=3
|
||||
speed=0.05
|
||||
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
|
||||
[/animation]
|
||||
@@ -3,7 +3,7 @@ frame_height=44
|
||||
|
||||
[animation]
|
||||
name=default
|
||||
speed=5
|
||||
speed=0.0833
|
||||
loop=0
|
||||
frames=0,1,2,3
|
||||
[/animation]
|
||||
@@ -3,14 +3,14 @@ frame_height=32
|
||||
|
||||
[animation]
|
||||
name=fly
|
||||
speed=2
|
||||
speed=0.0333
|
||||
loop=0
|
||||
frames=0,1
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=hit
|
||||
speed=2
|
||||
speed=0.0333
|
||||
loop=0
|
||||
frames=2,3
|
||||
[/animation]
|
||||
@@ -3,7 +3,7 @@ frame_height=16
|
||||
|
||||
[animation]
|
||||
name=default
|
||||
speed=8
|
||||
speed=0.1333
|
||||
loop=-1
|
||||
frames=0,1,2,3,4,5,6
|
||||
[/animation]
|
||||
@@ -27,6 +27,7 @@
|
||||
"[GAME_TEXT] 7": "Endavant!",
|
||||
"[GAME_TEXT] 8": "1.000.000 de punts!",
|
||||
"[GAME_TEXT] THANK_YOU": "Gracies!",
|
||||
"[GAME_TEXT] NEW_RECORD": "Nou record!",
|
||||
|
||||
"[HIGHSCORE_TABLE] CAPTION": "Millors puntuacions",
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"[GAME_TEXT] 7": "Get Ready!",
|
||||
"[GAME_TEXT] 8": "1,000,000 points!",
|
||||
"[GAME_TEXT] THANK_YOU": "Thank you!",
|
||||
"[GAME_TEXT] NEW_RECORD": "New record!",
|
||||
|
||||
"[HIGHSCORE_TABLE] CAPTION": "Best scores",
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"[GAME_TEXT] 7": "Adelante!",
|
||||
"[GAME_TEXT] 8": "1.000.000 de puntos!",
|
||||
"[GAME_TEXT] THANK_YOU": "Gracias!",
|
||||
"[GAME_TEXT] NEW_RECORD": "Nuevo record!",
|
||||
|
||||
"[HIGHSCORE_TABLE] CAPTION": "Mejores puntuaciones",
|
||||
|
||||
|
||||
BIN
data/music/congratulations.ogg
Normal file
BIN
data/sound/name_input_accept.wav
Normal file
BIN
data/sound/service_menu_back.wav
Normal file
BIN
define_buttons.o
43
development_guidelines.md
Normal 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
|
||||
@@ -9,22 +9,44 @@
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <utility> // Para pair
|
||||
|
||||
#include "texture.h" // Para Texture
|
||||
#include "utils.h" // Para printWithDots
|
||||
#include "resource_helper.h" // Para ResourceHelper
|
||||
#include "texture.h" // Para Texture
|
||||
#include "utils.h" // Para printWithDots
|
||||
|
||||
// Carga las animaciones en un vector(Animations) desde un fichero
|
||||
auto loadAnimationsFromFile(const std::string& file_path) -> AnimationsFileBuffer {
|
||||
std::ifstream file(file_path);
|
||||
if (!file) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str());
|
||||
throw std::runtime_error("Fichero no encontrado: " + file_path);
|
||||
// Intentar cargar desde ResourceHelper primero
|
||||
auto resource_data = ResourceHelper::loadFile(file_path);
|
||||
std::istringstream stream;
|
||||
bool using_resource_data = false;
|
||||
|
||||
if (!resource_data.empty()) {
|
||||
std::string content(resource_data.begin(), resource_data.end());
|
||||
stream.str(content);
|
||||
using_resource_data = true;
|
||||
}
|
||||
|
||||
// Fallback a archivo directo
|
||||
std::ifstream file;
|
||||
if (!using_resource_data) {
|
||||
file.open(file_path);
|
||||
if (!file) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str());
|
||||
throw std::runtime_error("Fichero no encontrado: " + file_path);
|
||||
}
|
||||
}
|
||||
|
||||
std::istream& input_stream = using_resource_data ? stream : static_cast<std::istream&>(file);
|
||||
|
||||
printWithDots("Animation : ", file_path.substr(file_path.find_last_of("\\/") + 1), "[ LOADED ]");
|
||||
|
||||
std::vector<std::string> buffer;
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
while (std::getline(input_stream, line)) {
|
||||
// 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()) {
|
||||
buffer.push_back(line);
|
||||
}
|
||||
@@ -64,33 +86,33 @@ auto AnimatedSprite::getAnimationIndex(const std::string& name) -> int {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Calcula el frame correspondiente a la animación
|
||||
void AnimatedSprite::animate() {
|
||||
// Calcula el frame correspondiente a la animación (time-based)
|
||||
void AnimatedSprite::animate(float deltaTime) {
|
||||
if (animations_[current_animation_].speed == 0 || animations_[current_animation_].paused) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calcula el frame actual a partir del contador
|
||||
animations_[current_animation_].current_frame = animations_[current_animation_].counter / animations_[current_animation_].speed;
|
||||
|
||||
// Si alcanza el final de la animación, reinicia el contador de la animación
|
||||
// en función de la variable loop y coloca el nuevo frame
|
||||
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
|
||||
animations_[current_animation_].current_frame = animations_[current_animation_].frames.size();
|
||||
animations_[current_animation_].completed = true;
|
||||
} else { // Si hay loop, vuelve al frame indicado
|
||||
animations_[current_animation_].counter = 0;
|
||||
animations_[current_animation_].current_frame = animations_[current_animation_].loop;
|
||||
// Acumular tiempo transcurrido
|
||||
animations_[current_animation_].time_accumulator += deltaTime;
|
||||
|
||||
// Verificar si es momento de cambiar 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_].loop == -1) { // Si no hay loop, deja el último frame
|
||||
animations_[current_animation_].current_frame = animations_[current_animation_].frames.size() - 1;
|
||||
animations_[current_animation_].completed = true;
|
||||
} else { // Si hay loop, vuelve al frame indicado
|
||||
animations_[current_animation_].time_accumulator = 0.0f;
|
||||
animations_[current_animation_].current_frame = animations_[current_animation_].loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
// En caso contrario
|
||||
else {
|
||||
// Escoge el frame correspondiente de la animación
|
||||
|
||||
// Actualizar el sprite clip
|
||||
updateSpriteClip();
|
||||
|
||||
// Incrementa el contador de la animacion
|
||||
animations_[current_animation_].counter++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,11 +129,11 @@ void AnimatedSprite::setCurrentAnimation(const std::string& name, bool reset) {
|
||||
current_animation_ = NEW_ANIMATION;
|
||||
if (reset) {
|
||||
animations_[current_animation_].current_frame = 0;
|
||||
animations_[current_animation_].counter = 0;
|
||||
animations_[current_animation_].time_accumulator = 0.0f;
|
||||
animations_[current_animation_].completed = false;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
updateSpriteClip();
|
||||
@@ -126,27 +148,27 @@ void AnimatedSprite::setCurrentAnimation(int index, bool reset) {
|
||||
current_animation_ = NEW_ANIMATION;
|
||||
if (reset) {
|
||||
animations_[current_animation_].current_frame = 0;
|
||||
animations_[current_animation_].counter = 0;
|
||||
animations_[current_animation_].time_accumulator = 0.0f;
|
||||
animations_[current_animation_].completed = false;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
updateSpriteClip();
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza las variables del objeto
|
||||
void AnimatedSprite::update() {
|
||||
animate();
|
||||
MovingSprite::update();
|
||||
// Actualiza las variables del objeto (time-based)
|
||||
void AnimatedSprite::update(float deltaTime) {
|
||||
animate(deltaTime);
|
||||
MovingSprite::update(deltaTime);
|
||||
}
|
||||
|
||||
// Reinicia la animación
|
||||
void AnimatedSprite::resetAnimation() {
|
||||
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_].paused = false;
|
||||
updateSpriteClip();
|
||||
@@ -172,6 +194,12 @@ void AnimatedSprite::loadFromAnimationsFileBuffer(const AnimationsFileBuffer& so
|
||||
// Pone un valor por defecto
|
||||
setWidth(config.frame_width);
|
||||
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
|
||||
@@ -241,7 +269,7 @@ void AnimatedSprite::processAnimationParameter(const std::string& line, Animatio
|
||||
if (key == "name") {
|
||||
animation.name = value;
|
||||
} else if (key == "speed") {
|
||||
animation.speed = std::stoi(value);
|
||||
animation.speed = std::stof(value);
|
||||
} else if (key == "loop") {
|
||||
animation.loop = std::stoi(value);
|
||||
} else if (key == "frames") {
|
||||
@@ -268,7 +296,7 @@ void AnimatedSprite::parseFramesParameter(const std::string& frames_str, Animati
|
||||
}
|
||||
|
||||
// Establece la velocidad de la animación
|
||||
void AnimatedSprite::setAnimationSpeed(size_t value) {
|
||||
void AnimatedSprite::setAnimationSpeed(float value) {
|
||||
animations_[current_animation_].speed = value;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,15 +17,15 @@ class Texture;
|
||||
|
||||
// --- Estructuras ---
|
||||
struct Animation {
|
||||
static constexpr int DEFAULT_SPEED = 5;
|
||||
static constexpr float DEFAULT_SPEED = 80.0F;
|
||||
|
||||
std::string name; // Nombre de 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)
|
||||
bool completed{false}; // Indica si la animación ha finalizado
|
||||
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
|
||||
|
||||
Animation() = default;
|
||||
@@ -50,18 +50,19 @@ class AnimatedSprite : public MovingSprite {
|
||||
// --- Constructores y destructor ---
|
||||
AnimatedSprite(std::shared_ptr<Texture> texture, const std::string& file_path);
|
||||
AnimatedSprite(std::shared_ptr<Texture> texture, const AnimationsFileBuffer& animations);
|
||||
explicit AnimatedSprite(std::shared_ptr<Texture> texture) : MovingSprite(std::move(texture)) {}
|
||||
explicit AnimatedSprite(std::shared_ptr<Texture> texture)
|
||||
: MovingSprite(std::move(texture)) {}
|
||||
~AnimatedSprite() override = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
void update() override; // Actualiza la animación
|
||||
void update(float deltaTime) override; // Actualiza la animación (time-based)
|
||||
|
||||
// --- Control de animaciones ---
|
||||
void setCurrentAnimation(const std::string& name = "default", bool reset = true); // Establece la animación por nombre
|
||||
void setCurrentAnimation(int index = 0, bool reset = true); // Establece la animación por índice
|
||||
void resetAnimation(); // Reinicia la animación actual
|
||||
void setAnimationSpeed(size_t value); // Establece la velocidad de la animación
|
||||
auto getAnimationSpeed() const -> size_t { return animations_[current_animation_].speed; } // Obtiene la velocidad de la animación actual
|
||||
void setAnimationSpeed(float value); // Establece la velocidad de la animación
|
||||
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 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
|
||||
@@ -77,7 +78,7 @@ class AnimatedSprite : public MovingSprite {
|
||||
int current_animation_ = 0; // Índice de la animación activa
|
||||
|
||||
// --- 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 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
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
#include <sstream> // Para basic_istringstream
|
||||
#include <stdexcept> // Para runtime_error
|
||||
|
||||
#include "utils.h" // Para getFileName
|
||||
#include "resource_helper.h" // Para ResourceHelper
|
||||
#include "utils.h" // Para getFileName
|
||||
|
||||
// Singleton
|
||||
Asset *Asset::instance = nullptr;
|
||||
@@ -139,6 +140,17 @@ auto Asset::get(const std::string &filename) const -> std::string {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Carga datos del archivo usando ResourceHelper
|
||||
auto Asset::loadData(const std::string &filename) const -> std::vector<uint8_t> {
|
||||
auto it = file_list_.find(filename);
|
||||
if (it != file_list_.end()) {
|
||||
return ResourceHelper::loadFile(it->second.file);
|
||||
}
|
||||
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Warning: file %s not found for data loading", filename.c_str());
|
||||
return {};
|
||||
}
|
||||
|
||||
// Verifica si un recurso existe
|
||||
auto Asset::exists(const std::string &filename) const -> bool {
|
||||
return file_list_.find(filename) != file_list_.end();
|
||||
@@ -194,9 +206,16 @@ auto Asset::check() const -> bool {
|
||||
|
||||
// Comprueba que existe un fichero
|
||||
auto Asset::checkFile(const std::string &path) -> bool {
|
||||
std::ifstream file(path);
|
||||
bool success = file.good();
|
||||
file.close();
|
||||
// Intentar primero con ResourceHelper
|
||||
auto data = ResourceHelper::loadFile(path);
|
||||
bool success = !data.empty();
|
||||
|
||||
// Si no se encuentra en el pack, intentar con filesystem directo
|
||||
if (!success) {
|
||||
std::ifstream file(path);
|
||||
success = file.good();
|
||||
file.close();
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // Para uint8_t
|
||||
#include <string> // Para string
|
||||
#include <unordered_map> // Para unordered_map
|
||||
#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 loadFromFile(const std::string &config_file_path, const std::string &prefix = "", const std::string &system_folder = ""); // Con soporte para variables
|
||||
[[nodiscard]] auto get(const std::string &filename) const -> std::string; // Mantener nombre original
|
||||
[[nodiscard]] auto loadData(const std::string &filename) const -> std::vector<uint8_t>; // Carga datos del archivo
|
||||
[[nodiscard]] auto check() const -> bool;
|
||||
[[nodiscard]] auto getListByType(Type type) const -> std::vector<std::string>;
|
||||
[[nodiscard]] auto exists(const std::string &filename) const -> bool; // Nueva función para verificar existencia
|
||||
@@ -45,7 +47,9 @@ class Asset {
|
||||
bool required; // Indica si el archivo es obligatorio
|
||||
|
||||
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 ---
|
||||
|
||||
106
source/asset_integrated.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#include "asset_integrated.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
bool AssetIntegrated::resource_pack_enabled_ = false;
|
||||
|
||||
void AssetIntegrated::initWithResourcePack(const std::string &executable_path,
|
||||
const std::string &resource_pack_path) {
|
||||
// Inicializar Asset normal
|
||||
Asset::init(executable_path);
|
||||
|
||||
// Inicializar ResourceLoader
|
||||
auto &loader = ResourceLoader::getInstance();
|
||||
if (loader.initialize(resource_pack_path, true)) {
|
||||
resource_pack_enabled_ = true;
|
||||
std::cout << "Asset system initialized with resource pack: " << resource_pack_path << std::endl;
|
||||
} else {
|
||||
resource_pack_enabled_ = false;
|
||||
std::cout << "Asset system initialized in fallback mode (filesystem)" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> AssetIntegrated::loadFile(const std::string &filename) {
|
||||
if (shouldUseResourcePack(filename) && resource_pack_enabled_) {
|
||||
// Intentar cargar del pack de recursos
|
||||
auto &loader = ResourceLoader::getInstance();
|
||||
|
||||
// Convertir ruta completa a ruta relativa para el pack
|
||||
std::string relativePath = filename;
|
||||
|
||||
// Si la ruta contiene "data/", extraer la parte relativa
|
||||
size_t dataPos = filename.find("data/");
|
||||
if (dataPos != std::string::npos) {
|
||||
relativePath = filename.substr(dataPos + 5); // +5 para saltar "data/"
|
||||
}
|
||||
|
||||
auto data = loader.loadResource(relativePath);
|
||||
if (!data.empty()) {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: cargar del filesystem
|
||||
std::ifstream file(filename, std::ios::binary | std::ios::ate);
|
||||
if (!file) {
|
||||
std::cerr << "Error: Could not open file: " << filename << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
std::streamsize fileSize = file.tellg();
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<uint8_t> data(fileSize);
|
||||
if (!file.read(reinterpret_cast<char *>(data.data()), fileSize)) {
|
||||
std::cerr << "Error: Could not read file: " << filename << std::endl;
|
||||
return {};
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
bool AssetIntegrated::fileExists(const std::string &filename) const {
|
||||
if (shouldUseResourcePack(filename) && resource_pack_enabled_) {
|
||||
auto &loader = ResourceLoader::getInstance();
|
||||
|
||||
// Convertir ruta completa a ruta relativa para el pack
|
||||
std::string relativePath = filename;
|
||||
size_t dataPos = filename.find("data/");
|
||||
if (dataPos != std::string::npos) {
|
||||
relativePath = filename.substr(dataPos + 5);
|
||||
}
|
||||
|
||||
if (loader.resourceExists(relativePath)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Verificar en filesystem
|
||||
return std::filesystem::exists(filename);
|
||||
}
|
||||
|
||||
std::string AssetIntegrated::getSystemPath(const std::string &filename) const {
|
||||
// Los archivos de sistema/config siempre van al filesystem
|
||||
return filename;
|
||||
}
|
||||
|
||||
bool AssetIntegrated::shouldUseResourcePack(const std::string &filepath) const {
|
||||
// Los archivos que NO van al pack:
|
||||
// - Archivos de config/ (ahora están fuera de data/)
|
||||
// - Archivos con absolute=true en assets.txt
|
||||
// - Archivos de sistema (${SYSTEM_FOLDER})
|
||||
|
||||
if (filepath.find("/config/") != std::string::npos ||
|
||||
filepath.find("config/") == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filepath.find("/data/") != std::string::npos ||
|
||||
filepath.find("data/") == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
29
source/asset_integrated.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "asset.h"
|
||||
#include "resource_loader.h"
|
||||
|
||||
// Extensión de Asset que integra ResourceLoader
|
||||
class AssetIntegrated : public Asset {
|
||||
public:
|
||||
// Inicializa Asset con ResourceLoader
|
||||
static void initWithResourcePack(const std::string &executable_path,
|
||||
const std::string &resource_pack_path = "resources.pack");
|
||||
|
||||
// Carga un archivo usando ResourceLoader como primera opción
|
||||
std::vector<uint8_t> loadFile(const std::string &filename);
|
||||
|
||||
// Verifica si un archivo existe (pack o filesystem)
|
||||
bool fileExists(const std::string &filename) const;
|
||||
|
||||
// Obtiene la ruta completa para archivos del sistema/config
|
||||
std::string getSystemPath(const std::string &filename) const;
|
||||
|
||||
private:
|
||||
static bool resource_pack_enabled_;
|
||||
|
||||
// Determina si un archivo debe cargarse del pack o del filesystem
|
||||
bool shouldUseResourcePack(const std::string &filepath) const;
|
||||
};
|
||||
@@ -100,13 +100,33 @@ void Audio::stopAllSounds() const {
|
||||
|
||||
// Realiza un fundido de salida de la música
|
||||
void Audio::fadeOutMusic(int milliseconds) const {
|
||||
if (music_enabled_) {
|
||||
if (music_enabled_ && getRealMusicState() == MusicState::PLAYING) {
|
||||
#ifndef NO_AUDIO
|
||||
JA_FadeOutMusic(milliseconds);
|
||||
#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
|
||||
void Audio::setSoundVolume(int sound_volume, Group group) const {
|
||||
if (sound_enabled_) {
|
||||
|
||||
@@ -13,6 +13,12 @@ class Audio {
|
||||
INTERFACE = 1 // Sonidos de la interfaz
|
||||
};
|
||||
|
||||
enum class MusicState {
|
||||
PLAYING, // Reproduciendo música
|
||||
PAUSED, // Música pausada
|
||||
STOPPED, // Música detenida
|
||||
};
|
||||
|
||||
// --- Constantes ---
|
||||
static constexpr int MAX_VOLUME = 100; // Volumen máximo
|
||||
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 setMusicVolume(int volume) const; // Ajustar volumen de música
|
||||
|
||||
private:
|
||||
// --- Enums privados ---
|
||||
enum class MusicState {
|
||||
PLAYING, // Reproduciendo música
|
||||
PAUSED, // Música pausada
|
||||
STOPPED, // Música detenida
|
||||
};
|
||||
// --- Getters para debug ---
|
||||
bool isEnabled() const { return enabled_; }
|
||||
bool isSoundEnabled() const { return sound_enabled_; }
|
||||
bool isMusicEnabled() const { return music_enabled_; }
|
||||
MusicState getMusicState() const { return music_.state; }
|
||||
MusicState getRealMusicState() const; // Consulta directamente a jailaudio
|
||||
const std::string& getCurrentMusicName() const { return music_.name; }
|
||||
|
||||
private:
|
||||
// --- Estructuras privadas ---
|
||||
struct Music {
|
||||
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
|
||||
|
||||
// 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
|
||||
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 ---
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "screen.h" // Para Screen
|
||||
#include "sprite.h" // Para Sprite
|
||||
#include "texture.h" // Para Texture
|
||||
#include "utils.h" // Para funciones de easing
|
||||
|
||||
// Constructor
|
||||
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),
|
||||
progress_per_stage_(total_progress_to_complete_ / STAGES),
|
||||
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)}),
|
||||
src_rect_({.x = 0, .y = 0, .w = 320, .h = 240}),
|
||||
@@ -93,20 +95,21 @@ void Background::initializeSprites() {
|
||||
|
||||
// Configura las propiedades iniciales de los sprites
|
||||
void Background::initializeSpriteProperties() {
|
||||
constexpr float TOP_CLOUDS_SPEED = 0.1F;
|
||||
constexpr float BOTTOM_CLOUDS_SPEED = 0.05F;
|
||||
// Velocidades iniciales que coinciden con updateCloudsSpeed() cuando progress=0
|
||||
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_->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_->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_->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_->setVelX(-BOTTOM_CLOUDS_SPEED);
|
||||
bottom_clouds_sprite_b_->setVelX(-INITIAL_BOTTOM_CLOUDS_SPEED_PX_PER_S);
|
||||
|
||||
buildings_sprite_->setY(base_ - buildings_sprite_->getHeight());
|
||||
grass_sprite_->setY(base_ - grass_sprite_->getHeight());
|
||||
@@ -126,20 +129,24 @@ void Background::initializeTextures() {
|
||||
}
|
||||
|
||||
// Actualiza la lógica del objeto
|
||||
void Background::update() {
|
||||
void Background::update(float delta_time) {
|
||||
// Actualiza la progresión y calcula transiciones
|
||||
if (!manual_mode_) {
|
||||
updateProgression();
|
||||
updateProgression(delta_time);
|
||||
}
|
||||
|
||||
// Actualiza el valor de alpha
|
||||
updateAlphaColorTexture();
|
||||
|
||||
// Actualiza las nubes
|
||||
updateClouds();
|
||||
updateClouds(delta_time);
|
||||
|
||||
// Calcula el frame de la hierba
|
||||
grass_sprite_->setSpriteClip(0, (10 * (counter_ / 20 % 2)), 320, 10);
|
||||
// Actualiza timer de hierba
|
||||
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
|
||||
alpha_ = std::max((255 - (int)(255 * transition_)), 0);
|
||||
@@ -148,9 +155,6 @@ void Background::update() {
|
||||
sun_sprite_->setPosition(sun_path_.at(sun_index_));
|
||||
moon_sprite_->setPosition(moon_path_.at(moon_index_));
|
||||
|
||||
// Incrementa el contador
|
||||
++counter_;
|
||||
|
||||
// Compone todos los elementos del fondo en la textura
|
||||
fillCanvas();
|
||||
}
|
||||
@@ -182,6 +186,12 @@ void Background::setProgress(float absolute_progress) {
|
||||
|
||||
// Cambia el estado del fondo
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -196,6 +206,10 @@ void Background::reset() {
|
||||
sun_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
|
||||
if (progress_callback_ && progress_ != old_progress) {
|
||||
progress_callback_(progress_);
|
||||
@@ -252,13 +266,24 @@ void Background::setMoonProgression(float progress) {
|
||||
}
|
||||
|
||||
// Actualiza la progresión y calcula las transiciones
|
||||
void Background::updateProgression() {
|
||||
// Si el juego está completado, reduce la progresión gradualmente
|
||||
void Background::updateProgression(float delta_time) {
|
||||
// Si el juego está completado, hacer transición suave con easing
|
||||
if (state_ == State::COMPLETED) {
|
||||
if (progress_ > MINIMUM_COMPLETED_PROGRESS) {
|
||||
progress_ -= COMPLETED_REDUCTION_RATE;
|
||||
completion_transition_timer_ += delta_time;
|
||||
|
||||
// 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 {
|
||||
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
|
||||
void Background::updateCloudsSpeed() {
|
||||
// Cálculo de velocidad según progreso
|
||||
constexpr float CLOUDS_INITIAL_SPEED = 0.05F;
|
||||
constexpr float CLOUDS_FINAL_SPEED = 2.00F - CLOUDS_INITIAL_SPEED;
|
||||
// Cálculo de velocidad según progreso (convertido de frame-based a time-based)
|
||||
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_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)
|
||||
float base_clouds_speed = (-CLOUDS_INITIAL_SPEED) +
|
||||
(-CLOUDS_FINAL_SPEED * (progress_ / total_progress_to_complete_));
|
||||
// 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_PX_PER_S) +
|
||||
(-CLOUDS_FINAL_SPEED_RANGE_PX_PER_S * (progress_ / total_progress_to_complete_));
|
||||
|
||||
// En estado completado, las nubes se ralentizan gradualmente
|
||||
if (state_ == State::COMPLETED) {
|
||||
float completion_factor = (progress_ - MINIMUM_COMPLETED_PROGRESS) /
|
||||
(total_progress_to_complete_ - MINIMUM_COMPLETED_PROGRESS);
|
||||
float completion_factor = (progress_ - minimum_completed_progress_) /
|
||||
(total_progress_to_complete_ - minimum_completed_progress_);
|
||||
completion_factor = std::max(0.1F, completion_factor);
|
||||
base_clouds_speed *= completion_factor;
|
||||
}
|
||||
@@ -314,12 +340,12 @@ void Background::updateCloudsSpeed() {
|
||||
}
|
||||
|
||||
// Actualiza las nubes
|
||||
void Background::updateClouds() {
|
||||
void Background::updateClouds(float deltaTime) {
|
||||
// Mueve las nubes
|
||||
top_clouds_sprite_a_->update();
|
||||
top_clouds_sprite_b_->update();
|
||||
bottom_clouds_sprite_a_->update();
|
||||
bottom_clouds_sprite_b_->update();
|
||||
top_clouds_sprite_a_->update(deltaTime);
|
||||
top_clouds_sprite_b_->update(deltaTime);
|
||||
bottom_clouds_sprite_a_->update(deltaTime);
|
||||
bottom_clouds_sprite_b_->update(deltaTime);
|
||||
|
||||
// Calcula el offset de las nubes
|
||||
if (top_clouds_sprite_a_->getPosX() < -top_clouds_sprite_a_->getWidth()) {
|
||||
|
||||
@@ -31,9 +31,9 @@ class Background {
|
||||
~Background(); // Destructor
|
||||
|
||||
// --- Métodos principales ---
|
||||
void update(); // Actualiza la lógica del objeto
|
||||
void render(); // Dibuja el objeto
|
||||
void reset(); // Reinicia la progresión
|
||||
void update(float delta_time); // Actualiza la lógica del objeto
|
||||
void render(); // Dibuja el objeto
|
||||
void reset(); // Reinicia la progresión
|
||||
|
||||
// --- Configuración ---
|
||||
void setPos(SDL_FRect pos); // Establece la posición del objeto
|
||||
@@ -60,10 +60,10 @@ class Background {
|
||||
|
||||
private:
|
||||
// --- Constantes ---
|
||||
static constexpr size_t STAGES = 4; // Número de etapas
|
||||
static constexpr float COMPLETED_REDUCTION_RATE = 25.0F; // Tasa de reducción completada
|
||||
static constexpr float MINIMUM_COMPLETED_PROGRESS = 200.0F; // Progreso mínimo completado
|
||||
static constexpr float SUN_COMPLETION_FACTOR = 0.5F; // Factor de completado del sol
|
||||
static constexpr size_t STAGES = 4; // Número de etapas
|
||||
static constexpr float MINIMUM_COMPLETED_PROGRESS_PERCENTAGE = 0.05F; // Porcentaje mínimo completado (10%)
|
||||
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 ---
|
||||
SDL_Renderer *renderer_; // Renderizador de la ventana
|
||||
@@ -90,46 +90,52 @@ class Background {
|
||||
const float total_progress_to_complete_; // Progreso total para completar
|
||||
const float progress_per_stage_; // Progreso por etapa
|
||||
const float sun_completion_progress_; // Progreso de completado del sol
|
||||
const float minimum_completed_progress_; // Progreso mínimo calculado dinámicamente
|
||||
ProgressCallback progress_callback_; // Callback para notificar cambios de progreso
|
||||
|
||||
// --- Variables de estado ---
|
||||
std::vector<SDL_FPoint> sun_path_; // Recorrido del sol
|
||||
std::vector<SDL_FPoint> moon_path_; // Recorrido de la luna
|
||||
std::array<SDL_FRect, STAGES> gradient_rect_; // Fondos degradados
|
||||
std::array<SDL_FRect, 4> top_clouds_rect_; // Nubes superiores
|
||||
std::array<SDL_FRect, 4> bottom_clouds_rect_; // Nubes inferiores
|
||||
SDL_FRect rect_; // Tamaño del objeto
|
||||
SDL_FRect src_rect_; // Parte del objeto para copiar en pantalla
|
||||
SDL_FRect dst_rect_; // Posición en pantalla donde se copia el objeto
|
||||
Color attenuate_color_; // Color de atenuación
|
||||
State state_ = State::NORMAL; // Estado actual
|
||||
float progress_ = 0.0F; // Progresión interna
|
||||
float clouds_speed_ = 0; // Velocidad de las nubes
|
||||
float transition_ = 0; // Porcentaje de transición
|
||||
size_t gradient_number_ = 0; // Índice de fondo degradado
|
||||
size_t counter_ = 0; // Contador interno
|
||||
size_t alpha_color_texture_ = 0; // Transparencia de atenuación
|
||||
size_t previous_alpha_color_texture_ = 0; // Transparencia anterior
|
||||
size_t sun_index_ = 0; // Índice del recorrido del sol
|
||||
size_t moon_index_ = 0; // Índice del recorrido de la luna
|
||||
int base_ = 0; // Posición base del fondo
|
||||
Uint8 alpha_ = 0; // Transparencia entre fases
|
||||
bool manual_mode_ = false; // Si está en modo manual
|
||||
std::vector<SDL_FPoint> sun_path_; // Recorrido del sol
|
||||
std::vector<SDL_FPoint> moon_path_; // Recorrido de la luna
|
||||
std::array<SDL_FRect, STAGES> gradient_rect_; // Fondos degradados
|
||||
std::array<SDL_FRect, 4> top_clouds_rect_; // Nubes superiores
|
||||
std::array<SDL_FRect, 4> bottom_clouds_rect_; // Nubes inferiores
|
||||
SDL_FRect rect_; // Tamaño del objeto
|
||||
SDL_FRect src_rect_; // Parte del objeto para copiar en pantalla
|
||||
SDL_FRect dst_rect_; // Posición en pantalla donde se copia el objeto
|
||||
Color attenuate_color_; // Color de atenuación
|
||||
State state_ = State::NORMAL; // Estado actual
|
||||
float progress_ = 0.0F; // Progresión interna
|
||||
float clouds_speed_ = 0; // Velocidad de las nubes
|
||||
float transition_ = 0; // Porcentaje de transición
|
||||
size_t gradient_number_ = 0; // Índice de fondo degradado
|
||||
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 previous_alpha_color_texture_ = 0; // Transparencia anterior
|
||||
size_t sun_index_ = 0; // Índice del recorrido del sol
|
||||
size_t moon_index_ = 0; // Índice del recorrido de la luna
|
||||
int base_ = 0; // Posición base del fondo
|
||||
Uint8 alpha_ = 0; // Transparencia entre fases
|
||||
bool manual_mode_ = false; // Si está en modo manual
|
||||
|
||||
// --- Variables 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 ---
|
||||
void initializePaths(); // Inicializa las rutas del sol y la luna
|
||||
void initializeRects(); // Inicializa los rectángulos de gradientes y nubes
|
||||
void initializeSprites(); // Crea los sprites
|
||||
void initializeSpriteProperties(); // Configura las propiedades iniciales de los sprites
|
||||
void initializeTextures(); // Inicializa las texturas de renderizado
|
||||
void updateProgression(); // Actualiza la progresión y calcula transiciones
|
||||
void updateCloudsSpeed(); // Actualiza la velocidad de las nubes según el estado
|
||||
void renderGradient(); // Dibuja el gradiente de fondo
|
||||
void renderTopClouds(); // Dibuja las nubes superiores
|
||||
void renderBottomClouds(); // Dibuja las nubes inferiores
|
||||
void fillCanvas(); // Compone todos los elementos en la textura
|
||||
void updateAlphaColorTexture(); // Actualiza el alpha de la textura de atenuación
|
||||
void updateClouds(); // Actualiza el movimiento de las nubes
|
||||
void createSunPath(); // Precalcula el recorrido del sol
|
||||
void createMoonPath(); // Precalcula el recorrido de la luna
|
||||
void initializePaths(); // Inicializa las rutas del sol y la luna
|
||||
void initializeRects(); // Inicializa los rectángulos de gradientes y nubes
|
||||
void initializeSprites(); // Crea los sprites
|
||||
void initializeSpriteProperties(); // Configura las propiedades iniciales de los sprites
|
||||
void initializeTextures(); // Inicializa las texturas de renderizado
|
||||
void updateProgression(float delta_time); // Actualiza la progresión y calcula transiciones
|
||||
void updateCloudsSpeed(); // Actualiza la velocidad de las nubes según el estado
|
||||
void renderGradient(); // Dibuja el gradiente de fondo
|
||||
void renderTopClouds(); // Dibuja las nubes superiores
|
||||
void renderBottomClouds(); // Dibuja las nubes inferiores
|
||||
void fillCanvas(); // Compone todos los elementos en la textura
|
||||
void updateAlphaColorTexture(); // Actualiza el alpha de la textura de atenuación
|
||||
void updateClouds(float deltaTime); // Actualiza el movimiento de las nubes (time-based)
|
||||
void createSunPath(); // Precalcula el recorrido del sol
|
||||
void createMoonPath(); // Precalcula el recorrido de la luna
|
||||
};
|
||||
@@ -11,24 +11,25 @@
|
||||
#include "texture.h" // Para Texture
|
||||
|
||||
// Constructor
|
||||
Balloon::Balloon(float x, float y, Type type, Size size, float vel_x, float speed, Uint16 creation_timer, SDL_FRect play_area, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation)
|
||||
: sprite_(std::make_unique<AnimatedSprite>(texture, animation)),
|
||||
x_(x),
|
||||
y_(y),
|
||||
vx_(vel_x),
|
||||
being_created_(creation_timer > 0),
|
||||
invulnerable_(creation_timer > 0),
|
||||
stopped_(creation_timer > 0),
|
||||
creation_counter_(creation_timer),
|
||||
creation_counter_ini_(creation_timer),
|
||||
type_(type),
|
||||
size_(size),
|
||||
speed_(speed),
|
||||
play_area_(play_area) {
|
||||
Balloon::Balloon(const Config& config)
|
||||
: sprite_(std::make_unique<AnimatedSprite>(config.texture, config.animation)),
|
||||
x_(config.x),
|
||||
y_(config.y),
|
||||
vx_(config.vel_x),
|
||||
being_created_(config.creation_counter > 0),
|
||||
invulnerable_(config.creation_counter > 0),
|
||||
stopped_(config.creation_counter > 0),
|
||||
creation_counter_(config.creation_counter),
|
||||
creation_counter_ini_(config.creation_counter),
|
||||
type_(config.type),
|
||||
size_(config.size),
|
||||
game_tempo_(config.game_tempo),
|
||||
play_area_(config.play_area),
|
||||
sound_(config.sound) {
|
||||
switch (type_) {
|
||||
case Type::BALLOON: {
|
||||
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_);
|
||||
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);
|
||||
menace_ = MENACE.at(INDEX);
|
||||
score_ = SCORE.at(INDEX);
|
||||
bouncing_sound_ = BOUNCING_SOUND.at(INDEX);
|
||||
popping_sound_ = POPPING_SOUND.at(INDEX);
|
||||
|
||||
sound_.bouncing_file = BOUNCING_SOUND.at(INDEX);
|
||||
sound_.popping_file = POPPING_SOUND.at(INDEX);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -52,27 +52,25 @@ Balloon::Balloon(float x, float y, Type type, Size size, float vel_x, float spee
|
||||
power_ = POWER.at(INDEX);
|
||||
menace_ = MENACE.at(INDEX);
|
||||
score_ = SCORE.at(INDEX);
|
||||
bouncing_sound_ = BOUNCING_SOUND.at(INDEX);
|
||||
popping_sound_ = POPPING_SOUND.at(INDEX);
|
||||
|
||||
sound_.bouncing_file = BOUNCING_SOUND.at(INDEX);
|
||||
sound_.popping_file = POPPING_SOUND.at(INDEX);
|
||||
break;
|
||||
}
|
||||
|
||||
case Type::POWERBALL: {
|
||||
constexpr int INDEX = 3;
|
||||
h_ = w_ = WIDTH.at(4);
|
||||
bouncing_sound_ = BOUNCING_SOUND.at(3);
|
||||
popping_sound_ = "power_ball_explosion.wav";
|
||||
sound_.bouncing_file = BOUNCING_SOUND.at(3);
|
||||
sound_.popping_file = "power_ball_explosion.wav";
|
||||
power_ = score_ = menace_ = 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;
|
||||
default_vy_ = param.balloon.settings.at(INDEX).vel;
|
||||
|
||||
sprite_->setRotate(creation_timer <= 0);
|
||||
sprite_->setRotateAmount(vx_ > 0.0F ? 2.0 : -2.0);
|
||||
|
||||
sprite_->setRotate(config.creation_counter <= 0);
|
||||
sprite_->setRotateAmount(vx_ > 0.0F ? 120.0 : -120.0); // Convert from 2 degrees/frame to 120 degrees/second
|
||||
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
|
||||
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
|
||||
@@ -137,19 +141,20 @@ void Balloon::render() {
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza la posición y estados del globo
|
||||
void Balloon::move() {
|
||||
// Actualiza la posición y estados del globo (time-based)
|
||||
void Balloon::move(float deltaTime) {
|
||||
if (isStopped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
handleHorizontalMovement();
|
||||
handleVerticalMovement();
|
||||
applyGravity();
|
||||
handleHorizontalMovement(deltaTime);
|
||||
handleVerticalMovement(deltaTime);
|
||||
applyGravity(deltaTime);
|
||||
}
|
||||
|
||||
void Balloon::handleHorizontalMovement() {
|
||||
x_ += vx_ * speed_;
|
||||
void Balloon::handleHorizontalMovement(float deltaTime) {
|
||||
// DeltaTime en segundos: velocidad (pixels/s) * tempo * tiempo (s)
|
||||
x_ += vx_ * game_tempo_ * deltaTime;
|
||||
|
||||
const int CLIP = 2;
|
||||
const float MIN_X = play_area_.x - CLIP;
|
||||
@@ -160,8 +165,9 @@ void Balloon::handleHorizontalMovement() {
|
||||
}
|
||||
}
|
||||
|
||||
void Balloon::handleVerticalMovement() {
|
||||
y_ += vy_ * speed_;
|
||||
void Balloon::handleVerticalMovement(float deltaTime) {
|
||||
// DeltaTime en segundos: velocidad (pixels/s) * tempo * tiempo (s)
|
||||
y_ += vy_ * game_tempo_ * deltaTime;
|
||||
|
||||
if (shouldCheckTopCollision()) {
|
||||
handleTopCollision();
|
||||
@@ -216,41 +222,37 @@ void Balloon::handleBottomCollision() {
|
||||
}
|
||||
}
|
||||
|
||||
void Balloon::applyGravity() {
|
||||
/*
|
||||
Para aplicar la gravedad, el diseño original la aplicaba en cada iteración del bucle
|
||||
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::applyGravity(float deltaTime) {
|
||||
// DeltaTime en segundos: aceleración (pixels/s²) * tempo * tiempo (s)
|
||||
vy_ += gravity_ * game_tempo_ * deltaTime;
|
||||
}
|
||||
|
||||
void Balloon::playBouncingSound() {
|
||||
if (bouncing_sound_enabled_) {
|
||||
playSound(bouncing_sound_);
|
||||
if (sound_.enabled && sound_.bouncing_enabled) {
|
||||
Audio::get()->playSound(sound_.bouncing_file);
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza al globo a su posicion, animación y controla los contadores
|
||||
void Balloon::update() {
|
||||
move();
|
||||
updateState();
|
||||
void Balloon::playPoppingSound() {
|
||||
if (sound_.enabled && sound_.poping_enabled) {
|
||||
Audio::get()->playSound(sound_.popping_file);
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza al globo a su posicion, animación y controla los contadores (time-based)
|
||||
void Balloon::update(float deltaTime) {
|
||||
move(deltaTime);
|
||||
updateState(deltaTime);
|
||||
updateBounceEffect();
|
||||
shiftSprite();
|
||||
shiftColliders();
|
||||
sprite_->update();
|
||||
++counter_;
|
||||
sprite_->update(deltaTime);
|
||||
// Contador interno con deltaTime en segundos
|
||||
counter_ += deltaTime;
|
||||
}
|
||||
|
||||
// Actualiza los estados del globo
|
||||
void Balloon::updateState() {
|
||||
// Actualiza los estados del globo (time-based)
|
||||
void Balloon::updateState(float deltaTime) {
|
||||
// Si se está creando
|
||||
if (isBeingCreated()) {
|
||||
// Actualiza el valor de las variables
|
||||
@@ -259,9 +261,14 @@ void Balloon::updateState() {
|
||||
|
||||
if (creation_counter_ > 0) {
|
||||
// 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_++;
|
||||
x_ += vx_;
|
||||
x_ += vx_ / 60.0f; // Convierte de pixels/segundo a pixels/frame para movimiento discreto
|
||||
|
||||
// Comprueba no se salga por los laterales
|
||||
const int MIN_X = play_area_.x;
|
||||
@@ -269,11 +276,12 @@ void Balloon::updateState() {
|
||||
|
||||
if (x_ < MIN_X || x_ > MAX_X) {
|
||||
// Corrige y cambia el sentido de la velocidad
|
||||
x_ -= vx_;
|
||||
x_ -= vx_ / 60.0f;
|
||||
vx_ = -vx_;
|
||||
}
|
||||
}
|
||||
--creation_counter_;
|
||||
creation_counter_ -= deltaTime;
|
||||
if (creation_counter_ < 0) creation_counter_ = 0;
|
||||
}
|
||||
|
||||
else {
|
||||
@@ -307,11 +315,14 @@ void Balloon::setAnimation() {
|
||||
}
|
||||
|
||||
// Establece el frame de animación
|
||||
std::string chosen_animation;
|
||||
if (use_reversed_colors_) {
|
||||
sprite_->setCurrentAnimation(creating_animation);
|
||||
chosen_animation = creating_animation;
|
||||
} else {
|
||||
sprite_->setCurrentAnimation(isBeingCreated() ? creating_animation : normal_animation);
|
||||
chosen_animation = isBeingCreated() ? creating_animation : normal_animation;
|
||||
}
|
||||
|
||||
sprite_->setCurrentAnimation(chosen_animation);
|
||||
}
|
||||
|
||||
// Detiene el globo
|
||||
@@ -368,23 +379,8 @@ void Balloon::useNormalColor() {
|
||||
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
|
||||
void Balloon::pop(bool should_sound) {
|
||||
if (should_sound) {
|
||||
if (poping_sound_enabled_) {
|
||||
playSound(popping_sound_);
|
||||
}
|
||||
}
|
||||
|
||||
if (should_sound) { playPoppingSound(); }
|
||||
enabled_ = false;
|
||||
}
|
||||
168
source/balloon.h
@@ -25,15 +25,23 @@ class Balloon {
|
||||
static constexpr std::array<int, 5> WIDTH = {10, 16, 26, 48, 49};
|
||||
|
||||
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 = {
|
||||
"balloon_pop0.wav", "balloon_pop1.wav", "balloon_pop2.wav", "balloon_pop3.wav"};
|
||||
"balloon_pop0.wav",
|
||||
"balloon_pop1.wav",
|
||||
"balloon_pop2.wav",
|
||||
"balloon_pop3.wav"};
|
||||
|
||||
static constexpr float VELX_POSITIVE = 0.7F;
|
||||
static constexpr float VELX_NEGATIVE = -0.7F;
|
||||
// Velocidades horizontales en pixels/segundo (convertidas desde 0.7 pixels/frame a 60fps)
|
||||
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_COUNTER = 8;
|
||||
@@ -52,26 +60,40 @@ class Balloon {
|
||||
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 ---
|
||||
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(const Config& config);
|
||||
~Balloon() = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
void alignTo(int x); // Centra el globo en la posición X
|
||||
void render(); // Pinta el globo en la pantalla
|
||||
void move(); // Actualiza la posición y estados del globo
|
||||
void update(); // Actualiza el globo (posición, animación, contadores)
|
||||
void stop(); // Detiene el globo
|
||||
void alignTo(int x); // Centra el globo en la posición X
|
||||
void render(); // Pinta el globo en la pantalla
|
||||
void move(float deltaTime); // Actualiza la posición y estados del globo (time-based)
|
||||
void update(float deltaTime); // Actualiza el globo (posición, animación, contadores) (time-based)
|
||||
void stop(); // Detiene el globo
|
||||
void start(); // Pone el globo en movimiento
|
||||
void pop(bool should_sound = false); // Explota el globo
|
||||
|
||||
@@ -100,11 +122,11 @@ class Balloon {
|
||||
|
||||
// --- Setters ---
|
||||
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 setBouncingSound(bool value) { bouncing_sound_enabled_ = value; }
|
||||
void setPoppingSound(bool value) { poping_sound_enabled_ = value; }
|
||||
void setSound(bool value) { sound_enabled_ = value; }
|
||||
void setBouncingSound(bool value) { sound_.bouncing_enabled = value; }
|
||||
void setPoppingSound(bool value) { sound_.poping_enabled = value; }
|
||||
void setSound(bool value) { sound_.enabled = value; }
|
||||
|
||||
private:
|
||||
// --- Estructura para el efecto de rebote ---
|
||||
@@ -114,10 +136,28 @@ class Balloon {
|
||||
|
||||
// Tablas de valores predefinidos para el efecto de rebote
|
||||
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 = {
|
||||
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
|
||||
bool enabled_ = false; // Si el efecto está activo
|
||||
@@ -203,52 +243,48 @@ class Balloon {
|
||||
std::unique_ptr<AnimatedSprite> sprite_; // Sprite del objeto globo
|
||||
|
||||
// --- Variables de estado y físicas ---
|
||||
float x_; // Posición X
|
||||
float y_; // Posición Y
|
||||
float w_; // Ancho
|
||||
float h_; // Alto
|
||||
float vx_; // Velocidad X
|
||||
float vy_; // Velocidad Y
|
||||
float gravity_; // Aceleración en Y
|
||||
float default_vy_; // Velocidad inicial al rebotar
|
||||
float max_vy_; // Máxima velocidad en Y
|
||||
bool being_created_; // Si el globo se está creando
|
||||
bool enabled_ = true; // Si el globo está activo
|
||||
bool invulnerable_; // Si el globo es invulnerable
|
||||
bool stopped_; // Si el globo está parado
|
||||
bool use_reversed_colors_ = false; // Si se usa el color alternativo
|
||||
Circle collider_; // Círculo de colisión
|
||||
Uint16 creation_counter_; // Temporizador de creación
|
||||
Uint16 creation_counter_ini_; // Valor inicial del temporizador de creación
|
||||
Uint16 score_; // Puntos al destruir el globo
|
||||
Type type_; // Tipo de globo
|
||||
Size size_; // Tamaño de globo
|
||||
Uint8 menace_; // Amenaza que genera el globo
|
||||
Uint32 counter_ = 0; // Contador interno
|
||||
float travel_y_ = 1.0F; // Distancia a recorrer en Y antes de aplicar gravedad
|
||||
float speed_; // Velocidad del globo
|
||||
Uint8 power_; // Poder que alberga el globo
|
||||
SDL_FRect play_area_; // Zona de movimiento del globo
|
||||
std::string bouncing_sound_; // Archivo de sonido al rebotar
|
||||
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
|
||||
float x_; // Posición X
|
||||
float y_; // Posición Y
|
||||
float w_; // Ancho
|
||||
float h_; // Alto
|
||||
float vx_; // Velocidad X
|
||||
float vy_; // Velocidad Y
|
||||
float gravity_; // Aceleración en Y
|
||||
float default_vy_; // Velocidad inicial al rebotar
|
||||
float max_vy_; // Máxima velocidad en Y
|
||||
bool being_created_; // Si el globo se está creando
|
||||
bool enabled_ = true; // Si el globo está activo
|
||||
bool invulnerable_; // Si el globo es invulnerable
|
||||
bool stopped_; // Si el globo está parado
|
||||
bool use_reversed_colors_ = false; // Si se usa el color alternativo
|
||||
Circle collider_; // Círculo de colisión
|
||||
float creation_counter_; // Temporizador de creación
|
||||
float creation_counter_ini_; // Valor inicial del temporizador de creación
|
||||
Uint16 score_; // Puntos al destruir el globo
|
||||
Type type_; // Tipo de globo
|
||||
Size size_; // Tamaño de globo
|
||||
Uint8 menace_; // Amenaza que genera el globo
|
||||
Uint32 counter_ = 0; // Contador interno
|
||||
float game_tempo_; // Multiplicador de tempo del juego
|
||||
float movement_accumulator_ = 0.0f; // Acumulador para movimiento durante creación (deltaTime)
|
||||
Uint8 power_; // Poder que alberga el globo
|
||||
SDL_FRect play_area_; // Zona de movimiento del globo
|
||||
Sound sound_; // Configuración de sonido del globo
|
||||
BounceEffect bounce_effect_; // Efecto de rebote
|
||||
|
||||
// --- Posicionamiento y transformación ---
|
||||
void shiftColliders(); // Alinea el círculo de colisión con el sprite
|
||||
void shiftSprite(); // Alinea el sprite en pantalla
|
||||
|
||||
// --- Animación y sonido ---
|
||||
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 setAnimation(); // Establece la animación correspondiente
|
||||
void playBouncingSound(); // Reproduce el sonido de rebote
|
||||
void playPoppingSound(); // Reproduce el sonido de reventar
|
||||
|
||||
// --- Movimiento y física ---
|
||||
void handleHorizontalMovement(); // Maneja el movimiento horizontal
|
||||
void handleVerticalMovement(); // Maneja el movimiento vertical
|
||||
void applyGravity(); // Aplica la gravedad al objeto
|
||||
void handleHorizontalMovement(float deltaTime); // Maneja el movimiento horizontal (time-based)
|
||||
void handleVerticalMovement(float deltaTime); // Maneja el movimiento vertical (time-based)
|
||||
void applyGravity(float deltaTime); // Aplica la gravedad al objeto (time-based)
|
||||
|
||||
// --- Rebote ---
|
||||
void enableBounceEffect(); // Activa el efecto de rebote
|
||||
@@ -263,5 +299,5 @@ class Balloon {
|
||||
void handleBottomCollision(); // Maneja la colisión inferior
|
||||
|
||||
// --- Lógica de estado ---
|
||||
void updateState(); // Actualiza los estados del globo
|
||||
void updateState(float deltaTime); // Actualiza los estados del globo (time-based)
|
||||
};
|
||||
@@ -155,7 +155,7 @@ auto BalloonFormations::parseBalloonLine(const std::string& line, const std::map
|
||||
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);
|
||||
} catch (const std::exception&) {
|
||||
@@ -168,7 +168,7 @@ auto BalloonFormations::evaluateExpression(const std::string& expr, const std::m
|
||||
|
||||
// Si es un número directo
|
||||
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
|
||||
@@ -205,7 +205,7 @@ auto BalloonFormations::evaluateSimpleExpression(const std::string& expr, const
|
||||
}
|
||||
|
||||
// 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 {
|
||||
@@ -235,10 +235,10 @@ void BalloonFormations::createFloaterVariants() {
|
||||
#ifdef _DEBUG
|
||||
void BalloonFormations::addTestFormation() {
|
||||
std::vector<SpawnParams> test_params = {
|
||||
{10, -BLOCK, 0, Balloon::Type::FLOATER, Balloon::Size::SMALL, 200},
|
||||
{50, -BLOCK, 0, Balloon::Type::FLOATER, Balloon::Size::MEDIUM, 200},
|
||||
{90, -BLOCK, 0, Balloon::Type::FLOATER, Balloon::Size::LARGE, 200},
|
||||
{140, -BLOCK, 0, Balloon::Type::FLOATER, Balloon::Size::EXTRALARGE, 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, 3.334f}, // 200 frames ÷ 60fps = 3.334s
|
||||
{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, 3.334f}}; // 200 frames ÷ 60fps = 3.334s
|
||||
|
||||
formations_.at(99) = Formation(test_params);
|
||||
}
|
||||
|
||||
@@ -15,19 +15,24 @@ class BalloonFormations {
|
||||
public:
|
||||
// --- Estructuras ---
|
||||
struct SpawnParams {
|
||||
int x = 0; // Posición en el eje X donde crear el globo
|
||||
int y = 0; // Posición en el eje Y donde crear el globo
|
||||
float x = 0; // Posición en el eje X 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
|
||||
Balloon::Type type = Balloon::Type::BALLOON; // Tipo 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
|
||||
SpawnParams() = default;
|
||||
|
||||
// Constructor con parámetros
|
||||
SpawnParams(int x, int y, float vel_x, Balloon::Type type, Balloon::Size size, int creation_counter)
|
||||
: x(x), y(y), vel_x(vel_x), type(type), size(size), creation_counter(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) {}
|
||||
};
|
||||
|
||||
struct Formation {
|
||||
@@ -77,7 +82,8 @@ class BalloonFormations {
|
||||
private:
|
||||
// --- Constantes ---
|
||||
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 ---
|
||||
std::vector<Formation> formations_; // Vector con todas las formaciones disponibles
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
|
||||
// Constructor
|
||||
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
|
||||
void BalloonManager::init() {
|
||||
@@ -60,13 +62,13 @@ void BalloonManager::init() {
|
||||
explosions_->addTexture(3, explosions_textures_.at(3), explosions_animations_.at(3));
|
||||
}
|
||||
|
||||
// Actualiza
|
||||
void BalloonManager::update() {
|
||||
// Actualiza (time-based)
|
||||
void BalloonManager::update(float deltaTime) {
|
||||
for (const auto &balloon : balloons_) {
|
||||
balloon->update();
|
||||
balloon->update(deltaTime);
|
||||
}
|
||||
updateBalloonDeployCounter();
|
||||
explosions_->update();
|
||||
updateBalloonDeployCounter(deltaTime);
|
||||
explosions_->update(deltaTime);
|
||||
}
|
||||
|
||||
// Renderiza los objetos
|
||||
@@ -79,12 +81,12 @@ void BalloonManager::render() {
|
||||
|
||||
// Crea una formación de globos
|
||||
void BalloonManager::deployRandomFormation(int stage) {
|
||||
// Solo despliega una formación enemiga si ha pasado cierto tiempo desde la última
|
||||
if (balloon_deploy_counter_ == 0) {
|
||||
// Solo despliega una formación enemiga si el timer ha llegado a cero
|
||||
if (balloon_deploy_counter_ <= 0.0f) {
|
||||
// En este punto se decide entre crear una powerball o una formación enemiga
|
||||
if ((rand() % 100 < 15) && (canPowerBallBeCreated())) {
|
||||
createPowerBall(); // Crea una powerball
|
||||
balloon_deploy_counter_ = 10; // Da un poco de margen para que se creen mas globos
|
||||
createPowerBall(); // Crea una powerball
|
||||
balloon_deploy_counter_ = POWERBALL_DEPLOY_DELAY; // Resetea con pequeño retraso
|
||||
} else {
|
||||
// Decrementa el contador de despliegues de globos necesarios para la siguiente PowerBall
|
||||
if (power_ball_counter_ > 0) {
|
||||
@@ -105,11 +107,19 @@ void BalloonManager::deployRandomFormation(int stage) {
|
||||
// Crea los globos de la formación
|
||||
const auto BALLOONS = balloon_formations_->getFormationFromPool(stage, formation_id).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
|
||||
balloon_deploy_counter_ = DEFAULT_BALLOON_DEPLOY_COUNTER;
|
||||
// Reinicia el timer para el próximo despliegue
|
||||
balloon_deploy_counter_ = DEFAULT_BALLOON_DEPLOY_DELAY;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,15 +128,31 @@ void BalloonManager::deployRandomFormation(int stage) {
|
||||
void BalloonManager::deployFormation(int formation_id) {
|
||||
const auto BALLOONS = balloon_formations_->getFormation(formation_id).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
|
||||
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;
|
||||
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());
|
||||
}
|
||||
|
||||
// Actualiza la variable enemyDeployCounter
|
||||
void BalloonManager::updateBalloonDeployCounter() {
|
||||
if (balloon_deploy_counter_ > 0) {
|
||||
--balloon_deploy_counter_;
|
||||
}
|
||||
// Actualiza el timer de despliegue de globos (time-based)
|
||||
void BalloonManager::updateBalloonDeployCounter(float deltaTime) {
|
||||
// DeltaTime en segundos - timer decrementa hasta llegar a cero
|
||||
balloon_deploy_counter_ -= deltaTime;
|
||||
}
|
||||
|
||||
// Indica si se puede crear una powerball
|
||||
@@ -152,13 +177,16 @@ auto BalloonManager::calculateScreenPower() -> int {
|
||||
}
|
||||
|
||||
// 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_) {
|
||||
const int INDEX = static_cast<int>(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)));
|
||||
balloons_.back()->setSound(sound_enabled_);
|
||||
balloons_.back()->setBouncingSound(bouncing_sound_enabled_);
|
||||
balloons_.back()->setPoppingSound(poping_sound_enabled_);
|
||||
const int INDEX = static_cast<int>(config.size);
|
||||
config.play_area = play_area_;
|
||||
config.texture = balloon_textures_.at(INDEX);
|
||||
config.animation = balloon_animations_.at(INDEX);
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
if (can_deploy_balloons_) {
|
||||
// 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 CHILD_HEIGHT = Balloon::WIDTH.at(static_cast<int>(balloon->getSize()) - 1);
|
||||
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 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
|
||||
auto b = createBalloon(x, Y, balloon->getType(), SIZE, VX, balloon_speed_, 0);
|
||||
auto b = createBalloon(config);
|
||||
|
||||
// Establece parametros
|
||||
b->setVelY(b->getType() == Balloon::Type::BALLOON ? -2.50F : Balloon::VELX_NEGATIVE * 2.0F);
|
||||
// Establece parametros (deltaTime en segundos - velocidades en pixels/segundo)
|
||||
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
|
||||
if (balloon->isStopped()) { b->stop(); }
|
||||
@@ -196,18 +230,32 @@ void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon> &balloon,
|
||||
void BalloonManager::createPowerBall() {
|
||||
if (can_deploy_balloons_) {
|
||||
constexpr int VALUES = 6;
|
||||
constexpr float POS_Y = -Balloon::WIDTH.at(4);
|
||||
constexpr int CREATION_TIME = 0;
|
||||
const int LUCK = rand() % VALUES;
|
||||
|
||||
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 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> 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);
|
||||
|
||||
power_ball_enabled_ = true;
|
||||
@@ -219,7 +267,7 @@ void BalloonManager::createPowerBall() {
|
||||
void BalloonManager::setBalloonSpeed(float speed) {
|
||||
balloon_speed_ = speed;
|
||||
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);
|
||||
score = destroyAllBalloons();
|
||||
power_ball_enabled_ = false;
|
||||
balloon_deploy_counter_ = 20;
|
||||
balloon_deploy_counter_ = BALLOON_POP_DELAY; // Resetea con retraso
|
||||
} else {
|
||||
score = balloon->getScore();
|
||||
if (balloon->getSize() != Balloon::Size::SMALL) {
|
||||
@@ -288,8 +336,8 @@ auto BalloonManager::destroyAllBalloons() -> int {
|
||||
score += destroyBalloon(balloon);
|
||||
}
|
||||
|
||||
balloon_deploy_counter_ = 300;
|
||||
Screen::get()->flash(Colors::FLASH, 3);
|
||||
balloon_deploy_counter_ = DEFAULT_BALLOON_DEPLOY_DELAY;
|
||||
Screen::get()->flash(Colors::FLASH, 0.05F);
|
||||
Screen::get()->shake();
|
||||
|
||||
return score;
|
||||
@@ -298,7 +346,9 @@ auto BalloonManager::destroyAllBalloons() -> int {
|
||||
// Detiene todos los globos
|
||||
void BalloonManager::stopAllBalloons() {
|
||||
for (auto &balloon : balloons_) {
|
||||
balloon->stop();
|
||||
if (!balloon->isBeingCreated()) {
|
||||
balloon->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,19 +382,6 @@ void BalloonManager::createTwoBigBalloons() {
|
||||
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
|
||||
auto BalloonManager::getMenace() -> int {
|
||||
return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon) { return sum + (balloon->isEnabled() ? balloon->getMenace() : 0); });
|
||||
|
||||
@@ -28,29 +28,28 @@ class BalloonManager {
|
||||
~BalloonManager() = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
void update(); // Actualiza el estado de los globos
|
||||
void render(); // Renderiza los globos en pantalla
|
||||
void update(float deltaTime); // Actualiza el estado de los globos (time-based)
|
||||
void render(); // Renderiza los globos en pantalla
|
||||
|
||||
// --- Gestión de globos ---
|
||||
void freeBalloons(); // Libera globos que ya no sirven
|
||||
|
||||
// --- Creación de formaciones enemigas ---
|
||||
void deployRandomFormation(int stage); // Crea una formación de globos aleatoria
|
||||
void deployFormation(int formation_id); // Crea una formación específica
|
||||
void deployFormation(int formation_id, int y); // Crea una formación específica con coordenadas
|
||||
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, float y); // Crea una formación específica con coordenadas
|
||||
|
||||
// --- Creación de globos ---
|
||||
auto createBalloon(float x, int y, Balloon::Type type, Balloon::Size size, float velx, float speed, int creation_timer) -> std::shared_ptr<Balloon>; // Crea un nuevo globo
|
||||
void createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction); // Crea un globo a partir de otro
|
||||
void createPowerBall(); // Crea una PowerBall
|
||||
void createTwoBigBalloons(); // Crea dos globos grandes
|
||||
void createRandomBalloons(); // Crea una disposición aleatoria de globos
|
||||
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 createPowerBall(); // Crea una PowerBall
|
||||
void createTwoBigBalloons(); // Crea dos globos grandes
|
||||
|
||||
// --- Control de velocidad y despliegue ---
|
||||
void setBalloonSpeed(float speed); // Ajusta la velocidad de los globos
|
||||
void setDefaultBalloonSpeed(float speed) { default_balloon_speed_ = speed; }; // Establece la velocidad base
|
||||
void resetBalloonSpeed() { setBalloonSpeed(default_balloon_speed_); }; // Restablece la velocidad de los globos
|
||||
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 calculateScreenPower() -> int; // Calcula el poder de los globos en pantalla
|
||||
|
||||
@@ -83,7 +82,9 @@ class BalloonManager {
|
||||
|
||||
private:
|
||||
// --- 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 ---
|
||||
Balloons balloons_; // Vector con los globos activos
|
||||
@@ -97,9 +98,9 @@ class BalloonManager {
|
||||
|
||||
// --- Variables de estado ---
|
||||
SDL_FRect play_area_ = param.game.play_area.rect;
|
||||
float balloon_speed_ = Balloon::SPEED.at(0);
|
||||
float default_balloon_speed_ = Balloon::SPEED.at(0);
|
||||
int balloon_deploy_counter_ = 0;
|
||||
float balloon_speed_ = Balloon::GAME_TEMPO.at(0);
|
||||
float default_balloon_speed_ = Balloon::GAME_TEMPO.at(0);
|
||||
float balloon_deploy_counter_ = 0;
|
||||
int power_ball_counter_ = 0;
|
||||
int last_balloon_deploy_ = 0;
|
||||
bool power_ball_enabled_ = false;
|
||||
|
||||
@@ -60,21 +60,22 @@ void Bullet::render() {
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el estado del objeto
|
||||
auto Bullet::update() -> BulletMoveStatus {
|
||||
sprite_->update();
|
||||
return move();
|
||||
// Actualiza el estado del objeto (time-based)
|
||||
auto Bullet::update(float deltaTime) -> BulletMoveStatus {
|
||||
sprite_->update(deltaTime);
|
||||
return move(deltaTime);
|
||||
}
|
||||
|
||||
// Implementación del movimiento usando BulletMoveStatus
|
||||
auto Bullet::move() -> BulletMoveStatus {
|
||||
pos_x_ += vel_x_;
|
||||
// Implementación del movimiento usando BulletMoveStatus (time-based)
|
||||
auto Bullet::move(float deltaTime) -> BulletMoveStatus {
|
||||
// DeltaTime puro: velocidad (pixels/segundo) * tiempo (segundos)
|
||||
pos_x_ += vel_x_ * deltaTime;
|
||||
if (pos_x_ < param.game.play_area.rect.x - WIDTH || pos_x_ > param.game.play_area.rect.w) {
|
||||
disable();
|
||||
return BulletMoveStatus::OUT;
|
||||
}
|
||||
|
||||
pos_y_ += VEL_Y;
|
||||
pos_y_ += VEL_Y * deltaTime;
|
||||
if (pos_y_ < param.game.play_area.rect.y - HEIGHT) {
|
||||
disable();
|
||||
return BulletMoveStatus::OUT;
|
||||
|
||||
@@ -34,9 +34,9 @@ class Bullet {
|
||||
~Bullet() = default; // Destructor
|
||||
|
||||
// --- Métodos principales ---
|
||||
void render(); // Dibuja la bala en pantalla
|
||||
auto update() -> BulletMoveStatus; // Actualiza el estado del objeto
|
||||
void disable(); // Desactiva la bala
|
||||
void render(); // Dibuja la bala en pantalla
|
||||
auto update(float deltaTime) -> BulletMoveStatus; // Actualiza el estado del objeto (time-based)
|
||||
void disable(); // Desactiva la bala
|
||||
|
||||
// --- Getters ---
|
||||
[[nodiscard]] auto isEnabled() const -> bool; // Comprueba si está activa
|
||||
@@ -45,10 +45,10 @@ class Bullet {
|
||||
|
||||
private:
|
||||
// --- Constantes ---
|
||||
static constexpr float VEL_Y = -3.0F; // Velocidad vertical
|
||||
static constexpr float VEL_X_LEFT = -2.0F; // Velocidad izquierda
|
||||
static constexpr float VEL_X_RIGHT = 2.0F; // Velocidad derecha
|
||||
static constexpr float VEL_X_CENTER = 0.0F; // Velocidad central
|
||||
static constexpr float VEL_Y = -180.0F; // Velocidad vertical (pixels/segundo) - era -0.18F pixels/ms
|
||||
static constexpr float VEL_X_LEFT = -120.0F; // Velocidad izquierda (pixels/segundo) - era -0.12F pixels/ms
|
||||
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
|
||||
|
||||
// --- Objetos y punteros ---
|
||||
std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los gráficos
|
||||
@@ -64,7 +64,7 @@ class Bullet {
|
||||
// --- Métodos internos ---
|
||||
void shiftColliders(); // Ajusta el círculo de colisión
|
||||
void shiftSprite(); // Ajusta el sprite
|
||||
auto move() -> BulletMoveStatus; // Mueve la bala y devuelve su estado
|
||||
auto move(float deltaTime) -> BulletMoveStatus; // 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 buildAnimationString(BulletType bullet_type, bool powered) -> std::string; // Construye el string de animación
|
||||
};
|
||||
|
||||
110
source/color.cpp
@@ -116,71 +116,71 @@ constexpr auto Color::hsvToRgb(HSV hsv) -> Color {
|
||||
|
||||
// Implementaciones del namespace Colors
|
||||
namespace Colors {
|
||||
// Obtiene un color del vector de colores imitando al Coche Fantástico
|
||||
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color {
|
||||
int cycle_length = (colors.size() * 2) - 2;
|
||||
size_t n = counter % cycle_length;
|
||||
// Obtiene un color del vector de colores imitando al Coche Fantástico
|
||||
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color {
|
||||
int cycle_length = (colors.size() * 2) - 2;
|
||||
size_t n = counter % cycle_length;
|
||||
|
||||
size_t index;
|
||||
if (n < colors.size()) {
|
||||
index = n; // Avanza: 0,1,2,3
|
||||
} else {
|
||||
index = 2 * (colors.size() - 1) - n; // Retrocede: 2,1
|
||||
}
|
||||
|
||||
return colors[index];
|
||||
size_t index;
|
||||
if (n < colors.size()) {
|
||||
index = n; // Avanza: 0,1,2,3
|
||||
} else {
|
||||
index = 2 * (colors.size() - 1) - n; // Retrocede: 2,1
|
||||
}
|
||||
|
||||
auto generateMirroredCycle(Color base, ColorCycleStyle style) -> Cycle {
|
||||
Cycle result{};
|
||||
HSV base_hsv = Color::rgbToHsv(base);
|
||||
return colors[index];
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < CYCLE_SIZE; ++i) {
|
||||
float t = static_cast<float>(i) / (CYCLE_SIZE - 1); // 0 → 1
|
||||
float hue_shift = 0.0F;
|
||||
float sat_shift = 0.0F;
|
||||
float val_shift = 0.0F;
|
||||
auto generateMirroredCycle(Color base, ColorCycleStyle style) -> Cycle {
|
||||
Cycle result{};
|
||||
HSV base_hsv = Color::rgbToHsv(base);
|
||||
|
||||
switch (style) {
|
||||
case ColorCycleStyle::SUBTLE_PULSE:
|
||||
// Solo brillo suave
|
||||
val_shift = 0.07F * sinf(t * M_PI);
|
||||
break;
|
||||
for (size_t i = 0; i < CYCLE_SIZE; ++i) {
|
||||
float t = static_cast<float>(i) / (CYCLE_SIZE - 1); // 0 → 1
|
||||
float hue_shift = 0.0F;
|
||||
float sat_shift = 0.0F;
|
||||
float val_shift = 0.0F;
|
||||
|
||||
case ColorCycleStyle::HUE_WAVE:
|
||||
// Oscilación leve de tono
|
||||
hue_shift = 15.0F * (t - 0.5F) * 2.0F;
|
||||
val_shift = 0.05F * sinf(t * M_PI);
|
||||
break;
|
||||
switch (style) {
|
||||
case ColorCycleStyle::SUBTLE_PULSE:
|
||||
// Solo brillo suave
|
||||
val_shift = 0.07F * sinf(t * M_PI);
|
||||
break;
|
||||
|
||||
case ColorCycleStyle::VIBRANT:
|
||||
// Cambios fuertes en tono y brillo
|
||||
hue_shift = 35.0F * sinf(t * M_PI);
|
||||
val_shift = 0.2F * sinf(t * M_PI);
|
||||
sat_shift = -0.2F * sinf(t * M_PI);
|
||||
break;
|
||||
case ColorCycleStyle::HUE_WAVE:
|
||||
// Oscilación leve de tono
|
||||
hue_shift = 15.0F * (t - 0.5F) * 2.0F;
|
||||
val_shift = 0.05F * sinf(t * M_PI);
|
||||
break;
|
||||
|
||||
case ColorCycleStyle::DARKEN_GLOW:
|
||||
// Se oscurece al centro
|
||||
val_shift = -0.15F * sinf(t * M_PI);
|
||||
break;
|
||||
case ColorCycleStyle::VIBRANT:
|
||||
// Cambios fuertes en tono y brillo
|
||||
hue_shift = 35.0F * sinf(t * M_PI);
|
||||
val_shift = 0.2F * sinf(t * M_PI);
|
||||
sat_shift = -0.2F * sinf(t * M_PI);
|
||||
break;
|
||||
|
||||
case ColorCycleStyle::LIGHT_FLASH:
|
||||
// Se ilumina al centro
|
||||
val_shift = 0.25F * sinf(t * M_PI);
|
||||
break;
|
||||
}
|
||||
case ColorCycleStyle::DARKEN_GLOW:
|
||||
// Se oscurece al centro
|
||||
val_shift = -0.15F * sinf(t * M_PI);
|
||||
break;
|
||||
|
||||
HSV adjusted = {
|
||||
.h = fmodf(base_hsv.h + hue_shift + 360.0F, 360.0F),
|
||||
.s = fminf(1.0F, fmaxf(0.0F, base_hsv.s + sat_shift)),
|
||||
.v = fminf(1.0F, fmaxf(0.0F, base_hsv.v + val_shift))};
|
||||
|
||||
Color c = Color::hsvToRgb(adjusted);
|
||||
result[i] = c;
|
||||
result[(2 * CYCLE_SIZE) - 1 - i] = c; // espejo
|
||||
case ColorCycleStyle::LIGHT_FLASH:
|
||||
// Se ilumina al centro
|
||||
val_shift = 0.25F * sinf(t * M_PI);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
HSV adjusted = {
|
||||
.h = fmodf(base_hsv.h + hue_shift + 360.0F, 360.0F),
|
||||
.s = fminf(1.0F, fmaxf(0.0F, base_hsv.s + sat_shift)),
|
||||
.v = fminf(1.0F, fmaxf(0.0F, base_hsv.v + val_shift))};
|
||||
|
||||
Color c = Color::hsvToRgb(adjusted);
|
||||
result[i] = c;
|
||||
result[(2 * CYCLE_SIZE) - 1 - i] = c; // espejo
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
} // namespace Colors
|
||||
@@ -36,10 +36,17 @@ struct Color {
|
||||
|
||||
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)
|
||||
: r(red), g(green), b(blue), a(alpha) {}
|
||||
: r(red),
|
||||
g(green),
|
||||
b(blue),
|
||||
a(alpha) {}
|
||||
|
||||
[[nodiscard]] constexpr auto INVERSE() const -> Color {
|
||||
return Color(MAX_COLOR_VALUE - r, MAX_COLOR_VALUE - g, MAX_COLOR_VALUE - b, a);
|
||||
@@ -108,25 +115,25 @@ enum class ColorCycleStyle {
|
||||
|
||||
// --- Namespace Colors: constantes y utilidades de color ---
|
||||
namespace Colors {
|
||||
// --- Constantes ---
|
||||
constexpr size_t CYCLE_SIZE = 6; // Mitad del ciclo espejado
|
||||
// --- Constantes ---
|
||||
constexpr size_t CYCLE_SIZE = 6; // Mitad del ciclo espejado
|
||||
|
||||
// --- Alias ---
|
||||
using Cycle = std::array<Color, 2 * CYCLE_SIZE>;
|
||||
// --- Alias ---
|
||||
using Cycle = std::array<Color, 2 * CYCLE_SIZE>;
|
||||
|
||||
// --- Colores predefinidos ---
|
||||
constexpr Color NO_COLOR_MOD = Color(0XFF, 0XFF, 0XFF);
|
||||
constexpr Color SHADOW_TEXT = Color(0X43, 0X43, 0X4F);
|
||||
constexpr Color TITLE_SHADOW_TEXT = Color(0x14, 0x87, 0xc4);
|
||||
constexpr Color ORANGE_TEXT = Color(0XFF, 0X7A, 0X00);
|
||||
// --- Colores predefinidos ---
|
||||
constexpr Color NO_COLOR_MOD = Color(0XFF, 0XFF, 0XFF);
|
||||
constexpr Color SHADOW_TEXT = Color(0X43, 0X43, 0X4F);
|
||||
constexpr Color TITLE_SHADOW_TEXT = Color(0x14, 0x87, 0xc4);
|
||||
constexpr Color ORANGE_TEXT = Color(0XFF, 0X7A, 0X00);
|
||||
|
||||
constexpr Color FLASH = Color(0XFF, 0XFF, 0XFF);
|
||||
constexpr Color FLASH = Color(0XFF, 0XFF, 0XFF);
|
||||
|
||||
constexpr Color BLUE_SKY = Color(0X02, 0X88, 0XD1);
|
||||
constexpr Color PINK_SKY = Color(0XFF, 0X6B, 0X97);
|
||||
constexpr Color GREEN_SKY = Color(0X00, 0X79, 0X6B);
|
||||
constexpr Color BLUE_SKY = Color(0X02, 0X88, 0XD1);
|
||||
constexpr Color PINK_SKY = Color(0XFF, 0X6B, 0X97);
|
||||
constexpr Color GREEN_SKY = Color(0X00, 0X79, 0X6B);
|
||||
|
||||
// --- Funciones ---
|
||||
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color;
|
||||
auto generateMirroredCycle(Color base, ColorCycleStyle style = ColorCycleStyle::SUBTLE_PULSE) -> Cycle;
|
||||
}
|
||||
// --- Funciones ---
|
||||
auto getColorLikeKnightRider(const std::vector<Color> &colors, int counter) -> Color;
|
||||
auto generateMirroredCycle(Color base, ColorCycleStyle style = ColorCycleStyle::SUBTLE_PULSE) -> Cycle;
|
||||
} // namespace Colors
|
||||
@@ -15,8 +15,8 @@ namespace Game {
|
||||
constexpr float WIDTH = 320.0F;
|
||||
constexpr float HEIGHT = 256.0F;
|
||||
constexpr float ITEM_SIZE = 20.0F;
|
||||
constexpr int NAME_ENTRY_IDLE_TIME = 10;
|
||||
constexpr int NAME_ENTRY_TOTAL_TIME = 60;
|
||||
constexpr int NAME_ENTRY_IDLE_TIME = 10;
|
||||
constexpr int NAME_ENTRY_TOTAL_TIME = 60;
|
||||
constexpr bool HIT_STOP = false;
|
||||
constexpr int HIT_STOP_MS = 500;
|
||||
constexpr const char* ITEM_TEXT_OUTLINE_COLOR = "FFFFFF00"; // 255, 255, 255, 0
|
||||
@@ -58,7 +58,7 @@ constexpr int SKIP_COUNTDOWN_VALUE = 8;
|
||||
// --- TITLE ---
|
||||
namespace Title {
|
||||
constexpr int PRESS_START_POSITION = 180;
|
||||
constexpr int DURATION = 800;
|
||||
constexpr float DURATION_S = 14.0F;
|
||||
constexpr int ARCADE_EDITION_POSITION = 123;
|
||||
constexpr int TITLE_C_C_POSITION = 80;
|
||||
constexpr const char* BG_COLOR = "41526F";
|
||||
@@ -76,14 +76,16 @@ struct BalloonSettings {
|
||||
float vel;
|
||||
float grav;
|
||||
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 = {{
|
||||
BalloonSettings(2.75F, 0.09F), // Globo 0
|
||||
BalloonSettings(3.70F, 0.10F), // Globo 1
|
||||
BalloonSettings(4.70F, 0.10F), // Globo 2
|
||||
BalloonSettings(5.45F, 0.10F) // Globo 3
|
||||
BalloonSettings(165.0F, 320.0F), // Globo 0: vel=165 pixels/s, grav=320 pixels/s²
|
||||
BalloonSettings(222.0F, 360.0F), // Globo 1: vel=222 pixels/s, grav=360 pixels/s²
|
||||
BalloonSettings(282.0F, 360.0F), // Globo 2: vel=282 pixels/s, grav=360 pixels/s²
|
||||
BalloonSettings(327.0F, 360.0F) // Globo 3: vel=327 pixels/s, grav=360 pixels/s²
|
||||
}};
|
||||
|
||||
constexpr std::array<const char*, 4> COLORS = {
|
||||
|
||||
@@ -39,22 +39,22 @@ void DefineButtons::render() {
|
||||
}
|
||||
}
|
||||
|
||||
void DefineButtons::update() {
|
||||
void DefineButtons::update(float delta_time) {
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Actualizar la ventana siempre
|
||||
if (window_message_) {
|
||||
window_message_->update();
|
||||
window_message_->update(delta_time);
|
||||
}
|
||||
|
||||
// Manejar la secuencia de cierre si ya terminamos
|
||||
if (finished_ && message_shown_) {
|
||||
message_timer_++;
|
||||
message_timer_ += delta_time;
|
||||
|
||||
// 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_) {
|
||||
window_message_->hide(); // Iniciar animación de cierre
|
||||
}
|
||||
@@ -234,7 +234,7 @@ void DefineButtons::checkEnd() {
|
||||
|
||||
// Solo marcar que ya mostramos el mensaje
|
||||
message_shown_ = true;
|
||||
message_timer_ = 0;
|
||||
message_timer_ = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,9 @@ class DefineButtons {
|
||||
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 ---
|
||||
@@ -34,7 +36,7 @@ class DefineButtons {
|
||||
|
||||
// --- Métodos principales ---
|
||||
void render();
|
||||
void update();
|
||||
void update(float delta_time);
|
||||
void handleEvents(const SDL_Event &event);
|
||||
auto enable(Options::Gamepad *options_gamepad) -> bool;
|
||||
void disable();
|
||||
@@ -46,7 +48,7 @@ class DefineButtons {
|
||||
|
||||
private:
|
||||
// --- 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 ---
|
||||
Input *input_ = nullptr; // Entrada del usuario
|
||||
@@ -57,7 +59,7 @@ class DefineButtons {
|
||||
std::vector<Button> buttons_; // Lista de botones
|
||||
std::vector<std::string> controller_names_; // Nombres de los controladores
|
||||
size_t index_button_ = 0; // Índice del botón seleccionado
|
||||
size_t message_timer_ = 0; // Contador de frames para el mensaje
|
||||
float message_timer_ = 0.0f; // Timer en segundos para el mensaje
|
||||
bool enabled_ = false; // Flag para indicar si está activo
|
||||
bool finished_ = false; // Flag para indicar si ha terminado
|
||||
bool closing_ = false; // Flag para indicar que está cerrando
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "param.h" // Para loadParamsFromFile
|
||||
#include "player.h" // Para Player
|
||||
#include "resource.h" // Para Resource
|
||||
#include "resource_helper.h" // Para ResourceHelper
|
||||
#include "screen.h" // Para Screen
|
||||
#include "section.hpp" // Para Name, Options, name, options, AttractMode, attract_mode
|
||||
#include "sections/credits.h" // Para Credits
|
||||
@@ -76,7 +77,13 @@ Director::~Director() {
|
||||
// Inicializa todo
|
||||
void Director::init() {
|
||||
// Configuración inicial de parametros
|
||||
Asset::init(executable_path_); // Inicializa el sistema de gestión de archivos
|
||||
Asset::init(executable_path_); // Inicializa el sistema de gestión de archivos
|
||||
|
||||
#ifdef MACOS_BUNDLE
|
||||
ResourceHelper::initializeResourceSystem(executable_path_ + "/../Resources/resources.pack");
|
||||
#else
|
||||
ResourceHelper::initializeResourceSystem("resources.pack");
|
||||
#endif
|
||||
loadAssets(); // Crea el índice de archivos
|
||||
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
|
||||
@@ -154,7 +161,7 @@ void Director::loadAssets() {
|
||||
#endif
|
||||
|
||||
// Cargar la configuración de assets (también aplicar el prefijo al archivo de configuración)
|
||||
std::string config_path = executable_path_ + PREFIX + "/data/config/assets.txt";
|
||||
std::string config_path = executable_path_ + PREFIX + "/config/assets.txt";
|
||||
Asset::get()->loadFromFile(config_path, PREFIX, system_folder_);
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Assets configuration loaded successfully");
|
||||
|
||||
@@ -45,7 +45,10 @@ void EnterName::incPosition() {
|
||||
} else if (position_ > 0) // No es necesario verificar position_ < MAX_NAME_LENGTH
|
||||
{
|
||||
// Copiamos el índice del carácter anterior si es posible.
|
||||
character_index_[position_] = character_index_[position_ - 1];
|
||||
// character_index_[position_] = character_index_[position_ - 1];
|
||||
|
||||
// Ponemos el caracter "espacio"
|
||||
character_index_[position_] = 0;
|
||||
} else {
|
||||
// Si position_ es 0, inicializamos el carácter actual.
|
||||
character_index_[position_] = 0;
|
||||
@@ -144,12 +147,19 @@ auto EnterName::findIndex(char character) const -> int {
|
||||
// Devuelve un nombre al azar
|
||||
auto EnterName::getRandomName() -> std::string {
|
||||
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()]);
|
||||
}
|
||||
// Obtiene el nombre final introducido
|
||||
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()) {
|
||||
name = getRandomName();
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
|
||||
class Texture; // lines 4-4
|
||||
|
||||
// Actualiza la lógica de la clase
|
||||
void Explosions::update() {
|
||||
// Actualiza la lógica de la clase (time-based)
|
||||
void Explosions::update(float deltaTime) {
|
||||
for (auto &explosion : explosions_) {
|
||||
explosion->update();
|
||||
explosion->update(deltaTime);
|
||||
}
|
||||
|
||||
// Vacia el vector de elementos finalizados
|
||||
|
||||
@@ -16,7 +16,9 @@ struct ExplosionTexture {
|
||||
std::vector<std::string> animation; // Animación para la textura
|
||||
|
||||
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 ---
|
||||
@@ -27,8 +29,8 @@ class Explosions {
|
||||
~Explosions() = default; // Destructor por defecto
|
||||
|
||||
// --- Métodos principales ---
|
||||
void update(); // Actualiza la lógica de la clase
|
||||
void render(); // Dibuja el objeto en pantalla
|
||||
void update(float deltaTime); // Actualiza la lógica de la clase (time-based)
|
||||
void render(); // Dibuja el objeto en pantalla
|
||||
|
||||
// --- Configuración ---
|
||||
void addTexture(int size, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation); // Añade texturas al objeto
|
||||
|
||||
@@ -41,7 +41,7 @@ void Fade::init() {
|
||||
num_squares_width_ = param.fade.num_squares_width;
|
||||
num_squares_height_ = param.fade.num_squares_height;
|
||||
random_squares_duration_ = param.fade.random_squares_duration_ms; // Usar como duración en ms
|
||||
square_transition_duration_ = random_squares_duration_ / 4; // 25% del tiempo total para la transición individual
|
||||
square_transition_duration_ = random_squares_duration_ / 4; // 25% del tiempo total para la transición individual
|
||||
random_squares_start_time_ = 0;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ void Fade::render() {
|
||||
if (state_ == State::FINISHED && mode_ == Mode::IN) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SDL_RenderTexture(renderer_, backbuffer_, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
@@ -82,10 +82,15 @@ 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() {
|
||||
// Sistema basado en tiempo únicamente
|
||||
Uint32 elapsed_time = SDL_GetTicks() - pre_start_time_;
|
||||
|
||||
|
||||
if (elapsed_time >= static_cast<Uint32>(pre_duration_)) {
|
||||
state_ = State::FADING;
|
||||
// CRÍTICO: Reinicializar tiempo de inicio para tipos que usan random_squares_start_time_
|
||||
@@ -129,17 +134,17 @@ void Fade::changeToPostState() {
|
||||
void Fade::updatePostState() {
|
||||
// Sistema basado en tiempo únicamente
|
||||
Uint32 elapsed_time = SDL_GetTicks() - post_start_time_;
|
||||
|
||||
|
||||
if (elapsed_time >= static_cast<Uint32>(post_duration_)) {
|
||||
state_ = State::FINISHED;
|
||||
}
|
||||
|
||||
|
||||
// Mantener el alpha final correcto para cada tipo de fade
|
||||
Uint8 post_alpha = a_;
|
||||
if (type_ == Type::RANDOM_SQUARE2 || type_ == Type::DIAGONAL) {
|
||||
post_alpha = (mode_ == Mode::OUT) ? 255 : 0;
|
||||
}
|
||||
|
||||
|
||||
cleanBackbuffer(r_, g_, b_, post_alpha);
|
||||
}
|
||||
|
||||
@@ -204,16 +209,16 @@ void Fade::updateRandomSquareFade() {
|
||||
|
||||
void Fade::updateRandomSquare2Fade() {
|
||||
Uint32 elapsed_time = SDL_GetTicks() - random_squares_start_time_;
|
||||
|
||||
|
||||
int total_squares = num_squares_width_ * num_squares_height_;
|
||||
|
||||
|
||||
// Calcula el tiempo de activación: total - tiempo que necesitan los últimos cuadrados
|
||||
int activation_time = random_squares_duration_ - square_transition_duration_;
|
||||
activation_time = std::max(activation_time, square_transition_duration_); // Mínimo igual a la duración de transición
|
||||
|
||||
|
||||
// Lógica diferente según el modo
|
||||
int squares_to_activate = 0;
|
||||
|
||||
|
||||
if (mode_ == Mode::OUT) {
|
||||
// OUT: Activa cuadrados gradualmente
|
||||
if (elapsed_time < static_cast<Uint32>(activation_time)) {
|
||||
@@ -222,7 +227,7 @@ void Fade::updateRandomSquare2Fade() {
|
||||
} else {
|
||||
squares_to_activate = total_squares; // Activar todos
|
||||
}
|
||||
|
||||
|
||||
// Activa nuevos cuadrados y guarda su tiempo de activación
|
||||
for (int i = 0; i < squares_to_activate && i < total_squares; ++i) {
|
||||
if (square_age_[i] == -1) {
|
||||
@@ -232,22 +237,22 @@ void Fade::updateRandomSquare2Fade() {
|
||||
} else {
|
||||
// IN: Todos los cuadrados empiezan activos desde el inicio
|
||||
squares_to_activate = total_squares;
|
||||
|
||||
|
||||
// Activa cuadrados gradualmente con tiempo de inicio escalonado
|
||||
float activation_progress = static_cast<float>(elapsed_time) / activation_time;
|
||||
int squares_starting_transition = static_cast<int>(activation_progress * total_squares);
|
||||
|
||||
|
||||
// Asegurar que al menos 1 cuadrado se active desde el primer frame
|
||||
squares_starting_transition = std::max(squares_starting_transition, 1);
|
||||
squares_starting_transition = std::min(squares_starting_transition, total_squares);
|
||||
|
||||
|
||||
for (int i = 0; i < squares_starting_transition; ++i) {
|
||||
if (square_age_[i] == -1) {
|
||||
square_age_[i] = elapsed_time; // Empieza la transición a transparente
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
drawRandomSquares2();
|
||||
|
||||
value_ = calculateValue(0, total_squares, squares_to_activate);
|
||||
@@ -265,7 +270,7 @@ void Fade::updateRandomSquare2Fade() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (all_completed) {
|
||||
// Pintar textura final: OUT opaca, IN transparente
|
||||
Uint8 final_alpha = (mode_ == Mode::OUT) ? 255 : 0;
|
||||
@@ -277,17 +282,17 @@ void Fade::updateRandomSquare2Fade() {
|
||||
|
||||
void Fade::updateDiagonalFade() {
|
||||
Uint32 elapsed_time = SDL_GetTicks() - random_squares_start_time_;
|
||||
|
||||
|
||||
int total_squares = num_squares_width_ * num_squares_height_;
|
||||
|
||||
|
||||
// Calcula el tiempo de activación: total - tiempo que necesitan los últimos cuadrados
|
||||
int activation_time = random_squares_duration_ - square_transition_duration_;
|
||||
activation_time = std::max(activation_time, square_transition_duration_);
|
||||
|
||||
|
||||
// Calcula cuántas diagonales deberían estar activas
|
||||
int max_diagonal = num_squares_width_ + num_squares_height_ - 1; // Número total de diagonales
|
||||
int active_diagonals = 0;
|
||||
|
||||
|
||||
if (mode_ == Mode::OUT) {
|
||||
// OUT: Activa diagonales gradualmente desde esquina superior izquierda
|
||||
if (elapsed_time < static_cast<Uint32>(activation_time)) {
|
||||
@@ -296,7 +301,7 @@ void Fade::updateDiagonalFade() {
|
||||
} else {
|
||||
active_diagonals = max_diagonal; // Activar todas
|
||||
}
|
||||
|
||||
|
||||
// Activa cuadrados por diagonales
|
||||
for (int diagonal = 0; diagonal < active_diagonals; ++diagonal) {
|
||||
activateDiagonal(diagonal, elapsed_time);
|
||||
@@ -304,12 +309,12 @@ void Fade::updateDiagonalFade() {
|
||||
} else {
|
||||
// IN: Todas las diagonales empiezan activas, van desapareciendo
|
||||
active_diagonals = max_diagonal;
|
||||
|
||||
|
||||
// Activa diagonales gradualmente para transición
|
||||
if (elapsed_time < static_cast<Uint32>(activation_time)) {
|
||||
float activation_progress = static_cast<float>(elapsed_time) / activation_time;
|
||||
int diagonals_starting_transition = static_cast<int>(activation_progress * max_diagonal);
|
||||
|
||||
|
||||
for (int diagonal = 0; diagonal < diagonals_starting_transition; ++diagonal) {
|
||||
activateDiagonal(diagonal, elapsed_time);
|
||||
}
|
||||
@@ -320,7 +325,7 @@ void Fade::updateDiagonalFade() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
drawDiagonal();
|
||||
|
||||
value_ = calculateValue(0, total_squares, active_diagonals * (total_squares / max_diagonal));
|
||||
@@ -338,7 +343,7 @@ void Fade::updateDiagonalFade() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (all_completed) {
|
||||
// Pintar textura final: OUT opaca, IN transparente
|
||||
Uint8 final_alpha = (mode_ == Mode::OUT) ? 255 : 0;
|
||||
@@ -354,15 +359,15 @@ void Fade::activateDiagonal(int diagonal_index, Uint32 current_time) {
|
||||
// Diagonal 1: (1,0), (0,1)
|
||||
// Diagonal 2: (2,0), (1,1), (0,2)
|
||||
// etc.
|
||||
|
||||
|
||||
for (int x = 0; x < num_squares_width_; ++x) {
|
||||
int y = diagonal_index - x;
|
||||
|
||||
|
||||
// Verificar que y está dentro de los límites
|
||||
if (y >= 0 && y < num_squares_height_) {
|
||||
// Convertir coordenadas (x,y) a índice en el vector
|
||||
int index = y * num_squares_width_ + x;
|
||||
|
||||
|
||||
if (index >= 0 && index < static_cast<int>(square_age_.size())) {
|
||||
if (square_age_[index] == -1) {
|
||||
square_age_[index] = current_time; // Guarda el tiempo de activación
|
||||
@@ -385,30 +390,30 @@ void Fade::drawDiagonal() {
|
||||
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND); // Usar BLEND para alpha
|
||||
|
||||
Uint32 current_time = SDL_GetTicks() - random_squares_start_time_;
|
||||
|
||||
|
||||
// Lógica unificada: sobre textura transparente, pintar cuadrados según su estado
|
||||
for (size_t i = 0; i < square_.size(); ++i) {
|
||||
Uint8 current_alpha = 0;
|
||||
|
||||
|
||||
if (square_age_[i] == -1) {
|
||||
// Cuadrado no activado
|
||||
if (mode_ == Mode::OUT) {
|
||||
current_alpha = 0; // OUT: transparente si no activado
|
||||
} else {
|
||||
current_alpha = a_; // IN: opaco si no activado
|
||||
current_alpha = a_; // IN: opaco si no activado
|
||||
}
|
||||
} else {
|
||||
// Cuadrado activado - calculamos progreso
|
||||
Uint32 square_elapsed = current_time - square_age_[i];
|
||||
float progress = std::min(static_cast<float>(square_elapsed) / square_transition_duration_, 1.0f);
|
||||
|
||||
|
||||
if (mode_ == Mode::OUT) {
|
||||
current_alpha = static_cast<Uint8>(progress * a_); // 0 → 255
|
||||
} else {
|
||||
current_alpha = static_cast<Uint8>((1.0f - progress) * a_); // 255 → 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (current_alpha > 0) {
|
||||
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, current_alpha);
|
||||
SDL_RenderFillRect(renderer_, &square_[i]);
|
||||
@@ -450,30 +455,30 @@ void Fade::drawRandomSquares2() {
|
||||
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND); // Usar BLEND para alpha
|
||||
|
||||
Uint32 current_time = SDL_GetTicks() - random_squares_start_time_;
|
||||
|
||||
|
||||
// Lógica unificada: sobre textura transparente, pintar cuadrados según su estado
|
||||
for (size_t i = 0; i < square_.size(); ++i) {
|
||||
Uint8 current_alpha = 0;
|
||||
|
||||
|
||||
if (square_age_[i] == -1) {
|
||||
// Cuadrado no activado
|
||||
if (mode_ == Mode::OUT) {
|
||||
current_alpha = 0; // OUT: transparente si no activado
|
||||
} else {
|
||||
current_alpha = a_; // IN: opaco si no activado
|
||||
current_alpha = a_; // IN: opaco si no activado
|
||||
}
|
||||
} else {
|
||||
// Cuadrado activado - calculamos progreso
|
||||
Uint32 square_elapsed = current_time - square_age_[i];
|
||||
float progress = std::min(static_cast<float>(square_elapsed) / square_transition_duration_, 1.0f);
|
||||
|
||||
|
||||
if (mode_ == Mode::OUT) {
|
||||
current_alpha = static_cast<Uint8>(progress * a_); // 0 → 255
|
||||
} else {
|
||||
current_alpha = static_cast<Uint8>((1.0f - progress) * a_); // 255 → 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (current_alpha > 0) {
|
||||
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, current_alpha);
|
||||
SDL_RenderFillRect(renderer_, &square_[i]);
|
||||
|
||||
@@ -11,12 +11,12 @@ class Fade {
|
||||
public:
|
||||
// --- Enums ---
|
||||
enum class Type : Uint8 {
|
||||
FULLSCREEN = 0, // Fundido de pantalla completa
|
||||
CENTER = 1, // Fundido desde el centro
|
||||
RANDOM_SQUARE = 2, // Fundido con cuadrados aleatorios
|
||||
RANDOM_SQUARE2 = 3, // Fundido con cuadrados aleatorios (variante 2)
|
||||
DIAGONAL = 4, // Fundido diagonal desde esquina superior izquierda
|
||||
VENETIAN = 5, // Fundido tipo persiana veneciana
|
||||
FULLSCREEN = 0, // Fundido de pantalla completa
|
||||
CENTER = 1, // Fundido desde el centro
|
||||
RANDOM_SQUARE = 2, // Fundido con cuadrados aleatorios
|
||||
RANDOM_SQUARE2 = 3, // Fundido con cuadrados aleatorios (variante 2)
|
||||
DIAGONAL = 4, // Fundido diagonal desde esquina superior izquierda
|
||||
VENETIAN = 5, // Fundido tipo persiana veneciana
|
||||
};
|
||||
|
||||
enum class Mode : Uint8 {
|
||||
@@ -37,18 +37,19 @@ class Fade {
|
||||
~Fade();
|
||||
|
||||
// --- Métodos principales ---
|
||||
void reset(); // Resetea variables para reutilizar el fade
|
||||
void render(); // Dibuja la transición en pantalla
|
||||
void update(); // Actualiza el estado interno
|
||||
void activate(); // Activa el fade
|
||||
void reset(); // Resetea variables para reutilizar el fade
|
||||
void render(); // Dibuja la transición en pantalla
|
||||
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
|
||||
|
||||
// --- Configuración ---
|
||||
void setColor(Uint8 r, Uint8 g, Uint8 b); // Establece el color RGB del fade
|
||||
void setColor(Color color); // Establece el color del fade
|
||||
void setType(Type type) { type_ = type; } // Establece el tipo de fade
|
||||
void setMode(Mode mode) { mode_ = mode; } // Establece el modo de fade
|
||||
void setPostDuration(int value) { post_duration_ = value; } // Duración posterior al fade en milisegundos
|
||||
void setPreDuration(int value) { pre_duration_ = value; } // Duración previa al fade en milisegundos
|
||||
void setColor(Uint8 r, Uint8 g, Uint8 b); // Establece el color RGB del fade
|
||||
void setColor(Color color); // Establece el color del fade
|
||||
void setType(Type type) { type_ = type; } // Establece el tipo de fade
|
||||
void setMode(Mode mode) { mode_ = mode; } // Establece el modo de fade
|
||||
void setPostDuration(int milliseconds) { post_duration_ = milliseconds; } // Duración posterior al fade en milisegundos
|
||||
void setPreDuration(int milliseconds) { pre_duration_ = milliseconds; } // Duración previa al fade en milisegundos
|
||||
|
||||
// --- Getters ---
|
||||
[[nodiscard]] auto getValue() const -> int { return value_; }
|
||||
@@ -104,10 +105,10 @@ class Fade {
|
||||
void calculateVenetianProgress(); // Calcula el progreso del efecto veneciano
|
||||
|
||||
// --- Dibujo de efectos visuales ---
|
||||
void drawCenterFadeRectangles(); // Dibuja los rectángulos del fundido central
|
||||
void drawRandomSquares(int active_count = -1); // Dibuja los cuadrados aleatorios del fundido
|
||||
void drawRandomSquares2(); // Dibuja los cuadrados con transición de color (RANDOM_SQUARE2)
|
||||
void drawDiagonal(); // Dibuja los cuadrados con patrón diagonal
|
||||
void drawCenterFadeRectangles(); // Dibuja los rectángulos del fundido central
|
||||
void drawRandomSquares(int active_count = -1); // Dibuja los cuadrados aleatorios del fundido
|
||||
void drawRandomSquares2(); // Dibuja los cuadrados con transición de color (RANDOM_SQUARE2)
|
||||
void drawDiagonal(); // Dibuja los cuadrados con patrón diagonal
|
||||
void activateDiagonal(int diagonal_index, Uint32 current_time); // Activa una diagonal específica
|
||||
void drawVenetianBlinds(); // Dibuja las persianas venecianas del fundido
|
||||
void drawVenetianBlinds(); // Dibuja las persianas venecianas del fundido
|
||||
};
|
||||
@@ -15,8 +15,9 @@
|
||||
#include "texture.h" // Para Texture
|
||||
|
||||
constexpr int ZOOM_FACTOR = 5;
|
||||
constexpr int FLASH_DELAY = 3;
|
||||
constexpr int FLASH_LENGTH = FLASH_DELAY + 3;
|
||||
constexpr float FLASH_DELAY_S = 0.05f; // 3 frames → 0.05s
|
||||
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
|
||||
GameLogo::GameLogo(int x, int y)
|
||||
@@ -45,6 +46,7 @@ void GameLogo::init() {
|
||||
arcade_edition_status_ = Status::DISABLED;
|
||||
shake_.init(1, 2, 8, XP);
|
||||
zoom_ = 3.0F * ZOOM_FACTOR;
|
||||
post_finished_timer_ = 0.0f;
|
||||
|
||||
// Inicializa el bitmap de 'Coffee'
|
||||
coffee_sprite_->setPosX(XP);
|
||||
@@ -52,44 +54,44 @@ void GameLogo::init() {
|
||||
coffee_sprite_->setWidth(coffee_texture_->getWidth());
|
||||
coffee_sprite_->setHeight(coffee_texture_->getHeight());
|
||||
coffee_sprite_->setVelX(0.0F);
|
||||
coffee_sprite_->setVelY(2.5F);
|
||||
coffee_sprite_->setVelY(COFFEE_VEL_Y);
|
||||
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_->setEnabled(true);
|
||||
coffee_sprite_->setFinishedCounter(0);
|
||||
coffee_sprite_->setFinishedDelay(0.0f);
|
||||
coffee_sprite_->setDestX(XP);
|
||||
coffee_sprite_->setDestY(y_ - coffee_texture_->getHeight());
|
||||
|
||||
// Inicializa el bitmap de 'Crisis'
|
||||
crisis_sprite_->setPosX(XP + 15);
|
||||
crisis_sprite_->setPosX(XP + CRISIS_OFFSET_X);
|
||||
crisis_sprite_->setPosY(y_ + DESP);
|
||||
crisis_sprite_->setWidth(crisis_texture_->getWidth());
|
||||
crisis_sprite_->setHeight(crisis_texture_->getHeight());
|
||||
crisis_sprite_->setVelX(0.0F);
|
||||
crisis_sprite_->setVelY(-2.5F);
|
||||
crisis_sprite_->setVelY(CRISIS_VEL_Y);
|
||||
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_->setEnabled(true);
|
||||
crisis_sprite_->setFinishedCounter(0);
|
||||
crisis_sprite_->setDestX(XP + 15);
|
||||
crisis_sprite_->setFinishedDelay(0.0f);
|
||||
crisis_sprite_->setDestX(XP + CRISIS_OFFSET_X);
|
||||
crisis_sprite_->setDestY(y_);
|
||||
|
||||
// Inicializa el bitmap de 'DustRight'
|
||||
dust_right_sprite_->resetAnimation();
|
||||
dust_right_sprite_->setPosX(coffee_sprite_->getPosX() + coffee_sprite_->getWidth());
|
||||
dust_right_sprite_->setPosY(y_);
|
||||
dust_right_sprite_->setWidth(16);
|
||||
dust_right_sprite_->setHeight(16);
|
||||
dust_right_sprite_->setWidth(DUST_SIZE);
|
||||
dust_right_sprite_->setHeight(DUST_SIZE);
|
||||
dust_right_sprite_->setFlip(SDL_FLIP_HORIZONTAL);
|
||||
|
||||
// Inicializa el bitmap de 'DustLeft'
|
||||
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_->setWidth(16);
|
||||
dust_left_sprite_->setHeight(16);
|
||||
dust_left_sprite_->setWidth(DUST_SIZE);
|
||||
dust_left_sprite_->setHeight(DUST_SIZE);
|
||||
|
||||
// Inicializa el bitmap de 'Arcade Edition'
|
||||
arcade_edition_sprite_->setZoom(zoom_);
|
||||
@@ -112,45 +114,45 @@ void GameLogo::render() {
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza la lógica de la clase
|
||||
void GameLogo::update() {
|
||||
updateCoffeeCrisis();
|
||||
updateArcadeEdition();
|
||||
updatePostFinishedCounter();
|
||||
// Actualiza la lógica de la clase (time-based)
|
||||
void GameLogo::update(float deltaTime) {
|
||||
updateCoffeeCrisis(deltaTime);
|
||||
updateArcadeEdition(deltaTime);
|
||||
updatePostFinishedCounter(deltaTime);
|
||||
}
|
||||
|
||||
void GameLogo::updateCoffeeCrisis() {
|
||||
void GameLogo::updateCoffeeCrisis(float deltaTime) {
|
||||
switch (coffee_crisis_status_) {
|
||||
case Status::MOVING:
|
||||
handleCoffeeCrisisMoving();
|
||||
handleCoffeeCrisisMoving(deltaTime);
|
||||
break;
|
||||
case Status::SHAKING:
|
||||
handleCoffeeCrisisShaking();
|
||||
handleCoffeeCrisisShaking(deltaTime);
|
||||
break;
|
||||
case Status::FINISHED:
|
||||
handleCoffeeCrisisFinished();
|
||||
handleCoffeeCrisisFinished(deltaTime);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GameLogo::updateArcadeEdition() {
|
||||
void GameLogo::updateArcadeEdition(float deltaTime) {
|
||||
switch (arcade_edition_status_) {
|
||||
case Status::MOVING:
|
||||
handleArcadeEditionMoving();
|
||||
handleArcadeEditionMoving(deltaTime);
|
||||
break;
|
||||
case Status::SHAKING:
|
||||
handleArcadeEditionShaking();
|
||||
handleArcadeEditionShaking(deltaTime);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GameLogo::handleCoffeeCrisisMoving() {
|
||||
coffee_sprite_->update();
|
||||
crisis_sprite_->update();
|
||||
void GameLogo::handleCoffeeCrisisMoving(float deltaTime) {
|
||||
coffee_sprite_->update(deltaTime);
|
||||
crisis_sprite_->update(deltaTime);
|
||||
|
||||
if (coffee_sprite_->hasFinished() && crisis_sprite_->hasFinished()) {
|
||||
coffee_crisis_status_ = Status::SHAKING;
|
||||
@@ -158,22 +160,23 @@ void GameLogo::handleCoffeeCrisisMoving() {
|
||||
}
|
||||
}
|
||||
|
||||
void GameLogo::handleCoffeeCrisisShaking() {
|
||||
void GameLogo::handleCoffeeCrisisShaking(float deltaTime) {
|
||||
if (shake_.remaining > 0) {
|
||||
processShakeEffect(coffee_sprite_.get(), crisis_sprite_.get());
|
||||
processShakeEffect(coffee_sprite_.get(), crisis_sprite_.get(), deltaTime);
|
||||
} else {
|
||||
finishCoffeeCrisisShaking();
|
||||
}
|
||||
|
||||
updateDustSprites();
|
||||
updateDustSprites(deltaTime);
|
||||
}
|
||||
|
||||
void GameLogo::handleCoffeeCrisisFinished() {
|
||||
updateDustSprites();
|
||||
void GameLogo::handleCoffeeCrisisFinished(float deltaTime) {
|
||||
updateDustSprites(deltaTime);
|
||||
}
|
||||
|
||||
void GameLogo::handleArcadeEditionMoving() {
|
||||
zoom_ -= 0.1F * ZOOM_FACTOR;
|
||||
void GameLogo::handleArcadeEditionMoving(float deltaTime) {
|
||||
// DeltaTime en segundos: decremento por segundo
|
||||
zoom_ -= (ZOOM_DECREMENT_PER_S * ZOOM_FACTOR) * deltaTime;
|
||||
arcade_edition_sprite_->setZoom(zoom_);
|
||||
|
||||
if (zoom_ <= 1.0F) {
|
||||
@@ -181,34 +184,38 @@ void GameLogo::handleArcadeEditionMoving() {
|
||||
}
|
||||
}
|
||||
|
||||
void GameLogo::handleArcadeEditionShaking() {
|
||||
void GameLogo::handleArcadeEditionShaking(float deltaTime) {
|
||||
if (shake_.remaining > 0) {
|
||||
processArcadeEditionShake();
|
||||
processArcadeEditionShake(deltaTime);
|
||||
} else {
|
||||
arcade_edition_sprite_->setX(shake_.origin);
|
||||
arcade_edition_status_ = Status::FINISHED;
|
||||
}
|
||||
}
|
||||
|
||||
void GameLogo::processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite) {
|
||||
if (shake_.counter > 0) {
|
||||
shake_.counter--;
|
||||
} else {
|
||||
shake_.counter = shake_.delay;
|
||||
|
||||
void GameLogo::processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite, float deltaTime) {
|
||||
shake_.time_accumulator += deltaTime;
|
||||
|
||||
if (shake_.time_accumulator >= SHAKE_DELAY_S) {
|
||||
shake_.time_accumulator -= SHAKE_DELAY_S;
|
||||
const auto DISPLACEMENT = calculateShakeDisplacement();
|
||||
primary_sprite->setPosX(shake_.origin + DISPLACEMENT);
|
||||
if (secondary_sprite != nullptr) {
|
||||
secondary_sprite->setPosX(shake_.origin + DISPLACEMENT + 15);
|
||||
secondary_sprite->setPosX(shake_.origin + DISPLACEMENT + CRISIS_OFFSET_X);
|
||||
}
|
||||
shake_.remaining--;
|
||||
}
|
||||
}
|
||||
|
||||
void GameLogo::processArcadeEditionShake() {
|
||||
if (shake_.counter > 0) {
|
||||
shake_.counter--;
|
||||
} else {
|
||||
shake_.counter = shake_.delay;
|
||||
void GameLogo::processArcadeEditionShake(float deltaTime) {
|
||||
// Delay fijo en segundos (shake_.delay era frames, ahora usamos constante)
|
||||
float delayTime = SHAKE_DELAY_S;
|
||||
|
||||
shake_.time_accumulator += deltaTime;
|
||||
|
||||
if (shake_.time_accumulator >= delayTime) {
|
||||
shake_.time_accumulator -= delayTime;
|
||||
const auto DISPLACEMENT = calculateShakeDisplacement();
|
||||
arcade_edition_sprite_->setX(shake_.origin + DISPLACEMENT);
|
||||
shake_.remaining--;
|
||||
@@ -221,7 +228,7 @@ auto GameLogo::calculateShakeDisplacement() const -> int {
|
||||
|
||||
void GameLogo::finishCoffeeCrisisShaking() {
|
||||
coffee_sprite_->setPosX(shake_.origin);
|
||||
crisis_sprite_->setPosX(shake_.origin + 15);
|
||||
crisis_sprite_->setPosX(shake_.origin + CRISIS_OFFSET_X);
|
||||
coffee_crisis_status_ = Status::FINISHED;
|
||||
arcade_edition_status_ = Status::MOVING;
|
||||
}
|
||||
@@ -236,20 +243,20 @@ void GameLogo::finishArcadeEditionMoving() {
|
||||
|
||||
void GameLogo::playTitleEffects() {
|
||||
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();
|
||||
}
|
||||
|
||||
void GameLogo::updateDustSprites() {
|
||||
dust_right_sprite_->update();
|
||||
dust_left_sprite_->update();
|
||||
void GameLogo::updateDustSprites(float deltaTime) {
|
||||
dust_right_sprite_->update(deltaTime);
|
||||
dust_left_sprite_->update(deltaTime);
|
||||
}
|
||||
|
||||
void GameLogo::updatePostFinishedCounter() {
|
||||
void GameLogo::updatePostFinishedCounter(float deltaTime) {
|
||||
if (coffee_crisis_status_ == Status::FINISHED &&
|
||||
arcade_edition_status_ == Status::FINISHED &&
|
||||
post_finished_counter_ > 0) {
|
||||
--post_finished_counter_;
|
||||
arcade_edition_status_ == Status::FINISHED) {
|
||||
|
||||
post_finished_timer_ += deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,7 +268,7 @@ void GameLogo::enable() {
|
||||
|
||||
// Indica si ha terminado la animación
|
||||
auto GameLogo::hasFinished() const -> bool {
|
||||
return post_finished_counter_ == 0;
|
||||
return post_finished_timer_ >= post_finished_delay_s_;
|
||||
}
|
||||
|
||||
// Calcula el desplazamiento vertical inicial
|
||||
|
||||
@@ -11,14 +11,25 @@ class Texture;
|
||||
// --- Clase GameLogo: gestor del logo del juego ---
|
||||
class GameLogo {
|
||||
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 ---
|
||||
GameLogo(int x, int y);
|
||||
~GameLogo() = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
void render(); // Pinta la clase en pantalla
|
||||
void update(); // Actualiza la lógica de la clase
|
||||
void enable(); // Activa la clase
|
||||
void render(); // Pinta la clase en pantalla
|
||||
void update(float deltaTime); // Actualiza la lógica de la clase (time-based)
|
||||
void enable(); // Activa la clase
|
||||
|
||||
// --- Getters ---
|
||||
[[nodiscard]] auto hasFinished() const -> bool; // Indica si ha terminado la animación
|
||||
@@ -34,16 +45,22 @@ class GameLogo {
|
||||
|
||||
// --- Estructuras privadas ---
|
||||
struct Shake {
|
||||
int desp = 1; // Pixels de desplazamiento para agitar la pantalla en el eje x
|
||||
int delay = 2; // Retraso entre cada desplazamiento de la pantalla al agitarse
|
||||
int length = 8; // Cantidad de desplazamientos a realizar
|
||||
int remaining = length; // Cantidad de desplazamientos pendientes a realizar
|
||||
int counter = delay; // Contador para el retraso
|
||||
int origin = 0; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
|
||||
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 (frame-based)
|
||||
int length = 8; // Cantidad de desplazamientos a realizar
|
||||
int remaining = length; // Cantidad de desplazamientos pendientes a realizar
|
||||
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
|
||||
|
||||
Shake() = default;
|
||||
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) {
|
||||
desp = d;
|
||||
@@ -51,6 +68,7 @@ class GameLogo {
|
||||
length = l;
|
||||
remaining = l;
|
||||
counter = de;
|
||||
time_accumulator = 0.0f;
|
||||
origin = o;
|
||||
}
|
||||
};
|
||||
@@ -74,32 +92,34 @@ class GameLogo {
|
||||
float x_; // Posición X del logo
|
||||
float y_; // Posición Y del logo
|
||||
float zoom_ = 1.0F; // Zoom aplicado al texto "ARCADE EDITION"
|
||||
int post_finished_counter_ = 1; // Contador final tras animaciones
|
||||
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 ---
|
||||
void init(); // Inicializa las variables
|
||||
[[nodiscard]] auto getInitialVerticalDesp() const -> int; // Calcula el desplazamiento vertical inicial
|
||||
|
||||
// --- Actualización de estados específicos ---
|
||||
void updateCoffeeCrisis(); // Actualiza el estado de "Coffee Crisis"
|
||||
void updateArcadeEdition(); // Actualiza el estado de "Arcade Edition"
|
||||
void updatePostFinishedCounter(); // Actualiza el contador tras finalizar una animación
|
||||
void updateCoffeeCrisis(float deltaTime); // Actualiza el estado de "Coffee Crisis" (time-based)
|
||||
void updateArcadeEdition(float deltaTime); // Actualiza el estado de "Arcade Edition" (time-based)
|
||||
void updatePostFinishedCounter(float deltaTime); // Actualiza el contador tras finalizar una animación (time-based)
|
||||
|
||||
// --- Efectos visuales: movimiento y sacudidas ---
|
||||
void handleCoffeeCrisisMoving(); // Maneja el movimiento de "Coffee Crisis"
|
||||
void handleCoffeeCrisisShaking(); // Maneja la sacudida de "Coffee Crisis"
|
||||
void handleArcadeEditionMoving(); // Maneja el movimiento de "Arcade Edition"
|
||||
void handleArcadeEditionShaking(); // Maneja la sacudida de "Arcade Edition"
|
||||
void processShakeEffect(SmartSprite* primary_sprite, SmartSprite* secondary_sprite = nullptr); // Procesa el efecto de sacudida en sprites
|
||||
void processArcadeEditionShake(); // Procesa la sacudida específica de "Arcade Edition"
|
||||
[[nodiscard]] auto calculateShakeDisplacement() const -> int; // Calcula el desplazamiento de la sacudida
|
||||
void handleCoffeeCrisisMoving(float deltaTime); // Maneja el movimiento de "Coffee Crisis" (time-based)
|
||||
void handleCoffeeCrisisShaking(float deltaTime); // Maneja la sacudida de "Coffee Crisis" (time-based)
|
||||
void handleArcadeEditionMoving(float deltaTime); // Maneja el movimiento de "Arcade Edition" (time-based)
|
||||
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 (frame-based)
|
||||
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
|
||||
|
||||
// --- Gestión de finalización de efectos ---
|
||||
void handleCoffeeCrisisFinished(); // Maneja el final de la animación "Coffee Crisis"
|
||||
void finishCoffeeCrisisShaking(); // Finaliza la sacudida de "Coffee Crisis"
|
||||
void finishArcadeEditionMoving(); // Finaliza el movimiento de "Arcade Edition"
|
||||
void handleCoffeeCrisisFinished(float deltaTime); // Maneja el final de la animación "Coffee Crisis" (time-based)
|
||||
void finishCoffeeCrisisShaking(); // Finaliza la sacudida de "Coffee Crisis"
|
||||
void finishArcadeEditionMoving(); // Finaliza el movimiento de "Arcade Edition"
|
||||
|
||||
// --- Utilidades ---
|
||||
static void playTitleEffects(); // Reproduce efectos visuales/sonoros del título
|
||||
void updateDustSprites(); // Actualiza los sprites de polvo
|
||||
static void playTitleEffects(); // Reproduce efectos visuales/sonoros del título
|
||||
void updateDustSprites(float deltaTime); // Actualiza los sprites de polvo (time-based)
|
||||
};
|
||||
@@ -32,7 +32,9 @@ class Input {
|
||||
bool just_pressed; // Se acaba de pulsar en este fotograma
|
||||
|
||||
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 {
|
||||
@@ -43,7 +45,10 @@ class Input {
|
||||
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)
|
||||
: 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 {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "item.h"
|
||||
|
||||
#include <algorithm> // Para clamp
|
||||
#include <cmath> // Para fmod
|
||||
#include <cstdlib> // Para rand
|
||||
|
||||
#include "animated_sprite.h" // Para AnimatedSprite
|
||||
@@ -9,16 +10,18 @@
|
||||
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)
|
||||
: 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) {
|
||||
case ItemType::COFFEE_MACHINE: {
|
||||
width_ = COFFEE_MACHINE_WIDTH;
|
||||
height_ = COFFEE_MACHINE_HEIGHT;
|
||||
pos_x_ = getCoffeeMachineSpawn(x, width_, play_area_.w);
|
||||
pos_y_ = y;
|
||||
vel_x_ = ((rand() % 3) - 1) * 0.5F;
|
||||
vel_y_ = -0.1F;
|
||||
accel_y_ = 0.1F;
|
||||
vel_x_ = ((rand() % 3) - 1) * COFFEE_MACHINE_VEL_X_FACTOR;
|
||||
vel_y_ = COFFEE_MACHINE_VEL_Y;
|
||||
accel_y_ = COFFEE_MACHINE_ACCEL_Y;
|
||||
collider_.r = 10;
|
||||
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;
|
||||
if (direction < 3) {
|
||||
// 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 {
|
||||
// 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;
|
||||
accel_y_ = 0.2F;
|
||||
vel_y_ = ITEM_VEL_Y;
|
||||
accel_y_ = ITEM_ACCEL_Y;
|
||||
collider_.r = width_ / 2;
|
||||
break;
|
||||
}
|
||||
@@ -64,24 +67,34 @@ void Item::alignTo(int x) {
|
||||
|
||||
void Item::render() {
|
||||
if (enabled_) {
|
||||
if (time_to_live_ > 200) {
|
||||
sprite_->render();
|
||||
} else if (time_to_live_ % 20 > 10) {
|
||||
// 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();
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Item::move() {
|
||||
void Item::move(float deltaTime) {
|
||||
floor_collision_ = false;
|
||||
|
||||
// Calcula la nueva posición
|
||||
pos_x_ += vel_x_;
|
||||
pos_y_ += vel_y_;
|
||||
// Calcula la nueva posición usando deltaTime (velocidad en pixels/segundo)
|
||||
pos_x_ += vel_x_ * deltaTime;
|
||||
pos_y_ += vel_y_ * deltaTime;
|
||||
|
||||
// Aplica las aceleraciones a la velocidad
|
||||
vel_x_ += accel_x_;
|
||||
vel_y_ += accel_y_;
|
||||
// Aplica las aceleraciones a la velocidad usando deltaTime (aceleración en pixels/segundo²)
|
||||
vel_x_ += accel_x_ * deltaTime;
|
||||
vel_y_ += accel_y_ * deltaTime;
|
||||
|
||||
// Comprueba los laterales de la zona de juego
|
||||
const float MIN_X = param.game.play_area.rect.x;
|
||||
@@ -90,7 +103,7 @@ void Item::move() {
|
||||
|
||||
// Si toca el borde lateral
|
||||
if (pos_x_ == MIN_X || pos_x_ == MAX_X) {
|
||||
vel_x_ = -vel_x_; // Invierte la velocidad horizontal
|
||||
vel_x_ = -vel_x_; // Invierte la velocidad horizontal
|
||||
}
|
||||
|
||||
// Si colisiona por arriba, rebota (excepto la máquina de café)
|
||||
@@ -111,24 +124,24 @@ void Item::move() {
|
||||
case ItemType::COFFEE_MACHINE:
|
||||
// La máquina de café es mas pesada y tiene una fisica diferente, ademas hace ruido
|
||||
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
|
||||
vel_y_ = vel_x_ = accel_x_ = accel_y_ = 0;
|
||||
} else {
|
||||
// Si la velocidad vertical es alta, el objeto rebota y pierde velocidad
|
||||
vel_y_ *= -0.20F;
|
||||
vel_x_ *= 0.75F;
|
||||
vel_y_ *= COFFEE_BOUNCE_DAMPING;
|
||||
vel_x_ *= HORIZONTAL_DAMPING;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// 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
|
||||
vel_y_ = vel_x_ = accel_x_ = accel_y_ = 0;
|
||||
} else {
|
||||
// Si la velocidad vertical es alta, el objeto rebota y pierde velocidad
|
||||
vel_y_ *= -0.5F;
|
||||
vel_x_ *= 0.75F;
|
||||
vel_y_ *= ITEM_BOUNCE_DAMPING;
|
||||
vel_x_ *= HORIZONTAL_DAMPING;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -141,16 +154,15 @@ void Item::move() {
|
||||
|
||||
void Item::disable() { enabled_ = false; }
|
||||
|
||||
void Item::update() {
|
||||
move();
|
||||
sprite_->update();
|
||||
updateTimeToLive();
|
||||
void Item::update(float deltaTime) {
|
||||
move(deltaTime);
|
||||
sprite_->update(deltaTime);
|
||||
updateTimeToLive(deltaTime);
|
||||
}
|
||||
|
||||
void Item::updateTimeToLive() {
|
||||
if (time_to_live_ > 0) {
|
||||
time_to_live_--;
|
||||
} else {
|
||||
void Item::updateTimeToLive(float deltaTime) {
|
||||
lifetime_timer_ += deltaTime;
|
||||
if (lifetime_timer_ >= LIFETIME_DURATION_S) {
|
||||
disable();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,16 +29,34 @@ class Item {
|
||||
// --- Constantes ---
|
||||
static constexpr int COFFEE_MACHINE_WIDTH = 30; // Anchura de la máquina de café
|
||||
static constexpr int COFFEE_MACHINE_HEIGHT = 39; // Altura de la máquina de café
|
||||
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 ---
|
||||
Item(ItemType type, float x, float y, SDL_FRect &play_area, const std::shared_ptr<Texture> &texture, const std::vector<std::string> &animation); // Constructor principal
|
||||
~Item() = default; // Destructor
|
||||
|
||||
// --- Métodos principales ---
|
||||
void alignTo(int x); // Centra el objeto en la posición X indicada
|
||||
void render(); // Renderiza el objeto en pantalla
|
||||
void disable(); // Desactiva el objeto
|
||||
void update(); // Actualiza la posición, animación y contadores
|
||||
void alignTo(int x); // Centra el objeto en la posición X indicada
|
||||
void render(); // Renderiza el objeto en pantalla
|
||||
void disable(); // Desactiva el objeto
|
||||
void update(float deltaTime); // Actualiza la posición, animación y contadores (time-based)
|
||||
|
||||
// --- Getters ---
|
||||
[[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
|
||||
int width_; // Ancho 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 enabled_ = true; // Indica si el objeto está habilitado
|
||||
|
||||
// --- Métodos internos ---
|
||||
void shiftColliders(); // Alinea el círculo de colisión con la posición del objeto
|
||||
void shiftSprite(); // Coloca el sprite en la posición del objeto
|
||||
void move(); // Actualiza la posición y estados del objeto
|
||||
void updateTimeToLive(); // Actualiza el contador de tiempo de vida
|
||||
void move(float deltaTime); // Actualiza la posición y estados del objeto (time-based)
|
||||
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é
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "difficulty.h" // Para Difficulty
|
||||
#include "external/json.hpp" // Para basic_json, iteration_proxy_value, oper...
|
||||
#include "options.h" // Para SettingsOpt...
|
||||
#include "resource_helper.h" // Para ResourceHelper
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
@@ -27,14 +28,24 @@ std::vector<Language> languages = {
|
||||
auto loadFromFile(const std::string &file_path) -> bool {
|
||||
texts.clear();
|
||||
|
||||
std::ifstream rfile(file_path);
|
||||
if (!rfile.is_open()) {
|
||||
return false;
|
||||
}
|
||||
// Intentar cargar desde ResourceHelper primero
|
||||
auto resource_data = ResourceHelper::loadFile(file_path);
|
||||
|
||||
try {
|
||||
json j;
|
||||
rfile >> j;
|
||||
|
||||
if (!resource_data.empty()) {
|
||||
// Cargar desde datos del pack
|
||||
std::string content(resource_data.begin(), resource_data.end());
|
||||
j = json::parse(content);
|
||||
} else {
|
||||
// Fallback a filesystem directo
|
||||
std::ifstream rfile(file_path);
|
||||
if (!rfile.is_open()) {
|
||||
return false;
|
||||
}
|
||||
rfile >> j;
|
||||
}
|
||||
|
||||
for (const auto &el : j.items()) {
|
||||
texts[el.key()] = el.value();
|
||||
|
||||
@@ -19,7 +19,9 @@ struct Language {
|
||||
std::string file_name; // Nombre del fichero con los textos
|
||||
|
||||
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 ---
|
||||
|
||||
@@ -24,6 +24,32 @@ void ManageHiScoreTable::clear() {
|
||||
table_.emplace_back("PACMQ", 200);
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,10 @@ struct HiScoreEntry {
|
||||
bool one_credit_complete; // Indica si se ha conseguido 1CC
|
||||
|
||||
// Constructor
|
||||
explicit HiScoreEntry(const std::string &n = "", int s = 0, bool occ = false)
|
||||
: name(n.substr(0, 6)), score(s), one_credit_complete(occ) {}
|
||||
explicit HiScoreEntry(const std::string &name = "", int score = 0, bool one_credit_complete = false)
|
||||
: name(name.substr(0, 6)),
|
||||
score(score),
|
||||
one_credit_complete(one_credit_complete) {}
|
||||
};
|
||||
|
||||
// --- Tipos ---
|
||||
|
||||
@@ -53,42 +53,41 @@ void MovingSprite::stop() {
|
||||
flip_ = SDL_FLIP_NONE; // Establece como se ha de voltear el sprite
|
||||
}
|
||||
|
||||
// Mueve el sprite
|
||||
void MovingSprite::move() {
|
||||
x_ += vx_;
|
||||
y_ += vy_;
|
||||
// Mueve el sprite (time-based)
|
||||
void MovingSprite::move(float deltaTime) {
|
||||
// DeltaTime puro: velocidad (pixels/ms) * tiempo (ms)
|
||||
x_ += vx_ * deltaTime;
|
||||
y_ += vy_ * deltaTime;
|
||||
|
||||
vx_ += ax_;
|
||||
vy_ += ay_;
|
||||
// Aceleración (pixels/ms²) * tiempo (ms)
|
||||
vx_ += ax_ * deltaTime;
|
||||
vy_ += ay_ * deltaTime;
|
||||
|
||||
pos_.x = static_cast<int>(x_);
|
||||
pos_.y = static_cast<int>(y_);
|
||||
}
|
||||
|
||||
// Actualiza las variables internas del objeto
|
||||
void MovingSprite::update() {
|
||||
move();
|
||||
rotate();
|
||||
// Actualiza las variables internas del objeto (time-based)
|
||||
void MovingSprite::update(float deltaTime) {
|
||||
move(deltaTime);
|
||||
rotate(deltaTime);
|
||||
}
|
||||
|
||||
// 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() {
|
||||
// Establece la rotacion (time-based)
|
||||
void MovingSprite::rotate(float deltaTime) {
|
||||
if (rotate_.enabled) {
|
||||
++rotate_.counter;
|
||||
if (rotate_.counter % rotate_.speed == 0) {
|
||||
updateAngle();
|
||||
rotate_.counter = 0;
|
||||
}
|
||||
rotate_.angle += rotate_.amount * deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Activa o desactiva el efecto de rotación
|
||||
void MovingSprite::setRotate(bool enable) {
|
||||
rotate_.enabled = enable;
|
||||
rotate_.counter = 0;
|
||||
}
|
||||
|
||||
// Establece la posición y_ el tamaño del objeto
|
||||
|
||||
@@ -15,7 +15,6 @@ class MovingSprite : public Sprite {
|
||||
// --- Estructuras ---
|
||||
struct Rotate {
|
||||
bool enabled{false}; // Indica si ha de rotar
|
||||
int counter{0}; // Contador
|
||||
int speed{1}; // Velocidad de giro
|
||||
double angle{0.0}; // Ángulo para dibujarlo
|
||||
float amount{0.0F}; // Cantidad de grados a girar en cada iteración
|
||||
@@ -29,10 +28,10 @@ class MovingSprite : public Sprite {
|
||||
~MovingSprite() override = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
virtual void update(); // Actualiza las variables internas del objeto
|
||||
void clear() override; // Reinicia todas las variables a cero
|
||||
void stop(); // Elimina el movimiento del sprite
|
||||
void render() override; // Muestra el sprite por pantalla
|
||||
virtual void update(float deltaTime); // Actualiza las variables internas del objeto (time-based)
|
||||
void clear() override; // Reinicia todas las variables a cero
|
||||
void stop(); // Elimina el movimiento del sprite
|
||||
void render() override; // Muestra el sprite por pantalla
|
||||
|
||||
// --- Configuración ---
|
||||
void setPos(SDL_FRect rect); // Establece la posición y el tamaño del objeto
|
||||
@@ -79,6 +78,6 @@ class MovingSprite : public Sprite {
|
||||
|
||||
// --- Métodos internos ---
|
||||
void updateAngle() { rotate_.angle += rotate_.amount; } // Incrementa el valor del ángulo
|
||||
void move(); // Mueve el sprite según velocidad y aceleración
|
||||
void rotate(); // Rota el sprite según los parámetros de rotación
|
||||
void move(float deltaTime); // Mueve el sprite según velocidad y aceleración (time-based)
|
||||
void rotate(float deltaTime); // Rota el sprite según los parámetros de rotación (time-based)
|
||||
};
|
||||
@@ -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.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.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.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); }}};
|
||||
@@ -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); }},
|
||||
{"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); }},
|
||||
{"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.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); }},
|
||||
@@ -196,46 +196,48 @@ auto setParams(const std::string& var, const std::string& value) -> bool {
|
||||
|
||||
// Colores válidos para globos
|
||||
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 {
|
||||
return VALID_BALLOON_COLORS.find(color) != VALID_BALLOON_COLORS.end();
|
||||
};
|
||||
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> STRING_PARAMS = {
|
||||
{"balloon.color[0]", [validateBalloonColor](const std::string& v) {
|
||||
if (!validateBalloonColor(v)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'blue' por defecto.", v.c_str());
|
||||
param.balloon.color.at(0) = "blue";
|
||||
} else {
|
||||
param.balloon.color.at(0) = v;
|
||||
}
|
||||
}},
|
||||
{"balloon.color[1]", [validateBalloonColor](const std::string& v) {
|
||||
if (!validateBalloonColor(v)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'orange' por defecto.", v.c_str());
|
||||
param.balloon.color.at(1) = "orange";
|
||||
} else {
|
||||
param.balloon.color.at(1) = v;
|
||||
}
|
||||
}},
|
||||
{"balloon.color[2]", [validateBalloonColor](const std::string& v) {
|
||||
if (!validateBalloonColor(v)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'red' por defecto.", v.c_str());
|
||||
param.balloon.color.at(2) = "red";
|
||||
} else {
|
||||
param.balloon.color.at(2) = v;
|
||||
}
|
||||
}},
|
||||
{"balloon.color[3]", [validateBalloonColor](const std::string& v) {
|
||||
if (!validateBalloonColor(v)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'green' por defecto.", v.c_str());
|
||||
param.balloon.color.at(3) = "green";
|
||||
} else {
|
||||
param.balloon.color.at(3) = v;
|
||||
}
|
||||
}}};
|
||||
{"balloon.color[0]", [validateBalloonColor](const std::string& v) {
|
||||
if (!validateBalloonColor(v)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'blue' por defecto.", v.c_str());
|
||||
param.balloon.color.at(0) = "blue";
|
||||
} else {
|
||||
param.balloon.color.at(0) = v;
|
||||
}
|
||||
}},
|
||||
{"balloon.color[1]", [validateBalloonColor](const std::string& v) {
|
||||
if (!validateBalloonColor(v)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'orange' por defecto.", v.c_str());
|
||||
param.balloon.color.at(1) = "orange";
|
||||
} else {
|
||||
param.balloon.color.at(1) = v;
|
||||
}
|
||||
}},
|
||||
{"balloon.color[2]", [validateBalloonColor](const std::string& v) {
|
||||
if (!validateBalloonColor(v)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'red' por defecto.", v.c_str());
|
||||
param.balloon.color.at(2) = "red";
|
||||
} else {
|
||||
param.balloon.color.at(2) = v;
|
||||
}
|
||||
}},
|
||||
{"balloon.color[3]", [validateBalloonColor](const std::string& v) {
|
||||
if (!validateBalloonColor(v)) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Color de globo inválido '%s'. Usando 'green' por defecto.", v.c_str());
|
||||
param.balloon.color.at(3) = "green";
|
||||
} else {
|
||||
param.balloon.color.at(3) = v;
|
||||
}
|
||||
}}};
|
||||
|
||||
// Lambda para intentar cada mapa de parámetros
|
||||
auto try_map = [&](const auto& param_map) -> bool {
|
||||
|
||||
@@ -38,7 +38,7 @@ struct ParamFade {
|
||||
// --- Parámetros de la pantalla de título ---
|
||||
struct ParamTitle {
|
||||
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 title_c_c_position = GameDefaults::Title::TITLE_C_C_POSITION;
|
||||
Color bg_color = Color::fromHex(GameDefaults::Title::BG_COLOR);
|
||||
@@ -57,7 +57,8 @@ struct ParamBalloon {
|
||||
|
||||
// Constructor por defecto
|
||||
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
|
||||
@@ -164,7 +165,10 @@ struct ParamPlayer {
|
||||
|
||||
// Constructor con tonalidades específicas
|
||||
Shirt(const Color& darkest_tone, const Color& dark_tone, const Color& base_tone, const Color& light_tone)
|
||||
: darkest(darkest_tone), dark(dark_tone), base(base_tone), light(light_tone) {}
|
||||
: darkest(darkest_tone),
|
||||
dark(dark_tone),
|
||||
base(base_tone),
|
||||
light(light_tone) {}
|
||||
};
|
||||
|
||||
// Inicialización con valores por defecto
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
#include <functional> // Para function
|
||||
#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
|
||||
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;
|
||||
@@ -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
|
||||
void PathSprite::update() {
|
||||
void PathSprite::update(float delta_time) {
|
||||
if (enabled_ && !has_finished_) {
|
||||
moveThroughCurrentPath();
|
||||
moveThroughCurrentPath(delta_time);
|
||||
goToNextPathOrDie();
|
||||
}
|
||||
}
|
||||
@@ -77,14 +83,14 @@ void PathSprite::addPath(Path path, bool centered) {
|
||||
}
|
||||
}
|
||||
|
||||
// Añade un recorrido
|
||||
void PathSprite::addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easing_function, int waiting_counter) {
|
||||
paths_.emplace_back(createPath(start, end, type, fixed_pos, steps, easing_function), waiting_counter);
|
||||
// Añade un recorrido generado (en segundos)
|
||||
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(start, end, type, fixed_pos, duration_s, waiting_time_s, easing_function);
|
||||
}
|
||||
|
||||
// Añade un recorrido
|
||||
void PathSprite::addPath(const std::vector<SDL_FPoint> &spots, int waiting_counter) {
|
||||
paths_.emplace_back(spots, waiting_counter);
|
||||
// Añade un recorrido por puntos (en segundos)
|
||||
void PathSprite::addPath(const std::vector<SDL_FPoint> &spots, float waiting_time_s) {
|
||||
paths_.emplace_back(spots, waiting_time_s);
|
||||
}
|
||||
|
||||
// Habilita el objeto
|
||||
@@ -95,35 +101,78 @@ void PathSprite::enable() {
|
||||
|
||||
enabled_ = true;
|
||||
|
||||
// Establece la posición
|
||||
// Establece la posición inicial
|
||||
auto &path = paths_.at(current_path_);
|
||||
const auto &p = path.spots.at(path.counter);
|
||||
setPosition(p);
|
||||
if (path.is_point_path) {
|
||||
const auto &p = path.spots.at(path.counter);
|
||||
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
|
||||
void PathSprite::moveThroughCurrentPath() {
|
||||
void PathSprite::moveThroughCurrentPath(float delta_time) {
|
||||
auto &path = paths_.at(current_path_);
|
||||
|
||||
// Establece la posición
|
||||
const auto &p = path.spots.at(path.counter);
|
||||
setPosition(p);
|
||||
if (path.is_point_path) {
|
||||
// Lógica para paths por puntos (compatibilidad)
|
||||
const auto &p = path.spots.at(path.counter);
|
||||
setPosition(p);
|
||||
|
||||
// Comprobar si ha terminado el recorrido
|
||||
if (!path.on_destination) {
|
||||
++path.counter;
|
||||
if (path.counter >= static_cast<int>(path.spots.size())) {
|
||||
path.on_destination = true;
|
||||
path.counter = static_cast<int>(path.spots.size()) - 1;
|
||||
if (!path.on_destination) {
|
||||
++path.counter;
|
||||
if (path.counter >= static_cast<int>(path.spots.size())) {
|
||||
path.on_destination = true;
|
||||
path.counter = static_cast<int>(path.spots.size()) - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Comprobar si ha terminado la espera
|
||||
if (path.on_destination) {
|
||||
if (path.waiting_counter == 0) {
|
||||
path.finished = true;
|
||||
if (path.on_destination) {
|
||||
path.waiting_elapsed += delta_time;
|
||||
if (path.waiting_elapsed >= path.waiting_time_s) {
|
||||
path.finished = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 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 {
|
||||
--path.waiting_counter;
|
||||
// Esperar en destino
|
||||
path.waiting_elapsed += delta_time;
|
||||
if (path.waiting_elapsed >= path.waiting_time_s) {
|
||||
path.finished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,16 +24,31 @@ enum class PathCentered { // Centrado del recorrido
|
||||
};
|
||||
|
||||
// --- Estructuras ---
|
||||
struct Path { // Define un recorrido para el sprite
|
||||
std::vector<SDL_FPoint> spots; // Puntos por los que se desplazará el sprite
|
||||
int waiting_counter; // Tiempo de espera una vez en el destino
|
||||
bool on_destination = false; // Indica si ha llegado al destino
|
||||
bool finished = false; // Indica si ha terminado de esperarse
|
||||
int counter = 0; // Contador interno
|
||||
struct Path { // Define un recorrido para el sprite
|
||||
float start_pos; // Posición inicial
|
||||
float end_pos; // Posición final
|
||||
PathType type; // Tipo de movimiento (horizontal/vertical)
|
||||
float fixed_pos; // Posición fija en el eje contrario
|
||||
float duration_s; // Duración de la animación en segundos
|
||||
float waiting_time_s; // Tiempo de espera una vez en el destino
|
||||
std::function<double(double)> easing_function; // Función de easing
|
||||
float elapsed_time = 0.0f; // Tiempo transcurrido
|
||||
float waiting_elapsed = 0.0f; // Tiempo de espera transcurrido
|
||||
bool on_destination = false; // Indica si ha llegado al destino
|
||||
bool finished = false; // Indica si ha terminado de esperarse
|
||||
|
||||
// Constructor
|
||||
Path(const std::vector<SDL_FPoint> &spots_init, int waiting_counter_init)
|
||||
: spots(spots_init), waiting_counter(waiting_counter_init) {}
|
||||
// Constructor para paths generados
|
||||
Path(float start, float end, PathType path_type, float fixed, float duration, float waiting, std::function<double(double)> easing)
|
||||
: start_pos(start), end_pos(end), type(path_type), fixed_pos(fixed),
|
||||
duration_s(duration), waiting_time_s(waiting), easing_function(std::move(easing)) {}
|
||||
|
||||
// Constructor para paths por puntos (convertido a segundos)
|
||||
Path(const std::vector<SDL_FPoint> &spots_init, float waiting_time_s_init);
|
||||
|
||||
// Variables para paths por puntos
|
||||
std::vector<SDL_FPoint> spots; // Solo para paths por puntos
|
||||
int counter = 0; // Solo para paths por puntos
|
||||
bool is_point_path = false; // Indica si es un path por puntos
|
||||
};
|
||||
|
||||
// --- Funciones ---
|
||||
@@ -48,13 +63,13 @@ class PathSprite : public Sprite {
|
||||
~PathSprite() override = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
void update(); // Actualiza la posición del sprite según el recorrido
|
||||
void update(float delta_time); // Actualiza la posición del sprite según el recorrido (delta_time en segundos)
|
||||
void render() override; // Muestra el sprite por pantalla
|
||||
|
||||
// --- Gestión de recorridos ---
|
||||
void addPath(Path path, bool centered = false); // Añade un recorrido (Path)
|
||||
void addPath(const std::vector<SDL_FPoint> &spots, int waiting_counter = 0); // Añade un recorrido a partir de puntos
|
||||
void addPath(int start, int end, PathType type, int fixed_pos, int steps, const std::function<double(double)> &easing_function, int waiting_counter = 0); // Añade un recorrido generado
|
||||
void addPath(const std::vector<SDL_FPoint> &spots, float waiting_time_s = 0.0f); // Añade un recorrido a partir de puntos
|
||||
void addPath(float start, float end, PathType type, float fixed_pos, float duration_s, const std::function<double(double)> &easing_function, float waiting_time_s = 0.0f); // Añade un recorrido generado
|
||||
|
||||
// --- Estado y control ---
|
||||
void enable(); // Habilita el objeto
|
||||
@@ -71,6 +86,6 @@ class PathSprite : public Sprite {
|
||||
std::vector<Path> paths_; // Caminos a recorrer por el sprite
|
||||
|
||||
// --- Métodos internos ---
|
||||
void moveThroughCurrentPath(); // Coloca el sprite en los diferentes puntos del recorrido
|
||||
void moveThroughCurrentPath(float delta_time); // Coloca el sprite en los diferentes puntos del recorrido
|
||||
void goToNextPathOrDie(); // Cambia de recorrido o finaliza
|
||||
};
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <SDL3/SDL.h> // Para SDL_GetTicks, SDL_FlipMode
|
||||
|
||||
#include <algorithm> // Para clamp, max, min
|
||||
#include <cmath> // Para fmod
|
||||
#include <cstdlib> // Para rand
|
||||
|
||||
#include "animated_sprite.h" // Para AnimatedSprite
|
||||
@@ -22,7 +23,17 @@
|
||||
|
||||
// Constructor
|
||||
Player::Player(const Config &config)
|
||||
: player_sprite_(std::make_unique<AnimatedSprite>(config.texture.at(0), config.animations.at(0))), power_sprite_(std::make_unique<AnimatedSprite>(config.texture.at(4), config.animations.at(1))), enter_name_(std::make_unique<EnterName>()), hi_score_table_(config.hi_score_table), glowing_entry_(config.glowing_entry), stage_info_(config.stage_info), play_area_(*config.play_area), id_(config.id), default_pos_x_(config.x), default_pos_y_(config.y), demo_(config.demo) {
|
||||
: player_sprite_(std::make_unique<AnimatedSprite>(config.texture.at(0), config.animations.at(0))),
|
||||
power_sprite_(std::make_unique<AnimatedSprite>(config.texture.at(4), config.animations.at(1))),
|
||||
enter_name_(std::make_unique<EnterName>()),
|
||||
hi_score_table_(config.hi_score_table),
|
||||
glowing_entry_(config.glowing_entry),
|
||||
stage_info_(config.stage_info),
|
||||
play_area_(*config.play_area),
|
||||
id_(config.id),
|
||||
default_pos_x_(config.x),
|
||||
default_pos_y_(config.y),
|
||||
demo_(config.demo) {
|
||||
// Configura objetos
|
||||
player_sprite_->addTexture(config.texture.at(1));
|
||||
player_sprite_->addTexture(config.texture.at(2));
|
||||
@@ -49,17 +60,14 @@ void Player::init() {
|
||||
power_up_counter_ = POWERUP_COUNTER;
|
||||
extra_hit_ = false;
|
||||
coffees_ = 0;
|
||||
continue_ticks_ = 0;
|
||||
continue_counter_ = 10;
|
||||
name_entry_ticks_ = 0;
|
||||
name_entry_idle_counter_ = 0;
|
||||
name_entry_total_counter_ = 0;
|
||||
name_entry_idle_time_accumulator_ = 0.0f;
|
||||
name_entry_total_time_accumulator_ = 0.0f;
|
||||
shiftColliders();
|
||||
vel_x_ = 0;
|
||||
vel_y_ = 0;
|
||||
score_ = 0;
|
||||
score_multiplier_ = 1.0F;
|
||||
cant_fire_counter_ = 10;
|
||||
enter_name_->init(last_enter_name_);
|
||||
|
||||
// Establece la posición del sprite
|
||||
@@ -138,35 +146,37 @@ void Player::setInputEnteringName(Input::Action action) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
name_entry_idle_counter_ = 0;
|
||||
name_entry_idle_time_accumulator_ = 0.0f;
|
||||
}
|
||||
|
||||
// Mueve el jugador a la posición y animación que le corresponde
|
||||
void Player::move() {
|
||||
// Sistema de movimiento
|
||||
void Player::move(float deltaTime) {
|
||||
switch (playing_state_) {
|
||||
case State::PLAYING:
|
||||
handlePlayingMovement();
|
||||
handlePlayingMovement(deltaTime);
|
||||
break;
|
||||
case State::ROLLING:
|
||||
handleRollingMovement();
|
||||
break;
|
||||
case State::TITLE_ANIMATION:
|
||||
handleTitleAnimation();
|
||||
handleTitleAnimation(deltaTime);
|
||||
break;
|
||||
case State::CONTINUE_TIME_OUT:
|
||||
handleContinueTimeOut();
|
||||
break;
|
||||
case State::LEAVING_SCREEN:
|
||||
handleLeavingScreen();
|
||||
updateStepCounter(deltaTime);
|
||||
handleLeavingScreen(deltaTime);
|
||||
break;
|
||||
case State::ENTERING_SCREEN:
|
||||
handleEnteringScreen();
|
||||
updateStepCounter(deltaTime);
|
||||
handleEnteringScreen(deltaTime);
|
||||
break;
|
||||
case State::CREDITS:
|
||||
handleCreditsMovement();
|
||||
handleCreditsMovement(deltaTime);
|
||||
break;
|
||||
case State::WAITING:
|
||||
handleWaitingMovement();
|
||||
handleWaitingMovement(deltaTime);
|
||||
break;
|
||||
case State::RECOVER:
|
||||
handleRecoverMovement();
|
||||
@@ -176,9 +186,10 @@ void Player::move() {
|
||||
}
|
||||
}
|
||||
|
||||
void Player::handlePlayingMovement() {
|
||||
// Mueve el jugador a derecha o izquierda
|
||||
pos_x_ += vel_x_;
|
||||
// Movimiento time-based durante el juego
|
||||
void Player::handlePlayingMovement(float deltaTime) {
|
||||
// Mueve el jugador a derecha o izquierda (time-based en segundos)
|
||||
pos_x_ += vel_x_ * deltaTime;
|
||||
|
||||
// Si el jugador abandona el area de juego por los laterales, restaura su posición
|
||||
const float MIN_X = play_area_.x - 5;
|
||||
@@ -215,7 +226,7 @@ void Player::handleRollingGroundCollision() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player_sprite_->getVelY() < 2.0F) {
|
||||
if (player_sprite_->getVelY() < 120.0F) { // 2.0F * 60fps = 120.0F pixels/segundo
|
||||
handleRollingStop();
|
||||
} else {
|
||||
handleRollingBounce();
|
||||
@@ -242,10 +253,10 @@ void Player::handleRollingBounce() {
|
||||
playSound("jump.wav");
|
||||
}
|
||||
|
||||
void Player::handleTitleAnimation() {
|
||||
void Player::handleTitleAnimation(float deltaTime) {
|
||||
setInputBasedOnPlayerId();
|
||||
|
||||
pos_x_ += vel_x_ * 2.0F;
|
||||
pos_x_ += (vel_x_ * 2.0F) * deltaTime;
|
||||
const float MIN_X = -WIDTH;
|
||||
const float MAX_X = play_area_.w;
|
||||
pos_x_ = std::clamp(pos_x_, MIN_X, MAX_X);
|
||||
@@ -264,11 +275,11 @@ void Player::handleContinueTimeOut() {
|
||||
}
|
||||
}
|
||||
|
||||
void Player::handleLeavingScreen() {
|
||||
updateStepCounter();
|
||||
void Player::handleLeavingScreen(float deltaTime) {
|
||||
// updateStepCounter se llama desde move() con deltaTime
|
||||
setInputBasedOnPlayerId();
|
||||
|
||||
pos_x_ += vel_x_;
|
||||
pos_x_ += vel_x_ * deltaTime;
|
||||
const float MIN_X = -WIDTH;
|
||||
const float MAX_X = play_area_.w;
|
||||
pos_x_ = std::clamp(pos_x_, MIN_X, MAX_X);
|
||||
@@ -279,15 +290,15 @@ void Player::handleLeavingScreen() {
|
||||
}
|
||||
}
|
||||
|
||||
void Player::handleEnteringScreen() {
|
||||
updateStepCounter();
|
||||
void Player::handleEnteringScreen(float deltaTime) {
|
||||
// updateStepCounter se llama desde move() con deltaTime
|
||||
|
||||
switch (id_) {
|
||||
case Id::PLAYER1:
|
||||
handlePlayer1Entering();
|
||||
handlePlayer1Entering(deltaTime);
|
||||
break;
|
||||
case Id::PLAYER2:
|
||||
handlePlayer2Entering();
|
||||
handlePlayer2Entering(deltaTime);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -296,26 +307,27 @@ void Player::handleEnteringScreen() {
|
||||
shiftSprite();
|
||||
}
|
||||
|
||||
void Player::handlePlayer1Entering() {
|
||||
void Player::handlePlayer1Entering(float deltaTime) {
|
||||
setInputPlaying(Input::Action::RIGHT);
|
||||
pos_x_ += vel_x_;
|
||||
pos_x_ += vel_x_ * deltaTime;
|
||||
if (pos_x_ > default_pos_x_) {
|
||||
pos_x_ = default_pos_x_;
|
||||
setPlayingState(State::PLAYING);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::handlePlayer2Entering() {
|
||||
void Player::handlePlayer2Entering(float deltaTime) {
|
||||
setInputPlaying(Input::Action::LEFT);
|
||||
pos_x_ += vel_x_;
|
||||
pos_x_ += vel_x_ * deltaTime;
|
||||
if (pos_x_ < default_pos_x_) {
|
||||
pos_x_ = default_pos_x_;
|
||||
setPlayingState(State::PLAYING);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::handleCreditsMovement() {
|
||||
pos_x_ += vel_x_ / 2.0F;
|
||||
// Movimiento general en la pantalla de créditos (time-based)
|
||||
void Player::handleCreditsMovement(float deltaTime) {
|
||||
pos_x_ += (vel_x_ / 2.0F) * deltaTime;
|
||||
|
||||
if (vel_x_ > 0) {
|
||||
handleCreditsRightMovement();
|
||||
@@ -341,10 +353,12 @@ void Player::handleCreditsLeftMovement() {
|
||||
}
|
||||
}
|
||||
|
||||
void Player::handleWaitingMovement() {
|
||||
++waiting_counter_;
|
||||
if (waiting_counter_ == WAITING_COUNTER) {
|
||||
waiting_counter_ = 0;
|
||||
// Controla la animación del jugador saludando (time-based)
|
||||
void Player::handleWaitingMovement(float deltaTime) {
|
||||
waiting_time_accumulator_ += deltaTime;
|
||||
const float WAITING_DURATION_S = static_cast<float>(WAITING_COUNTER) / 60.0f; // Convert frames to seconds
|
||||
if (waiting_time_accumulator_ >= WAITING_DURATION_S) {
|
||||
waiting_time_accumulator_ = 0.0f;
|
||||
player_sprite_->resetAnimation();
|
||||
}
|
||||
}
|
||||
@@ -370,9 +384,12 @@ void Player::setInputBasedOnPlayerId() {
|
||||
}
|
||||
}
|
||||
|
||||
void Player::updateStepCounter() {
|
||||
++step_counter_;
|
||||
if (step_counter_ % 10 == 0) {
|
||||
// Incrementa o ajusta el contador de pasos (time-based)
|
||||
void Player::updateStepCounter(float deltaTime) {
|
||||
step_time_accumulator_ += deltaTime;
|
||||
const float STEP_INTERVAL_S = 10.0f / 60.0f; // 10 frames converted to seconds
|
||||
if (step_time_accumulator_ >= STEP_INTERVAL_S) {
|
||||
step_time_accumulator_ = 0.0f;
|
||||
playSound("walk.wav");
|
||||
}
|
||||
}
|
||||
@@ -380,8 +397,22 @@ void Player::updateStepCounter() {
|
||||
// Pinta el jugador en pantalla
|
||||
void Player::render() {
|
||||
if (power_up_ && isPlaying()) {
|
||||
if (power_up_counter_ > (POWERUP_COUNTER / 4) || power_up_counter_ % 20 > 4) {
|
||||
// Convertir lógica de parpadeo a deltaTime en segundos
|
||||
const float TOTAL_POWERUP_TIME_S = static_cast<float>(POWERUP_COUNTER) / 60.0f; // Total time in seconds
|
||||
const float QUARTER_TIME_S = TOTAL_POWERUP_TIME_S / 4.0f; // 25% del tiempo total
|
||||
|
||||
if (power_up_time_accumulator_ > QUARTER_TIME_S) {
|
||||
// En los primeros 75% del tiempo, siempre visible
|
||||
power_sprite_->render();
|
||||
} else {
|
||||
// En el último 25%, parpadea cada 20 frames (≈0.333s)
|
||||
constexpr float BLINK_PERIOD_S = 20.0f / 60.0f; // 20 frames in seconds
|
||||
constexpr float VISIBLE_PROPORTION = 4.0f / 20.0f; // 4 frames visible de 20 total
|
||||
|
||||
float cycle_position = fmod(power_up_time_accumulator_, BLINK_PERIOD_S) / BLINK_PERIOD_S;
|
||||
if (cycle_position >= VISIBLE_PROPORTION) {
|
||||
power_sprite_->render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,10 +476,9 @@ auto Player::computeAnimation() const -> std::pair<std::string, SDL_FlipMode> {
|
||||
}
|
||||
|
||||
// Establece la animación correspondiente al estado
|
||||
void Player::setAnimation() {
|
||||
void Player::setAnimation(float deltaTime) {
|
||||
switch (playing_state_) {
|
||||
case State::PLAYING:
|
||||
case State::ENTERING_NAME_GAME_COMPLETED:
|
||||
case State::ENTERING_SCREEN:
|
||||
case State::LEAVING_SCREEN:
|
||||
case State::TITLE_ANIMATION:
|
||||
@@ -474,6 +504,7 @@ void Player::setAnimation() {
|
||||
case State::CONTINUE:
|
||||
player_sprite_->setCurrentAnimation("dizzy");
|
||||
break;
|
||||
case State::ENTERING_NAME_GAME_COMPLETED:
|
||||
case State::CELEBRATING:
|
||||
player_sprite_->setCurrentAnimation("celebration");
|
||||
break;
|
||||
@@ -481,110 +512,33 @@ void Player::setAnimation() {
|
||||
break;
|
||||
}
|
||||
|
||||
player_sprite_->update();
|
||||
power_sprite_->update();
|
||||
// La diferencia clave: usa deltaTime para las animaciones
|
||||
player_sprite_->update(deltaTime);
|
||||
power_sprite_->update(deltaTime);
|
||||
}
|
||||
|
||||
// Actualiza el valor de la variable
|
||||
void Player::updateCooldown() {
|
||||
if (playing_state_ != State::PLAYING) {
|
||||
return;
|
||||
}
|
||||
// Actualiza al jugador con deltaTime (time-based)
|
||||
void Player::update(float deltaTime) {
|
||||
move(deltaTime); // Sistema de movimiento time-based
|
||||
setAnimation(deltaTime); // Animaciones time-based
|
||||
shiftColliders(); // Sin cambios (posicional)
|
||||
updateFireSystem(deltaTime); // Sistema de disparo de dos líneas
|
||||
updatePowerUp(deltaTime); // Sistema de power-up time-based
|
||||
updateInvulnerable(deltaTime); // Sistema de invulnerabilidad time-based
|
||||
updateScoreboard(); // Sin cambios (no temporal)
|
||||
updateContinueCounter(deltaTime); // Sistema de continue time-based
|
||||
updateEnterNameCounter(deltaTime); // Sistema de name entry time-based
|
||||
updateShowingName(deltaTime); // Sistema de showing name time-based
|
||||
}
|
||||
|
||||
if (cant_fire_counter_ > 0) {
|
||||
handleFiringCooldown();
|
||||
void Player::passShowingName() {
|
||||
if (game_completed_) {
|
||||
setPlayingState(State::LEAVING_SCREEN);
|
||||
} else {
|
||||
handleRecoilAndCooling();
|
||||
setPlayingState(State::CONTINUE);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::handleFiringCooldown() {
|
||||
cooling_state_counter_ = COOLING_DURATION;
|
||||
|
||||
// Transition to recoiling state at halfway point
|
||||
if (cant_fire_counter_ == recoiling_state_duration_ / 2) {
|
||||
transitionToRecoiling();
|
||||
}
|
||||
|
||||
--cant_fire_counter_;
|
||||
if (cant_fire_counter_ == 0) {
|
||||
recoiling_state_counter_ = recoiling_state_duration_;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::handleRecoilAndCooling() {
|
||||
if (recoiling_state_counter_ > 0) {
|
||||
--recoiling_state_counter_;
|
||||
return;
|
||||
}
|
||||
|
||||
handleCoolingState();
|
||||
}
|
||||
|
||||
void Player::handleCoolingState() {
|
||||
if (cooling_state_counter_ > COOLING_COMPLETE) {
|
||||
if (cooling_state_counter_ == COOLING_DURATION) {
|
||||
transitionToCooling();
|
||||
}
|
||||
--cooling_state_counter_;
|
||||
}
|
||||
|
||||
if (cooling_state_counter_ == COOLING_COMPLETE) {
|
||||
completeCooling();
|
||||
}
|
||||
}
|
||||
|
||||
void Player::transitionToRecoiling() {
|
||||
switch (firing_state_) {
|
||||
case State::FIRING_LEFT:
|
||||
setFiringState(State::RECOILING_LEFT);
|
||||
break;
|
||||
case State::FIRING_RIGHT:
|
||||
setFiringState(State::RECOILING_RIGHT);
|
||||
break;
|
||||
case State::FIRING_UP:
|
||||
setFiringState(State::RECOILING_UP);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::transitionToCooling() {
|
||||
switch (firing_state_) {
|
||||
case State::RECOILING_LEFT:
|
||||
setFiringState(State::COOLING_LEFT);
|
||||
break;
|
||||
case State::RECOILING_RIGHT:
|
||||
setFiringState(State::COOLING_RIGHT);
|
||||
break;
|
||||
case State::RECOILING_UP:
|
||||
setFiringState(State::COOLING_UP);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::completeCooling() {
|
||||
setFiringState(State::FIRING_NONE);
|
||||
cooling_state_counter_ = -1;
|
||||
}
|
||||
|
||||
// Actualiza al jugador a su posicion, animación y controla los contadores
|
||||
void Player::update() {
|
||||
move();
|
||||
setAnimation();
|
||||
shiftColliders();
|
||||
updateCooldown();
|
||||
updatePowerUp();
|
||||
updateInvulnerable();
|
||||
updateScoreboard();
|
||||
updateContinueCounter();
|
||||
updateEnterNameCounter();
|
||||
updateShowingName();
|
||||
}
|
||||
|
||||
// Incrementa la puntuación del jugador
|
||||
void Player::addScore(int score, int lowest_hi_score_entry) {
|
||||
if (isPlaying()) {
|
||||
@@ -624,6 +578,9 @@ void Player::setPlayingState(State state) {
|
||||
|
||||
switch (playing_state_) {
|
||||
case State::RECOVER: {
|
||||
score_ = 0; // Pon los puntos a cero para que no se vea en el marcador
|
||||
score_multiplier_ = 1.0F;
|
||||
setScoreboardMode(Scoreboard::Mode::SCORE);
|
||||
break;
|
||||
}
|
||||
case State::RESPAWNING: {
|
||||
@@ -641,8 +598,8 @@ void Player::setPlayingState(State state) {
|
||||
}
|
||||
case State::CONTINUE: {
|
||||
// Inicializa el contador de continuar
|
||||
continue_ticks_ = SDL_GetTicks();
|
||||
continue_counter_ = 9;
|
||||
continue_time_accumulator_ = 0.0f; // Initialize time accumulator
|
||||
playSound("continue_clock.wav");
|
||||
setScoreboardMode(Scoreboard::Mode::CONTINUE);
|
||||
break;
|
||||
@@ -661,6 +618,7 @@ void Player::setPlayingState(State state) {
|
||||
}
|
||||
pos_y_ = default_pos_y_;
|
||||
waiting_counter_ = 0;
|
||||
waiting_time_accumulator_ = 0.0f; // Initialize time accumulator
|
||||
shiftSprite();
|
||||
player_sprite_->setCurrentAnimation("hello");
|
||||
player_sprite_->animtionPause();
|
||||
@@ -672,7 +630,7 @@ void Player::setPlayingState(State state) {
|
||||
break;
|
||||
}
|
||||
case State::SHOWING_NAME: {
|
||||
showing_name_ticks_ = SDL_GetTicks();
|
||||
showing_name_time_accumulator_ = 0.0f; // Inicializar acumulador time-based
|
||||
setScoreboardMode(Scoreboard::Mode::SHOW_NAME);
|
||||
Scoreboard::get()->setRecordName(scoreboard_panel_, last_enter_name_);
|
||||
addScoreToScoreBoard();
|
||||
@@ -681,15 +639,15 @@ void Player::setPlayingState(State state) {
|
||||
case State::ROLLING: {
|
||||
// Activa la animación de rodar dando botes
|
||||
player_sprite_->setCurrentAnimation("rolling");
|
||||
player_sprite_->setAnimationSpeed(4);
|
||||
player_sprite_->setVelY(-6.6F); // Velocidad inicial
|
||||
player_sprite_->setAccelY(0.2F); // Gravedad
|
||||
player_sprite_->setPosY(pos_y_ - 2); // Para "sacarlo" del suelo, ya que está hundido un pixel para ocultar el outline de los pies
|
||||
(rand() % 2 == 0) ? player_sprite_->setVelX(3.3F) : player_sprite_->setVelX(-3.3F);
|
||||
player_sprite_->setAnimationSpeed(4.0f / 60.0f); // 4 frames convertido a segundos
|
||||
player_sprite_->setVelY(-396.0F); // Velocidad inicial (6.6 * 60 = 396 pixels/s)
|
||||
player_sprite_->setAccelY(720.0F); // Gravedad (0.2 * 60² = 720 pixels/s²)
|
||||
player_sprite_->setPosY(pos_y_ - 2); // Para "sacarlo" del suelo, ya que está hundido un pixel para ocultar el outline de los pies
|
||||
(rand() % 2 == 0) ? player_sprite_->setVelX(198.0F) : player_sprite_->setVelX(-198.0F); // 3.3 * 60 = 198 pixels/s
|
||||
break;
|
||||
}
|
||||
case State::TITLE_ANIMATION: {
|
||||
// Activa la animación de rodar
|
||||
// Activa la animación de caminar
|
||||
player_sprite_->setCurrentAnimation("walk");
|
||||
playSound("voice_credit_thankyou.wav");
|
||||
break;
|
||||
@@ -701,11 +659,11 @@ void Player::setPlayingState(State state) {
|
||||
}
|
||||
case State::CONTINUE_TIME_OUT: {
|
||||
// Activa la animación de sacar al jugador de la zona de juego
|
||||
player_sprite_->setAccelY(0.2F);
|
||||
player_sprite_->setVelY(-4.0F);
|
||||
player_sprite_->setAccelY(720.0F); // 0.2 * 60² = 720 pixels/s²
|
||||
player_sprite_->setVelY(-240.0F); // -4.0 * 60 = -240 pixels/s
|
||||
player_sprite_->setVelX(0.0F);
|
||||
player_sprite_->setCurrentAnimation("rolling");
|
||||
player_sprite_->setAnimationSpeed(5);
|
||||
player_sprite_->setAnimationSpeed(5.0f / 60.0f); // 5 frames convertido a segundos
|
||||
setScoreboardMode(Scoreboard::Mode::GAME_OVER);
|
||||
playSound("voice_aw_aw_aw.wav");
|
||||
playSound("jump.wav");
|
||||
@@ -721,19 +679,21 @@ void Player::setPlayingState(State state) {
|
||||
break;
|
||||
}
|
||||
case State::ENTERING_NAME_GAME_COMPLETED: {
|
||||
setWalkingState(State::WALKING_STOP);
|
||||
setFiringState(State::FIRING_NONE);
|
||||
// setWalkingState(State::WALKING_STOP);
|
||||
// setFiringState(State::FIRING_NONE);
|
||||
setScoreboardMode(Scoreboard::Mode::ENTER_NAME);
|
||||
break;
|
||||
}
|
||||
case State::LEAVING_SCREEN: {
|
||||
step_counter_ = 0;
|
||||
step_time_accumulator_ = 0.0f; // Initialize time accumulator
|
||||
setScoreboardMode(Scoreboard::Mode::GAME_COMPLETED);
|
||||
break;
|
||||
}
|
||||
case State::ENTERING_SCREEN: {
|
||||
init();
|
||||
step_counter_ = 0;
|
||||
step_time_accumulator_ = 0.0f; // Initialize time accumulator
|
||||
setScoreboardMode(Scoreboard::Mode::SCORE);
|
||||
switch (id_) {
|
||||
case Id::PLAYER1:
|
||||
@@ -774,32 +734,35 @@ void Player::decScoreMultiplier() {
|
||||
void Player::setInvulnerable(bool value) {
|
||||
invulnerable_ = value;
|
||||
invulnerable_counter_ = invulnerable_ ? INVULNERABLE_COUNTER : 0;
|
||||
invulnerable_time_accumulator_ = invulnerable_ ? static_cast<float>(INVULNERABLE_COUNTER) / 60.0f : 0.0f; // Convert frames to seconds
|
||||
}
|
||||
|
||||
// Monitoriza el estado
|
||||
void Player::updateInvulnerable() {
|
||||
// Monitoriza el estado (time-based)
|
||||
void Player::updateInvulnerable(float deltaTime) {
|
||||
if (playing_state_ == State::PLAYING && invulnerable_) {
|
||||
if (invulnerable_counter_ > 0) {
|
||||
--invulnerable_counter_;
|
||||
|
||||
// Frecuencia fija de parpadeo (como el original)
|
||||
constexpr int blink_speed = 8;
|
||||
|
||||
// Calcula proporción decreciente: menos textura blanca hacia el final
|
||||
// Al inicio: 50-50, hacia el final: 70-30 (menos blanco)
|
||||
float progress = 1.0f - (static_cast<float>(invulnerable_counter_) / INVULNERABLE_COUNTER);
|
||||
int white_frames = static_cast<int>((0.5f - progress * 0.2f) * blink_speed);
|
||||
|
||||
// Alterna entre texturas con proporción variable
|
||||
bool should_show_invulnerable = (invulnerable_counter_ % blink_speed) < white_frames;
|
||||
if (invulnerable_time_accumulator_ > 0) {
|
||||
invulnerable_time_accumulator_ -= deltaTime;
|
||||
|
||||
// Frecuencia fija de parpadeo adaptada a deltaTime (en segundos)
|
||||
constexpr float BLINK_PERIOD_S = 8.0f / 60.0f; // 8 frames convertidos a segundos
|
||||
|
||||
// Calcula proporción decreciente basada en tiempo restante
|
||||
const float TOTAL_INVULNERABLE_TIME_S = static_cast<float>(INVULNERABLE_COUNTER) / 60.0f;
|
||||
float progress = 1.0f - (invulnerable_time_accumulator_ / TOTAL_INVULNERABLE_TIME_S);
|
||||
float white_proportion = 0.5f - progress * 0.2f; // Menos blanco hacia el final
|
||||
|
||||
// Calcula si debe mostrar textura de invulnerabilidad basado en el ciclo temporal
|
||||
float cycle_position = fmod(invulnerable_time_accumulator_, BLINK_PERIOD_S) / BLINK_PERIOD_S;
|
||||
bool should_show_invulnerable = cycle_position < white_proportion;
|
||||
size_t target_texture = should_show_invulnerable ? INVULNERABLE_TEXTURE : coffees_;
|
||||
|
||||
|
||||
// Solo cambia textura si es diferente (optimización)
|
||||
if (player_sprite_->getActiveTexture() != target_texture) {
|
||||
player_sprite_->setActiveTexture(target_texture);
|
||||
}
|
||||
} else {
|
||||
// Fin de invulnerabilidad
|
||||
invulnerable_time_accumulator_ = 0;
|
||||
setInvulnerable(false);
|
||||
player_sprite_->setActiveTexture(coffees_);
|
||||
}
|
||||
@@ -810,14 +773,18 @@ void Player::updateInvulnerable() {
|
||||
void Player::setPowerUp() {
|
||||
power_up_ = true;
|
||||
power_up_counter_ = POWERUP_COUNTER;
|
||||
power_up_time_accumulator_ = static_cast<float>(POWERUP_COUNTER) / 60.0f; // Convert frames to seconds
|
||||
}
|
||||
|
||||
// Actualiza el valor de la variable
|
||||
void Player::updatePowerUp() {
|
||||
// Actualiza el valor de la variable (time-based)
|
||||
void Player::updatePowerUp(float deltaTime) {
|
||||
if (playing_state_ == State::PLAYING) {
|
||||
if (power_up_) {
|
||||
--power_up_counter_;
|
||||
power_up_ = power_up_counter_ > 0;
|
||||
power_up_time_accumulator_ -= deltaTime;
|
||||
power_up_ = power_up_time_accumulator_ > 0;
|
||||
if (!power_up_) {
|
||||
power_up_time_accumulator_ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -854,31 +821,36 @@ void Player::setPlayerTextures(const std::vector<std::shared_ptr<Texture>> &text
|
||||
power_sprite_->setTexture(texture[1]);
|
||||
}
|
||||
|
||||
// Actualiza el contador de continue
|
||||
void Player::updateContinueCounter() {
|
||||
// Actualiza el contador de continue (time-based)
|
||||
void Player::updateContinueCounter(float deltaTime) {
|
||||
if (playing_state_ == State::CONTINUE) {
|
||||
constexpr int TICKS_SPEED = 1000;
|
||||
if (SDL_GetTicks() - continue_ticks_ > TICKS_SPEED) {
|
||||
continue_time_accumulator_ += deltaTime;
|
||||
constexpr float CONTINUE_INTERVAL_S = 1.0f; // 1 segundo
|
||||
if (continue_time_accumulator_ >= CONTINUE_INTERVAL_S) {
|
||||
continue_time_accumulator_ -= CONTINUE_INTERVAL_S;
|
||||
decContinueCounter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el contador de entrar nombre
|
||||
void Player::updateEnterNameCounter() {
|
||||
// Actualiza el contador de entrar nombre (time-based)
|
||||
void Player::updateEnterNameCounter(float deltaTime) {
|
||||
if (playing_state_ == State::ENTERING_NAME || playing_state_ == State::ENTERING_NAME_GAME_COMPLETED) {
|
||||
constexpr int TICKS_SPEED = 1000;
|
||||
if (SDL_GetTicks() - name_entry_ticks_ > TICKS_SPEED) {
|
||||
name_entry_time_accumulator_ += deltaTime;
|
||||
constexpr float NAME_ENTRY_INTERVAL_S = 1.0f; // 1 segundo
|
||||
if (name_entry_time_accumulator_ >= NAME_ENTRY_INTERVAL_S) {
|
||||
name_entry_time_accumulator_ -= NAME_ENTRY_INTERVAL_S;
|
||||
decNameEntryCounter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el estado de SHOWING_NAME
|
||||
void Player::updateShowingName() {
|
||||
// Actualiza el estado de SHOWING_NAME (time-based)
|
||||
void Player::updateShowingName(float deltaTime) {
|
||||
if (playing_state_ == State::SHOWING_NAME) {
|
||||
constexpr int TICKS_SPEED = 5000;
|
||||
if (SDL_GetTicks() - name_entry_ticks_ > TICKS_SPEED) {
|
||||
showing_name_time_accumulator_ += deltaTime;
|
||||
constexpr float SHOWING_NAME_DURATION_S = 5.0f; // 5 segundos
|
||||
if (showing_name_time_accumulator_ >= SHOWING_NAME_DURATION_S) {
|
||||
game_completed_ ? setPlayingState(State::LEAVING_SCREEN) : setPlayingState(State::CONTINUE);
|
||||
}
|
||||
}
|
||||
@@ -886,7 +858,7 @@ void Player::updateShowingName() {
|
||||
|
||||
// Decrementa el contador de continuar
|
||||
void Player::decContinueCounter() {
|
||||
continue_ticks_ = SDL_GetTicks();
|
||||
continue_time_accumulator_ = 0.0f; // Reset time accumulator
|
||||
--continue_counter_;
|
||||
if (continue_counter_ < 0) {
|
||||
setPlayingState(State::CONTINUE_TIME_OUT);
|
||||
@@ -897,17 +869,16 @@ void Player::decContinueCounter() {
|
||||
|
||||
// Decrementa el contador de entrar nombre
|
||||
void Player::decNameEntryCounter() {
|
||||
name_entry_ticks_ = SDL_GetTicks();
|
||||
name_entry_time_accumulator_ = 0.0f; // Reset time accumulator
|
||||
|
||||
// Actualiza contadores
|
||||
++name_entry_idle_counter_;
|
||||
++name_entry_total_counter_;
|
||||
// Incrementa acumuladores de tiempo (1 segundo)
|
||||
name_entry_idle_time_accumulator_ += 1.0f;
|
||||
name_entry_total_time_accumulator_ += 1.0f;
|
||||
|
||||
// Comprueba los contadores
|
||||
if ((name_entry_total_counter_ >= param.game.name_entry_total_time) ||
|
||||
(name_entry_idle_counter_ >= param.game.name_entry_idle_time)) {
|
||||
name_entry_total_counter_ = 0;
|
||||
name_entry_idle_counter_ = 0;
|
||||
if ((name_entry_total_time_accumulator_ >= param.game.name_entry_total_time) ||
|
||||
(name_entry_idle_time_accumulator_ >= param.game.name_entry_idle_time)) {
|
||||
name_entry_total_time_accumulator_ = 0.0f;
|
||||
name_entry_idle_time_accumulator_ = 0.0f;
|
||||
if (playing_state_ == State::ENTERING_NAME) {
|
||||
last_enter_name_ = getRecordName();
|
||||
setPlayingState(State::SHOWING_NAME);
|
||||
@@ -967,4 +938,161 @@ void Player::addScoreToScoreBoard() const {
|
||||
void Player::addCredit() {
|
||||
++credits_used_;
|
||||
playSound("credit.wav");
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// SISTEMA DE DISPARO DE DOS LÍNEAS
|
||||
// ========================================
|
||||
|
||||
// Método principal del sistema de disparo
|
||||
void Player::updateFireSystem(float deltaTime) {
|
||||
updateFunctionalLine(deltaTime); // Línea 1: CanFire
|
||||
updateVisualLine(deltaTime); // Línea 2: Animaciones
|
||||
}
|
||||
|
||||
// LÍNEA 1: Sistema Funcional (CanFire)
|
||||
void Player::updateFunctionalLine(float deltaTime) {
|
||||
if (fire_cooldown_timer_ > 0) {
|
||||
fire_cooldown_timer_ -= deltaTime;
|
||||
can_fire_new_system_ = false;
|
||||
} else {
|
||||
fire_cooldown_timer_ = 0; // Evitar valores negativos
|
||||
can_fire_new_system_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
// LÍNEA 2: Sistema Visual (Animaciones)
|
||||
void Player::updateVisualLine(float deltaTime) {
|
||||
if (visual_fire_state_ == VisualFireState::NORMAL) {
|
||||
return; // No hay temporizador activo en estado NORMAL
|
||||
}
|
||||
|
||||
visual_state_timer_ -= deltaTime;
|
||||
|
||||
switch (visual_fire_state_) {
|
||||
case VisualFireState::AIMING:
|
||||
if (visual_state_timer_ <= 0) {
|
||||
transitionToRecoilingNew();
|
||||
}
|
||||
break;
|
||||
|
||||
case VisualFireState::RECOILING:
|
||||
if (visual_state_timer_ <= 0) {
|
||||
transitionToThreatPose();
|
||||
}
|
||||
break;
|
||||
|
||||
case VisualFireState::THREAT_POSE:
|
||||
if (visual_state_timer_ <= 0) {
|
||||
transitionToNormalNew();
|
||||
}
|
||||
break;
|
||||
|
||||
case VisualFireState::NORMAL:
|
||||
// Ya manejado arriba
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Inicia un disparo en ambas líneas
|
||||
void Player::startFiringSystem(int cooldown_frames) {
|
||||
// LÍNEA 1: Inicia cooldown funcional
|
||||
fire_cooldown_timer_ = static_cast<float>(cooldown_frames) / 60.0f; // Convertir frames a segundos
|
||||
can_fire_new_system_ = false;
|
||||
|
||||
// LÍNEA 2: Resetea completamente el estado visual
|
||||
aiming_duration_ = fire_cooldown_timer_ * AIMING_DURATION_FACTOR; // 50% del cooldown
|
||||
recoiling_duration_ = aiming_duration_ * RECOILING_DURATION_MULTIPLIER; // 4 veces la duración de aiming
|
||||
|
||||
visual_fire_state_ = VisualFireState::AIMING;
|
||||
visual_state_timer_ = aiming_duration_;
|
||||
|
||||
updateFiringStateFromVisual(); // Sincroniza firing_state_ para animaciones
|
||||
}
|
||||
|
||||
// Sincroniza firing_state_ con visual_fire_state_
|
||||
void Player::updateFiringStateFromVisual() {
|
||||
// Mantener la dirección actual del disparo
|
||||
State base_state = State::FIRING_NONE;
|
||||
|
||||
if (firing_state_ == State::FIRING_LEFT || firing_state_ == State::RECOILING_LEFT || firing_state_ == State::COOLING_LEFT) {
|
||||
base_state = State::FIRING_LEFT;
|
||||
} else if (firing_state_ == State::FIRING_RIGHT || firing_state_ == State::RECOILING_RIGHT || firing_state_ == State::COOLING_RIGHT) {
|
||||
base_state = State::FIRING_RIGHT;
|
||||
} else if (firing_state_ == State::FIRING_UP || firing_state_ == State::RECOILING_UP || firing_state_ == State::COOLING_UP) {
|
||||
base_state = State::FIRING_UP;
|
||||
}
|
||||
|
||||
switch (visual_fire_state_) {
|
||||
case VisualFireState::NORMAL:
|
||||
firing_state_ = State::FIRING_NONE;
|
||||
break;
|
||||
|
||||
case VisualFireState::AIMING:
|
||||
firing_state_ = base_state; // FIRING_LEFT/RIGHT/UP
|
||||
break;
|
||||
|
||||
case VisualFireState::RECOILING:
|
||||
switch (base_state) {
|
||||
case State::FIRING_LEFT:
|
||||
firing_state_ = State::RECOILING_LEFT;
|
||||
break;
|
||||
case State::FIRING_RIGHT:
|
||||
firing_state_ = State::RECOILING_RIGHT;
|
||||
break;
|
||||
case State::FIRING_UP:
|
||||
firing_state_ = State::RECOILING_UP;
|
||||
break;
|
||||
default:
|
||||
firing_state_ = State::RECOILING_UP;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case VisualFireState::THREAT_POSE:
|
||||
switch (base_state) {
|
||||
case State::FIRING_LEFT:
|
||||
firing_state_ = State::COOLING_LEFT;
|
||||
break;
|
||||
case State::FIRING_RIGHT:
|
||||
firing_state_ = State::COOLING_RIGHT;
|
||||
break;
|
||||
case State::FIRING_UP:
|
||||
firing_state_ = State::COOLING_UP;
|
||||
break;
|
||||
default:
|
||||
firing_state_ = State::COOLING_UP;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Transiciones del sistema visual
|
||||
void Player::transitionToRecoilingNew() {
|
||||
visual_fire_state_ = VisualFireState::RECOILING;
|
||||
visual_state_timer_ = recoiling_duration_;
|
||||
updateFiringStateFromVisual();
|
||||
}
|
||||
|
||||
void Player::transitionToThreatPose() {
|
||||
visual_fire_state_ = VisualFireState::THREAT_POSE;
|
||||
|
||||
// Calcular threat_pose_duration ajustada:
|
||||
// Duración original (833ms) menos el tiempo extra que ahora dura recoiling
|
||||
float original_recoiling_duration = fire_cooldown_timer_; // Era 100% del cooldown
|
||||
float new_recoiling_duration = aiming_duration_ * RECOILING_DURATION_MULTIPLIER; // Ahora es más del cooldown
|
||||
float extra_recoiling_time = new_recoiling_duration - original_recoiling_duration;
|
||||
float adjusted_threat_duration = THREAT_POSE_DURATION - extra_recoiling_time;
|
||||
|
||||
// Asegurar que no sea negativo
|
||||
visual_state_timer_ = std::max(adjusted_threat_duration, MIN_THREAT_POSE_DURATION);
|
||||
|
||||
updateFiringStateFromVisual();
|
||||
}
|
||||
|
||||
void Player::transitionToNormalNew() {
|
||||
visual_fire_state_ = VisualFireState::NORMAL;
|
||||
visual_state_timer_ = 0;
|
||||
updateFiringStateFromVisual();
|
||||
}
|
||||
154
source/player.h
@@ -17,7 +17,21 @@
|
||||
|
||||
class Texture;
|
||||
|
||||
// --- Clase Player ---
|
||||
// --- Clase Player: jugador principal del juego ---
|
||||
//
|
||||
// Esta clase gestiona todos los aspectos de un jugador durante el juego,
|
||||
// incluyendo movimiento, disparos, animaciones y estados especiales.
|
||||
//
|
||||
// Funcionalidades principales:
|
||||
// • Sistema de disparo de dos líneas: funcional (cooldown) + visual (animaciones)
|
||||
// • Estados de animación: normal → aiming → recoiling → threat_pose → normal
|
||||
// • Movimiento time-based: compatibilidad con deltaTime para fluidez variable
|
||||
// • Power-ups e invulnerabilidad: coffee machine, extra hits, parpadeos
|
||||
// • Sistema de puntuación: multipliers, high scores, entrada de nombres
|
||||
// • Estados de juego: playing, rolling, continue, entering_name, etc.
|
||||
//
|
||||
// El sistema de disparo utiliza duraciones configurables mediante constantes
|
||||
// para facilitar el ajuste del gameplay y la sensación de disparo.
|
||||
class Player {
|
||||
public:
|
||||
// --- Constantes ---
|
||||
@@ -94,9 +108,9 @@ class Player {
|
||||
~Player() = default;
|
||||
|
||||
// --- Inicialización y ciclo de vida ---
|
||||
void init(); // Inicializa el jugador
|
||||
void update(); // Actualiza estado, animación y contadores
|
||||
void render(); // Dibuja el jugador en pantalla
|
||||
void init(); // Inicializa el jugador
|
||||
void update(float deltaTime); // Actualiza estado, animación y contadores (time-based)
|
||||
void render(); // Dibuja el jugador en pantalla
|
||||
|
||||
// --- Entrada y control ---
|
||||
void setInput(Input::Action action); // Procesa entrada general
|
||||
@@ -104,14 +118,13 @@ class Player {
|
||||
void setInputEnteringName(Input::Action action); // Procesa entrada al introducir nombre
|
||||
|
||||
// --- Movimiento y animación ---
|
||||
void move(); // Mueve el jugador
|
||||
void setAnimation(); // Establece la animación según el estado
|
||||
void move(float deltaTime); // Mueve el jugador (time-based)
|
||||
void setAnimation(float deltaTime); // Establece la animación según el estado (time-based)
|
||||
|
||||
// --- Texturas y animaciones ---
|
||||
void setPlayerTextures(const std::vector<std::shared_ptr<Texture>> &texture); // Cambia las texturas del jugador
|
||||
|
||||
// --- Estados y contadores ---
|
||||
void updateCooldown(); // Actualiza el cooldown de disparo
|
||||
|
||||
// --- Puntuación y marcador ---
|
||||
void addScore(int score, int lowest_hi_score_entry); // Añade puntos
|
||||
@@ -122,7 +135,7 @@ class Player {
|
||||
void setPlayingState(State state); // Cambia el estado de juego
|
||||
void setInvulnerable(bool value); // Establece el valor del estado de invulnerabilidad
|
||||
void setPowerUp(); // Activa el modo PowerUp
|
||||
void updatePowerUp(); // Actualiza el valor de PowerUp
|
||||
void updatePowerUp(float deltaTime); // Actualiza el valor de PowerUp (time-based)
|
||||
void giveExtraHit(); // Concede un toque extra al jugador
|
||||
void removeExtraHit(); // Quita el toque extra al jugador
|
||||
void decContinueCounter(); // Decrementa el contador de continuar
|
||||
@@ -145,7 +158,7 @@ class Player {
|
||||
[[nodiscard]] auto isTitleHidden() const -> bool { return playing_state_ == State::TITLE_HIDDEN; }
|
||||
|
||||
// Getters
|
||||
[[nodiscard]] auto canFire() const -> bool { return cant_fire_counter_ <= 0; }
|
||||
[[nodiscard]] auto canFire() const -> bool { return can_fire_new_system_; } // Usa nuevo sistema
|
||||
[[nodiscard]] auto hasExtraHit() const -> bool { return extra_hit_; }
|
||||
[[nodiscard]] auto isCooling() const -> bool { return firing_state_ == State::COOLING_LEFT || firing_state_ == State::COOLING_UP || firing_state_ == State::COOLING_RIGHT; }
|
||||
[[nodiscard]] auto isRecoiling() const -> bool { return firing_state_ == State::RECOILING_LEFT || firing_state_ == State::RECOILING_UP || firing_state_ == State::RECOILING_RIGHT; }
|
||||
@@ -170,12 +183,12 @@ class Player {
|
||||
[[nodiscard]] static auto getWidth() -> int { return WIDTH; }
|
||||
[[nodiscard]] auto getPlayingState() const -> State { return playing_state_; }
|
||||
[[nodiscard]] auto getName() const -> const std::string & { return name_; }
|
||||
[[nodiscard]] auto get1CC() const -> bool { return game_completed_ && credits_used_ == 1; }
|
||||
[[nodiscard]] auto get1CC() const -> bool { return game_completed_ && credits_used_ <= 1; }
|
||||
[[nodiscard]] auto getEnterNamePositionOverflow() const -> bool { return enter_name_ ? enter_name_->getPositionOverflow() : false; }
|
||||
|
||||
// Setters inline
|
||||
void setController(int index) { controller_index_ = index; }
|
||||
void setCantFireCounter(int counter) { recoiling_state_duration_ = cant_fire_counter_ = counter; }
|
||||
void startFiringSystem(int cooldown_frames); // Método público para iniciar disparo
|
||||
void setFiringState(State state) { firing_state_ = state; }
|
||||
void setInvulnerableCounter(int value) { invulnerable_counter_ = value; }
|
||||
void setName(const std::string &name) { name_ = name; }
|
||||
@@ -186,21 +199,34 @@ class Player {
|
||||
void setWalkingState(State state) { walking_state_ = state; }
|
||||
|
||||
void addCredit();
|
||||
void passShowingName();
|
||||
void setGamepad(std::shared_ptr<Input::Gamepad> gamepad) { gamepad_ = std::move(gamepad); }
|
||||
[[nodiscard]] auto getGamepad() const -> std::shared_ptr<Input::Gamepad> { return gamepad_; }
|
||||
void setUsesKeyboard(bool value) { uses_keyboard_ = value; }
|
||||
[[nodiscard]] auto getUsesKeyboard() const -> bool { return uses_keyboard_; }
|
||||
|
||||
private:
|
||||
// --- Constantes ---
|
||||
static constexpr int POWERUP_COUNTER = 1500; // Duración del estado PowerUp
|
||||
static constexpr int INVULNERABLE_COUNTER = 200; // Duración del estado invulnerable
|
||||
// --- Constantes de física y movimiento ---
|
||||
static constexpr float BASE_SPEED = 90.0f; // Velocidad base del jugador (pixels/segundo)
|
||||
|
||||
// --- Constantes de power-ups y estados especiales ---
|
||||
static constexpr int POWERUP_COUNTER = 1500; // Duración del estado PowerUp (frames)
|
||||
static constexpr int INVULNERABLE_COUNTER = 200; // Duración del estado invulnerable (frames)
|
||||
static constexpr size_t INVULNERABLE_TEXTURE = 3; // Textura usada durante invulnerabilidad
|
||||
static constexpr float BASE_SPEED = 1.5F; // Velocidad base del jugador
|
||||
|
||||
// --- Constantes del sistema de disparo (obsoletas - usar nuevo sistema) ---
|
||||
static constexpr int COOLING_DURATION = 50; // Duración del enfriamiento tras disparar
|
||||
static constexpr int COOLING_COMPLETE = 0; // Valor que indica enfriamiento completado
|
||||
|
||||
// --- Constantes de estados de espera ---
|
||||
static constexpr int WAITING_COUNTER = 1000; // Tiempo de espera en estado de espera
|
||||
|
||||
// --- Constantes del nuevo sistema de disparo de dos líneas ---
|
||||
static constexpr float AIMING_DURATION_FACTOR = 0.5f; // 50% del cooldown funcional
|
||||
static constexpr float RECOILING_DURATION_MULTIPLIER = 4.0f; // 4 veces la duración de aiming
|
||||
static constexpr float THREAT_POSE_DURATION = 50.0f / 60.0f; // 50 frames = ~0.833s (duración base)
|
||||
static constexpr float MIN_THREAT_POSE_DURATION = 6.0f / 60.0f; // 6 frames = ~0.1s (duración mínima)
|
||||
|
||||
// --- Objetos y punteros ---
|
||||
std::unique_ptr<AnimatedSprite> player_sprite_; // Sprite para dibujar el jugador
|
||||
std::unique_ptr<AnimatedSprite> power_sprite_; // Sprite para dibujar el aura del jugador con el poder a tope
|
||||
@@ -221,9 +247,6 @@ class Player {
|
||||
State firing_state_ = State::FIRING_NONE; // Estado del jugador al disparar
|
||||
State playing_state_ = State::WAITING; // Estado del jugador en el juego
|
||||
|
||||
Uint32 continue_ticks_ = 0; // Variable para poder cambiar el contador de continue en función del tiempo
|
||||
Uint32 name_entry_ticks_ = 0; // Variable para poder cambiar el contador de poner nombre en función del tiempo
|
||||
Uint32 showing_name_ticks_ = 0; // Tiempo en el que se entra al estado SHOWING_NAME
|
||||
float pos_x_ = 0.0F; // Posición en el eje X
|
||||
float default_pos_x_; // Posición inicial para el jugador
|
||||
float vel_x_ = 0.0F; // Cantidad de píxeles a desplazarse en el eje X
|
||||
@@ -231,10 +254,36 @@ class Player {
|
||||
int pos_y_ = 0; // Posición en el eje Y
|
||||
int default_pos_y_; // Posición inicial para el jugador
|
||||
int vel_y_ = 0; // Cantidad de píxeles a desplazarse en el eje Y
|
||||
int cant_fire_counter_ = 0; // Contador durante el cual no puede disparar
|
||||
int recoiling_state_counter_ = 0; // Contador para la animación del estado de retroceso
|
||||
int recoiling_state_duration_ = 0; // Número de frames que dura el estado de retroceso
|
||||
int cooling_state_counter_ = 0; // Contador para la animación del estado cooling
|
||||
float invulnerable_time_accumulator_ = 0.0f; // Acumulador de tiempo para invulnerabilidad (time-based)
|
||||
float power_up_time_accumulator_ = 0.0f; // Acumulador de tiempo para power-up (time-based)
|
||||
float continue_time_accumulator_ = 0.0f; // Acumulador de tiempo para continue counter (time-based)
|
||||
float name_entry_time_accumulator_ = 0.0f; // Acumulador de tiempo para name entry counter (time-based)
|
||||
float showing_name_time_accumulator_ = 0.0f; // Acumulador de tiempo para showing name (time-based)
|
||||
float waiting_time_accumulator_ = 0.0f; // Acumulador de tiempo para waiting movement (time-based)
|
||||
float step_time_accumulator_ = 0.0f; // Acumulador de tiempo para step counter (time-based)
|
||||
|
||||
// ========================================
|
||||
// NUEVO SISTEMA DE DISPARO DE DOS LÍNEAS
|
||||
// ========================================
|
||||
|
||||
// LÍNEA 1: SISTEMA FUNCIONAL (CanFire)
|
||||
float fire_cooldown_timer_ = 0.0f; // Tiempo restante hasta poder disparar otra vez
|
||||
bool can_fire_new_system_ = true; // true si puede disparar ahora mismo
|
||||
|
||||
// LÍNEA 2: SISTEMA VISUAL (Animaciones)
|
||||
enum class VisualFireState {
|
||||
NORMAL, // Brazo en posición neutral
|
||||
AIMING, // Brazo alzado (disparando)
|
||||
RECOILING, // Brazo en retroceso
|
||||
THREAT_POSE // Posición amenazante
|
||||
};
|
||||
|
||||
VisualFireState visual_fire_state_ = VisualFireState::NORMAL;
|
||||
float visual_state_timer_ = 0.0f; // Tiempo en el estado visual actual
|
||||
float aiming_duration_ = 0.0f; // Duración del estado AIMING
|
||||
float recoiling_duration_ = 0.0f; // Duración del estado RECOILING
|
||||
|
||||
|
||||
int invulnerable_counter_ = INVULNERABLE_COUNTER; // Contador para la invulnerabilidad
|
||||
int score_ = 0; // Puntos del jugador
|
||||
int coffees_ = 0; // Indica cuántos cafés lleva acumulados
|
||||
@@ -242,8 +291,8 @@ class Player {
|
||||
int power_up_x_offset_ = 0; // Desplazamiento del sprite de PowerUp respecto al sprite del jugador
|
||||
int continue_counter_ = 10; // Contador para poder continuar
|
||||
int controller_index_ = 0; // Índice del array de mandos que utilizará para moverse
|
||||
int name_entry_idle_counter_ = 0; // Contador para poner nombre
|
||||
int name_entry_total_counter_ = 0; // Segundos totales que lleva acumulados poniendo nombre
|
||||
float name_entry_idle_time_accumulator_ = 0.0f; // Tiempo idle acumulado para poner nombre (milisegundos)
|
||||
float name_entry_total_time_accumulator_ = 0.0f; // Tiempo total acumulado poniendo nombre (milisegundos)
|
||||
int step_counter_ = 0; // Cuenta los pasos para los estados en los que camina automáticamente
|
||||
int credits_used_ = 0; // Indica el número de veces que ha continuado
|
||||
int waiting_counter_ = 0; // Contador para el estado de espera
|
||||
@@ -258,41 +307,60 @@ class Player {
|
||||
// --- Métodos internos ---
|
||||
void shiftColliders(); // Actualiza el círculo de colisión a la posición del jugador
|
||||
void shiftSprite(); // Recoloca el sprite
|
||||
void updateInvulnerable(); // Monitoriza el estado de invulnerabilidad
|
||||
void updateContinueCounter(); // Actualiza el contador de continue
|
||||
void updateEnterNameCounter(); // Actualiza el contador de entrar nombre
|
||||
void updateShowingName(); // Actualiza el estado SHOWING_NAME
|
||||
void updateInvulnerable(float deltaTime); // Monitoriza el estado de invulnerabilidad (time-based)
|
||||
void updateContinueCounter(float deltaTime); // Actualiza el contador de continue (time-based)
|
||||
void updateEnterNameCounter(float deltaTime); // Actualiza el contador de entrar nombre (time-based)
|
||||
void updateShowingName(float deltaTime); // Actualiza el estado SHOWING_NAME (time-based)
|
||||
void decNameEntryCounter(); // Decrementa el contador de entrar nombre
|
||||
void updateScoreboard(); // Actualiza el panel del marcador
|
||||
void setScoreboardMode(Scoreboard::Mode mode) const; // Cambia el modo del marcador
|
||||
void playSound(const std::string &name) const; // Hace sonar un sonido
|
||||
[[nodiscard]] auto isRenderable() const -> bool; // Indica si se puede dibujar el objeto
|
||||
void addScoreToScoreBoard() const; // Añade una puntuación a la tabla de records
|
||||
void handleFiringCooldown(); // Gestiona el tiempo de espera después de disparar antes de permitir otro disparo
|
||||
void handleRecoilAndCooling(); // Procesa simultáneamente el retroceso del arma y la transición al estado de enfriamiento si aplica
|
||||
void handleCoolingState(); // Actualiza la lógica interna mientras el sistema está en estado de enfriamiento
|
||||
void transitionToRecoiling(); // Cambia el estado actual al de retroceso después de disparar
|
||||
void transitionToCooling(); // Cambia el estado actual al de enfriamiento (por ejemplo, tras una ráfaga o sobrecalentamiento)
|
||||
void completeCooling(); // Finaliza el proceso de enfriamiento y restablece el estado listo para disparar
|
||||
void handlePlayingMovement(); // Gestiona el movimiento del personaje u objeto durante el estado de juego activo
|
||||
|
||||
// --- Métodos del sistema de disparo de dos líneas ---
|
||||
void updateFireSystem(float deltaTime); // Método principal del nuevo sistema de disparo
|
||||
void updateFunctionalLine(float deltaTime); // Actualiza la línea funcional (CanFire)
|
||||
void updateVisualLine(float deltaTime); // Actualiza la línea visual (Animaciones)
|
||||
void startFiring(int cooldown_frames); // Inicia un nuevo disparo en ambas líneas
|
||||
void updateFiringStateFromVisual(); // Sincroniza firing_state_ con visual_fire_state_
|
||||
void transitionToRecoilingNew(); // Transición AIMING → RECOILING
|
||||
void transitionToThreatPose(); // Transición RECOILING → THREAT_POSE
|
||||
void transitionToNormalNew(); // Transición THREAT_POSE → NORMAL
|
||||
|
||||
// --- Métodos del sistema de disparo obsoleto ---
|
||||
void handleFiringCooldown(); // Gestiona el tiempo de espera después de disparar (frame-based)
|
||||
void handleFiringCooldown(float deltaTime); // Gestiona el tiempo de espera después de disparar (time-based)
|
||||
void handleRecoilAndCooling(); // Procesa retroceso y enfriamiento (frame-based)
|
||||
void handleRecoilAndCooling(float deltaTime); // Procesa retroceso y enfriamiento (time-based)
|
||||
void handleCoolingState(); // Actualiza estado de enfriamiento (frame-based)
|
||||
void handleCoolingState(float deltaTime); // Actualiza estado de enfriamiento (time-based)
|
||||
void transitionToRecoiling(); // Transición a retroceso (sistema obsoleto)
|
||||
void transitionToCooling(); // Transición a enfriamiento (sistema obsoleto)
|
||||
void completeCooling(); // Finaliza enfriamiento (sistema obsoleto)
|
||||
void handlePlayingMovement(); // Gestiona el movimiento del personaje u objeto durante el estado de juego activo (frame-based)
|
||||
void handlePlayingMovement(float deltaTime); // Gestiona el movimiento del personaje u objeto durante el estado de juego activo (time-based)
|
||||
void handleRecoverMovement(); // Comprueba si ha acabado la animación
|
||||
void handleRollingMovement(); // Actualiza la lógica de movimiento de "rodar" (posiblemente tras impacto o acción especial)
|
||||
void handleRollingBoundaryCollision(); // Detecta y maneja colisiones del objeto rodante con los límites de la pantalla
|
||||
void handleRollingGroundCollision(); // Gestiona la interacción del objeto rodante con el suelo (rebotes, frenado, etc.)
|
||||
void handleRollingStop(); // Detiene el movimiento del objeto rodante cuando se cumplen las condiciones necesarias
|
||||
void handleRollingBounce(); // Aplica una lógica de rebote al colisionar con superficies durante el rodamiento
|
||||
void handleTitleAnimation(); // Ejecuta la animación del título en pantalla (ej. entrada, parpadeo o desplazamiento)
|
||||
void handleTitleAnimation(float deltaTime); // Ejecuta la animación del título en pantalla (ej. entrada, parpadeo o desplazamiento)
|
||||
void handleContinueTimeOut(); // Gestiona el tiempo de espera en la pantalla de "Continuar" y decide si pasar a otro estado
|
||||
void handleLeavingScreen(); // Lógica para salir de la pantalla actual (transición visual o cambio de escena)
|
||||
void handleEnteringScreen(); // Lógica para entrar en una nueva pantalla, posiblemente con animación o retraso
|
||||
void handlePlayer1Entering(); // Controla la animación o posición de entrada del Jugador 1 en pantalla
|
||||
void handlePlayer2Entering(); // Controla la animación o posición de entrada del Jugador 2 en pantalla
|
||||
void handleCreditsMovement(); // Movimiento general en la pantalla de créditos (desplazamiento vertical u horizontal)
|
||||
void handleLeavingScreen(float deltaTime); // Lógica para salir de la pantalla actual (transición visual o cambio de escena)
|
||||
void handleEnteringScreen(float deltaTime); // Lógica para entrar en una nueva pantalla, posiblemente con animación o retraso
|
||||
void handlePlayer1Entering(float deltaTime); // Controla la animación o posición de entrada del Jugador 1 en pantalla
|
||||
void handlePlayer2Entering(float deltaTime); // Controla la animación o posición de entrada del Jugador 2 en pantalla
|
||||
void handleCreditsMovement(); // Movimiento general en la pantalla de créditos (frame-based)
|
||||
void handleCreditsMovement(float deltaTime); // Movimiento general en la pantalla de créditos (time-based)
|
||||
void handleCreditsRightMovement(); // Lógica específica para mover los créditos hacia la derecha
|
||||
void handleCreditsLeftMovement(); // Lógica específica para mover los créditos hacia la izquierda
|
||||
void handleWaitingMovement(); // Controla la animación del jugador saludando
|
||||
void handleWaitingMovement(); // Controla la animación del jugador saludando (frame-based)
|
||||
void handleWaitingMovement(float deltaTime); // Controla la animación del jugador saludando (time-based)
|
||||
void updateWalkingStateForCredits(); // Actualiza el estado de caminata de algún personaje u elemento animado en los créditos
|
||||
void setInputBasedOnPlayerId(); // Asocia las entradas de control en función del identificador del jugador (teclas, mando, etc.)
|
||||
void updateStepCounter(); // Incrementa o ajusta el contador de pasos para animaciones o mecánicas relacionadas con movimiento
|
||||
void updateStepCounter(); // Incrementa o ajusta el contador de pasos (frame-based)
|
||||
void updateStepCounter(float deltaTime); // Incrementa o ajusta el contador de pasos (time-based)
|
||||
[[nodiscard]] auto computeAnimation() const -> std::pair<std::string, SDL_FlipMode>; // Calcula la animacion de moverse y disparar del jugador
|
||||
};
|
||||
@@ -2,25 +2,58 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_LogInfo, SDL_LogCategory, SDL_LogError, SDL_SetRenderDrawColor, SDL_EventType, SDL_PollEvent, SDL_RenderFillRect, SDL_RenderRect, SDLK_ESCAPE, SDL_Event
|
||||
|
||||
#include <algorithm> // Para find_if, max, find
|
||||
#include <array> // Para array
|
||||
#include <cstdlib> // Para exit
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <utility> // Para move
|
||||
#include <algorithm> // Para find_if, max, find
|
||||
#include <array> // Para array
|
||||
#include <cstdlib> // Para exit, getenv
|
||||
#include <filesystem> // Para filesystem::remove, filesystem::exists
|
||||
#include <fstream> // Para ofstream
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <utility> // Para move
|
||||
|
||||
#include "asset.h" // Para Asset
|
||||
#include "color.h" // Para Color
|
||||
#ifndef NO_AUDIO
|
||||
#include "external/jail_audio.h" // Para JA_LoadMusic, JA_LoadSound, JA_DeleteMusic, JA_DeleteSound
|
||||
#endif
|
||||
#include "lang.h" // Para getText
|
||||
#include "param.h" // Para Param, param, ParamResource, ParamGame
|
||||
#include "screen.h" // Para Screen
|
||||
#include "text.h" // Para Text
|
||||
#include "lang.h" // Para getText
|
||||
#include "param.h" // Para Param, param, ParamResource, ParamGame
|
||||
#include "resource_helper.h" // Para ResourceHelper
|
||||
#include "screen.h" // Para Screen
|
||||
#include "text.h" // Para Text
|
||||
|
||||
struct JA_Music_t; // lines 11-11
|
||||
struct JA_Sound_t; // lines 12-12
|
||||
|
||||
// Helper para cargar archivos de audio desde pack o filesystem
|
||||
namespace {
|
||||
std::string createTempAudioFile(const std::string &file_path, std::vector<std::string> &temp_files_tracker) {
|
||||
auto resource_data = ResourceHelper::loadFile(file_path);
|
||||
if (!resource_data.empty()) {
|
||||
// Crear archivo temporal
|
||||
std::string temp_dir;
|
||||
#ifdef _WIN32
|
||||
temp_dir = std::getenv("TEMP") ? std::getenv("TEMP") : "C:\\temp";
|
||||
#else
|
||||
temp_dir = "/tmp";
|
||||
#endif
|
||||
std::string temp_path = temp_dir + "/ccae_audio_" + std::to_string(std::hash<std::string>{}(file_path));
|
||||
std::ofstream temp_file(temp_path, std::ios::binary);
|
||||
if (!temp_file) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Cannot create temp file %s", temp_path.c_str());
|
||||
return file_path;
|
||||
}
|
||||
temp_file.write(reinterpret_cast<const char *>(resource_data.data()), resource_data.size());
|
||||
temp_file.close();
|
||||
|
||||
// Agregar a la lista de archivos temporales para limpieza posterior
|
||||
temp_files_tracker.push_back(temp_path);
|
||||
|
||||
return temp_path;
|
||||
}
|
||||
return file_path; // Usar ruta original si no está en pack
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// Declaraciones de funciones que necesitas implementar en otros archivos
|
||||
|
||||
// Singleton
|
||||
@@ -42,7 +75,8 @@ auto Resource::get() -> Resource * { return Resource::instance; }
|
||||
|
||||
// Constructor con modo de carga
|
||||
Resource::Resource(LoadingMode mode)
|
||||
: loading_mode_(mode), loading_text_(nullptr) {
|
||||
: loading_mode_(mode),
|
||||
loading_text_(nullptr) {
|
||||
if (loading_mode_ == LoadingMode::PRELOAD) {
|
||||
loading_text_ = Screen::get()->getText();
|
||||
load();
|
||||
@@ -55,6 +89,7 @@ Resource::Resource(LoadingMode mode)
|
||||
|
||||
// Destructor
|
||||
Resource::~Resource() {
|
||||
cleanupTempAudioFiles();
|
||||
clear();
|
||||
}
|
||||
|
||||
@@ -293,7 +328,8 @@ auto Resource::loadSoundLazy(const std::string &name) -> JA_Sound_t * {
|
||||
auto sound_list = Asset::get()->getListByType(Asset::Type::SOUND);
|
||||
for (const auto &file : sound_list) {
|
||||
if (getFileName(file) == name) {
|
||||
return JA_LoadSound(file.c_str());
|
||||
std::string audio_path = createTempAudioFile(file, Resource::get()->temp_audio_files_);
|
||||
return JA_LoadSound(audio_path.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -306,7 +342,8 @@ auto Resource::loadMusicLazy(const std::string &name) -> JA_Music_t * {
|
||||
auto music_list = Asset::get()->getListByType(Asset::Type::MUSIC);
|
||||
for (const auto &file : music_list) {
|
||||
if (getFileName(file) == name) {
|
||||
return JA_LoadMusic(file.c_str());
|
||||
std::string audio_path = createTempAudioFile(file, Resource::get()->temp_audio_files_);
|
||||
return JA_LoadMusic(audio_path.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -448,7 +485,8 @@ void Resource::loadSounds() {
|
||||
auto name = getFileName(l);
|
||||
updateLoadingProgress(name);
|
||||
#ifndef NO_AUDIO
|
||||
sounds_.emplace_back(name, JA_LoadSound(l.c_str()));
|
||||
std::string audio_path = createTempAudioFile(l, temp_audio_files_);
|
||||
sounds_.emplace_back(name, JA_LoadSound(audio_path.c_str()));
|
||||
#else
|
||||
sounds_.emplace_back(name, nullptr);
|
||||
#endif
|
||||
@@ -466,7 +504,8 @@ void Resource::loadMusics() {
|
||||
auto name = getFileName(l);
|
||||
updateLoadingProgress(name);
|
||||
#ifndef NO_AUDIO
|
||||
musics_.emplace_back(name, JA_LoadMusic(l.c_str()));
|
||||
std::string audio_path = createTempAudioFile(l, temp_audio_files_);
|
||||
musics_.emplace_back(name, JA_LoadMusic(audio_path.c_str()));
|
||||
#else
|
||||
musics_.emplace_back(name, nullptr);
|
||||
#endif
|
||||
@@ -567,7 +606,7 @@ void Resource::createPlayerTextures() {
|
||||
texture->setPaletteColor(0, 19, param.player.default_shirt[player_idx].light.TO_UINT32());
|
||||
texture->setPaletteColor(0, 56, param.player.outline_color[player_idx].TO_UINT32());
|
||||
} else {
|
||||
// Crear textura nueva desde archivo
|
||||
// Crear textura nueva desde archivo usando ResourceHelper
|
||||
texture = std::make_shared<Texture>(Screen::get()->getRenderer(), texture_file_path);
|
||||
|
||||
// Añadir todas las paletas
|
||||
@@ -611,7 +650,8 @@ void Resource::createTextTextures() {
|
||||
std::string text;
|
||||
|
||||
NameAndText(std::string name_init, std::string text_init)
|
||||
: name(std::move(name_init)), text(std::move(text_init)) {}
|
||||
: name(std::move(name_init)),
|
||||
text(std::move(text_init)) {}
|
||||
};
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> CREATING TEXTURES");
|
||||
@@ -623,7 +663,8 @@ void Resource::createTextTextures() {
|
||||
{"game_text_5000_points", "5.000"},
|
||||
{"game_text_powerup", Lang::getText("[GAME_TEXT] 4")},
|
||||
{"game_text_one_hit", Lang::getText("[GAME_TEXT] 5")},
|
||||
{"game_text_stop", Lang::getText("[GAME_TEXT] 6")}};
|
||||
{"game_text_stop", Lang::getText("[GAME_TEXT] 6")},
|
||||
{"game_text_1000000_points", Lang::getText("[GAME_TEXT] 8")}};
|
||||
|
||||
auto text1 = getText("04b_25_enhanced");
|
||||
for (const auto &s : strings1) {
|
||||
@@ -631,27 +672,18 @@ void Resource::createTextTextures() {
|
||||
printWithDots("Texture : ", s.name, "[ DONE ]");
|
||||
}
|
||||
|
||||
// Texturas de tamaño normal
|
||||
std::vector<NameAndText> strings2 = {
|
||||
{"game_text_1000000_points", Lang::getText("[GAME_TEXT] 8")}};
|
||||
|
||||
auto text2 = getText("04b_25");
|
||||
for (const auto &s : strings2) {
|
||||
textures_.emplace_back(s.name, text2->writeDXToTexture(Text::STROKE, s.text, -2, Colors::NO_COLOR_MOD, 1, param.game.item_text_outline_color));
|
||||
printWithDots("Texture : ", s.name, "[ DONE ]");
|
||||
}
|
||||
|
||||
// Texturas de tamaño doble
|
||||
std::vector<NameAndText> strings3 = {
|
||||
std::vector<NameAndText> strings2 = {
|
||||
{"game_text_100000_points", "100.000"},
|
||||
{"game_text_get_ready", Lang::getText("[GAME_TEXT] 7")},
|
||||
{"game_text_last_stage", Lang::getText("[GAME_TEXT] 3")},
|
||||
{"game_text_congratulations", Lang::getText("[GAME_TEXT] 1")},
|
||||
{"game_text_new_record", Lang::getText("[GAME_TEXT] NEW_RECORD")},
|
||||
{"game_text_game_over", "Game Over"}};
|
||||
|
||||
auto text3 = getText("04b_25_2x");
|
||||
for (const auto &s : strings3) {
|
||||
textures_.emplace_back(s.name, text3->writeToTexture(s.text, 1, -4));
|
||||
auto text2 = getText("04b_25_2x_enhanced");
|
||||
for (const auto &s : strings2) {
|
||||
textures_.emplace_back(s.name, text2->writeDXToTexture(Text::STROKE, s.text, -4, Colors::NO_COLOR_MOD, 1, param.game.item_text_outline_color));
|
||||
printWithDots("Texture : ", s.name, "[ DONE ]");
|
||||
}
|
||||
}
|
||||
@@ -665,7 +697,10 @@ void Resource::createText() {
|
||||
std::string white_texture_file; // Textura blanca opcional
|
||||
|
||||
ResourceInfo(std::string k, std::string t_file, std::string txt_file, std::string w_file = "")
|
||||
: key(std::move(k)), texture_file(std::move(t_file)), text_file(std::move(txt_file)), white_texture_file(std::move(w_file)) {}
|
||||
: key(std::move(k)),
|
||||
texture_file(std::move(t_file)),
|
||||
text_file(std::move(txt_file)),
|
||||
white_texture_file(std::move(w_file)) {}
|
||||
};
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "\n>> CREATING TEXT OBJECTS");
|
||||
@@ -675,6 +710,7 @@ void Resource::createText() {
|
||||
{"04b_25_enhanced", "04b_25.png", "04b_25.txt", "04b_25_white.png"}, // Nueva fuente con textura blanca
|
||||
{"04b_25_white", "04b_25_white.png", "04b_25.txt"},
|
||||
{"04b_25_2x", "04b_25_2x.png", "04b_25_2x.txt"},
|
||||
{"04b_25_2x_enhanced", "04b_25_2x.png", "04b_25_2x.txt", "04b_25_2x_white.png"}, // Nueva fuente con textura blanca
|
||||
{"04b_25_metal", "04b_25_metal.png", "04b_25.txt"},
|
||||
{"04b_25_grey", "04b_25_grey.png", "04b_25.txt"},
|
||||
{"04b_25_flat", "04b_25_flat.png", "04b_25.txt"},
|
||||
@@ -833,3 +869,18 @@ void Resource::updateLoadingProgress(std::string name) {
|
||||
void Resource::updateProgressBar() {
|
||||
loading_full_rect_.w = loading_wired_rect_.w * loading_count_.getPercentage();
|
||||
}
|
||||
|
||||
// Limpia archivos temporales de audio
|
||||
void Resource::cleanupTempAudioFiles() {
|
||||
for (const auto &temp_path : temp_audio_files_) {
|
||||
try {
|
||||
if (std::filesystem::exists(temp_path)) {
|
||||
std::filesystem::remove(temp_path);
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Removed temp audio file: %s", temp_path.c_str());
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to remove temp audio file %s: %s", temp_path.c_str(), e.what());
|
||||
}
|
||||
}
|
||||
temp_audio_files_.clear();
|
||||
}
|
||||
|
||||