Compare commits
149 Commits
2025-08-17
...
opengl
| Author | SHA1 | Date | |
|---|---|---|---|
| ff7aef827c | |||
| 6ff7ccf69a | |||
| e347e04d33 | |||
| 7946ea54a6 | |||
| 79033346c0 | |||
| 62b73d6f41 | |||
| 218ddabb5e | |||
| 427f40632a | |||
| a29b4d4379 | |||
| d851cdd2fe | |||
| 3354d00814 | |||
| 7bd7ba84e0 | |||
| 6ad34eaf57 | |||
| b4f2251508 | |||
| 473a52f986 | |||
| bcdd48d622 | |||
| 6985569573 | |||
| 5db43e674d | |||
| 34baa3c97d | |||
| bddb790fe2 | |||
| 6fae12ba02 | |||
| 4e083a8cdb | |||
| cbe4315701 | |||
| 49d561b583 | |||
| 6e56a6fd79 | |||
| 267d9647e0 | |||
| 13b3702d00 | |||
| 4500845dcd | |||
| a4abc02f88 | |||
| a0fb6934b0 | |||
| 19645445b2 | |||
| efe8628a3c | |||
| c98cb0d29f | |||
| c16fc1bae5 | |||
| fa0af1179a | |||
| d1e4a5eb07 | |||
| e18d1b186a | |||
| d056a5e336 | |||
| b9e26aa755 | |||
| b2afef2226 | |||
| c400aa96c0 | |||
| 8818954dcd | |||
| b92e5df98b | |||
| 83871273ec | |||
| 0459b39366 | |||
| 5bb0ff19bc | |||
| a867b3cf4d | |||
| 8a6ce8e66d | |||
| a40f04a739 | |||
| 0c670fd344 | |||
| 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
|
||||
|
||||
4
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
.vscode
|
||||
.claude
|
||||
build/
|
||||
data/config/config.txt
|
||||
*.DS_Store
|
||||
@@ -16,4 +17,5 @@ coffee_crisis*
|
||||
debug.txt
|
||||
cppcheck-result*
|
||||
desktop.ini
|
||||
ccae_release/
|
||||
ccae_release/
|
||||
resources.pack
|
||||
@@ -14,6 +14,22 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
cmake_policy(SET CMP0072 NEW)
|
||||
set(OpenGL_GL_PREFERENCE GLVND)
|
||||
|
||||
# --- GENERACIÓN DE VERSIÓN AUTOMÁTICA ---
|
||||
find_package(Git QUIET)
|
||||
if(GIT_FOUND)
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} rev-parse --short=7 HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
else()
|
||||
set(GIT_HASH "unknown")
|
||||
endif()
|
||||
|
||||
# Configurar archivo de versión
|
||||
configure_file(${CMAKE_SOURCE_DIR}/source/version.h.in ${CMAKE_BINARY_DIR}/version.h @ONLY)
|
||||
|
||||
# --- 1. LISTA EXPLÍCITA DE FUENTES ---
|
||||
set(APP_SOURCES
|
||||
@@ -28,6 +44,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
|
||||
@@ -45,6 +64,7 @@ set(APP_SOURCES
|
||||
source/balloon_manager.cpp
|
||||
source/balloon.cpp
|
||||
source/bullet.cpp
|
||||
source/bullet_manager.cpp
|
||||
source/enter_name.cpp
|
||||
source/explosions.cpp
|
||||
source/game_logo.cpp
|
||||
@@ -76,6 +96,7 @@ set(APP_SOURCES
|
||||
|
||||
# --- Otros ---
|
||||
source/color.cpp
|
||||
source/demo.cpp
|
||||
source/define_buttons.cpp
|
||||
source/difficulty.cpp
|
||||
source/input_types.cpp
|
||||
@@ -89,28 +110,29 @@ set(APP_SOURCES
|
||||
|
||||
# Fuentes de librerías de terceros
|
||||
set(EXTERNAL_SOURCES
|
||||
source/external/jail_shader.cpp
|
||||
source/external/jail_audio.cpp
|
||||
source/external/json.hpp
|
||||
source/external/gif.cpp
|
||||
source/external/gif.cpp
|
||||
)
|
||||
|
||||
# Añadir jail_audio.cpp solo si el audio está habilitado
|
||||
if(NOT DISABLE_AUDIO)
|
||||
list(APPEND EXTERNAL_SOURCES source/external/jail_audio.cpp)
|
||||
endif()
|
||||
|
||||
# Fuentes del sistema de renderizado
|
||||
set(RENDERING_SOURCES
|
||||
source/rendering/opengl/opengl_shader.cpp
|
||||
)
|
||||
|
||||
# Configuración de SDL3
|
||||
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3)
|
||||
message(STATUS "SDL3 encontrado: ${SDL3_INCLUDE_DIRS}")
|
||||
|
||||
# --- 2. AÑADIR EJECUTABLE ---
|
||||
add_executable(${PROJECT_NAME} ${APP_SOURCES} ${EXTERNAL_SOURCES})
|
||||
add_executable(${PROJECT_NAME} ${APP_SOURCES} ${EXTERNAL_SOURCES} ${RENDERING_SOURCES})
|
||||
|
||||
# --- 3. DIRECTORIOS DE INCLUSIÓN ---
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
"${CMAKE_SOURCE_DIR}/source"
|
||||
"${CMAKE_SOURCE_DIR}/source/external"
|
||||
"${CMAKE_SOURCE_DIR}/source/external"
|
||||
"${CMAKE_SOURCE_DIR}/source/rendering"
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
)
|
||||
|
||||
# Enlazar la librería SDL3
|
||||
@@ -125,16 +147,9 @@ target_compile_options(${PROJECT_NAME} PRIVATE $<$<CONFIG:RELEASE>:-Os -ffunctio
|
||||
# Definir _DEBUG en modo Debug
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<CONFIG:DEBUG>:_DEBUG>)
|
||||
|
||||
# Opción para habilitar/deshabilitar audio
|
||||
option(DISABLE_AUDIO "Disable audio system" OFF)
|
||||
# Descomentar la siguiente línea para activar el modo grabación de demos
|
||||
# target_compile_definitions(${PROJECT_NAME} PRIVATE RECORDING)
|
||||
|
||||
# Definir NO_AUDIO si la opción está activada
|
||||
if(DISABLE_AUDIO)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE NO_AUDIO)
|
||||
message(STATUS "Audio deshabilitado - NO_AUDIO definido")
|
||||
else()
|
||||
message(STATUS "Audio habilitado")
|
||||
endif()
|
||||
|
||||
# Configuración específica para cada plataforma
|
||||
if(WIN32)
|
||||
|
||||
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.
|
||||
66
Makefile
@@ -3,6 +3,7 @@ DIR_ROOT := $(dir $(abspath $(MAKEFILE_LIST)))
|
||||
DIR_SOURCES := $(addsuffix /, $(DIR_ROOT)source)
|
||||
DIR_BIN := $(addsuffix /, $(DIR_ROOT))
|
||||
DIR_BUILD := $(addsuffix /, $(DIR_ROOT)build)
|
||||
DIR_TOOLS := $(addsuffix /, $(DIR_ROOT)tools)
|
||||
|
||||
# Variables
|
||||
TARGET_NAME := coffee_crisis_arcade_edition
|
||||
@@ -12,6 +13,17 @@ RELEASE_FOLDER := ccae_release
|
||||
RELEASE_FILE := $(RELEASE_FOLDER)/$(TARGET_NAME)
|
||||
RESOURCE_FILE := release/coffee.res
|
||||
|
||||
# Variables para herramienta de empaquetado
|
||||
ifeq ($(OS),Windows_NT)
|
||||
PACK_TOOL := $(DIR_TOOLS)pack_resources.exe
|
||||
PACK_CXX := $(CXX)
|
||||
else
|
||||
PACK_TOOL := $(DIR_TOOLS)pack_resources
|
||||
PACK_CXX := $(CXX)
|
||||
endif
|
||||
PACK_SOURCES := $(DIR_TOOLS)pack_resources.cpp $(DIR_SOURCES)resource_pack.cpp
|
||||
PACK_INCLUDES := -I$(DIR_ROOT)
|
||||
|
||||
# Versión automática basada en la fecha actual (específica por SO)
|
||||
ifeq ($(OS),Windows_NT)
|
||||
VERSION := $(shell powershell -Command "Get-Date -Format 'yyyy-MM-dd'")
|
||||
@@ -71,6 +83,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 +119,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
|
||||
@@ -132,6 +147,19 @@ else
|
||||
endif
|
||||
endif
|
||||
|
||||
# Reglas para herramienta de empaquetado y resources.pack
|
||||
$(PACK_TOOL): $(PACK_SOURCES)
|
||||
@echo "Compilando herramienta de empaquetado..."
|
||||
$(PACK_CXX) -std=c++17 -Wall -Os $(PACK_INCLUDES) $(PACK_SOURCES) -o $(PACK_TOOL)
|
||||
@echo "✓ Herramienta de empaquetado lista: $(PACK_TOOL)"
|
||||
|
||||
pack_tool: $(PACK_TOOL)
|
||||
|
||||
resources.pack: $(PACK_TOOL)
|
||||
@echo "Generando resources.pack desde directorio data/..."
|
||||
$(PACK_TOOL) data resources.pack
|
||||
@echo "✓ resources.pack generado exitosamente"
|
||||
|
||||
# Reglas para compilación
|
||||
windows:
|
||||
@echo off
|
||||
@@ -150,7 +178,7 @@ windows_debug:
|
||||
@echo Compilando version debug para Windows: "$(APP_NAME)_debug.exe"
|
||||
$(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(WIN_TARGET_FILE)_debug.exe"
|
||||
|
||||
windows_release:
|
||||
windows_release: resources.pack
|
||||
@echo off
|
||||
@echo Creando release para Windows - Version: $(VERSION)
|
||||
|
||||
@@ -158,8 +186,9 @@ windows_release:
|
||||
powershell if (Test-Path "$(RELEASE_FOLDER)") {Remove-Item "$(RELEASE_FOLDER)" -Recurse -Force}
|
||||
powershell if (-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)"
|
||||
@@ -187,7 +216,7 @@ macos_debug:
|
||||
@echo "Compilando version debug para macOS: $(TARGET_NAME)_debug"
|
||||
$(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
|
||||
|
||||
macos_release:
|
||||
macos_release: resources.pack
|
||||
@echo "Creando release para macOS - Version: $(VERSION)"
|
||||
# Elimina datos de compilaciones anteriores
|
||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||
@@ -203,7 +232,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"
|
||||
@@ -253,7 +283,7 @@ linux_debug:
|
||||
@echo "Compilando version debug para Linux: $(TARGET_NAME)_debug"
|
||||
$(CXX) $(APP_SOURCES) $(INCLUDES) -DDEBUG -DVERBOSE $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
|
||||
|
||||
linux_release:
|
||||
linux_release: resources.pack
|
||||
@echo "Creando release para Linux - Version: $(VERSION)"
|
||||
# Elimina carpetas previas
|
||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||
@@ -262,7 +292,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)"
|
||||
|
||||
@@ -278,7 +309,7 @@ linux_release:
|
||||
# Elimina la carpeta temporal
|
||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||
|
||||
linux_release_desktop:
|
||||
linux_release_desktop: resources.pack
|
||||
@echo "Creando release con integracion desktop para Linux - Version: $(VERSION)"
|
||||
# Elimina carpetas previas
|
||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||
@@ -291,7 +322,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)/"
|
||||
|
||||
@@ -382,7 +414,7 @@ raspi_debug:
|
||||
@echo "Compilando version debug para Raspberry Pi: $(TARGET_NAME)_debug"
|
||||
$(CXX) $(APP_SOURCES) $(INCLUDES) -DVERBOSE -DDEBUG $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
|
||||
|
||||
raspi_release:
|
||||
raspi_release: resources.pack
|
||||
@echo "Creando release para Raspberry Pi - Version: $(VERSION)"
|
||||
# Elimina carpetas previas
|
||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||
@@ -391,7 +423,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)"
|
||||
|
||||
@@ -407,7 +440,7 @@ raspi_release:
|
||||
# Elimina la carpeta temporal
|
||||
$(RMDIR) "$(RELEASE_FOLDER)"
|
||||
|
||||
anbernic:
|
||||
anbernic: resources.pack
|
||||
@echo "Compilando para Anbernic: $(TARGET_NAME)"
|
||||
# Elimina carpetas previas
|
||||
$(RMDIR) "$(RELEASE_FOLDER)"_anbernic
|
||||
@@ -416,7 +449,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)
|
||||
@@ -448,7 +482,9 @@ help:
|
||||
@echo " raspi_release - Crear release completo para Raspberry Pi"
|
||||
@echo " anbernic - Compilar para Anbernic"
|
||||
@echo " no_audio - Compilar sin sistema de audio"
|
||||
@echo " pack_tool - Compilar herramienta de empaquetado"
|
||||
@echo " resources.pack - Generar pack de recursos desde data/"
|
||||
@echo " show_version - Mostrar version actual ($(VERSION))"
|
||||
@echo " help - Mostrar esta ayuda"
|
||||
|
||||
.PHONY: windows windows_rec windows_debug windows_release macos macos_debug macos_release linux linux_debug linux_release linux_release_desktop raspi raspi_debug raspi_release anbernic no_audio show_version help
|
||||
.PHONY: windows windows_rec windows_debug windows_release macos macos_debug macos_release linux linux_debug linux_release linux_release_desktop raspi raspi_debug raspi_release anbernic no_audio show_version help pack_tool
|
||||
61
TODO.md
Normal file
@@ -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"
|
||||
@@ -4,22 +4,26 @@
|
||||
# Variables: ${PREFIX}, ${SYSTEM_FOLDER}
|
||||
|
||||
# Archivos de configuración del sistema (absolutos y opcionales)
|
||||
DATA|${SYSTEM_FOLDER}/config.txt|optional,absolute
|
||||
DATA|${SYSTEM_FOLDER}/config_v2.txt|optional,absolute
|
||||
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
|
||||
DEMODATA|${PREFIX}/data/demo/demo3.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
|
||||
@@ -34,7 +38,8 @@ SOUND|${PREFIX}/data/sound/balloon_pop0.wav
|
||||
SOUND|${PREFIX}/data/sound/balloon_pop1.wav
|
||||
SOUND|${PREFIX}/data/sound/balloon_pop2.wav
|
||||
SOUND|${PREFIX}/data/sound/balloon_pop3.wav
|
||||
SOUND|${PREFIX}/data/sound/bullet.wav
|
||||
SOUND|${PREFIX}/data/sound/bullet1p.wav
|
||||
SOUND|${PREFIX}/data/sound/bullet2p.wav
|
||||
SOUND|${PREFIX}/data/sound/clock.wav
|
||||
SOUND|${PREFIX}/data/sound/coffee_out.wav
|
||||
SOUND|${PREFIX}/data/sound/continue_clock.wav
|
||||
@@ -46,10 +51,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
|
||||
@@ -59,6 +66,7 @@ SOUND|${PREFIX}/data/sound/title.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_aw_aw_aw.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_coffee.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_credit_thankyou.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_game_over.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_get_ready.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_no.wav
|
||||
SOUND|${PREFIX}/data/sound/voice_power_up.wav
|
||||
@@ -67,8 +75,8 @@ SOUND|${PREFIX}/data/sound/voice_thankyou.wav
|
||||
SOUND|${PREFIX}/data/sound/walk.wav
|
||||
|
||||
# Shaders
|
||||
DATA|${PREFIX}/data/shaders/crtpi_240.glsl
|
||||
DATA|${PREFIX}/data/shaders/crtpi_256.glsl
|
||||
DATA|${PREFIX}/data/shaders/crtpi_vertex.glsl
|
||||
DATA|${PREFIX}/data/shaders/crtpi_fragment.glsl
|
||||
|
||||
# Texturas - Balloons
|
||||
ANIMATION|${PREFIX}/data/gfx/balloon/balloon0.ani
|
||||
@@ -172,6 +180,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
|
||||
@@ -2,7 +2,6 @@
|
||||
# Formato: PARAMETRO VALOR
|
||||
|
||||
# --- GAME ---
|
||||
game.item_size 20 # Tamaño de los items del juego (en píxeles)
|
||||
game.item_text_outline_color E0E0E0F0 # Color del outline del texto de los items (RGBA hex)
|
||||
game.width 320 # Ancho de la resolución nativa del juego (en píxeles)
|
||||
game.height 240 # Alto de la resolución nativa del juego (en píxeles)
|
||||
@@ -39,24 +38,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
|
||||
@@ -4,31 +4,31 @@
|
||||
# Los pools no necesitan estar ordenados ni ser consecutivos
|
||||
|
||||
# Pool para la fase 1
|
||||
POOL: 0 FORMATIONS: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||
POOL: 0 FORMATIONS: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
|
||||
|
||||
# Pool para la fase 2
|
||||
POOL: 1 FORMATIONS: 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
|
||||
POOL: 1 FORMATIONS: 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
|
||||
|
||||
# Pool para la fase 3
|
||||
POOL: 2 FORMATIONS: 0, 1, 2, 3, 4, 55, 56, 57, 58, 59
|
||||
POOL: 2 FORMATIONS: 0, 1, 2, 3, 4, 55, 56, 57, 58, 59
|
||||
|
||||
# Pool para la fase 4
|
||||
POOL: 3 FORMATIONS: 50, 51, 52, 53, 54, 5, 6, 7, 8, 9
|
||||
POOL: 3 FORMATIONS: 50, 51, 52, 53, 54, 5, 6, 7, 8, 9
|
||||
|
||||
# Pool para la fase 5
|
||||
POOL: 4 FORMATIONS: 60, 61, 62, 63, 64, 65, 66, 67, 68, 69
|
||||
POOL: 4 FORMATIONS: 60, 61, 62, 63, 64, 65, 66, 67, 68, 69
|
||||
|
||||
# Pool para la fase 6
|
||||
POOL: 5 FORMATIONS: 10, 61, 12, 63, 14, 65, 16, 67, 18, 69
|
||||
POOL: 5 FORMATIONS: 10, 61, 12, 63, 14, 65, 16, 67, 18, 69
|
||||
|
||||
# Pool para la fase 7
|
||||
POOL: 6 FORMATIONS: 60, 11, 62, 13, 64, 15, 66, 17, 68, 19
|
||||
POOL: 6 FORMATIONS: 60, 11, 62, 13, 64, 15, 66, 17, 68, 19
|
||||
|
||||
# Pool para la fase 8
|
||||
POOL: 7 FORMATIONS: 20, 21, 22, 23, 24, 65, 66, 67, 68, 69
|
||||
POOL: 7 FORMATIONS: 20, 21, 22, 23, 24, 65, 66, 67, 68, 69
|
||||
|
||||
# Pool para la fase 9
|
||||
POOL: 8 FORMATIONS: 70, 71, 72, 73, 74, 15, 16, 17, 18, 19
|
||||
POOL: 8 FORMATIONS: 70, 71, 72, 73, 74, 15, 16, 17, 18, 19
|
||||
|
||||
# Pool para la fase 10
|
||||
POOL: 9 FORMATIONS: 20, 21, 22, 23, 24, 70, 71, 72, 73, 74
|
||||
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB |
@@ -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
|
||||
BIN
data/demo/demo1.bin
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
data/demo/demo2.bin
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
data/demo/demo3.bin
Normal file
|
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]
|
||||
@@ -2,43 +2,85 @@ frame_width=12
|
||||
frame_height=12
|
||||
|
||||
[animation]
|
||||
name=normal_up
|
||||
speed=5
|
||||
loop=0
|
||||
frames=0,1,2
|
||||
name=yellow_up
|
||||
speed=20
|
||||
loop=-1
|
||||
frames=0
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=normal_left
|
||||
speed=5
|
||||
loop=0
|
||||
frames=3,4,5,5,4,3
|
||||
name=yellow_left
|
||||
speed=20
|
||||
loop=-1
|
||||
frames=1
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=normal_right
|
||||
speed=5
|
||||
loop=0
|
||||
frames=6,7,8,8,7,6
|
||||
name=yellow_right
|
||||
speed=20
|
||||
loop=-1
|
||||
frames=2
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=powered_up
|
||||
speed=5
|
||||
loop=0
|
||||
frames=9,10,11,11,10,9
|
||||
name=green_up
|
||||
speed=20
|
||||
loop=-1
|
||||
frames=3
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=powered_left
|
||||
speed=5
|
||||
loop=0
|
||||
frames=12,13,14,14,13,12
|
||||
name=green_left
|
||||
speed=20
|
||||
loop=-1
|
||||
frames=4
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=powered_right
|
||||
speed=5
|
||||
loop=0
|
||||
frames=15,16,17,17,26,15
|
||||
name=green_right
|
||||
speed=20
|
||||
loop=-1
|
||||
frames=5
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=red_up
|
||||
speed=20
|
||||
loop=-1
|
||||
frames=6
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=red_left
|
||||
speed=20
|
||||
loop=-1
|
||||
frames=7
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=red_right
|
||||
speed=20
|
||||
loop=-1
|
||||
frames=8
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=purple_up
|
||||
speed=20
|
||||
loop=-1
|
||||
frames=9
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=purple_left
|
||||
speed=20
|
||||
loop=-1
|
||||
frames=10
|
||||
[/animation]
|
||||
|
||||
[animation]
|
||||
name=purple_right
|
||||
speed=20
|
||||
loop=-1
|
||||
frames=11
|
||||
[/animation]
|
||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -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
@@ -1,234 +0,0 @@
|
||||
/*
|
||||
crt-pi - A Raspberry Pi friendly CRT shader.
|
||||
|
||||
Copyright (C) 2015-2016 davej
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
|
||||
Notes:
|
||||
|
||||
This shader is designed to work well on Raspberry Pi GPUs (i.e. 1080P @ 60Hz on a game with a 4:3 aspect ratio). It pushes the Pi's GPU hard and enabling some features will slow it down so that it is no longer able to match 1080P @ 60Hz. You will need to overclock your Pi to the fastest setting in raspi-config to get the best results from this shader: 'Pi2' for Pi2 and 'Turbo' for original Pi and Pi Zero. Note: Pi2s are slower at running the shader than other Pis, this seems to be down to Pi2s lower maximum memory speed. Pi2s don't quite manage 1080P @ 60Hz - they drop about 1 in 1000 frames. You probably won't notice this, but if you do, try enabling FAKE_GAMMA.
|
||||
|
||||
SCANLINES enables scanlines. You'll almost certainly want to use it with MULTISAMPLE to reduce moire effects. SCANLINE_WEIGHT defines how wide scanlines are (it is an inverse value so a higher number = thinner lines). SCANLINE_GAP_BRIGHTNESS defines how dark the gaps between the scan lines are. Darker gaps between scan lines make moire effects more likely.
|
||||
|
||||
GAMMA enables gamma correction using the values in INPUT_GAMMA and OUTPUT_GAMMA. FAKE_GAMMA causes it to ignore the values in INPUT_GAMMA and OUTPUT_GAMMA and approximate gamma correction in a way which is faster than true gamma whilst still looking better than having none. You must have GAMMA defined to enable FAKE_GAMMA.
|
||||
|
||||
CURVATURE distorts the screen by CURVATURE_X and CURVATURE_Y. Curvature slows things down a lot.
|
||||
|
||||
By default the shader uses linear blending horizontally. If you find this too blury, enable SHARPER.
|
||||
|
||||
BLOOM_FACTOR controls the increase in width for bright scanlines.
|
||||
|
||||
MASK_TYPE defines what, if any, shadow mask to use. MASK_BRIGHTNESS defines how much the mask type darkens the screen.
|
||||
|
||||
*/
|
||||
|
||||
#pragma parameter CURVATURE_X "Screen curvature - horizontal" 0.10 0.0 1.0 0.01
|
||||
#pragma parameter CURVATURE_Y "Screen curvature - vertical" 0.15 0.0 1.0 0.01
|
||||
#pragma parameter MASK_BRIGHTNESS "Mask brightness" 0.70 0.0 1.0 0.01
|
||||
#pragma parameter SCANLINE_WEIGHT "Scanline weight" 6.0 0.0 15.0 0.1
|
||||
#pragma parameter SCANLINE_GAP_BRIGHTNESS "Scanline gap brightness" 0.12 0.0 1.0 0.01
|
||||
#pragma parameter BLOOM_FACTOR "Bloom factor" 1.5 0.0 5.0 0.01
|
||||
#pragma parameter INPUT_GAMMA "Input gamma" 2.4 0.0 5.0 0.01
|
||||
#pragma parameter OUTPUT_GAMMA "Output gamma" 2.2 0.0 5.0 0.01
|
||||
|
||||
// Haven't put these as parameters as it would slow the code down.
|
||||
#define SCANLINES
|
||||
#define MULTISAMPLE
|
||||
#define GAMMA
|
||||
//#define FAKE_GAMMA
|
||||
//#define CURVATURE
|
||||
//#define SHARPER
|
||||
// MASK_TYPE: 0 = none, 1 = green/magenta, 2 = trinitron(ish)
|
||||
#define MASK_TYPE 2
|
||||
|
||||
|
||||
#ifdef GL_ES
|
||||
#define COMPAT_PRECISION mediump
|
||||
precision mediump float;
|
||||
#else
|
||||
#define COMPAT_PRECISION
|
||||
#endif
|
||||
|
||||
#ifdef PARAMETER_UNIFORM
|
||||
uniform COMPAT_PRECISION float CURVATURE_X;
|
||||
uniform COMPAT_PRECISION float CURVATURE_Y;
|
||||
uniform COMPAT_PRECISION float MASK_BRIGHTNESS;
|
||||
uniform COMPAT_PRECISION float SCANLINE_WEIGHT;
|
||||
uniform COMPAT_PRECISION float SCANLINE_GAP_BRIGHTNESS;
|
||||
uniform COMPAT_PRECISION float BLOOM_FACTOR;
|
||||
uniform COMPAT_PRECISION float INPUT_GAMMA;
|
||||
uniform COMPAT_PRECISION float OUTPUT_GAMMA;
|
||||
#else
|
||||
#define CURVATURE_X 0.05
|
||||
#define CURVATURE_Y 0.1
|
||||
#define MASK_BRIGHTNESS 0.80
|
||||
#define SCANLINE_WEIGHT 6.0
|
||||
#define SCANLINE_GAP_BRIGHTNESS 0.12
|
||||
#define BLOOM_FACTOR 3.5
|
||||
#define INPUT_GAMMA 2.4
|
||||
#define OUTPUT_GAMMA 2.2
|
||||
#endif
|
||||
|
||||
/* COMPATIBILITY
|
||||
- GLSL compilers
|
||||
*/
|
||||
|
||||
//uniform vec2 TextureSize;
|
||||
#if defined(CURVATURE)
|
||||
varying vec2 screenScale;
|
||||
#endif
|
||||
varying vec2 TEX0;
|
||||
varying float filterWidth;
|
||||
|
||||
#if defined(VERTEX)
|
||||
//uniform mat4 MVPMatrix;
|
||||
//attribute vec4 VertexCoord;
|
||||
//attribute vec2 TexCoord;
|
||||
//uniform vec2 InputSize;
|
||||
//uniform vec2 OutputSize;
|
||||
|
||||
void main()
|
||||
{
|
||||
#if defined(CURVATURE)
|
||||
screenScale = vec2(1.0, 1.0); //TextureSize / InputSize;
|
||||
#endif
|
||||
filterWidth = (768.0 / 240.0) / 3.0;
|
||||
TEX0 = vec2(gl_MultiTexCoord0.x, 1.0-gl_MultiTexCoord0.y)*1.0001;
|
||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
}
|
||||
#elif defined(FRAGMENT)
|
||||
|
||||
uniform sampler2D Texture;
|
||||
|
||||
#if defined(CURVATURE)
|
||||
vec2 Distort(vec2 coord)
|
||||
{
|
||||
vec2 CURVATURE_DISTORTION = vec2(CURVATURE_X, CURVATURE_Y);
|
||||
// Barrel distortion shrinks the display area a bit, this will allow us to counteract that.
|
||||
vec2 barrelScale = 1.0 - (0.23 * CURVATURE_DISTORTION);
|
||||
coord *= screenScale;
|
||||
coord -= vec2(0.5);
|
||||
float rsq = coord.x * coord.x + coord.y * coord.y;
|
||||
coord += coord * (CURVATURE_DISTORTION * rsq);
|
||||
coord *= barrelScale;
|
||||
if (abs(coord.x) >= 0.5 || abs(coord.y) >= 0.5)
|
||||
coord = vec2(-1.0); // If out of bounds, return an invalid value.
|
||||
else
|
||||
{
|
||||
coord += vec2(0.5);
|
||||
coord /= screenScale;
|
||||
}
|
||||
|
||||
return coord;
|
||||
}
|
||||
#endif
|
||||
|
||||
float CalcScanLineWeight(float dist)
|
||||
{
|
||||
return max(1.0-dist*dist*SCANLINE_WEIGHT, SCANLINE_GAP_BRIGHTNESS);
|
||||
}
|
||||
|
||||
float CalcScanLine(float dy)
|
||||
{
|
||||
float scanLineWeight = CalcScanLineWeight(dy);
|
||||
#if defined(MULTISAMPLE)
|
||||
scanLineWeight += CalcScanLineWeight(dy-filterWidth);
|
||||
scanLineWeight += CalcScanLineWeight(dy+filterWidth);
|
||||
scanLineWeight *= 0.3333333;
|
||||
#endif
|
||||
return scanLineWeight;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 TextureSize = vec2(320.0, 240.0);
|
||||
#if defined(CURVATURE)
|
||||
vec2 texcoord = Distort(TEX0);
|
||||
if (texcoord.x < 0.0)
|
||||
gl_FragColor = vec4(0.0);
|
||||
else
|
||||
#else
|
||||
vec2 texcoord = TEX0;
|
||||
#endif
|
||||
{
|
||||
vec2 texcoordInPixels = texcoord * TextureSize;
|
||||
#if defined(SHARPER)
|
||||
vec2 tempCoord = floor(texcoordInPixels) + 0.5;
|
||||
vec2 coord = tempCoord / TextureSize;
|
||||
vec2 deltas = texcoordInPixels - tempCoord;
|
||||
float scanLineWeight = CalcScanLine(deltas.y);
|
||||
vec2 signs = sign(deltas);
|
||||
deltas.x *= 2.0;
|
||||
deltas = deltas * deltas;
|
||||
deltas.y = deltas.y * deltas.y;
|
||||
deltas.x *= 0.5;
|
||||
deltas.y *= 8.0;
|
||||
deltas /= TextureSize;
|
||||
deltas *= signs;
|
||||
vec2 tc = coord + deltas;
|
||||
#else
|
||||
float tempY = floor(texcoordInPixels.y) + 0.5;
|
||||
float yCoord = tempY / TextureSize.y;
|
||||
float dy = texcoordInPixels.y - tempY;
|
||||
float scanLineWeight = CalcScanLine(dy);
|
||||
float signY = sign(dy);
|
||||
dy = dy * dy;
|
||||
dy = dy * dy;
|
||||
dy *= 8.0;
|
||||
dy /= TextureSize.y;
|
||||
dy *= signY;
|
||||
vec2 tc = vec2(texcoord.x, yCoord + dy);
|
||||
#endif
|
||||
|
||||
vec3 colour = texture2D(Texture, tc).rgb;
|
||||
|
||||
#if defined(SCANLINES)
|
||||
#if defined(GAMMA)
|
||||
#if defined(FAKE_GAMMA)
|
||||
colour = colour * colour;
|
||||
#else
|
||||
colour = pow(colour, vec3(INPUT_GAMMA));
|
||||
#endif
|
||||
#endif
|
||||
scanLineWeight *= BLOOM_FACTOR;
|
||||
colour *= scanLineWeight;
|
||||
|
||||
#if defined(GAMMA)
|
||||
#if defined(FAKE_GAMMA)
|
||||
colour = sqrt(colour);
|
||||
#else
|
||||
colour = pow(colour, vec3(1.0/OUTPUT_GAMMA));
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#if MASK_TYPE == 0
|
||||
gl_FragColor = vec4(colour, 1.0);
|
||||
#else
|
||||
#if MASK_TYPE == 1
|
||||
float whichMask = fract((gl_FragCoord.x*1.0001) * 0.5);
|
||||
vec3 mask;
|
||||
if (whichMask < 0.5)
|
||||
mask = vec3(MASK_BRIGHTNESS, 1.0, MASK_BRIGHTNESS);
|
||||
else
|
||||
mask = vec3(1.0, MASK_BRIGHTNESS, 1.0);
|
||||
#elif MASK_TYPE == 2
|
||||
float whichMask = fract((gl_FragCoord.x*1.0001) * 0.3333333);
|
||||
vec3 mask = vec3(MASK_BRIGHTNESS, MASK_BRIGHTNESS, MASK_BRIGHTNESS);
|
||||
if (whichMask < 0.3333333)
|
||||
mask.x = 1.0;
|
||||
else if (whichMask < 0.6666666)
|
||||
mask.y = 1.0;
|
||||
else
|
||||
mask.z = 1.0;
|
||||
#endif
|
||||
|
||||
gl_FragColor = vec4(colour * mask, 1.0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,234 +0,0 @@
|
||||
/*
|
||||
crt-pi - A Raspberry Pi friendly CRT shader.
|
||||
|
||||
Copyright (C) 2015-2016 davej
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
|
||||
Notes:
|
||||
|
||||
This shader is designed to work well on Raspberry Pi GPUs (i.e. 1080P @ 60Hz on a game with a 4:3 aspect ratio). It pushes the Pi's GPU hard and enabling some features will slow it down so that it is no longer able to match 1080P @ 60Hz. You will need to overclock your Pi to the fastest setting in raspi-config to get the best results from this shader: 'Pi2' for Pi2 and 'Turbo' for original Pi and Pi Zero. Note: Pi2s are slower at running the shader than other Pis, this seems to be down to Pi2s lower maximum memory speed. Pi2s don't quite manage 1080P @ 60Hz - they drop about 1 in 1000 frames. You probably won't notice this, but if you do, try enabling FAKE_GAMMA.
|
||||
|
||||
SCANLINES enables scanlines. You'll almost certainly want to use it with MULTISAMPLE to reduce moire effects. SCANLINE_WEIGHT defines how wide scanlines are (it is an inverse value so a higher number = thinner lines). SCANLINE_GAP_BRIGHTNESS defines how dark the gaps between the scan lines are. Darker gaps between scan lines make moire effects more likely.
|
||||
|
||||
GAMMA enables gamma correction using the values in INPUT_GAMMA and OUTPUT_GAMMA. FAKE_GAMMA causes it to ignore the values in INPUT_GAMMA and OUTPUT_GAMMA and approximate gamma correction in a way which is faster than true gamma whilst still looking better than having none. You must have GAMMA defined to enable FAKE_GAMMA.
|
||||
|
||||
CURVATURE distorts the screen by CURVATURE_X and CURVATURE_Y. Curvature slows things down a lot.
|
||||
|
||||
By default the shader uses linear blending horizontally. If you find this too blury, enable SHARPER.
|
||||
|
||||
BLOOM_FACTOR controls the increase in width for bright scanlines.
|
||||
|
||||
MASK_TYPE defines what, if any, shadow mask to use. MASK_BRIGHTNESS defines how much the mask type darkens the screen.
|
||||
|
||||
*/
|
||||
|
||||
#pragma parameter CURVATURE_X "Screen curvature - horizontal" 0.10 0.0 1.0 0.01
|
||||
#pragma parameter CURVATURE_Y "Screen curvature - vertical" 0.15 0.0 1.0 0.01
|
||||
#pragma parameter MASK_BRIGHTNESS "Mask brightness" 0.70 0.0 1.0 0.01
|
||||
#pragma parameter SCANLINE_WEIGHT "Scanline weight" 6.0 0.0 15.0 0.1
|
||||
#pragma parameter SCANLINE_GAP_BRIGHTNESS "Scanline gap brightness" 0.12 0.0 1.0 0.01
|
||||
#pragma parameter BLOOM_FACTOR "Bloom factor" 1.5 0.0 5.0 0.01
|
||||
#pragma parameter INPUT_GAMMA "Input gamma" 2.4 0.0 5.0 0.01
|
||||
#pragma parameter OUTPUT_GAMMA "Output gamma" 2.2 0.0 5.0 0.01
|
||||
|
||||
// Haven't put these as parameters as it would slow the code down.
|
||||
#define SCANLINES
|
||||
#define MULTISAMPLE
|
||||
#define GAMMA
|
||||
//#define FAKE_GAMMA
|
||||
//#define CURVATURE
|
||||
//#define SHARPER
|
||||
// MASK_TYPE: 0 = none, 1 = green/magenta, 2 = trinitron(ish)
|
||||
#define MASK_TYPE 2
|
||||
|
||||
|
||||
#ifdef GL_ES
|
||||
#define COMPAT_PRECISION mediump
|
||||
precision mediump float;
|
||||
#else
|
||||
#define COMPAT_PRECISION
|
||||
#endif
|
||||
|
||||
#ifdef PARAMETER_UNIFORM
|
||||
uniform COMPAT_PRECISION float CURVATURE_X;
|
||||
uniform COMPAT_PRECISION float CURVATURE_Y;
|
||||
uniform COMPAT_PRECISION float MASK_BRIGHTNESS;
|
||||
uniform COMPAT_PRECISION float SCANLINE_WEIGHT;
|
||||
uniform COMPAT_PRECISION float SCANLINE_GAP_BRIGHTNESS;
|
||||
uniform COMPAT_PRECISION float BLOOM_FACTOR;
|
||||
uniform COMPAT_PRECISION float INPUT_GAMMA;
|
||||
uniform COMPAT_PRECISION float OUTPUT_GAMMA;
|
||||
#else
|
||||
#define CURVATURE_X 0.05
|
||||
#define CURVATURE_Y 0.1
|
||||
#define MASK_BRIGHTNESS 0.80
|
||||
#define SCANLINE_WEIGHT 6.0
|
||||
#define SCANLINE_GAP_BRIGHTNESS 0.12
|
||||
#define BLOOM_FACTOR 3.5
|
||||
#define INPUT_GAMMA 2.4
|
||||
#define OUTPUT_GAMMA 2.2
|
||||
#endif
|
||||
|
||||
/* COMPATIBILITY
|
||||
- GLSL compilers
|
||||
*/
|
||||
|
||||
//uniform vec2 TextureSize;
|
||||
#if defined(CURVATURE)
|
||||
varying vec2 screenScale;
|
||||
#endif
|
||||
varying vec2 TEX0;
|
||||
varying float filterWidth;
|
||||
|
||||
#if defined(VERTEX)
|
||||
//uniform mat4 MVPMatrix;
|
||||
//attribute vec4 VertexCoord;
|
||||
//attribute vec2 TexCoord;
|
||||
//uniform vec2 InputSize;
|
||||
//uniform vec2 OutputSize;
|
||||
|
||||
void main()
|
||||
{
|
||||
#if defined(CURVATURE)
|
||||
screenScale = vec2(1.0, 1.0); //TextureSize / InputSize;
|
||||
#endif
|
||||
filterWidth = (768.0 / 256.0) / 3.0;
|
||||
TEX0 = vec2(gl_MultiTexCoord0.x, 1.0-gl_MultiTexCoord0.y)*1.0001;
|
||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
}
|
||||
#elif defined(FRAGMENT)
|
||||
|
||||
uniform sampler2D Texture;
|
||||
|
||||
#if defined(CURVATURE)
|
||||
vec2 Distort(vec2 coord)
|
||||
{
|
||||
vec2 CURVATURE_DISTORTION = vec2(CURVATURE_X, CURVATURE_Y);
|
||||
// Barrel distortion shrinks the display area a bit, this will allow us to counteract that.
|
||||
vec2 barrelScale = 1.0 - (0.23 * CURVATURE_DISTORTION);
|
||||
coord *= screenScale;
|
||||
coord -= vec2(0.5);
|
||||
float rsq = coord.x * coord.x + coord.y * coord.y;
|
||||
coord += coord * (CURVATURE_DISTORTION * rsq);
|
||||
coord *= barrelScale;
|
||||
if (abs(coord.x) >= 0.5 || abs(coord.y) >= 0.5)
|
||||
coord = vec2(-1.0); // If out of bounds, return an invalid value.
|
||||
else
|
||||
{
|
||||
coord += vec2(0.5);
|
||||
coord /= screenScale;
|
||||
}
|
||||
|
||||
return coord;
|
||||
}
|
||||
#endif
|
||||
|
||||
float CalcScanLineWeight(float dist)
|
||||
{
|
||||
return max(1.0-dist*dist*SCANLINE_WEIGHT, SCANLINE_GAP_BRIGHTNESS);
|
||||
}
|
||||
|
||||
float CalcScanLine(float dy)
|
||||
{
|
||||
float scanLineWeight = CalcScanLineWeight(dy);
|
||||
#if defined(MULTISAMPLE)
|
||||
scanLineWeight += CalcScanLineWeight(dy-filterWidth);
|
||||
scanLineWeight += CalcScanLineWeight(dy+filterWidth);
|
||||
scanLineWeight *= 0.3333333;
|
||||
#endif
|
||||
return scanLineWeight;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 TextureSize = vec2(320.0, 256.0);
|
||||
#if defined(CURVATURE)
|
||||
vec2 texcoord = Distort(TEX0);
|
||||
if (texcoord.x < 0.0)
|
||||
gl_FragColor = vec4(0.0);
|
||||
else
|
||||
#else
|
||||
vec2 texcoord = TEX0;
|
||||
#endif
|
||||
{
|
||||
vec2 texcoordInPixels = texcoord * TextureSize;
|
||||
#if defined(SHARPER)
|
||||
vec2 tempCoord = floor(texcoordInPixels) + 0.5;
|
||||
vec2 coord = tempCoord / TextureSize;
|
||||
vec2 deltas = texcoordInPixels - tempCoord;
|
||||
float scanLineWeight = CalcScanLine(deltas.y);
|
||||
vec2 signs = sign(deltas);
|
||||
deltas.x *= 2.0;
|
||||
deltas = deltas * deltas;
|
||||
deltas.y = deltas.y * deltas.y;
|
||||
deltas.x *= 0.5;
|
||||
deltas.y *= 8.0;
|
||||
deltas /= TextureSize;
|
||||
deltas *= signs;
|
||||
vec2 tc = coord + deltas;
|
||||
#else
|
||||
float tempY = floor(texcoordInPixels.y) + 0.5;
|
||||
float yCoord = tempY / TextureSize.y;
|
||||
float dy = texcoordInPixels.y - tempY;
|
||||
float scanLineWeight = CalcScanLine(dy);
|
||||
float signY = sign(dy);
|
||||
dy = dy * dy;
|
||||
dy = dy * dy;
|
||||
dy *= 8.0;
|
||||
dy /= TextureSize.y;
|
||||
dy *= signY;
|
||||
vec2 tc = vec2(texcoord.x, yCoord + dy);
|
||||
#endif
|
||||
|
||||
vec3 colour = texture2D(Texture, tc).rgb;
|
||||
|
||||
#if defined(SCANLINES)
|
||||
#if defined(GAMMA)
|
||||
#if defined(FAKE_GAMMA)
|
||||
colour = colour * colour;
|
||||
#else
|
||||
colour = pow(colour, vec3(INPUT_GAMMA));
|
||||
#endif
|
||||
#endif
|
||||
scanLineWeight *= BLOOM_FACTOR;
|
||||
colour *= scanLineWeight;
|
||||
|
||||
#if defined(GAMMA)
|
||||
#if defined(FAKE_GAMMA)
|
||||
colour = sqrt(colour);
|
||||
#else
|
||||
colour = pow(colour, vec3(1.0/OUTPUT_GAMMA));
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#if MASK_TYPE == 0
|
||||
gl_FragColor = vec4(colour, 1.0);
|
||||
#else
|
||||
#if MASK_TYPE == 1
|
||||
float whichMask = fract((gl_FragCoord.x*1.0001) * 0.5);
|
||||
vec3 mask;
|
||||
if (whichMask < 0.5)
|
||||
mask = vec3(MASK_BRIGHTNESS, 1.0, MASK_BRIGHTNESS);
|
||||
else
|
||||
mask = vec3(1.0, MASK_BRIGHTNESS, 1.0);
|
||||
#elif MASK_TYPE == 2
|
||||
float whichMask = fract((gl_FragCoord.x*1.0001) * 0.3333333);
|
||||
vec3 mask = vec3(MASK_BRIGHTNESS, MASK_BRIGHTNESS, MASK_BRIGHTNESS);
|
||||
if (whichMask < 0.3333333)
|
||||
mask.x = 1.0;
|
||||
else if (whichMask < 0.6666666)
|
||||
mask.y = 1.0;
|
||||
else
|
||||
mask.z = 1.0;
|
||||
#endif
|
||||
|
||||
gl_FragColor = vec4(colour * mask, 1.0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
157
data/shaders/crtpi_fragment.glsl
Normal file
@@ -0,0 +1,157 @@
|
||||
#version 330 core
|
||||
|
||||
// Configuración
|
||||
#define SCANLINES
|
||||
#define MULTISAMPLE
|
||||
#define GAMMA
|
||||
//#define FAKE_GAMMA
|
||||
//#define CURVATURE
|
||||
//#define SHARPER
|
||||
#define MASK_TYPE 2
|
||||
|
||||
#define CURVATURE_X 0.05
|
||||
#define CURVATURE_Y 0.1
|
||||
#define MASK_BRIGHTNESS 0.80
|
||||
#define SCANLINE_WEIGHT 6.0
|
||||
#define SCANLINE_GAP_BRIGHTNESS 0.12
|
||||
#define BLOOM_FACTOR 3.5
|
||||
#define INPUT_GAMMA 2.4
|
||||
#define OUTPUT_GAMMA 2.2
|
||||
|
||||
// Inputs desde vertex shader
|
||||
in vec2 vTexCoord;
|
||||
in float vFilterWidth;
|
||||
#if defined(CURVATURE)
|
||||
in vec2 vScreenScale;
|
||||
#endif
|
||||
|
||||
// Output
|
||||
out vec4 FragColor;
|
||||
|
||||
// Uniforms
|
||||
uniform sampler2D Texture;
|
||||
uniform vec2 TextureSize;
|
||||
|
||||
#if defined(CURVATURE)
|
||||
vec2 Distort(vec2 coord)
|
||||
{
|
||||
vec2 CURVATURE_DISTORTION = vec2(CURVATURE_X, CURVATURE_Y);
|
||||
vec2 barrelScale = 1.0 - (0.23 * CURVATURE_DISTORTION);
|
||||
coord *= vScreenScale;
|
||||
coord -= vec2(0.5);
|
||||
float rsq = coord.x * coord.x + coord.y * coord.y;
|
||||
coord += coord * (CURVATURE_DISTORTION * rsq);
|
||||
coord *= barrelScale;
|
||||
if (abs(coord.x) >= 0.5 || abs(coord.y) >= 0.5)
|
||||
coord = vec2(-1.0);
|
||||
else
|
||||
{
|
||||
coord += vec2(0.5);
|
||||
coord /= vScreenScale;
|
||||
}
|
||||
return coord;
|
||||
}
|
||||
#endif
|
||||
|
||||
float CalcScanLineWeight(float dist)
|
||||
{
|
||||
return max(1.0 - dist * dist * SCANLINE_WEIGHT, SCANLINE_GAP_BRIGHTNESS);
|
||||
}
|
||||
|
||||
float CalcScanLine(float dy)
|
||||
{
|
||||
float scanLineWeight = CalcScanLineWeight(dy);
|
||||
#if defined(MULTISAMPLE)
|
||||
scanLineWeight += CalcScanLineWeight(dy - vFilterWidth);
|
||||
scanLineWeight += CalcScanLineWeight(dy + vFilterWidth);
|
||||
scanLineWeight *= 0.3333333;
|
||||
#endif
|
||||
return scanLineWeight;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
#if defined(CURVATURE)
|
||||
vec2 texcoord = Distort(vTexCoord);
|
||||
if (texcoord.x < 0.0) {
|
||||
FragColor = vec4(0.0);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
vec2 texcoord = vTexCoord;
|
||||
#endif
|
||||
|
||||
vec2 texcoordInPixels = texcoord * TextureSize;
|
||||
|
||||
#if defined(SHARPER)
|
||||
vec2 tempCoord = floor(texcoordInPixels) + 0.5;
|
||||
vec2 coord = tempCoord / TextureSize;
|
||||
vec2 deltas = texcoordInPixels - tempCoord;
|
||||
float scanLineWeight = CalcScanLine(deltas.y);
|
||||
vec2 signs = sign(deltas);
|
||||
deltas.x *= 2.0;
|
||||
deltas = deltas * deltas;
|
||||
deltas.y = deltas.y * deltas.y;
|
||||
deltas.x *= 0.5;
|
||||
deltas.y *= 8.0;
|
||||
deltas /= TextureSize;
|
||||
deltas *= signs;
|
||||
vec2 tc = coord + deltas;
|
||||
#else
|
||||
float tempY = floor(texcoordInPixels.y) + 0.5;
|
||||
float yCoord = tempY / TextureSize.y;
|
||||
float dy = texcoordInPixels.y - tempY;
|
||||
float scanLineWeight = CalcScanLine(dy);
|
||||
float signY = sign(dy);
|
||||
dy = dy * dy;
|
||||
dy = dy * dy;
|
||||
dy *= 8.0;
|
||||
dy /= TextureSize.y;
|
||||
dy *= signY;
|
||||
vec2 tc = vec2(texcoord.x, yCoord + dy);
|
||||
#endif
|
||||
|
||||
vec3 colour = texture(Texture, tc).rgb;
|
||||
|
||||
#if defined(SCANLINES)
|
||||
#if defined(GAMMA)
|
||||
#if defined(FAKE_GAMMA)
|
||||
colour = colour * colour;
|
||||
#else
|
||||
colour = pow(colour, vec3(INPUT_GAMMA));
|
||||
#endif
|
||||
#endif
|
||||
scanLineWeight *= BLOOM_FACTOR;
|
||||
colour *= scanLineWeight;
|
||||
|
||||
#if defined(GAMMA)
|
||||
#if defined(FAKE_GAMMA)
|
||||
colour = sqrt(colour);
|
||||
#else
|
||||
colour = pow(colour, vec3(1.0 / OUTPUT_GAMMA));
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MASK_TYPE == 0
|
||||
FragColor = vec4(colour, 1.0);
|
||||
#elif MASK_TYPE == 1
|
||||
float whichMask = fract(gl_FragCoord.x * 0.5);
|
||||
vec3 mask;
|
||||
if (whichMask < 0.5)
|
||||
mask = vec3(MASK_BRIGHTNESS, 1.0, MASK_BRIGHTNESS);
|
||||
else
|
||||
mask = vec3(1.0, MASK_BRIGHTNESS, 1.0);
|
||||
FragColor = vec4(colour * mask, 1.0);
|
||||
#elif MASK_TYPE == 2
|
||||
float whichMask = fract(gl_FragCoord.x * 0.3333333);
|
||||
vec3 mask = vec3(MASK_BRIGHTNESS, MASK_BRIGHTNESS, MASK_BRIGHTNESS);
|
||||
if (whichMask < 0.3333333)
|
||||
mask.x = 1.0;
|
||||
else if (whichMask < 0.6666666)
|
||||
mask.y = 1.0;
|
||||
else
|
||||
mask.z = 1.0;
|
||||
FragColor = vec4(colour * mask, 1.0);
|
||||
#endif
|
||||
}
|
||||
48
data/shaders/crtpi_vertex.glsl
Normal file
@@ -0,0 +1,48 @@
|
||||
#version 330 core
|
||||
|
||||
// Configuración
|
||||
#define SCANLINES
|
||||
#define MULTISAMPLE
|
||||
#define GAMMA
|
||||
//#define FAKE_GAMMA
|
||||
//#define CURVATURE
|
||||
//#define SHARPER
|
||||
#define MASK_TYPE 2
|
||||
|
||||
#define CURVATURE_X 0.05
|
||||
#define CURVATURE_Y 0.1
|
||||
#define MASK_BRIGHTNESS 0.80
|
||||
#define SCANLINE_WEIGHT 6.0
|
||||
#define SCANLINE_GAP_BRIGHTNESS 0.12
|
||||
#define BLOOM_FACTOR 3.5
|
||||
#define INPUT_GAMMA 2.4
|
||||
#define OUTPUT_GAMMA 2.2
|
||||
|
||||
// Inputs (desde VAO)
|
||||
layout(location = 0) in vec2 aPosition;
|
||||
layout(location = 1) in vec2 aTexCoord;
|
||||
|
||||
// Outputs al fragment shader
|
||||
out vec2 vTexCoord;
|
||||
out float vFilterWidth;
|
||||
#if defined(CURVATURE)
|
||||
out vec2 vScreenScale;
|
||||
#endif
|
||||
|
||||
// Uniforms
|
||||
uniform vec2 TextureSize;
|
||||
|
||||
void main()
|
||||
{
|
||||
#if defined(CURVATURE)
|
||||
vScreenScale = vec2(1.0, 1.0);
|
||||
#endif
|
||||
// Calcula filterWidth dinámicamente basándose en la altura de la textura
|
||||
vFilterWidth = (768.0 / TextureSize.y) / 3.0;
|
||||
|
||||
// Pasar coordenadas de textura (invertir Y para SDL)
|
||||
vTexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y) * 1.0001;
|
||||
|
||||
// Posición del vértice (ya en espacio de clip [-1, 1])
|
||||
gl_Position = vec4(aPosition, 0.0, 1.0);
|
||||
}
|
||||
BIN
data/sound/bullet2p.wav
Normal file
BIN
data/sound/name_input_accept.wav
Normal file
BIN
data/sound/service_menu_back.wav
Normal file
BIN
data/sound/voice_game_over.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
|
||||
|
||||
@@ -2,13 +2,16 @@
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_LogCategory, SDL_LogInfo, SDL_LogError, SDL_LogWarn
|
||||
|
||||
#include <cstddef> // Para size_t
|
||||
#include <exception> // Para exception
|
||||
#include <fstream> // Para basic_istream, basic_ifstream, ifstream, istringstream
|
||||
#include <sstream> // Para basic_istringstream
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <algorithm> // Para std::sort
|
||||
#include <cstddef> // Para size_t
|
||||
#include <exception> // Para exception
|
||||
#include <filesystem> // Para std::filesystem
|
||||
#include <fstream> // Para basic_istream, basic_ifstream, ifstream, istringstream
|
||||
#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 +142,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();
|
||||
@@ -193,18 +207,28 @@ 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();
|
||||
auto Asset::checkFile(const std::string &path) const -> bool {
|
||||
// Construir ruta del pack usando executable_path_
|
||||
std::string pack_path = executable_path_ + "resources.pack";
|
||||
bool pack_exists = std::filesystem::exists(pack_path);
|
||||
|
||||
if (!success) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Checking file: %s [ ERROR ]",
|
||||
getFileName(path).c_str());
|
||||
if (pack_exists) {
|
||||
// MODO PACK: Usar ResourceHelper (igual que la carga real)
|
||||
auto data = ResourceHelper::loadFile(path);
|
||||
return !data.empty();
|
||||
} else {
|
||||
// MODO FILESYSTEM: Verificación directa (modo desarrollo)
|
||||
std::ifstream file(path);
|
||||
bool success = file.good();
|
||||
file.close();
|
||||
|
||||
if (!success) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Error: Could not open file: %s", path.c_str());
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// Parsea string a Type
|
||||
@@ -276,6 +300,9 @@ auto Asset::getListByType(Type type) const -> std::vector<std::string> {
|
||||
}
|
||||
}
|
||||
|
||||
// Ordenar alfabéticamente para garantizar orden consistente
|
||||
std::sort(list.begin(), list.end());
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ---
|
||||
@@ -53,7 +57,7 @@ class Asset {
|
||||
std::string executable_path_; // Ruta del ejecutable
|
||||
|
||||
// --- Métodos internos ---
|
||||
[[nodiscard]] static auto checkFile(const std::string &path) -> bool; // Verifica si un archivo existe
|
||||
[[nodiscard]] auto checkFile(const std::string &path) const -> bool; // Verifica si un archivo existe
|
||||
[[nodiscard]] static auto getTypeName(Type type) -> std::string; // Obtiene el nombre del tipo
|
||||
[[nodiscard]] static auto parseAssetType(const std::string &type_str) -> Type; // Convierte string a tipo
|
||||
void addToMap(const std::string &file_path, Type type, bool required, bool absolute); // Añade archivo al mapa
|
||||
|
||||
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;
|
||||
};
|
||||
@@ -4,9 +4,7 @@
|
||||
|
||||
#include <algorithm> // Para clamp
|
||||
|
||||
#ifndef NO_AUDIO
|
||||
#include "external/jail_audio.h" // Para JA_FadeOutMusic, JA_Init, JA_PauseM...
|
||||
#endif
|
||||
#include "options.h" // Para AudioOptions, audio, MusicOptions
|
||||
#include "resource.h" // Para Resource
|
||||
|
||||
@@ -27,9 +25,7 @@ Audio::Audio() { initSDLAudio(); }
|
||||
|
||||
// Destructor
|
||||
Audio::~Audio() {
|
||||
#ifndef NO_AUDIO
|
||||
JA_Quit();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Método principal
|
||||
@@ -43,9 +39,7 @@ void Audio::playMusic(const std::string &name, const int loop) {
|
||||
music_.loop = (loop != 0);
|
||||
|
||||
if (music_enabled_ && music_.state != MusicState::PLAYING) {
|
||||
#ifndef NO_AUDIO
|
||||
JA_PlayMusic(Resource::get()->getMusic(name), loop);
|
||||
#endif
|
||||
music_.state = MusicState::PLAYING;
|
||||
}
|
||||
}
|
||||
@@ -53,9 +47,7 @@ void Audio::playMusic(const std::string &name, const int loop) {
|
||||
// Pausa la música
|
||||
void Audio::pauseMusic() {
|
||||
if (music_enabled_ && music_.state == MusicState::PLAYING) {
|
||||
#ifndef NO_AUDIO
|
||||
JA_PauseMusic();
|
||||
#endif
|
||||
music_.state = MusicState::PAUSED;
|
||||
}
|
||||
}
|
||||
@@ -63,9 +55,7 @@ void Audio::pauseMusic() {
|
||||
// Continua la música pausada
|
||||
void Audio::resumeMusic() {
|
||||
if (music_enabled_ && music_.state == MusicState::PAUSED) {
|
||||
#ifndef NO_AUDIO
|
||||
JA_ResumeMusic();
|
||||
#endif
|
||||
music_.state = MusicState::PLAYING;
|
||||
}
|
||||
}
|
||||
@@ -73,9 +63,7 @@ void Audio::resumeMusic() {
|
||||
// Detiene la música
|
||||
void Audio::stopMusic() {
|
||||
if (music_enabled_) {
|
||||
#ifndef NO_AUDIO
|
||||
JA_StopMusic();
|
||||
#endif
|
||||
music_.state = MusicState::STOPPED;
|
||||
}
|
||||
}
|
||||
@@ -83,27 +71,37 @@ void Audio::stopMusic() {
|
||||
// Reproduce un sonido
|
||||
void Audio::playSound(const std::string &name, Group group) const {
|
||||
if (sound_enabled_) {
|
||||
#ifndef NO_AUDIO
|
||||
JA_PlaySound(Resource::get()->getSound(name), 0, static_cast<int>(group));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Detiene todos los sonidos
|
||||
void Audio::stopAllSounds() const {
|
||||
if (sound_enabled_) {
|
||||
#ifndef NO_AUDIO
|
||||
JA_StopChannel(-1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Realiza un fundido de salida de la música
|
||||
void Audio::fadeOutMusic(int milliseconds) const {
|
||||
if (music_enabled_) {
|
||||
#ifndef NO_AUDIO
|
||||
if (music_enabled_ && getRealMusicState() == MusicState::PLAYING) {
|
||||
JA_FadeOutMusic(milliseconds);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Consulta directamente el estado real de la música en jailaudio
|
||||
auto Audio::getRealMusicState() const -> MusicState {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,10 +109,8 @@ void Audio::fadeOutMusic(int milliseconds) const {
|
||||
void Audio::setSoundVolume(int sound_volume, Group group) const {
|
||||
if (sound_enabled_) {
|
||||
sound_volume = std::clamp(sound_volume, MIN_VOLUME, MAX_VOLUME);
|
||||
#ifndef NO_AUDIO
|
||||
const float CONVERTED_VOLUME = (sound_volume / 100.0F) * (Options::audio.volume / 100.0F);
|
||||
JA_SetSoundVolume(CONVERTED_VOLUME, static_cast<int>(group));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,10 +118,8 @@ void Audio::setSoundVolume(int sound_volume, Group group) const {
|
||||
void Audio::setMusicVolume(int music_volume) const {
|
||||
if (music_enabled_) {
|
||||
music_volume = std::clamp(music_volume, MIN_VOLUME, MAX_VOLUME);
|
||||
#ifndef NO_AUDIO
|
||||
const float CONVERTED_VOLUME = (music_volume / 100.0F) * (Options::audio.volume / 100.0F);
|
||||
JA_SetMusicVolume(CONVERTED_VOLUME);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +138,6 @@ void Audio::enable(bool value) {
|
||||
|
||||
// Inicializa SDL Audio
|
||||
void Audio::initSDLAudio() {
|
||||
#ifndef NO_AUDIO
|
||||
if (!SDL_Init(SDL_INIT_AUDIO)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_AUDIO could not initialize! SDL Error: %s", SDL_GetError());
|
||||
} else {
|
||||
@@ -153,7 +146,4 @@ void Audio::initSDLAudio() {
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "** Audio system initialized successfully");
|
||||
}
|
||||
#else
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "** Audio system disabled");
|
||||
#endif
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
170
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,13 @@ class Balloon {
|
||||
|
||||
// --- Setters ---
|
||||
void setVelY(float vel_y) { vy_ = vel_y; }
|
||||
void setSpeed(float speed) { speed_ = speed; }
|
||||
void setVelX(float vel_x) { vx_ = vel_x; }
|
||||
void alterVelX(float percent) {vx_ *= percent; }
|
||||
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 +138,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 +245,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 +301,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
|
||||
|
||||
@@ -16,8 +16,10 @@
|
||||
#include "utils.h"
|
||||
|
||||
// Constructor
|
||||
BalloonManager::BalloonManager(IStageInfo *stage_info)
|
||||
: explosions_(std::make_unique<Explosions>()), balloon_formations_(std::make_unique<BalloonFormations>()), stage_info_(stage_info) { init(); }
|
||||
BalloonManager::BalloonManager(IStageInfo* stage_info)
|
||||
: explosions_(std::make_unique<Explosions>()),
|
||||
balloon_formations_(std::make_unique<BalloonFormations>()),
|
||||
stage_info_(stage_info) { init(); }
|
||||
|
||||
// Inicializa
|
||||
void BalloonManager::init() {
|
||||
@@ -60,18 +62,18 @@ void BalloonManager::init() {
|
||||
explosions_->addTexture(3, explosions_textures_.at(3), explosions_animations_.at(3));
|
||||
}
|
||||
|
||||
// Actualiza
|
||||
void BalloonManager::update() {
|
||||
for (const auto &balloon : balloons_) {
|
||||
balloon->update();
|
||||
// Actualiza (time-based)
|
||||
void BalloonManager::update(float deltaTime) {
|
||||
for (const auto& balloon : balloons_) {
|
||||
balloon->update(deltaTime);
|
||||
}
|
||||
updateBalloonDeployCounter();
|
||||
explosions_->update();
|
||||
updateBalloonDeployCounter(deltaTime);
|
||||
explosions_->update(deltaTime);
|
||||
}
|
||||
|
||||
// Renderiza los objetos
|
||||
void BalloonManager::render() {
|
||||
for (auto &balloon : balloons_) {
|
||||
for (auto& balloon : balloons_) {
|
||||
balloon->render();
|
||||
}
|
||||
explosions_->render();
|
||||
@@ -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,29 +128,44 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
// Vacia del vector de globos los globos que ya no sirven
|
||||
void BalloonManager::freeBalloons() {
|
||||
auto result = std::ranges::remove_if(balloons_, [](const auto &balloon) { return !balloon->isEnabled(); });
|
||||
auto result = std::ranges::remove_if(balloons_, [](const auto& balloon) { return !balloon->isEnabled(); });
|
||||
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
|
||||
@@ -148,17 +173,20 @@ auto BalloonManager::canPowerBallBeCreated() -> bool { return (!power_ball_enabl
|
||||
|
||||
// Calcula el poder actual de los globos en pantalla
|
||||
auto BalloonManager::calculateScreenPower() -> int {
|
||||
return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon) { return sum + (balloon->isEnabled() ? balloon->getPower() : 0); });
|
||||
return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto& balloon) { return sum + (balloon->isEnabled() ? balloon->getPower() : 0); });
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
@@ -166,25 +194,45 @@ auto BalloonManager::createBalloon(float x, int y, Balloon::Type type, Balloon::
|
||||
}
|
||||
|
||||
// Crea un globo a partir de otro globo
|
||||
void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon> &balloon, const std::string &direction) {
|
||||
void BalloonManager::createChildBalloon(const std::shared_ptr<Balloon>& balloon, const std::string& direction) {
|
||||
if (can_deploy_balloons_) {
|
||||
// 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),
|
||||
.type = balloon->getType(),
|
||||
.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);
|
||||
constexpr float VEL_Y_BALLOON_PER_S = -150.0F;
|
||||
switch (b->getType()) {
|
||||
case Balloon::Type::BALLOON: {
|
||||
b->setVelY(VEL_Y_BALLOON_PER_S);
|
||||
break;
|
||||
}
|
||||
case Balloon::Type::FLOATER: {
|
||||
const float MODIFIER = (rand() % 2 == 0) ? 1.0F : 1.0F;
|
||||
b->setVelY(Balloon::VELX_NEGATIVE * 2.0F * MODIFIER);
|
||||
(rand() % 2 == 0) ? b->alterVelX(1.0F) : b->alterVelX(1.0F);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Herencia de estados
|
||||
if (balloon->isStopped()) { b->stop(); }
|
||||
@@ -196,18 +244,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;
|
||||
@@ -218,13 +280,13 @@ void BalloonManager::createPowerBall() {
|
||||
// Establece la velocidad de los globos
|
||||
void BalloonManager::setBalloonSpeed(float speed) {
|
||||
balloon_speed_ = speed;
|
||||
for (auto &balloon : balloons_) {
|
||||
balloon->setSpeed(speed);
|
||||
for (auto& balloon : balloons_) {
|
||||
balloon->setGameTempo(speed);
|
||||
}
|
||||
}
|
||||
|
||||
// Explosiona un globo. Lo destruye y crea otros dos si es el caso
|
||||
auto BalloonManager::popBalloon(const std::shared_ptr<Balloon> &balloon) -> int {
|
||||
auto BalloonManager::popBalloon(const std::shared_ptr<Balloon>& balloon) -> int {
|
||||
stage_info_->addPower(1);
|
||||
int score = 0;
|
||||
|
||||
@@ -232,7 +294,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) {
|
||||
@@ -249,7 +311,7 @@ auto BalloonManager::popBalloon(const std::shared_ptr<Balloon> &balloon) -> int
|
||||
}
|
||||
|
||||
// Explosiona un globo. Lo destruye = no crea otros globos
|
||||
auto BalloonManager::destroyBalloon(std::shared_ptr<Balloon> &balloon) -> int {
|
||||
auto BalloonManager::destroyBalloon(std::shared_ptr<Balloon>& balloon) -> int {
|
||||
int score = 0;
|
||||
|
||||
// Calcula la puntuación y el poder que generaria el globo en caso de romperlo a él y a sus hijos
|
||||
@@ -284,12 +346,12 @@ auto BalloonManager::destroyBalloon(std::shared_ptr<Balloon> &balloon) -> int {
|
||||
// Destruye todos los globos
|
||||
auto BalloonManager::destroyAllBalloons() -> int {
|
||||
int score = 0;
|
||||
for (auto &balloon : balloons_) {
|
||||
for (auto& balloon : balloons_) {
|
||||
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;
|
||||
@@ -297,14 +359,16 @@ auto BalloonManager::destroyAllBalloons() -> int {
|
||||
|
||||
// Detiene todos los globos
|
||||
void BalloonManager::stopAllBalloons() {
|
||||
for (auto &balloon : balloons_) {
|
||||
balloon->stop();
|
||||
for (auto& balloon : balloons_) {
|
||||
if (!balloon->isBeingCreated()) {
|
||||
balloon->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pone en marcha todos los globos
|
||||
void BalloonManager::startAllBalloons() {
|
||||
for (auto &balloon : balloons_) {
|
||||
for (auto& balloon : balloons_) {
|
||||
if (!balloon->isBeingCreated()) {
|
||||
balloon->start();
|
||||
}
|
||||
@@ -313,7 +377,7 @@ void BalloonManager::startAllBalloons() {
|
||||
|
||||
// Cambia el color de todos los globos
|
||||
void BalloonManager::reverseColorsToAllBalloons() {
|
||||
for (auto &balloon : balloons_) {
|
||||
for (auto& balloon : balloons_) {
|
||||
if (balloon->isStopped()) {
|
||||
balloon->useReverseColor();
|
||||
}
|
||||
@@ -322,7 +386,7 @@ void BalloonManager::reverseColorsToAllBalloons() {
|
||||
|
||||
// Cambia el color de todos los globos
|
||||
void BalloonManager::normalColorsToAllBalloons() {
|
||||
for (auto &balloon : balloons_) {
|
||||
for (auto& balloon : balloons_) {
|
||||
balloon->useNormalColor();
|
||||
}
|
||||
}
|
||||
@@ -332,28 +396,15 @@ 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); });
|
||||
return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto& balloon) { return sum + (balloon->isEnabled() ? balloon->getMenace() : 0); });
|
||||
}
|
||||
|
||||
// Establece el sonido de los globos
|
||||
void BalloonManager::setSounds(bool value) {
|
||||
sound_enabled_ = value;
|
||||
for (auto &balloon : balloons_) {
|
||||
for (auto& balloon : balloons_) {
|
||||
balloon->setSound(value);
|
||||
}
|
||||
}
|
||||
@@ -361,14 +412,14 @@ void BalloonManager::setSounds(bool value) {
|
||||
// Activa o desactiva los sonidos de rebote los globos
|
||||
void BalloonManager::setBouncingSounds(bool value) {
|
||||
bouncing_sound_enabled_ = value;
|
||||
for (auto &balloon : balloons_) {
|
||||
for (auto& balloon : balloons_) {
|
||||
balloon->setBouncingSound(value);
|
||||
}
|
||||
}
|
||||
// Activa o desactiva los sonidos de los globos al explotar
|
||||
void BalloonManager::setPoppingSounds(bool value) {
|
||||
poping_sound_enabled_ = value;
|
||||
for (auto &balloon : balloons_) {
|
||||
for (auto& balloon : balloons_) {
|
||||
balloon->setPoppingSound(value);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -4,46 +4,64 @@
|
||||
#include <string> // Para char_traits, basic_string, operator+, string
|
||||
|
||||
#include "param.h" // Para Param, ParamGame, param
|
||||
#include "player.h" // Para Player::Id
|
||||
#include "resource.h" // Para Resource
|
||||
|
||||
// Constructor
|
||||
Bullet::Bullet(float x, float y, BulletType bullet_type, bool powered, Player::Id owner)
|
||||
Bullet::Bullet(float x, float y, Type type, Color color, int owner)
|
||||
: sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("bullet.png"), Resource::get()->getAnimation("bullet.ani"))),
|
||||
bullet_type_(bullet_type),
|
||||
type_(type),
|
||||
owner_(owner),
|
||||
pos_x_(x),
|
||||
pos_y_(y) {
|
||||
vel_x_ = calculateVelocity(bullet_type_);
|
||||
sprite_->setCurrentAnimation(buildAnimationString(bullet_type_, powered));
|
||||
vel_x_ = calculateVelocity(type_);
|
||||
sprite_->setCurrentAnimation(buildAnimationString(type_, color));
|
||||
|
||||
collider_.r = WIDTH / 2;
|
||||
shiftColliders();
|
||||
}
|
||||
|
||||
// Calcula la velocidad horizontal de la bala basada en su tipo
|
||||
auto Bullet::calculateVelocity(BulletType bullet_type) -> float {
|
||||
switch (bullet_type) {
|
||||
case BulletType::LEFT:
|
||||
auto Bullet::calculateVelocity(Type type) -> float {
|
||||
switch (type) {
|
||||
case Type::LEFT:
|
||||
return VEL_X_LEFT;
|
||||
case BulletType::RIGHT:
|
||||
case Type::RIGHT:
|
||||
return VEL_X_RIGHT;
|
||||
default:
|
||||
return VEL_X_CENTER;
|
||||
}
|
||||
}
|
||||
|
||||
// Construye el string de animación basado en el tipo de bala y si está potenciada
|
||||
auto Bullet::buildAnimationString(BulletType bullet_type, bool powered) -> std::string {
|
||||
std::string animation_string = powered ? "powered_" : "normal_";
|
||||
// Construye el string de animación basado en el tipo de bala y color específico
|
||||
auto Bullet::buildAnimationString(Type type, Color color) -> std::string {
|
||||
std::string animation_string;
|
||||
|
||||
switch (bullet_type) {
|
||||
case BulletType::UP:
|
||||
// Mapear color a string específico
|
||||
switch (color) {
|
||||
case Color::YELLOW:
|
||||
animation_string = "yellow_";
|
||||
break;
|
||||
case Color::GREEN:
|
||||
animation_string = "green_";
|
||||
break;
|
||||
case Color::RED:
|
||||
animation_string = "red_";
|
||||
break;
|
||||
case Color::PURPLE:
|
||||
animation_string = "purple_";
|
||||
break;
|
||||
}
|
||||
|
||||
// Añadir dirección
|
||||
switch (type) {
|
||||
case Type::UP:
|
||||
animation_string += "up";
|
||||
break;
|
||||
case BulletType::LEFT:
|
||||
case Type::LEFT:
|
||||
animation_string += "left";
|
||||
break;
|
||||
case BulletType::RIGHT:
|
||||
case Type::RIGHT:
|
||||
animation_string += "right";
|
||||
break;
|
||||
default:
|
||||
@@ -53,48 +71,48 @@ auto Bullet::buildAnimationString(BulletType bullet_type, bool powered) -> std::
|
||||
return animation_string;
|
||||
}
|
||||
|
||||
// Implementación de render (llama al render del sprite_)
|
||||
// Implementación de render
|
||||
void Bullet::render() {
|
||||
if (bullet_type_ != BulletType::NONE) {
|
||||
if (type_ != Type::NONE) {
|
||||
sprite_->render();
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el estado del objeto
|
||||
auto Bullet::update() -> BulletMoveStatus {
|
||||
sprite_->update();
|
||||
return move();
|
||||
auto Bullet::update(float deltaTime) -> MoveStatus {
|
||||
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 MoveStatus
|
||||
auto Bullet::move(float deltaTime) -> MoveStatus {
|
||||
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;
|
||||
return MoveStatus::OUT;
|
||||
}
|
||||
|
||||
pos_y_ += VEL_Y;
|
||||
pos_y_ += VEL_Y * deltaTime;
|
||||
if (pos_y_ < param.game.play_area.rect.y - HEIGHT) {
|
||||
disable();
|
||||
return BulletMoveStatus::OUT;
|
||||
return MoveStatus::OUT;
|
||||
}
|
||||
|
||||
shiftSprite();
|
||||
shiftColliders();
|
||||
|
||||
return BulletMoveStatus::OK;
|
||||
return MoveStatus::OK;
|
||||
}
|
||||
|
||||
auto Bullet::isEnabled() const -> bool {
|
||||
return bullet_type_ != BulletType::NONE;
|
||||
return type_ != Type::NONE;
|
||||
}
|
||||
|
||||
void Bullet::disable() {
|
||||
bullet_type_ = BulletType::NONE;
|
||||
type_ = Type::NONE;
|
||||
}
|
||||
|
||||
auto Bullet::getOwner() const -> Player::Id {
|
||||
auto Bullet::getOwner() const -> int {
|
||||
return owner_;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,22 +6,8 @@
|
||||
#include <string> // Para string
|
||||
|
||||
#include "animated_sprite.h" // Para AnimatedSprite
|
||||
#include "player.h" // Para Player
|
||||
#include "utils.h" // Para Circle
|
||||
|
||||
// --- Enums ---
|
||||
enum class BulletType : Uint8 {
|
||||
UP, // Bala hacia arriba
|
||||
LEFT, // Bala hacia la izquierda
|
||||
RIGHT, // Bala hacia la derecha
|
||||
NONE // Sin bala
|
||||
};
|
||||
|
||||
enum class BulletMoveStatus : Uint8 {
|
||||
OK = 0, // Movimiento normal
|
||||
OUT = 1 // Fuera de los límites
|
||||
};
|
||||
|
||||
// --- Clase Bullet: representa una bala del jugador ---
|
||||
class Bullet {
|
||||
public:
|
||||
@@ -29,42 +15,62 @@ class Bullet {
|
||||
static constexpr float WIDTH = 12.0F; // Anchura de la bala
|
||||
static constexpr float HEIGHT = 12.0F; // Altura de la bala
|
||||
|
||||
// --- Enums ---
|
||||
enum class Type : Uint8 {
|
||||
UP, // Bala hacia arriba
|
||||
LEFT, // Bala hacia la izquierda
|
||||
RIGHT, // Bala hacia la derecha
|
||||
NONE // Sin bala
|
||||
};
|
||||
|
||||
enum class MoveStatus : Uint8 {
|
||||
OK = 0, // Movimiento normal
|
||||
OUT = 1 // Fuera de los límites
|
||||
};
|
||||
|
||||
enum class Color : Uint8 {
|
||||
YELLOW,
|
||||
GREEN,
|
||||
RED,
|
||||
PURPLE
|
||||
};
|
||||
|
||||
// --- Constructor y destructor ---
|
||||
Bullet(float x, float y, BulletType bullet_type, bool powered, Player::Id owner); // Constructor principal
|
||||
~Bullet() = default; // Destructor
|
||||
Bullet(float x, float y, Type type, Color color, int owner); // Constructor principal
|
||||
~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) -> MoveStatus; // Actualiza el estado del objeto (time-based)
|
||||
void disable(); // Desactiva la bala
|
||||
|
||||
// --- Getters ---
|
||||
[[nodiscard]] auto isEnabled() const -> bool; // Comprueba si está activa
|
||||
[[nodiscard]] auto getOwner() const -> Player::Id; // Devuelve el identificador del dueño
|
||||
auto getCollider() -> Circle &; // Devuelve el círculo de colisión
|
||||
[[nodiscard]] auto isEnabled() const -> bool; // Comprueba si está activa
|
||||
[[nodiscard]] auto getOwner() const -> int; // Devuelve el identificador del dueño
|
||||
auto getCollider() -> Circle&; // Devuelve el círculo de colisión
|
||||
|
||||
private:
|
||||
// --- Constantes ---
|
||||
static constexpr float VEL_Y = -3.0F; // 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
|
||||
|
||||
// --- Variables de estado ---
|
||||
Circle collider_; // Círculo de colisión
|
||||
BulletType bullet_type_; // Tipo de bala
|
||||
Player::Id owner_; // Identificador del dueño
|
||||
float pos_x_; // Posición en el eje X
|
||||
float pos_y_; // Posición en el eje Y
|
||||
float vel_x_; // Velocidad en el eje X
|
||||
Circle collider_; // Círculo de colisión
|
||||
Type type_; // Tipo de bala
|
||||
int owner_; // Identificador del jugador
|
||||
float pos_x_; // Posición en el eje X
|
||||
float pos_y_; // Posición en el eje Y
|
||||
float vel_x_; // Velocidad en el eje X
|
||||
|
||||
// --- Métodos internos ---
|
||||
void shiftColliders(); // Ajusta el círculo de colisión
|
||||
void shiftSprite(); // Ajusta el sprite
|
||||
auto move() -> BulletMoveStatus; // Mueve la bala y devuelve su estado
|
||||
static auto calculateVelocity(BulletType bullet_type) -> float; // Calcula la velocidad horizontal de la bala
|
||||
static auto buildAnimationString(BulletType bullet_type, bool powered) -> std::string; // Construye el string de animación
|
||||
void shiftColliders(); // Ajusta el círculo de colisión
|
||||
void shiftSprite(); // Ajusta el sprite
|
||||
auto move(float deltaTime) -> MoveStatus; // Mueve la bala y devuelve su estado (time-based)
|
||||
static auto calculateVelocity(Type type) -> float; // Calcula la velocidad horizontal de la bala
|
||||
static auto buildAnimationString(Type type, Color color) -> std::string; // Construye el string de animación
|
||||
};
|
||||
|
||||
109
source/bullet_manager.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
#include "bullet_manager.h"
|
||||
|
||||
#include <algorithm> // Para remove_if
|
||||
|
||||
#include "bullet.h" // Para Bullet
|
||||
#include "param.h" // Para param
|
||||
#include "player.h" // Para Player
|
||||
|
||||
// Constructor
|
||||
BulletManager::BulletManager()
|
||||
: play_area_(param.game.play_area.rect) {
|
||||
}
|
||||
|
||||
// Actualiza el estado de todas las balas
|
||||
void BulletManager::update(float deltaTime) {
|
||||
for (auto& bullet : bullets_) {
|
||||
if (bullet->isEnabled()) {
|
||||
processBulletUpdate(bullet, deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Renderiza todas las balas activas
|
||||
void BulletManager::render() {
|
||||
for (auto& bullet : bullets_) {
|
||||
if (bullet->isEnabled()) {
|
||||
bullet->render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Crea una nueva bala
|
||||
void BulletManager::createBullet(int x, int y, Bullet::Type type, Bullet::Color color, int owner) {
|
||||
bullets_.emplace_back(std::make_shared<Bullet>(x, y, type, color, owner));
|
||||
}
|
||||
|
||||
// Libera balas que ya no están habilitadas
|
||||
void BulletManager::freeBullets() {
|
||||
if (!bullets_.empty()) {
|
||||
// Elimina las balas deshabilitadas del vector
|
||||
bullets_.erase(
|
||||
std::remove_if(bullets_.begin(), bullets_.end(),
|
||||
[](const std::shared_ptr<Bullet>& bullet) {
|
||||
return !bullet->isEnabled();
|
||||
}),
|
||||
bullets_.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Elimina todas las balas
|
||||
void BulletManager::clearAllBullets() {
|
||||
bullets_.clear();
|
||||
}
|
||||
|
||||
// Verifica colisiones de todas las balas
|
||||
void BulletManager::checkCollisions() {
|
||||
for (auto& bullet : bullets_) {
|
||||
if (!bullet->isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verifica colisión con Tabe
|
||||
if (tabe_collision_callback_ && tabe_collision_callback_(bullet)) {
|
||||
break; // Sale del bucle si hubo colisión
|
||||
}
|
||||
|
||||
// Verifica colisión con globos
|
||||
if (balloon_collision_callback_ && balloon_collision_callback_(bullet)) {
|
||||
break; // Sale del bucle si hubo colisión
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Establece el callback para colisión con Tabe
|
||||
void BulletManager::setTabeCollisionCallback(CollisionCallback callback) {
|
||||
tabe_collision_callback_ = callback;
|
||||
}
|
||||
|
||||
// Establece el callback para colisión con globos
|
||||
void BulletManager::setBalloonCollisionCallback(CollisionCallback callback) {
|
||||
balloon_collision_callback_ = callback;
|
||||
}
|
||||
|
||||
// Establece el callback para balas fuera de límites
|
||||
void BulletManager::setOutOfBoundsCallback(OutOfBoundsCallback callback) {
|
||||
out_of_bounds_callback_ = callback;
|
||||
}
|
||||
|
||||
// --- Métodos privados ---
|
||||
|
||||
// Procesa la actualización individual de una bala
|
||||
void BulletManager::processBulletUpdate(const std::shared_ptr<Bullet>& bullet, float deltaTime) {
|
||||
auto status = bullet->update(deltaTime);
|
||||
|
||||
// Si la bala salió de los límites, llama al callback
|
||||
if (status == Bullet::MoveStatus::OUT && out_of_bounds_callback_) {
|
||||
out_of_bounds_callback_(bullet);
|
||||
}
|
||||
}
|
||||
|
||||
// Verifica si la bala está fuera de los límites del área de juego
|
||||
auto BulletManager::isBulletOutOfBounds(const std::shared_ptr<Bullet>& bullet) -> bool {
|
||||
auto collider = bullet->getCollider();
|
||||
|
||||
return (collider.x < play_area_.x ||
|
||||
collider.x > play_area_.x + play_area_.w ||
|
||||
collider.y < play_area_.y ||
|
||||
collider.y > play_area_.y + play_area_.h);
|
||||
}
|
||||
79
source/bullet_manager.h
Normal file
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_FRect
|
||||
|
||||
#include <functional> // Para function
|
||||
#include <memory> // Para shared_ptr, unique_ptr
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "bullet.h" // Para Bullet
|
||||
#include "utils.h" // Para Circle
|
||||
|
||||
// --- Types ---
|
||||
using Bullets = std::vector<std::shared_ptr<Bullet>>;
|
||||
|
||||
// --- Forward declarations ---
|
||||
class Player;
|
||||
|
||||
// --- Clase BulletManager: gestiona todas las balas del juego ---
|
||||
//
|
||||
// Esta clase se encarga de la gestión completa de las balas del juego,
|
||||
// incluyendo su creación, actualización, renderizado y colisiones.
|
||||
//
|
||||
// Funcionalidades principales:
|
||||
// • Gestión del ciclo de vida: creación, actualización y destrucción de balas
|
||||
// • Renderizado: dibuja todas las balas activas en pantalla
|
||||
// • Detección de colisiones: mediante sistema de callbacks
|
||||
// • Limpieza automática: elimina balas deshabilitadas del contenedor
|
||||
// • Configuración flexible: permite ajustar parámetros de las balas
|
||||
//
|
||||
// La clase utiliza un sistema de callbacks para manejar las colisiones,
|
||||
// permitiendo que la lógica específica del juego permanezca en Game.
|
||||
class BulletManager {
|
||||
public:
|
||||
// --- Types para callbacks ---
|
||||
using CollisionCallback = std::function<bool(const std::shared_ptr<Bullet>&)>;
|
||||
using OutOfBoundsCallback = std::function<void(const std::shared_ptr<Bullet>&)>;
|
||||
|
||||
// --- Constructor y destructor ---
|
||||
BulletManager();
|
||||
~BulletManager() = default;
|
||||
|
||||
// --- Métodos principales ---
|
||||
void update(float deltaTime); // Actualiza el estado de las balas (time-based)
|
||||
void render(); // Renderiza las balas en pantalla
|
||||
|
||||
// --- Gestión de balas ---
|
||||
void createBullet(int x, int y, Bullet::Type type, Bullet::Color color, int owner); // Crea una nueva bala
|
||||
void freeBullets(); // Libera balas que ya no sirven
|
||||
void clearAllBullets(); // Elimina todas las balas
|
||||
|
||||
// --- Detección de colisiones ---
|
||||
void checkCollisions(); // Verifica colisiones de todas las balas
|
||||
void setTabeCollisionCallback(CollisionCallback callback); // Establece callback para colisión con Tabe
|
||||
void setBalloonCollisionCallback(CollisionCallback callback); // Establece callback para colisión con globos
|
||||
void setOutOfBoundsCallback(OutOfBoundsCallback callback); // Establece callback para balas fuera de límites
|
||||
|
||||
// --- Configuración ---
|
||||
void setPlayArea(SDL_FRect play_area) { play_area_ = play_area; }; // Define el área de juego
|
||||
|
||||
// --- Getters ---
|
||||
auto getBullets() -> Bullets& { return bullets_; } // Obtiene referencia al vector de balas
|
||||
[[nodiscard]] auto getNumBullets() const -> int { return bullets_.size(); } // Obtiene el número de balas activas
|
||||
|
||||
private:
|
||||
// --- Objetos y punteros ---
|
||||
Bullets bullets_; // Vector con las balas activas
|
||||
|
||||
// --- Variables de configuración ---
|
||||
SDL_FRect play_area_; // Área de juego para límites
|
||||
|
||||
// --- Callbacks para colisiones ---
|
||||
CollisionCallback tabe_collision_callback_; // Callback para colisión con Tabe
|
||||
CollisionCallback balloon_collision_callback_; // Callback para colisión con globos
|
||||
OutOfBoundsCallback out_of_bounds_callback_; // Callback para balas fuera de límites
|
||||
|
||||
// --- Métodos internos ---
|
||||
void processBulletUpdate(const std::shared_ptr<Bullet>& bullet, float deltaTime); // Procesa actualización individual
|
||||
auto isBulletOutOfBounds(const std::shared_ptr<Bullet>& bullet) -> bool; // Verifica si la bala está fuera de límites
|
||||
};
|
||||
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);
|
||||
@@ -88,6 +95,29 @@ struct Color {
|
||||
return Color(new_r, new_g, new_b, new_a);
|
||||
}
|
||||
|
||||
// Interpolación lineal hacia otro color (t=0.0: this, t=1.0: target)
|
||||
[[nodiscard]] constexpr auto LERP(const Color &target, float t) const -> Color {
|
||||
// Asegurar que t esté en el rango [0.0, 1.0]
|
||||
t = std::clamp(t, 0.0f, 1.0f);
|
||||
|
||||
// Interpolación lineal para cada componente
|
||||
auto lerp_component = [t](Uint8 start, Uint8 end) -> Uint8 {
|
||||
return static_cast<Uint8>(start + (end - start) * t);
|
||||
};
|
||||
|
||||
return Color(
|
||||
lerp_component(r, target.r),
|
||||
lerp_component(g, target.g),
|
||||
lerp_component(b, target.b),
|
||||
lerp_component(a, target.a)
|
||||
);
|
||||
}
|
||||
|
||||
// Sobrecarga para aceptar componentes RGBA directamente
|
||||
[[nodiscard]] constexpr auto LERP(Uint8 red, Uint8 green, Uint8 blue, Uint8 alpha, float t) const -> Color {
|
||||
return LERP(Color(red, green, blue, alpha), t);
|
||||
}
|
||||
|
||||
// Convierte el color a un entero de 32 bits en formato RGBA
|
||||
[[nodiscard]] constexpr auto TO_UINT32() const -> Uint32 {
|
||||
return (static_cast<Uint32>(r) << 24) |
|
||||
@@ -108,25 +138,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
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "color.h"
|
||||
#include "ui/notifier.h" // Para Notifier::Position
|
||||
#include "version.h" // Para Version::APP_NAME
|
||||
|
||||
// --- Namespace GameDefaults: configuración centralizada con valores por defecto del juego ---
|
||||
namespace GameDefaults {
|
||||
@@ -14,9 +15,8 @@ namespace GameDefaults {
|
||||
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 = {
|
||||
@@ -209,7 +211,7 @@ constexpr const char* PLAYER1 = "422028FF";
|
||||
// --- OPTIONS ---
|
||||
namespace Options {
|
||||
// Window
|
||||
constexpr const char* WINDOW_CAPTION = "Coffee Crisis Arcade Edition";
|
||||
constexpr const char* WINDOW_CAPTION = Version::APP_NAME;
|
||||
constexpr int WINDOW_ZOOM = 2;
|
||||
constexpr int WINDOW_MAX_ZOOM = 2;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
70
source/demo.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#include "demo.h"
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_IOStream, SDL_IOFromConstMem, SDL_IOFromFile, SDL_ReadIO, SDL_WriteIO, SDL_CloseIO
|
||||
#include <stdexcept> // Para runtime_error
|
||||
|
||||
#include "resource_helper.h" // Para ResourceHelper
|
||||
#include "utils.h" // Para printWithDots, getFileName
|
||||
|
||||
// Carga el fichero de datos para la demo
|
||||
auto loadDemoDataFromFile(const std::string &file_path) -> DemoData {
|
||||
DemoData dd;
|
||||
|
||||
SDL_IOStream *file = nullptr;
|
||||
|
||||
// Intentar cargar desde ResourceHelper primero
|
||||
auto resource_data = ResourceHelper::loadFile(file_path);
|
||||
if (!resource_data.empty()) {
|
||||
file = SDL_IOFromConstMem(resource_data.data(), resource_data.size());
|
||||
} else {
|
||||
// Fallback a filesystem directo
|
||||
file = SDL_IOFromFile(file_path.c_str(), "r+b");
|
||||
}
|
||||
|
||||
if (file == nullptr) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Fichero no encontrado %s", file_path.c_str());
|
||||
throw std::runtime_error("Fichero no encontrado: " + file_path);
|
||||
}
|
||||
printWithDots("DemoData : ", getFileName(file_path), "[ LOADED ]");
|
||||
|
||||
// Lee todos los datos del fichero y los deja en el destino
|
||||
for (int i = 0; i < TOTAL_DEMO_DATA; ++i) {
|
||||
DemoKeys dk = DemoKeys();
|
||||
SDL_ReadIO(file, &dk, sizeof(DemoKeys));
|
||||
dd.push_back(dk);
|
||||
}
|
||||
|
||||
// Cierra el fichero
|
||||
SDL_CloseIO(file);
|
||||
|
||||
return dd;
|
||||
}
|
||||
|
||||
#ifdef RECORDING
|
||||
// Guarda el fichero de datos para la demo
|
||||
bool saveDemoFile(const std::string &file_path, const DemoData &dd) {
|
||||
auto success = true;
|
||||
auto file = SDL_IOFromFile(file_path.c_str(), "w+b");
|
||||
|
||||
if (file) {
|
||||
// Guarda los datos
|
||||
for (const auto &data : dd) {
|
||||
if (SDL_WriteIO(file, &data, sizeof(DemoKeys)) != sizeof(DemoKeys)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al escribir el fichero %s", getFileName(file_path).c_str());
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Writing file %s", getFileName(file_path).c_str());
|
||||
}
|
||||
// Cierra el fichero
|
||||
SDL_CloseIO(file);
|
||||
} else {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: Unable to save %s file! %s", getFileName(file_path).c_str(), SDL_GetError());
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
#endif // RECORDING
|
||||
54
source/demo.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h> // Para Uint8
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
// --- Constantes ---
|
||||
constexpr int TOTAL_DEMO_DATA = 2000;
|
||||
|
||||
// --- Estructuras ---
|
||||
struct DemoKeys {
|
||||
Uint8 left;
|
||||
Uint8 right;
|
||||
Uint8 no_input;
|
||||
Uint8 fire;
|
||||
Uint8 fire_left;
|
||||
Uint8 fire_right;
|
||||
|
||||
explicit DemoKeys(Uint8 l = 0, Uint8 r = 0, Uint8 ni = 0, Uint8 f = 0, Uint8 fl = 0, Uint8 fr = 0)
|
||||
: left(l),
|
||||
right(r),
|
||||
no_input(ni),
|
||||
fire(f),
|
||||
fire_left(fl),
|
||||
fire_right(fr) {}
|
||||
};
|
||||
|
||||
// --- Tipos ---
|
||||
using DemoData = std::vector<DemoKeys>;
|
||||
|
||||
struct Demo {
|
||||
bool enabled = false; // Indica si está activo el modo demo
|
||||
bool recording = false; // Indica si está activado el modo para grabar la demo
|
||||
float elapsed_s = 0.0F; // Segundos transcurridos de demo
|
||||
int index = 0; // Contador para el modo demo
|
||||
DemoKeys keys; // Variable con las pulsaciones de teclas del modo demo
|
||||
std::vector<DemoData> data; // Vector con diferentes sets de datos con los movimientos para la demo
|
||||
|
||||
Demo() = default;
|
||||
|
||||
Demo(bool e, bool r, int c, const DemoKeys& k, const std::vector<DemoData>& d)
|
||||
: enabled(e),
|
||||
recording(r),
|
||||
index(c),
|
||||
keys(k),
|
||||
data(d) {}
|
||||
};
|
||||
|
||||
// --- Funciones ---
|
||||
auto loadDemoDataFromFile(const std::string& file_path) -> DemoData;
|
||||
|
||||
#ifdef RECORDING
|
||||
bool saveDemoFile(const std::string& file_path, const DemoData& dd);
|
||||
#endif
|
||||
@@ -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,10 +77,16 @@ 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(executable_path_ + "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
|
||||
Options::setConfigFile(Asset::get()->get("config_v2.txt")); // Establece el fichero de configuración
|
||||
Options::setControllersFile(Asset::get()->get("controllers.json")); // Establece el fichero de configuración de mandos
|
||||
Options::loadFromFile(); // Carga el archivo de configuración
|
||||
loadParams(); // Carga los parámetros del programa
|
||||
@@ -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");
|
||||
@@ -167,8 +174,14 @@ void Director::loadAssets() {
|
||||
|
||||
// Comprueba los parametros del programa
|
||||
void Director::checkProgramArguments(int argc, std::span<char *> argv) {
|
||||
// Establece la ruta del programa
|
||||
executable_path_ = getPath(argv[0]);
|
||||
// Obtener la ruta absoluta del ejecutable
|
||||
std::filesystem::path exe_path = std::filesystem::absolute(argv[0]);
|
||||
executable_path_ = exe_path.parent_path().string();
|
||||
|
||||
// Asegurar que termine con separador de directorio
|
||||
if (!executable_path_.empty() && executable_path_.back() != '/' && executable_path_.back() != '\\') {
|
||||
executable_path_ += "/";
|
||||
}
|
||||
|
||||
// Comprueba el resto de parámetros
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
|
||||
@@ -1,158 +1,116 @@
|
||||
#include "enter_name.h"
|
||||
|
||||
#include <cstddef> // Para size_t
|
||||
#include <array> // Para array
|
||||
#include <cstdlib> // Para rand
|
||||
#include <string_view> // Para basic_string_view, string_view
|
||||
|
||||
#include "utils.h" // Para trim
|
||||
|
||||
// Constructor
|
||||
EnterName::EnterName()
|
||||
: character_list_(" ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789."),
|
||||
character_index_{0} {}
|
||||
: character_list_("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789."),
|
||||
selected_index_(0) {}
|
||||
|
||||
// Inicializa el objeto
|
||||
void EnterName::init(const std::string &name) {
|
||||
// No se pasa ningún nombre
|
||||
if (name.empty()) {
|
||||
name_ = "A";
|
||||
position_ = 0;
|
||||
position_overflow_ = false;
|
||||
}
|
||||
// Se pasa un nombre
|
||||
else {
|
||||
name_ = name;
|
||||
position_ = name_.length();
|
||||
position_overflow_ = position_ >= NAME_SIZE;
|
||||
}
|
||||
|
||||
// Inicializa el vector de indices con el nombre y espacios
|
||||
initCharacterIndex(name_);
|
||||
name_ = sanitizeName(name);
|
||||
selected_index_ = 0;
|
||||
}
|
||||
|
||||
// Incrementa la posición
|
||||
void EnterName::incPosition() {
|
||||
if (position_overflow_) {
|
||||
// Si ya estamos en overflow, no incrementamos más.
|
||||
return;
|
||||
}
|
||||
|
||||
++position_;
|
||||
|
||||
if (position_ >= NAME_SIZE) {
|
||||
position_ = NAME_SIZE; // Mantenemos en el índice máximo válido.
|
||||
position_overflow_ = true; // Activamos el flag de overflow.
|
||||
} else if (position_ > 0) // No es necesario verificar position_ < MAX_NAME_LENGTH
|
||||
{
|
||||
// Copiamos el índice del carácter anterior si es posible.
|
||||
character_index_[position_] = character_index_[position_ - 1];
|
||||
} else {
|
||||
// Si position_ es 0, inicializamos el carácter actual.
|
||||
character_index_[position_] = 0;
|
||||
}
|
||||
|
||||
updateNameFromCharacterIndex();
|
||||
}
|
||||
|
||||
// Decrementa la posición
|
||||
void EnterName::decPosition() {
|
||||
if (position_overflow_) {
|
||||
// Si estaba en overflow, lo desactivamos y mantenemos position_ en el máximo.
|
||||
position_overflow_ = false;
|
||||
position_ = NAME_SIZE - 1;
|
||||
} else {
|
||||
if (position_ > 0) {
|
||||
--position_;
|
||||
|
||||
// Limpiamos el carácter siguiente si el índice es válido.
|
||||
if (position_ + 1 < NAME_SIZE) {
|
||||
character_index_[position_ + 1] = 0;
|
||||
}
|
||||
} else {
|
||||
// Si position_ es 0, aseguramos que no vaya a ser negativo y limpiamos el carácter actual.
|
||||
position_ = 0;
|
||||
// character_index_[position_] = 0;
|
||||
}
|
||||
|
||||
// Si position_ es menor que NAME_LENGTH, aseguramos que el overflow esté desactivado.
|
||||
if (position_ < NAME_SIZE) {
|
||||
position_overflow_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
updateNameFromCharacterIndex();
|
||||
}
|
||||
|
||||
// Incrementa el índice
|
||||
// Incrementa el índice del carácter seleccionado
|
||||
void EnterName::incIndex() {
|
||||
if (position_overflow_) {
|
||||
return;
|
||||
++selected_index_;
|
||||
if (selected_index_ >= static_cast<int>(character_list_.size())) {
|
||||
selected_index_ = 0;
|
||||
}
|
||||
|
||||
++character_index_[position_];
|
||||
if (character_index_[position_] >= static_cast<int>(character_list_.size())) {
|
||||
character_index_[position_] = 0;
|
||||
}
|
||||
updateNameFromCharacterIndex();
|
||||
}
|
||||
|
||||
// Decrementa el índice
|
||||
// Decrementa el índice del carácter seleccionado
|
||||
void EnterName::decIndex() {
|
||||
if (position_overflow_) {
|
||||
return;
|
||||
}
|
||||
|
||||
--character_index_[position_];
|
||||
if (character_index_[position_] < 0) {
|
||||
character_index_[position_] = character_list_.size() - 1;
|
||||
}
|
||||
updateNameFromCharacterIndex();
|
||||
}
|
||||
|
||||
// Actualiza el nombre a partir de la lista de índices
|
||||
void EnterName::updateNameFromCharacterIndex() {
|
||||
name_.clear();
|
||||
for (size_t i = 0; i < NAME_SIZE; ++i) {
|
||||
name_.push_back(character_list_[character_index_[i]]);
|
||||
}
|
||||
name_ = trim(name_);
|
||||
}
|
||||
|
||||
// Actualiza la variable
|
||||
void EnterName::initCharacterIndex(const std::string &name) {
|
||||
// Rellena de espacios
|
||||
for (size_t i = 0; i < NAME_SIZE; ++i) {
|
||||
character_index_[i] = 0;
|
||||
}
|
||||
|
||||
// Coloca los índices en función de los caracteres que forman el nombre
|
||||
for (size_t i = 0; i < name.substr(0, NAME_SIZE).size(); ++i) {
|
||||
character_index_[i] = findIndex(name.at(i));
|
||||
--selected_index_;
|
||||
if (selected_index_ < 0) {
|
||||
selected_index_ = character_list_.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Encuentra el indice de un caracter en "character_list_"
|
||||
auto EnterName::findIndex(char character) const -> int {
|
||||
for (size_t i = 0; i < character_list_.size(); ++i) {
|
||||
if (character == character_list_.at(i)) {
|
||||
return i;
|
||||
// Añade el carácter seleccionado al nombre
|
||||
void EnterName::addCharacter() {
|
||||
if (name_.length() < MAX_NAME_SIZE) {
|
||||
name_.push_back(character_list_[selected_index_]);
|
||||
}
|
||||
}
|
||||
|
||||
// Elimina el último carácter del nombre
|
||||
void EnterName::removeLastCharacter() {
|
||||
if (!name_.empty()) {
|
||||
name_.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
// Devuelve el carácter seleccionado con offset relativo como string
|
||||
auto EnterName::getSelectedCharacter(int offset) const -> std::string {
|
||||
// Calcular el índice con offset, con wrap-around circular
|
||||
int size = static_cast<int>(character_list_.size());
|
||||
int index = (selected_index_ + offset) % size;
|
||||
|
||||
// Manejar índices negativos (hacer wrap-around hacia atrás)
|
||||
if (index < 0) {
|
||||
index += size;
|
||||
}
|
||||
|
||||
return std::string(1, character_list_[index]);
|
||||
}
|
||||
|
||||
// Devuelve el carrusel completo de caracteres centrado en el seleccionado
|
||||
auto EnterName::getCarousel(int size) const -> std::string {
|
||||
// Asegurar que el tamaño sea impar para tener un centro claro
|
||||
if (size % 2 == 0) {
|
||||
++size;
|
||||
}
|
||||
|
||||
std::string carousel;
|
||||
carousel.reserve(size); // Optimización: reservar memoria de antemano
|
||||
|
||||
int half = size / 2;
|
||||
|
||||
// Construir desde -half hasta +half (inclusive)
|
||||
for (int offset = -half; offset <= half; ++offset) {
|
||||
carousel += getSelectedCharacter(offset);
|
||||
}
|
||||
|
||||
return carousel;
|
||||
}
|
||||
|
||||
// Valida y limpia el nombre: solo caracteres legales y longitud máxima
|
||||
auto EnterName::sanitizeName(const std::string &name) const -> std::string {
|
||||
std::string sanitized;
|
||||
|
||||
for (size_t i = 0; i < name.length() && sanitized.length() < MAX_NAME_SIZE; ++i) {
|
||||
// Verifica si el carácter está en la lista permitida
|
||||
if (character_list_.find(name[i]) != std::string::npos) {
|
||||
sanitized.push_back(name[i]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
// 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_));
|
||||
if (name.empty()) {
|
||||
name = getRandomName();
|
||||
if (name_.empty()) {
|
||||
name_ = getRandomName();
|
||||
}
|
||||
name_ = name;
|
||||
return name_;
|
||||
}
|
||||
|
||||
@@ -1,43 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <array> // Para array
|
||||
#include <cstddef> // Para size_t
|
||||
#include <string> // Para allocator, string
|
||||
|
||||
#include "utils.h" // Para trim
|
||||
|
||||
// --- Constantes ---
|
||||
constexpr size_t NAME_SIZE = 5; // Tamaño máximo del nombre
|
||||
|
||||
// --- Clase EnterName: gestor de entrada de nombre del jugador ---
|
||||
class EnterName {
|
||||
public:
|
||||
// --- Constantes ---
|
||||
static constexpr size_t MAX_NAME_SIZE = 6; // Tamaño máximo del nombre
|
||||
|
||||
EnterName();
|
||||
~EnterName() = default;
|
||||
|
||||
void init(const std::string &name = ""); // Inicializa con un nombre opcional
|
||||
void init(const std::string &name = ""); // Inicializa con nombre opcional (vacío por defecto)
|
||||
|
||||
void incPosition(); // Incrementa la posición del carácter actual
|
||||
void decPosition(); // Decrementa la posición del carácter actual
|
||||
void incIndex(); // Incrementa el índice del carácter en la lista
|
||||
void decIndex(); // Decrementa el índice del carácter en la lista
|
||||
void incIndex(); // Incrementa el índice del carácter seleccionado en la lista
|
||||
void decIndex(); // Decrementa el índice del carácter seleccionado en la lista
|
||||
|
||||
auto getFinalName() -> std::string; // Obtiene el nombre final introducido
|
||||
[[nodiscard]] auto getCurrentName() const -> std::string { return trim(name_); } // Obtiene el nombre actual en proceso
|
||||
void addCharacter(); // Añade el carácter seleccionado al nombre
|
||||
void removeLastCharacter(); // Elimina el último carácter del nombre
|
||||
|
||||
[[nodiscard]] auto getPosition() const -> int { return position_; } // Posición actual del carácter editado
|
||||
[[nodiscard]] auto getPositionOverflow() const -> bool { return position_overflow_; } // Indica si la posición excede el límite
|
||||
auto getFinalName() -> std::string; // Obtiene el nombre final (o aleatorio si vacío)
|
||||
[[nodiscard]] auto getCurrentName() const -> std::string { return name_; } // Obtiene el nombre actual en proceso
|
||||
[[nodiscard]] auto getSelectedCharacter(int offset = 0) const -> std::string; // Devuelve el carácter seleccionado con offset relativo
|
||||
[[nodiscard]] auto getCarousel(int size) const -> std::string; // Devuelve el carrusel de caracteres (size debe ser impar)
|
||||
[[nodiscard]] auto getSelectedIndex() const -> int { return selected_index_; } // Obtiene el índice del carácter seleccionado
|
||||
[[nodiscard]] auto getCharacterList() const -> const std::string& { return character_list_; } // Obtiene la lista completa de caracteres
|
||||
|
||||
private:
|
||||
// --- Variables de estado ---
|
||||
std::string character_list_; // Lista de caracteres permitidos
|
||||
std::string name_; // Nombre en proceso
|
||||
std::array<int, NAME_SIZE> character_index_; // Índices a "character_list_"
|
||||
size_t position_ = 0; // Índice del carácter que se edita
|
||||
bool position_overflow_ = false; // Flag para exceder límite
|
||||
std::string character_list_; // Lista de caracteres permitidos
|
||||
std::string name_; // Nombre en proceso
|
||||
int selected_index_ = 0; // Índice del carácter seleccionado en "character_list_"
|
||||
|
||||
void updateNameFromCharacterIndex(); // Actualiza "name_" según "character_index_"
|
||||
void initCharacterIndex(const std::string &name); // Inicializa índices desde el nombre
|
||||
[[nodiscard]] auto findIndex(char character) const -> int; // Busca el índice de un carácter en "character_list_"
|
||||
static auto getRandomName() -> std::string; // Devuelve un nombre al azar
|
||||
[[nodiscard]] auto sanitizeName(const std::string &name) const -> std::string; // Valida y limpia el nombre
|
||||
static auto getRandomName() -> std::string; // Devuelve un nombre al azar
|
||||
};
|
||||
@@ -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
|
||||
|
||||
415
source/external/jail_shader.cpp
vendored
@@ -1,415 +0,0 @@
|
||||
#include "jail_shader.h"
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_GL_GetProcAddress, SDL_LogError
|
||||
#include <stdint.h> // Para uintptr_t
|
||||
#include <cstring> // Para strncmp
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <vector> // Para vector
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <OpenGL/OpenGL.h> // Para OpenGL en macOS
|
||||
|
||||
#include "CoreFoundation/CoreFoundation.h" // Para Core Foundation en macOS
|
||||
#if ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
||||
#include <OpenGL/gl3.h> // Para OpenGL 3 en macOS
|
||||
#else // NO ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
||||
#include <OpenGL/gl.h> // Para OpenGL (compatibilidad) en macOS
|
||||
#endif // ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
||||
#else // SI NO ES __APPLE__
|
||||
#include <SDL3/SDL_opengl.h> // Para GLuint, GLint, glTexCoord2f, glVertex2f
|
||||
#endif // __APPLE__
|
||||
|
||||
namespace shader {
|
||||
// Constantes
|
||||
const GLuint INVALID_SHADER_ID = 0;
|
||||
const GLuint INVALID_PROGRAM_ID = 0;
|
||||
const GLuint DEFAULT_TEXTURE_ID = 1;
|
||||
|
||||
// Variables globales
|
||||
SDL_Window *win = nullptr;
|
||||
SDL_Renderer *renderer = nullptr;
|
||||
GLuint programId = 0;
|
||||
SDL_Texture *backBuffer = nullptr;
|
||||
SDL_Point win_size = {320 * 4, 256 * 4};
|
||||
SDL_FPoint tex_size = {320, 256};
|
||||
bool usingOpenGL = false;
|
||||
|
||||
#ifndef __APPLE__
|
||||
// Declaración de funciones de extensión de OpenGL (evitando GLEW)
|
||||
PFNGLCREATESHADERPROC glCreateShader;
|
||||
PFNGLSHADERSOURCEPROC glShaderSource;
|
||||
PFNGLCOMPILESHADERPROC glCompileShader;
|
||||
PFNGLGETSHADERIVPROC glGetShaderiv;
|
||||
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
|
||||
PFNGLDELETESHADERPROC glDeleteShader;
|
||||
PFNGLATTACHSHADERPROC glAttachShader;
|
||||
PFNGLCREATEPROGRAMPROC glCreateProgram;
|
||||
PFNGLLINKPROGRAMPROC glLinkProgram;
|
||||
PFNGLVALIDATEPROGRAMPROC glValidateProgram;
|
||||
PFNGLGETPROGRAMIVPROC glGetProgramiv;
|
||||
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
|
||||
PFNGLUSEPROGRAMPROC glUseProgram;
|
||||
PFNGLDELETEPROGRAMPROC glDeleteProgram;
|
||||
|
||||
bool initGLExtensions() {
|
||||
glCreateShader = (PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader");
|
||||
glShaderSource = (PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource");
|
||||
glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader");
|
||||
glGetShaderiv = (PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv");
|
||||
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog");
|
||||
glDeleteShader = (PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader");
|
||||
glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader");
|
||||
glCreateProgram = (PFNGLCREATEPROGRAMPROC)SDL_GL_GetProcAddress("glCreateProgram");
|
||||
glLinkProgram = (PFNGLLINKPROGRAMPROC)SDL_GL_GetProcAddress("glLinkProgram");
|
||||
glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)SDL_GL_GetProcAddress("glValidateProgram");
|
||||
glGetProgramiv = (PFNGLGETPROGRAMIVPROC)SDL_GL_GetProcAddress("glGetProgramiv");
|
||||
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)SDL_GL_GetProcAddress("glGetProgramInfoLog");
|
||||
glUseProgram = (PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram");
|
||||
glDeleteProgram = (PFNGLDELETEPROGRAMPROC)SDL_GL_GetProcAddress("glDeleteProgram");
|
||||
|
||||
return glCreateShader && glShaderSource && glCompileShader && glGetShaderiv &&
|
||||
glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram &&
|
||||
glLinkProgram && glValidateProgram && glGetProgramiv && glGetProgramInfoLog &&
|
||||
glUseProgram && glDeleteProgram;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Función para verificar errores de OpenGL
|
||||
void checkGLError(const char *operation) {
|
||||
GLenum error = glGetError();
|
||||
if (error != GL_NO_ERROR) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Error OpenGL en %s: 0x%x",
|
||||
operation,
|
||||
error);
|
||||
}
|
||||
}
|
||||
|
||||
// Función para compilar un shader a partir de un std::string
|
||||
GLuint compileShader(const std::string &source, GLuint shader_type) {
|
||||
if (source.empty()) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR FATAL: El código fuente del shader está vacío.");
|
||||
throw std::runtime_error("ERROR FATAL: El código fuente del shader está vacío.");
|
||||
}
|
||||
|
||||
// Crear identificador del shader
|
||||
GLuint shader_id = glCreateShader(shader_type);
|
||||
if (shader_id == INVALID_SHADER_ID) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al crear el shader.");
|
||||
checkGLError("glCreateShader");
|
||||
return INVALID_SHADER_ID;
|
||||
}
|
||||
|
||||
// Agregar una directiva según el tipo de shader
|
||||
std::string directive = (shader_type == GL_VERTEX_SHADER)
|
||||
? "#define VERTEX\n"
|
||||
: "#define FRAGMENT\n";
|
||||
|
||||
const char *sources[2] = {directive.c_str(), source.c_str()};
|
||||
|
||||
// Especificar el código fuente del shader
|
||||
glShaderSource(shader_id, 2, sources, nullptr);
|
||||
checkGLError("glShaderSource");
|
||||
|
||||
// Compilar el shader
|
||||
glCompileShader(shader_id);
|
||||
checkGLError("glCompileShader");
|
||||
|
||||
// Verificar si la compilación fue exitosa
|
||||
GLint compiled_ok = GL_FALSE;
|
||||
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &compiled_ok);
|
||||
if (compiled_ok != GL_TRUE) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error en la compilación del shader (%d)!", shader_id);
|
||||
GLint log_length;
|
||||
glGetShaderiv(shader_id, GL_INFO_LOG_LENGTH, &log_length);
|
||||
if (log_length > 0) {
|
||||
std::vector<GLchar> log(log_length);
|
||||
glGetShaderInfoLog(shader_id, log_length, &log_length, log.data());
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Registro de compilación del shader: %s", log.data());
|
||||
}
|
||||
glDeleteShader(shader_id);
|
||||
return INVALID_SHADER_ID;
|
||||
}
|
||||
return shader_id;
|
||||
}
|
||||
|
||||
// Función para compilar un programa de shaders (vertex y fragment) a partir de std::string
|
||||
GLuint compileProgram(const std::string &vertex_shader_source, const std::string &fragment_shader_source) {
|
||||
GLuint program_id = glCreateProgram();
|
||||
if (program_id == INVALID_PROGRAM_ID) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al crear el programa de shaders.");
|
||||
checkGLError("glCreateProgram");
|
||||
return INVALID_PROGRAM_ID;
|
||||
}
|
||||
|
||||
// Si el fragment shader está vacío, reutilizamos el código del vertex shader
|
||||
GLuint vertex_shader_id = compileShader(vertex_shader_source, GL_VERTEX_SHADER);
|
||||
GLuint fragment_shader_id = compileShader(fragment_shader_source.empty() ? vertex_shader_source : fragment_shader_source, GL_FRAGMENT_SHADER);
|
||||
|
||||
if (vertex_shader_id != INVALID_SHADER_ID && fragment_shader_id != INVALID_SHADER_ID) {
|
||||
// Asociar los shaders al programa
|
||||
glAttachShader(program_id, vertex_shader_id);
|
||||
checkGLError("glAttachShader vertex");
|
||||
glAttachShader(program_id, fragment_shader_id);
|
||||
checkGLError("glAttachShader fragment");
|
||||
|
||||
glLinkProgram(program_id);
|
||||
checkGLError("glLinkProgram");
|
||||
|
||||
// Verificar el estado del enlace
|
||||
GLint isLinked = GL_FALSE;
|
||||
glGetProgramiv(program_id, GL_LINK_STATUS, &isLinked);
|
||||
if (isLinked == GL_FALSE) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error al enlazar el programa de shaders.");
|
||||
GLint log_length;
|
||||
glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &log_length);
|
||||
if (log_length > 0) {
|
||||
std::vector<char> log(log_length);
|
||||
glGetProgramInfoLog(program_id, log_length, &log_length, log.data());
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Registro de enlace del programa: %s", log.data());
|
||||
}
|
||||
glDeleteProgram(program_id);
|
||||
program_id = INVALID_PROGRAM_ID;
|
||||
} else {
|
||||
glValidateProgram(program_id);
|
||||
checkGLError("glValidateProgram");
|
||||
|
||||
// Log de información del programa (solo si hay información)
|
||||
GLint log_length;
|
||||
glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &log_length);
|
||||
if (log_length > 1) // > 1 porque algunos drivers devuelven 1 para cadena vacía
|
||||
{
|
||||
std::vector<char> log(log_length);
|
||||
glGetProgramInfoLog(program_id, log_length, &log_length, log.data());
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Registro de información del programa:\n%s", log.data());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudieron compilar los shaders.");
|
||||
glDeleteProgram(program_id);
|
||||
program_id = INVALID_PROGRAM_ID;
|
||||
}
|
||||
|
||||
// Limpiar los shaders (ya no son necesarios después del enlace)
|
||||
if (vertex_shader_id != INVALID_SHADER_ID) {
|
||||
glDeleteShader(vertex_shader_id);
|
||||
}
|
||||
if (fragment_shader_id != INVALID_SHADER_ID) {
|
||||
glDeleteShader(fragment_shader_id);
|
||||
}
|
||||
|
||||
return program_id;
|
||||
}
|
||||
|
||||
// Función para obtener el ID de textura OpenGL desde SDL3
|
||||
GLuint getTextureID(SDL_Texture *texture) {
|
||||
if (!texture)
|
||||
return DEFAULT_TEXTURE_ID;
|
||||
|
||||
// Intentar obtener el ID de textura OpenGL desde las propiedades de SDL3
|
||||
SDL_PropertiesID props = SDL_GetTextureProperties(texture);
|
||||
GLuint textureId = 0;
|
||||
|
||||
// Intentar diferentes nombres de propiedades según la versión de SDL3
|
||||
textureId = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "SDL.texture.opengl.texture", nullptr);
|
||||
|
||||
// Si la primera no funciona, intentar con el nombre alternativo
|
||||
if (textureId == 0) {
|
||||
textureId = (GLuint)(uintptr_t)SDL_GetPointerProperty(props, "texture.opengl.texture", nullptr);
|
||||
}
|
||||
|
||||
// Si aún no funciona, intentar obtener como número
|
||||
if (textureId == 0) {
|
||||
textureId = (GLuint)SDL_GetNumberProperty(props, "SDL.texture.opengl.texture", DEFAULT_TEXTURE_ID);
|
||||
}
|
||||
|
||||
// Si ninguna funciona, usar el método manual de bindeo de textura
|
||||
if (textureId == 0) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"No se pudo obtener el ID de textura OpenGL, usando ID por defecto (%d)",
|
||||
DEFAULT_TEXTURE_ID);
|
||||
textureId = DEFAULT_TEXTURE_ID;
|
||||
}
|
||||
|
||||
return textureId;
|
||||
}
|
||||
|
||||
bool init(SDL_Window *window, SDL_Texture *back_buffer_texture, const std::string &vertex_shader, const std::string &fragment_shader) {
|
||||
shader::win = window;
|
||||
shader::renderer = SDL_GetRenderer(window);
|
||||
shader::backBuffer = back_buffer_texture;
|
||||
|
||||
if (!shader::renderer) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo obtener el renderer de la ventana.");
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_GetWindowSize(window, &win_size.x, &win_size.y);
|
||||
SDL_GetTextureSize(back_buffer_texture, &tex_size.x, &tex_size.y);
|
||||
|
||||
const auto render_name = SDL_GetRendererName(renderer);
|
||||
if (!render_name) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error: No se pudo obtener el nombre del renderer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verificar que el renderer sea OpenGL
|
||||
if (!strncmp(render_name, "opengl", 6)) {
|
||||
#ifndef __APPLE__
|
||||
if (!initGLExtensions()) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR: No se han podido inicializar las extensiones de OpenGL.");
|
||||
usingOpenGL = false;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
// Compilar el programa de shaders utilizando std::string
|
||||
programId = compileProgram(vertex_shader, fragment_shader);
|
||||
if (programId == INVALID_PROGRAM_ID) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "ERROR: No se pudo compilar el programa de shaders.");
|
||||
usingOpenGL = false;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "ADVERTENCIA: El driver del renderer no es OpenGL (%s).", render_name);
|
||||
usingOpenGL = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
usingOpenGL = true;
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "** Shader system initialized successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
void render() {
|
||||
// Establece el color de fondo
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||
SDL_SetRenderTarget(renderer, nullptr);
|
||||
SDL_RenderClear(renderer);
|
||||
|
||||
if (usingOpenGL && programId != INVALID_PROGRAM_ID) {
|
||||
// Guardar estados de OpenGL
|
||||
GLint oldProgramId;
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgramId);
|
||||
|
||||
GLint oldViewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, oldViewport);
|
||||
|
||||
GLboolean wasTextureEnabled = glIsEnabled(GL_TEXTURE_2D);
|
||||
GLint oldTextureId;
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &oldTextureId);
|
||||
|
||||
// Obtener y bindear la textura
|
||||
GLuint textureId = getTextureID(backBuffer);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, textureId);
|
||||
checkGLError("glBindTexture");
|
||||
|
||||
// Usar nuestro programa de shaders
|
||||
glUseProgram(programId);
|
||||
checkGLError("glUseProgram");
|
||||
|
||||
// Recupera el tamaño lógico configurado con SDL_RenderSetLogicalSize
|
||||
int logicalW, logicalH;
|
||||
SDL_RendererLogicalPresentation mode;
|
||||
SDL_GetRenderLogicalPresentation(renderer, &logicalW, &logicalH, &mode);
|
||||
if (logicalW == 0 || logicalH == 0) {
|
||||
logicalW = win_size.x;
|
||||
logicalH = win_size.y;
|
||||
}
|
||||
|
||||
// Cálculo del viewport
|
||||
int viewportX = 0, viewportY = 0, viewportW = win_size.x, viewportH = win_size.y;
|
||||
const bool USE_INTEGER_SCALE = mode == SDL_LOGICAL_PRESENTATION_INTEGER_SCALE;
|
||||
if (USE_INTEGER_SCALE) {
|
||||
// Calcula el factor de escalado entero máximo que se puede aplicar
|
||||
int scaleX = win_size.x / logicalW;
|
||||
int scaleY = win_size.y / logicalH;
|
||||
int scale = (scaleX < scaleY ? scaleX : scaleY);
|
||||
if (scale < 1) {
|
||||
scale = 1;
|
||||
}
|
||||
viewportW = logicalW * scale;
|
||||
viewportH = logicalH * scale;
|
||||
viewportX = (win_size.x - viewportW) / 2;
|
||||
viewportY = (win_size.y - viewportH) / 2;
|
||||
} else {
|
||||
// Letterboxing: preserva la relación de aspecto usando una escala flotante
|
||||
float windowAspect = static_cast<float>(win_size.x) / win_size.y;
|
||||
float logicalAspect = static_cast<float>(logicalW) / logicalH;
|
||||
if (windowAspect > logicalAspect) {
|
||||
viewportW = static_cast<int>(logicalAspect * win_size.y);
|
||||
viewportX = (win_size.x - viewportW) / 2;
|
||||
} else {
|
||||
viewportH = static_cast<int>(win_size.x / logicalAspect);
|
||||
viewportY = (win_size.y - viewportH) / 2;
|
||||
}
|
||||
}
|
||||
glViewport(viewportX, viewportY, viewportW, viewportH);
|
||||
checkGLError("glViewport");
|
||||
|
||||
// Configurar la proyección ortográfica usando el espacio lógico
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
// Queremos que el origen esté en la esquina superior izquierda del espacio lógico.
|
||||
glOrtho(0, static_cast<GLdouble>(logicalW), static_cast<GLdouble>(logicalH), 0, -1, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
// Dibuja el quad con las coordenadas ajustadas.
|
||||
// Se asignan las coordenadas de textura "normales" para que no quede espejado horizontalmente,
|
||||
// y se mantiene el flip vertical para que la imagen no aparezca volteada.
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
// Vértice superior izquierdo
|
||||
glTexCoord2f(0.0f, 1.0f);
|
||||
glVertex2f(0.0f, 0.0f);
|
||||
// Vértice superior derecho
|
||||
glTexCoord2f(1.0f, 1.0f);
|
||||
glVertex2f(static_cast<GLfloat>(logicalW), 0.0f);
|
||||
// Vértice inferior izquierdo
|
||||
glTexCoord2f(0.0f, 0.0f);
|
||||
glVertex2f(0.0f, static_cast<GLfloat>(logicalH));
|
||||
// Vértice inferior derecho
|
||||
glTexCoord2f(1.0f, 0.0f);
|
||||
glVertex2f(static_cast<GLfloat>(logicalW), static_cast<GLfloat>(logicalH));
|
||||
glEnd();
|
||||
checkGLError("render quad");
|
||||
|
||||
SDL_GL_SwapWindow(win);
|
||||
|
||||
// Restaurar estados de OpenGL
|
||||
glUseProgram(oldProgramId);
|
||||
glBindTexture(GL_TEXTURE_2D, oldTextureId);
|
||||
if (!wasTextureEnabled) {
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
glViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
|
||||
} else {
|
||||
// Fallback a renderizado normal de SDL
|
||||
SDL_RenderTexture(renderer, backBuffer, nullptr, nullptr);
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
if (programId != INVALID_PROGRAM_ID) {
|
||||
glDeleteProgram(programId);
|
||||
programId = INVALID_PROGRAM_ID;
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Programa de shaders liberado.");
|
||||
}
|
||||
|
||||
// Reinicializar variables
|
||||
win = nullptr;
|
||||
renderer = nullptr;
|
||||
backBuffer = nullptr;
|
||||
usingOpenGL = false;
|
||||
}
|
||||
|
||||
bool isUsingOpenGL() {
|
||||
return usingOpenGL;
|
||||
}
|
||||
|
||||
GLuint getProgramId() {
|
||||
return programId;
|
||||
}
|
||||
} // namespace shader
|
||||
9
source/external/jail_shader.h
vendored
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_Texture, SDL_Window
|
||||
#include <string> // Para basic_string, string
|
||||
|
||||
namespace shader {
|
||||
bool init(SDL_Window *ventana, SDL_Texture *texturaBackBuffer, const std::string &vertexShader, const std::string &fragmentShader = "");
|
||||
void render();
|
||||
} // namespace shader
|
||||
@@ -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
|
||||
};
|
||||