23 Commits

Author SHA1 Message Date
40dfc32e84 Actualitzada la data de la versió 2024-12-31 10:23:01 +01:00
4cd1d91560 Actualitzat jail_audio 2024-12-30 20:08:08 +01:00
e43badd703 Merge branch 'main' of https://gitea.sustancia.synology.me/JailDesigner/coffee_crisis_arcade_edition 2024-12-30 20:06:04 +01:00
71dcf9cf87 Afegit coffee.res, coffee.rc i icon.ico per a tindre iconet en windows 2024-12-30 19:56:35 +01:00
3a8521a1da Arreglat windows_release en Makefile 2024-12-30 19:56:00 +01:00
74d9c9a2b9 Commit per a vore qué està passant amb la música 2024-12-30 19:07:13 +01:00
9532caace8 Arreglades les release de windows, linux i raspberry 2024-12-30 13:44:09 +01:00
0bbd14067a Text::writeToTexture no deixava el renderitzador com estava 2024-12-30 13:43:12 +01:00
cfaa143c44 Actualitzat jail_audio 2024-12-30 13:30:06 +01:00
e61daeb92e Modificats els grafics del enemic nou
Afegits nous audios i veus
Completat el comportament del enemic nou
Ampliat el numero máxim de sons simultanis
2024-12-28 21:23:04 +01:00
d57cc15aee Treballant en el enemic nou 2024-12-27 13:38:07 +01:00
de3b18a407 Posat ordre en el Attract Mode 2024-12-26 13:58:25 +01:00
7f444fef33 Fix: mil minibugs relacionats amb el audio 2024-12-26 10:39:48 +01:00
ca18baefd7 Fix: el modo demo desactivava els sons i ja no s'activaven mai mes 2024-12-26 10:05:41 +01:00
b8dca0a46f Fet el fade out del title de video i audio i el fade in del joc de video i audio
Actualitzat jail_audio a la última versió
2024-12-26 10:03:02 +01:00
ca2c48ea17 Au, paca casa. M'he quedat a mitjes fent un fade de audio sincronitzat amb el fade de video en el titol 2024-12-23 13:56:11 +01:00
fb4d0d12db Afegits roidets de colisió per als globos per a certs moments 2024-12-23 12:37:19 +01:00
fb31445731 Comprova al iniciar que el tamany de finestra no siga mes gran que el tamany de la pantalla 2024-12-23 11:22:26 +01:00
cf4f0459b3 Es pot fer la finestra tan gran com deixe la pantalla, es a dir, el factor de zoom ja no va de 1 a 4 sino de 1 a X 2024-12-23 11:13:14 +01:00
fe0900a686 Afegides veus al jugador
Afegit efectes de so al rebotar el jugador quan mor
2024-12-15 20:00:35 +01:00
3367b70cd5 Afegit delay opcional al flash de la classe Screen 2024-12-09 20:06:59 +01:00
7016849587 FIX: afegit StopChannel en lloc de PauseChannel en el destructor del Logo
Retocada la animació del logo del joc en Title
2024-12-09 19:08:22 +01:00
301c059a26 Afegit botó per activar o desactivar el autofire 2024-12-05 12:24:18 +01:00
45 changed files with 980 additions and 483 deletions

3
.gitignore vendored
View File

@@ -15,4 +15,5 @@ thumbs.db
*score.bin *score.bin
coffee_crisis* coffee_crisis*
debug.txt debug.txt
cppcheck-result* cppcheck-result*
desktop.ini

156
Makefile
View File

@@ -1,59 +1,63 @@
# Directorios # Directorios
DIR_ROOT := $(dir $(abspath $(MAKEFILE_LIST))) DIR_ROOT := $(dir $(abspath $(MAKEFILE_LIST)))
DIR_SOURCES:= $(addsuffix /, $(DIR_ROOT)source) DIR_SOURCES := $(addsuffix /, $(DIR_ROOT)source)
DIR_BIN := $(addsuffix /, $(DIR_ROOT)) DIR_BIN := $(addsuffix /, $(DIR_ROOT))
DIR_BUILD := $(addsuffix /, $(DIR_ROOT)build) DIR_BUILD := $(addsuffix /, $(DIR_ROOT)build)
# Variables # Variables
TARGET_NAME := coffee_crisis_arcade_edition TARGET_NAME := coffee_crisis_arcade_edition
TARGET_FILE := $(DIR_BIN)$(TARGET_NAME) TARGET_FILE := $(DIR_BIN)$(TARGET_NAME)
APP_NAME := Coffee Crisis Arcade Edition APP_NAME := Coffee Crisis Arcade Edition
RELEASE_FOLDER:= ccae_release RELEASE_FOLDER := ccae_release
RELEASE_FILE := $(RELEASE_FOLDER)/$(TARGET_NAME) RELEASE_FILE := $(RELEASE_FOLDER)/$(TARGET_NAME)
VERSION := v0.01 RESOURCE_FILE := release/coffee.res
VERSION := 2024-12-31
# Nombres para los ficheros de lanzamiento # Nombres para los ficheros de lanzamiento
WINDOWS_RELEASE := $(TARGET_FILE)-$(VERSION)-win32-x64.zip WINDOWS_RELEASE := $(TARGET_NAME)-$(VERSION)-win32-x64.zip
MACOS_INTEL_RELEASE := $(TARGET_FILE)-$(VERSION)-macos-intel.dmg MACOS_INTEL_RELEASE := $(TARGET_FILE)-$(VERSION)-macos-intel.dmg
MACOS_APPLE_SILICON_RELEASE:= $(TARGET_FILE)-$(VERSION)-macos-apple-silicon.dmg MACOS_APPLE_SILICON_RELEASE := $(TARGET_FILE)-$(VERSION)-macos-apple-silicon.dmg
LINUX_RELEASE := $(TARGET_FILE)-$(VERSION)-linux.tar.gz LINUX_RELEASE := $(TARGET_FILE)-$(VERSION)-linux.tar.gz
RASPI_RELEASE := $(TARGET_FILE)-$(VERSION)-raspberry.tar.gz
# Includes # Includes
INCLUDES:= -I$(DIR_SOURCES) INCLUDES := -I$(DIR_SOURCES)
# Variables según el sistema operativo # Variables según el sistema operativo
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
FixPath = $(subst /,\,$1) FixPath = $(subst /,\\,$1)
SOURCES := source/*.cpp SOURCES := source/*.cpp
CXXFLAGS:= -std=c++20 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows CXXFLAGS := -std=c++20 -Wall -Os -ffunction-sections -fdata-sections -Wl,--gc-sections -static-libstdc++ -Wl,-subsystem,windows
CXXFLAGS_DEBUG:= -std=c++20 -Wall -g CXXFLAGS_DEBUG := -std=c++20 -Wall -g
LDFLAGS := -lmingw32 -lws2_32 -lSDL2main -lSDL2 -lopengl32 LDFLAGS := -lmingw32 -lws2_32 -lSDL2main -lSDL2 -lopengl32
RM = del /Q RM := del /Q
MKD:= mkdir MKDIR := mkdir
else else
FixPath = $1 FixPath = $1
SOURCES := $(shell find $(DIR_SOURCES) -name '*.cpp') SOURCES := $(shell find $(DIR_SOURCES) -name '*.cpp')
SOURCES := source/*.cpp SOURCES := source/*.cpp
CXXFLAGS:= -std=c++20 -Wall -Os -ffunction-sections -fdata-sections CXXFLAGS := -std=c++20 -Wall -Os -ffunction-sections -fdata-sections
CXXFLAGS_DEBUG:= -std=c++20 -Wall -g CXXFLAGS_DEBUG := -std=c++20 -Wall -g
LDFLAGS := -lSDL2 LDFLAGS := -lSDL2
RM = rm -f RMFILE := rm -f
MKD:= mkdir -p RMDIR := rm -rdf
UNAME_S := $(shell uname -s) MKDIR := mkdir -p
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux) ifeq ($(UNAME_S),Linux)
LDFLAGS += -lGL LDFLAGS += -lGL
endif endif
ifeq ($(UNAME_S),Darwin) ifeq ($(UNAME_S),Darwin)
CXXFLAGS += -Wno-deprecated CXXFLAGS += -Wno-deprecated
CXXFLAGS_DEBUG += -Wno-deprecated CXXFLAGS_DEBUG += -Wno-deprecated
LDFLAGS += -framework OpenGL LDFLAGS += -framework OpenGL
endif endif
endif endif
# Rules # Reglas para compilación
windows: windows:
@echo off @echo off
$(CXX) $(SOURCES) $(CXXFLAGS) $(LDFLAGS) -o "$(TARGET_FILE).exe" windres release/coffee.rc -O coff -o $(RESOURCE_FILE)
$(CXX) $(SOURCES) $(RESOURCE_FILE) $(CXXFLAGS) $(LDFLAGS) -o "$(TARGET_FILE).exe"
strip -s -R .comment -R .gnu.version "$(TARGET_FILE).exe" --strip-unneeded strip -s -R .comment -R .gnu.version "$(TARGET_FILE).exe" --strip-unneeded
windows_rec: windows_rec:
@@ -80,12 +84,13 @@ windows_release:
powershell Copy-Item "release\*.dll" -Destination "$(RELEASE_FOLDER)" powershell Copy-Item "release\*.dll" -Destination "$(RELEASE_FOLDER)"
# Compila # Compila
$(CXX) $(SOURCES) $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FILE).exe" windres release/coffee.rc -O coff -o $(RESOURCE_FILE)
strip -s -R .comment -R .gnu.version "$(RELEASE_FOLDER)/$(TARGET_FILE).exe" --strip-unneeded $(CXX) $(SOURCES) $(RESOURCE_FILE) $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FILE).exe"
strip -s -R .comment -R .gnu.version "$(RELEASE_FILE).exe" --strip-unneeded
# Crea el fichero .zip # Crea el fichero .zip
powershell if (Test-Path $(WINDOWS_RELEASE)) {Remove-Item $(WINDOWS_RELEASE)} powershell if (Test-Path "$(WINDOWS_RELEASE)") {Remove-Item "$(WINDOWS_RELEASE)"}
powershell Compress-Archive -Path "$(RELEASE_FOLDER)"/* -DestinationPath $(WINDOWS_RELEASE) powershell Compress-Archive -Path "$(RELEASE_FOLDER)"/* -DestinationPath "$(WINDOWS_RELEASE)"
# Elimina la carpeta temporal 'RELEASE_FOLDER' # Elimina la carpeta temporal 'RELEASE_FOLDER'
powershell if (Test-Path "$(RELEASE_FOLDER)") {Remove-Item "$(RELEASE_FOLDER)" -Recurse -Force} powershell if (Test-Path "$(RELEASE_FOLDER)") {Remove-Item "$(RELEASE_FOLDER)" -Recurse -Force}
@@ -98,17 +103,17 @@ macos_debug:
macos_release: macos_release:
# Elimina datos de compilaciones anteriores # Elimina datos de compilaciones anteriores
rm -rdf "$(RELEASE_FOLDER)" $(RMDIR) "$(RELEASE_FOLDER)"
rm -rdf Frameworks $(RMDIR) Frameworks
rm -f tmp.dmg $(RMFILE) tmp.dmg
rm -f "$(MACOS_INTEL_RELEASE)" $(RMFILE) "$(MACOS_INTEL_RELEASE)"
rm -f "$(MACOS_APPLE_SILICON_RELEASE)" $(RMFILE) "$(MACOS_APPLE_SILICON_RELEASE)"
# Crea la carpeta temporal para hacer el trabajo y las carpetas obligatorias para crear una app de macos # Crea la carpeta temporal para hacer el trabajo y las carpetas obligatorias para crear una app de macos
mkdir -p "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks" $(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Frameworks"
mkdir -p "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS" $(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS"
mkdir -p "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources" $(MKDIR) "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
mkdir -p Frameworks $(MKDIR) Frameworks
# Copia carpetas y ficheros # Copia carpetas y ficheros
cp -R data "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources" cp -R data "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/Resources"
@@ -123,24 +128,24 @@ macos_release:
ln -s /Applications "$(RELEASE_FOLDER)"/Applications ln -s /Applications "$(RELEASE_FOLDER)"/Applications
# Compila la versión para procesadores Intel # Compila la versión para procesadores Intel
$(CXX) $(SOURCES) -D MACOS_BUNDLE $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_FILE)" -rpath @executable_path/../Frameworks/ -target x86_64-apple-macos10.12 $(CXX) $(SOURCES) -D MACOS_BUNDLE $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)" -rpath @executable_path/../Frameworks/ -target x86_64-apple-macos10.12
# Empaqueta el .dmg de la versión Intel # Empaqueta el .dmg de la versión Intel
hdiutil create tmp.dmg -ov -volname "$(APP_NAME)" -fs HFS+ -srcfolder "$(RELEASE_FOLDER)" hdiutil create tmp.dmg -ov -volname "$(APP_NAME)" -fs HFS+ -srcfolder "$(RELEASE_FOLDER)"
hdiutil convert tmp.dmg -format UDZO -o "$(MACOS_INTEL_RELEASE)" hdiutil convert tmp.dmg -format UDZO -o "$(MACOS_INTEL_RELEASE)"
rm -f tmp.dmg $(RMFILE) tmp.dmg
# Compila la versión para procesadores Apple Silicon # Compila la versión para procesadores Apple Silicon
$(CXX) $(SOURCES) -D MACOS_BUNDLE $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_FILE)" -rpath @executable_path/../Frameworks/ -target arm64-apple-macos11 $(CXX) $(SOURCES) -D MACOS_BUNDLE -D SDL_DISABLE_IMMINTRIN_H $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FOLDER)/$(APP_NAME).app/Contents/MacOS/$(TARGET_NAME)" -rpath @executable_path/../Frameworks/ -target arm64-apple-macos11
# Empaqueta el .dmg de la versión Apple Silicon # Empaqueta el .dmg de la versión Apple Silicon
hdiutil create tmp.dmg -ov -volname "$(APP_NAME)" -fs HFS+ -srcfolder "$(RELEASE_FOLDER)" hdiutil create tmp.dmg -ov -volname "$(APP_NAME)" -fs HFS+ -srcfolder "$(RELEASE_FOLDER)"
hdiutil convert tmp.dmg -format UDZO -o "$(MACOS_APPLE_SILICON_RELEASE)" hdiutil convert tmp.dmg -format UDZO -o "$(MACOS_APPLE_SILICON_RELEASE)"
rm -f tmp.dmg $(RMFILE) tmp.dmg
# Elimina las carpetas temporales # Elimina las carpetas temporales
$(RM) Frameworks $(RMDIR) Frameworks
$(RM) "$(RELEASE_FOLDER)" $(RMDIR) "$(RELEASE_FOLDER)"
linux: linux:
$(CXX) $(SOURCES) $(CXXFLAGS) $(LDFLAGS) -o "$(TARGET_FILE)" $(CXX) $(SOURCES) $(CXXFLAGS) $(LDFLAGS) -o "$(TARGET_FILE)"
@@ -151,10 +156,10 @@ linux_debug:
linux_release: linux_release:
# Elimina carpetas previas # Elimina carpetas previas
$(RM) "$(RELEASE_FOLDER)" $(RMDIR) "$(RELEASE_FOLDER)"
# Crea la carpeta temporal para realizar el lanzamiento # Crea la carpeta temporal para realizar el lanzamiento
mkdir -p "$(RELEASE_FOLDER)" $(MKDIR) "$(RELEASE_FOLDER)"
# Copia ficheros # Copia ficheros
cp -R data "$(RELEASE_FOLDER)" cp -R data "$(RELEASE_FOLDER)"
@@ -166,11 +171,11 @@ linux_release:
strip -s -R .comment -R .gnu.version "$(RELEASE_FILE)" --strip-unneeded strip -s -R .comment -R .gnu.version "$(RELEASE_FILE)" --strip-unneeded
# Empaqueta ficheros # Empaqueta ficheros
$(RM) "$(LINUX_RELEASE)" $(RMFILE) "$(LINUX_RELEASE)"
cd "$(RELEASE_FOLDER)" && tar -czvf "../$(LINUX_RELEASE)" * cd "$(RELEASE_FOLDER)" && tar -czvf "$(LINUX_RELEASE)" *
# Elimina la carpeta temporal # Elimina la carpeta temporal
$(RM) "$(RELEASE_FOLDER)" $(RMDIR) "$(RELEASE_FOLDER)"
raspi: raspi:
$(CXX) $(SOURCES) -D ARCADE -D VERBOSE $(CXXFLAGS) $(LDFLAGS) -o $(TARGET_FILE) $(CXX) $(SOURCES) -D ARCADE -D VERBOSE $(CXXFLAGS) $(LDFLAGS) -o $(TARGET_FILE)
@@ -179,12 +184,35 @@ raspi:
raspi_debug: raspi_debug:
$(CXX) $(SOURCES) -D ARCADE -D VERBOSE -D DEBUG $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug" $(CXX) $(SOURCES) -D ARCADE -D VERBOSE -D DEBUG $(CXXFLAGS_DEBUG) $(LDFLAGS) -o "$(TARGET_FILE)_debug"
anbernic: raspi_release:
# Elimina carpetas previas # Elimina carpetas previas
$(RM) "$(RELEASE_FOLDER)"_anbernic $(RMDIR) "$(RELEASE_FOLDER)"
# Crea la carpeta temporal para realizar el lanzamiento # Crea la carpeta temporal para realizar el lanzamiento
mkdir -p "$(RELEASE_FOLDER)"_anbernic $(MKDIR) "$(RELEASE_FOLDER)"
# Copia ficheros
cp -R data "$(RELEASE_FOLDER)"
cp LICENSE "$(RELEASE_FOLDER)"
cp README.md "$(RELEASE_FOLDER)"
# Complia
$(CXX) $(SOURCES) -D ARCADE -D VERBOSE $(CXXFLAGS) $(LDFLAGS) -o "$(RELEASE_FILE)"
strip -s -R .comment -R .gnu.version "$(RELEASE_FILE)" --strip-unneeded
# Empaqueta ficheros
$(RMFILE) "$(LINUX_RELEASE)"
cd "$(RELEASE_FOLDER)" && tar -czvf "$(RASPI_RELEASE)" *
# Elimina la carpeta temporal
$(RMDIR) "$(RELEASE_FOLDER)"
anbernic:
# Elimina carpetas previas
$(RMDIR) "$(RELEASE_FOLDER)"_anbernic
# Crea la carpeta temporal para realizar el lanzamiento
$(MKDIR) "$(RELEASE_FOLDER)"_anbernic
# Copia ficheros # Copia ficheros
cp -R data "$(RELEASE_FOLDER)"_anbernic cp -R data "$(RELEASE_FOLDER)"_anbernic

View File

@@ -30,7 +30,9 @@ Les tecles son les següents:
- **Tecla F5**: Activa o desactiva l'audio - **Tecla F5**: Activa o desactiva l'audio
- **Tecla F6**: Canvia el idioma del joc i reinicia - **Tecla F6**: Activa o desactiva el dispar automàtic
- **Tecla F7**: Canvia el idioma del joc i reinicia
- **Tecla F10**: Reset - **Tecla F10**: Reset

View File

@@ -14,7 +14,7 @@ fade.num_squares_height 120
fade.random_squares_delay 1 fade.random_squares_delay 1
fade.random_squares_mult 500 fade.random_squares_mult 500
fade.post_duration 80 fade.post_duration 80
fade.venetian_size 16 fade.venetian_size 12
## SCOREBOARD ## SCOREBOARD
scoreboard.x 0 scoreboard.x 0

View File

@@ -14,7 +14,7 @@ fade.num_squares_height 128
fade.random_squares_delay 1 fade.random_squares_delay 1
fade.random_squares_mult 500 fade.random_squares_mult 500
fade.post_duration 80 fade.post_duration 80
fade.venetian_size 16 fade.venetian_size 12
## SCOREBOARD ## SCOREBOARD
scoreboard.x 0 scoreboard.x 0

9
data/gfx/tabe/tabe.ani Normal file
View File

@@ -0,0 +1,9 @@
frame_width=32
frame_height=32
[animation]
name=default
speed=2
loop=0
frames=0,1
[/animation]

BIN
data/gfx/tabe/tabe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
data/sound/game_start.wav Normal file

Binary file not shown.

BIN
data/sound/tabe.wav Normal file

Binary file not shown.

BIN
data/sound/voice_coffee.wav Normal file

Binary file not shown.

Binary file not shown.

BIN
data/sound/voice_no.wav Normal file

Binary file not shown.

Binary file not shown.

2
release/coffee.rc Normal file
View File

@@ -0,0 +1,2 @@
// coffee.rc
IDI_ICON1 ICON "icon.ico"

BIN
release/coffee.res Normal file

Binary file not shown.

BIN
release/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -5,6 +5,8 @@
#include "param.h" // Para Param, param, ParamBalloon, ParamGame #include "param.h" // Para Param, param, ParamBalloon, ParamGame
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "resource.h"
#include "jail_audio.h"
// Constructor // Constructor
Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel_x, float speed, Uint16 creation_timer, SDL_Rect play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation) Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel_x, float speed, Uint16 creation_timer, SDL_Rect play_area, std::shared_ptr<Texture> texture, const std::vector<std::string> &animation)
@@ -36,6 +38,7 @@ Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel
power_ = BALLOON_POWER[index]; power_ = BALLOON_POWER[index];
menace_ = BALLOON_MENACE[index]; menace_ = BALLOON_MENACE[index];
score_ = BALLOON_SCORE[index]; score_ = BALLOON_SCORE[index];
sound_ = BALLOON_SOUND[index];
break; break;
} }
@@ -50,14 +53,16 @@ Balloon::Balloon(float x, float y, BalloonType type, BalloonSize size, float vel
power_ = BALLOON_POWER[index]; power_ = BALLOON_POWER[index];
menace_ = BALLOON_MENACE[index]; menace_ = BALLOON_MENACE[index];
score_ = BALLOON_SCORE[index]; score_ = BALLOON_SCORE[index];
sound_ = BALLOON_SOUND[index];
break; break;
} }
case BalloonType::POWERBALL: case BalloonType::POWERBALL:
{ {
const int index = 3; constexpr int index = 3;
h_ = w_ = BALLOON_SIZE[4]; h_ = w_ = BALLOON_SIZE[4];
sound_ = BALLOON_SOUND[3];
power_ = score_ = menace_ = 0; power_ = score_ = menace_ = 0;
vy_ = 0; vy_ = 0;
@@ -145,6 +150,7 @@ void Balloon::move()
const float max_x = play_area_.x + play_area_.w - w_ + clip; const float max_x = play_area_.x + play_area_.w - w_ + clip;
if (x_ < min_x || x_ > max_x) if (x_ < min_x || x_ > max_x)
{ {
playSound();
x_ = std::clamp(x_, min_x, max_x); x_ = std::clamp(x_, min_x, max_x);
vx_ = -vx_; vx_ = -vx_;
// Activa el efecto de rebote o invierte la rotación // Activa el efecto de rebote o invierte la rotación
@@ -179,6 +185,7 @@ void Balloon::move()
const int min_y = play_area_.y; const int min_y = play_area_.y;
if (y_ < min_y) if (y_ < min_y)
{ {
playSound();
y_ = min_y; y_ = min_y;
vy_ = -vy_; vy_ = -vy_;
enableBounce(); enableBounce();
@@ -189,6 +196,7 @@ void Balloon::move()
const int max_y = play_area_.y + play_area_.h - h_; const int max_y = play_area_.y + play_area_.h - h_;
if (y_ > max_y) if (y_ > max_y)
{ {
playSound();
y_ = max_y; y_ = max_y;
vy_ = -default_vy_; vy_ = -default_vy_;
if (type_ != BalloonType::POWERBALL) if (type_ != BalloonType::POWERBALL)
@@ -401,4 +409,13 @@ void Balloon::useNormalColor()
{ {
use_reversed_colors_ = false; use_reversed_colors_ = false;
setAnimation(); setAnimation();
}
// Reproduce el sonido al rebotar
void Balloon::playSound()
{
if (sound_enabled_)
{
JA_PlaySound(Resource::get()->getSound(sound_));
}
} }

View File

@@ -17,6 +17,7 @@ constexpr int BALLOON_SCORE[] = {50, 100, 200, 400};
constexpr int BALLOON_POWER[] = {1, 3, 7, 15}; constexpr int BALLOON_POWER[] = {1, 3, 7, 15};
constexpr int BALLOON_MENACE[] = {1, 2, 4, 8}; constexpr int BALLOON_MENACE[] = {1, 2, 4, 8};
constexpr int BALLOON_SIZE[] = {10, 16, 26, 48, 49}; constexpr int BALLOON_SIZE[] = {10, 16, 26, 48, 49};
const std::string BALLOON_SOUND[] = {"bubble1.wav", "bubble2.wav", "bubble3.wav", "bubble4.wav"};
// Tamaños de globo // Tamaños de globo
enum class BalloonSize : Uint8 enum class BalloonSize : Uint8
@@ -113,6 +114,8 @@ private:
float speed_; // Velocidad a la que se mueven los globos float speed_; // Velocidad a la que se mueven los globos
Uint8 power_; // Cantidad de poder que alberga el globo Uint8 power_; // Cantidad de poder que alberga el globo
SDL_Rect play_area_; // Zona por donde se puede mover el globo SDL_Rect play_area_; // Zona por donde se puede mover el globo
std::string sound_; // Archivo de sonido que hace el globo al rebotar
bool sound_enabled_ = false; // Indica si ha de sonar el sonido del globo al rebotar
// Alinea el circulo de colisión con la posición del objeto globo // Alinea el circulo de colisión con la posición del objeto globo
void shiftColliders(); void shiftColliders();
@@ -138,6 +141,9 @@ private:
// Establece la animación correspondiente // Establece la animación correspondiente
void setAnimation(); void setAnimation();
// Reproduce el sonido al rebotar
void playSound();
public: public:
// Constructor // Constructor
Balloon( Balloon(
@@ -208,4 +214,5 @@ public:
void setVelY(float vel_y) { vy_ = vel_y; } void setVelY(float vel_y) { vy_ = vel_y; }
void setSpeed(float speed) { speed_ = speed; } void setSpeed(float speed) { speed_ = speed; }
void setInvulnerable(bool value) { invulnerable_ = value; } void setInvulnerable(bool value) { invulnerable_ = value; }
void setSound(bool value) { sound_enabled_ = value; }
}; };

View File

@@ -371,4 +371,13 @@ int BalloonManager::getMenace()
{ {
return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon) return std::accumulate(balloons_.begin(), balloons_.end(), 0, [](int sum, const auto &balloon)
{ return sum + (balloon->isEnabled() ? balloon->getMenace() : 0); }); { return sum + (balloon->isEnabled() ? balloon->getMenace() : 0); });
}
// Establece el sonido de los globos
void BalloonManager::setSounds(bool value)
{
for (auto &balloon : balloons_)
{
balloon->setSound(value);
}
} }

View File

@@ -111,6 +111,9 @@ public:
// Obtiene el nivel de ameza actual generado por los globos // Obtiene el nivel de ameza actual generado por los globos
int getMenace(); int getMenace();
// Establece el sonido de los globos
void setSounds(bool value);
// Getters // Getters
float getBalloonSpeed() const { return balloon_speed_; } float getBalloonSpeed() const { return balloon_speed_; }
Balloons &getBalloons() { return balloons_; } Balloons &getBalloons() { return balloons_; }

View File

@@ -180,8 +180,9 @@ void Director::bindInputs()
Input::get()->bindKey(InputType::WINDOW_FULLSCREEN, SDL_SCANCODE_F3); Input::get()->bindKey(InputType::WINDOW_FULLSCREEN, SDL_SCANCODE_F3);
Input::get()->bindKey(InputType::VIDEO_SHADERS, SDL_SCANCODE_F4); Input::get()->bindKey(InputType::VIDEO_SHADERS, SDL_SCANCODE_F4);
Input::get()->bindKey(InputType::MUTE, SDL_SCANCODE_F5); Input::get()->bindKey(InputType::MUTE, SDL_SCANCODE_F5);
Input::get()->bindKey(InputType::CHANGE_LANG, SDL_SCANCODE_F6); Input::get()->bindKey(InputType::AUTO_FIRE, SDL_SCANCODE_F6);
Input::get()->bindKey(InputType::SHOWINFO, SDL_SCANCODE_F7); Input::get()->bindKey(InputType::CHANGE_LANG, SDL_SCANCODE_F7);
Input::get()->bindKey(InputType::SHOWINFO, SDL_SCANCODE_F8);
Input::get()->bindKey(InputType::RESET, SDL_SCANCODE_F10); Input::get()->bindKey(InputType::RESET, SDL_SCANCODE_F10);
// Asigna botones a inputs // Asigna botones a inputs
@@ -295,8 +296,15 @@ bool Director::initSDL()
} }
*/ */
// Obtiene información sobre la pantalla
SDL_DisplayMode DM; SDL_DisplayMode DM;
SDL_GetCurrentDisplayMode(0, &DM); SDL_GetCurrentDisplayMode(0, &DM);
// Calcula el máximo factor de zoom que se puede aplicar a la pantalla
options.video.window.max_size = std::min(DM.w / param.game.width, DM.h / param.game.height);
options.video.window.size = std::min(options.video.window.size, options.video.window.max_size);
// Muestra información sobre el tamaño de la pantalla y de la ventana de juego
std::cout << "\nCurrent display mode: " << DM.w << "x" << DM.h << " @ " << DM.refresh_rate << "Hz" << std::endl; std::cout << "\nCurrent display mode: " << DM.w << "x" << DM.h << " @ " << DM.refresh_rate << "Hz" << std::endl;
std::cout << "Window resolution : " << param.game.width << "x" << param.game.height << " x" << options.video.window.size << std::endl; std::cout << "Window resolution : " << param.game.width << "x" << param.game.height << " x" << options.video.window.size << std::endl;
@@ -380,6 +388,7 @@ void Director::setFileList()
Asset::get()->add(prefix + "/data/music/credits.ogg", AssetType::MUSIC); Asset::get()->add(prefix + "/data/music/credits.ogg", AssetType::MUSIC);
// Sonidos // Sonidos
Asset::get()->add(prefix + "/data/sound/game_start.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/balloon.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/balloon.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bubble1.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/bubble1.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/bubble2.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/bubble2.wav", AssetType::SOUND);
@@ -397,6 +406,11 @@ void Director::setFileList()
Asset::get()->add(prefix + "/data/sound/powerball.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/powerball.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/notify.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/notify.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/logo.wav", AssetType::SOUND); Asset::get()->add(prefix + "/data/sound/logo.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_coffee.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_power_up.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_no.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/voice_get_ready.wav", AssetType::SOUND);
Asset::get()->add(prefix + "/data/sound/tabe.wav", AssetType::SOUND);
// Shaders // Shaders
Asset::get()->add(prefix + "/data/shaders/crtpi_256.glsl", AssetType::DATA); Asset::get()->add(prefix + "/data/shaders/crtpi_256.glsl", AssetType::DATA);
@@ -439,6 +453,11 @@ void Director::setFileList()
Asset::get()->add(prefix + "/data/gfx/bullet/bullet.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/bullet/bullet.png", AssetType::BITMAP);
} }
{ // Tabe
Asset::get()->add(prefix + "/data/gfx/tabe/tabe.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/tabe/tabe.ani", AssetType::ANIMATION);
}
{ // Juego { // Juego
Asset::get()->add(prefix + "/data/gfx/game/game_buildings.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/game/game_buildings.png", AssetType::BITMAP);
Asset::get()->add(prefix + "/data/gfx/game/game_clouds1.png", AssetType::BITMAP); Asset::get()->add(prefix + "/data/gfx/game/game_clouds1.png", AssetType::BITMAP);

View File

@@ -100,6 +100,8 @@ void Fade::update()
SDL_RenderFillRect(renderer_, &rect1_); SDL_RenderFillRect(renderer_, &rect1_);
SDL_RenderFillRect(renderer_, &rect2_); SDL_RenderFillRect(renderer_, &rect2_);
value_ = calculateValue(0, counter_, i);
} }
// Deja el renderizador como estaba // Deja el renderizador como estaba
@@ -121,7 +123,6 @@ void Fade::update()
// Dibuja sobre el backbuffer_ // Dibuja sobre el backbuffer_
auto temp = SDL_GetRenderTarget(renderer_); auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_); SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE); SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_); SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
@@ -133,12 +134,12 @@ void Fade::update()
SDL_RenderFillRect(renderer_, &square_[index2]); SDL_RenderFillRect(renderer_, &square_[index2]);
} }
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_BLEND);
// Deja el renderizador como estaba // Deja el renderizador como estaba
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
} }
value_ = calculateValue(0, static_cast<int>(num_squares_width_ * num_squares_height_), static_cast<int>(counter_ * fade_random_squares_mult_ / fade_random_squares_delay_));
// Comprueba si ha terminado // Comprueba si ha terminado
if (counter_ * fade_random_squares_mult_ / fade_random_squares_delay_ >= num_squares_width_ * num_squares_height_) if (counter_ * fade_random_squares_mult_ / fade_random_squares_delay_ >= num_squares_width_ * num_squares_height_)
{ {
@@ -156,9 +157,11 @@ void Fade::update()
// Dibuja sobre el backbuffer_ // Dibuja sobre el backbuffer_
auto temp = SDL_GetRenderTarget(renderer_); auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_); SDL_SetRenderTarget(renderer_, backbuffer_);
SDL_SetRenderDrawBlendMode(renderer_, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_); SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_);
for (auto rect : square_)
// Dibuja el cuadrado correspondiente
for (const auto rect : square_)
{ {
SDL_RenderFillRect(renderer_, &rect); SDL_RenderFillRect(renderer_, &rect);
} }
@@ -166,11 +169,12 @@ void Fade::update()
// Deja el renderizador como estaba // Deja el renderizador como estaba
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
const auto h = counter_ / 3; // Modifica el tamaño de los rectangulos
for (int i = 0; i < (int)square_.size(); ++i) const auto h = counter_ / 2;
for (size_t i = 0; i < square_.size(); ++i)
{ {
// A partir del segundo rectangulo se pinta en función del anterior // A partir del segundo rectangulo se pinta en función del anterior
square_[i].h = i == 0 ? h : std::max(square_[i - 1].h - 3, 0); square_.at(i).h = i == 0 ? h : std::max(square_.at(i - 1).h - 2, 0);
} }
} }
else else
@@ -251,12 +255,8 @@ void Fade::activate()
} }
// Limpia la textura // Limpia la textura
auto temp = SDL_GetRenderTarget(renderer_);
SDL_SetRenderTarget(renderer_, backbuffer_);
a_ = mode_ == FadeMode::OUT ? 0 : 255; a_ = mode_ == FadeMode::OUT ? 0 : 255;
SDL_SetRenderDrawColor(renderer_, r_, g_, b_, a_); cleanBackbuffer(r_, g_, b_, a_);
SDL_RenderClear(renderer_);
SDL_SetRenderTarget(renderer_, temp);
// Deja el color listo para usar // Deja el color listo para usar
a_ = mode_ == FadeMode::OUT ? 255 : 0; a_ = mode_ == FadeMode::OUT ? 255 : 0;
@@ -266,12 +266,16 @@ void Fade::activate()
case FadeType::VENETIAN: case FadeType::VENETIAN:
{ {
cleanBackbuffer(0, 0, 0, 0); // Limpia la textura
rect1_ = {0, 0, param.game.width, 0}; a_ = mode_ == FadeMode::OUT ? 0 : 255;
square_.clear(); cleanBackbuffer(r_, g_, b_, a_);
a_ = 255;
// Deja el color listo para usar
a_ = mode_ == FadeMode::OUT ? 255 : 0;
// Añade los cuadrados al vector // Añade los cuadrados al vector
square_.clear();
rect1_ = {0, 0, param.game.width, 0};
const int max = param.game.height / param.fade.venetian_size; const int max = param.game.height / param.fade.venetian_size;
for (int i = 0; i < max; ++i) for (int i = 0; i < max; ++i)
@@ -285,31 +289,6 @@ void Fade::activate()
} }
} }
// Comprueba si está activo
bool Fade::isEnabled() const
{
return enabled_;
}
// Comprueba si ha terminado la transicion
bool Fade::hasEnded() const
{
// Ha terminado cuando ha finalizado la transición y se ha deshabilitado
return !enabled_ && finished_;
}
// Establece el tipo de fade
void Fade::setType(FadeType type)
{
type_ = type;
}
// Establece el modo de fade
void Fade::setMode(FadeMode mode)
{
mode_ = mode;
}
// Establece el color del fade // Establece el color del fade
void Fade::setColor(Uint8 r, Uint8 g, Uint8 b) void Fade::setColor(Uint8 r, Uint8 g, Uint8 b)
{ {
@@ -318,12 +297,6 @@ void Fade::setColor(Uint8 r, Uint8 g, Uint8 b)
b_ = b; b_ = b;
} }
// Establece la duración posterior
void Fade::setPost(int value)
{
post_duration_ = value;
}
// Limpia el backbuffer // Limpia el backbuffer
void Fade::cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a) void Fade::cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{ {
@@ -337,4 +310,14 @@ void Fade::cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
// Vuelve a dejar el renderizador como estaba // Vuelve a dejar el renderizador como estaba
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
}
// Calcula el valor del estado del fade
int Fade::calculateValue(int min, int max, int current)
{
if (max == 0)
{
return 0;
}
return std::clamp(current * 100 / max, 0, 100);
} }

View File

@@ -45,6 +45,7 @@ private:
int fade_random_squares_mult_; // Cantidad de cuadrados que se pintaran cada vez int fade_random_squares_mult_; // Cantidad de cuadrados que se pintaran cada vez
int post_duration_; // Duración posterior del fade tras finalizar int post_duration_; // Duración posterior del fade tras finalizar
int post_counter_; // Contador para la duración posterior int post_counter_; // Contador para la duración posterior
int value_ = 0; // Estado actual del fade entre 0 y 100
// Inicializa las variables // Inicializa las variables
void init(); void init();
@@ -52,6 +53,9 @@ private:
// Limpia el backbuffer // Limpia el backbuffer
void cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a); void cleanBackbuffer(Uint8 r, Uint8 g, Uint8 b, Uint8 a);
// Calcula el valor del estado del fade
int calculateValue(int min, int max, int current);
public: public:
// Constructor // Constructor
Fade(); Fade();
@@ -71,21 +75,16 @@ public:
// Activa el fade // Activa el fade
void activate(); void activate();
// Comprueba si ha terminado la transicion
bool hasEnded() const;
// Comprueba si está activo
bool isEnabled() const;
// Establece el tipo de fade
void setType(FadeType type);
// Establece el modo de fade
void setMode(FadeMode mode);
// Establece el color del fade // Establece el color del fade
void setColor(Uint8 r, Uint8 g, Uint8 b); void setColor(Uint8 r, Uint8 g, Uint8 b);
// Establece la duración posterior // Getters
void setPost(int value); int getValue() const { return value_; }
bool isEnabled() const { return enabled_; }
bool hasEnded() const { return !enabled_ && finished_; }
// Setters
void setType(FadeType type) { type_ = type; }
void setMode(FadeMode mode) { mode_ = mode; }
void setPost(int value) { post_duration_ = value; }
}; };

View File

@@ -32,6 +32,7 @@
#include "section.h" // Para Name, name, Options, options #include "section.h" // Para Name, name, Options, options
#include "smart_sprite.h" // Para SmartSprite #include "smart_sprite.h" // Para SmartSprite
#include "stage.h" // Para number, get, Stage, power, total_p... #include "stage.h" // Para number, get, Stage, power, total_p...
#include "tabe.h" // Para Tabe
#include "text.h" // Para Text #include "text.h" // Para Text
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
struct JA_Sound_t; // lines 37-37 struct JA_Sound_t; // lines 37-37
@@ -44,8 +45,10 @@ Game::Game(int player_id, int current_stage, bool demo)
input_(Input::get()), input_(Input::get()),
background_(std::make_unique<Background>()), background_(std::make_unique<Background>()),
canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.play_area.rect.w, param.game.play_area.rect.h)), canvas_(SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, param.game.play_area.rect.w, param.game.play_area.rect.h)),
fade_(std::make_unique<Fade>()), fade_in_(std::make_unique<Fade>()),
balloon_manager_(std::make_unique<BalloonManager>()) fade_out_(std::make_unique<Fade>()),
balloon_manager_(std::make_unique<BalloonManager>()),
tabe_(std::make_unique<Tabe>())
{ {
// Pasa variables // Pasa variables
demo_.enabled = demo; demo_.enabled = demo;
@@ -63,9 +66,15 @@ Game::Game(int player_id, int current_stage, bool demo)
Scoreboard::init(); Scoreboard::init();
scoreboard_ = Scoreboard::get(); scoreboard_ = Scoreboard::get();
fade_->setColor(fade_color.r, fade_color.g, fade_color.b); fade_in_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_->setPost(param.fade.post_duration); fade_in_->setPost(0);
fade_->setType(FadeType::VENETIAN); fade_in_->setType(FadeType::RANDOM_SQUARE);
fade_in_->setMode(FadeMode::IN);
fade_in_->activate();
fade_out_->setColor(fade_color.r, fade_color.g, fade_color.b);
fade_out_->setPost(param.fade.post_duration);
fade_out_->setType(FadeType::VENETIAN);
background_->setPos(param.game.play_area.rect); background_->setPos(param.game.play_area.rect);
@@ -87,24 +96,25 @@ Game::Game(int player_id, int current_stage, bool demo)
Stage::total_power += Stage::get(i).power_to_complete; Stage::total_power += Stage::get(i).power_to_complete;
} }
#endif #endif
// Crea los primeros globos y el mensaje de inicio
if (!demo_.enabled)
{
balloon_manager_->createTwoBigBalloons();
evaluateAndSetMenace();
createMessage({paths_.at(0), paths_.at(1)}, Resource::get()->getTexture("get_ready"));
}
} }
Game::~Game() Game::~Game()
{ {
// Guarda las puntuaciones en un fichero // MODO DEMO
if (!demo_.enabled) if (demo_.enabled)
{ {
// Habilita los sonidos
JA_EnableSound(true);
}
// MODO JUEGO
else
{
// Guarda las puntuaciones en un fichero
auto manager = std::make_unique<ManageHiScoreTable>(options.game.hi_score_table); auto manager = std::make_unique<ManageHiScoreTable>(options.game.hi_score_table);
manager->saveToFile(asset_->get("score.bin")); manager->saveToFile(asset_->get("score.bin"));
section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
} }
#ifdef RECORDING #ifdef RECORDING
saveDemoFile(Asset::get()->get("demo1.bin"), demo_.data.at(0)); saveDemoFile(Asset::get()->get("demo1.bin"), demo_.data.at(0));
#endif #endif
@@ -213,8 +223,8 @@ void Game::updatePlayers()
if (demo_.enabled && allPlayersAreNotPlaying()) if (demo_.enabled && allPlayersAreNotPlaying())
{ {
fade_->setType(FadeType::RANDOM_SQUARE); fade_out_->setType(FadeType::RANDOM_SQUARE);
fade_->activate(); fade_out_->activate();
} }
} }
@@ -262,7 +272,7 @@ void Game::updateStage()
std::vector<Path> paths = {paths_.at(2), paths_.at(3)}; std::vector<Path> paths = {paths_.at(2), paths_.at(3)};
if (Stage::number == 9) if (Stage::number == 9)
{ {
createMessage(paths, Resource::get()->getTexture("last_stage")); createMessage(paths, Resource::get()->getTexture("game_text_last_stage"));
} }
else else
{ {
@@ -275,6 +285,27 @@ void Game::updateStage()
} }
} }
// Actualiza el estado de fade in
void Game::updateFadeInState()
{
if (state_ == GameState::FADE_IN)
{
if (fade_in_->hasEnded())
{
state_ = GameState::PLAYING;
// Crea los primeros globos y el mensaje de inicio
if (!demo_.enabled)
{
balloon_manager_->createTwoBigBalloons();
evaluateAndSetMenace();
createMessage({paths_.at(0), paths_.at(1)}, Resource::get()->getTexture("game_text_get_ready"));
JA_PlaySound(Resource::get()->getSound("voice_get_ready.wav"));
}
}
}
}
// Actualiza el estado de fin de la partida // Actualiza el estado de fin de la partida
void Game::updateGameOverState() void Game::updateGameOverState()
{ {
@@ -283,25 +314,21 @@ void Game::updateGameOverState()
if (game_over_counter_ > 0) if (game_over_counter_ > 0)
{ {
if (game_over_counter_ == GAME_OVER_COUNTER_) if (game_over_counter_ == GAME_OVER_COUNTER_)
createMessage({paths_.at(2), paths_.at(3)}, Resource::get()->getTexture("game_over")); {
createMessage({paths_.at(2), paths_.at(3)}, Resource::get()->getTexture("game_text_game_over"));
JA_FadeOutMusic(1000);
balloon_manager_->setSounds(true);
}
game_over_counter_--; game_over_counter_--;
if ((game_over_counter_ == 250) || (game_over_counter_ == 200) || (game_over_counter_ == 180) || (game_over_counter_ == 120) || (game_over_counter_ == 60))
{
// Hace sonar aleatoriamente uno de los 4 sonidos de burbujas
const auto index = rand() % 4;
JA_Sound_t *sound[4] = {Resource::get()->getSound("bubble1.wav"), Resource::get()->getSound("bubble2.wav"), Resource::get()->getSound("bubble3.wav"), Resource::get()->getSound("bubble4.wav")};
JA_PlaySound(sound[index], 0);
}
if (game_over_counter_ == 150) if (game_over_counter_ == 150)
{ {
fade_->activate(); fade_out_->activate();
} }
} }
if (fade_->hasEnded()) if (fade_out_->hasEnded())
{ {
if (game_completed_counter_ > 0) if (game_completed_counter_ > 0)
{ {
@@ -336,8 +363,8 @@ void Game::updateCompletedState()
// Muestra el mensaje de felicitación y da los puntos a los jugadores // Muestra el mensaje de felicitación y da los puntos a los jugadores
if (game_completed_counter_ == 200) if (game_completed_counter_ == 200)
{ {
createMessage({paths_.at(4), paths_.at(5)}, Resource::get()->getTexture("congratulations")); createMessage({paths_.at(4), paths_.at(5)}, Resource::get()->getTexture("game_text_congratulations"));
createMessage({paths_.at(6), paths_.at(7)}, Resource::get()->getTexture("1000000_points")); createMessage({paths_.at(6), paths_.at(7)}, Resource::get()->getTexture("game_text_1000000_points"));
for (auto &player : players_) for (auto &player : players_)
if (player->isPlaying()) if (player->isPlaying())
@@ -474,6 +501,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
(item->getWidth() - game_text_textures_[4]->getWidth()) / 2; (item->getWidth() - game_text_textures_[4]->getWidth()) / 2;
createItemText(x, game_text_textures_[4]); createItemText(x, game_text_textures_[4]);
} }
JA_PlaySound(Resource::get()->getSound("voice_coffee.wav"));
break; break;
} }
case ItemType::COFFEE_MACHINE: case ItemType::COFFEE_MACHINE:
@@ -484,6 +512,7 @@ void Game::checkPlayerItemCollision(std::shared_ptr<Player> &player)
item->getPosX() + item->getPosX() +
(item->getWidth() - game_text_textures_[3]->getWidth()) / 2; (item->getWidth() - game_text_textures_[3]->getWidth()) / 2;
createItemText(x, game_text_textures_[3]); createItemText(x, game_text_textures_[3]);
JA_PlaySound(Resource::get()->getSound("voice_power_up.wav"));
break; break;
} }
default: default:
@@ -722,7 +751,9 @@ void Game::createMessage(const std::vector<Path> &paths, std::shared_ptr<Texture
// Inicializa // Inicializa
for (const auto &path : paths) for (const auto &path : paths)
{
path_sprites_.back()->addPath(path, true); path_sprites_.back()->addPath(path, true);
}
path_sprites_.back()->enable(); path_sprites_.back()->enable();
} }
@@ -815,13 +846,12 @@ void Game::killPlayer(std::shared_ptr<Player> &player)
else else
{ {
// Si no tiene cafes, muere // Si no tiene cafes, muere
pauseMusic(); // pauseMusic();
balloon_manager_->stopAllBalloons(); balloon_manager_->stopAllBalloons();
JA_PlaySound(Resource::get()->getSound("player_collision.wav")); JA_PlaySound(Resource::get()->getSound("player_collision.wav"));
screen_->shake(); screen_->shake();
JA_PlaySound(Resource::get()->getSound("coffeeout.wav")); JA_PlaySound(Resource::get()->getSound("voice_no.wav"));
player->setPlayingState(PlayerState::DYING); player->setPlayingState(PlayerState::DYING);
allPlayersAreNotPlaying() ? stopMusic() : resumeMusic();
} }
} }
@@ -869,7 +899,7 @@ void Game::update()
checkMusicStatus(); checkMusicStatus();
screen_->update(); screen_->update();
globalInputs::update(); globalInputs::update();
fillCanvas(); fillCanvas();
} }
} }
@@ -912,11 +942,10 @@ void Game::fillCanvas()
renderItems(); renderItems();
renderSmartSprites(); renderSmartSprites();
balloon_manager_->render(); balloon_manager_->render();
tabe_->render();
renderBullets(); renderBullets();
renderPathSprites(); renderPathSprites();
renderPlayers(); renderPlayers();
// dbg_print(0, 40, std::to_string(menace_current_).c_str(), 255, 0, 0);
// dbg_print(0, 50, std::to_string(menace_threshold_).c_str(), 255, 0, 0);
// Deja el renderizador apuntando donde estaba // Deja el renderizador apuntando donde estaba
SDL_SetRenderTarget(renderer_, temp); SDL_SetRenderTarget(renderer_, temp);
@@ -935,7 +964,8 @@ void Game::render()
scoreboard_->render(); scoreboard_->render();
// Dibuja el fade // Dibuja el fade
fade_->render(); fade_in_->render();
fade_out_->render();
// Vuelca el contenido del renderizador en pantalla // Vuelca el contenido del renderizador en pantalla
screen_->blit(); screen_->blit();
@@ -960,10 +990,11 @@ void Game::disableTimeStopItem()
// Comprueba si la música ha de estar sonando // Comprueba si la música ha de estar sonando
void Game::checkMusicStatus() void Game::checkMusicStatus()
{ {
// Si la música no está sonando // Si se ha completado el juego o los jugadores han terminado, detiene la música
if (JA_GetMusicState() == JA_MUSIC_INVALID || JA_GetMusicState() == JA_MUSIC_STOPPED) if (state_ != GameState::COMPLETED && !allPlayersAreGameOver())
// Si se ha completado el juego o los jugadores han terminado, detiene la música {
state_ == GameState::COMPLETED || allPlayersAreGameOver() ? JA_StopMusic() : JA_PlayMusic(Resource::get()->getMusic("playing.ogg")); playMusic();
}
} }
// Bucle para el juego // Bucle para el juego
@@ -988,7 +1019,7 @@ void Game::initPaths()
{ {
// Recorrido para el texto de "Get Ready!" (0,1) // Recorrido para el texto de "Get Ready!" (0,1)
{ {
const auto &texture = Resource::get()->getTexture("get_ready"); const auto &texture = Resource::get()->getTexture("game_text_get_ready");
const auto w = texture->getWidth(); const auto w = texture->getWidth();
const int x0 = -w; const int x0 = -w;
const int x1 = param.game.play_area.center_x - w / 2; const int x1 = param.game.play_area.center_x - w / 2;
@@ -998,10 +1029,9 @@ void Game::initPaths()
paths_.emplace_back(Path(createPath(x1, x2, PathType::HORIZONTAL, y, 80, easeInQuint), 0)); paths_.emplace_back(Path(createPath(x1, x2, PathType::HORIZONTAL, y, 80, easeInQuint), 0));
} }
// Recorrido para el texto de "Last Stage!" o de "X stages left" o "Game Over" // Recorrido para el texto de "Last Stage!" o de "X stages left" o "Game Over" (2,3)
// (2,3)
{ {
const auto &texture = Resource::get()->getTexture("last_stage"); const auto &texture = Resource::get()->getTexture("game_text_last_stage");
const auto h = texture->getHeight(); const auto h = texture->getHeight();
const int y0 = param.game.play_area.rect.h - h; const int y0 = param.game.play_area.rect.h - h;
const int y1 = param.game.play_area.center_y - h / 2; const int y1 = param.game.play_area.center_y - h / 2;
@@ -1013,7 +1043,7 @@ void Game::initPaths()
// Recorrido para el texto de "Congratulations!!" (3,4) // Recorrido para el texto de "Congratulations!!" (3,4)
{ {
const auto &texture = Resource::get()->getTexture("congratulations"); const auto &texture = Resource::get()->getTexture("game_text_congratulations");
const auto w = texture->getWidth(); const auto w = texture->getWidth();
const auto h = texture->getHeight(); const auto h = texture->getHeight();
const int x0 = -w; const int x0 = -w;
@@ -1026,7 +1056,7 @@ void Game::initPaths()
// Recorrido para el texto de "1.000.000 points!" (5,6) // Recorrido para el texto de "1.000.000 points!" (5,6)
{ {
const auto &texture = Resource::get()->getTexture("1000000_points"); const auto &texture = Resource::get()->getTexture("game_text_1000000_points");
const auto w = texture->getWidth(); const auto w = texture->getWidth();
const auto h = texture->getHeight(); const auto h = texture->getHeight();
const int x0 = param.game.play_area.rect.w; const int x0 = param.game.play_area.rect.w;
@@ -1164,8 +1194,7 @@ void Game::checkEvents()
} }
case SDLK_6: // Crea un mensaje case SDLK_6: // Crea un mensaje
{ {
createMessage({paths_.at(4), paths_.at(5)}, Resource::get()->getTexture("congratulations")); createMessage({paths_.at(2), paths_.at(3)}, Resource::get()->getTexture("game_text_congratulations"));
createMessage({paths_.at(6), paths_.at(7)}, Resource::get()->getTexture("1000000_points"));
break; break;
} }
case SDLK_7: // Flash case SDLK_7: // Flash
@@ -1176,6 +1205,12 @@ void Game::checkEvents()
case SDLK_8: case SDLK_8:
{ {
players_.at(0)->setPlayingState(PlayerState::LEAVING_SCREEN); players_.at(0)->setPlayingState(PlayerState::LEAVING_SCREEN);
break;
}
case SDLK_9:
{
tabe_->enable();
break;
} }
default: default:
break; break;
@@ -1342,7 +1377,8 @@ void Game::handleDemoMode()
if (input_->checkAnyButtonPressed()) if (input_->checkAnyButtonPressed())
{ {
section::name = section::Name::TITLE; // Salir del modo demo y regresar al menú principal. section::name = section::Name::TITLE; // Salir del modo demo y regresar al menú principal.
section::attract_mode = section::AttractMode::TITLE_TO_DEMO; // El juego volverá a mostrar la demo
return; return;
} }
++index; ++index;
@@ -1691,6 +1727,16 @@ void Game::resumeMusic()
} }
} }
// Hace sonar la música
void Game::playMusic()
{
// Si la música no está sonando
if (JA_GetMusicState() == JA_MUSIC_INVALID || JA_GetMusicState() == JA_MUSIC_STOPPED)
{
JA_PlayMusic(Resource::get()->getMusic("playing.ogg"));
}
}
// Detiene la música // Detiene la música
void Game::stopMusic() void Game::stopMusic()
{ {
@@ -1712,12 +1758,12 @@ void Game::updateDemo()
// Activa el fundido antes de acabar con los datos de la demo // Activa el fundido antes de acabar con los datos de la demo
if (demo_.counter == TOTAL_DEMO_DATA - 200) if (demo_.counter == TOTAL_DEMO_DATA - 200)
{ {
fade_->setType(FadeType::RANDOM_SQUARE); fade_out_->setType(FadeType::RANDOM_SQUARE);
fade_->activate(); fade_out_->activate();
} }
// Si ha terminado el fundido, cambia de sección // Si ha terminado el fundido, cambia de sección
if (fade_->hasEnded()) if (fade_out_->hasEnded())
{ {
section::name = section::Name::HI_SCORE_TABLE; section::name = section::Name::HI_SCORE_TABLE;
return; return;
@@ -1756,15 +1802,18 @@ void Game::updateGame()
Stage::addPower(5); Stage::addPower(5);
} }
#endif #endif
fade_->update(); fade_in_->update();
fade_out_->update();
updatePlayers(); updatePlayers();
checkPlayersStatusPlaying(); checkPlayersStatusPlaying();
updateScoreboard(); updateScoreboard();
updateBackground(); updateBackground();
balloon_manager_->update(); balloon_manager_->update();
tabe_->update();
moveBullets(); moveBullets();
updateItems(); updateItems();
updateStage(); updateStage();
updateFadeInState();
updateGameOverState(); updateGameOverState();
updateCompletedState(); updateCompletedState();
updateSmartSprites(); updateSmartSprites();
@@ -1792,21 +1841,24 @@ void Game::cleanVectors()
// Gestiona el nivel de amenaza // Gestiona el nivel de amenaza
void Game::updateMenace() void Game::updateMenace()
{ {
const auto stage = Stage::get(Stage::number); if (state_ == GameState::PLAYING)
const float percent = Stage::power / stage.power_to_complete;
const int difference = stage.max_menace - stage.min_menace;
// Aumenta el nivel de amenaza en función de la puntuación
menace_threshold_ = stage.min_menace + (difference * percent);
// Si el nivel de amenza es inferior al umbral
if (menace_current_ < menace_threshold_)
{ {
// Crea una formación de enemigos const auto stage = Stage::get(Stage::number);
balloon_manager_->deployBalloonFormation(Stage::number); const float percent = Stage::power / stage.power_to_complete;
const int difference = stage.max_menace - stage.min_menace;
// Recalcula el nivel de amenaza con el nuevo globo // Aumenta el nivel de amenaza en función de la puntuación
evaluateAndSetMenace(); menace_threshold_ = stage.min_menace + (difference * percent);
// Si el nivel de amenza es inferior al umbral
if (menace_current_ < menace_threshold_)
{
// Crea una formación de enemigos
balloon_manager_->deployBalloonFormation(Stage::number);
// Recalcula el nivel de amenaza con el nuevo globo
evaluateAndSetMenace();
}
} }
} }

View File

@@ -12,6 +12,7 @@
class Asset; // lines 13-13 class Asset; // lines 13-13
class Background; // lines 14-14 class Background; // lines 14-14
class BalloonManager; class BalloonManager;
class Tabe;
class Bullet; // lines 15-15 class Bullet; // lines 15-15
class Fade; // lines 16-16 class Fade; // lines 16-16
class Input; // lines 17-17 class Input; // lines 17-17
@@ -65,6 +66,7 @@ private:
// Enum // Enum
enum class GameState enum class GameState
{ {
FADE_IN,
PLAYING, PLAYING,
COMPLETED, COMPLETED,
GAME_OVER, GAME_OVER,
@@ -140,8 +142,10 @@ private:
std::vector<std::vector<std::string>> item_animations_; // Vector con las animaciones de los items std::vector<std::vector<std::string>> item_animations_; // Vector con las animaciones de los items
std::vector<std::vector<std::string>> player_animations_; // Vector con las animaciones del jugador std::vector<std::vector<std::string>> player_animations_; // Vector con las animaciones del jugador
std::unique_ptr<Fade> fade_; // Objeto para renderizar fades std::unique_ptr<Fade> fade_in_; // Objeto para renderizar fades
std::unique_ptr<Fade> fade_out_; // Objeto para renderizar fades
std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos std::unique_ptr<BalloonManager> balloon_manager_; // Objeto para gestionar los globos
std::unique_ptr<Tabe> tabe_; // Objeto para gestionar el Tabe Volaor
std::vector<Path> paths_; // Vector con los recorridos precalculados almacenados std::vector<Path> paths_; // Vector con los recorridos precalculados almacenados
// Variables // Variables
@@ -164,7 +168,7 @@ private:
int total_power_to_complete_game_; // La suma del poder necesario para completar todas las fases int total_power_to_complete_game_; // La suma del poder necesario para completar todas las fases
int menace_current_ = 0; // Nivel de amenaza actual int menace_current_ = 0; // Nivel de amenaza actual
int menace_threshold_ = 0; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el número de globos int menace_threshold_ = 0; // Umbral del nivel de amenaza. Si el nivel de amenaza cae por debajo del umbral, se generan más globos. Si el umbral aumenta, aumenta el número de globos
GameState state_ = GameState::PLAYING; // Estado GameState state_ = GameState::FADE_IN; // Estado
#ifdef DEBUG #ifdef DEBUG
bool auto_pop_balloons_ = false; // Si es true, incrementa automaticamente los globos explotados bool auto_pop_balloons_ = false; // Si es true, incrementa automaticamente los globos explotados
#endif #endif
@@ -193,6 +197,9 @@ private:
// Comprueba si hay cambio de fase y actualiza las variables // Comprueba si hay cambio de fase y actualiza las variables
void updateStage(); void updateStage();
// Actualiza el estado de fade in
void updateFadeInState();
// Actualiza el estado de fin de la partida // Actualiza el estado de fin de la partida
void updateGameOverState(); void updateGameOverState();
@@ -373,6 +380,9 @@ private:
// Reanuda la música // Reanuda la música
void resumeMusic(); void resumeMusic();
// Hace sonar la música
void playMusic();
// Detiene la música // Detiene la música
void stopMusic(); void stopMusic();

View File

@@ -1,4 +1,5 @@
#include "game_logo.h" #include "game_logo.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL #include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL
#include <algorithm> // Para max #include <algorithm> // Para max
#include "animated_sprite.h" // Para AnimatedSprite #include "animated_sprite.h" // Para AnimatedSprite
@@ -8,6 +9,11 @@
#include "smart_sprite.h" // Para SmartSprite #include "smart_sprite.h" // Para SmartSprite
#include "sprite.h" // Para Sprite #include "sprite.h" // Para Sprite
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "screen.h"
constexpr int ZOOM_FACTOR = 5;
constexpr int FLASH_DELAY = 3;
constexpr int FLASH_LENGHT = FLASH_DELAY + 3;
// Constructor // Constructor
GameLogo::GameLogo(int x, int y) GameLogo::GameLogo(int x, int y)
@@ -21,7 +27,7 @@ GameLogo::GameLogo(int x, int y)
crisis_sprite_(std::make_unique<SmartSprite>(crisis_texture_)), crisis_sprite_(std::make_unique<SmartSprite>(crisis_texture_)),
arcade_edition_sprite_(std::make_unique<Sprite>(arcade_edition_texture_, (param.game.width - arcade_edition_texture_->getWidth()) / 2, param.title.arcade_edition_position, arcade_edition_texture_->getWidth(), arcade_edition_texture_->getHeight())), arcade_edition_sprite_(std::make_unique<Sprite>(arcade_edition_texture_, (param.game.width - arcade_edition_texture_->getWidth()) / 2, param.title.arcade_edition_position, arcade_edition_texture_->getWidth(), arcade_edition_texture_->getHeight())),
x_(x), x_(x),
y_(y) { } y_(y) {}
// Inicializa las variables // Inicializa las variables
void GameLogo::init() void GameLogo::init()
@@ -32,15 +38,8 @@ void GameLogo::init()
// Variables // Variables
coffee_crisis_status_ = Status::DISABLED; coffee_crisis_status_ = Status::DISABLED;
arcade_edition_status_ = Status::DISABLED; arcade_edition_status_ = Status::DISABLED;
shake_.init(1, 2, 8, xp);
shake_.desp = 1; zoom_ = 3.0f * ZOOM_FACTOR;
shake_.delay = 2;
shake_.lenght = 8;
shake_.remaining = shake_.lenght;
shake_.counter = shake_.delay;
shake_.origin = xp;
zoom_ = 3.0f;
// Inicializa el bitmap de 'Coffee' // Inicializa el bitmap de 'Coffee'
coffee_sprite_->setPosX(xp); coffee_sprite_->setPosX(xp);
@@ -122,10 +121,11 @@ void GameLogo::update()
if (coffee_sprite_->hasFinished() && crisis_sprite_->hasFinished()) if (coffee_sprite_->hasFinished() && crisis_sprite_->hasFinished())
{ {
coffee_crisis_status_ = Status::SHAKING; coffee_crisis_status_ = Status::SHAKING;
arcade_edition_status_ = Status::MOVING;
// Reproduce el efecto sonoro // Reproduce el efecto sonoro
JA_PlaySound(Resource::get()->getSound("title.wav")); JA_PlaySound(Resource::get()->getSound("title.wav"));
Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGHT, FLASH_DELAY);
Screen::get()->shake();
} }
break; break;
@@ -133,7 +133,7 @@ void GameLogo::update()
case Status::SHAKING: case Status::SHAKING:
{ {
// Agita el logo // Agita "COFFEE CRISIS"
if (shake_.remaining > 0) if (shake_.remaining > 0)
{ {
if (shake_.counter > 0) if (shake_.counter > 0)
@@ -154,6 +154,7 @@ void GameLogo::update()
coffee_sprite_->setPosX(shake_.origin); coffee_sprite_->setPosX(shake_.origin);
crisis_sprite_->setPosX(shake_.origin + 15); crisis_sprite_->setPosX(shake_.origin + 15);
coffee_crisis_status_ = Status::FINISHED; coffee_crisis_status_ = Status::FINISHED;
arcade_edition_status_ = Status::MOVING;
} }
dust_right_sprite_->update(); dust_right_sprite_->update();
@@ -178,12 +179,42 @@ void GameLogo::update()
{ {
case Status::MOVING: case Status::MOVING:
{ {
zoom_ -= 0.1f; zoom_ -= 0.1f * ZOOM_FACTOR;
arcade_edition_sprite_->setZoom(zoom_); arcade_edition_sprite_->setZoom(zoom_);
if (zoom_ <= 1.0f) if (zoom_ <= 1.0f)
{ {
arcade_edition_status_ = Status::FINISHED; arcade_edition_status_ = Status::SHAKING;
zoom_ = 1.0f; zoom_ = 1.0f;
arcade_edition_sprite_->setZoom(zoom_);
shake_.init(1, 2, 8, arcade_edition_sprite_->getX());
JA_PlaySound(Resource::get()->getSound("title.wav"));
Screen::get()->flash(Color(0xFF, 0xFF, 0xFF), FLASH_LENGHT, FLASH_DELAY);
Screen::get()->shake();
}
break;
}
case Status::SHAKING:
{
// Agita "ARCADE EDITION"
if (shake_.remaining > 0)
{
if (shake_.counter > 0)
{
shake_.counter--;
}
else
{
shake_.counter = shake_.delay;
const auto desp = shake_.remaining % 2 == 0 ? shake_.desp * (-1) : shake_.desp;
arcade_edition_sprite_->setX(shake_.origin + desp);
shake_.remaining--;
}
}
else
{
arcade_edition_sprite_->setX(shake_.origin);
arcade_edition_status_ = Status::FINISHED;
} }
break; break;
} }
@@ -191,6 +222,13 @@ void GameLogo::update()
default: default:
break; break;
} }
if (coffee_crisis_status_ == Status::FINISHED &&
arcade_edition_status_ == Status::FINISHED &&
post_finished_counter_ > 0)
{
--post_finished_counter_;
}
} }
// Activa la clase // Activa la clase
@@ -203,7 +241,7 @@ void GameLogo::enable()
// Indica si ha terminado la animación // Indica si ha terminado la animación
bool GameLogo::hasFinished() const bool GameLogo::hasFinished() const
{ {
return coffee_crisis_status_ == Status::FINISHED && arcade_edition_status_ == Status::FINISHED; return post_finished_counter_ == 0;
} }
// Recarga las texturas // Recarga las texturas

View File

@@ -20,12 +20,30 @@ private:
struct Shake struct Shake
{ {
int desp; // Pixels de desplazamiento para agitar la pantalla en el eje x int desp = 1; // Pixels de desplazamiento para agitar la pantalla en el eje x
int delay; // Retraso entre cada desplazamiento de la pantalla al agitarse int delay = 2; // Retraso entre cada desplazamiento de la pantalla al agitarse
int counter; // Contador para el retraso int lenght = 8; // Cantidad de desplazamientos a realizar
int lenght; // Cantidad de desplazamientos a realizar int remaining = lenght; // Cantidad de desplazamientos pendientes a realizar
int remaining; // Cantidad de desplazamientos pendientes a realizar int counter = delay; // Contador para el retraso
int origin; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento int origin; // Valor inicial de la pantalla para dejarla igual tras el desplazamiento
// Constructor por defect
Shake() = default;
// Constructor
Shake(int d, int de, int l, int o)
: desp(d), delay(de), lenght(l), remaining(l), counter(de), origin(o) {}
// Inicializa los miembros
void init(int d, int de, int l, int o)
{
desp = d;
delay = de;
lenght = l;
remaining = l;
counter = de;
origin = o;
}
}; };
// Objetos y punteros // Objetos y punteros
@@ -43,9 +61,10 @@ private:
std::unique_ptr<Sprite> arcade_edition_sprite_; // Sprite con los graficos de "Arcade Edition" std::unique_ptr<Sprite> arcade_edition_sprite_; // Sprite con los graficos de "Arcade Edition"
// Variables // Variables
int x_; // Posición donde dibujar el logo int x_; // Posición donde dibujar el logo
int y_; // Posición donde dibujar el logo int y_; // Posición donde dibujar el logo
float zoom_; // Zoom aplicado al texto "ARCADE EDITION" float zoom_; // Zoom aplicado al texto "ARCADE EDITION"
int post_finished_counter_ = 1; // Contador final una vez terminada las animaciones de los logos
Status coffee_crisis_status_ = Status::DISABLED; // Estado en el que se encuentra el texto "COFFEE CRISIS" Status coffee_crisis_status_ = Status::DISABLED; // Estado en el que se encuentra el texto "COFFEE CRISIS"
Status arcade_edition_status_ = Status::DISABLED; // Estado en el que se encuentra el texto "ARCADE_EDITION" Status arcade_edition_status_ = Status::DISABLED; // Estado en el que se encuentra el texto "ARCADE_EDITION"

View File

@@ -108,6 +108,13 @@ namespace globalInputs
Notifier::get()->showText({getLangName(options.game.language)}); Notifier::get()->showText({getLangName(options.game.language)});
} }
// Cambia el modo de disparo
void toggleFireMode()
{
options.game.autofire = !options.game.autofire;
Notifier::get()->showText({"Autofire " + boolToOnOff(options.game.autofire)});
}
// Comprueba los inputs que se pueden introducir en cualquier sección del juego // Comprueba los inputs que se pueden introducir en cualquier sección del juego
void check() void check()
{ {
@@ -162,6 +169,13 @@ namespace globalInputs
return; return;
} }
// Autofire
if (Input::get()->checkInput(InputType::AUTO_FIRE, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
{
toggleFireMode();
return;
}
// Idioma // Idioma
if (Input::get()->checkInput(InputType::CHANGE_LANG, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD)) if (Input::get()->checkInput(InputType::CHANGE_LANG, INPUT_DO_NOT_ALLOW_REPEAT, InputDeviceToUse::KEYBOARD))
{ {

View File

@@ -205,9 +205,10 @@ void HiScoreTable::checkInput()
// Comprueba si se ha pulsado cualquier botón (de los usados para jugar) // Comprueba si se ha pulsado cualquier botón (de los usados para jugar)
if (Input::get()->checkAnyButtonPressed()) if (Input::get()->checkAnyButtonPressed())
{ {
JA_StopMusic(); //JA_StopMusic();
section::name = section::Name::TITLE; section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1; section::options = section::Options::TITLE_1;
section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
return; return;
} }

View File

@@ -44,6 +44,7 @@ enum class InputType : int
SHOWINFO, SHOWINFO,
CONFIG, CONFIG,
SWAP_CONTROLLERS, SWAP_CONTROLLERS,
AUTO_FIRE,
// Input obligatorio // Input obligatorio
NONE, NONE,

View File

@@ -310,9 +310,10 @@ void Instructions::checkInput()
// Comprueba si se ha pulsado cualquier botón (de los usados para jugar) // Comprueba si se ha pulsado cualquier botón (de los usados para jugar)
if (Input::get()->checkAnyButtonPressed()) if (Input::get()->checkAnyButtonPressed())
{ {
JA_StopMusic(); //JA_StopMusic();
section::name = section::Name::TITLE; section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1; section::options = section::Options::TITLE_1;
section::attract_mode = section::AttractMode::TITLE_TO_DEMO;
return; return;
} }

View File

@@ -416,7 +416,6 @@ void Intro::render()
void Intro::run() void Intro::run()
{ {
JA_PlayMusic(Resource::get()->getMusic("intro.ogg"), 0); JA_PlayMusic(Resource::get()->getMusic("intro.ogg"), 0);
while (section::name == section::Name::INTRO) while (section::name == section::Name::INTRO)
{ {
checkInput(); checkInput();

View File

@@ -1,91 +1,92 @@
#ifndef JA_USESDLMIXER #ifndef JA_USESDLMIXER
#include "jail_audio.h" #include "jail_audio.h"
#include <stdint.h> // para uint8_t #include "stb_vorbis.c"
#include <stdio.h> // para NULL, fseek, fclose, fopen, fread, ftell, FILE #include <SDL2/SDL.h>
#include <stdlib.h> // para free, malloc #include <stdio.h>
#include "stb_vorbis.c" // para stb_vorbis_decode_memory
#define JA_MAX_SIMULTANEOUS_CHANNELS 5 #define JA_MAX_SIMULTANEOUS_CHANNELS 20
struct JA_Sound_t struct JA_Sound_t {
{ Uint32 length {0};
Uint32 length{0}; Uint8* buffer {NULL};
Uint8 *buffer{NULL};
}; };
struct JA_Channel_t struct JA_Channel_t {
{ JA_Sound_t *sound;
JA_Sound_t *sound; int pos {0};
int pos{0}; int times {0};
int times{0}; JA_Channel_state state { JA_CHANNEL_FREE };
JA_Channel_state state{JA_CHANNEL_FREE};
}; };
struct JA_Music_t struct JA_Music_t {
{ int samples {0};
int samples{0}; Uint32 length {0};
int pos{0}; int pos {0};
int times{0}; int times {0};
short *output{NULL}; short* output {NULL};
JA_Music_state state{JA_MUSIC_INVALID}; JA_Music_state state {JA_MUSIC_INVALID};
}; };
JA_Music_t *current_music{NULL}; JA_Music_t *current_music{NULL};
JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS]; JA_Channel_t channels[JA_MAX_SIMULTANEOUS_CHANNELS];
int JA_freq{48000}; int JA_freq {48000};
SDL_AudioFormat JA_format{AUDIO_S16}; SDL_AudioFormat JA_format {AUDIO_S16};
Uint8 JA_channels{2}; Uint8 JA_channels {2};
int JA_musicVolume = 128; int JA_musicVolume = 128;
int JA_soundVolume = 64; int JA_soundVolume = 64;
bool JA_musicEnabled = true; bool JA_musicEnabled = true;
bool JA_soundEnabled = true; bool JA_soundEnabled = true;
SDL_AudioDeviceID sdlAudioDevice = 0; SDL_AudioDeviceID sdlAudioDevice = 0;
void audioCallback(void *userdata, uint8_t *stream, int len) bool fading = false;
{ int fade_start_time;
int fade_duration;
int fade_initial_volume;
void audioCallback(void * userdata, uint8_t * stream, int len) {
SDL_memset(stream, 0, len); SDL_memset(stream, 0, len);
if (current_music != NULL && current_music->state == JA_MUSIC_PLAYING) if (current_music != NULL && current_music->state == JA_MUSIC_PLAYING) {
{ int volume = JA_musicVolume;
const int size = SDL_min(len, current_music->samples * 2 - current_music->pos); if (fading) {
SDL_MixAudioFormat(stream, (Uint8 *)(current_music->output + current_music->pos), AUDIO_S16, size, JA_musicVolume); int time = SDL_GetTicks();
current_music->pos += size / 2; if (time > (fade_start_time+fade_duration)) {
if (size < len) fading = false;
{ current_music->pos = 0;
if (current_music->times != 0) current_music->state = JA_MUSIC_STOPPED;
{ volume = 0;
SDL_MixAudioFormat(stream + size, (Uint8 *)current_music->output, AUDIO_S16, len - size, JA_musicVolume); } else {
current_music->pos = (len - size) / 2; const int time_passed = time - fade_start_time;
if (current_music->times > 0) const float percent = (float)time_passed / (float)fade_duration;
current_music->times--; volume = JA_musicVolume * (1.0 - percent);
} }
else }
{ const int size = SDL_min(len, current_music->length - current_music->pos);
SDL_MixAudioFormat(stream, (Uint8*)(current_music->output)+current_music->pos, AUDIO_S16, size, volume);
current_music->pos += size;
if (size < len) {
if (current_music->times != 0) {
SDL_MixAudioFormat(stream+size, (Uint8*)current_music->output, AUDIO_S16, len-size, volume);
current_music->pos = len-size;
if (current_music->times > 0) current_music->times--;
} else {
current_music->pos = 0; current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
} }
} }
} }
// Mixar els channels mi amol // Mixar els channels mi amol
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
{ if (channels[i].state == JA_CHANNEL_PLAYING) {
if (channels[i].state == JA_CHANNEL_PLAYING)
{
const int size = SDL_min(len, channels[i].sound->length - channels[i].pos); const int size = SDL_min(len, channels[i].sound->length - channels[i].pos);
SDL_MixAudioFormat(stream, channels[i].sound->buffer + channels[i].pos, AUDIO_S16, size, JA_soundVolume); SDL_MixAudioFormat(stream, channels[i].sound->buffer + channels[i].pos, AUDIO_S16, size, JA_soundVolume);
channels[i].pos += size; channels[i].pos += size;
if (size < len) if (size < len) {
{ if (channels[i].times != 0) {
if (channels[i].times != 0) SDL_MixAudioFormat(stream + size, channels[i].sound->buffer, AUDIO_S16, len-size, JA_soundVolume);
{ channels[i].pos = len-size;
SDL_MixAudioFormat(stream + size, channels[i].sound->buffer, AUDIO_S16, len - size, JA_soundVolume); if (channels[i].times > 0) channels[i].times--;
channels[i].pos = len - size; } else {
if (channels[i].times > 0)
channels[i].times--;
}
else
{
JA_StopChannel(i); JA_StopChannel(i);
} }
} }
@@ -95,69 +96,84 @@ void audioCallback(void *userdata, uint8_t *stream, int len)
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels) void JA_Init(const int freq, const SDL_AudioFormat format, const int channels)
{ {
#ifdef DEBUG
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG);
#endif
SDL_Log("Iniciant JailAudio...");
JA_freq = freq; JA_freq = freq;
JA_format = format; JA_format = format;
JA_channels = channels; JA_channels = channels;
SDL_AudioSpec audioSpec{JA_freq, JA_format, JA_channels, 0, 1024, 0, 0, audioCallback, NULL}; SDL_AudioSpec audioSpec{JA_freq, JA_format, JA_channels, 0, 1024, 0, 0, audioCallback, NULL};
if (sdlAudioDevice != 0) if (sdlAudioDevice != 0) SDL_CloseAudioDevice(sdlAudioDevice);
SDL_CloseAudioDevice(sdlAudioDevice);
sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0); sdlAudioDevice = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0);
if (sdlAudioDevice==0)
{
SDL_Log("FAILED!\n");
SDL_Log("Failed to initialize SDL audio!\n");
} else {
SDL_Log("OK!\n");
}
SDL_PauseAudioDevice(sdlAudioDevice, 0); SDL_PauseAudioDevice(sdlAudioDevice, 0);
} }
void JA_Quit() void JA_Quit() {
{
SDL_PauseAudioDevice(sdlAudioDevice, 1); SDL_PauseAudioDevice(sdlAudioDevice, 1);
if (sdlAudioDevice != 0) if (sdlAudioDevice != 0) SDL_CloseAudioDevice(sdlAudioDevice);
SDL_CloseAudioDevice(sdlAudioDevice);
sdlAudioDevice = 0; sdlAudioDevice = 0;
} }
JA_Music_t *JA_LoadMusic(const char *filename) JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length)
{ {
int chan, samplerate; int chan, samplerate;
// [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid.
FILE *f = fopen(filename, "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
Uint8 *buffer = (Uint8 *)malloc(fsize + 1);
if (fread(buffer, fsize, 1, f) != 1)
return NULL;
fclose(f);
JA_Music_t *music = new JA_Music_t(); JA_Music_t *music = new JA_Music_t();
music->samples = stb_vorbis_decode_memory(buffer, fsize, &chan, &samplerate, &music->output); music->samples = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &music->output);
free(buffer);
// [RZC 28/08/22] Abans el descomprimiem mentre el teniem obert // [RZC 28/08/22] Abans el descomprimiem mentre el teniem obert
// music->samples = stb_vorbis_decode_filename(filename, &chan, &samplerate, &music->output); // music->samples = stb_vorbis_decode_filename(filename, &chan, &samplerate, &music->output);
SDL_AudioCVT cvt; SDL_AudioCVT cvt;
SDL_BuildAudioCVT(&cvt, AUDIO_S16, chan, samplerate, JA_format, JA_channels, JA_freq); SDL_BuildAudioCVT(&cvt, AUDIO_S16, chan, samplerate, JA_format, JA_channels, JA_freq);
if (cvt.needed) SDL_Log("Music length: %f\n", float(music->samples)/float(JA_freq));
{ if (cvt.needed) {
cvt.len = music->samples * chan * 2; cvt.len = music->samples * chan * 2;
cvt.buf = (Uint8 *)SDL_malloc(cvt.len * cvt.len_mult); music->length = cvt.len;
cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult);
SDL_memcpy(cvt.buf, music->output, cvt.len); SDL_memcpy(cvt.buf, music->output, cvt.len);
SDL_ConvertAudio(&cvt); SDL_ConvertAudio(&cvt);
free(music->output); free(music->output);
music->output = (short *)cvt.buf; music->output = (short*)cvt.buf;
} }
music->length = music->samples * chan * 2;
music->pos = 0; music->pos = 0;
music->state = JA_MUSIC_STOPPED; music->state = JA_MUSIC_STOPPED;
return music; return music;
} }
JA_Music_t *JA_LoadMusic(const char* filename)
{
// [RZC 28/08/22] Carreguem primer el arxiu en memòria i després el descomprimim. Es algo més rapid.
FILE *f = fopen(filename, "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
Uint8 *buffer = (Uint8*)malloc(fsize + 1);
if (fread(buffer, fsize, 1, f)!=1) return NULL;
fclose(f);
JA_Music_t *music = JA_LoadMusic(buffer, fsize);
free(buffer);
return music;
}
void JA_PlayMusic(JA_Music_t *music, const int loop) void JA_PlayMusic(JA_Music_t *music, const int loop)
{ {
if (!JA_musicEnabled || !music) if (!JA_musicEnabled) return;
return;
if (current_music != NULL) if (current_music != NULL) {
{
current_music->pos = 0; current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
} }
@@ -169,78 +185,108 @@ void JA_PlayMusic(JA_Music_t *music, const int loop)
void JA_PauseMusic() void JA_PauseMusic()
{ {
if (!JA_musicEnabled) if (!JA_musicEnabled) return;
return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
return;
current_music->state = JA_MUSIC_PAUSED; current_music->state = JA_MUSIC_PAUSED;
} }
void JA_ResumeMusic() void JA_ResumeMusic()
{ {
if (!JA_musicEnabled) if (!JA_musicEnabled) return;
return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
return;
current_music->state = JA_MUSIC_PLAYING; current_music->state = JA_MUSIC_PLAYING;
} }
void JA_StopMusic() void JA_StopMusic()
{ {
if (!JA_musicEnabled) if (!JA_musicEnabled) return;
return;
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
return;
current_music->pos = 0; current_music->pos = 0;
current_music->state = JA_MUSIC_STOPPED; current_music->state = JA_MUSIC_STOPPED;
} }
JA_Music_state JA_GetMusicState() void JA_FadeOutMusic(const int milliseconds)
{ {
if (!JA_musicEnabled) if (!JA_musicEnabled) return;
return JA_MUSIC_DISABLED; if (current_music == NULL || current_music->state == JA_MUSIC_INVALID) return;
if (current_music == NULL) fading = true;
return JA_MUSIC_INVALID; fade_start_time = SDL_GetTicks();
fade_duration = milliseconds;
fade_initial_volume = JA_musicVolume;
}
JA_Music_state JA_GetMusicState() {
if (!JA_musicEnabled) return JA_MUSIC_DISABLED;
if (current_music == NULL) return JA_MUSIC_INVALID;
return current_music->state; return current_music->state;
} }
void JA_DeleteMusic(JA_Music_t *music) void JA_DeleteMusic(JA_Music_t *music) {
{ if (current_music == music) current_music = NULL;
if (current_music == music)
current_music = NULL;
free(music->output); free(music->output);
delete music; delete music;
} }
int JA_SetMusicVolume(int volume) int JA_SetMusicVolume(int volume)
{ {
JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume;
: volume;
return JA_musicVolume; return JA_musicVolume;
} }
void JA_SetMusicPosition(float value)
{
if (!current_music) return;
current_music->pos = value * JA_freq;
}
float JA_GetMusicPosition()
{
if (!current_music) return 0;
return float(current_music->pos)/float(JA_freq);
}
void JA_EnableMusic(const bool value) void JA_EnableMusic(const bool value)
{ {
if (!value && current_music != NULL && current_music->state == JA_MUSIC_PLAYING) if (!value && current_music != NULL && current_music->state==JA_MUSIC_PLAYING) JA_StopMusic();
JA_StopMusic();
JA_musicEnabled = value; JA_musicEnabled = value;
} }
JA_Sound_t *JA_NewSound(Uint8 *buffer, Uint32 length)
{
JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length) {
JA_Sound_t *sound = new JA_Sound_t(); JA_Sound_t *sound = new JA_Sound_t();
sound->buffer = buffer; sound->buffer = buffer;
sound->length = length; sound->length = length;
return sound; return sound;
} }
JA_Sound_t *JA_LoadSound(const char *filename) JA_Sound_t *JA_LoadSound(uint8_t* buffer, uint32_t size) {
{ JA_Sound_t *sound = new JA_Sound_t();
SDL_AudioSpec wavSpec;
SDL_LoadWAV_RW(SDL_RWFromMem(buffer, size),1, &wavSpec, &sound->buffer, &sound->length);
SDL_AudioCVT cvt;
SDL_BuildAudioCVT(&cvt, wavSpec.format, wavSpec.channels, wavSpec.freq, JA_format, JA_channels, JA_freq);
cvt.len = sound->length;
cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult);
SDL_memcpy(cvt.buf, sound->buffer, sound->length);
SDL_ConvertAudio(&cvt);
SDL_FreeWAV(sound->buffer);
sound->buffer = cvt.buf;
sound->length = cvt.len_cvt;
return sound;
}
JA_Sound_t *JA_LoadSound(const char* filename) {
JA_Sound_t *sound = new JA_Sound_t(); JA_Sound_t *sound = new JA_Sound_t();
SDL_AudioSpec wavSpec; SDL_AudioSpec wavSpec;
SDL_LoadWAV(filename, &wavSpec, &sound->buffer, &sound->length); SDL_LoadWAV(filename, &wavSpec, &sound->buffer, &sound->length);
@@ -248,7 +294,7 @@ JA_Sound_t *JA_LoadSound(const char *filename)
SDL_AudioCVT cvt; SDL_AudioCVT cvt;
SDL_BuildAudioCVT(&cvt, wavSpec.format, wavSpec.channels, wavSpec.freq, JA_format, JA_channels, JA_freq); SDL_BuildAudioCVT(&cvt, wavSpec.format, wavSpec.channels, wavSpec.freq, JA_format, JA_channels, JA_freq);
cvt.len = sound->length; cvt.len = sound->length;
cvt.buf = (Uint8 *)SDL_malloc(cvt.len * cvt.len_mult); cvt.buf = (Uint8 *) SDL_malloc(cvt.len * cvt.len_mult);
SDL_memcpy(cvt.buf, sound->buffer, sound->length); SDL_memcpy(cvt.buf, sound->buffer, sound->length);
SDL_ConvertAudio(&cvt); SDL_ConvertAudio(&cvt);
SDL_FreeWAV(sound->buffer); SDL_FreeWAV(sound->buffer);
@@ -260,16 +306,24 @@ JA_Sound_t *JA_LoadSound(const char *filename)
int JA_PlaySound(JA_Sound_t *sound, const int loop) int JA_PlaySound(JA_Sound_t *sound, const int loop)
{ {
if (!JA_soundEnabled || !sound) if (!JA_soundEnabled) return -1;
return 0;
int channel = 0; int channel = 0;
while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) while (channel < JA_MAX_SIMULTANEOUS_CHANNELS && channels[channel].state != JA_CHANNEL_FREE) { channel++; }
{ if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) channel = 0;
channel++;
} channels[channel].sound = sound;
if (channel == JA_MAX_SIMULTANEOUS_CHANNELS) channels[channel].times = loop;
channel = 0; channels[channel].pos = 0;
channels[channel].state = JA_CHANNEL_PLAYING;
return channel;
}
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop)
{
if (!JA_soundEnabled) return -1;
if (channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return -1;
channels[channel].sound = sound; channels[channel].sound = sound;
channels[channel].times = loop; channels[channel].times = loop;
@@ -280,10 +334,8 @@ int JA_PlaySound(JA_Sound_t *sound, const int loop)
void JA_DeleteSound(JA_Sound_t *sound) void JA_DeleteSound(JA_Sound_t *sound)
{ {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
{ if (channels[i].sound == sound) JA_StopChannel(i);
if (channels[i].sound == sound)
JA_StopChannel(i);
} }
SDL_free(sound->buffer); SDL_free(sound->buffer);
delete sound; delete sound;
@@ -291,60 +343,41 @@ void JA_DeleteSound(JA_Sound_t *sound)
void JA_PauseChannel(const int channel) void JA_PauseChannel(const int channel)
{ {
if (!JA_soundEnabled) if (!JA_soundEnabled) return;
return;
if (channel == -1) if (channel == -1) {
{ for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) if (channels[i].state == JA_CHANNEL_PLAYING) channels[i].state = JA_CHANNEL_PAUSED;
{
if (channels[i].state == JA_CHANNEL_PLAYING)
channels[i].state = JA_CHANNEL_PAUSED;
} }
} } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) if (channels[channel].state == JA_CHANNEL_PLAYING) channels[channel].state = JA_CHANNEL_PAUSED;
{
if (channels[channel].state == JA_CHANNEL_PLAYING)
channels[channel].state = JA_CHANNEL_PAUSED;
} }
} }
void JA_ResumeChannel(const int channel) void JA_ResumeChannel(const int channel)
{ {
if (!JA_soundEnabled) if (!JA_soundEnabled) return;
return;
if (channel == -1) if (channel == -1) {
{ for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) if (channels[i].state == JA_CHANNEL_PAUSED) channels[i].state = JA_CHANNEL_PLAYING;
{
if (channels[i].state == JA_CHANNEL_PAUSED)
channels[i].state = JA_CHANNEL_PLAYING;
} }
} } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) if (channels[channel].state == JA_CHANNEL_PAUSED) channels[channel].state = JA_CHANNEL_PLAYING;
{
if (channels[channel].state == JA_CHANNEL_PAUSED)
channels[channel].state = JA_CHANNEL_PLAYING;
} }
} }
void JA_StopChannel(const int channel) void JA_StopChannel(const int channel)
{ {
if (!JA_soundEnabled) if (!JA_soundEnabled) return;
return;
if (channel == -1) if (channel == -1) {
{ for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{
channels[i].state = JA_CHANNEL_FREE; channels[i].state = JA_CHANNEL_FREE;
channels[i].pos = 0; channels[i].pos = 0;
channels[i].sound = NULL; channels[i].sound = NULL;
} }
} } else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS) {
else if (channel >= 0 && channel < JA_MAX_SIMULTANEOUS_CHANNELS)
{
channels[channel].state = JA_CHANNEL_FREE; channels[channel].state = JA_CHANNEL_FREE;
channels[channel].pos = 0; channels[channel].pos = 0;
channels[channel].sound = NULL; channels[channel].sound = NULL;
@@ -353,18 +386,15 @@ void JA_StopChannel(const int channel)
JA_Channel_state JA_GetChannelState(const int channel) JA_Channel_state JA_GetChannelState(const int channel)
{ {
if (!JA_soundEnabled) if (!JA_soundEnabled) return JA_SOUND_DISABLED;
return JA_SOUND_DISABLED;
if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) if (channel < 0 || channel >= JA_MAX_SIMULTANEOUS_CHANNELS) return JA_CHANNEL_INVALID;
return JA_CHANNEL_INVALID;
return channels[channel].state; return channels[channel].state;
} }
int JA_SetSoundVolume(int volume) int JA_SetSoundVolume(int volume)
{ {
JA_soundVolume = volume > 128 ? 128 : volume < 0 ? 0 JA_soundVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume;
: volume;
return JA_soundVolume; return JA_soundVolume;
} }
@@ -372,17 +402,15 @@ void JA_EnableSound(const bool value)
{ {
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
{ {
if (channels[i].state == JA_CHANNEL_PLAYING) if (channels[i].state == JA_CHANNEL_PLAYING) JA_StopChannel(i);
JA_StopChannel(i);
} }
JA_soundEnabled = value; JA_soundEnabled = value;
} }
int JA_SetVolume(int volume) int JA_SetVolume(int volume)
{ {
JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0 : volume;
: volume; JA_soundVolume = JA_musicVolume/2;
JA_soundVolume = JA_musicVolume / 2;
return JA_musicVolume; return JA_musicVolume;
} }

View File

@@ -1,43 +1,34 @@
#pragma once #pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h> // para SDL_AudioFormat enum JA_Channel_state { JA_CHANNEL_INVALID, JA_CHANNEL_FREE, JA_CHANNEL_PLAYING, JA_CHANNEL_PAUSED, JA_SOUND_DISABLED };
#include <SDL2/SDL_stdinc.h> // para Uint32, Uint8 enum JA_Music_state { JA_MUSIC_INVALID, JA_MUSIC_PLAYING, JA_MUSIC_PAUSED, JA_MUSIC_STOPPED, JA_MUSIC_DISABLED };
struct JA_Music_t; // lines 5-5
struct JA_Sound_t; // lines 6-6
enum JA_Channel_state struct JA_Sound_t;
{ struct JA_Music_t;
JA_CHANNEL_INVALID,
JA_CHANNEL_FREE,
JA_CHANNEL_PLAYING,
JA_CHANNEL_PAUSED,
JA_SOUND_DISABLED
};
enum JA_Music_state
{
JA_MUSIC_INVALID,
JA_MUSIC_PLAYING,
JA_MUSIC_PAUSED,
JA_MUSIC_STOPPED,
JA_MUSIC_DISABLED
};
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels); void JA_Init(const int freq, const SDL_AudioFormat format, const int channels);
void JA_Quit(); void JA_Quit();
JA_Music_t *JA_LoadMusic(const char *filename); JA_Music_t *JA_LoadMusic(const char* filename);
JA_Music_t *JA_LoadMusic(Uint8* buffer, Uint32 length);
void JA_PlayMusic(JA_Music_t *music, const int loop = -1); void JA_PlayMusic(JA_Music_t *music, const int loop = -1);
void JA_PauseMusic(); void JA_PauseMusic();
void JA_ResumeMusic(); void JA_ResumeMusic();
void JA_StopMusic(); void JA_StopMusic();
void JA_FadeOutMusic(const int milliseconds);
JA_Music_state JA_GetMusicState(); JA_Music_state JA_GetMusicState();
void JA_DeleteMusic(JA_Music_t *music); void JA_DeleteMusic(JA_Music_t *music);
int JA_SetMusicVolume(int volume); int JA_SetMusicVolume(int volume);
void JA_SetMusicPosition(float value);
float JA_GetMusicPosition();
void JA_EnableMusic(const bool value); void JA_EnableMusic(const bool value);
JA_Sound_t *JA_NewSound(Uint8 *buffer, Uint32 length); JA_Sound_t *JA_NewSound(Uint8* buffer, Uint32 length);
JA_Sound_t *JA_LoadSound(const char *filename); JA_Sound_t *JA_LoadSound(Uint8* buffer, Uint32 length);
JA_Sound_t *JA_LoadSound(const char* filename);
int JA_PlaySound(JA_Sound_t *sound, const int loop = 0); int JA_PlaySound(JA_Sound_t *sound, const int loop = 0);
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop = 0);
void JA_PauseChannel(const int channel); void JA_PauseChannel(const int channel);
void JA_ResumeChannel(const int channel); void JA_ResumeChannel(const int channel);
void JA_StopChannel(const int channel); void JA_StopChannel(const int channel);

View File

@@ -59,7 +59,7 @@ Logo::~Logo()
{ {
jail_texture_->setColor(255, 255, 255); jail_texture_->setColor(255, 255, 255);
since_texture_->setColor(255, 255, 255); since_texture_->setColor(255, 255, 255);
JA_PauseChannel(-1); JA_StopChannel(-1);
} }
// Recarga todas las texturas // Recarga todas las texturas
@@ -101,7 +101,6 @@ void Logo::checkInput()
// Comprueba si se ha pulsado cualquier botón (de los usados para jugar) // Comprueba si se ha pulsado cualquier botón (de los usados para jugar)
if (Input::get()->checkAnyButtonPressed()) if (Input::get()->checkAnyButtonPressed())
{ {
JA_StopMusic();
section::name = section::Name::TITLE; section::name = section::Name::TITLE;
section::options = section::Options::TITLE_1; section::options = section::Options::TITLE_1;
return; return;
@@ -235,7 +234,7 @@ void Logo::render()
void Logo::run() void Logo::run()
{ {
// Detiene la música // Detiene la música
JA_StopMusic(); JA_FadeOutMusic(300);
while (section::name == section::Name::LOGO) while (section::name == section::Name::LOGO)
{ {

View File

@@ -23,7 +23,8 @@ enum class GameDifficulty
// Estructura para las opciones de la ventana // Estructura para las opciones de la ventana
struct OptionsWindow struct OptionsWindow
{ {
int size; // Contiene el valor por el que se multiplica el tamaño de la ventana int size = 1; // Contiene el valor por el que se multiplica el tamaño de la ventana
int max_size = 1; // Tamaño máximo para que el tamaño de la ventana no sea mayor que el tamaño de la pantalla
}; };
// Estructura con opciones para el video // Estructura con opciones para el video

View File

@@ -8,6 +8,8 @@
#include "param.h" // Para Param, ParamGame, param #include "param.h" // Para Param, ParamGame, param
#include "scoreboard.h" // Para Scoreboard, ScoreboardMode #include "scoreboard.h" // Para Scoreboard, ScoreboardMode
#include "texture.h" // Para Texture #include "texture.h" // Para Texture
#include "resource.h"
#include "jail_audio.h"
// Constructor // Constructor
Player::Player(int id, float x, int y, bool demo, SDL_Rect &play_area, std::vector<std::shared_ptr<Texture>> texture, const std::vector<std::vector<std::string>> &animations) Player::Player(int id, float x, int y, bool demo, SDL_Rect &play_area, std::vector<std::shared_ptr<Texture>> texture, const std::vector<std::vector<std::string>> &animations)
@@ -175,6 +177,7 @@ void Player::move()
if ((player_sprite_->getPosX() < play_area_.x) || (player_sprite_->getPosX() + WIDTH_ > play_area_.w)) if ((player_sprite_->getPosX() < play_area_.x) || (player_sprite_->getPosX() + WIDTH_ > play_area_.w))
{ {
player_sprite_->setVelX(-player_sprite_->getVelX()); player_sprite_->setVelX(-player_sprite_->getVelX());
JA_PlaySound(Resource::get()->getSound("bubble4.wav"));
} }
// Si el cadaver toca el suelo cambia el estado // Si el cadaver toca el suelo cambia el estado
@@ -188,6 +191,7 @@ void Player::move()
pos_y_ = default_pos_y_; pos_y_ = default_pos_y_;
player_sprite_->clear(); player_sprite_->clear();
shiftSprite(); shiftSprite();
JA_PlaySound(Resource::get()->getSound("bubble4.wav"));
} }
else else
{ {
@@ -195,6 +199,7 @@ void Player::move()
player_sprite_->setPosY(play_area_.h - HEIGHT_); player_sprite_->setPosY(play_area_.h - HEIGHT_);
player_sprite_->setVelY(player_sprite_->getVelY() * -0.5f); player_sprite_->setVelY(player_sprite_->getVelY() * -0.5f);
player_sprite_->setVelX(player_sprite_->getVelX() * 0.75f); player_sprite_->setVelX(player_sprite_->getVelX() * 0.75f);
JA_PlaySound(Resource::get()->getSound("bubble4.wav"));
} }
} }
break; break;

View File

@@ -290,7 +290,7 @@ void Resource::createTextures()
NameAndText("game_text_powerup", lang::getText(117)), NameAndText("game_text_powerup", lang::getText(117)),
NameAndText("game_text_one_hit", lang::getText(118)), NameAndText("game_text_one_hit", lang::getText(118)),
NameAndText("game_text_stop", lang::getText(119)), NameAndText("game_text_stop", lang::getText(119)),
NameAndText("1000000_points", lang::getText(76))}; NameAndText("game_text_1000000_points", lang::getText(76))};
auto text = getText("04b_25"); auto text = getText("04b_25");
for (const auto &s : strings) for (const auto &s : strings)
@@ -301,10 +301,10 @@ void Resource::createTextures()
// Tamaño doble // Tamaño doble
std::vector<NameAndText> strings2X = { std::vector<NameAndText> strings2X = {
NameAndText("get_ready", lang::getText(75)), NameAndText("game_text_get_ready", lang::getText(75)),
NameAndText("last_stage", lang::getText(79)), NameAndText("game_text_last_stage", lang::getText(79)),
NameAndText("congratulations", lang::getText(50)), NameAndText("game_text_congratulations", lang::getText(50)),
NameAndText("game_over", "Game Over")}; NameAndText("game_text_game_over", "Game Over")};
auto text2 = getText("04b_25_2x"); auto text2 = getText("04b_25_2x");
for (const auto &s : strings2X) for (const auto &s : strings2X)

View File

@@ -235,7 +235,7 @@ void Screen::decWindowSize()
void Screen::incWindowSize() void Screen::incWindowSize()
{ {
++options.video.window.size; ++options.video.window.size;
options.video.window.size = std::min(options.video.window.size, 4); options.video.window.size = std::min(options.video.window.size, options.video.window.max_size);
setVideoMode(ScreenVideoMode::WINDOW); setVideoMode(ScreenVideoMode::WINDOW);
} }
@@ -308,15 +308,15 @@ void Screen::updateShakeEffect()
} }
// Pone la pantalla de color // Pone la pantalla de color
void Screen::flash(Color color, int lenght) void Screen::flash(Color color, int lenght, int delay)
{ {
flash_effect_ = FlashEffect(true, lenght, color); flash_effect_ = FlashEffect(true, lenght, delay, color);
} }
// Actualiza y dibuja el efecto de flash en la pantalla // Actualiza y dibuja el efecto de flash en la pantalla
void Screen::renderFlash() void Screen::renderFlash()
{ {
if (flash_effect_.enabled) if (flash_effect_.isRendarable())
{ {
SDL_SetRenderDrawColor(renderer_, flash_effect_.color.r, flash_effect_.color.g, flash_effect_.color.b, 0xFF); SDL_SetRenderDrawColor(renderer_, flash_effect_.color.r, flash_effect_.color.g, flash_effect_.color.b, 0xFF);
SDL_RenderClear(renderer_); SDL_RenderClear(renderer_);
@@ -326,10 +326,7 @@ void Screen::renderFlash()
// Actualiza el efecto de flash // Actualiza el efecto de flash
void Screen::updateFlash() void Screen::updateFlash()
{ {
if (flash_effect_.enabled) flash_effect_.update();
{
flash_effect_.counter > 0 ? flash_effect_.counter-- : flash_effect_.enabled = false;
}
} }
// Atenua la pantalla // Atenua la pantalla

View File

@@ -51,12 +51,20 @@ private:
struct FlashEffect struct FlashEffect
{ {
bool enabled; // Indica si el efecto está activo bool enabled; // Indica si el efecto está activo
int lenght; // Duración del efecto
int delay; // Frames iniciales en los que no se aplica
int counter; // Contador para el efecto int counter; // Contador para el efecto
Color color; // Color del efecto Color color; // Color del efecto
// Constructor // Constructor
explicit FlashEffect(bool en = false, int cnt = 0, Color col = Color(0xFF, 0xFF, 0xFF)) explicit FlashEffect(bool enabled = false, int lenght = 0, int delay = 0, Color color = Color(0xFF, 0xFF, 0xFF))
: enabled(en), counter(cnt), color(col) {} : enabled(enabled), lenght(lenght), delay(delay), counter(lenght), color(color) {}
// Actualiza
void update() { (enabled && counter > 0) ? counter-- : enabled = false; }
// Indica si se pude dibujar
bool isRendarable() { return enabled && counter < lenght - delay; }
}; };
struct ShakeEffect struct ShakeEffect
@@ -155,7 +163,7 @@ public:
void shake(); void shake();
// Pone la pantalla de color // Pone la pantalla de color
void flash(Color color, int lenght); void flash(Color color, int lenght, int delay = 0);
// Activa / desactiva los shaders // Activa / desactiva los shaders
void toggleShaders(); void toggleShaders();

145
source/tabe.cpp Normal file
View File

@@ -0,0 +1,145 @@
#include "tabe.h"
#include "resource.h"
#include "param.h"
#include "jail_audio.h"
#include <algorithm>
// Constructor
Tabe::Tabe()
: sprite_(std::make_unique<AnimatedSprite>(Resource::get()->getTexture("tabe.png"), Resource::get()->getAnimation("tabe.ani"))) {}
// Actualiza la lógica
void Tabe::update()
{
if (enabled_)
{
sprite_->update();
move();
}
}
// Dibuja el objeto
void Tabe::render()
{
if (enabled_)
{
sprite_->render();
}
}
// Mueve el objeto
void Tabe::move()
{
const int x = static_cast<int>(x_);
speed_ += accel_;
x_ += speed_;
fly_distance_ -= std::abs(x - static_cast<int>(x_));
// Comprueba si sale por los bordes
const float min_x = param.game.game_area.rect.x - WIDTH_;
const float max_x = param.game.game_area.rect.x + param.game.game_area.rect.w;
switch (destiny_)
{
case TabeDirection::TO_THE_LEFT:
{
if (x_ < min_x)
{
enabled_ = false;
}
if (x_ > param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_ && direction_ == TabeDirection::TO_THE_RIGHT)
{
setRandomFlyPath(TabeDirection::TO_THE_LEFT, 80);
x_ = param.game.game_area.rect.x + param.game.game_area.rect.w - WIDTH_;
}
break;
}
case TabeDirection::TO_THE_RIGHT:
{
if (x_ > max_x)
{
enabled_ = false;
}
if (x_ < param.game.game_area.rect.x && direction_ == TabeDirection::TO_THE_LEFT)
{
setRandomFlyPath(TabeDirection::TO_THE_RIGHT, 80);
x_ = param.game.game_area.rect.x;
}
break;
}
default:
break;
}
if (fly_distance_ <= 0)
{
if (waiting_counter_ > 0)
{
accel_ = speed_ = 0.0f;
--waiting_counter_;
}
else
{
constexpr int CHOICES = 4;
const TabeDirection left[CHOICES] = {TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_RIGHT};
const TabeDirection right[CHOICES] = {TabeDirection::TO_THE_LEFT, TabeDirection::TO_THE_RIGHT, TabeDirection::TO_THE_RIGHT, TabeDirection::TO_THE_RIGHT};
const TabeDirection direction = destiny_ == TabeDirection::TO_THE_LEFT ? left[rand() % CHOICES] : right[rand() % CHOICES];
setRandomFlyPath(direction, 20 + rand() % 40);
}
}
shiftSprite();
}
// Habilita el objeto
void Tabe::enable()
{
if (!enabled_)
{
enabled_ = true;
y_ = 20.0f;
// Establece una dirección aleatoria
destiny_ = direction_ = rand() % 2 == 0 ? TabeDirection::TO_THE_LEFT : TabeDirection::TO_THE_RIGHT;
// Establece la posición inicial
x_ = (direction_ == TabeDirection::TO_THE_LEFT) ? param.game.game_area.rect.x + param.game.game_area.rect.w : param.game.game_area.rect.x - WIDTH_;
// Crea una ruta de vuelo
setRandomFlyPath(direction_, 60);
shiftSprite();
}
}
// Establece un vuelo aleatorio
void Tabe::setRandomFlyPath(TabeDirection direction, int lenght)
{
direction_ = direction;
fly_distance_ = lenght;
waiting_counter_ = 5 + rand() % 15;
JA_PlaySound(Resource::get()->getSound("tabe.wav"));
constexpr float SPEED = 2.0f;
switch (direction)
{
case TabeDirection::TO_THE_LEFT:
{
speed_ = -1.0f * SPEED;
accel_ = -1.0f * (1 + rand() % 10) / 30.0f;
sprite_->setFlip(SDL_FLIP_NONE);
break;
}
case TabeDirection::TO_THE_RIGHT:
{
speed_ = SPEED;
accel_ = (1 + rand() % 10) / 30.0f;
sprite_->setFlip(SDL_FLIP_HORIZONTAL);
break;
}
default:
break;
}
}

58
source/tabe.h Normal file
View File

@@ -0,0 +1,58 @@
#pragma once
#include "animated_sprite.h"
#include <memory>
enum class TabeDirection : int
{
TO_THE_LEFT = 0,
TO_THE_RIGHT = 1,
};
// Clase Tabe
class Tabe
{
private:
// Constantes
static constexpr int WIDTH_ = 32;
static constexpr int HEIGHT_ = 32;
// Punteros
std::unique_ptr<AnimatedSprite> sprite_; // Sprite con los graficos y animaciones
// Variables
float x_ = 0; // Posición del objeto
float y_ = 0; // Posición del objeto
float speed_ = 0.0f; // Velocidad de movimiento del objeto
float accel_ = 0.0f; // Aceleración del objeto
int fly_distance_ = 0; // Distancia de vuelo
int waiting_counter_ = 0; // Tiempo que pasa quieto el objeto
bool enabled_ = false; // Indica si el objeto está activo
TabeDirection direction_; // Dirección del objeto
TabeDirection destiny_; // Destino del objeto
// Mueve el objeto
void move();
// Actualiza la posición del sprite
void shiftSprite() { sprite_->setPos(x_, y_); }
// Establece un vuelo aleatorio
void setRandomFlyPath(TabeDirection direction, int lenght);
public:
// Constructor
Tabe();
// Destructor
~Tabe() = default;
// Actualiza la lógica
void update();
// Dibuja el objeto
void render();
// Habilita el objeto
void enable();
};

View File

@@ -161,12 +161,14 @@ std::shared_ptr<Texture> Text::writeToTexture(const std::string &text, int zoom,
auto texture = std::make_shared<Texture>(renderer); auto texture = std::make_shared<Texture>(renderer);
auto width = lenght(text, kerning) * zoom; auto width = lenght(text, kerning) * zoom;
auto height = box_height_ * zoom; auto height = box_height_ * zoom;
auto temp = SDL_GetRenderTarget(renderer);
texture->createBlank(width, height, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET); texture->createBlank(width, height, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET);
texture->setBlendMode(SDL_BLENDMODE_BLEND); texture->setBlendMode(SDL_BLENDMODE_BLEND);
texture->setAsRenderTarget(renderer); texture->setAsRenderTarget(renderer);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
zoom == 1 ? write(0, 0, text, kerning) : write2X(0, 0, text, kerning); zoom == 1 ? write(0, 0, text, kerning) : write2X(0, 0, text, kerning);
SDL_SetRenderTarget(renderer, temp);
return texture; return texture;
} }

View File

@@ -31,9 +31,10 @@ Title::Title()
fade_(std::make_unique<Fade>()), fade_(std::make_unique<Fade>()),
tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::RANDOM)), tiled_bg_(std::make_unique<TiledBG>(param.game.game_area.rect, TiledBGMode::RANDOM)),
game_logo_(std::make_unique<GameLogo>(param.game.game_area.center_x, param.title.title_c_c_position)), game_logo_(std::make_unique<GameLogo>(param.game.game_area.center_x, param.title.title_c_c_position)),
mini_logo_sprite_(std::make_unique<Sprite>(Resource::get()->getTexture("logo_jailgames_mini.png"))), mini_logo_sprite_(std::make_unique<Sprite>(Resource::get()->getTexture("logo_jailgames_mini.png"))),
define_buttons_(std::make_unique<DefineButtons>()), define_buttons_(std::make_unique<DefineButtons>()),
num_controllers_(Input::get()->getNumControllers()) num_controllers_(Input::get()->getNumControllers()),
state_(TitleState::LOGO_ANIMATING)
{ {
// Configura objetos // Configura objetos
game_logo_->enable(); game_logo_->enable();
@@ -54,6 +55,7 @@ Title::Title()
Title::~Title() Title::~Title()
{ {
Resource::get()->getTexture("smb2.gif")->setPalette(0); Resource::get()->getTexture("smb2.gif")->setPalette(0);
JA_StopChannel(-1);
} }
// Actualiza las variables del objeto // Actualiza las variables del objeto
@@ -70,9 +72,9 @@ void Title::update()
Screen::get()->update(); Screen::get()->update();
// Actualiza las variables de globalInputs // Actualiza las variables de globalInputs
globalInputs::update(); globalInputs::update();
// Comprueba el fundido y si se ha acabado // Comprueba el fundido
fade_->update(); fade_->update();
if (fade_->hasEnded()) if (fade_->hasEnded())
{ {
@@ -88,18 +90,19 @@ void Title::update()
} }
} }
// Sección 1 - Titulo animandose // Establece la lógica según el estado
if (section::options == section::Options::TITLE_1) switch (state_)
{
case TitleState::LOGO_ANIMATING:
{ {
game_logo_->update(); game_logo_->update();
if (game_logo_->hasFinished()) if (game_logo_->hasFinished())
{ {
section::options = section::Options::TITLE_2; state_ = TitleState::LOGO_FINISHED;
} }
break;
} }
case TitleState::LOGO_FINISHED:
// Sección 2 - La pantalla con el titulo, el fondo animado y la música
else if (section::options == section::Options::TITLE_2)
{ {
// El contador solo sube si no estamos definiendo botones // El contador solo sube si no estamos definiendo botones
counter_ = define_buttons_->isEnabled() ? 0 : counter_ + 1; counter_ = define_buttons_->isEnabled() ? 0 : counter_ + 1;
@@ -121,6 +124,27 @@ void Title::update()
fade_->activate(); fade_->activate();
post_fade_ = -1; post_fade_ = -1;
} }
break;
}
case TitleState::START_HAS_BEEN_PRESSED:
{
// Actualiza el logo con el título del juego
game_logo_->update();
// Actualiza el mosaico de fondo
tiled_bg_->update();
if (counter_ == 100)
{
fade_->activate();
}
++counter_;
break;
}
default:
break;
} }
} }
} }
@@ -140,16 +164,10 @@ void Title::render()
// Dibuja el logo con el título del juego // Dibuja el logo con el título del juego
game_logo_->render(); game_logo_->render();
if (section::options == section::Options::TITLE_2) constexpr Color shadow = Color(0x14, 0x87, 0xc4);
if (state_ != TitleState::LOGO_ANIMATING)
{ {
constexpr Color shadow = Color(0x14, 0x87, 0xc4);
// 'PRESS TO PLAY'
if (counter_ % 50 > 14 && !define_buttons_->isEnabled())
{
text_->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, param.title.press_start_position, lang::getText(23), 1, no_color, 1, shadow);
}
// Mini logo // Mini logo
const int pos1 = (param.game.height / 5 * 4) + BLOCK; const int pos1 = (param.game.height / 5 * 4) + BLOCK;
const int pos2 = pos1 + mini_logo_sprite_->getHeight() + 3; const int pos2 = pos1 + mini_logo_sprite_->getHeight() + 3;
@@ -160,6 +178,24 @@ void Title::render()
text_->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, pos2, TEXT_COPYRIGHT, 1, no_color, 1, shadow); text_->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, pos2, TEXT_COPYRIGHT, 1, no_color, 1, shadow);
} }
if (state_ == TitleState::LOGO_FINISHED)
{
// 'PRESS TO PLAY'
if (counter_ % 50 > 14 && !define_buttons_->isEnabled())
{
text_->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, param.title.press_start_position, lang::getText(23), 1, no_color, 1, shadow);
}
}
if (state_ == TitleState::START_HAS_BEEN_PRESSED)
{
// 'PRESS TO PLAY'
if (counter_ % 10 > 4 && !define_buttons_->isEnabled())
{
text_->writeDX(TEXT_CENTER | TEXT_SHADOW, param.game.game_area.center_x, param.title.press_start_position, lang::getText(23), 1, no_color, 1, shadow);
}
}
// Define Buttons // Define Buttons
define_buttons_->render(); define_buttons_->render();
@@ -241,24 +277,28 @@ void Title::checkEvents()
// Comprueba las entradas // Comprueba las entradas
void Title::checkInput() void Title::checkInput()
{ {
// Comprueba los controladores solo si no se estan definiendo los botones // Comprueba las entradas solo si no se estan definiendo los botones
if (!define_buttons_->isEnabled()) if (!define_buttons_->isEnabled())
{ {
// Comprueba los métodos de control // Comprueba todos los métodos de control
for (const auto &controller : options.controllers) for (const auto &controller : options.controllers)
{ {
// START
if (Input::get()->checkInput(InputType::START, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index) && if (Input::get()->checkInput(InputType::START, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index) &&
!Input::get()->checkInput(InputType::SERVICE, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index)) !Input::get()->checkInput(InputType::SERVICE, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index))
{ {
if (section::options == section::Options::TITLE_2 || ALLOW_TITLE_ANIMATION_SKIP) if (state_ == TitleState::LOGO_FINISHED || ALLOW_TITLE_ANIMATION_SKIP)
{ {
fade_->activate(); JA_PlaySound(Resource::get()->getSound("game_start.wav"));
JA_FadeOutMusic(1500);
post_fade_ = controller.player_id; post_fade_ = controller.player_id;
state_ = TitleState::START_HAS_BEEN_PRESSED;
counter_ = 0;
return; return;
} }
} }
// Comprueba si se va a intercambiar la asignación de mandos a jugadores // SWAP_CONTROLLERS
if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, controller.type, controller.index) && if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, controller.type, controller.index) &&
Input::get()->checkInput(InputType::SWAP_CONTROLLERS, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index)) Input::get()->checkInput(InputType::SWAP_CONTROLLERS, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index))
{ {
@@ -266,7 +306,7 @@ void Title::checkInput()
return; return;
} }
// Comprueba si algun mando quiere ser configurado // CONFIG
if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, controller.type, controller.index) && if (Input::get()->checkInput(InputType::SERVICE, INPUT_ALLOW_REPEAT, controller.type, controller.index) &&
Input::get()->checkInput(InputType::CONFIG, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index)) Input::get()->checkInput(InputType::CONFIG, INPUT_DO_NOT_ALLOW_REPEAT, controller.type, controller.index))
{ {
@@ -345,7 +385,6 @@ void Title::showControllers()
} }
} }
// std::string spaces(lang::getText(100).length() + 3, ' '); // Muestra la notificación
// std::string kb_text = spaces + lang::getText(69);
Notifier::get()->showText({text.at(0), text.at(1)}); Notifier::get()->showText({text.at(0), text.at(1)});
} }

View File

@@ -18,7 +18,7 @@ namespace section
constexpr const char TEXT_COPYRIGHT[] = "@2020,2024 JailDesigner"; constexpr const char TEXT_COPYRIGHT[] = "@2020,2024 JailDesigner";
// Parámetros // Parámetros
constexpr bool ALLOW_TITLE_ANIMATION_SKIP = true; constexpr bool ALLOW_TITLE_ANIMATION_SKIP = false;
/* /*
Esta clase gestiona un estado del programa. Se encarga de la parte del titulo o menu Esta clase gestiona un estado del programa. Se encarga de la parte del titulo o menu
@@ -27,9 +27,10 @@ constexpr bool ALLOW_TITLE_ANIMATION_SKIP = true;
- Dibujar el tileado de fondo - Dibujar el tileado de fondo
- Redifinir los botones de los mandos de juego - Redifinir los botones de los mandos de juego
Esta clase tiene dos estados: Esta clase tiene tres estados:
- El titulo está animandose, con el fondo estático - El titulo está animandose, con el fondo estático
- El titulo ya está en su sitio y el fondo se está animando - El titulo ya está en su sitio y el fondo se está animando
- Se ha pulsado el botón de start
Por razones de diseño, no se permite saltarse la animación del titulo, aunque es Por razones de diseño, no se permite saltarse la animación del titulo, aunque es
configurable mediante un define configurable mediante un define
@@ -39,6 +40,14 @@ constexpr bool ALLOW_TITLE_ANIMATION_SKIP = true;
class Title class Title
{ {
private: private:
// Enumeraciones
enum class TitleState
{
LOGO_ANIMATING,
LOGO_FINISHED,
START_HAS_BEEN_PRESSED,
};
// Objetos y punteros // Objetos y punteros
std::shared_ptr<Text> text_; // Objeto de texto para poder escribir textos en pantalla std::shared_ptr<Text> text_; // Objeto de texto para poder escribir textos en pantalla
std::unique_ptr<Fade> fade_; // Objeto para realizar fundidos en pantalla std::unique_ptr<Fade> fade_; // Objeto para realizar fundidos en pantalla
@@ -53,6 +62,7 @@ private:
section::Name next_section_; // Indica cual es la siguiente sección a cargar cuando termine el contador del titulo section::Name next_section_; // Indica cual es la siguiente sección a cargar cuando termine el contador del titulo
int post_fade_ = 0; // Opción a realizar cuando termina el fundido int post_fade_ = 0; // Opción a realizar cuando termina el fundido
int num_controllers_; // Número de mandos conectados int num_controllers_; // Número de mandos conectados
TitleState state_; // Estado en el que se encuentra la sección
// Actualiza las variables del objeto // Actualiza las variables del objeto
void update(); void update();