Redistribuits els .cpp en carpetes
Actualitzat cmake Modificats els include de SDL2 a SDL3
This commit is contained in:
21
.clang-format
Normal file
21
.clang-format
Normal file
@@ -0,0 +1,21 @@
|
||||
BasedOnStyle: Google
|
||||
IndentWidth: 4
|
||||
IndentAccessModifiers: true
|
||||
ColumnLimit: 0 # Sin límite de longitud de línea
|
||||
BreakBeforeBraces: Attach # Llaves en la misma línea
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AlignOperands: DontAlign
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
ContinuationIndentWidth: 4
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
Cpp11BracedListStyle: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
PackConstructorInitializers: Never
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
83
.clang-tidy
Normal file
83
.clang-tidy
Normal file
@@ -0,0 +1,83 @@
|
||||
Checks: >
|
||||
readability-*,
|
||||
modernize-*,
|
||||
performance-*,
|
||||
bugprone-unchecked-optional-access,
|
||||
bugprone-sizeof-expression,
|
||||
bugprone-suspicious-missing-comma,
|
||||
bugprone-suspicious-index,
|
||||
bugprone-undefined-memory-manipulation,
|
||||
bugprone-use-after-move,
|
||||
bugprone-out-of-bound-access,
|
||||
-readability-identifier-length,
|
||||
-readability-magic-numbers,
|
||||
-bugprone-narrowing-conversions,
|
||||
-performance-enum-size,
|
||||
-performance-inefficient-string-concatenation,
|
||||
-bugprone-integer-division,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
|
||||
WarningsAsErrors: '*'
|
||||
# Solo incluir archivos de tu código fuente
|
||||
HeaderFilterRegex: '^source/(sections|ui)/.*'
|
||||
FormatStyle: file
|
||||
|
||||
CheckOptions:
|
||||
# Variables locales en snake_case
|
||||
- { key: readability-identifier-naming.VariableCase, value: lower_case }
|
||||
|
||||
# Miembros privados en snake_case con sufijo _
|
||||
- { key: readability-identifier-naming.PrivateMemberCase, value: lower_case }
|
||||
- { key: readability-identifier-naming.PrivateMemberSuffix, value: _ }
|
||||
|
||||
# Miembros protegidos en snake_case con sufijo _
|
||||
- { key: readability-identifier-naming.ProtectedMemberCase, value: lower_case }
|
||||
- { key: readability-identifier-naming.ProtectedMemberSuffix, value: _ }
|
||||
|
||||
# Miembros públicos en snake_case (sin sufijo)
|
||||
- { key: readability-identifier-naming.PublicMemberCase, value: lower_case }
|
||||
|
||||
# Namespaces en CamelCase
|
||||
- { key: readability-identifier-naming.NamespaceCase, value: CamelCase }
|
||||
|
||||
# Variables estáticas privadas como miembros privados
|
||||
- { key: readability-identifier-naming.StaticVariableCase, value: lower_case }
|
||||
- { key: readability-identifier-naming.StaticVariableSuffix, value: _ }
|
||||
|
||||
# Constantes estáticas sin sufijo
|
||||
- { key: readability-identifier-naming.StaticConstantCase, value: UPPER_CASE }
|
||||
|
||||
# Constantes globales en UPPER_CASE
|
||||
- { key: readability-identifier-naming.GlobalConstantCase, value: UPPER_CASE }
|
||||
|
||||
# Variables constexpr globales en UPPER_CASE
|
||||
- { key: readability-identifier-naming.ConstexprVariableCase, value: UPPER_CASE }
|
||||
|
||||
# Constantes locales en UPPER_CASE
|
||||
- { key: readability-identifier-naming.LocalConstantCase, value: UPPER_CASE }
|
||||
|
||||
# Constexpr miembros en UPPER_CASE (sin sufijo)
|
||||
- { key: readability-identifier-naming.ConstexprMemberCase, value: UPPER_CASE }
|
||||
|
||||
# Constexpr miembros privados/protegidos con sufijo _
|
||||
- { key: readability-identifier-naming.ConstexprMethodCase, value: UPPER_CASE }
|
||||
|
||||
# Clases, structs y enums en CamelCase
|
||||
- { key: readability-identifier-naming.ClassCase, value: CamelCase }
|
||||
- { key: readability-identifier-naming.StructCase, value: CamelCase }
|
||||
- { key: readability-identifier-naming.EnumCase, value: CamelCase }
|
||||
|
||||
# Valores de enums en UPPER_CASE
|
||||
- { key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE }
|
||||
|
||||
# Métodos en camelBack (sin sufijos)
|
||||
- { key: readability-identifier-naming.MethodCase, value: camelBack }
|
||||
- { key: readability-identifier-naming.PrivateMethodCase, value: camelBack }
|
||||
- { key: readability-identifier-naming.ProtectedMethodCase, value: camelBack }
|
||||
- { key: readability-identifier-naming.PublicMethodCase, value: camelBack }
|
||||
|
||||
# Funciones en camelBack
|
||||
- { key: readability-identifier-naming.FunctionCase, value: camelBack }
|
||||
|
||||
# Parámetros en lower_case
|
||||
- { key: readability-identifier-naming.ParameterCase, value: lower_case }
|
||||
144
CMakeLists.txt
144
CMakeLists.txt
@@ -3,86 +3,128 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(jaildoctors_dilemma VERSION 1.00)
|
||||
|
||||
# Establece las políticas
|
||||
cmake_policy(SET CMP0072 NEW)
|
||||
|
||||
# Configuración de compilador para MinGW en Windows, si es necesario
|
||||
if(WIN32 AND NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
set(CMAKE_CXX_COMPILER "g++")
|
||||
set(CMAKE_C_COMPILER "gcc")
|
||||
endif()
|
||||
|
||||
# Establecer estándar de C++
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
# Configuración global de flags de compilación
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os -ffunction-sections -fdata-sections")
|
||||
# Establece la política CMP0072 para indicar cómo se debe seleccionar la implementación de OpenGL.
|
||||
# En este caso, se elige la opción "GLVND", que utiliza bibliotecas modernas y modulares (libOpenGL, libGLX),
|
||||
# en lugar de la biblioteca OpenGL clásica (libGL). Esto mejora la compatibilidad con drivers recientes
|
||||
# y evita ambigüedades cuando se encuentran múltiples implementaciones de OpenGL en el sistema.
|
||||
cmake_policy(SET CMP0072 NEW)
|
||||
set(OpenGL_GL_PREFERENCE GLVND)
|
||||
|
||||
# Define el directorio de los archivos fuente
|
||||
set(DIR_SOURCES "${CMAKE_SOURCE_DIR}/source")
|
||||
|
||||
# Cargar todos los archivos fuente en DIR_SOURCES
|
||||
file(GLOB SOURCES "${DIR_SOURCES}/*.cpp")
|
||||
|
||||
# Verificar si se encontraron archivos fuente
|
||||
if(NOT SOURCES)
|
||||
message(FATAL_ERROR "No se encontraron archivos fuente en ${DIR_SOURCES}. Verifica que el directorio existe y contiene archivos .cpp.")
|
||||
endif()
|
||||
|
||||
# Configuración de SDL2
|
||||
find_package(SDL2 REQUIRED)
|
||||
if(SDL2_FOUND)
|
||||
message(STATUS "SDL2 encontrado: ${SDL2_INCLUDE_DIRS}")
|
||||
include_directories(${SDL2_INCLUDE_DIRS})
|
||||
link_directories(${SDL2_LIBDIR})
|
||||
# --- GENERACIÓN DE VERSIÓN AUTOMÁTICA ---
|
||||
find_package(Git QUIET)
|
||||
if(GIT_FOUND)
|
||||
execute_process(
|
||||
COMMAND ${GIT_EXECUTABLE} rev-parse --short=7 HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR "SDL2 no encontrado")
|
||||
set(GIT_HASH "unknown")
|
||||
endif()
|
||||
|
||||
# Incluye rutas de SDL2 obtenidas con pkg-config
|
||||
include_directories(/usr/local/include /usr/local/include/SDL2)
|
||||
link_directories(/usr/local/lib)
|
||||
# Configurar archivo de versión
|
||||
configure_file(${CMAKE_SOURCE_DIR}/source/version.h.in ${CMAKE_BINARY_DIR}/version.h @ONLY)
|
||||
|
||||
# Definir las bibliotecas comunes
|
||||
set(LIBS SDL2)
|
||||
# --- 1. LISTA EXPLÍCITA DE FUENTES ---
|
||||
set(APP_SOURCES
|
||||
source/asset.cpp
|
||||
source/cheevos.cpp
|
||||
source/debug.cpp
|
||||
source/director.cpp
|
||||
source/enemy.cpp
|
||||
source/gif.cpp
|
||||
source/global_events.cpp
|
||||
source/global_inputs.cpp
|
||||
source/input.cpp
|
||||
source/item_tracker.cpp
|
||||
source/item.cpp
|
||||
source/main.cpp
|
||||
source/mouse.cpp
|
||||
source/options.cpp
|
||||
source/player.cpp
|
||||
source/resource.cpp
|
||||
source/room_tracker.cpp
|
||||
source/room.cpp
|
||||
source/scoreboard.cpp
|
||||
source/screen.cpp
|
||||
source/stats.cpp
|
||||
source/surface.cpp
|
||||
source/text.cpp
|
||||
source/texture.cpp
|
||||
source/utils.cpp
|
||||
|
||||
# Configuración común de salida de ejecutables en el directorio raíz
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
source/ui/notifier.cpp
|
||||
|
||||
# Añadir ejecutable principal
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
source/sections/credits.cpp
|
||||
source/sections/ending.cpp
|
||||
source/sections/ending2.cpp
|
||||
source/sections/game_over.cpp
|
||||
source/sections/game.cpp
|
||||
source/sections/loading_screen.cpp
|
||||
source/sections/logo.cpp
|
||||
source/sections/title.cpp
|
||||
|
||||
# Añadir definiciones de compilación dependiendo del tipo de build
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<CONFIG:DEBUG>:DEBUG VERBOSE>)
|
||||
source/sprite/surface_animated_sprite.cpp
|
||||
source/sprite/surface_moving_sprite.cpp
|
||||
source/sprite/surface_sprite.cpp
|
||||
|
||||
# Enlazar bibliotecas
|
||||
target_link_libraries(${PROJECT_NAME} ${LIBS})
|
||||
source/external/jail_audio.cpp
|
||||
source/external/jail_shader.cpp
|
||||
)
|
||||
|
||||
# Configuración de SDL3
|
||||
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3)
|
||||
message(STATUS "SDL3 encontrado: ${SDL3_INCLUDE_DIRS}")
|
||||
|
||||
# --- 2. AÑADIR EJECUTABLE ---
|
||||
add_executable(${PROJECT_NAME} ${APP_SOURCES})
|
||||
|
||||
# --- 3. DIRECTORIOS DE INCLUSIÓN ---
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
"${CMAKE_SOURCE_DIR}/source"
|
||||
"${CMAKE_BINARY_DIR}"
|
||||
)
|
||||
|
||||
# Enlazar la librería SDL3
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE SDL3::SDL3)
|
||||
|
||||
|
||||
# --- 4. CONFIGURACIÓN PLATAFORMAS Y COMPILADOR ---
|
||||
# Configuración de flags de compilación
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall)
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE $<$<CONFIG:RELEASE>:-Os -ffunction-sections -fdata-sections>)
|
||||
|
||||
# Definir _DEBUG en modo Debug
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE $<$<CONFIG:DEBUG>:_DEBUG>)
|
||||
|
||||
# Configuración específica para cada plataforma
|
||||
if(WIN32)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE WINDOWS_BUILD)
|
||||
target_link_libraries(${PROJECT_NAME} mingw32 opengl32 gdi32 winmm imm32 ole32 version)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32 mingw32 opengl32)
|
||||
elseif(APPLE)
|
||||
set(LIBS ${LIBS} "-framework OpenGL")
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE MACOS_BUILD)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated")
|
||||
# Configurar compilación para Apple Silicon
|
||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wno-deprecated)
|
||||
set(CMAKE_OSX_ARCHITECTURES "arm64")
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
set(LIBS ${LIBS} GL)
|
||||
target_compile_definitions(${PROJECT_NAME} PRIVATE LINUX_BUILD)
|
||||
target_link_libraries(${PROJECT_NAME} ${LIBS})
|
||||
endif()
|
||||
|
||||
# Añadir OpenGL a las bibliotecas enlazadas
|
||||
# Configuración común para OpenGL
|
||||
if(NOT WIN32)
|
||||
find_package(OpenGL REQUIRED)
|
||||
if(OPENGL_FOUND)
|
||||
message(STATUS "OpenGL encontrado: ${OPENGL_LIBRARIES}")
|
||||
target_link_libraries(${PROJECT_NAME} ${OPENGL_LIBRARIES})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${OPENGL_LIBRARIES})
|
||||
else()
|
||||
message(FATAL_ERROR "OpenGL no encontrado")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Especificar la ubicación del ejecutable
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR})
|
||||
@@ -1,50 +1,47 @@
|
||||
#include "cheevos.h"
|
||||
#include <SDL2/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL2/SDL_rwops.h> // Para SDL_RWFromFile, SDL_RWclose, SDL_RWwrite
|
||||
|
||||
#include <SDL3/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL3/SDL_rwops.h> // Para SDL_RWFromFile, SDL_RWclose, SDL_RWwrite
|
||||
#include <stddef.h> // Para NULL
|
||||
|
||||
#include <fstream> // Para basic_ostream, operator<<, basic_ofstream
|
||||
#include <iostream> // Para cout, cerr
|
||||
|
||||
#include "notifier.h" // Para Notifier
|
||||
#include "options.h" // Para Options, options
|
||||
|
||||
// [SINGLETON]
|
||||
Cheevos *Cheevos::cheevos_ = nullptr;
|
||||
Cheevos* Cheevos::cheevos_ = nullptr;
|
||||
|
||||
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||
void Cheevos::init(const std::string &file)
|
||||
{
|
||||
void Cheevos::init(const std::string& file) {
|
||||
Cheevos::cheevos_ = new Cheevos(file);
|
||||
}
|
||||
|
||||
// [SINGLETON] Destruiremos el objeto con esta función estática
|
||||
void Cheevos::destroy()
|
||||
{
|
||||
void Cheevos::destroy() {
|
||||
delete Cheevos::cheevos_;
|
||||
}
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
Cheevos *Cheevos::get()
|
||||
{
|
||||
Cheevos* Cheevos::get() {
|
||||
return Cheevos::cheevos_;
|
||||
}
|
||||
|
||||
// Constructor
|
||||
Cheevos::Cheevos(const std::string &file)
|
||||
: file_(file)
|
||||
{
|
||||
Cheevos::Cheevos(const std::string& file)
|
||||
: file_(file) {
|
||||
init();
|
||||
loadFromFile();
|
||||
}
|
||||
|
||||
// Destructor
|
||||
Cheevos::~Cheevos()
|
||||
{
|
||||
Cheevos::~Cheevos() {
|
||||
saveToFile();
|
||||
}
|
||||
|
||||
// Inicializa los logros
|
||||
void Cheevos::init()
|
||||
{
|
||||
void Cheevos::init() {
|
||||
cheevos_list_.clear();
|
||||
cheevos_list_.emplace_back(1, "SHINY THINGS", "Get 25% of the items", 2);
|
||||
cheevos_list_.emplace_back(2, "HALF THE WORK", "Get 50% of the items", 2);
|
||||
@@ -61,12 +58,9 @@ void Cheevos::init()
|
||||
}
|
||||
|
||||
// Busca un logro por id y devuelve el indice
|
||||
int Cheevos::find(int id)
|
||||
{
|
||||
for (int i = 0; i < (int)cheevos_list_.size(); ++i)
|
||||
{
|
||||
if (cheevos_list_[i].id == id)
|
||||
{
|
||||
int Cheevos::find(int id) {
|
||||
for (int i = 0; i < (int)cheevos_list_.size(); ++i) {
|
||||
if (cheevos_list_[i].id == id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -75,13 +69,11 @@ int Cheevos::find(int id)
|
||||
}
|
||||
|
||||
// Desbloquea un logro
|
||||
void Cheevos::unlock(int id)
|
||||
{
|
||||
void Cheevos::unlock(int id) {
|
||||
const int INDEX = find(id);
|
||||
|
||||
// Si el índice es inválido, el logro no es válido, ya está completado o el sistema de logros no está habilitado, no hacemos nada
|
||||
if (INDEX == -1 || !cheevos_list_.at(INDEX).obtainable || cheevos_list_.at(INDEX).completed || !enabled_)
|
||||
{
|
||||
if (INDEX == -1 || !cheevos_list_.at(INDEX).obtainable || cheevos_list_.at(INDEX).completed || !enabled_) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -96,103 +88,80 @@ void Cheevos::unlock(int id)
|
||||
}
|
||||
|
||||
// Invalida un logro
|
||||
void Cheevos::setUnobtainable(int id)
|
||||
{
|
||||
void Cheevos::setUnobtainable(int id) {
|
||||
const int index = find(id);
|
||||
|
||||
// Si el índice es válido, se invalida el logro
|
||||
if (index != -1)
|
||||
{
|
||||
if (index != -1) {
|
||||
cheevos_list_.at(index).obtainable = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Carga el estado de los logros desde un fichero
|
||||
void Cheevos::loadFromFile()
|
||||
{
|
||||
void Cheevos::loadFromFile() {
|
||||
std::ifstream file(file_, std::ios::binary);
|
||||
|
||||
// El fichero no existe
|
||||
if (!file)
|
||||
{
|
||||
if (options.console)
|
||||
{
|
||||
if (!file) {
|
||||
if (options.console) {
|
||||
std::cout << "Warning: Unable to open " << file_ << "! Creating new file..." << std::endl;
|
||||
}
|
||||
|
||||
// Crea el fichero en modo escritura (binario)
|
||||
std::ofstream newFile(file_, std::ios::binary);
|
||||
|
||||
if (newFile)
|
||||
{
|
||||
if (options.console)
|
||||
{
|
||||
if (newFile) {
|
||||
if (options.console) {
|
||||
std::cout << "New " << file_ << " created!" << std::endl;
|
||||
}
|
||||
|
||||
// Guarda la información
|
||||
for (const auto &cheevo : cheevos_list_)
|
||||
{
|
||||
newFile.write(reinterpret_cast<const char *>(&cheevo.completed), sizeof(bool));
|
||||
for (const auto& cheevo : cheevos_list_) {
|
||||
newFile.write(reinterpret_cast<const char*>(&cheevo.completed), sizeof(bool));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (options.console)
|
||||
{
|
||||
} else {
|
||||
if (options.console) {
|
||||
std::cerr << "Error: Unable to create " << file_ << "!" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
// El fichero existe
|
||||
else
|
||||
{
|
||||
if (options.console)
|
||||
{
|
||||
else {
|
||||
if (options.console) {
|
||||
std::cout << "Reading " << file_ << std::endl;
|
||||
}
|
||||
|
||||
// Carga los datos
|
||||
for (auto &cheevo : cheevos_list_)
|
||||
{
|
||||
file.read(reinterpret_cast<char *>(&cheevo.completed), sizeof(bool));
|
||||
for (auto& cheevo : cheevos_list_) {
|
||||
file.read(reinterpret_cast<char*>(&cheevo.completed), sizeof(bool));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Guarda el estado de los logros en un fichero
|
||||
void Cheevos::saveToFile()
|
||||
{
|
||||
void Cheevos::saveToFile() {
|
||||
// Abre el fichero en modo escritura (binario)
|
||||
SDL_RWops *file = SDL_RWFromFile(this->file_.c_str(), "w+b");
|
||||
if (file != NULL)
|
||||
{
|
||||
SDL_RWops* file = SDL_RWFromFile(this->file_.c_str(), "w+b");
|
||||
if (file != NULL) {
|
||||
// Guarda la información
|
||||
for (int i = 0; i < (int)cheevos_list_.size(); ++i)
|
||||
{
|
||||
for (int i = 0; i < (int)cheevos_list_.size(); ++i) {
|
||||
SDL_RWwrite(file, &cheevos_list_[i].completed, sizeof(bool), 1);
|
||||
}
|
||||
|
||||
// Cierra el fichero
|
||||
SDL_RWclose(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (options.console)
|
||||
{
|
||||
} else {
|
||||
if (options.console) {
|
||||
std::cout << "Error: Unable to save file! " << SDL_GetError() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Devuelve el número total de logros desbloqueados
|
||||
int Cheevos::getTotalUnlockedAchievements()
|
||||
{
|
||||
int Cheevos::getTotalUnlockedAchievements() {
|
||||
int count = 0;
|
||||
for (const auto &cheevo : cheevos_list_)
|
||||
{
|
||||
if (cheevo.completed)
|
||||
{
|
||||
for (const auto& cheevo : cheevos_list_) {
|
||||
if (cheevo.completed) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
@@ -200,10 +169,8 @@ int Cheevos::getTotalUnlockedAchievements()
|
||||
}
|
||||
|
||||
// Elimina el estado "no obtenible"
|
||||
void Cheevos::clearUnobtainableState()
|
||||
{
|
||||
for (auto &cheevo : cheevos_list_)
|
||||
{
|
||||
void Cheevos::clearUnobtainableState() {
|
||||
for (auto& cheevo : cheevos_list_) {
|
||||
cheevo.obtainable = true;
|
||||
}
|
||||
}
|
||||
@@ -1,279 +0,0 @@
|
||||
#include "credits.h"
|
||||
#include <SDL2/SDL_events.h> // Para SDL_PollEvent, SDL_Event
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
||||
#include <algorithm> // Para min
|
||||
#include "defines.h" // Para GAME_SPEED, PLAY_AREA_CENTER_X, PLAY_...
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
#include "options.h" // Para Options, options, OptionsGame, Sectio...
|
||||
#include "resource.h" // Para Resource
|
||||
#include "s_animated_sprite.h" // Para SAnimatedSprite
|
||||
#include "screen.h" // Para Screen
|
||||
#include "surface.h" // Para Surface
|
||||
#include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR
|
||||
#include "utils.h" // Para PaletteColor
|
||||
|
||||
// Constructor
|
||||
Credits::Credits()
|
||||
: shining_sprite_(std::make_shared<SAnimatedSprite>(Resource::get()->getSurface("shine.gif"), Resource::get()->getAnimations("shine.ani")))
|
||||
{
|
||||
// Inicializa variables
|
||||
options.section.section = Section::CREDITS;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
shining_sprite_->setPos({194, 174, 8, 8});
|
||||
|
||||
// Cambia el color del borde
|
||||
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
// Crea la textura para el texto que se escribe en pantalla
|
||||
text_surface_ = std::make_shared<Surface>(options.game.width, options.game.height);
|
||||
|
||||
// Crea la textura para cubrir el rexto
|
||||
cover_surface_ = std::make_shared<Surface>(options.game.width, options.game.height);
|
||||
|
||||
// Escribe el texto en la textura
|
||||
fillTexture();
|
||||
}
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void Credits::checkEvents()
|
||||
{
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
globalEvents::check(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las entradas
|
||||
void Credits::checkInput()
|
||||
{
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Inicializa los textos
|
||||
void Credits::iniTexts()
|
||||
{
|
||||
#ifndef GAME_CONSOLE
|
||||
std::string keys = "";
|
||||
|
||||
switch (options.keys)
|
||||
{
|
||||
case ControlScheme::CURSOR:
|
||||
keys = "CURSORS";
|
||||
break;
|
||||
case ControlScheme::OPQA:
|
||||
keys = "O,P AND Q";
|
||||
break;
|
||||
case ControlScheme::WASD:
|
||||
keys = "A,D AND W";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
texts_.clear();
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"INSTRUCTIONS:", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"HELP JAILDOC TO GET BACK ALL", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"HIS PROJECTS AND GO TO THE", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"JAIL TO FINISH THEM", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
|
||||
texts_.push_back({"KEYS:", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({keys + " TO MOVE AND JUMP", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"M TO SWITCH THE MUSIC", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"H TO PAUSE THE GAME", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"F1-F2 TO CHANGE WINDOWS SIZE", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"F3 TO SWITCH TO FULLSCREEN", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"B TO TOOGLE THE BORDER SCREEN", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
|
||||
texts_.push_back({"A GAME BY JAILDESIGNER", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({"MADE ON SUMMER/FALL 2022", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
|
||||
texts_.push_back({"I LOVE JAILGAMES! ", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
#else
|
||||
texts.clear();
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"INSTRUCTIONS:", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"HELP JAILDOC TO GET BACK ALL", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"HIS PROJECTS AND GO TO THE", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"JAIL TO FINISH THEM", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
|
||||
texts.push_back({"KEYS:", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"B TO JUMP", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"R TO SWITCH THE MUSIC", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"L TO SWAP THE COLOR PALETTE", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"START TO PAUSE", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"SELECT TO EXIT", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
|
||||
texts.push_back({"A GAME BY JAILDESIGNER", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts.push_back({"MADE ON SUMMER/FALL 2022", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
|
||||
texts.push_back({"I LOVE JAILGAMES! ", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
#endif
|
||||
}
|
||||
|
||||
// Escribe el texto en la textura
|
||||
void Credits::fillTexture()
|
||||
{
|
||||
// Inicializa los textos
|
||||
iniTexts();
|
||||
|
||||
// Rellena la textura de texto
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(text_surface_);
|
||||
text_surface_->clear(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
|
||||
// Escribe el texto en la textura
|
||||
const int SIZE = text->getCharacterSize();
|
||||
int pos_y = 0;
|
||||
|
||||
for (const auto &t : texts_)
|
||||
{
|
||||
text->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, pos_y * SIZE, t.label, 1, t.color);
|
||||
pos_y++;
|
||||
}
|
||||
|
||||
// Escribe el corazón
|
||||
const int TEXT_LENGHT = text->lenght(texts_[22].label, 1) - text->lenght(" ", 1); // Se resta el ultimo caracter que es un espacio
|
||||
const int POS_X = ((PLAY_AREA_WIDTH - TEXT_LENGHT) / 2) + TEXT_LENGHT;
|
||||
text->writeColored(POS_X, 176, "}", static_cast<Uint8>(PaletteColor::BRIGHT_RED));
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
|
||||
// Recoloca el sprite del brillo
|
||||
shining_sprite_->setPosX(POS_X + 2);
|
||||
|
||||
// Rellena la textura que cubre el texto con color transparente
|
||||
cover_surface_->clear(static_cast<Uint8>(PaletteColor::TRANSPARENT));
|
||||
|
||||
// Los primeros 8 pixels crea una malla
|
||||
auto color = static_cast<Uint8>(PaletteColor::BLACK);
|
||||
for (int i = 0; i < 256; i += 2)
|
||||
{
|
||||
cover_surface_->putPixel(i, 0, color);
|
||||
cover_surface_->putPixel(i, 2, color);
|
||||
cover_surface_->putPixel(i, 4, color);
|
||||
cover_surface_->putPixel(i, 6, color);
|
||||
|
||||
cover_surface_->putPixel(i + 1, 5, color);
|
||||
cover_surface_->putPixel(i + 1, 7, color);
|
||||
}
|
||||
|
||||
// El resto se rellena de color sólido
|
||||
SDL_Rect rect = {0, 8, 256, 192};
|
||||
cover_surface_->fillRect(&rect, color);
|
||||
}
|
||||
|
||||
// Actualiza el contador
|
||||
void Credits::updateCounter()
|
||||
{
|
||||
// Incrementa el contador
|
||||
if (counter_enabled_)
|
||||
{
|
||||
counter_++;
|
||||
if (counter_ == 224 || counter_ == 544 || counter_ == 672)
|
||||
{
|
||||
counter_enabled_ = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sub_counter_++;
|
||||
if (sub_counter_ == 100)
|
||||
{
|
||||
counter_enabled_ = true;
|
||||
sub_counter_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba si ha terminado la sección
|
||||
if (counter_ > 1200)
|
||||
{
|
||||
options.section.section = Section::DEMO;
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza las variables
|
||||
void Credits::update()
|
||||
{
|
||||
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED)
|
||||
{
|
||||
// Actualiza el contador de ticks
|
||||
ticks_ = SDL_GetTicks();
|
||||
|
||||
// Comprueba las entradas
|
||||
checkInput();
|
||||
|
||||
// Actualiza el contador
|
||||
updateCounter();
|
||||
|
||||
Screen::get()->update();
|
||||
|
||||
// Actualiza el sprite con el brillo
|
||||
if (counter_ > 770)
|
||||
{
|
||||
shining_sprite_->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja en pantalla
|
||||
void Credits::render()
|
||||
{
|
||||
// Prepara para empezar a dibujar en la textura de juego
|
||||
Screen::get()->start();
|
||||
|
||||
// Limpia la pantalla
|
||||
Screen::get()->clearSurface(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
if (counter_ < 1150)
|
||||
{
|
||||
// Dibuja la textura con el texto en pantalla
|
||||
text_surface_->render(0, 0);
|
||||
|
||||
// Dibuja la textura que cubre el texto
|
||||
const int offset = std::min(counter_ / 8, 192 / 2);
|
||||
SDL_Rect srcRect = {0, 0, 256, 192 - (offset * 2)};
|
||||
cover_surface_->render(0, offset * 2, &srcRect);
|
||||
|
||||
// Dibuja el sprite con el brillo
|
||||
shining_sprite_->render(1, static_cast<Uint8>(PaletteColor::BRIGHT_WHITE));
|
||||
}
|
||||
|
||||
// Vuelca el contenido del renderizador en pantalla
|
||||
Screen::get()->render();
|
||||
}
|
||||
|
||||
// Bucle para el logo del juego
|
||||
void Credits::run()
|
||||
{
|
||||
while (options.section.section == Section::CREDITS)
|
||||
{
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint32, Uint8
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
class SAnimatedSprite; // lines 11-11
|
||||
class Surface;
|
||||
|
||||
class Credits
|
||||
{
|
||||
private:
|
||||
struct Captions
|
||||
{
|
||||
std::string label; // Texto a escribir
|
||||
Uint8 color; // Color del texto
|
||||
};
|
||||
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<Surface> text_surface_; // Textura para dibujar el texto
|
||||
std::shared_ptr<Surface> cover_surface_; // Textura para cubrir el texto
|
||||
std::shared_ptr<SAnimatedSprite> shining_sprite_; // Sprite para el brillo del corazón
|
||||
|
||||
// Variables
|
||||
int counter_ = 0; // Contador
|
||||
bool counter_enabled_ = true; // Indica si esta activo el contador
|
||||
int sub_counter_ = 0; // Contador secundario
|
||||
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
std::vector<Captions> texts_; // Vector con los textos
|
||||
|
||||
// Actualiza las variables
|
||||
void update();
|
||||
|
||||
// Dibuja en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void checkEvents();
|
||||
|
||||
// Comprueba las entradas
|
||||
void checkInput();
|
||||
|
||||
// Actualiza el contador
|
||||
void updateCounter();
|
||||
|
||||
// Inicializa los textos
|
||||
void iniTexts();
|
||||
|
||||
// Escribe el texto en la textura
|
||||
void fillTexture();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Credits();
|
||||
|
||||
// Destructor
|
||||
~Credits() = default;
|
||||
|
||||
// Bucle principal
|
||||
void run();
|
||||
};
|
||||
@@ -1,15 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Point
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Point
|
||||
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
// Clase Debug
|
||||
class Debug
|
||||
{
|
||||
private:
|
||||
class Debug {
|
||||
private:
|
||||
// [SINGLETON] Objeto privado
|
||||
static Debug *debug_;
|
||||
static Debug* debug_;
|
||||
|
||||
// Variables
|
||||
std::vector<std::string> slot_; // Vector con los textos a escribir
|
||||
@@ -24,7 +24,7 @@ private:
|
||||
// Destructor
|
||||
~Debug() = default;
|
||||
|
||||
public:
|
||||
public:
|
||||
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||
static void init();
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
static void destroy();
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
static Debug *get();
|
||||
static Debug* get();
|
||||
|
||||
// Dibuja en pantalla
|
||||
void render();
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
// Textos
|
||||
constexpr const char *WINDOW_CAPTION = "JailDoctor's Dilemma";
|
||||
constexpr const char *TEXT_COPYRIGHT = "@2022 JailDesigner";
|
||||
constexpr const char *VERSION = "1.10";
|
||||
constexpr const char* WINDOW_CAPTION = "JailDoctor's Dilemma";
|
||||
constexpr const char* TEXT_COPYRIGHT = "@2022 JailDesigner";
|
||||
constexpr const char* VERSION = "1.10";
|
||||
|
||||
// Velocidad del juego
|
||||
constexpr Uint32 GAME_SPEED = 15;
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
#include "director.h"
|
||||
#include <SDL2/SDL.h> // Para SDL_Init, SDL_Quit, SDL_INIT_EV...
|
||||
#include <SDL2/SDL_audio.h> // Para AUDIO_S16
|
||||
#include <SDL2/SDL_blendmode.h> // Para SDL_BLENDMODE_BLEND
|
||||
#include <SDL2/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL2/SDL_events.h> // Para SDL_DISABLE
|
||||
#include <SDL2/SDL_gamecontroller.h> // Para SDL_CONTROLLER_BUTTON_B, SDL_CO...
|
||||
#include <SDL2/SDL_hints.h> // Para SDL_SetHint, SDL_HINT_RENDER_DR...
|
||||
#include <SDL2/SDL_mouse.h> // Para SDL_ShowCursor
|
||||
#include <SDL2/SDL_scancode.h> // Para SDL_SCANCODE_A, SDL_SCANCODE_ES...
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint32
|
||||
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_Init, SDL_Quit, SDL_INIT_EV...
|
||||
#include <SDL3/SDL_audio.h> // Para AUDIO_S16
|
||||
#include <SDL3/SDL_blendmode.h> // Para SDL_BLENDMODE_BLEND
|
||||
#include <SDL3/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL3/SDL_events.h> // Para SDL_DISABLE
|
||||
#include <SDL3/SDL_gamecontroller.h> // Para SDL_CONTROLLER_BUTTON_B, SDL_CO...
|
||||
#include <SDL3/SDL_hints.h> // Para SDL_SetHint, SDL_HINT_RENDER_DR...
|
||||
#include <SDL3/SDL_mouse.h> // Para SDL_ShowCursor
|
||||
#include <SDL3/SDL_scancode.h> // Para SDL_SCANCODE_A, SDL_SCANCODE_ES...
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint32
|
||||
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
||||
#include <errno.h> // Para errno, EEXIST, EACCES, ENAMETOO...
|
||||
#include <stdio.h> // Para printf, perror
|
||||
#include <sys/stat.h> // Para mkdir, stat, S_IRWXU
|
||||
#include <unistd.h> // Para getuid
|
||||
|
||||
#include <cstdlib> // Para exit, EXIT_FAILURE, srand
|
||||
#include <iostream> // Para basic_ostream, operator<<, cout
|
||||
#include <memory> // Para make_unique, unique_ptr
|
||||
#include <string> // Para operator+, allocator, char_traits
|
||||
|
||||
#include "asset.h" // Para Asset, AssetType
|
||||
#include "cheevos.h" // Para Cheevos
|
||||
#include "credits.h" // Para Credits
|
||||
@@ -42,8 +45,7 @@
|
||||
#endif
|
||||
|
||||
// Constructor
|
||||
Director::Director(int argc, const char *argv[])
|
||||
{
|
||||
Director::Director(int argc, const char* argv[]) {
|
||||
std::cout << "Game start" << std::endl;
|
||||
|
||||
// Crea e inicializa las opciones del programa
|
||||
@@ -60,8 +62,7 @@ Director::Director(int argc, const char *argv[])
|
||||
createSystemFolder("jailgames/jaildoctors_dilemma");
|
||||
|
||||
// Si falta algún fichero no inicia el programa
|
||||
if (!setFileList())
|
||||
{
|
||||
if (!setFileList()) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -86,8 +87,7 @@ Director::Director(int argc, const char *argv[])
|
||||
Cheevos::init(Asset::get()->get("cheevos.bin"));
|
||||
}
|
||||
|
||||
Director::~Director()
|
||||
{
|
||||
Director::~Director() {
|
||||
// Guarda las opciones a un fichero
|
||||
saveOptionsToFile(Asset::get()->get("config.txt"));
|
||||
|
||||
@@ -108,31 +108,20 @@ Director::~Director()
|
||||
}
|
||||
|
||||
// Comprueba los parametros del programa
|
||||
std::string Director::checkProgramArguments(int argc, const char *argv[])
|
||||
{
|
||||
std::string Director::checkProgramArguments(int argc, const char* argv[]) {
|
||||
// Iterar sobre los argumentos del programa
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
std::string argument(argv[i]);
|
||||
|
||||
if (argument == "--console")
|
||||
{
|
||||
if (argument == "--console") {
|
||||
options.console = true;
|
||||
}
|
||||
else if (argument == "--infiniteLives")
|
||||
{
|
||||
} else if (argument == "--infiniteLives") {
|
||||
options.cheats.infinite_lives = Cheat::CheatState::ENABLED;
|
||||
}
|
||||
else if (argument == "--invincible")
|
||||
{
|
||||
} else if (argument == "--invincible") {
|
||||
options.cheats.invincible = Cheat::CheatState::ENABLED;
|
||||
}
|
||||
else if (argument == "--jailEnabled")
|
||||
{
|
||||
} else if (argument == "--jailEnabled") {
|
||||
options.cheats.jail_is_open = Cheat::CheatState::ENABLED;
|
||||
}
|
||||
else if (argument == "--altSkin")
|
||||
{
|
||||
} else if (argument == "--altSkin") {
|
||||
options.cheats.alternate_skin = Cheat::CheatState::ENABLED;
|
||||
}
|
||||
}
|
||||
@@ -141,25 +130,23 @@ std::string Director::checkProgramArguments(int argc, const char *argv[])
|
||||
}
|
||||
|
||||
// Crea la carpeta del sistema donde guardar datos
|
||||
void Director::createSystemFolder(const std::string &folder)
|
||||
{
|
||||
void Director::createSystemFolder(const std::string& folder) {
|
||||
#ifdef _WIN32
|
||||
system_folder_ = std::string(getenv("APPDATA")) + "/" + folder;
|
||||
#elif __APPLE__
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
const char *homedir = pw->pw_dir;
|
||||
struct passwd* pw = getpwuid(getuid());
|
||||
const char* homedir = pw->pw_dir;
|
||||
system_folder_ = std::string(homedir) + "/Library/Application Support" + "/" + folder;
|
||||
#elif __linux__
|
||||
struct passwd *pw = getpwuid(getuid());
|
||||
const char *homedir = pw->pw_dir;
|
||||
struct passwd* pw = getpwuid(getuid());
|
||||
const char* homedir = pw->pw_dir;
|
||||
system_folder_ = std::string(homedir) + "/.config/" + folder;
|
||||
|
||||
{
|
||||
// Intenta crear ".config", per si no existeix
|
||||
std::string config_base_folder = std::string(homedir) + "/.config";
|
||||
int ret = mkdir(config_base_folder.c_str(), S_IRWXU);
|
||||
if (ret == -1 && errno != EEXIST)
|
||||
{
|
||||
if (ret == -1 && errno != EEXIST) {
|
||||
printf("ERROR CREATING CONFIG BASE FOLDER.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -167,8 +154,7 @@ void Director::createSystemFolder(const std::string &folder)
|
||||
#endif
|
||||
|
||||
struct stat st = {0};
|
||||
if (stat(system_folder_.c_str(), &st) == -1)
|
||||
{
|
||||
if (stat(system_folder_.c_str(), &st) == -1) {
|
||||
errno = 0;
|
||||
#ifdef _WIN32
|
||||
int ret = mkdir(system_folder_.c_str());
|
||||
@@ -176,10 +162,8 @@ void Director::createSystemFolder(const std::string &folder)
|
||||
int ret = mkdir(system_folder_.c_str(), S_IRWXU);
|
||||
#endif
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
if (ret == -1) {
|
||||
switch (errno) {
|
||||
case EACCES:
|
||||
printf("the parent directory does not allow write");
|
||||
exit(EXIT_FAILURE);
|
||||
@@ -201,30 +185,24 @@ void Director::createSystemFolder(const std::string &folder)
|
||||
}
|
||||
|
||||
// Inicia las variables necesarias para arrancar el programa
|
||||
void Director::initInput()
|
||||
{
|
||||
void Director::initInput() {
|
||||
// Busca si hay un mando conectado
|
||||
Input::get()->discoverGameControllers();
|
||||
|
||||
// Teclado - Movimiento
|
||||
if (options.keys == ControlScheme::CURSOR)
|
||||
{
|
||||
if (options.keys == ControlScheme::CURSOR) {
|
||||
Input::get()->bindKey(InputAction::JUMP, SDL_SCANCODE_UP);
|
||||
Input::get()->bindKey(InputAction::LEFT, SDL_SCANCODE_LEFT);
|
||||
Input::get()->bindKey(InputAction::RIGHT, SDL_SCANCODE_RIGHT);
|
||||
Input::get()->bindKey(InputAction::UP, SDL_SCANCODE_UP);
|
||||
Input::get()->bindKey(InputAction::DOWN, SDL_SCANCODE_DOWN);
|
||||
}
|
||||
else if (options.keys == ControlScheme::OPQA)
|
||||
{
|
||||
} else if (options.keys == ControlScheme::OPQA) {
|
||||
Input::get()->bindKey(InputAction::JUMP, SDL_SCANCODE_Q);
|
||||
Input::get()->bindKey(InputAction::LEFT, SDL_SCANCODE_O);
|
||||
Input::get()->bindKey(InputAction::RIGHT, SDL_SCANCODE_P);
|
||||
Input::get()->bindKey(InputAction::UP, SDL_SCANCODE_Q);
|
||||
Input::get()->bindKey(InputAction::DOWN, SDL_SCANCODE_A);
|
||||
}
|
||||
else if (options.keys == ControlScheme::WASD)
|
||||
{
|
||||
} else if (options.keys == ControlScheme::WASD) {
|
||||
Input::get()->bindKey(InputAction::JUMP, SDL_SCANCODE_W);
|
||||
Input::get()->bindKey(InputAction::LEFT, SDL_SCANCODE_A);
|
||||
Input::get()->bindKey(InputAction::RIGHT, SDL_SCANCODE_D);
|
||||
@@ -250,8 +228,7 @@ void Director::initInput()
|
||||
|
||||
// MANDO
|
||||
const int NUM_GAMEPADS = Input::get()->getNumControllers();
|
||||
for (int i = 0; i < NUM_GAMEPADS; ++i)
|
||||
{
|
||||
for (int i = 0; i < NUM_GAMEPADS; ++i) {
|
||||
// Movimiento
|
||||
Input::get()->bindGameControllerButton(i, InputAction::JUMP, SDL_CONTROLLER_BUTTON_B);
|
||||
Input::get()->bindGameControllerButton(i, InputAction::LEFT, SDL_CONTROLLER_BUTTON_DPAD_LEFT);
|
||||
@@ -274,53 +251,41 @@ void Director::initInput()
|
||||
}
|
||||
|
||||
// Inicializa JailAudio
|
||||
void Director::initJailAudio()
|
||||
{
|
||||
void Director::initJailAudio() {
|
||||
JA_Init(48000, AUDIO_S16, 2);
|
||||
if (options.audio.enabled)
|
||||
{
|
||||
if (options.audio.enabled) {
|
||||
JA_SetMusicVolume(options.audio.music.volume);
|
||||
JA_SetSoundVolume(options.audio.sound.volume);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
JA_SetMusicVolume(0);
|
||||
JA_SetSoundVolume(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Arranca SDL y crea la ventana
|
||||
bool Director::initSDL()
|
||||
{
|
||||
bool Director::initSDL() {
|
||||
// Indicador de éxito
|
||||
bool success = true;
|
||||
|
||||
// Inicializa SDL
|
||||
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
|
||||
{
|
||||
if (options.console)
|
||||
{
|
||||
if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
|
||||
if (options.console) {
|
||||
std::cout << "SDL could not initialize!\nSDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
success = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Inicia el generador de numeros aleatorios
|
||||
std::srand(static_cast<unsigned int>(SDL_GetTicks()));
|
||||
|
||||
// Establece el filtro de la textura a nearest
|
||||
if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, std::to_string(static_cast<int>(options.video.filter)).c_str()))
|
||||
{
|
||||
if (options.console)
|
||||
{
|
||||
if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, std::to_string(static_cast<int>(options.video.filter)).c_str())) {
|
||||
if (options.console) {
|
||||
std::cout << "Warning: Nearest texture filtering not enabled!\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Activa el render OpenGL
|
||||
if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl"))
|
||||
{
|
||||
if (!SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl")) {
|
||||
std::cout << "Warning: opengl not enabled!\n";
|
||||
}
|
||||
|
||||
@@ -329,34 +294,25 @@ bool Director::initSDL()
|
||||
const auto window_height = options.video.border.enabled ? options.game.height + options.video.border.height * 2 : options.game.height;
|
||||
|
||||
window_ = SDL_CreateWindow(WINDOW_CAPTION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, window_width * options.window.zoom, window_height * options.window.zoom, SDL_WINDOW_HIDDEN);
|
||||
if (window_ == nullptr)
|
||||
{
|
||||
if (options.console)
|
||||
{
|
||||
if (window_ == nullptr) {
|
||||
if (options.console) {
|
||||
std::cout << "Window could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
success = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Crea un renderizador para la ventana. El vsync se activa en funcion de las opciones
|
||||
Uint32 flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
|
||||
if (options.video.vertical_sync)
|
||||
{
|
||||
if (options.video.vertical_sync) {
|
||||
flags = flags | SDL_RENDERER_PRESENTVSYNC;
|
||||
}
|
||||
renderer_ = SDL_CreateRenderer(window_, -1, flags);
|
||||
|
||||
if (renderer_ == nullptr)
|
||||
{
|
||||
if (options.console)
|
||||
{
|
||||
if (renderer_ == nullptr) {
|
||||
if (options.console) {
|
||||
std::cout << "Renderer could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
success = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Inicializa el color de renderizado
|
||||
SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF);
|
||||
|
||||
@@ -371,16 +327,14 @@ bool Director::initSDL()
|
||||
}
|
||||
}
|
||||
|
||||
if (options.console)
|
||||
{
|
||||
if (options.console) {
|
||||
std::cout << std::endl;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
// Crea el indice de ficheros
|
||||
bool Director::setFileList()
|
||||
{
|
||||
bool Director::setFileList() {
|
||||
#ifdef MACOS_BUNDLE
|
||||
const std::string prefix = "/../Resources";
|
||||
#else
|
||||
@@ -429,8 +383,7 @@ bool Director::setFileList()
|
||||
Asset::get()->add(system_folder_ + "/cheevos.bin", AssetType::DATA, false, true);
|
||||
|
||||
// Tilemaps y Rooms
|
||||
for (int i = 1; i <= 60; ++i)
|
||||
{
|
||||
for (int i = 1; i <= 60; ++i) {
|
||||
std::string index = (i < 10 ? "0" : "") + std::to_string(i);
|
||||
Asset::get()->add(prefix + "/data/room/" + index + ".tmx", AssetType::TILEMAP);
|
||||
Asset::get()->add(prefix + "/data/room/" + index + ".room", AssetType::ROOM);
|
||||
@@ -582,8 +535,7 @@ bool Director::setFileList()
|
||||
Asset::get()->add(prefix + "/data/sound/notify.wav", AssetType::SOUND);
|
||||
|
||||
// Efectos de sonido para el salto
|
||||
for (int i = 1; i <= 24; ++i)
|
||||
{
|
||||
for (int i = 1; i <= 24; ++i) {
|
||||
std::string jump_index = std::to_string(i);
|
||||
Asset::get()->add(prefix + "/data/sound/jump" + jump_index + ".wav", AssetType::SOUND);
|
||||
}
|
||||
@@ -614,76 +566,64 @@ bool Director::setFileList()
|
||||
}
|
||||
|
||||
// Ejecuta la seccion de juego con el logo
|
||||
void Director::runLogo()
|
||||
{
|
||||
void Director::runLogo() {
|
||||
auto logo = std::make_unique<Logo>();
|
||||
logo->run();
|
||||
}
|
||||
|
||||
// Ejecuta la seccion de juego de la pantalla de carga
|
||||
void Director::runLoadingScreen()
|
||||
{
|
||||
void Director::runLoadingScreen() {
|
||||
auto loadingScreen = std::make_unique<LoadingScreen>();
|
||||
loadingScreen->run();
|
||||
}
|
||||
|
||||
// Ejecuta la seccion de juego con el titulo y los menus
|
||||
void Director::runTitle()
|
||||
{
|
||||
void Director::runTitle() {
|
||||
auto title = std::make_unique<Title>();
|
||||
title->run();
|
||||
}
|
||||
|
||||
// Ejecuta la seccion de los creditos del juego
|
||||
void Director::runCredits()
|
||||
{
|
||||
void Director::runCredits() {
|
||||
auto credits = std::make_unique<Credits>();
|
||||
credits->run();
|
||||
}
|
||||
|
||||
// Ejecuta la seccion de la demo, donde se ven pantallas del juego
|
||||
void Director::runDemo()
|
||||
{
|
||||
void Director::runDemo() {
|
||||
auto game = std::make_unique<Game>(GameMode::DEMO);
|
||||
game->run();
|
||||
}
|
||||
|
||||
// Ejecuta la seccion del final del juego
|
||||
void Director::runEnding()
|
||||
{
|
||||
void Director::runEnding() {
|
||||
auto ending = std::make_unique<Ending>();
|
||||
ending->run();
|
||||
}
|
||||
|
||||
// Ejecuta la seccion del final del juego
|
||||
void Director::runEnding2()
|
||||
{
|
||||
void Director::runEnding2() {
|
||||
auto ending2 = std::make_unique<Ending2>();
|
||||
ending2->run();
|
||||
}
|
||||
|
||||
// Ejecuta la seccion del final de la partida
|
||||
void Director::runGameOver()
|
||||
{
|
||||
void Director::runGameOver() {
|
||||
auto gameOver = std::make_unique<GameOver>();
|
||||
gameOver->run();
|
||||
}
|
||||
|
||||
// Ejecuta la seccion de juego donde se juega
|
||||
void Director::runGame()
|
||||
{
|
||||
void Director::runGame() {
|
||||
JA_StopMusic();
|
||||
auto game = std::make_unique<Game>(GameMode::GAME);
|
||||
game->run();
|
||||
}
|
||||
|
||||
int Director::run()
|
||||
{
|
||||
int Director::run() {
|
||||
// Bucle principal
|
||||
while (options.section.section != Section::QUIT)
|
||||
{
|
||||
switch (options.section.section)
|
||||
{
|
||||
while (options.section.section != Section::QUIT) {
|
||||
switch (options.section.section) {
|
||||
case Section::LOGO:
|
||||
runLogo();
|
||||
break;
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_render.h> // Para SDL_Renderer
|
||||
#include <SDL2/SDL_video.h> // Para SDL_Window
|
||||
#include <SDL3/SDL_render.h> // Para SDL_Renderer
|
||||
#include <SDL3/SDL_video.h> // Para SDL_Window
|
||||
|
||||
#include <string> // Para string
|
||||
|
||||
class Director
|
||||
{
|
||||
private:
|
||||
class Director {
|
||||
private:
|
||||
// Objetos y punteros
|
||||
SDL_Window *window_; // La ventana donde dibujamos
|
||||
SDL_Renderer *renderer_; // El renderizador de la ventana
|
||||
SDL_Window* window_; // La ventana donde dibujamos
|
||||
SDL_Renderer* renderer_; // El renderizador de la ventana
|
||||
|
||||
// Variables
|
||||
std::string executable_path_; // Path del ejecutable
|
||||
std::string system_folder_; // Carpeta del sistema donde guardar datos
|
||||
|
||||
// Comprueba los parametros del programa
|
||||
std::string checkProgramArguments(int argc, const char *argv[]);
|
||||
std::string checkProgramArguments(int argc, const char* argv[]);
|
||||
|
||||
// Crea la carpeta del sistema donde guardar datos
|
||||
void createSystemFolder(const std::string &folder);
|
||||
void createSystemFolder(const std::string& folder);
|
||||
|
||||
// Inicializa jail_audio
|
||||
void initJailAudio();
|
||||
@@ -60,9 +60,9 @@ private:
|
||||
// Ejecuta la seccion de juego donde se juega
|
||||
void runGame();
|
||||
|
||||
public:
|
||||
public:
|
||||
// Constructor
|
||||
Director(int argc, const char *argv[]);
|
||||
Director(int argc, const char* argv[]);
|
||||
|
||||
// Destructor
|
||||
~Director();
|
||||
|
||||
104
source/ending.h
104
source/ending.h
@@ -1,104 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint32
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
class SSprite; // lines 8-8
|
||||
class Surface; // lines 9-9
|
||||
|
||||
class Ending
|
||||
{
|
||||
private:
|
||||
// Estructuras
|
||||
struct EndingSurface // Estructura con dos texturas y sprites, uno para mostrar y el otro hace de cortinilla
|
||||
{
|
||||
std::shared_ptr<Surface> image_surface; // Surface a mostrar
|
||||
std::shared_ptr<SSprite> image_sprite; // SSprite para mostrar la textura
|
||||
std::shared_ptr<Surface> cover_surface; // Surface que cubre a la otra textura
|
||||
std::shared_ptr<SSprite> cover_sprite; // SSprite para mostrar la textura que cubre a la otra textura
|
||||
int cover_clip_desp; // Desplazamiento del spriteClip de la textura de cobertura
|
||||
int cover_clip_height; // Altura del spriteClip de la textura de cobertura
|
||||
};
|
||||
|
||||
struct TextAndPosition // Estructura con un texto y su posición en el eje Y
|
||||
{
|
||||
std::string caption; // Texto
|
||||
int pos; // Posición
|
||||
};
|
||||
|
||||
struct TextIndex
|
||||
{
|
||||
int index;
|
||||
int trigger;
|
||||
};
|
||||
|
||||
struct SceneData // Estructura para crear cada una de las escenas del final
|
||||
{
|
||||
std::vector<TextIndex> text_index; // Indices del vector de textos a mostrar y su disparador
|
||||
int picture_index; // Indice del vector de imagenes a mostrar
|
||||
int counter_end; // Valor del contador en el que finaliza la escena
|
||||
};
|
||||
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<Surface> cover_surface_; // Surface para cubrir el texto
|
||||
|
||||
// Variables
|
||||
int counter_; // Contador
|
||||
int pre_counter_; // Contador previo
|
||||
int cover_counter_; // Contador para la cortinilla
|
||||
Uint32 ticks_; // Contador de ticks para ajustar la velocidad del programa
|
||||
std::vector<EndingSurface> sprite_texts_; // Vector con los sprites de texto con su cortinilla
|
||||
std::vector<EndingSurface> sprite_pics_; // Vector con los sprites de texto con su cortinilla
|
||||
int current_scene_; // Escena actual
|
||||
std::vector<SceneData> scenes_; // Vector con los textos e imagenes de cada escena
|
||||
|
||||
// Actualiza el objeto
|
||||
void update();
|
||||
|
||||
// Dibuja el final en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void checkEvents();
|
||||
|
||||
// Comprueba las entradas
|
||||
void checkInput();
|
||||
|
||||
// Inicializa los textos
|
||||
void iniTexts();
|
||||
|
||||
// Inicializa las imagenes
|
||||
void iniPics();
|
||||
|
||||
// Inicializa las escenas
|
||||
void iniScenes();
|
||||
|
||||
// Actualiza los contadores
|
||||
void updateCounters();
|
||||
|
||||
// Actualiza las cortinillas de los elementos
|
||||
void updateSpriteCovers();
|
||||
|
||||
// Comprueba si se ha de cambiar de escena
|
||||
void checkChangeScene();
|
||||
|
||||
// Rellena la textura para la cortinilla
|
||||
void fillCoverTexture();
|
||||
|
||||
// Dibuja la cortinilla de cambio de escena
|
||||
void renderCoverTexture();
|
||||
|
||||
// Actualiza el volumen de la musica
|
||||
void updateMusicVolume();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Ending();
|
||||
|
||||
// Destructor
|
||||
~Ending() = default;
|
||||
|
||||
// Bucle principal
|
||||
void run();
|
||||
};
|
||||
142
source/ending2.h
142
source/ending2.h
@@ -1,142 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint32, Uint8
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
#include "defines.h" // Para GAMECANVAS_WIDTH, GAMECANVAS_FIRST_QUAR...
|
||||
class SAnimatedSprite; // lines 9-9
|
||||
class SMovingSprite; // lines 10-10
|
||||
|
||||
class Ending2
|
||||
{
|
||||
private:
|
||||
// Enum para representar los estados del final
|
||||
enum class EndingState : int
|
||||
{
|
||||
PRE_CREDITS, // Estado previo a los créditos
|
||||
CREDITS, // Estado de los créditos
|
||||
POST_CREDITS, // Estado posterior a los créditos
|
||||
FADING, // Estado de fundido de los textos a negrp
|
||||
};
|
||||
|
||||
// Estructura para controlar los estados y su duración
|
||||
struct State
|
||||
{
|
||||
EndingState state; // Estado actual
|
||||
Uint32 init_ticks; // Ticks en los que se inicializó el estado
|
||||
Uint32 duration; // Duración en milisegundos para el estado actual
|
||||
|
||||
// Constructor parametrizado para inicializar la estructura
|
||||
State(EndingState initialState, Uint32 initialTicks, Uint32 stateDuration)
|
||||
: state(initialState), init_ticks(initialTicks), duration(stateDuration) {}
|
||||
|
||||
// Método para comprobar si el estado ha terminado y verifica el nombre del estado
|
||||
bool hasEnded(EndingState expectedState) const
|
||||
{
|
||||
// Comprobar si el estado actual coincide con el estado esperado
|
||||
if (state != expectedState)
|
||||
{
|
||||
return false; // Si no coincide, considerar que no ha terminado
|
||||
}
|
||||
|
||||
// Comprobar si el tiempo transcurrido excede la duración
|
||||
return (SDL_GetTicks() - init_ticks) >= duration;
|
||||
}
|
||||
|
||||
// Método para establecer un nuevo estado
|
||||
void set(EndingState newState, Uint32 newDuration)
|
||||
{
|
||||
state = newState; // Actualizar el estado
|
||||
init_ticks = SDL_GetTicks(); // Reiniciar el tiempo de inicio
|
||||
duration = newDuration; // Actualizar la duración
|
||||
}
|
||||
};
|
||||
|
||||
// Constantes
|
||||
static constexpr int FIRST_COL_ = GAMECANVAS_FIRST_QUARTER_X + (GAMECANVAS_WIDTH / 16); // Primera columna por donde desfilan los sprites
|
||||
static constexpr int SECOND_COL_ = GAMECANVAS_THIRD_QUARTER_X - (GAMECANVAS_WIDTH / 16); // Segunda columna por donde desfilan los sprites
|
||||
static constexpr int DIST_SPRITE_TEXT_ = 8; // Distancia entre el sprite y el texto que lo acompaña
|
||||
static constexpr int DIST_SPRITE_SPRITE_ = 0; // Distancia entre dos sprites de la misma columna
|
||||
static constexpr float SPRITE_DESP_SPEED_ = -0.2f; // Velocidad de desplazamiento de los sprites
|
||||
static constexpr int STATE_PRE_CREDITS_DURATION_ = 3000;
|
||||
static constexpr int STATE_POST_CREDITS_DURATION_ = 5000;
|
||||
static constexpr int STATE_FADE_DURATION_ = 5000;
|
||||
|
||||
// Objetos y punteros
|
||||
std::vector<std::shared_ptr<SAnimatedSprite>> sprites_; // Vector con todos los sprites a dibujar
|
||||
std::vector<std::shared_ptr<SMovingSprite>> sprite_texts_; // Vector con los sprites de texto de los sprites
|
||||
std::vector<std::shared_ptr<SMovingSprite>> texts_; // Vector con los sprites de texto
|
||||
|
||||
// Variables
|
||||
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
std::vector<std::string> sprite_list_; // Lista con todos los sprites a dibujar
|
||||
std::vector<Uint8> colors_; // Vector con los colores para el fade
|
||||
int sprite_max_width_ = 0; // El valor de ancho del sprite mas ancho
|
||||
int sprite_max_height_ = 0; // El valor de alto del sprite mas alto
|
||||
State state_; // Controla el estado de la clase
|
||||
|
||||
// Actualiza el objeto
|
||||
void update();
|
||||
|
||||
// Dibuja el final en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void checkEvents();
|
||||
|
||||
// Comprueba las entradas
|
||||
void checkInput();
|
||||
|
||||
// Actualiza el estado
|
||||
void updateState();
|
||||
|
||||
// Inicializa la lista de sprites
|
||||
void iniSpriteList();
|
||||
|
||||
// Carga todos los sprites desde una lista
|
||||
void loadSprites();
|
||||
|
||||
// Actualiza los sprites
|
||||
void updateSprites();
|
||||
|
||||
// Actualiza los sprites de texto
|
||||
void updateTextSprites();
|
||||
|
||||
// Actualiza los sprites de texto del final
|
||||
void updateTexts();
|
||||
|
||||
// Dibuja los sprites
|
||||
void renderSprites();
|
||||
|
||||
// Dibuja los sprites con el texto
|
||||
void renderSpriteTexts();
|
||||
|
||||
// Dibuja los sprites con el texto del final
|
||||
void renderTexts();
|
||||
|
||||
// Coloca los sprites en su sito
|
||||
void placeSprites();
|
||||
|
||||
// Crea los sprites con las texturas con los textos
|
||||
void createSpriteTexts();
|
||||
|
||||
// Crea los sprites con las texturas con los textos del final
|
||||
void createTexts();
|
||||
|
||||
// Actualiza el fade final
|
||||
void updateFinalFade();
|
||||
|
||||
// Actualiza el volumen de la musica
|
||||
void updateMusicVolume();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Ending2();
|
||||
|
||||
// Destructor
|
||||
~Ending2() = default;
|
||||
|
||||
// Bucle principal
|
||||
void run();
|
||||
};
|
||||
@@ -1,12 +1,14 @@
|
||||
#include "enemy.h"
|
||||
#include <SDL2/SDL_render.h> // Para SDL_RendererFlip, SDL_FLIP_NONE, SDL_...
|
||||
|
||||
#include <SDL3/SDL_render.h> // Para SDL_RendererFlip, SDL_FLIP_NONE, SDL_...
|
||||
#include <stdlib.h> // Para rand
|
||||
|
||||
#include "resource.h" // Para Resource
|
||||
#include "s_animated_sprite.h" // Para SAnimatedSprite
|
||||
#include "utils.h" // Para stringToColor
|
||||
|
||||
// Constructor
|
||||
Enemy::Enemy(const EnemyData &enemy)
|
||||
Enemy::Enemy(const EnemyData& enemy)
|
||||
: sprite_(std::make_shared<SAnimatedSprite>(Resource::get()->getSurface(enemy.surface_path), Resource::get()->getAnimations(enemy.animation_path))),
|
||||
color_string_(enemy.color),
|
||||
x1_(enemy.x1),
|
||||
@@ -14,8 +16,7 @@ Enemy::Enemy(const EnemyData &enemy)
|
||||
y1_(enemy.y1),
|
||||
y2_(enemy.y2),
|
||||
should_flip_(enemy.flip),
|
||||
should_mirror_(enemy.mirror)
|
||||
{
|
||||
should_mirror_(enemy.mirror) {
|
||||
// Obten el resto de valores
|
||||
sprite_->setPosX(enemy.x);
|
||||
sprite_->setPosY(enemy.y);
|
||||
@@ -37,31 +38,24 @@ Enemy::Enemy(const EnemyData &enemy)
|
||||
}
|
||||
|
||||
// Pinta el enemigo en pantalla
|
||||
void Enemy::render()
|
||||
{
|
||||
void Enemy::render() {
|
||||
sprite_->render(1, color_);
|
||||
}
|
||||
|
||||
// Actualiza las variables del objeto
|
||||
void Enemy::update()
|
||||
{
|
||||
void Enemy::update() {
|
||||
sprite_->update();
|
||||
checkPath();
|
||||
collider_ = getRect();
|
||||
}
|
||||
|
||||
// Comprueba si ha llegado al limite del recorrido para darse media vuelta
|
||||
void Enemy::checkPath()
|
||||
{
|
||||
if (sprite_->getPosX() > x2_ || sprite_->getPosX() < x1_)
|
||||
{
|
||||
void Enemy::checkPath() {
|
||||
if (sprite_->getPosX() > x2_ || sprite_->getPosX() < x1_) {
|
||||
// Recoloca
|
||||
if (sprite_->getPosX() > x2_)
|
||||
{
|
||||
if (sprite_->getPosX() > x2_) {
|
||||
sprite_->setPosX(x2_);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
sprite_->setPosX(x1_);
|
||||
}
|
||||
|
||||
@@ -69,21 +63,16 @@ void Enemy::checkPath()
|
||||
sprite_->setVelX(sprite_->getVelX() * (-1));
|
||||
|
||||
// Invierte el sprite
|
||||
if (should_flip_)
|
||||
{
|
||||
if (should_flip_) {
|
||||
sprite_->flip();
|
||||
}
|
||||
}
|
||||
|
||||
if (sprite_->getPosY() > y2_ || sprite_->getPosY() < y1_)
|
||||
{
|
||||
if (sprite_->getPosY() > y2_ || sprite_->getPosY() < y1_) {
|
||||
// Recoloca
|
||||
if (sprite_->getPosY() > y2_)
|
||||
{
|
||||
if (sprite_->getPosY() > y2_) {
|
||||
sprite_->setPosY(y2_);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
sprite_->setPosY(y1_);
|
||||
}
|
||||
|
||||
@@ -91,21 +80,18 @@ void Enemy::checkPath()
|
||||
sprite_->setVelY(sprite_->getVelY() * (-1));
|
||||
|
||||
// Invierte el sprite
|
||||
if (should_flip_)
|
||||
{
|
||||
if (should_flip_) {
|
||||
sprite_->flip();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Devuelve el rectangulo que contiene al enemigo
|
||||
SDL_Rect Enemy::getRect()
|
||||
{
|
||||
SDL_Rect Enemy::getRect() {
|
||||
return sprite_->getRect();
|
||||
}
|
||||
|
||||
// Obtiene el rectangulo de colision del enemigo
|
||||
SDL_Rect &Enemy::getCollider()
|
||||
{
|
||||
SDL_Rect& Enemy::getCollider() {
|
||||
return collider_;
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint8
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint8
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
class SAnimatedSprite; // lines 7-7
|
||||
|
||||
// Estructura para pasar los datos de un enemigo
|
||||
struct EnemyData
|
||||
{
|
||||
struct EnemyData {
|
||||
std::string surface_path; // Ruta al fichero con la textura
|
||||
std::string animation_path; // Ruta al fichero con la animación
|
||||
int w; // Anchura del enemigo
|
||||
@@ -27,9 +27,8 @@ struct EnemyData
|
||||
std::string color; // Color del enemigo
|
||||
};
|
||||
|
||||
class Enemy
|
||||
{
|
||||
private:
|
||||
class Enemy {
|
||||
private:
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<SAnimatedSprite> sprite_; // Sprite del enemigo
|
||||
|
||||
@@ -47,9 +46,9 @@ private:
|
||||
// Comprueba si ha llegado al limite del recorrido para darse media vuelta
|
||||
void checkPath();
|
||||
|
||||
public:
|
||||
public:
|
||||
// Constructor
|
||||
explicit Enemy(const EnemyData &enemy);
|
||||
explicit Enemy(const EnemyData& enemy);
|
||||
|
||||
// Destructor
|
||||
~Enemy() = default;
|
||||
@@ -64,5 +63,5 @@ public:
|
||||
SDL_Rect getRect();
|
||||
|
||||
// Obtiene el rectangulo de colision del enemigo
|
||||
SDL_Rect &getCollider();
|
||||
SDL_Rect& getCollider();
|
||||
};
|
||||
|
||||
2
source/external/.clang-format
vendored
Normal file
2
source/external/.clang-format
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
DisableFormat: true
|
||||
SortIncludes: Never
|
||||
4
source/external/.clang-tidy
vendored
Normal file
4
source/external/.clang-tidy
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# source/external/.clang-tidy
|
||||
Checks: '-*'
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: ''
|
||||
@@ -1,38 +1,37 @@
|
||||
#include "jail_audio.h"
|
||||
#include <SDL2/SDL_rwops.h> // Para SDL_RWFromMem
|
||||
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <SDL3/SDL_rwops.h> // Para SDL_RWFromMem
|
||||
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
||||
#include <stdint.h> // Para uint8_t, uint32_t
|
||||
#include <stdio.h> // Para NULL, fseek, fclose, fopen, fread, ftell
|
||||
#include <stdlib.h> // Para free, malloc
|
||||
|
||||
#include "stb_vorbis.c" // Para stb_vorbis_decode_memory
|
||||
|
||||
constexpr int JA_MAX_SIMULTANEOUS_CHANNELS = 20;
|
||||
|
||||
struct JA_Sound_t
|
||||
{
|
||||
struct JA_Sound_t {
|
||||
Uint32 length{0};
|
||||
Uint8 *buffer{NULL};
|
||||
Uint8* buffer{NULL};
|
||||
};
|
||||
|
||||
struct JA_Channel_t
|
||||
{
|
||||
JA_Sound_t *sound;
|
||||
struct JA_Channel_t {
|
||||
JA_Sound_t* sound;
|
||||
int pos{0};
|
||||
int times{0};
|
||||
JA_Channel_state state{JA_CHANNEL_FREE};
|
||||
};
|
||||
|
||||
struct JA_Music_t
|
||||
{
|
||||
struct JA_Music_t {
|
||||
int samples{0};
|
||||
Uint32 length{0};
|
||||
int pos{0};
|
||||
int times{0};
|
||||
short *output{NULL};
|
||||
short* output{NULL};
|
||||
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];
|
||||
|
||||
int JA_freq{48000};
|
||||
@@ -49,67 +48,51 @@ int fade_start_time;
|
||||
int fade_duration;
|
||||
int fade_initial_volume;
|
||||
|
||||
void audioCallback(void *userdata, uint8_t *stream, int len)
|
||||
{
|
||||
void audioCallback(void* userdata, uint8_t* stream, int 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;
|
||||
if (fading)
|
||||
{
|
||||
if (fading) {
|
||||
int time = SDL_GetTicks();
|
||||
if (time > (fade_start_time + fade_duration))
|
||||
{
|
||||
if (time > (fade_start_time + fade_duration)) {
|
||||
fading = false;
|
||||
current_music->pos = 0;
|
||||
current_music->state = JA_MUSIC_STOPPED;
|
||||
volume = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
const int time_passed = time - fade_start_time;
|
||||
const float percent = (float)time_passed / (float)fade_duration;
|
||||
volume = JA_musicVolume * (1.0 - percent);
|
||||
}
|
||||
}
|
||||
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);
|
||||
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);
|
||||
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
|
||||
{
|
||||
} else {
|
||||
current_music->pos = 0;
|
||||
current_music->state = JA_MUSIC_STOPPED;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Mixar els channels mi amol
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
|
||||
{
|
||||
if (channels[i].state == JA_CHANNEL_PLAYING)
|
||||
{
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
|
||||
if (channels[i].state == JA_CHANNEL_PLAYING) {
|
||||
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);
|
||||
channels[i].pos += size;
|
||||
if (size < len)
|
||||
{
|
||||
if (channels[i].times != 0)
|
||||
{
|
||||
if (size < len) {
|
||||
if (channels[i].times != 0) {
|
||||
SDL_MixAudioFormat(stream + size, channels[i].sound->buffer, AUDIO_S16, len - size, JA_soundVolume);
|
||||
channels[i].pos = len - size;
|
||||
if (channels[i].times > 0)
|
||||
channels[i].times--;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
JA_StopChannel(i);
|
||||
}
|
||||
}
|
||||
@@ -117,8 +100,7 @@ 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) {
|
||||
JA_freq = freq;
|
||||
JA_format = format;
|
||||
JA_channels = channels;
|
||||
@@ -129,32 +111,29 @@ void JA_Init(const int freq, const SDL_AudioFormat format, const int channels)
|
||||
SDL_PauseAudioDevice(sdlAudioDevice, 0);
|
||||
}
|
||||
|
||||
void JA_Quit()
|
||||
{
|
||||
void JA_Quit() {
|
||||
SDL_PauseAudioDevice(sdlAudioDevice, 1);
|
||||
if (sdlAudioDevice != 0)
|
||||
SDL_CloseAudioDevice(sdlAudioDevice);
|
||||
sdlAudioDevice = 0;
|
||||
}
|
||||
|
||||
JA_Music_t *JA_LoadMusic(Uint8 *buffer, Uint32 length)
|
||||
{
|
||||
JA_Music_t* JA_LoadMusic(Uint8* buffer, Uint32 length) {
|
||||
int chan, samplerate;
|
||||
JA_Music_t *music = new JA_Music_t();
|
||||
JA_Music_t* music = new JA_Music_t();
|
||||
|
||||
music->samples = stb_vorbis_decode_memory(buffer, length, &chan, &samplerate, &music->output);
|
||||
|
||||
SDL_AudioCVT cvt;
|
||||
SDL_BuildAudioCVT(&cvt, AUDIO_S16, chan, samplerate, JA_format, JA_channels, JA_freq);
|
||||
if (cvt.needed)
|
||||
{
|
||||
if (cvt.needed) {
|
||||
cvt.len = music->samples * chan * 2;
|
||||
music->length = cvt.len;
|
||||
cvt.buf = (Uint8 *)SDL_malloc(cvt.len * cvt.len_mult);
|
||||
cvt.buf = (Uint8*)SDL_malloc(cvt.len * cvt.len_mult);
|
||||
SDL_memcpy(cvt.buf, music->output, cvt.len);
|
||||
SDL_ConvertAudio(&cvt);
|
||||
free(music->output);
|
||||
music->output = (short *)cvt.buf;
|
||||
music->output = (short*)cvt.buf;
|
||||
}
|
||||
music->length = music->samples * chan * 2;
|
||||
music->pos = 0;
|
||||
@@ -163,32 +142,29 @@ JA_Music_t *JA_LoadMusic(Uint8 *buffer, Uint32 length)
|
||||
return music;
|
||||
}
|
||||
|
||||
JA_Music_t *JA_LoadMusic(const char *filename)
|
||||
{
|
||||
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");
|
||||
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);
|
||||
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);
|
||||
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)
|
||||
return;
|
||||
|
||||
if (current_music != NULL)
|
||||
{
|
||||
if (current_music != NULL) {
|
||||
current_music->pos = 0;
|
||||
current_music->state = JA_MUSIC_STOPPED;
|
||||
}
|
||||
@@ -198,8 +174,7 @@ void JA_PlayMusic(JA_Music_t *music, const int loop)
|
||||
current_music->times = loop;
|
||||
}
|
||||
|
||||
void JA_PauseMusic()
|
||||
{
|
||||
void JA_PauseMusic() {
|
||||
if (!JA_musicEnabled)
|
||||
return;
|
||||
|
||||
@@ -208,8 +183,7 @@ void JA_PauseMusic()
|
||||
current_music->state = JA_MUSIC_PAUSED;
|
||||
}
|
||||
|
||||
void JA_ResumeMusic()
|
||||
{
|
||||
void JA_ResumeMusic() {
|
||||
if (!JA_musicEnabled)
|
||||
return;
|
||||
|
||||
@@ -218,8 +192,7 @@ void JA_ResumeMusic()
|
||||
current_music->state = JA_MUSIC_PLAYING;
|
||||
}
|
||||
|
||||
void JA_StopMusic()
|
||||
{
|
||||
void JA_StopMusic() {
|
||||
if (!JA_musicEnabled)
|
||||
return;
|
||||
|
||||
@@ -229,8 +202,7 @@ void JA_StopMusic()
|
||||
current_music->state = JA_MUSIC_STOPPED;
|
||||
}
|
||||
|
||||
void JA_FadeOutMusic(const int milliseconds)
|
||||
{
|
||||
void JA_FadeOutMusic(const int milliseconds) {
|
||||
if (!JA_musicEnabled)
|
||||
return;
|
||||
if (current_music == NULL || current_music->state == JA_MUSIC_INVALID)
|
||||
@@ -242,8 +214,7 @@ void JA_FadeOutMusic(const int milliseconds)
|
||||
fade_initial_volume = JA_musicVolume;
|
||||
}
|
||||
|
||||
JA_Music_state JA_GetMusicState()
|
||||
{
|
||||
JA_Music_state JA_GetMusicState() {
|
||||
if (!JA_musicEnabled)
|
||||
return JA_MUSIC_DISABLED;
|
||||
|
||||
@@ -252,61 +223,54 @@ JA_Music_state JA_GetMusicState()
|
||||
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;
|
||||
free(music->output);
|
||||
delete music;
|
||||
}
|
||||
|
||||
int JA_SetMusicVolume(int volume)
|
||||
{
|
||||
int JA_SetMusicVolume(int volume) {
|
||||
JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0
|
||||
: volume;
|
||||
return JA_musicVolume;
|
||||
}
|
||||
|
||||
void JA_SetMusicPosition(float value)
|
||||
{
|
||||
void JA_SetMusicPosition(float value) {
|
||||
if (!current_music)
|
||||
return;
|
||||
current_music->pos = value * JA_freq;
|
||||
}
|
||||
|
||||
float JA_GetMusicPosition()
|
||||
{
|
||||
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)
|
||||
JA_StopMusic();
|
||||
|
||||
JA_musicEnabled = value;
|
||||
}
|
||||
|
||||
JA_Sound_t *JA_NewSound(Uint8 *buffer, Uint32 length)
|
||||
{
|
||||
JA_Sound_t *sound = new JA_Sound_t();
|
||||
JA_Sound_t* JA_NewSound(Uint8* buffer, Uint32 length) {
|
||||
JA_Sound_t* sound = new JA_Sound_t();
|
||||
sound->buffer = buffer;
|
||||
sound->length = length;
|
||||
return sound;
|
||||
}
|
||||
|
||||
JA_Sound_t *JA_LoadSound(uint8_t *buffer, uint32_t size)
|
||||
{
|
||||
JA_Sound_t *sound = new JA_Sound_t();
|
||||
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);
|
||||
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);
|
||||
@@ -316,16 +280,15 @@ JA_Sound_t *JA_LoadSound(uint8_t *buffer, uint32_t size)
|
||||
return sound;
|
||||
}
|
||||
|
||||
JA_Sound_t *JA_LoadSound(const char *filename)
|
||||
{
|
||||
JA_Sound_t *sound = new JA_Sound_t();
|
||||
JA_Sound_t* JA_LoadSound(const char* filename) {
|
||||
JA_Sound_t* sound = new JA_Sound_t();
|
||||
SDL_AudioSpec wavSpec;
|
||||
SDL_LoadWAV(filename, &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);
|
||||
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);
|
||||
@@ -335,14 +298,12 @@ JA_Sound_t *JA_LoadSound(const char *filename)
|
||||
return sound;
|
||||
}
|
||||
|
||||
int JA_PlaySound(JA_Sound_t *sound, const int loop)
|
||||
{
|
||||
int JA_PlaySound(JA_Sound_t* sound, const int loop) {
|
||||
if (!JA_soundEnabled)
|
||||
return -1;
|
||||
|
||||
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)
|
||||
@@ -355,8 +316,7 @@ int JA_PlaySound(JA_Sound_t *sound, const int loop)
|
||||
return channel;
|
||||
}
|
||||
|
||||
int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop)
|
||||
{
|
||||
int JA_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int loop) {
|
||||
if (!JA_soundEnabled)
|
||||
return -1;
|
||||
|
||||
@@ -370,10 +330,8 @@ int JA_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop)
|
||||
return channel;
|
||||
}
|
||||
|
||||
void JA_DeleteSound(JA_Sound_t *sound)
|
||||
{
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
|
||||
{
|
||||
void JA_DeleteSound(JA_Sound_t* sound) {
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
|
||||
if (channels[i].sound == sound)
|
||||
JA_StopChannel(i);
|
||||
}
|
||||
@@ -381,70 +339,54 @@ void JA_DeleteSound(JA_Sound_t *sound)
|
||||
delete sound;
|
||||
}
|
||||
|
||||
void JA_PauseChannel(const int channel)
|
||||
{
|
||||
void JA_PauseChannel(const int channel) {
|
||||
if (!JA_soundEnabled)
|
||||
return;
|
||||
|
||||
if (channel == -1)
|
||||
{
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
|
||||
{
|
||||
if (channel == -1) {
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void JA_ResumeChannel(const int channel)
|
||||
{
|
||||
void JA_ResumeChannel(const int channel) {
|
||||
if (!JA_soundEnabled)
|
||||
return;
|
||||
|
||||
if (channel == -1)
|
||||
{
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
|
||||
{
|
||||
if (channel == -1) {
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void JA_StopChannel(const int channel)
|
||||
{
|
||||
void JA_StopChannel(const int channel) {
|
||||
if (!JA_soundEnabled)
|
||||
return;
|
||||
|
||||
if (channel == -1)
|
||||
{
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
|
||||
{
|
||||
if (channel == -1) {
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
|
||||
channels[i].state = JA_CHANNEL_FREE;
|
||||
channels[i].pos = 0;
|
||||
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].pos = 0;
|
||||
channels[channel].sound = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
JA_Channel_state JA_GetChannelState(const int channel)
|
||||
{
|
||||
JA_Channel_state JA_GetChannelState(const int channel) {
|
||||
if (!JA_soundEnabled)
|
||||
return JA_SOUND_DISABLED;
|
||||
|
||||
@@ -453,25 +395,21 @@ JA_Channel_state JA_GetChannelState(const int channel)
|
||||
return channels[channel].state;
|
||||
}
|
||||
|
||||
int JA_SetSoundVolume(int volume)
|
||||
{
|
||||
int JA_SetSoundVolume(int volume) {
|
||||
JA_soundVolume = volume > 128 ? 128 : volume < 0 ? 0
|
||||
: volume;
|
||||
return JA_soundVolume;
|
||||
}
|
||||
|
||||
void JA_EnableSound(const bool value)
|
||||
{
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++)
|
||||
{
|
||||
void JA_EnableSound(const bool value) {
|
||||
for (int i = 0; i < JA_MAX_SIMULTANEOUS_CHANNELS; i++) {
|
||||
if (channels[i].state == JA_CHANNEL_PLAYING)
|
||||
JA_StopChannel(i);
|
||||
}
|
||||
JA_soundEnabled = value;
|
||||
}
|
||||
|
||||
int JA_SetVolume(int volume)
|
||||
{
|
||||
int JA_SetVolume(int volume) {
|
||||
JA_musicVolume = volume > 128 ? 128 : volume < 0 ? 0
|
||||
: volume;
|
||||
JA_soundVolume = JA_musicVolume / 2;
|
||||
@@ -1,20 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_audio.h> // Para SDL_AudioFormat
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint32, Uint8
|
||||
#include <SDL3/SDL_audio.h> // Para SDL_AudioFormat
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint32, Uint8
|
||||
struct JA_Music_t; // lines 5-5
|
||||
struct JA_Sound_t; // lines 6-6
|
||||
|
||||
enum JA_Channel_state
|
||||
{
|
||||
enum JA_Channel_state {
|
||||
JA_CHANNEL_INVALID,
|
||||
JA_CHANNEL_FREE,
|
||||
JA_CHANNEL_PLAYING,
|
||||
JA_CHANNEL_PAUSED,
|
||||
JA_SOUND_DISABLED
|
||||
};
|
||||
enum JA_Music_state
|
||||
{
|
||||
enum JA_Music_state {
|
||||
JA_MUSIC_INVALID,
|
||||
JA_MUSIC_PLAYING,
|
||||
JA_MUSIC_PAUSED,
|
||||
@@ -28,30 +26,30 @@ struct JA_Music_t;
|
||||
void JA_Init(const int freq, const SDL_AudioFormat format, const int channels);
|
||||
void JA_Quit();
|
||||
|
||||
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);
|
||||
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_PauseMusic();
|
||||
void JA_ResumeMusic();
|
||||
void JA_StopMusic();
|
||||
void JA_FadeOutMusic(const int milliseconds);
|
||||
JA_Music_state JA_GetMusicState();
|
||||
void JA_DeleteMusic(JA_Music_t *music);
|
||||
void JA_DeleteMusic(JA_Music_t* music);
|
||||
int JA_SetMusicVolume(int volume);
|
||||
void JA_SetMusicPosition(float value);
|
||||
float JA_GetMusicPosition();
|
||||
void JA_EnableMusic(const bool value);
|
||||
|
||||
JA_Sound_t *JA_NewSound(Uint8 *buffer, Uint32 length);
|
||||
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_PlaySoundOnChannel(JA_Sound_t *sound, const int channel, const int loop = 0);
|
||||
JA_Sound_t* JA_NewSound(Uint8* buffer, Uint32 length);
|
||||
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_PlaySoundOnChannel(JA_Sound_t* sound, const int channel, const int loop = 0);
|
||||
void JA_PauseChannel(const int channel);
|
||||
void JA_ResumeChannel(const int channel);
|
||||
void JA_StopChannel(const int channel);
|
||||
JA_Channel_state JA_GetChannelState(const int channel);
|
||||
void JA_DeleteSound(JA_Sound_t *sound);
|
||||
void JA_DeleteSound(JA_Sound_t* sound);
|
||||
int JA_SetSoundVolume(int volume);
|
||||
void JA_EnableSound(const bool value);
|
||||
|
||||
267
source/external/jail_shader.cpp
vendored
Normal file
267
source/external/jail_shader.cpp
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
#include "jail_shader.h"
|
||||
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Point
|
||||
#include <SDL3/SDL_stdinc.h> // Para SDL_bool
|
||||
|
||||
#include <cstring> // Para strncmp
|
||||
#include <iostream> // Para basic_ostream, operator<<, endl, cout
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <vector> // Para vector
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <OpenGL/OpenGL.h> // Para OpenGL en macOS
|
||||
|
||||
#include "CoreFoundation/CoreFoundation.h" // Para Core Foundation en macOS
|
||||
#if ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
||||
#include <OpenGL/gl3.h> // Para OpenGL 3 en macOS
|
||||
#else // NO ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
||||
#include <OpenGL/gl.h> // Para OpenGL (compatibilidad) en macOS
|
||||
#endif // ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
||||
#else // SI NO ES __APPLE__
|
||||
#include <SDL3/SDL_opengl.h> // Para GLuint, glTexCoord2f, glVertex2f, GLfloat
|
||||
#endif // __APPLE__
|
||||
|
||||
namespace shader {
|
||||
SDL_Window* win = nullptr;
|
||||
SDL_Renderer* renderer = nullptr;
|
||||
GLuint programId = 0;
|
||||
SDL_Texture* backBuffer = nullptr;
|
||||
SDL_Point win_size = {320 * 4, 256 * 4};
|
||||
SDL_Point tex_size = {320, 256};
|
||||
bool usingOpenGL = false;
|
||||
|
||||
#ifndef __APPLE__
|
||||
// Declaración de funciones de extensión de OpenGL (evitando GLEW)
|
||||
PFNGLCREATESHADERPROC glCreateShader;
|
||||
PFNGLSHADERSOURCEPROC glShaderSource;
|
||||
PFNGLCOMPILESHADERPROC glCompileShader;
|
||||
PFNGLGETSHADERIVPROC glGetShaderiv;
|
||||
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
|
||||
PFNGLDELETESHADERPROC glDeleteShader;
|
||||
PFNGLATTACHSHADERPROC glAttachShader;
|
||||
PFNGLCREATEPROGRAMPROC glCreateProgram;
|
||||
PFNGLLINKPROGRAMPROC glLinkProgram;
|
||||
PFNGLVALIDATEPROGRAMPROC glValidateProgram;
|
||||
PFNGLGETPROGRAMIVPROC glGetProgramiv;
|
||||
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
|
||||
PFNGLUSEPROGRAMPROC glUseProgram;
|
||||
|
||||
bool initGLExtensions() {
|
||||
glCreateShader = (PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader");
|
||||
glShaderSource = (PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource");
|
||||
glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader");
|
||||
glGetShaderiv = (PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv");
|
||||
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog");
|
||||
glDeleteShader = (PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader");
|
||||
glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader");
|
||||
glCreateProgram = (PFNGLCREATEPROGRAMPROC)SDL_GL_GetProcAddress("glCreateProgram");
|
||||
glLinkProgram = (PFNGLLINKPROGRAMPROC)SDL_GL_GetProcAddress("glLinkProgram");
|
||||
glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)SDL_GL_GetProcAddress("glValidateProgram");
|
||||
glGetProgramiv = (PFNGLGETPROGRAMIVPROC)SDL_GL_GetProcAddress("glGetProgramiv");
|
||||
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)SDL_GL_GetProcAddress("glGetProgramInfoLog");
|
||||
glUseProgram = (PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram");
|
||||
|
||||
return glCreateShader && glShaderSource && glCompileShader && glGetShaderiv &&
|
||||
glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram &&
|
||||
glLinkProgram && glValidateProgram && glGetProgramiv && glGetProgramInfoLog &&
|
||||
glUseProgram;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Función para compilar un shader a partir de un std::string
|
||||
GLuint compileShader(const std::string& source, GLuint shaderType) {
|
||||
if (source.empty()) {
|
||||
throw std::runtime_error("ERROR FATAL: El código fuente del shader está vacío.");
|
||||
}
|
||||
|
||||
// Crear identificador del shader
|
||||
GLuint resultado = glCreateShader(shaderType);
|
||||
|
||||
// Agregar una directiva según el tipo de shader
|
||||
std::string directiva = (shaderType == GL_VERTEX_SHADER)
|
||||
? "#define VERTEX\n"
|
||||
: "#define FRAGMENT\n";
|
||||
|
||||
const char* sources[2] = {directiva.c_str(), source.c_str()};
|
||||
|
||||
// Especificar el código fuente del shader
|
||||
glShaderSource(resultado, 2, sources, nullptr);
|
||||
|
||||
// Compilar el shader
|
||||
glCompileShader(resultado);
|
||||
|
||||
// Verificar si la compilación fue exitosa
|
||||
GLint compiladoCorrectamente = GL_FALSE;
|
||||
glGetShaderiv(resultado, GL_COMPILE_STATUS, &compiladoCorrectamente);
|
||||
if (compiladoCorrectamente != GL_TRUE) {
|
||||
std::cout << "Error en la compilación del shader (" << resultado << ")!" << std::endl;
|
||||
GLint longitudLog;
|
||||
glGetShaderiv(resultado, GL_INFO_LOG_LENGTH, &longitudLog);
|
||||
if (longitudLog > 0) {
|
||||
std::vector<GLchar> log(longitudLog);
|
||||
glGetShaderInfoLog(resultado, longitudLog, &longitudLog, log.data());
|
||||
std::cout << "Registro de compilación del shader: " << log.data() << std::endl;
|
||||
}
|
||||
glDeleteShader(resultado);
|
||||
resultado = 0;
|
||||
}
|
||||
return resultado;
|
||||
}
|
||||
|
||||
// Función para compilar un programa de shaders (vertex y fragment) a partir de std::string
|
||||
GLuint compileProgram(const std::string& vertexShaderSource, const std::string& fragmentShaderSource) {
|
||||
GLuint idPrograma = glCreateProgram();
|
||||
|
||||
// Si el fragment shader está vacío, reutilizamos el código del vertex shader
|
||||
GLuint idShaderVertice = compileShader(vertexShaderSource, GL_VERTEX_SHADER);
|
||||
GLuint idShaderFragmento = compileShader(fragmentShaderSource.empty() ? vertexShaderSource : fragmentShaderSource, GL_FRAGMENT_SHADER);
|
||||
|
||||
if (idShaderVertice && idShaderFragmento) {
|
||||
// Asociar los shaders al programa
|
||||
glAttachShader(idPrograma, idShaderVertice);
|
||||
glAttachShader(idPrograma, idShaderFragmento);
|
||||
glLinkProgram(idPrograma);
|
||||
glValidateProgram(idPrograma);
|
||||
|
||||
// Verificar el estado del enlace
|
||||
GLint longitudLog;
|
||||
glGetProgramiv(idPrograma, GL_INFO_LOG_LENGTH, &longitudLog);
|
||||
if (longitudLog > 0) {
|
||||
std::vector<char> log(longitudLog);
|
||||
glGetProgramInfoLog(idPrograma, longitudLog, &longitudLog, log.data());
|
||||
std::cout << "Registro de información del programa:" << std::endl
|
||||
<< log.data() << std::endl;
|
||||
}
|
||||
}
|
||||
if (idShaderVertice) {
|
||||
glDeleteShader(idShaderVertice);
|
||||
}
|
||||
if (idShaderFragmento) {
|
||||
glDeleteShader(idShaderFragmento);
|
||||
}
|
||||
return idPrograma;
|
||||
}
|
||||
|
||||
bool init(SDL_Window* ventana, SDL_Texture* texturaBackBuffer, const std::string& vertexShader, const std::string& fragmentShader) {
|
||||
shader::win = ventana;
|
||||
shader::renderer = SDL_GetRenderer(ventana);
|
||||
shader::backBuffer = texturaBackBuffer;
|
||||
SDL_GetWindowSize(ventana, &win_size.x, &win_size.y);
|
||||
|
||||
int acceso;
|
||||
SDL_QueryTexture(texturaBackBuffer, nullptr, &acceso, &tex_size.x, &tex_size.y);
|
||||
if (acceso != SDL_TEXTUREACCESS_TARGET) {
|
||||
throw std::runtime_error("ERROR FATAL: La textura debe tener definido SDL_TEXTUREACCESS_TARGET.");
|
||||
}
|
||||
|
||||
SDL_RendererInfo infoRenderer;
|
||||
SDL_GetRendererInfo(renderer, &infoRenderer);
|
||||
|
||||
// Verificar que el renderer sea OpenGL
|
||||
if (!strncmp(infoRenderer.name, "opengl", 6)) {
|
||||
#ifndef __APPLE__
|
||||
if (!initGLExtensions()) {
|
||||
std::cout << "ADVERTENCIA: No se han podido inicializar las extensiones de OpenGL." << std::endl;
|
||||
usingOpenGL = false;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
// Compilar el programa de shaders utilizando std::string
|
||||
programId = compileProgram(vertexShader, fragmentShader);
|
||||
} else {
|
||||
std::cout << "ADVERTENCIA: El driver del renderer no es OpenGL." << std::endl;
|
||||
usingOpenGL = false;
|
||||
return false;
|
||||
}
|
||||
usingOpenGL = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void render() {
|
||||
GLint oldProgramId;
|
||||
// Establece el color de fondo
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||
SDL_SetRenderTarget(renderer, nullptr);
|
||||
SDL_RenderClear(renderer);
|
||||
|
||||
if (usingOpenGL) {
|
||||
SDL_GL_BindTexture(backBuffer, nullptr, nullptr);
|
||||
if (programId != 0) {
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgramId);
|
||||
glUseProgram(programId);
|
||||
}
|
||||
|
||||
// Recupera el tamaño lógico configurado con SDL_RenderSetLogicalSize
|
||||
int logicalW, logicalH;
|
||||
SDL_RenderGetLogicalSize(renderer, &logicalW, &logicalH);
|
||||
if (logicalW == 0 || logicalH == 0) {
|
||||
logicalW = win_size.x;
|
||||
logicalH = win_size.y;
|
||||
}
|
||||
|
||||
// Cálculo del viewport
|
||||
int viewportX = 0, viewportY = 0, viewportW = win_size.x, viewportH = win_size.y;
|
||||
SDL_bool useIntegerScale = SDL_RenderGetIntegerScale(renderer);
|
||||
if (useIntegerScale) {
|
||||
// Calcula el factor de escalado entero máximo que se puede aplicar
|
||||
int scaleX = win_size.x / logicalW;
|
||||
int scaleY = win_size.y / logicalH;
|
||||
int scale = (scaleX < scaleY ? scaleX : scaleY);
|
||||
if (scale < 1)
|
||||
scale = 1;
|
||||
viewportW = logicalW * scale;
|
||||
viewportH = logicalH * scale;
|
||||
viewportX = (win_size.x - viewportW) / 2;
|
||||
viewportY = (win_size.y - viewportH) / 2;
|
||||
} else {
|
||||
// Letterboxing: preserva la relación de aspecto usando una escala flotante
|
||||
float windowAspect = static_cast<float>(win_size.x) / win_size.y;
|
||||
float logicalAspect = static_cast<float>(logicalW) / logicalH;
|
||||
if (windowAspect > logicalAspect) {
|
||||
viewportW = static_cast<int>(logicalAspect * win_size.y);
|
||||
viewportX = (win_size.x - viewportW) / 2;
|
||||
} else {
|
||||
viewportH = static_cast<int>(win_size.x / logicalAspect);
|
||||
viewportY = (win_size.y - viewportH) / 2;
|
||||
}
|
||||
}
|
||||
glViewport(viewportX, viewportY, viewportW, viewportH);
|
||||
|
||||
// Configurar la proyección ortográfica usando el espacio lógico
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
// Queremos que el origen esté en la esquina superior izquierda del espacio lógico.
|
||||
glOrtho(0, static_cast<GLdouble>(logicalW), static_cast<GLdouble>(logicalH), 0, -1, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
// Dibuja el quad con las coordenadas ajustadas.
|
||||
// Se asignan las coordenadas de textura "normales" para que no quede espejado horizontalmente,
|
||||
// y se mantiene el flip vertical para que la imagen no aparezca volteada.
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
// Vértice superior izquierdo
|
||||
glTexCoord2f(0.0f, 1.0f);
|
||||
glVertex2f(0.0f, 0.0f);
|
||||
// Vértice superior derecho
|
||||
glTexCoord2f(1.0f, 1.0f);
|
||||
glVertex2f(static_cast<GLfloat>(logicalW), 0.0f);
|
||||
// Vértice inferior izquierdo
|
||||
glTexCoord2f(0.0f, 0.0f);
|
||||
glVertex2f(0.0f, static_cast<GLfloat>(logicalH));
|
||||
// Vértice inferior derecho
|
||||
glTexCoord2f(1.0f, 0.0f);
|
||||
glVertex2f(static_cast<GLfloat>(logicalW), static_cast<GLfloat>(logicalH));
|
||||
glEnd();
|
||||
|
||||
SDL_GL_SwapWindow(win);
|
||||
|
||||
if (programId != 0) {
|
||||
glUseProgram(oldProgramId);
|
||||
}
|
||||
} else {
|
||||
SDL_RenderCopy(renderer, backBuffer, nullptr, nullptr);
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
}
|
||||
} // namespace shader
|
||||
@@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_render.h> // Para SDL_Texture
|
||||
#include <SDL2/SDL_video.h> // Para SDL_Window
|
||||
#include <SDL3/SDL_render.h> // Para SDL_Texture
|
||||
#include <SDL3/SDL_video.h> // Para SDL_Window
|
||||
|
||||
#include <string>
|
||||
|
||||
// TIPS:
|
||||
@@ -37,9 +38,8 @@
|
||||
// Ah! una cosa mes: al compilar, en Linux afegir "-lGL", en Windows afegir "-lopengl32".
|
||||
// En Mac ni idea
|
||||
|
||||
namespace shader
|
||||
{
|
||||
// const bool init(SDL_Window *ventana, SDL_Texture *texturaBackBuffer, const char *vertexShader, const char *fragmentShader = nullptr);
|
||||
bool init(SDL_Window *ventana, SDL_Texture *texturaBackBuffer, const std::string &vertexShader, const std::string &fragmentShader = "");
|
||||
void render();
|
||||
}
|
||||
namespace shader {
|
||||
// const bool init(SDL_Window *ventana, SDL_Texture *texturaBackBuffer, const char *vertexShader, const char *fragmentShader = nullptr);
|
||||
bool init(SDL_Window* ventana, SDL_Texture* texturaBackBuffer, const std::string& vertexShader, const std::string& fragmentShader = "");
|
||||
void render();
|
||||
} // namespace shader
|
||||
709
source/game.cpp
709
source/game.cpp
@@ -1,709 +0,0 @@
|
||||
#include "game.h"
|
||||
#include <SDL2/SDL_render.h> // Para SDL_FLIP_HORIZONTAL
|
||||
#include <SDL2/SDL_scancode.h> // Para SDL_SCANCODE_7, SDL_SCANCODE_A, SDL_S...
|
||||
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
||||
#include <vector> // Para vector
|
||||
#include "asset.h" // Para Asset
|
||||
#include "cheevos.h" // Para Cheevos
|
||||
#include "debug.h" // Para Debug
|
||||
#include "defines.h" // Para BLOCK, PLAY_AREA_HEIGHT, RoomBorder::BOTTOM
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
#include "input.h" // Para Input, InputAction, INPUT_DO_NOT_ALLOW_REPEAT
|
||||
#include "item_tracker.h" // Para ItemTracker
|
||||
#include "jail_audio.h" // Para JA_PauseMusic, JA_GetMusicState, JA_P...
|
||||
#include "notifier.h" // Para Notifier, NotificationText, CHEEVO_NO...
|
||||
#include "options.h" // Para Options, options, Cheat, SectionState
|
||||
#include "resource.h" // Para ResourceRoom, Resource
|
||||
#include "room.h" // Para Room, RoomData
|
||||
#include "room_tracker.h" // Para RoomTracker
|
||||
#include "scoreboard.h" // Para ScoreboardData, Scoreboard
|
||||
#include "screen.h" // Para Screen
|
||||
#include "stats.h" // Para Stats
|
||||
#include "surface.h" // Para Surface
|
||||
#include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR
|
||||
#include "utils.h" // Para PaletteColor, stringToColor
|
||||
|
||||
// Constructor
|
||||
Game::Game(GameMode mode)
|
||||
: board_(std::make_shared<ScoreboardData>(0, 9, 0, true, 0, SDL_GetTicks(), options.cheats.jail_is_open == Cheat::CheatState::ENABLED)),
|
||||
scoreboard_(std::make_shared<Scoreboard>(board_)),
|
||||
room_tracker_(std::make_shared<RoomTracker>()),
|
||||
stats_(std::make_shared<Stats>(Asset::get()->get("stats.csv"), Asset::get()->get("stats_buffer.csv"))),
|
||||
mode_(mode),
|
||||
#ifdef DEBUG
|
||||
current_room_("03.room"),
|
||||
spawn_point_(PlayerSpawn(25 * BLOCK, 13 * BLOCK, 0, 0, 0, PlayerState::STANDING, SDL_FLIP_HORIZONTAL))
|
||||
#else
|
||||
current_room_("03.room"),
|
||||
spawn_point_(PlayerSpawn(25 * BLOCK, 13 * BLOCK, 0, 0, 0, PlayerState::STANDING, SDL_FLIP_HORIZONTAL))
|
||||
#endif
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Debug::get()->setEnabled(false);
|
||||
#endif
|
||||
|
||||
// Crea objetos e inicializa variables
|
||||
ItemTracker::init();
|
||||
DEMO_init();
|
||||
room_ = std::make_shared<Room>(current_room_, board_);
|
||||
initPlayer(spawn_point_, room_);
|
||||
initStats();
|
||||
total_items_ = getTotalItems();
|
||||
|
||||
createRoomNameTexture();
|
||||
changeRoom(current_room_);
|
||||
|
||||
Cheevos::get()->enable(!options.cheats.enabled()); // Deshabilita los logros si hay trucos activados
|
||||
Cheevos::get()->clearUnobtainableState();
|
||||
|
||||
options.section.section = (mode_ == GameMode::GAME) ? Section::GAME : Section::DEMO;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
}
|
||||
|
||||
Game::~Game()
|
||||
{
|
||||
ItemTracker::destroy();
|
||||
}
|
||||
|
||||
// Comprueba los eventos de la cola
|
||||
void Game::checkEvents()
|
||||
{
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
globalEvents::check(event);
|
||||
#ifdef DEBUG
|
||||
checkDebugEvents(event);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba el teclado
|
||||
void Game::checkInput()
|
||||
{
|
||||
if (Input::get()->checkInput(InputAction::TOGGLE_MUSIC, INPUT_DO_NOT_ALLOW_REPEAT))
|
||||
{
|
||||
board_->music = !board_->music;
|
||||
board_->music ? JA_ResumeMusic() : JA_PauseMusic();
|
||||
Notifier::get()->show({"MUSIC " + std::string(board_->music ? "ENABLED" : "DISABLED")}, NotificationText::CENTER);
|
||||
}
|
||||
|
||||
else if (Input::get()->checkInput(InputAction::PAUSE, INPUT_DO_NOT_ALLOW_REPEAT))
|
||||
{
|
||||
togglePause();
|
||||
Notifier::get()->show({std::string(paused_ ? "GAME PAUSED" : "GAME RUNNING")}, NotificationText::CENTER);
|
||||
}
|
||||
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Bucle para el juego
|
||||
void Game::run()
|
||||
{
|
||||
keepMusicPlaying();
|
||||
if (!board_->music && mode_ == GameMode::GAME)
|
||||
{
|
||||
JA_PauseMusic();
|
||||
}
|
||||
|
||||
while (options.section.section == Section::GAME || options.section.section == Section::DEMO)
|
||||
{
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
}
|
||||
|
||||
if (mode_ == GameMode::GAME)
|
||||
{
|
||||
JA_StopMusic();
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el juego, las variables, comprueba la entrada, etc.
|
||||
void Game::update()
|
||||
{
|
||||
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED)
|
||||
{
|
||||
// Actualiza el contador de ticks
|
||||
ticks_ = SDL_GetTicks();
|
||||
|
||||
// Comprueba el teclado
|
||||
checkInput();
|
||||
|
||||
#ifdef DEBUG
|
||||
Debug::get()->clear();
|
||||
#endif
|
||||
|
||||
// Actualiza los objetos
|
||||
room_->update();
|
||||
if (mode_ == GameMode::GAME)
|
||||
{
|
||||
player_->update();
|
||||
checkPlayerIsOnBorder();
|
||||
checkPlayerAndItems();
|
||||
checkPlayerAndEnemies();
|
||||
checkIfPlayerIsAlive();
|
||||
checkGameOver();
|
||||
checkEndGame();
|
||||
checkRestoringJail();
|
||||
checkSomeCheevos();
|
||||
}
|
||||
DEMO_checkRoomChange();
|
||||
scoreboard_->update();
|
||||
keepMusicPlaying();
|
||||
updateBlackScreen();
|
||||
|
||||
Screen::get()->update();
|
||||
|
||||
#ifdef DEBUG
|
||||
updateDebugInfo();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Pinta los objetos en pantalla
|
||||
void Game::render()
|
||||
{
|
||||
// Prepara para dibujar el frame
|
||||
Screen::get()->start();
|
||||
|
||||
// Dibuja los elementos del juego en orden
|
||||
room_->renderMap();
|
||||
room_->renderEnemies();
|
||||
room_->renderItems();
|
||||
if (mode_ == GameMode::GAME)
|
||||
{
|
||||
player_->render();
|
||||
}
|
||||
renderRoomName();
|
||||
scoreboard_->render();
|
||||
renderBlackScreen();
|
||||
|
||||
#ifdef DEBUG
|
||||
// Debug info
|
||||
renderDebugInfo();
|
||||
#endif
|
||||
|
||||
// Actualiza la pantalla
|
||||
Screen::get()->render();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Pasa la información de debug
|
||||
void Game::updateDebugInfo()
|
||||
{
|
||||
Debug::get()->add("X = " + std::to_string(static_cast<int>(player_->x_)) + ", Y = " + std::to_string(static_cast<int>(player_->y_)));
|
||||
Debug::get()->add("VX = " + std::to_string(player_->vx_).substr(0, 4) + ", VY = " + std::to_string(player_->vy_).substr(0, 4));
|
||||
Debug::get()->add("STATE = " + std::to_string(static_cast<int>(player_->state_)));
|
||||
}
|
||||
|
||||
// Pone la información de debug en pantalla
|
||||
void Game::renderDebugInfo()
|
||||
{
|
||||
|
||||
if (!Debug::get()->getEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto surface = Screen::get()->getRendererSurface();
|
||||
|
||||
// Borra el marcador
|
||||
SDL_Rect rect = {0, 18 * BLOCK, PLAY_AREA_WIDTH, GAMECANVAS_HEIGHT - PLAY_AREA_HEIGHT};
|
||||
surface->fillRect(&rect, static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
// Pinta la rejilla
|
||||
/*for (int i = 0; i < PLAY_AREA_BOTTOM; i += 8)
|
||||
{
|
||||
// Lineas horizontales
|
||||
surface->drawLine(0, i, PLAY_AREA_RIGHT, i, static_cast<Uint8>(PaletteColor::BRIGHT_BLACK));
|
||||
}
|
||||
for (int i = 0; i < PLAY_AREA_RIGHT; i += 8)
|
||||
{
|
||||
// Lineas verticales
|
||||
surface->drawLine(i, 0, i, PLAY_AREA_BOTTOM - 1, static_cast<Uint8>(PaletteColor::BRIGHT_BLACK));
|
||||
}*/
|
||||
|
||||
// Pinta el texto
|
||||
Debug::get()->setPos({1, 18 * 8});
|
||||
Debug::get()->render();
|
||||
|
||||
}
|
||||
|
||||
// Comprueba los eventos
|
||||
void Game::checkDebugEvents(const SDL_Event &event)
|
||||
{
|
||||
if (event.type == SDL_KEYDOWN && event.key.repeat == 0)
|
||||
{
|
||||
switch (event.key.keysym.scancode)
|
||||
{
|
||||
case SDL_SCANCODE_G:
|
||||
Debug::get()->toggleEnabled();
|
||||
options.cheats.invincible = static_cast<Cheat::CheatState>(Debug::get()->getEnabled());
|
||||
board_->music = !Debug::get()->getEnabled();
|
||||
board_->music ? JA_ResumeMusic() : JA_PauseMusic();
|
||||
break;
|
||||
|
||||
case SDL_SCANCODE_R:
|
||||
Resource::get()->reload();
|
||||
break;
|
||||
|
||||
case SDL_SCANCODE_W:
|
||||
changeRoom(room_->getRoom(RoomBorder::TOP));
|
||||
break;
|
||||
|
||||
case SDL_SCANCODE_A:
|
||||
changeRoom(room_->getRoom(RoomBorder::LEFT));
|
||||
break;
|
||||
|
||||
case SDL_SCANCODE_S:
|
||||
changeRoom(room_->getRoom(RoomBorder::BOTTOM));
|
||||
break;
|
||||
|
||||
case SDL_SCANCODE_D:
|
||||
changeRoom(room_->getRoom(RoomBorder::RIGHT));
|
||||
break;
|
||||
|
||||
case SDL_SCANCODE_7:
|
||||
Notifier::get()->show({"ACHIEVEMENT UNLOCKED!", "I LIKE MY MULTICOLOURED FRIENDS"}, NotificationText::CENTER, CHEEVO_NOTIFICATION_DURATION, -1, false, "F7");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Escribe el nombre de la pantalla
|
||||
void Game::renderRoomName()
|
||||
{
|
||||
// Dibuja la textura con el nombre de la habitación
|
||||
room_name_surface_->render(nullptr, &room_name_rect_);
|
||||
}
|
||||
|
||||
// Cambia de habitación
|
||||
bool Game::changeRoom(const std::string &room_path)
|
||||
{
|
||||
// En las habitaciones los limites tienen la cadena del fichero o un 0 en caso de no limitar con nada
|
||||
if (room_path == "0")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verifica que exista el fichero que se va a cargar
|
||||
if (Asset::get()->get(room_path) != "")
|
||||
{
|
||||
// Crea un objeto habitación nuevo a partir del fichero
|
||||
room_ = std::make_shared<Room>(room_path, board_);
|
||||
|
||||
// Pone el nombre de la habitación en la textura
|
||||
fillRoomNameTexture();
|
||||
|
||||
// Pone el color del marcador en función del color del borde de la habitación
|
||||
setScoreBoardColor();
|
||||
|
||||
if (room_tracker_->addRoom(room_path))
|
||||
{
|
||||
// Incrementa el contador de habitaciones visitadas
|
||||
board_->rooms++;
|
||||
options.stats.rooms = board_->rooms;
|
||||
|
||||
// Actualiza las estadisticas
|
||||
stats_->addVisit(room_->getName());
|
||||
}
|
||||
|
||||
// Pasa la nueva habitación al jugador
|
||||
player_->setRoom(room_);
|
||||
|
||||
// Cambia la habitación actual
|
||||
current_room_ = room_path;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si el jugador esta en el borde de la pantalla
|
||||
void Game::checkPlayerIsOnBorder()
|
||||
{
|
||||
if (player_->getOnBorder())
|
||||
{
|
||||
const std::string roomName = room_->getRoom(player_->getBorder());
|
||||
if (changeRoom(roomName))
|
||||
{
|
||||
player_->switchBorders();
|
||||
spawn_point_ = player_->getSpawnParams();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las colisiones del jugador con los enemigos
|
||||
bool Game::checkPlayerAndEnemies()
|
||||
{
|
||||
const bool death = room_->enemyCollision(player_->getCollider());
|
||||
if (death)
|
||||
{
|
||||
killPlayer();
|
||||
}
|
||||
return death;
|
||||
}
|
||||
|
||||
// Comprueba las colisiones del jugador con los objetos
|
||||
void Game::checkPlayerAndItems()
|
||||
{
|
||||
room_->itemCollision(player_->getCollider());
|
||||
}
|
||||
|
||||
// Comprueba si el jugador esta vivo
|
||||
void Game::checkIfPlayerIsAlive()
|
||||
{
|
||||
if (!player_->isAlive())
|
||||
{
|
||||
killPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba si ha terminado la partida
|
||||
void Game::checkGameOver()
|
||||
{
|
||||
if (board_->lives < 0 && black_screen_counter_ > 17)
|
||||
{
|
||||
options.section.section = Section::GAME_OVER;
|
||||
}
|
||||
}
|
||||
|
||||
// Mata al jugador
|
||||
void Game::killPlayer()
|
||||
{
|
||||
if (options.cheats.invincible == Cheat::CheatState::ENABLED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Resta una vida al jugador
|
||||
if (options.cheats.infinite_lives == Cheat::CheatState::DISABLED)
|
||||
{
|
||||
--board_->lives;
|
||||
}
|
||||
|
||||
// Actualiza las estadisticas
|
||||
stats_->addDeath(room_->getName());
|
||||
|
||||
// Invalida el logro de pasarse el juego sin morir
|
||||
Cheevos::get()->setUnobtainable(11);
|
||||
|
||||
// Sonido
|
||||
JA_PlaySound(Resource::get()->getSound("death.wav"));
|
||||
|
||||
// Pone la pantalla en negro un tiempo
|
||||
setBlackScreen();
|
||||
|
||||
// Crea la nueva habitación y el nuevo jugador
|
||||
room_ = std::make_shared<Room>(current_room_, board_);
|
||||
initPlayer(spawn_point_, room_);
|
||||
|
||||
// Pone los objetos en pausa mientras esta la habitación en negro
|
||||
room_->setPaused(true);
|
||||
player_->setPaused(true);
|
||||
}
|
||||
|
||||
// Establece la pantalla en negro
|
||||
void Game::setBlackScreen()
|
||||
{
|
||||
black_screen_ = true;
|
||||
}
|
||||
|
||||
// Actualiza las variables relativas a la pantalla en negro
|
||||
void Game::updateBlackScreen()
|
||||
{
|
||||
if (black_screen_)
|
||||
{
|
||||
black_screen_counter_++;
|
||||
if (black_screen_counter_ > 20)
|
||||
{
|
||||
black_screen_ = false;
|
||||
black_screen_counter_ = 0;
|
||||
|
||||
player_->setPaused(false);
|
||||
room_->setPaused(false);
|
||||
Screen::get()->setBorderColor(room_->getBorderColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja la pantalla negra
|
||||
void Game::renderBlackScreen()
|
||||
{
|
||||
if (black_screen_)
|
||||
{
|
||||
auto const color = static_cast<Uint8>(PaletteColor::BLACK);
|
||||
Screen::get()->setRendererSurface();
|
||||
Screen::get()->clearSurface(color);
|
||||
Screen::get()->setBorderColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
// Pone el color del marcador en función del color del borde de la habitación
|
||||
void Game::setScoreBoardColor()
|
||||
{
|
||||
// Obtiene el color del borde
|
||||
const Uint8 BORDER_COLOR = room_->getBorderColor();
|
||||
|
||||
const bool IS_BLACK = BORDER_COLOR == static_cast<Uint8>(PaletteColor::BLACK);
|
||||
const bool IS_BRIGHT_BLACK = BORDER_COLOR == static_cast<Uint8>(PaletteColor::BRIGHT_BLACK);
|
||||
|
||||
// Si el color del borde es negro o negro brillante cambia el texto del marcador a blanco
|
||||
board_->color = IS_BLACK || IS_BRIGHT_BLACK ? static_cast<Uint8>(PaletteColor::WHITE) : BORDER_COLOR;
|
||||
}
|
||||
|
||||
// Comprueba si ha finalizado el juego
|
||||
bool Game::checkEndGame()
|
||||
{
|
||||
const bool isOnTheRoom = room_->getName() == "THE JAIL"; // Estar en la habitación que toca
|
||||
const bool haveTheItems = board_->items >= int(total_items_ * 0.9f) || options.cheats.jail_is_open == Cheat::CheatState::ENABLED; // Con mas del 90% de los items recogidos
|
||||
const bool isOnTheDoor = player_->getRect().x <= 128; // Y en la ubicación que toca (En la puerta)
|
||||
|
||||
if (haveTheItems)
|
||||
{
|
||||
board_->jail_is_open = true;
|
||||
}
|
||||
|
||||
if (haveTheItems && isOnTheRoom && isOnTheDoor)
|
||||
{
|
||||
// Comprueba los logros de completar el juego
|
||||
checkEndGameCheevos();
|
||||
|
||||
options.section.section = Section::ENDING;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Obtiene la cantidad total de items que hay en el mapeado del juego
|
||||
int Game::getTotalItems()
|
||||
{
|
||||
int items = 0;
|
||||
auto rooms = Resource::get()->getRooms();
|
||||
|
||||
for (const auto &room : rooms)
|
||||
{
|
||||
items += room.room->items.size();
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
// Pone el juego en pausa
|
||||
void Game::togglePause()
|
||||
{
|
||||
paused_ = !paused_;
|
||||
|
||||
player_->setPaused(paused_);
|
||||
room_->setPaused(paused_);
|
||||
scoreboard_->setPaused(paused_);
|
||||
}
|
||||
|
||||
// Da vidas al jugador cuando está en la Jail
|
||||
void Game::checkRestoringJail()
|
||||
{
|
||||
if (room_->getName() != "THE JAIL" || board_->lives == 9)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static int counter = 0;
|
||||
|
||||
if (!paused_)
|
||||
{
|
||||
counter++;
|
||||
}
|
||||
|
||||
// Incrementa el numero de vidas
|
||||
if (counter == 100)
|
||||
{
|
||||
counter = 0;
|
||||
board_->lives++;
|
||||
JA_PlaySound(Resource::get()->getSound("death.wav"));
|
||||
|
||||
// Invalida el logro de completar el juego sin entrar a la jail
|
||||
const bool haveTheItems = board_->items >= int(total_items_ * 0.9f);
|
||||
if (!haveTheItems)
|
||||
{
|
||||
Cheevos::get()->setUnobtainable(9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Inicializa el diccionario de las estadísticas
|
||||
void Game::initStats()
|
||||
{
|
||||
auto rooms = Resource::get()->getRooms();
|
||||
|
||||
for (const auto &room : rooms)
|
||||
{
|
||||
stats_->addDictionary(room.room->number, room.room->name);
|
||||
}
|
||||
|
||||
stats_->init();
|
||||
}
|
||||
|
||||
// Crea la textura con el nombre de la habitación
|
||||
void Game::fillRoomNameTexture()
|
||||
{
|
||||
// Pone la textura como destino de renderizado
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(room_name_surface_);
|
||||
|
||||
// Rellena la textura de color
|
||||
room_name_surface_->clear(stringToColor("white"));
|
||||
|
||||
// Escribe el texto en la textura
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, text->getCharacterSize() / 2, room_->getName(), 1, room_->getBGColor());
|
||||
|
||||
// Deja el renderizador por defecto
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
}
|
||||
|
||||
// Comprueba algunos logros
|
||||
void Game::checkSomeCheevos()
|
||||
{
|
||||
auto cheevos = Cheevos::get();
|
||||
|
||||
// Logros sobre la cantidad de items
|
||||
if (board_->items == total_items_)
|
||||
{
|
||||
cheevos->unlock(4);
|
||||
cheevos->unlock(3);
|
||||
cheevos->unlock(2);
|
||||
cheevos->unlock(1);
|
||||
}
|
||||
else if (board_->items >= total_items_ * 0.75f)
|
||||
{
|
||||
cheevos->unlock(3);
|
||||
cheevos->unlock(2);
|
||||
cheevos->unlock(1);
|
||||
}
|
||||
else if (board_->items >= total_items_ * 0.5f)
|
||||
{
|
||||
cheevos->unlock(2);
|
||||
cheevos->unlock(1);
|
||||
}
|
||||
else if (board_->items >= total_items_ * 0.25f)
|
||||
{
|
||||
cheevos->unlock(1);
|
||||
}
|
||||
|
||||
// Logros sobre las habitaciones visitadas
|
||||
if (board_->rooms >= 60)
|
||||
{
|
||||
cheevos->unlock(7);
|
||||
cheevos->unlock(6);
|
||||
cheevos->unlock(5);
|
||||
}
|
||||
else if (board_->rooms >= 40)
|
||||
{
|
||||
cheevos->unlock(6);
|
||||
cheevos->unlock(5);
|
||||
}
|
||||
else if (board_->rooms >= 20)
|
||||
{
|
||||
cheevos->unlock(5);
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba los logros de completar el juego
|
||||
void Game::checkEndGameCheevos()
|
||||
{
|
||||
auto cheevos = Cheevos::get();
|
||||
|
||||
// "Complete the game"
|
||||
cheevos->unlock(8);
|
||||
|
||||
// "Complete the game without entering the jail"
|
||||
cheevos->unlock(9);
|
||||
|
||||
// "Complete the game with all items"
|
||||
if (board_->items == total_items_)
|
||||
{
|
||||
cheevos->unlock(10);
|
||||
}
|
||||
|
||||
// "Complete the game without dying"
|
||||
cheevos->unlock(11);
|
||||
|
||||
// "Complete the game in under 30 minutes"
|
||||
if (scoreboard_->getMinutes() < 30)
|
||||
{
|
||||
cheevos->unlock(12);
|
||||
}
|
||||
}
|
||||
|
||||
// Inicializa al jugador
|
||||
void Game::initPlayer(const PlayerSpawn &spawn_point, std::shared_ptr<Room> room)
|
||||
{
|
||||
std::string player_texture = options.cheats.alternate_skin == Cheat::CheatState::ENABLED ? "player2.gif" : "player.gif";
|
||||
std::string player_animations = options.cheats.alternate_skin == Cheat::CheatState::ENABLED ? "player2.ani" : "player.ani";
|
||||
const PlayerData player(spawn_point, player_texture, player_animations, room);
|
||||
player_ = std::make_shared<Player>(player);
|
||||
}
|
||||
|
||||
// Crea la textura para poner el nombre de la habitación
|
||||
void Game::createRoomNameTexture()
|
||||
{
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
room_name_surface_ = std::make_shared<Surface>(options.game.width, text->getCharacterSize() * 2);
|
||||
|
||||
// Establece el destino de la textura
|
||||
room_name_rect_ = {0, PLAY_AREA_HEIGHT, options.game.width, text->getCharacterSize() * 2};
|
||||
}
|
||||
|
||||
// Hace sonar la música
|
||||
void Game::keepMusicPlaying()
|
||||
{
|
||||
const std::string music_path = mode_ == GameMode::GAME ? "game.ogg" : "title.ogg";
|
||||
|
||||
// Si la música no está sonando
|
||||
if (JA_GetMusicState() == JA_MUSIC_INVALID || JA_GetMusicState() == JA_MUSIC_STOPPED)
|
||||
{
|
||||
JA_PlayMusic(Resource::get()->getMusic(music_path));
|
||||
}
|
||||
}
|
||||
|
||||
// DEMO MODE: Inicializa las variables para el modo demo
|
||||
void Game::DEMO_init()
|
||||
{
|
||||
if (mode_ == GameMode::DEMO)
|
||||
{
|
||||
demo_ = DemoData(0, 400, 0, {"04.room", "54.room", "20.room", "09.room", "05.room", "11.room", "31.room", "44.room"});
|
||||
current_room_ = demo_.rooms.front();
|
||||
}
|
||||
}
|
||||
|
||||
// DEMO MODE: Comprueba si se ha de cambiar de habitación
|
||||
void Game::DEMO_checkRoomChange()
|
||||
{
|
||||
if (mode_ == GameMode::DEMO)
|
||||
{
|
||||
demo_.counter++;
|
||||
if (demo_.counter == demo_.room_time)
|
||||
{
|
||||
demo_.counter = 0;
|
||||
demo_.room_index++;
|
||||
if (demo_.room_index == (int)demo_.rooms.size())
|
||||
{
|
||||
options.section.section = Section::LOGO;
|
||||
options.section.subsection = Subsection::LOGO_TO_TITLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
changeRoom(demo_.rooms[demo_.room_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
172
source/game.h
172
source/game.h
@@ -1,172 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_events.h> // Para SDL_Event
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint32
|
||||
#include <initializer_list> // Para initializer_list
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
#include "player.h" // Para PlayerSpawn
|
||||
class Room; // lines 12-12
|
||||
class RoomTracker; // lines 13-13
|
||||
class Scoreboard; // lines 14-14
|
||||
class Stats; // lines 15-15
|
||||
class Surface;
|
||||
struct ScoreboardData; // lines 16-16
|
||||
|
||||
enum class GameMode
|
||||
{
|
||||
DEMO,
|
||||
GAME
|
||||
};
|
||||
|
||||
class Game
|
||||
{
|
||||
private:
|
||||
// Estructuras
|
||||
struct DemoData
|
||||
{
|
||||
int counter; // Contador para el modo demo
|
||||
int room_time; // Tiempo que se muestra cada habitación
|
||||
int room_index; // Índice para el vector de habitaciones
|
||||
std::vector<std::string> rooms; // Listado con los mapas de la demo
|
||||
|
||||
// Constructor por defecto
|
||||
DemoData()
|
||||
: counter(0), room_time(0), room_index(0), rooms({}) {}
|
||||
|
||||
// Constructor parametrizado
|
||||
DemoData(int counter, int room_time, int room_index, const std::vector<std::string> &rooms)
|
||||
: counter(counter), room_time(room_time), room_index(room_index), rooms(rooms) {}
|
||||
};
|
||||
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<ScoreboardData> board_; // Estructura con los datos del marcador
|
||||
std::shared_ptr<Scoreboard> scoreboard_; // Objeto encargado de gestionar el marcador
|
||||
std::shared_ptr<RoomTracker> room_tracker_; // Lleva el control de las habitaciones visitadas
|
||||
std::shared_ptr<Room> room_; // Objeto encargado de gestionar cada habitación del juego
|
||||
std::shared_ptr<Player> player_; // Objeto con el jugador
|
||||
std::shared_ptr<Stats> stats_; // Objeto encargado de gestionar las estadísticas
|
||||
std::shared_ptr<Surface> room_name_surface_; // Textura para escribir el nombre de la habitación
|
||||
|
||||
// Variables
|
||||
GameMode mode_; // Modo del juego
|
||||
DemoData demo_; // Variables para el modo demo
|
||||
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
std::string current_room_; // Fichero de la habitación actual
|
||||
PlayerSpawn spawn_point_; // Lugar de la habitación donde aparece el jugador
|
||||
bool paused_ = false; // Indica si el juego se encuentra en pausa
|
||||
bool black_screen_ = false; // Indica si la pantalla está en negro. Se utiliza para la muerte del jugador
|
||||
int black_screen_counter_ = 0; // Contador para temporizar la pantalla en negro
|
||||
int total_items_; // Cantidad total de items que hay en el mapeado del juego
|
||||
SDL_Rect room_name_rect_; // Rectangulo donde pintar la textura con el nombre de la habitación
|
||||
|
||||
// Actualiza el juego, las variables, comprueba la entrada, etc.
|
||||
void update();
|
||||
|
||||
// Pinta los objetos en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba los eventos de la cola
|
||||
void checkEvents();
|
||||
|
||||
#ifdef DEBUG
|
||||
// Pone la información de debug en pantalla
|
||||
void updateDebugInfo();
|
||||
|
||||
// Pone la información de debug en pantalla
|
||||
void renderDebugInfo();
|
||||
|
||||
// Comprueba los eventos
|
||||
void checkDebugEvents(const SDL_Event &event);
|
||||
#endif
|
||||
|
||||
// Escribe el nombre de la pantalla
|
||||
void renderRoomName();
|
||||
|
||||
// Cambia de habitación
|
||||
bool changeRoom(const std::string &file);
|
||||
|
||||
// Comprueba el teclado
|
||||
void checkInput();
|
||||
|
||||
// Comprueba si el jugador esta en el borde de la pantalla y actua
|
||||
void checkPlayerIsOnBorder();
|
||||
|
||||
// Comprueba las colisiones del jugador con los enemigos
|
||||
bool checkPlayerAndEnemies();
|
||||
|
||||
// Comprueba las colisiones del jugador con los objetos
|
||||
void checkPlayerAndItems();
|
||||
|
||||
// Comprueba si el jugador esta vivo
|
||||
void checkIfPlayerIsAlive();
|
||||
|
||||
// Comprueba si ha terminado la partida
|
||||
void checkGameOver();
|
||||
|
||||
// Mata al jugador
|
||||
void killPlayer();
|
||||
|
||||
// Establece la pantalla en negro
|
||||
void setBlackScreen();
|
||||
|
||||
// Actualiza las variables relativas a la pantalla en negro
|
||||
void updateBlackScreen();
|
||||
|
||||
// Dibuja la pantalla negra
|
||||
void renderBlackScreen();
|
||||
|
||||
// Pone el color del marcador en función del color del borde de la habitación
|
||||
void setScoreBoardColor();
|
||||
|
||||
// Comprueba si ha finalizado el juego
|
||||
bool checkEndGame();
|
||||
|
||||
// Obtiene la cantidad total de items que hay en el mapeado del juego
|
||||
int getTotalItems();
|
||||
|
||||
// Pone el juego en pausa
|
||||
void togglePause();
|
||||
|
||||
// Da vidas al jugador cuando está en la Jail
|
||||
void checkRestoringJail();
|
||||
|
||||
// Inicializa el diccionario de las estadísticas
|
||||
void initStats();
|
||||
|
||||
// Pone el nombre de la habitación en la textura
|
||||
void fillRoomNameTexture();
|
||||
|
||||
// Comprueba algunos logros
|
||||
void checkSomeCheevos();
|
||||
|
||||
// Comprueba los logros de completar el juego
|
||||
void checkEndGameCheevos();
|
||||
|
||||
// Inicializa al jugador
|
||||
void initPlayer(const PlayerSpawn &spawn_point, std::shared_ptr<Room> room);
|
||||
|
||||
// Crea la textura para poner el nombre de la habitación
|
||||
void createRoomNameTexture();
|
||||
|
||||
// Hace sonar la música
|
||||
void keepMusicPlaying();
|
||||
|
||||
// DEMO MODE: Inicializa las variables para el modo demo
|
||||
void DEMO_init();
|
||||
|
||||
// DEMO MODE: Comprueba si se ha de cambiar de habitación
|
||||
void DEMO_checkRoomChange();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
explicit Game(GameMode mode);
|
||||
|
||||
// Destructor
|
||||
~Game();
|
||||
|
||||
// Bucle para el juego
|
||||
void run();
|
||||
};
|
||||
@@ -1,57 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint8, Uint32
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <vector> // Para vector
|
||||
class SAnimatedSprite; // lines 7-7
|
||||
|
||||
class GameOver
|
||||
{
|
||||
private:
|
||||
// Constantes
|
||||
static constexpr int COUNTER_SECTION_END_ = 400; // Contador: cuando acaba la sección
|
||||
static constexpr int COUNTER_INIT_FADE_ = 310; // Contador: cuando emiepza el fade
|
||||
static constexpr int COUNTER_FADE_LENGHT_ = 20; // Contador: duración del fade
|
||||
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<SAnimatedSprite> player_sprite_; // Sprite con el jugador
|
||||
std::shared_ptr<SAnimatedSprite> tv_sprite_; // Sprite con el televisor
|
||||
|
||||
// Variables
|
||||
int pre_counter_ = 0; // Contador previo
|
||||
int counter_ = 0; // Contador
|
||||
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
std::vector<Uint8> colors_; // Vector con los colores para el fade
|
||||
Uint8 color_; // Color usado para el texto y los sprites
|
||||
|
||||
// Actualiza el objeto
|
||||
void update();
|
||||
|
||||
// Dibuja el final en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void checkEvents();
|
||||
|
||||
// Comprueba las entradas
|
||||
void checkInput();
|
||||
|
||||
// Actualiza el color usado para renderizar los textos e imagenes
|
||||
void updateColor();
|
||||
|
||||
// Dibuja los sprites
|
||||
void renderSprites();
|
||||
|
||||
// Actualiza los contadores
|
||||
void updateCounters();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
GameOver();
|
||||
|
||||
// Destructor
|
||||
~GameOver() = default;
|
||||
|
||||
// Bucle principal
|
||||
void run();
|
||||
};
|
||||
@@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include <SDL3/SDL_events.h>
|
||||
|
||||
namespace globalEvents
|
||||
{
|
||||
// Comprueba los eventos que se pueden producir en cualquier sección del juego
|
||||
void check(const SDL_Event &event);
|
||||
}
|
||||
namespace globalEvents {
|
||||
// Comprueba los eventos que se pueden producir en cualquier sección del juego
|
||||
void check(const SDL_Event& event);
|
||||
} // namespace globalEvents
|
||||
@@ -1,37 +1,33 @@
|
||||
#include "global_inputs.h"
|
||||
#include <SDL2/SDL_render.h> // Para SDL_RenderSetIntegerScale
|
||||
#include <SDL2/SDL_stdinc.h> // Para SDL_FALSE, SDL_TRUE
|
||||
|
||||
#include <SDL3/SDL_render.h> // Para SDL_RenderSetIntegerScale
|
||||
#include <SDL3/SDL_stdinc.h> // Para SDL_FALSE, SDL_TRUE
|
||||
|
||||
#include <string> // Para allocator, operator+, char_traits, string
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "input.h" // Para Input, InputAction, INPUT_DO_NOT_ALLOW_REPEAT
|
||||
#include "notifier.h" // Para Notifier, NotificationText
|
||||
#include "options.h" // Para Options, options, OptionsVideo, Section
|
||||
#include "screen.h" // Para Screen
|
||||
#include "utils.h" // Para stringInVector
|
||||
|
||||
namespace globalInputs
|
||||
{
|
||||
void quit()
|
||||
{
|
||||
namespace globalInputs {
|
||||
void quit() {
|
||||
const std::string code = options.section.section == Section::GAME ? "PRESS AGAIN TO RETURN TO MENU" : "PRESS AGAIN TO EXIT";
|
||||
auto code_found = stringInVector(Notifier::get()->getCodes(), code);
|
||||
if (code_found)
|
||||
{
|
||||
if (code_found) {
|
||||
// Si la notificación de salir está activa, cambia de sección
|
||||
options.section.section = options.section.section == Section::GAME ? Section::TITLE : Section::QUIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Si la notificación de salir no está activa, muestra la notificación
|
||||
Notifier::get()->show({code}, NotificationText::CENTER, 2000, -1, true, code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cambia de seccion
|
||||
void skip_section()
|
||||
{
|
||||
switch (options.section.section)
|
||||
{
|
||||
// Cambia de seccion
|
||||
void skip_section() {
|
||||
switch (options.section.section) {
|
||||
case Section::LOGO:
|
||||
case Section::LOADING_SCREEN:
|
||||
case Section::CREDITS:
|
||||
@@ -46,78 +42,64 @@ namespace globalInputs
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
|
||||
void check()
|
||||
{
|
||||
if (Input::get()->checkInput(InputAction::EXIT, INPUT_DO_NOT_ALLOW_REPEAT))
|
||||
{
|
||||
// Comprueba los inputs que se pueden introducir en cualquier sección del juego
|
||||
void check() {
|
||||
if (Input::get()->checkInput(InputAction::EXIT, INPUT_DO_NOT_ALLOW_REPEAT)) {
|
||||
quit();
|
||||
}
|
||||
|
||||
else if (Input::get()->checkInput(InputAction::ACCEPT, INPUT_DO_NOT_ALLOW_REPEAT))
|
||||
{
|
||||
else if (Input::get()->checkInput(InputAction::ACCEPT, INPUT_DO_NOT_ALLOW_REPEAT)) {
|
||||
skip_section();
|
||||
}
|
||||
|
||||
else if (Input::get()->checkInput(InputAction::TOGGLE_BORDER, INPUT_DO_NOT_ALLOW_REPEAT))
|
||||
{
|
||||
else if (Input::get()->checkInput(InputAction::TOGGLE_BORDER, INPUT_DO_NOT_ALLOW_REPEAT)) {
|
||||
Screen::get()->toggleBorder();
|
||||
Notifier::get()->show({"BORDER " + std::string(options.video.border.enabled ? "ENABLED" : "DISABLED")}, NotificationText::CENTER);
|
||||
}
|
||||
|
||||
else if (Input::get()->checkInput(InputAction::TOGGLE_VIDEOMODE, INPUT_DO_NOT_ALLOW_REPEAT))
|
||||
{
|
||||
else if (Input::get()->checkInput(InputAction::TOGGLE_VIDEOMODE, INPUT_DO_NOT_ALLOW_REPEAT)) {
|
||||
Screen::get()->toggleVideoMode();
|
||||
Notifier::get()->show({"FULLSCREEN " + std::string(options.video.mode == 0 ? "DISABLED" : "ENABLED")}, NotificationText::CENTER);
|
||||
}
|
||||
|
||||
else if (Input::get()->checkInput(InputAction::WINDOW_DEC_ZOOM, INPUT_DO_NOT_ALLOW_REPEAT))
|
||||
{
|
||||
if (Screen::get()->decWindowZoom())
|
||||
{
|
||||
else if (Input::get()->checkInput(InputAction::WINDOW_DEC_ZOOM, INPUT_DO_NOT_ALLOW_REPEAT)) {
|
||||
if (Screen::get()->decWindowZoom()) {
|
||||
Notifier::get()->show({"WINDOW ZOOM x" + std::to_string(options.window.zoom)}, NotificationText::CENTER);
|
||||
}
|
||||
}
|
||||
|
||||
else if (Input::get()->checkInput(InputAction::WINDOW_INC_ZOOM, INPUT_DO_NOT_ALLOW_REPEAT))
|
||||
{
|
||||
if (Screen::get()->incWindowZoom())
|
||||
{
|
||||
else if (Input::get()->checkInput(InputAction::WINDOW_INC_ZOOM, INPUT_DO_NOT_ALLOW_REPEAT)) {
|
||||
if (Screen::get()->incWindowZoom()) {
|
||||
Notifier::get()->show({"WINDOW ZOOM x" + std::to_string(options.window.zoom)}, NotificationText::CENTER);
|
||||
}
|
||||
}
|
||||
|
||||
else if (Input::get()->checkInput(InputAction::TOGGLE_SHADERS, INPUT_DO_NOT_ALLOW_REPEAT))
|
||||
{
|
||||
else if (Input::get()->checkInput(InputAction::TOGGLE_SHADERS, INPUT_DO_NOT_ALLOW_REPEAT)) {
|
||||
Screen::get()->toggleShaders();
|
||||
Notifier::get()->show({"SHADERS " + std::string(options.video.shaders ? "ENABLED" : "DISABLED")}, NotificationText::CENTER);
|
||||
}
|
||||
|
||||
else if (Input::get()->checkInput(InputAction::NEXT_PALETTE, INPUT_DO_NOT_ALLOW_REPEAT))
|
||||
{
|
||||
else if (Input::get()->checkInput(InputAction::NEXT_PALETTE, INPUT_DO_NOT_ALLOW_REPEAT)) {
|
||||
Screen::get()->nextPalette();
|
||||
Notifier::get()->show({"PALETTE " + options.video.palette}, NotificationText::CENTER);
|
||||
}
|
||||
|
||||
else if (Input::get()->checkInput(InputAction::PREVIOUS_PALETTE, INPUT_DO_NOT_ALLOW_REPEAT))
|
||||
{
|
||||
else if (Input::get()->checkInput(InputAction::PREVIOUS_PALETTE, INPUT_DO_NOT_ALLOW_REPEAT)) {
|
||||
Screen::get()->previousPalette();
|
||||
Notifier::get()->show({"PALETTE " + options.video.palette}, NotificationText::CENTER);
|
||||
}
|
||||
|
||||
else if (Input::get()->checkInput(InputAction::TOGGLE_INTEGER_SCALE, INPUT_DO_NOT_ALLOW_REPEAT))
|
||||
{
|
||||
else if (Input::get()->checkInput(InputAction::TOGGLE_INTEGER_SCALE, INPUT_DO_NOT_ALLOW_REPEAT)) {
|
||||
options.video.integer_scale = !options.video.integer_scale;
|
||||
SDL_RenderSetIntegerScale(Screen::get()->getRenderer(), options.video.integer_scale ? SDL_TRUE : SDL_FALSE);
|
||||
Screen::get()->setVideoMode(options.video.mode);
|
||||
Notifier::get()->show({"INTEGER SCALE " + std::string(options.video.integer_scale ? "ENABLED" : "DISABLED")}, NotificationText::CENTER);
|
||||
}
|
||||
|
||||
else if (Input::get()->checkInput(InputAction::SHOW_DEBUG_INFO, INPUT_DO_NOT_ALLOW_REPEAT))
|
||||
{
|
||||
else if (Input::get()->checkInput(InputAction::SHOW_DEBUG_INFO, INPUT_DO_NOT_ALLOW_REPEAT)) {
|
||||
Screen::get()->toggleDebugInfo();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace globalInputs
|
||||
204
source/input.cpp
204
source/input.cpp
@@ -1,8 +1,10 @@
|
||||
#include "input.h"
|
||||
#include <SDL2/SDL.h> // Para SDL_INIT_GAMECONTROLLER, SDL_InitSubS...
|
||||
#include <SDL2/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL2/SDL_events.h> // Para SDL_ENABLE
|
||||
#include <SDL2/SDL_keyboard.h> // Para SDL_GetKeyboardState
|
||||
|
||||
#include <SDL3/SDL.h> // Para SDL_INIT_GAMECONTROLLER, SDL_InitSubS...
|
||||
#include <SDL3/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL3/SDL_events.h> // Para SDL_ENABLE
|
||||
#include <SDL3/SDL_keyboard.h> // Para SDL_GetKeyboardState
|
||||
|
||||
#include <algorithm> // Para find
|
||||
#include <iostream> // Para basic_ostream, operator<<, cout, endl
|
||||
#include <iterator> // Para distance
|
||||
@@ -10,30 +12,26 @@
|
||||
#include <utility> // Para pair
|
||||
|
||||
// [SINGLETON]
|
||||
Input *Input::input_ = nullptr;
|
||||
Input* Input::input_ = nullptr;
|
||||
|
||||
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||
void Input::init(const std::string &game_controller_db_path)
|
||||
{
|
||||
void Input::init(const std::string& game_controller_db_path) {
|
||||
Input::input_ = new Input(game_controller_db_path);
|
||||
}
|
||||
|
||||
// [SINGLETON] Destruiremos el objeto con esta función estática
|
||||
void Input::destroy()
|
||||
{
|
||||
void Input::destroy() {
|
||||
delete Input::input_;
|
||||
}
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
Input *Input::get()
|
||||
{
|
||||
Input* Input::get() {
|
||||
return Input::input_;
|
||||
}
|
||||
|
||||
// Constructor
|
||||
Input::Input(const std::string &game_controller_db_path)
|
||||
: game_controller_db_path_(game_controller_db_path)
|
||||
{
|
||||
Input::Input(const std::string& game_controller_db_path)
|
||||
: game_controller_db_path_(game_controller_db_path) {
|
||||
// Busca si hay mandos conectados
|
||||
discoverGameControllers();
|
||||
|
||||
@@ -46,62 +44,45 @@ Input::Input(const std::string &game_controller_db_path)
|
||||
}
|
||||
|
||||
// Asigna inputs a teclas
|
||||
void Input::bindKey(InputAction input, SDL_Scancode code)
|
||||
{
|
||||
void Input::bindKey(InputAction input, SDL_Scancode code) {
|
||||
key_bindings_.at(static_cast<int>(input)).scancode = code;
|
||||
}
|
||||
|
||||
// Asigna inputs a botones del mando
|
||||
void Input::bindGameControllerButton(int controller_index, InputAction input, SDL_GameControllerButton button)
|
||||
{
|
||||
if (controller_index < num_gamepads_)
|
||||
{
|
||||
void Input::bindGameControllerButton(int controller_index, InputAction input, SDL_GameControllerButton button) {
|
||||
if (controller_index < num_gamepads_) {
|
||||
controller_bindings_.at(controller_index).at(static_cast<int>(input)).button = button;
|
||||
}
|
||||
}
|
||||
|
||||
// Asigna inputs a botones del mando
|
||||
void Input::bindGameControllerButton(int controller_index, InputAction input_target, InputAction input_source)
|
||||
{
|
||||
if (controller_index < num_gamepads_)
|
||||
{
|
||||
void Input::bindGameControllerButton(int controller_index, InputAction input_target, InputAction input_source) {
|
||||
if (controller_index < num_gamepads_) {
|
||||
controller_bindings_.at(controller_index).at(static_cast<int>(input_target)).button = controller_bindings_.at(controller_index).at(static_cast<int>(input_source)).button;
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba si un input esta activo
|
||||
bool Input::checkInput(InputAction input, bool repeat, InputDeviceToUse device, int controller_index)
|
||||
{
|
||||
bool Input::checkInput(InputAction input, bool repeat, InputDeviceToUse device, int controller_index) {
|
||||
bool success_keyboard = false;
|
||||
bool success_controller = false;
|
||||
const int input_index = static_cast<int>(input);
|
||||
|
||||
if (device == InputDeviceToUse::KEYBOARD || device == InputDeviceToUse::ANY)
|
||||
{
|
||||
const Uint8 *keyStates = SDL_GetKeyboardState(nullptr);
|
||||
if (device == InputDeviceToUse::KEYBOARD || device == InputDeviceToUse::ANY) {
|
||||
const Uint8* keyStates = SDL_GetKeyboardState(nullptr);
|
||||
|
||||
if (repeat)
|
||||
{
|
||||
if (repeat) {
|
||||
success_keyboard = keyStates[key_bindings_[input_index].scancode] != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!key_bindings_[input_index].active)
|
||||
{
|
||||
if (keyStates[key_bindings_[input_index].scancode] != 0)
|
||||
{
|
||||
} else {
|
||||
if (!key_bindings_[input_index].active) {
|
||||
if (keyStates[key_bindings_[input_index].scancode] != 0) {
|
||||
key_bindings_[input_index].active = true;
|
||||
success_keyboard = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
success_keyboard = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (keyStates[key_bindings_[input_index].scancode] == 0)
|
||||
{
|
||||
} else {
|
||||
if (keyStates[key_bindings_[input_index].scancode] == 0) {
|
||||
key_bindings_[input_index].active = false;
|
||||
}
|
||||
success_keyboard = false;
|
||||
@@ -109,36 +90,23 @@ bool Input::checkInput(InputAction input, bool repeat, InputDeviceToUse device,
|
||||
}
|
||||
}
|
||||
|
||||
if (gameControllerFound() && controller_index >= 0 && controller_index < num_gamepads_)
|
||||
{
|
||||
if ((device == InputDeviceToUse::CONTROLLER) || (device == InputDeviceToUse::ANY))
|
||||
{
|
||||
if (gameControllerFound() && controller_index >= 0 && controller_index < num_gamepads_) {
|
||||
if ((device == InputDeviceToUse::CONTROLLER) || (device == InputDeviceToUse::ANY)) {
|
||||
success_controller = checkAxisInput(input, controller_index, repeat);
|
||||
|
||||
if (!success_controller)
|
||||
{
|
||||
if (repeat)
|
||||
{
|
||||
if (!success_controller) {
|
||||
if (repeat) {
|
||||
success_controller = SDL_GameControllerGetButton(connected_controllers_.at(controller_index), controller_bindings_.at(controller_index).at(input_index).button) != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!controller_bindings_.at(controller_index).at(input_index).active)
|
||||
{
|
||||
if (SDL_GameControllerGetButton(connected_controllers_.at(controller_index), controller_bindings_.at(controller_index).at(input_index).button) != 0)
|
||||
{
|
||||
} else {
|
||||
if (!controller_bindings_.at(controller_index).at(input_index).active) {
|
||||
if (SDL_GameControllerGetButton(connected_controllers_.at(controller_index), controller_bindings_.at(controller_index).at(input_index).button) != 0) {
|
||||
controller_bindings_.at(controller_index).at(input_index).active = true;
|
||||
success_controller = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
success_controller = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SDL_GameControllerGetButton(connected_controllers_.at(controller_index), controller_bindings_.at(controller_index).at(input_index).button) == 0)
|
||||
{
|
||||
} else {
|
||||
if (SDL_GameControllerGetButton(connected_controllers_.at(controller_index), controller_bindings_.at(controller_index).at(input_index).button) == 0) {
|
||||
controller_bindings_.at(controller_index).at(input_index).active = false;
|
||||
}
|
||||
success_controller = false;
|
||||
@@ -152,30 +120,22 @@ bool Input::checkInput(InputAction input, bool repeat, InputDeviceToUse device,
|
||||
}
|
||||
|
||||
// Comprueba si hay almenos un input activo
|
||||
bool Input::checkAnyInput(InputDeviceToUse device, int controller_index)
|
||||
{
|
||||
if (device == InputDeviceToUse::KEYBOARD || device == InputDeviceToUse::ANY)
|
||||
{
|
||||
const Uint8 *mKeystates = SDL_GetKeyboardState(nullptr);
|
||||
bool Input::checkAnyInput(InputDeviceToUse device, int controller_index) {
|
||||
if (device == InputDeviceToUse::KEYBOARD || device == InputDeviceToUse::ANY) {
|
||||
const Uint8* mKeystates = SDL_GetKeyboardState(nullptr);
|
||||
|
||||
for (int i = 0; i < (int)key_bindings_.size(); ++i)
|
||||
{
|
||||
if (mKeystates[key_bindings_[i].scancode] != 0 && !key_bindings_[i].active)
|
||||
{
|
||||
for (int i = 0; i < (int)key_bindings_.size(); ++i) {
|
||||
if (mKeystates[key_bindings_[i].scancode] != 0 && !key_bindings_[i].active) {
|
||||
key_bindings_[i].active = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gameControllerFound())
|
||||
{
|
||||
if (device == InputDeviceToUse::CONTROLLER || device == InputDeviceToUse::ANY)
|
||||
{
|
||||
for (int i = 0; i < (int)controller_bindings_.size(); ++i)
|
||||
{
|
||||
if (SDL_GameControllerGetButton(connected_controllers_[controller_index], controller_bindings_[controller_index][i].button) != 0 && !controller_bindings_[controller_index][i].active)
|
||||
{
|
||||
if (gameControllerFound()) {
|
||||
if (device == InputDeviceToUse::CONTROLLER || device == InputDeviceToUse::ANY) {
|
||||
for (int i = 0; i < (int)controller_bindings_.size(); ++i) {
|
||||
if (SDL_GameControllerGetButton(connected_controllers_[controller_index], controller_bindings_[controller_index][i].button) != 0 && !controller_bindings_[controller_index][i].active) {
|
||||
controller_bindings_[controller_index][i].active = true;
|
||||
return true;
|
||||
}
|
||||
@@ -187,17 +147,14 @@ bool Input::checkAnyInput(InputDeviceToUse device, int controller_index)
|
||||
}
|
||||
|
||||
// Busca si hay mandos conectados
|
||||
bool Input::discoverGameControllers()
|
||||
{
|
||||
bool Input::discoverGameControllers() {
|
||||
bool found = false;
|
||||
|
||||
if (SDL_WasInit(SDL_INIT_GAMECONTROLLER) != 1)
|
||||
{
|
||||
if (SDL_WasInit(SDL_INIT_GAMECONTROLLER) != 1) {
|
||||
SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
|
||||
}
|
||||
|
||||
if (SDL_GameControllerAddMappingsFromFile(game_controller_db_path_.c_str()) < 0)
|
||||
{
|
||||
if (SDL_GameControllerAddMappingsFromFile(game_controller_db_path_.c_str()) < 0) {
|
||||
std::cout << "Error, could not load " << game_controller_db_path_.c_str() << " file: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
|
||||
@@ -206,44 +163,34 @@ bool Input::discoverGameControllers()
|
||||
|
||||
// Cuenta el número de mandos
|
||||
joysticks_.clear();
|
||||
for (int i = 0; i < num_joysticks_; ++i)
|
||||
{
|
||||
for (int i = 0; i < num_joysticks_; ++i) {
|
||||
auto joy = SDL_JoystickOpen(i);
|
||||
joysticks_.push_back(joy);
|
||||
if (SDL_IsGameController(i))
|
||||
{
|
||||
if (SDL_IsGameController(i)) {
|
||||
num_gamepads_++;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "\n** LOOKING FOR GAME CONTROLLERS" << std::endl;
|
||||
if (num_joysticks_ != num_gamepads_)
|
||||
{
|
||||
if (num_joysticks_ != num_gamepads_) {
|
||||
std::cout << "Joysticks found: " << num_joysticks_ << std::endl;
|
||||
std::cout << "Gamepads found : " << num_gamepads_ << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
std::cout << "Gamepads found: " << num_gamepads_ << std::endl;
|
||||
}
|
||||
|
||||
if (num_gamepads_ > 0)
|
||||
{
|
||||
if (num_gamepads_ > 0) {
|
||||
found = true;
|
||||
|
||||
for (int i = 0; i < num_gamepads_; i++)
|
||||
{
|
||||
for (int i = 0; i < num_gamepads_; i++) {
|
||||
// Abre el mando y lo añade a la lista
|
||||
auto pad = SDL_GameControllerOpen(i);
|
||||
if (SDL_GameControllerGetAttached(pad) == 1)
|
||||
{
|
||||
if (SDL_GameControllerGetAttached(pad) == 1) {
|
||||
connected_controllers_.push_back(pad);
|
||||
const std::string name = SDL_GameControllerNameForIndex(i);
|
||||
std::cout << "#" << i << ": " << name << std::endl;
|
||||
controller_names_.push_back(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
std::cout << "SDL_GetError() = " << SDL_GetError() << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -265,12 +212,9 @@ std::string Input::getControllerName(int controller_index) const { return num_ga
|
||||
int Input::getNumControllers() const { return num_gamepads_; }
|
||||
|
||||
// Obtiene el indice del controlador a partir de un event.id
|
||||
int Input::getJoyIndex(int id) const
|
||||
{
|
||||
for (int i = 0; i < num_joysticks_; ++i)
|
||||
{
|
||||
if (SDL_JoystickInstanceID(joysticks_[i]) == id)
|
||||
{
|
||||
int Input::getJoyIndex(int id) const {
|
||||
for (int i = 0; i < num_joysticks_; ++i) {
|
||||
if (SDL_JoystickInstanceID(joysticks_[i]) == id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -278,27 +222,23 @@ int Input::getJoyIndex(int id) const
|
||||
}
|
||||
|
||||
// Obtiene el SDL_GameControllerButton asignado a un input
|
||||
SDL_GameControllerButton Input::getControllerBinding(int controller_index, InputAction input) const
|
||||
{
|
||||
SDL_GameControllerButton Input::getControllerBinding(int controller_index, InputAction input) const {
|
||||
return controller_bindings_[controller_index][static_cast<int>(input)].button;
|
||||
}
|
||||
|
||||
// Obtiene el indice a partir del nombre del mando
|
||||
int Input::getIndexByName(const std::string &name) const
|
||||
{
|
||||
int Input::getIndexByName(const std::string& name) const {
|
||||
auto it = std::find(controller_names_.begin(), controller_names_.end(), name);
|
||||
return it != controller_names_.end() ? std::distance(controller_names_.begin(), it) : -1;
|
||||
}
|
||||
|
||||
// Comprueba el eje del mando
|
||||
bool Input::checkAxisInput(InputAction input, int controller_index, bool repeat)
|
||||
{
|
||||
bool Input::checkAxisInput(InputAction input, int controller_index, bool repeat) {
|
||||
// Umbral para considerar el eje como activo
|
||||
const Sint16 threshold = 30000;
|
||||
bool axis_active_now = false;
|
||||
|
||||
switch (input)
|
||||
{
|
||||
switch (input) {
|
||||
case InputAction::LEFT:
|
||||
axis_active_now = SDL_GameControllerGetAxis(connected_controllers_[controller_index], SDL_CONTROLLER_AXIS_LEFTX) < -threshold;
|
||||
break;
|
||||
@@ -316,24 +256,18 @@ bool Input::checkAxisInput(InputAction input, int controller_index, bool repeat)
|
||||
}
|
||||
|
||||
// Referencia al binding correspondiente
|
||||
auto &binding = controller_bindings_.at(controller_index).at(static_cast<int>(input));
|
||||
auto& binding = controller_bindings_.at(controller_index).at(static_cast<int>(input));
|
||||
|
||||
if (repeat)
|
||||
{
|
||||
if (repeat) {
|
||||
// Si se permite repetir, simplemente devolvemos el estado actual
|
||||
return axis_active_now;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Si no se permite repetir, aplicamos la lógica de transición
|
||||
if (axis_active_now && !binding.axis_active)
|
||||
{
|
||||
if (axis_active_now && !binding.axis_active) {
|
||||
// Transición de inactivo a activo
|
||||
binding.axis_active = true;
|
||||
return true;
|
||||
}
|
||||
else if (!axis_active_now && binding.axis_active)
|
||||
{
|
||||
} else if (!axis_active_now && binding.axis_active) {
|
||||
// Transición de activo a inactivo
|
||||
binding.axis_active = false;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_gamecontroller.h> // Para SDL_GameControllerButton, SDL_G...
|
||||
#include <SDL2/SDL_scancode.h> // Para SDL_Scancode
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint8
|
||||
#include <SDL3/SDL_gamecontroller.h> // Para SDL_GameControllerButton, SDL_G...
|
||||
#include <SDL3/SDL_scancode.h> // Para SDL_Scancode
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint8
|
||||
|
||||
#include <string> // Para string, basic_string
|
||||
#include <vector> // Para vector
|
||||
|
||||
@@ -11,15 +12,13 @@ constexpr bool INPUT_ALLOW_REPEAT = true;
|
||||
constexpr bool INPUT_DO_NOT_ALLOW_REPEAT = false;
|
||||
|
||||
// Tipos de entrada
|
||||
enum class InputDeviceToUse : int
|
||||
{
|
||||
enum class InputDeviceToUse : int {
|
||||
KEYBOARD = 0,
|
||||
CONTROLLER = 1,
|
||||
ANY = 2,
|
||||
};
|
||||
|
||||
enum class InputAction
|
||||
{
|
||||
enum class InputAction {
|
||||
// Inputs obligatorios
|
||||
UP,
|
||||
DOWN,
|
||||
@@ -48,36 +47,36 @@ enum class InputAction
|
||||
SIZE
|
||||
};
|
||||
|
||||
class Input
|
||||
{
|
||||
private:
|
||||
class Input {
|
||||
private:
|
||||
// [SINGLETON] Objeto privado
|
||||
static Input *input_;
|
||||
static Input* input_;
|
||||
|
||||
struct KeyBindings
|
||||
{
|
||||
struct KeyBindings {
|
||||
Uint8 scancode; // Scancode asociado
|
||||
bool active; // Indica si está activo
|
||||
|
||||
// Constructor
|
||||
explicit KeyBindings(Uint8 sc = 0, bool act = false)
|
||||
: scancode(sc), active(act) {}
|
||||
: scancode(sc),
|
||||
active(act) {}
|
||||
};
|
||||
|
||||
struct ControllerBindings
|
||||
{
|
||||
struct ControllerBindings {
|
||||
SDL_GameControllerButton button; // GameControllerButton asociado
|
||||
bool active; // Indica si está activo
|
||||
bool axis_active; // Estado del eje
|
||||
|
||||
// Constructor
|
||||
explicit ControllerBindings(SDL_GameControllerButton btn = SDL_CONTROLLER_BUTTON_INVALID, bool act = false, bool axis_act = false)
|
||||
: button(btn), active(act), axis_active(axis_act) {}
|
||||
: button(btn),
|
||||
active(act),
|
||||
axis_active(axis_act) {}
|
||||
};
|
||||
|
||||
// Variables
|
||||
std::vector<SDL_GameController *> connected_controllers_; // Vector con todos los mandos conectados
|
||||
std::vector<SDL_Joystick *> joysticks_; // Vector con todos los joysticks conectados
|
||||
std::vector<SDL_GameController*> connected_controllers_; // Vector con todos los mandos conectados
|
||||
std::vector<SDL_Joystick*> joysticks_; // Vector con todos los joysticks conectados
|
||||
std::vector<KeyBindings> key_bindings_; // Vector con las teclas asociadas a los inputs predefinidos
|
||||
std::vector<std::vector<ControllerBindings>> controller_bindings_; // Vector con los botones asociadas a los inputs predefinidos para cada mando
|
||||
std::vector<std::string> controller_names_; // Vector con los nombres de los mandos
|
||||
@@ -90,20 +89,20 @@ private:
|
||||
bool checkAxisInput(InputAction input, int controller_index, bool repeat);
|
||||
|
||||
// Constructor
|
||||
explicit Input(const std::string &game_controller_db_path);
|
||||
explicit Input(const std::string& game_controller_db_path);
|
||||
|
||||
// Destructor
|
||||
~Input() = default;
|
||||
|
||||
public:
|
||||
public:
|
||||
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||
static void init(const std::string &game_controller_db_path);
|
||||
static void init(const std::string& game_controller_db_path);
|
||||
|
||||
// [SINGLETON] Destruiremos el objeto con esta función estática
|
||||
static void destroy();
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
static Input *get();
|
||||
static Input* get();
|
||||
|
||||
// Asigna inputs a teclas
|
||||
void bindKey(InputAction input, SDL_Scancode code);
|
||||
@@ -137,5 +136,5 @@ public:
|
||||
SDL_GameControllerButton getControllerBinding(int controller_index, InputAction input) const;
|
||||
|
||||
// Obtiene el indice a partir del nombre del mando
|
||||
int getIndexByName(const std::string &name) const;
|
||||
int getIndexByName(const std::string& name) const;
|
||||
};
|
||||
@@ -1,14 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect, SDL_Point
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint8
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect, SDL_Point
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint8
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
class SSprite;
|
||||
|
||||
struct ItemData
|
||||
{
|
||||
struct ItemData {
|
||||
std::string tile_set_file; // Ruta al fichero con los gráficos del item
|
||||
int x; // Posición del item en pantalla
|
||||
int y; // Posición del item en pantalla
|
||||
@@ -18,12 +18,17 @@ struct ItemData
|
||||
Uint8 color2; // Uno de los dos colores que se utiliza para el item
|
||||
|
||||
// Constructor
|
||||
ItemData() : x(0), y(0), tile(0), counter(0), color1(), color2() {}
|
||||
ItemData()
|
||||
: x(0),
|
||||
y(0),
|
||||
tile(0),
|
||||
counter(0),
|
||||
color1(),
|
||||
color2() {}
|
||||
};
|
||||
|
||||
class Item
|
||||
{
|
||||
private:
|
||||
class Item {
|
||||
private:
|
||||
// Constantes
|
||||
static constexpr int ITEM_SIZE_ = 8;
|
||||
|
||||
@@ -36,7 +41,7 @@ private:
|
||||
SDL_Rect collider_; // Rectangulo de colisión
|
||||
int change_color_speed; // Cuanto mas alto, mas tarda en cambiar de color
|
||||
|
||||
public:
|
||||
public:
|
||||
// Constructor
|
||||
explicit Item(ItemData item);
|
||||
|
||||
@@ -50,7 +55,7 @@ public:
|
||||
void update() { counter_++; }
|
||||
|
||||
// Obtiene el rectangulo de colision del objeto
|
||||
SDL_Rect &getCollider() { return collider_; }
|
||||
SDL_Rect& getCollider() { return collider_; }
|
||||
|
||||
// Obtiene su ubicación
|
||||
SDL_Point getPos();
|
||||
|
||||
@@ -1,33 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Point
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Point
|
||||
|
||||
#include <string> // Para string, basic_string
|
||||
#include <vector> // Para vector
|
||||
|
||||
struct ItemTrackerData
|
||||
{
|
||||
struct ItemTrackerData {
|
||||
std::string name; // Nombre de la habitación donde se encuentra el objeto
|
||||
std::vector<SDL_Point> pos; // Lista de objetos cogidos de la habitación
|
||||
|
||||
// Constructor
|
||||
ItemTrackerData(const std::string &name, const SDL_Point &position)
|
||||
: name(name)
|
||||
{
|
||||
ItemTrackerData(const std::string& name, const SDL_Point& position)
|
||||
: name(name) {
|
||||
pos.push_back(position);
|
||||
}
|
||||
};
|
||||
|
||||
class ItemTracker
|
||||
{
|
||||
private:
|
||||
class ItemTracker {
|
||||
private:
|
||||
// [SINGLETON] Objeto privado
|
||||
static ItemTracker *item_tracker_;
|
||||
static ItemTracker* item_tracker_;
|
||||
|
||||
// Variables
|
||||
std::vector<ItemTrackerData> item_list_; // Lista con todos los objetos recogidos
|
||||
|
||||
// Busca una entrada en la lista por nombre
|
||||
int findByName(const std::string &name);
|
||||
int findByName(const std::string& name);
|
||||
|
||||
// Busca una entrada en la lista por posición
|
||||
int findByPos(int index, SDL_Point pos);
|
||||
@@ -38,7 +36,7 @@ private:
|
||||
// Destructor
|
||||
~ItemTracker() = default;
|
||||
|
||||
public:
|
||||
public:
|
||||
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||
static void init();
|
||||
|
||||
@@ -46,11 +44,11 @@ public:
|
||||
static void destroy();
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
static ItemTracker *get();
|
||||
static ItemTracker* get();
|
||||
|
||||
// Comprueba si el objeto ya ha sido cogido
|
||||
bool hasBeenPicked(const std::string &name, SDL_Point pos);
|
||||
bool hasBeenPicked(const std::string& name, SDL_Point pos);
|
||||
|
||||
// Añade el objeto a la lista de objetos cogidos
|
||||
void addItem(const std::string &name, SDL_Point pos);
|
||||
void addItem(const std::string& name, SDL_Point pos);
|
||||
};
|
||||
@@ -1,294 +0,0 @@
|
||||
#include "jail_shader.h"
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Point
|
||||
#include <SDL2/SDL_stdinc.h> // Para SDL_bool
|
||||
#include <cstring> // Para strncmp
|
||||
#include <iostream> // Para basic_ostream, operator<<, endl, cout
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <vector> // Para vector
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include "CoreFoundation/CoreFoundation.h" // Para Core Foundation en macOS
|
||||
#include <OpenGL/OpenGL.h> // Para OpenGL en macOS
|
||||
#if ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
||||
#include <OpenGL/gl3.h> // Para OpenGL 3 en macOS
|
||||
#else // NO ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
||||
#include <OpenGL/gl.h> // Para OpenGL (compatibilidad) en macOS
|
||||
#endif // ESSENTIAL_GL_PRACTICES_SUPPORT_GL3
|
||||
#else // SI NO ES __APPLE__
|
||||
#include <SDL2/SDL_opengl.h> // Para GLuint, glTexCoord2f, glVertex2f, GLfloat
|
||||
#endif // __APPLE__
|
||||
|
||||
namespace shader
|
||||
{
|
||||
SDL_Window *win = nullptr;
|
||||
SDL_Renderer *renderer = nullptr;
|
||||
GLuint programId = 0;
|
||||
SDL_Texture *backBuffer = nullptr;
|
||||
SDL_Point win_size = {320 * 4, 256 * 4};
|
||||
SDL_Point tex_size = {320, 256};
|
||||
bool usingOpenGL = false;
|
||||
|
||||
#ifndef __APPLE__
|
||||
// Declaración de funciones de extensión de OpenGL (evitando GLEW)
|
||||
PFNGLCREATESHADERPROC glCreateShader;
|
||||
PFNGLSHADERSOURCEPROC glShaderSource;
|
||||
PFNGLCOMPILESHADERPROC glCompileShader;
|
||||
PFNGLGETSHADERIVPROC glGetShaderiv;
|
||||
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
|
||||
PFNGLDELETESHADERPROC glDeleteShader;
|
||||
PFNGLATTACHSHADERPROC glAttachShader;
|
||||
PFNGLCREATEPROGRAMPROC glCreateProgram;
|
||||
PFNGLLINKPROGRAMPROC glLinkProgram;
|
||||
PFNGLVALIDATEPROGRAMPROC glValidateProgram;
|
||||
PFNGLGETPROGRAMIVPROC glGetProgramiv;
|
||||
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
|
||||
PFNGLUSEPROGRAMPROC glUseProgram;
|
||||
|
||||
bool initGLExtensions()
|
||||
{
|
||||
glCreateShader = (PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader");
|
||||
glShaderSource = (PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource");
|
||||
glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader");
|
||||
glGetShaderiv = (PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv");
|
||||
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog");
|
||||
glDeleteShader = (PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader");
|
||||
glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader");
|
||||
glCreateProgram = (PFNGLCREATEPROGRAMPROC)SDL_GL_GetProcAddress("glCreateProgram");
|
||||
glLinkProgram = (PFNGLLINKPROGRAMPROC)SDL_GL_GetProcAddress("glLinkProgram");
|
||||
glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)SDL_GL_GetProcAddress("glValidateProgram");
|
||||
glGetProgramiv = (PFNGLGETPROGRAMIVPROC)SDL_GL_GetProcAddress("glGetProgramiv");
|
||||
glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)SDL_GL_GetProcAddress("glGetProgramInfoLog");
|
||||
glUseProgram = (PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram");
|
||||
|
||||
return glCreateShader && glShaderSource && glCompileShader && glGetShaderiv &&
|
||||
glGetShaderInfoLog && glDeleteShader && glAttachShader && glCreateProgram &&
|
||||
glLinkProgram && glValidateProgram && glGetProgramiv && glGetProgramInfoLog &&
|
||||
glUseProgram;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Función para compilar un shader a partir de un std::string
|
||||
GLuint compileShader(const std::string &source, GLuint shaderType)
|
||||
{
|
||||
if (source.empty())
|
||||
{
|
||||
throw std::runtime_error("ERROR FATAL: El código fuente del shader está vacío.");
|
||||
}
|
||||
|
||||
// Crear identificador del shader
|
||||
GLuint resultado = glCreateShader(shaderType);
|
||||
|
||||
// Agregar una directiva según el tipo de shader
|
||||
std::string directiva = (shaderType == GL_VERTEX_SHADER)
|
||||
? "#define VERTEX\n"
|
||||
: "#define FRAGMENT\n";
|
||||
|
||||
const char *sources[2] = {directiva.c_str(), source.c_str()};
|
||||
|
||||
// Especificar el código fuente del shader
|
||||
glShaderSource(resultado, 2, sources, nullptr);
|
||||
|
||||
// Compilar el shader
|
||||
glCompileShader(resultado);
|
||||
|
||||
// Verificar si la compilación fue exitosa
|
||||
GLint compiladoCorrectamente = GL_FALSE;
|
||||
glGetShaderiv(resultado, GL_COMPILE_STATUS, &compiladoCorrectamente);
|
||||
if (compiladoCorrectamente != GL_TRUE)
|
||||
{
|
||||
std::cout << "Error en la compilación del shader (" << resultado << ")!" << std::endl;
|
||||
GLint longitudLog;
|
||||
glGetShaderiv(resultado, GL_INFO_LOG_LENGTH, &longitudLog);
|
||||
if (longitudLog > 0)
|
||||
{
|
||||
std::vector<GLchar> log(longitudLog);
|
||||
glGetShaderInfoLog(resultado, longitudLog, &longitudLog, log.data());
|
||||
std::cout << "Registro de compilación del shader: " << log.data() << std::endl;
|
||||
}
|
||||
glDeleteShader(resultado);
|
||||
resultado = 0;
|
||||
}
|
||||
return resultado;
|
||||
}
|
||||
|
||||
// Función para compilar un programa de shaders (vertex y fragment) a partir de std::string
|
||||
GLuint compileProgram(const std::string &vertexShaderSource, const std::string &fragmentShaderSource)
|
||||
{
|
||||
GLuint idPrograma = glCreateProgram();
|
||||
|
||||
// Si el fragment shader está vacío, reutilizamos el código del vertex shader
|
||||
GLuint idShaderVertice = compileShader(vertexShaderSource, GL_VERTEX_SHADER);
|
||||
GLuint idShaderFragmento = compileShader(fragmentShaderSource.empty() ? vertexShaderSource : fragmentShaderSource, GL_FRAGMENT_SHADER);
|
||||
|
||||
if (idShaderVertice && idShaderFragmento)
|
||||
{
|
||||
// Asociar los shaders al programa
|
||||
glAttachShader(idPrograma, idShaderVertice);
|
||||
glAttachShader(idPrograma, idShaderFragmento);
|
||||
glLinkProgram(idPrograma);
|
||||
glValidateProgram(idPrograma);
|
||||
|
||||
// Verificar el estado del enlace
|
||||
GLint longitudLog;
|
||||
glGetProgramiv(idPrograma, GL_INFO_LOG_LENGTH, &longitudLog);
|
||||
if (longitudLog > 0)
|
||||
{
|
||||
std::vector<char> log(longitudLog);
|
||||
glGetProgramInfoLog(idPrograma, longitudLog, &longitudLog, log.data());
|
||||
std::cout << "Registro de información del programa:" << std::endl
|
||||
<< log.data() << std::endl;
|
||||
}
|
||||
}
|
||||
if (idShaderVertice)
|
||||
{
|
||||
glDeleteShader(idShaderVertice);
|
||||
}
|
||||
if (idShaderFragmento)
|
||||
{
|
||||
glDeleteShader(idShaderFragmento);
|
||||
}
|
||||
return idPrograma;
|
||||
}
|
||||
|
||||
bool init(SDL_Window *ventana, SDL_Texture *texturaBackBuffer, const std::string &vertexShader, const std::string &fragmentShader)
|
||||
{
|
||||
shader::win = ventana;
|
||||
shader::renderer = SDL_GetRenderer(ventana);
|
||||
shader::backBuffer = texturaBackBuffer;
|
||||
SDL_GetWindowSize(ventana, &win_size.x, &win_size.y);
|
||||
|
||||
int acceso;
|
||||
SDL_QueryTexture(texturaBackBuffer, nullptr, &acceso, &tex_size.x, &tex_size.y);
|
||||
if (acceso != SDL_TEXTUREACCESS_TARGET)
|
||||
{
|
||||
throw std::runtime_error("ERROR FATAL: La textura debe tener definido SDL_TEXTUREACCESS_TARGET.");
|
||||
}
|
||||
|
||||
SDL_RendererInfo infoRenderer;
|
||||
SDL_GetRendererInfo(renderer, &infoRenderer);
|
||||
|
||||
// Verificar que el renderer sea OpenGL
|
||||
if (!strncmp(infoRenderer.name, "opengl", 6))
|
||||
{
|
||||
#ifndef __APPLE__
|
||||
if (!initGLExtensions())
|
||||
{
|
||||
std::cout << "ADVERTENCIA: No se han podido inicializar las extensiones de OpenGL." << std::endl;
|
||||
usingOpenGL = false;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
// Compilar el programa de shaders utilizando std::string
|
||||
programId = compileProgram(vertexShader, fragmentShader);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "ADVERTENCIA: El driver del renderer no es OpenGL." << std::endl;
|
||||
usingOpenGL = false;
|
||||
return false;
|
||||
}
|
||||
usingOpenGL = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void render()
|
||||
{
|
||||
GLint oldProgramId;
|
||||
// Establece el color de fondo
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||
SDL_SetRenderTarget(renderer, nullptr);
|
||||
SDL_RenderClear(renderer);
|
||||
|
||||
if (usingOpenGL)
|
||||
{
|
||||
SDL_GL_BindTexture(backBuffer, nullptr, nullptr);
|
||||
if (programId != 0)
|
||||
{
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgramId);
|
||||
glUseProgram(programId);
|
||||
}
|
||||
|
||||
// Recupera el tamaño lógico configurado con SDL_RenderSetLogicalSize
|
||||
int logicalW, logicalH;
|
||||
SDL_RenderGetLogicalSize(renderer, &logicalW, &logicalH);
|
||||
if (logicalW == 0 || logicalH == 0)
|
||||
{
|
||||
logicalW = win_size.x;
|
||||
logicalH = win_size.y;
|
||||
}
|
||||
|
||||
// Cálculo del viewport
|
||||
int viewportX = 0, viewportY = 0, viewportW = win_size.x, viewportH = win_size.y;
|
||||
SDL_bool useIntegerScale = SDL_RenderGetIntegerScale(renderer);
|
||||
if (useIntegerScale)
|
||||
{
|
||||
// Calcula el factor de escalado entero máximo que se puede aplicar
|
||||
int scaleX = win_size.x / logicalW;
|
||||
int scaleY = win_size.y / logicalH;
|
||||
int scale = (scaleX < scaleY ? scaleX : scaleY);
|
||||
if (scale < 1)
|
||||
scale = 1;
|
||||
viewportW = logicalW * scale;
|
||||
viewportH = logicalH * scale;
|
||||
viewportX = (win_size.x - viewportW) / 2;
|
||||
viewportY = (win_size.y - viewportH) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Letterboxing: preserva la relación de aspecto usando una escala flotante
|
||||
float windowAspect = static_cast<float>(win_size.x) / win_size.y;
|
||||
float logicalAspect = static_cast<float>(logicalW) / logicalH;
|
||||
if (windowAspect > logicalAspect)
|
||||
{
|
||||
viewportW = static_cast<int>(logicalAspect * win_size.y);
|
||||
viewportX = (win_size.x - viewportW) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
viewportH = static_cast<int>(win_size.x / logicalAspect);
|
||||
viewportY = (win_size.y - viewportH) / 2;
|
||||
}
|
||||
}
|
||||
glViewport(viewportX, viewportY, viewportW, viewportH);
|
||||
|
||||
// Configurar la proyección ortográfica usando el espacio lógico
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
// Queremos que el origen esté en la esquina superior izquierda del espacio lógico.
|
||||
glOrtho(0, static_cast<GLdouble>(logicalW), static_cast<GLdouble>(logicalH), 0, -1, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
// Dibuja el quad con las coordenadas ajustadas.
|
||||
// Se asignan las coordenadas de textura "normales" para que no quede espejado horizontalmente,
|
||||
// y se mantiene el flip vertical para que la imagen no aparezca volteada.
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
// Vértice superior izquierdo
|
||||
glTexCoord2f(0.0f, 1.0f);
|
||||
glVertex2f(0.0f, 0.0f);
|
||||
// Vértice superior derecho
|
||||
glTexCoord2f(1.0f, 1.0f);
|
||||
glVertex2f(static_cast<GLfloat>(logicalW), 0.0f);
|
||||
// Vértice inferior izquierdo
|
||||
glTexCoord2f(0.0f, 0.0f);
|
||||
glVertex2f(0.0f, static_cast<GLfloat>(logicalH));
|
||||
// Vértice inferior derecho
|
||||
glTexCoord2f(1.0f, 0.0f);
|
||||
glVertex2f(static_cast<GLfloat>(logicalW), static_cast<GLfloat>(logicalH));
|
||||
glEnd();
|
||||
|
||||
SDL_GL_SwapWindow(win);
|
||||
|
||||
if (programId != 0)
|
||||
{
|
||||
glUseProgram(oldProgramId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_RenderCopy(renderer, backBuffer, nullptr, nullptr);
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
#include "loading_screen.h"
|
||||
#include <SDL2/SDL_events.h> // Para SDL_PollEvent, SDL_Event
|
||||
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
||||
#include <stdlib.h> // Para rand
|
||||
#include "defines.h" // Para GAME_SPEED
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
#include "jail_audio.h" // Para JA_PlayMusic, JA_SetVolume, JA_StopMusic
|
||||
#include "options.h" // Para Options, options, SectionState, Options...
|
||||
#include "resource.h" // Para Resource
|
||||
#include "s_sprite.h" // Para SSprite
|
||||
#include "screen.h" // Para Screen
|
||||
#include "surface.h" // Para Surface
|
||||
#include "utils.h" // Para stringToColor, PaletteColor
|
||||
|
||||
// Constructor
|
||||
LoadingScreen::LoadingScreen()
|
||||
: mono_loading_screen_surface_(Resource::get()->getSurface("loading_screen_bn.gif")),
|
||||
color_loading_screen_surface_(Resource::get()->getSurface("loading_screen_color.gif")),
|
||||
mono_loading_screen_sprite_(std::make_shared<SSprite>(mono_loading_screen_surface_, 0, 0, mono_loading_screen_surface_->getWidth(), mono_loading_screen_surface_->getHeight())),
|
||||
color_loading_screen_sprite_(std::make_shared<SSprite>(color_loading_screen_surface_, 0, 0, color_loading_screen_surface_->getWidth(), color_loading_screen_surface_->getHeight())),
|
||||
screen_surface_(std::make_shared<Surface>(options.game.width, options.game.height))
|
||||
{
|
||||
// Configura la superficie donde se van a pintar los sprites
|
||||
screen_surface_->clear(static_cast<Uint8>(PaletteColor::WHITE));
|
||||
|
||||
// Inicializa variables
|
||||
options.section.section = Section::LOADING_SCREEN;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
|
||||
// Establece el orden de las lineas para imitar el direccionamiento de memoria del spectrum
|
||||
for (int i = 0; i < 192; ++i)
|
||||
{
|
||||
if (i < 64)
|
||||
{ // Primer bloque de 2K
|
||||
line_index_[i] = ((i % 8) * 8) + (i / 8);
|
||||
}
|
||||
else if (i < 128)
|
||||
{ // Segundo bloque de 2K
|
||||
line_index_[i] = 64 + ((i % 8) * 8) + ((i - 64) / 8);
|
||||
}
|
||||
else
|
||||
{ // Tercer bloque de 2K
|
||||
line_index_[i] = 128 + ((i % 8) * 8) + ((i - 128) / 8);
|
||||
}
|
||||
}
|
||||
|
||||
// Cambia el color del borde
|
||||
Screen::get()->setBorderColor(stringToColor("black"));
|
||||
}
|
||||
|
||||
// Destructor
|
||||
LoadingScreen::~LoadingScreen()
|
||||
{
|
||||
JA_StopMusic();
|
||||
}
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void LoadingScreen::checkEvents()
|
||||
{
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
globalEvents::check(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las entradas
|
||||
void LoadingScreen::checkInput()
|
||||
{
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Gestiona el contador de carga
|
||||
void LoadingScreen::updateLoad()
|
||||
{
|
||||
// Primera parte de la carga, la parte en blanco y negro
|
||||
if (loading_first_part_)
|
||||
{
|
||||
// Cada 5 pasos el load_counter_ se incrementa en uno
|
||||
constexpr int NUM_STEPS = 5;
|
||||
constexpr int STEPS = 51;
|
||||
load_counter_ = counter_ / NUM_STEPS;
|
||||
|
||||
if (load_counter_ < 192)
|
||||
{
|
||||
load_rect_.x = STEPS * (counter_ % NUM_STEPS);
|
||||
load_rect_.y = line_index_[load_counter_];
|
||||
mono_loading_screen_sprite_->setClip(load_rect_);
|
||||
mono_loading_screen_sprite_->setPosition(load_rect_);
|
||||
}
|
||||
// Una vez actualizadas las 192 lineas, pasa a la segunda fase de la carga
|
||||
else if (load_counter_ == 192)
|
||||
{
|
||||
loading_first_part_ = false;
|
||||
load_counter_ = 0;
|
||||
load_rect_ = {0, 0, 16, 8};
|
||||
color_loading_screen_sprite_->setClip(load_rect_);
|
||||
color_loading_screen_sprite_->setPosition(load_rect_);
|
||||
JA_PlayMusic(Resource::get()->getMusic("loading_sound3.ogg"));
|
||||
}
|
||||
}
|
||||
// Segunda parte de la carga, la parte de los bloques en color
|
||||
else
|
||||
{
|
||||
load_counter_ += 2;
|
||||
load_rect_.x = (load_counter_ * 8) % 256;
|
||||
load_rect_.y = (load_counter_ / 32) * 8;
|
||||
color_loading_screen_sprite_->setClip(load_rect_);
|
||||
color_loading_screen_sprite_->setPosition(load_rect_);
|
||||
|
||||
// Comprueba si ha terminado la intro
|
||||
if (load_counter_ >= 768)
|
||||
{
|
||||
options.section.section = Section::TITLE;
|
||||
options.section.subsection = Subsection::TITLE_WITH_LOADING_SCREEN;
|
||||
JA_StopMusic();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gestiona el contador interno
|
||||
void LoadingScreen::updateCounter()
|
||||
{
|
||||
(pre_counter_ >= 50) ? counter_++ : pre_counter_++;
|
||||
|
||||
if (counter_ == 1)
|
||||
{
|
||||
JA_PlayMusic(Resource::get()->getMusic("loading_sound2.ogg"));
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja la pantalla de carga
|
||||
void LoadingScreen::renderLoad()
|
||||
{
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(screen_surface_);
|
||||
loading_first_part_ ? mono_loading_screen_sprite_->render(1, stringToColor("black")) : color_loading_screen_sprite_->render();
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
}
|
||||
|
||||
// Dibuja el efecto de carga en el borde
|
||||
void LoadingScreen::renderBorder()
|
||||
{
|
||||
// Obtiene la Surface del borde
|
||||
auto border = Screen::get()->getBorderSurface();
|
||||
|
||||
// Pinta el borde de color azul
|
||||
border->clear(static_cast<Uint8>(PaletteColor::BLUE));
|
||||
|
||||
// Añade lineas amarillas
|
||||
const Uint8 COLOR = static_cast<Uint8>(PaletteColor::YELLOW);
|
||||
const int WIDTH = options.game.width + (options.video.border.width * 2);
|
||||
const int HEIGHT = options.game.height + (options.video.border.height * 2);
|
||||
bool draw_enabled = rand() % 2 == 0 ? true : false;
|
||||
|
||||
int row = 0;
|
||||
while (row < HEIGHT)
|
||||
{
|
||||
const int ROW_HEIGHT = (rand() % 4) + 3;
|
||||
if (draw_enabled)
|
||||
{
|
||||
for (int i = row; i < row + ROW_HEIGHT; ++i)
|
||||
{
|
||||
border->drawLine(0, i, WIDTH, i, COLOR);
|
||||
}
|
||||
}
|
||||
row += ROW_HEIGHT;
|
||||
draw_enabled = !draw_enabled;
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza las variables
|
||||
void LoadingScreen::update()
|
||||
{
|
||||
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED)
|
||||
{
|
||||
ticks_ = SDL_GetTicks();
|
||||
checkInput();
|
||||
updateCounter();
|
||||
updateLoad();
|
||||
renderLoad();
|
||||
Screen::get()->update();
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja en pantalla
|
||||
void LoadingScreen::render()
|
||||
{
|
||||
if (options.video.border.enabled)
|
||||
{
|
||||
// Dibuja el efecto de carga en el borde
|
||||
renderBorder();
|
||||
}
|
||||
|
||||
// Prepara para empezar a dibujar en la textura de juego
|
||||
Screen::get()->start();
|
||||
Screen::get()->clearSurface(stringToColor("white"));
|
||||
|
||||
// Copia la surface a la surface de Screen
|
||||
screen_surface_->render(0, 0);
|
||||
|
||||
// Vuelca el contenido del renderizador en pantalla
|
||||
Screen::get()->render();
|
||||
}
|
||||
|
||||
// Bucle para el logo del juego
|
||||
void LoadingScreen::run()
|
||||
{
|
||||
// Inicia el sonido de carga
|
||||
JA_SetVolume(64);
|
||||
JA_PlayMusic(Resource::get()->getMusic("loading_sound1.ogg"));
|
||||
|
||||
// Limpia la pantalla
|
||||
Screen::get()->start();
|
||||
Screen::get()->clearRenderer();
|
||||
Screen::get()->render();
|
||||
|
||||
while (options.section.section == Section::LOADING_SCREEN)
|
||||
{
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
}
|
||||
|
||||
JA_SetVolume(128);
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint32
|
||||
#include <memory> // Para shared_ptr
|
||||
class SSprite; // lines 7-7
|
||||
class Surface; // lines 8-8
|
||||
|
||||
class LoadingScreen
|
||||
{
|
||||
private:
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<Surface> mono_loading_screen_surface_; // Surface con la pantalla de carga en blanco y negro
|
||||
std::shared_ptr<Surface> color_loading_screen_surface_; // Surface con la pantalla de carga en color
|
||||
std::shared_ptr<SSprite> mono_loading_screen_sprite_; // SSprite para manejar la textura loadingScreenTexture1
|
||||
std::shared_ptr<SSprite> color_loading_screen_sprite_; // SSprite para manejar la textura loadingScreenTexture2
|
||||
std::shared_ptr<Surface> screen_surface_; // Surface para dibujar la pantalla de carga
|
||||
|
||||
// Variables
|
||||
int pre_counter_ = 0; // Contador previo para realizar una pausa inicial
|
||||
int counter_ = 0; // Contador
|
||||
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
int load_counter_ = 0; // Contador para controlar las cargas
|
||||
bool loading_first_part_ = true; // Para saber en que parte de la carga se encuentra
|
||||
int line_index_[192]; // El orden en el que se procesan las 192 lineas de la pantalla de carga
|
||||
SDL_Rect load_rect_ = {0, 0, 52, 1}; // Rectangulo para dibujar la pantalla de carga
|
||||
|
||||
// Actualiza las variables
|
||||
void update();
|
||||
|
||||
// Dibuja en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void checkEvents();
|
||||
|
||||
// Comprueba las entradas
|
||||
void checkInput();
|
||||
|
||||
// Gestiona el contador interno
|
||||
void updateCounter();
|
||||
|
||||
// Gestiona el contador de carga
|
||||
void updateLoad();
|
||||
|
||||
// Dibuja la pantalla de carga
|
||||
void renderLoad();
|
||||
|
||||
// Dibuja el efecto de carga en el borde
|
||||
void renderBorder();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
LoadingScreen();
|
||||
|
||||
// Destructor
|
||||
~LoadingScreen();
|
||||
|
||||
// Bucle principal
|
||||
void run();
|
||||
};
|
||||
265
source/logo.cpp
265
source/logo.cpp
@@ -1,265 +0,0 @@
|
||||
#include "logo.h"
|
||||
#include <SDL2/SDL_events.h> // Para SDL_PollEvent, SDL_Event
|
||||
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
||||
#include "defines.h" // Para GAME_SPEED
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
#include "options.h" // Para Options, SectionState, options, Section
|
||||
#include "resource.h" // Para Resource
|
||||
#include "s_sprite.h" // Para SSprite
|
||||
#include "screen.h" // Para Screen
|
||||
#include "surface.h" // Para Surface
|
||||
#include "utils.h" // Para PaletteColor
|
||||
|
||||
// Constructor
|
||||
Logo::Logo()
|
||||
: jailgames_surface_(Resource::get()->getSurface("jailgames.gif")),
|
||||
since_1998_surface_(Resource::get()->getSurface("since_1998.gif")),
|
||||
since_1998_sprite_(std::make_shared<SSprite>(since_1998_surface_, (256 - since_1998_surface_->getWidth()) / 2, 83 + jailgames_surface_->getHeight() + 5, since_1998_surface_->getWidth(), since_1998_surface_->getHeight()))
|
||||
{
|
||||
since_1998_sprite_->setClip(0, 0, since_1998_surface_->getWidth(), since_1998_surface_->getHeight());
|
||||
since_1998_color_ = static_cast<Uint8>(PaletteColor::BLACK);
|
||||
jailgames_color_ = static_cast<Uint8>(PaletteColor::BRIGHT_WHITE);
|
||||
|
||||
// Crea los sprites de cada linea
|
||||
for (int i = 0; i < jailgames_surface_->getHeight(); ++i)
|
||||
{
|
||||
jailgames_sprite_.push_back(std::make_shared<SSprite>(jailgames_surface_, 0, i, jailgames_surface_->getWidth(), 1));
|
||||
jailgames_sprite_.back()->setClip(0, i, jailgames_surface_->getWidth(), 1);
|
||||
jailgames_sprite_.at(i)->setX((i % 2 == 0) ? (256 + (i * 3)) : (-181 - (i * 3)));
|
||||
jailgames_sprite_.at(i)->setY(83 + i);
|
||||
}
|
||||
|
||||
// Inicializa variables
|
||||
options.section.section = Section::LOGO;
|
||||
|
||||
// Inicializa el vector de colores
|
||||
const std::vector<Uint8> COLORS = {
|
||||
static_cast<Uint8>(PaletteColor::BLACK),
|
||||
static_cast<Uint8>(PaletteColor::BLUE),
|
||||
static_cast<Uint8>(PaletteColor::RED),
|
||||
static_cast<Uint8>(PaletteColor::MAGENTA),
|
||||
static_cast<Uint8>(PaletteColor::GREEN),
|
||||
static_cast<Uint8>(PaletteColor::CYAN),
|
||||
static_cast<Uint8>(PaletteColor::YELLOW),
|
||||
static_cast<Uint8>(PaletteColor::BRIGHT_WHITE)};
|
||||
for (const auto &color : COLORS)
|
||||
{
|
||||
color_.push_back(color);
|
||||
}
|
||||
|
||||
// Cambia el color del borde
|
||||
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
}
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void Logo::checkEvents()
|
||||
{
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
globalEvents::check(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las entradas
|
||||
void Logo::checkInput()
|
||||
{
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Gestiona el logo de JAILGAME
|
||||
void Logo::updateJAILGAMES()
|
||||
{
|
||||
if (counter_ > 30)
|
||||
{
|
||||
for (int i = 1; i < (int)jailgames_sprite_.size(); ++i)
|
||||
{
|
||||
constexpr int SPEED = 8;
|
||||
constexpr int DEST = 37;
|
||||
if (jailgames_sprite_.at(i)->getX() != 37)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
jailgames_sprite_.at(i)->incX(-SPEED);
|
||||
if (jailgames_sprite_.at(i)->getX() < DEST)
|
||||
{
|
||||
jailgames_sprite_.at(i)->setX(DEST);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
jailgames_sprite_.at(i)->incX(SPEED);
|
||||
if (jailgames_sprite_.at(i)->getX() > DEST)
|
||||
{
|
||||
jailgames_sprite_.at(i)->setX(DEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gestiona el color de las texturas
|
||||
void Logo::updateTextureColors()
|
||||
{
|
||||
constexpr int INI = 70;
|
||||
constexpr int INC = 4;
|
||||
|
||||
if (counter_ == INI + INC * 0)
|
||||
{
|
||||
since_1998_color_ = color_.at(0);
|
||||
}
|
||||
|
||||
else if (counter_ == INI + INC * 1)
|
||||
{
|
||||
since_1998_color_ = color_.at(1);
|
||||
}
|
||||
|
||||
else if (counter_ == INI + INC * 2)
|
||||
{
|
||||
since_1998_color_ = color_.at(2);
|
||||
}
|
||||
|
||||
else if (counter_ == INI + INC * 3)
|
||||
{
|
||||
since_1998_color_ = color_.at(3);
|
||||
}
|
||||
|
||||
else if (counter_ == INI + INC * 4)
|
||||
{
|
||||
since_1998_color_ = color_.at(4);
|
||||
}
|
||||
|
||||
else if (counter_ == INI + INC * 5)
|
||||
{
|
||||
since_1998_color_ = color_.at(5);
|
||||
}
|
||||
|
||||
else if (counter_ == INI + INC * 6)
|
||||
{
|
||||
since_1998_color_ = color_.at(6);
|
||||
}
|
||||
|
||||
else if (counter_ == INI + INC * 7)
|
||||
{
|
||||
since_1998_color_ = color_.at(7);
|
||||
}
|
||||
|
||||
else if (counter_ == INIT_FADE_ + INC * 0)
|
||||
{
|
||||
jailgames_color_ = color_.at(6);
|
||||
since_1998_color_ = color_.at(6);
|
||||
}
|
||||
|
||||
else if (counter_ == INIT_FADE_ + INC * 1)
|
||||
{
|
||||
jailgames_color_ = color_.at(5);
|
||||
since_1998_color_ = color_.at(5);
|
||||
}
|
||||
|
||||
else if (counter_ == INIT_FADE_ + INC * 2)
|
||||
{
|
||||
jailgames_color_ = color_.at(4);
|
||||
since_1998_color_ = color_.at(4);
|
||||
}
|
||||
|
||||
else if (counter_ == INIT_FADE_ + INC * 3)
|
||||
{
|
||||
jailgames_color_ = color_.at(3);
|
||||
since_1998_color_ = color_.at(3);
|
||||
}
|
||||
|
||||
else if (counter_ == INIT_FADE_ + INC * 4)
|
||||
{
|
||||
jailgames_color_ = color_.at(2);
|
||||
since_1998_color_ = color_.at(2);
|
||||
}
|
||||
|
||||
else if (counter_ == INIT_FADE_ + INC * 5)
|
||||
{
|
||||
jailgames_color_ = color_.at(1);
|
||||
since_1998_color_ = color_.at(1);
|
||||
}
|
||||
|
||||
else if (counter_ == INIT_FADE_ + INC * 6)
|
||||
{
|
||||
jailgames_color_ = color_.at(0);
|
||||
since_1998_color_ = color_.at(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza las variables
|
||||
void Logo::update()
|
||||
{
|
||||
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED)
|
||||
{
|
||||
// Actualiza el contador de ticks
|
||||
ticks_ = SDL_GetTicks();
|
||||
|
||||
// Comprueba las entradas
|
||||
checkInput();
|
||||
|
||||
// Incrementa el contador
|
||||
counter_++;
|
||||
|
||||
// Gestiona el logo de JAILGAME
|
||||
updateJAILGAMES();
|
||||
|
||||
// Gestiona el color de las texturas
|
||||
updateTextureColors();
|
||||
|
||||
// Actualiza el objeto Screen
|
||||
Screen::get()->update();
|
||||
|
||||
// Comprueba si ha terminado el logo
|
||||
if (counter_ == END_LOGO_ + POST_LOGO_)
|
||||
{
|
||||
endSection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja en pantalla
|
||||
void Logo::render()
|
||||
{
|
||||
// Prepara para empezar a dibujar en la textura de juego
|
||||
Screen::get()->start();
|
||||
Screen::get()->clearSurface(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
// Dibuja los objetos
|
||||
for (const auto &s : jailgames_sprite_)
|
||||
{
|
||||
s->render(1, jailgames_color_);
|
||||
}
|
||||
since_1998_sprite_->render(1, since_1998_color_);
|
||||
|
||||
// Vuelca el contenido del renderizador en pantalla
|
||||
Screen::get()->render();
|
||||
}
|
||||
|
||||
// Bucle para el logo del juego
|
||||
void Logo::run()
|
||||
{
|
||||
while (options.section.section == Section::LOGO)
|
||||
{
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
// Termina la sección
|
||||
void Logo::endSection()
|
||||
{
|
||||
if (options.section.subsection == Subsection::LOGO_TO_TITLE)
|
||||
{
|
||||
options.section.section = Section::TITLE;
|
||||
}
|
||||
|
||||
else if (options.section.subsection == Subsection::LOGO_TO_INTRO)
|
||||
{
|
||||
options.section.section = Section::LOADING_SCREEN;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint8, Uint32
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <vector> // Para vector
|
||||
class SSprite; // lines 7-7
|
||||
class Surface; // lines 8-8
|
||||
|
||||
class Logo
|
||||
{
|
||||
private:
|
||||
// Constantes
|
||||
static constexpr int INIT_FADE_ = 300; // Tiempo del contador cuando inicia el fade a negro
|
||||
static constexpr int END_LOGO_ = 400; // Tiempo del contador para terminar el logo
|
||||
static constexpr int POST_LOGO_ = 20; // Tiempo que dura el logo con el fade al maximo
|
||||
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<Surface> jailgames_surface_; // Textura con los graficos "JAILGAMES"
|
||||
std::shared_ptr<Surface> since_1998_surface_; // Textura con los graficos "Since 1998"
|
||||
std::vector<std::shared_ptr<SSprite>> jailgames_sprite_; // Vector con los sprites de cada linea que forman el bitmap JAILGAMES
|
||||
std::shared_ptr<SSprite> since_1998_sprite_; // SSprite para manejar la textura2
|
||||
Uint8 jailgames_color_ = 0; // Color para el sprite de "JAILGAMES"
|
||||
Uint8 since_1998_color_ = 0; // Color para el sprite de "Since 1998"
|
||||
|
||||
// Variables
|
||||
std::vector<Uint8> color_; // Vector con los colores para el fade
|
||||
int counter_ = 0; // Contador
|
||||
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
|
||||
// Actualiza las variables
|
||||
void update();
|
||||
|
||||
// Dibuja en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void checkEvents();
|
||||
|
||||
// Comprueba las entradas
|
||||
void checkInput();
|
||||
|
||||
// Gestiona el logo de JAILGAME
|
||||
void updateJAILGAMES();
|
||||
|
||||
// Gestiona el color de las texturas
|
||||
void updateTextureColors();
|
||||
|
||||
// Termina la sección
|
||||
void endSection();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Logo();
|
||||
|
||||
// Destructor
|
||||
~Logo() = default;
|
||||
|
||||
// Bucle principal
|
||||
void run();
|
||||
};
|
||||
@@ -1,33 +1,28 @@
|
||||
#include "mouse.h"
|
||||
#include <SDL2/SDL_mouse.h> // Para SDL_ShowCursor
|
||||
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
namespace Mouse
|
||||
{
|
||||
Uint32 cursor_hide_time = 3000; // Tiempo en milisegundos para ocultar el cursor
|
||||
Uint32 last_mouse_move_time = 0; // Última vez que el ratón se movió
|
||||
bool cursor_visible = true; // Estado del cursor
|
||||
#include <SDL3/SDL_mouse.h> // Para SDL_ShowCursor
|
||||
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
void handleEvent(const SDL_Event &event)
|
||||
{
|
||||
if (event.type == SDL_MOUSEMOTION)
|
||||
{
|
||||
namespace Mouse {
|
||||
Uint32 cursor_hide_time = 3000; // Tiempo en milisegundos para ocultar el cursor
|
||||
Uint32 last_mouse_move_time = 0; // Última vez que el ratón se movió
|
||||
bool cursor_visible = true; // Estado del cursor
|
||||
|
||||
void handleEvent(const SDL_Event& event) {
|
||||
if (event.type == SDL_MOUSEMOTION) {
|
||||
last_mouse_move_time = SDL_GetTicks();
|
||||
if (!cursor_visible)
|
||||
{
|
||||
if (!cursor_visible) {
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
cursor_visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateCursorVisibility()
|
||||
{
|
||||
void updateCursorVisibility() {
|
||||
Uint32 current_time = SDL_GetTicks();
|
||||
if (cursor_visible && (current_time - last_mouse_move_time > cursor_hide_time))
|
||||
{
|
||||
if (cursor_visible && (current_time - last_mouse_move_time > cursor_hide_time)) {
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
cursor_visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Mouse
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_events.h> // Para SDL_Event
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint32
|
||||
#include <SDL3/SDL_events.h> // Para SDL_Event
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint32
|
||||
|
||||
namespace Mouse
|
||||
{
|
||||
extern Uint32 cursor_hide_time; // Tiempo en milisegundos para ocultar el cursor
|
||||
extern Uint32 last_mouse_move_time; // Última vez que el ratón se movió
|
||||
extern bool cursor_visible; // Estado del cursor
|
||||
namespace Mouse {
|
||||
extern Uint32 cursor_hide_time; // Tiempo en milisegundos para ocultar el cursor
|
||||
extern Uint32 last_mouse_move_time; // Última vez que el ratón se movió
|
||||
extern bool cursor_visible; // Estado del cursor
|
||||
|
||||
void handleEvent(const SDL_Event &event);
|
||||
void updateCursorVisibility();
|
||||
}
|
||||
void handleEvent(const SDL_Event& event);
|
||||
void updateCursorVisibility();
|
||||
} // namespace Mouse
|
||||
@@ -1,131 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint32, Uint8
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string, basic_string
|
||||
#include <vector> // Para vector
|
||||
class SSprite; // lines 8-8
|
||||
class Surface; // lines 10-10
|
||||
class Text; // lines 9-9
|
||||
|
||||
// Constantes
|
||||
constexpr Uint32 DEFAULT_NOTIFICATION_DURATION = 2000;
|
||||
constexpr Uint32 CHEEVO_NOTIFICATION_DURATION = 4000;
|
||||
|
||||
// Justificado para las notificaciones
|
||||
enum class NotificationText
|
||||
{
|
||||
LEFT,
|
||||
CENTER,
|
||||
};
|
||||
|
||||
class Notifier
|
||||
{
|
||||
private:
|
||||
// Constantes
|
||||
static constexpr int ICON_SIZE_ = 16;
|
||||
static constexpr int PADDING_OUT_ = 0;
|
||||
|
||||
// [SINGLETON] Objeto notifier
|
||||
static Notifier *notifier_;
|
||||
|
||||
enum class NotificationStatus
|
||||
{
|
||||
RISING,
|
||||
STAY,
|
||||
VANISHING,
|
||||
FINISHED,
|
||||
};
|
||||
|
||||
enum class NotificationShape
|
||||
{
|
||||
ROUNDED,
|
||||
SQUARED,
|
||||
};
|
||||
|
||||
struct Notification
|
||||
{
|
||||
std::shared_ptr<Surface> surface; // Superficie asociada a la notificación
|
||||
std::shared_ptr<SSprite> sprite; // Sprite asociado para gráficos o animaciones
|
||||
std::vector<std::string> texts; // Lista de textos incluidos en la notificación
|
||||
NotificationStatus state; // Estado actual de la notificación (RISING, SHOWING, etc.)
|
||||
NotificationShape shape; // Forma de la notificación (ej. SQUARED o ROUNDED)
|
||||
SDL_Rect rect; // Dimensiones y posición de la notificación en pantalla
|
||||
int y; // Posición actual en el eje Y
|
||||
int travel_dist; // Distancia a recorrer (por ejemplo, en animaciones)
|
||||
std::string code; // Código identificador único para esta notificación
|
||||
bool can_be_removed; // Indica si la notificación puede ser eliminada
|
||||
int height; // Altura de la notificación
|
||||
Uint32 start_time; // Momento en que se creó la notificación
|
||||
Uint32 elapsed_time; // Tiempo transcurrido desde la creación
|
||||
Uint32 display_duration; // Duración total para mostrar la notificación
|
||||
|
||||
// Constructor
|
||||
explicit Notification()
|
||||
: surface(nullptr), // Inicializar superficie como nula
|
||||
sprite(nullptr), // Inicializar sprite como nulo
|
||||
texts(), // Inicializar lista de textos vacía
|
||||
state(NotificationStatus::RISING), // Estado inicial como "RISING"
|
||||
shape(NotificationShape::SQUARED), // Forma inicial como "SQUARED"
|
||||
rect{0, 0, 0, 0}, // Rectángulo inicial vacío
|
||||
y(0), // Posición Y inicializada a 0
|
||||
travel_dist(0), // Distancia inicializada a 0
|
||||
code(""), // Código identificador vacío
|
||||
can_be_removed(true), // Inicialmente se puede eliminar
|
||||
height(0), // Altura inicializada a 0
|
||||
start_time(0), // Tiempo de creación inicializado a 0
|
||||
elapsed_time(0), // Tiempo transcurrido inicializado a 0
|
||||
display_duration(0) // Duración inicializada a 0
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<Surface> icon_surface_; // Textura para los iconos de las notificaciones
|
||||
std::shared_ptr<Text> text_; // Objeto para dibujar texto
|
||||
|
||||
// Variables
|
||||
Uint8 bg_color_; // Color de fondo de las notificaciones
|
||||
std::vector<Notification> notifications_; // La lista de notificaciones activas
|
||||
bool stack_; // Indica si las notificaciones se apilan
|
||||
bool has_icons_; // Indica si el notificador tiene textura para iconos
|
||||
|
||||
// Elimina las notificaciones finalizadas
|
||||
void clearFinishedNotifications();
|
||||
|
||||
// Finaliza y elimnina todas las notificaciones activas
|
||||
void clearNotifications();
|
||||
|
||||
// [SINGLETON] Ahora el constructor y el destructor son privados, para no poder crear objetos notifier desde fuera
|
||||
|
||||
// Constructor
|
||||
Notifier(const std::string &icon_file, const std::string &text);
|
||||
|
||||
// Destructor
|
||||
~Notifier() = default;
|
||||
|
||||
public:
|
||||
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||
static void init(const std::string &icon_file, const std::string &text);
|
||||
|
||||
// [SINGLETON] Destruiremos el objeto con esta función estática
|
||||
static void destroy();
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
static Notifier *get();
|
||||
|
||||
// Dibuja las notificaciones por pantalla
|
||||
void render();
|
||||
|
||||
// Actualiza el estado de las notificaiones
|
||||
void update();
|
||||
|
||||
// Muestra una notificación de texto por pantalla
|
||||
void show(std::vector<std::string> texts, NotificationText text_is = NotificationText::LEFT, Uint32 display_duration = DEFAULT_NOTIFICATION_DURATION, int icon = -1, bool can_be_removed = true, const std::string &code = std::string());
|
||||
|
||||
// Indica si hay notificaciones activas
|
||||
bool isActive();
|
||||
|
||||
// Obtiene los códigos de las notificaciones
|
||||
std::vector<std::string> getCodes();
|
||||
};
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "options.h"
|
||||
#include <SDL2/SDL_video.h> // Para SDL_WINDOW_FULLSCREEN_DESKTOP
|
||||
|
||||
#include <SDL3/SDL_video.h> // Para SDL_WINDOW_FULLSCREEN_DESKTOP
|
||||
|
||||
#include <algorithm> // Para find_if
|
||||
#include <cctype> // Para isspace
|
||||
#include <fstream> // Para basic_ostream, operator<<, basic_ofstream
|
||||
@@ -13,11 +15,10 @@
|
||||
// Variables
|
||||
Options options;
|
||||
|
||||
bool setOptions(const std::string &var, const std::string &value);
|
||||
bool setOptions(const std::string& var, const std::string& value);
|
||||
|
||||
// Crea e inicializa las opciones del programa
|
||||
void initOptions()
|
||||
{
|
||||
void initOptions() {
|
||||
options = Options();
|
||||
|
||||
#ifdef DEBUG
|
||||
@@ -30,8 +31,7 @@ void initOptions()
|
||||
}
|
||||
|
||||
// Carga las opciones desde un fichero
|
||||
bool loadOptionsFromFile(const std::string &file_path)
|
||||
{
|
||||
bool loadOptionsFromFile(const std::string& file_path) {
|
||||
// Indicador de éxito en la carga
|
||||
bool success = true;
|
||||
|
||||
@@ -43,28 +43,22 @@ bool loadOptionsFromFile(const std::string &file_path)
|
||||
std::ifstream file(file_path);
|
||||
|
||||
// Si el fichero se puede abrir
|
||||
if (file.good())
|
||||
{
|
||||
if (file.good()) {
|
||||
// Procesa el fichero línea a línea
|
||||
if (options.console)
|
||||
{
|
||||
if (options.console) {
|
||||
std::cout << "Reading file config.txt\n";
|
||||
}
|
||||
std::string line;
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
while (std::getline(file, line)) {
|
||||
// Elimina espacios en blanco iniciales y finales
|
||||
line = std::string(std::find_if(line.begin(), line.end(), [](int ch)
|
||||
{ return !std::isspace(ch); }),
|
||||
line = std::string(std::find_if(line.begin(), line.end(), [](int ch) { return !std::isspace(ch); }),
|
||||
line.end());
|
||||
line.erase(std::find_if(line.rbegin(), line.rend(), [](int ch)
|
||||
{ return !std::isspace(ch); })
|
||||
line.erase(std::find_if(line.rbegin(), line.rend(), [](int ch) { return !std::isspace(ch); })
|
||||
.base(),
|
||||
line.end());
|
||||
|
||||
// Ignora líneas vacías o comentarios
|
||||
if (line.empty() || line[0] == '#')
|
||||
{
|
||||
if (line.empty() || line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -72,12 +66,9 @@ bool loadOptionsFromFile(const std::string &file_path)
|
||||
std::istringstream iss(line);
|
||||
std::string key, value;
|
||||
|
||||
if (iss >> key >> value)
|
||||
{
|
||||
if (!setOptions(key, value))
|
||||
{
|
||||
if (options.console)
|
||||
{
|
||||
if (iss >> key >> value) {
|
||||
if (!setOptions(key, value)) {
|
||||
if (options.console) {
|
||||
std::cout << "Warning: file config.txt\n";
|
||||
std::cout << "unknown parameter " << key << std::endl;
|
||||
}
|
||||
@@ -87,25 +78,20 @@ bool loadOptionsFromFile(const std::string &file_path)
|
||||
}
|
||||
|
||||
// Cierra el fichero
|
||||
if (options.console)
|
||||
{
|
||||
if (options.console) {
|
||||
std::cout << "Closing file config.txt\n\n";
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Crea el fichero con los valores por defecto
|
||||
saveOptionsToFile(file_path);
|
||||
}
|
||||
|
||||
// Si la versión de fichero no coincide, crea un fichero nuevo con los valores por defecto
|
||||
if (configVersion != options.version)
|
||||
{
|
||||
if (configVersion != options.version) {
|
||||
initOptions();
|
||||
saveOptionsToFile(file_path);
|
||||
if (options.console)
|
||||
{
|
||||
if (options.console) {
|
||||
std::cout << "Wrong config file: initializing options.\n\n";
|
||||
}
|
||||
}
|
||||
@@ -114,23 +100,20 @@ bool loadOptionsFromFile(const std::string &file_path)
|
||||
}
|
||||
|
||||
// Guarda las opciones en un fichero
|
||||
bool saveOptionsToFile(const std::string &file_path)
|
||||
{
|
||||
bool saveOptionsToFile(const std::string& file_path) {
|
||||
// Crea y abre el fichero de texto
|
||||
std::ofstream file(file_path);
|
||||
bool success = file.is_open(); // Verifica si el archivo se abrió correctamente
|
||||
|
||||
if (!success) // Si no se pudo abrir el archivo, muestra un mensaje de error y devuelve false
|
||||
{
|
||||
if (options.console)
|
||||
{
|
||||
if (options.console) {
|
||||
std::cerr << "Error: Unable to open file " << file_path << " for writing." << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.console)
|
||||
{
|
||||
if (options.console) {
|
||||
std::cout << file_path << " open for writing" << std::endl;
|
||||
}
|
||||
|
||||
@@ -174,101 +157,68 @@ bool saveOptionsToFile(const std::string &file_path)
|
||||
return success;
|
||||
}
|
||||
|
||||
bool setOptions(const std::string &var, const std::string &value)
|
||||
{
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string &)>> optionHandlers = {
|
||||
{"version", [](const std::string &v)
|
||||
{ options.version = v; }},
|
||||
{"keys", [](const std::string &v)
|
||||
{
|
||||
bool setOptions(const std::string& var, const std::string& value) {
|
||||
static const std::unordered_map<std::string, std::function<void(const std::string&)>> optionHandlers = {
|
||||
{"version", [](const std::string& v) { options.version = v; }},
|
||||
{"keys", [](const std::string& v) {
|
||||
int val = safeStoi(v, static_cast<int>(DEFAULT_CONTROL_SCHEME));
|
||||
if (val == static_cast<int>(ControlScheme::CURSOR) || val == static_cast<int>(ControlScheme::OPQA) || val == static_cast<int>(ControlScheme::WASD))
|
||||
{
|
||||
if (val == static_cast<int>(ControlScheme::CURSOR) || val == static_cast<int>(ControlScheme::OPQA) || val == static_cast<int>(ControlScheme::WASD)) {
|
||||
options.keys = static_cast<ControlScheme>(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
options.keys = DEFAULT_CONTROL_SCHEME;
|
||||
}
|
||||
}},
|
||||
{"window.zoom", [](const std::string &v)
|
||||
{
|
||||
{"window.zoom", [](const std::string& v) {
|
||||
int val = safeStoi(v, DEFAULT_WINDOW_ZOOM);
|
||||
if (val > 0)
|
||||
{
|
||||
if (val > 0) {
|
||||
options.window.zoom = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
options.window.zoom = DEFAULT_WINDOW_ZOOM;
|
||||
}
|
||||
}},
|
||||
{"video.mode", [](const std::string &v)
|
||||
{
|
||||
{"video.mode", [](const std::string& v) {
|
||||
int val = safeStoi(v, 0);
|
||||
if (val == 0 || val == SDL_WINDOW_FULLSCREEN_DESKTOP)
|
||||
{
|
||||
if (val == 0 || val == SDL_WINDOW_FULLSCREEN_DESKTOP) {
|
||||
options.video.mode = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
options.video.mode = 0;
|
||||
}
|
||||
}},
|
||||
{"video.filter", [](const std::string &v)
|
||||
{
|
||||
{"video.filter", [](const std::string& v) {
|
||||
int val = safeStoi(v, static_cast<int>(DEFAULT_VIDEO_FILTER));
|
||||
if (val == static_cast<int>(ScreenFilter::NEAREST) || val == static_cast<int>(ScreenFilter::LINEAR))
|
||||
{
|
||||
if (val == static_cast<int>(ScreenFilter::NEAREST) || val == static_cast<int>(ScreenFilter::LINEAR)) {
|
||||
options.video.filter = static_cast<ScreenFilter>(val);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
options.video.filter = DEFAULT_VIDEO_FILTER;
|
||||
}
|
||||
}},
|
||||
{"video.shaders", [](const std::string &v)
|
||||
{ options.video.shaders = stringToBool(v); }},
|
||||
{"video.vertical_sync", [](const std::string &v)
|
||||
{ options.video.vertical_sync = stringToBool(v); }},
|
||||
{"video.integer_scale", [](const std::string &v)
|
||||
{ options.video.integer_scale = stringToBool(v); }},
|
||||
{"video.keep_aspect", [](const std::string &v)
|
||||
{ options.video.keep_aspect = stringToBool(v); }},
|
||||
{"video.border.enabled", [](const std::string &v)
|
||||
{ options.video.border.enabled = stringToBool(v); }},
|
||||
{"video.border.width", [](const std::string &v)
|
||||
{
|
||||
{"video.shaders", [](const std::string& v) { options.video.shaders = stringToBool(v); }},
|
||||
{"video.vertical_sync", [](const std::string& v) { options.video.vertical_sync = stringToBool(v); }},
|
||||
{"video.integer_scale", [](const std::string& v) { options.video.integer_scale = stringToBool(v); }},
|
||||
{"video.keep_aspect", [](const std::string& v) { options.video.keep_aspect = stringToBool(v); }},
|
||||
{"video.border.enabled", [](const std::string& v) { options.video.border.enabled = stringToBool(v); }},
|
||||
{"video.border.width", [](const std::string& v) {
|
||||
int val = safeStoi(v, DEFAULT_BORDER_WIDTH);
|
||||
if (val > 0)
|
||||
{
|
||||
if (val > 0) {
|
||||
options.video.border.width = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
options.video.border.width = DEFAULT_BORDER_WIDTH;
|
||||
}
|
||||
}},
|
||||
{"video.border.height", [](const std::string &v)
|
||||
{
|
||||
{"video.border.height", [](const std::string& v) {
|
||||
int val = safeStoi(v, DEFAULT_BORDER_HEIGHT);
|
||||
if (val > 0)
|
||||
{
|
||||
if (val > 0) {
|
||||
options.video.border.height = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
options.video.border.height = DEFAULT_BORDER_HEIGHT;
|
||||
}
|
||||
}},
|
||||
{"video.palette", [](const std::string &v)
|
||||
{
|
||||
{"video.palette", [](const std::string& v) {
|
||||
options.video.palette = v;
|
||||
}}};
|
||||
|
||||
auto it = optionHandlers.find(var);
|
||||
if (it != optionHandlers.end())
|
||||
{
|
||||
if (it != optionHandlers.end()) {
|
||||
it->second(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint32
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint32
|
||||
|
||||
#include <algorithm>
|
||||
#include <string> // Para string, basic_string
|
||||
|
||||
#include "screen.h" // Para ScreenFilter
|
||||
#include "utils.h" // Para Color, Palette
|
||||
#include <algorithm>
|
||||
|
||||
// Secciones del programa
|
||||
enum class Section
|
||||
{
|
||||
enum class Section {
|
||||
LOGO,
|
||||
LOADING_SCREEN,
|
||||
TITLE,
|
||||
@@ -22,8 +23,7 @@ enum class Section
|
||||
};
|
||||
|
||||
// Subsecciones
|
||||
enum class Subsection
|
||||
{
|
||||
enum class Subsection {
|
||||
NONE,
|
||||
LOGO_TO_INTRO,
|
||||
LOGO_TO_TITLE,
|
||||
@@ -32,8 +32,7 @@ enum class Subsection
|
||||
};
|
||||
|
||||
// Posiciones de las notificaciones
|
||||
enum class NotificationPosition
|
||||
{
|
||||
enum class NotificationPosition {
|
||||
UPPER_LEFT,
|
||||
UPPER_CENTER,
|
||||
UPPER_RIGHT,
|
||||
@@ -49,8 +48,7 @@ enum class NotificationPosition
|
||||
};
|
||||
|
||||
// Tipos de control de teclado
|
||||
enum class ControlScheme
|
||||
{
|
||||
enum class ControlScheme {
|
||||
CURSOR,
|
||||
OPQA,
|
||||
WASD
|
||||
@@ -75,7 +73,7 @@ constexpr int DEFAULT_MUSIC_VOLUME = 80;
|
||||
constexpr bool DEFAULT_MUSIC_ENABLED = true; // Musica habilitada por defecto
|
||||
constexpr int DEFAULT_AUDIO_VOLUME = 100; // Volumen por defecto
|
||||
constexpr bool DEFAULT_AUDIO_ENABLED = true; // Audio por defecto
|
||||
constexpr const char *DEFAULT_PALETTE = "zx-spectrum"; // Paleta por defecto
|
||||
constexpr const char* DEFAULT_PALETTE = "zx-spectrum"; // Paleta por defecto
|
||||
constexpr Section DEFAULT_SECTION = Section::LOGO; // Sección por defecto
|
||||
constexpr Subsection DEFAULT_SUBSECTION = Subsection::LOGO_TO_INTRO; // Subsección por defecto
|
||||
constexpr ControlScheme DEFAULT_CONTROL_SCHEME = ControlScheme::CURSOR; // Control por defecto
|
||||
@@ -83,11 +81,10 @@ constexpr NotificationPosition DEFAULT_NOTIFICATION_POSITION = NotificationPosit
|
||||
constexpr bool DEFAULT_NOTIFICATION_SOUND = true; // Sonido de las notificaciones por defecto
|
||||
const Uint8 DEFAULT_NOTIFICATION_COLOR = static_cast<Uint8>(PaletteColor::BLUE); // Color de las notificaciones por defecto
|
||||
constexpr bool DEFAULT_CONSOLE = false; // Consola desactivada por defecto
|
||||
constexpr const char *DEFAULT_VERSION = "1.10"; // Versión por defecto
|
||||
constexpr const char* DEFAULT_VERSION = "1.10"; // Versión por defecto
|
||||
|
||||
// Estructura para las opciones de las notificaciones
|
||||
struct OptionsNotification
|
||||
{
|
||||
struct OptionsNotification {
|
||||
NotificationPosition pos; // Ubicación de las notificaciones en pantalla
|
||||
bool sound; // Indica si las notificaciones suenan
|
||||
Uint8 color; // Color de las notificaciones
|
||||
@@ -105,10 +102,8 @@ struct OptionsNotification
|
||||
color(c) {}
|
||||
|
||||
// Método que devuelve la posición horizontal
|
||||
NotificationPosition getHorizontalPosition() const
|
||||
{
|
||||
switch (pos)
|
||||
{
|
||||
NotificationPosition getHorizontalPosition() const {
|
||||
switch (pos) {
|
||||
case NotificationPosition::UPPER_LEFT:
|
||||
case NotificationPosition::BOTTOM_LEFT:
|
||||
return NotificationPosition::LEFT;
|
||||
@@ -125,10 +120,8 @@ struct OptionsNotification
|
||||
}
|
||||
|
||||
// Método que devuelve la posición vertical
|
||||
NotificationPosition getVerticalPosition() const
|
||||
{
|
||||
switch (pos)
|
||||
{
|
||||
NotificationPosition getVerticalPosition() const {
|
||||
switch (pos) {
|
||||
case NotificationPosition::UPPER_LEFT:
|
||||
case NotificationPosition::UPPER_CENTER:
|
||||
case NotificationPosition::UPPER_RIGHT:
|
||||
@@ -145,8 +138,7 @@ struct OptionsNotification
|
||||
};
|
||||
|
||||
// Estructura para saber la seccion y subseccion del programa
|
||||
struct SectionState
|
||||
{
|
||||
struct SectionState {
|
||||
Section section;
|
||||
Subsection subsection;
|
||||
|
||||
@@ -162,10 +154,8 @@ struct SectionState
|
||||
};
|
||||
|
||||
// Estructura para albergar trucos
|
||||
struct Cheat
|
||||
{
|
||||
enum class CheatState : bool
|
||||
{
|
||||
struct Cheat {
|
||||
enum class CheatState : bool {
|
||||
DISABLED = false,
|
||||
ENABLED = true
|
||||
};
|
||||
@@ -190,8 +180,7 @@ struct Cheat
|
||||
alternate_skin(as) {}
|
||||
|
||||
// Método para comprobar si alguno de los tres primeros trucos está activo
|
||||
bool enabled() const
|
||||
{
|
||||
bool enabled() const {
|
||||
return infinite_lives == CheatState::ENABLED ||
|
||||
invincible == CheatState::ENABLED ||
|
||||
jail_is_open == CheatState::ENABLED;
|
||||
@@ -199,8 +188,7 @@ struct Cheat
|
||||
};
|
||||
|
||||
// Estructura para almacenar estadísticas
|
||||
struct OptionsStats
|
||||
{
|
||||
struct OptionsStats {
|
||||
int rooms; // Cantidad de habitaciones visitadas
|
||||
int items; // Cantidad de items obtenidos
|
||||
std::string worst_nightmare; // Habitación con más muertes acumuladas
|
||||
@@ -219,8 +207,7 @@ struct OptionsStats
|
||||
};
|
||||
|
||||
// Estructura con opciones de la ventana
|
||||
struct OptionsWindow
|
||||
{
|
||||
struct OptionsWindow {
|
||||
int zoom; // Zoom de la ventana
|
||||
int max_zoom; // Máximo tamaño de zoom para la ventana
|
||||
|
||||
@@ -236,8 +223,7 @@ struct OptionsWindow
|
||||
};
|
||||
|
||||
// Estructura para gestionar el borde de la pantalla
|
||||
struct Border
|
||||
{
|
||||
struct Border {
|
||||
bool enabled; // Indica si se ha de mostrar el borde
|
||||
int width; // Ancho del borde
|
||||
int height; // Alto del borde
|
||||
@@ -256,8 +242,7 @@ struct Border
|
||||
};
|
||||
|
||||
// Estructura para las opciones de video
|
||||
struct OptionsVideo
|
||||
{
|
||||
struct OptionsVideo {
|
||||
Uint32 mode; // Contiene el valor del modo de pantalla completa
|
||||
ScreenFilter filter; // Filtro usado para el escalado de la imagen
|
||||
bool vertical_sync; // Indica si se quiere usar vsync o no
|
||||
@@ -279,7 +264,7 @@ struct OptionsVideo
|
||||
palette(DEFAULT_PALETTE) {}
|
||||
|
||||
// Constructor
|
||||
OptionsVideo(Uint32 m, ScreenFilter f, bool vs, bool s, bool is, bool ka, Border b, const std::string &p)
|
||||
OptionsVideo(Uint32 m, ScreenFilter f, bool vs, bool s, bool is, bool ka, Border b, const std::string& p)
|
||||
: mode(m),
|
||||
filter(f),
|
||||
vertical_sync(vs),
|
||||
@@ -291,8 +276,7 @@ struct OptionsVideo
|
||||
};
|
||||
|
||||
// Estructura para las opciones de musica
|
||||
struct OptionsMusic
|
||||
{
|
||||
struct OptionsMusic {
|
||||
bool enabled; // Indica si la música suena o no
|
||||
int volume; // Volumen al que suena la música (0 a 128 internamente)
|
||||
|
||||
@@ -307,22 +291,19 @@ struct OptionsMusic
|
||||
volume(convertVolume(v)) {} // Convierte el volumen usando el método estático
|
||||
|
||||
// Método para establecer el volumen
|
||||
void setVolume(int v)
|
||||
{
|
||||
void setVolume(int v) {
|
||||
v = std::clamp(v, 0, 100); // Ajusta v al rango [0, 100]
|
||||
volume = convertVolume(v); // Convierte al rango interno
|
||||
}
|
||||
|
||||
// Método estático para convertir de 0-100 a 0-128
|
||||
static int convertVolume(int v)
|
||||
{
|
||||
static int convertVolume(int v) {
|
||||
return (v * 128) / 100;
|
||||
}
|
||||
};
|
||||
|
||||
// Estructura para las opciones de sonido
|
||||
struct OptionsSound
|
||||
{
|
||||
struct OptionsSound {
|
||||
bool enabled; // Indica si los sonidos suenan o no
|
||||
int volume; // Volumen al que suenan los sonidos (0 a 128 internamente)
|
||||
|
||||
@@ -337,22 +318,19 @@ struct OptionsSound
|
||||
volume(convertVolume(v)) {} // También lo integra aquí
|
||||
|
||||
// Método para establecer el volumen
|
||||
void setVolume(int v)
|
||||
{
|
||||
void setVolume(int v) {
|
||||
v = std::clamp(v, 0, 100); // Ajusta v al rango [0, 100]
|
||||
volume = convertVolume(v); // Convierte al rango interno
|
||||
}
|
||||
|
||||
// Método estático para convertir de 0-100 a 0-128
|
||||
static int convertVolume(int v)
|
||||
{
|
||||
static int convertVolume(int v) {
|
||||
return (v * 128) / 100;
|
||||
}
|
||||
};
|
||||
|
||||
// Estructura para las opciones de audio
|
||||
struct OptionsAudio
|
||||
{
|
||||
struct OptionsAudio {
|
||||
OptionsMusic music; // Opciones para la música
|
||||
OptionsSound sound; // Opciones para los efectos de sonido
|
||||
bool enabled; // Indica si el audio está activo o no
|
||||
@@ -374,8 +352,7 @@ struct OptionsAudio
|
||||
};
|
||||
|
||||
// Estructura para las opciones de juego
|
||||
struct OptionsGame
|
||||
{
|
||||
struct OptionsGame {
|
||||
int width; // Ancho de la resolucion del juego
|
||||
int height; // Alto de la resolucion del juego
|
||||
|
||||
@@ -391,8 +368,7 @@ struct OptionsGame
|
||||
};
|
||||
|
||||
// Estructura con todas las opciones de configuración del programa
|
||||
struct Options
|
||||
{
|
||||
struct Options {
|
||||
std::string version; // Versión del fichero de configuración. Sirve para saber si las opciones son compatibles
|
||||
bool console; // Indica si ha de mostrar información por la consola de texto
|
||||
Cheat cheats; // Contiene trucos y ventajas para el juego
|
||||
@@ -440,7 +416,7 @@ extern Options options;
|
||||
void initOptions();
|
||||
|
||||
// Carga las opciones desde un fichero
|
||||
bool loadOptionsFromFile(const std::string &file_path);
|
||||
bool loadOptionsFromFile(const std::string& file_path);
|
||||
|
||||
// Guarda las opciones a un fichero
|
||||
bool saveOptionsToFile(const std::string &file_path);
|
||||
bool saveOptionsToFile(const std::string& file_path);
|
||||
@@ -1,26 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect, SDL_Point
|
||||
#include <SDL2/SDL_render.h> // Para SDL_RendererFlip, SDL_FLIP_NONE
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint8
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect, SDL_Point
|
||||
#include <SDL3/SDL_render.h> // Para SDL_RendererFlip, SDL_FLIP_NONE
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint8
|
||||
|
||||
#include <memory> // Para shared_ptr, __shared_ptr_access
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "defines.h" // Para BORDER_TOP, BLOCK
|
||||
#include "room.h"
|
||||
#include "s_animated_sprite.h" // Para SAnimatedSprite
|
||||
#include "utils.h" // Para Color
|
||||
#include "room.h"
|
||||
struct JA_Sound_t; // lines 13-13
|
||||
|
||||
enum class PlayerState
|
||||
{
|
||||
enum class PlayerState {
|
||||
STANDING,
|
||||
JUMPING,
|
||||
FALLING,
|
||||
};
|
||||
|
||||
struct PlayerSpawn
|
||||
{
|
||||
struct PlayerSpawn {
|
||||
float x;
|
||||
float y;
|
||||
float vx;
|
||||
@@ -30,15 +30,27 @@ struct PlayerSpawn
|
||||
SDL_RendererFlip flip;
|
||||
|
||||
// Constructor por defecto
|
||||
PlayerSpawn() : x(0), y(0), vx(0), vy(0), jump_init_pos(0), state(PlayerState::STANDING), flip(SDL_FLIP_NONE) {}
|
||||
PlayerSpawn()
|
||||
: x(0),
|
||||
y(0),
|
||||
vx(0),
|
||||
vy(0),
|
||||
jump_init_pos(0),
|
||||
state(PlayerState::STANDING),
|
||||
flip(SDL_FLIP_NONE) {}
|
||||
|
||||
// Constructor
|
||||
PlayerSpawn(float x, float y, float vx, float vy, int jump_init_pos, PlayerState state, SDL_RendererFlip flip)
|
||||
: x(x), y(y), vx(vx), vy(vy), jump_init_pos(jump_init_pos), state(state), flip(flip) {}
|
||||
: x(x),
|
||||
y(y),
|
||||
vx(vx),
|
||||
vy(vy),
|
||||
jump_init_pos(jump_init_pos),
|
||||
state(state),
|
||||
flip(flip) {}
|
||||
};
|
||||
|
||||
struct PlayerData
|
||||
{
|
||||
struct PlayerData {
|
||||
PlayerSpawn spawn;
|
||||
std::string texture_path;
|
||||
std::string animations_path;
|
||||
@@ -46,12 +58,14 @@ struct PlayerData
|
||||
|
||||
// Constructor
|
||||
PlayerData(PlayerSpawn spawn, std::string texture_path, std::string animations_path, std::shared_ptr<Room> room)
|
||||
: spawn(spawn), texture_path(texture_path), animations_path(animations_path), room(room) {}
|
||||
: spawn(spawn),
|
||||
texture_path(texture_path),
|
||||
animations_path(animations_path),
|
||||
room(room) {}
|
||||
};
|
||||
|
||||
class Player
|
||||
{
|
||||
public:
|
||||
class Player {
|
||||
public:
|
||||
// Constantes
|
||||
static constexpr int WIDTH_ = 8; // Ancho del jugador
|
||||
static constexpr int HEIGHT_ = 16; // ALto del jugador
|
||||
@@ -81,8 +95,8 @@ public:
|
||||
RoomBorder border_ = RoomBorder::TOP; // Indica en cual de los cuatro bordes se encuentra
|
||||
SDL_Rect last_position_; // Contiene la ultima posición del jugador, por si hay que deshacer algun movimiento
|
||||
int jump_init_pos_; // Valor del eje Y en el que se inicia el salto
|
||||
std::vector<JA_Sound_t *> jumping_sound_; // Vecor con todos los sonidos del salto
|
||||
std::vector<JA_Sound_t *> falling_sound_; // Vecor con todos los sonidos de la caída
|
||||
std::vector<JA_Sound_t*> jumping_sound_; // Vecor con todos los sonidos del salto
|
||||
std::vector<JA_Sound_t*> falling_sound_; // Vecor con todos los sonidos de la caída
|
||||
int jumping_counter_ = 0; // Cuenta el tiempo de salto
|
||||
int falling_counter_ = 0; // Cuenta el tiempo de caida
|
||||
|
||||
@@ -148,19 +162,19 @@ public:
|
||||
void placeSprite() { sprite_->setPos(x_, y_); }
|
||||
|
||||
// Aplica los valores de spawn al jugador
|
||||
void applySpawnValues(const PlayerSpawn &spawn);
|
||||
void applySpawnValues(const PlayerSpawn& spawn);
|
||||
|
||||
// Inicializa el sprite del jugador
|
||||
void initSprite(const std::string &texture_path, const std::string &animations_path);
|
||||
void initSprite(const std::string& texture_path, const std::string& animations_path);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Pinta la información de debug del jugador
|
||||
void renderDebugInfo();
|
||||
#endif
|
||||
|
||||
public:
|
||||
public:
|
||||
// Constructor
|
||||
explicit Player(const PlayerData &player);
|
||||
explicit Player(const PlayerData& player);
|
||||
|
||||
// Destructor
|
||||
~Player() = default;
|
||||
@@ -184,7 +198,7 @@ public:
|
||||
SDL_Rect getRect() { return {static_cast<int>(x_), static_cast<int>(y_), WIDTH_, HEIGHT_}; }
|
||||
|
||||
// Obtiene el rectangulo de colision del jugador
|
||||
SDL_Rect &getCollider() { return collider_box_; }
|
||||
SDL_Rect& getCollider() { return collider_box_; }
|
||||
|
||||
// Obtiene el estado de reaparición del jugador
|
||||
PlayerSpawn getSpawnParams() { return {x_, y_, vx_, vy_, jump_init_pos_, state_, sprite_->getFlip()}; }
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#include "resource.h"
|
||||
#include <SDL2/SDL_events.h> // Para SDL_PollEvent, SDL_Event, SDL_KEYDOWN
|
||||
#include <SDL2/SDL_keycode.h> // Para SDLK_ESCAPE
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint8
|
||||
|
||||
#include <SDL3/SDL_events.h> // Para SDL_PollEvent, SDL_Event, SDL_KEYDOWN
|
||||
#include <SDL3/SDL_keycode.h> // Para SDLK_ESCAPE
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint8
|
||||
#include <stdlib.h> // Para exit, size_t
|
||||
|
||||
#include <algorithm> // Para find_if
|
||||
#include <iostream> // Para basic_ostream, operator<<, endl, cout
|
||||
#include <stdexcept> // Para runtime_error
|
||||
|
||||
#include "asset.h" // Para AssetType, Asset
|
||||
#include "jail_audio.h" // Para JA_DeleteMusic, JA_DeleteSound, JA_Loa...
|
||||
#include "options.h" // Para Options, OptionsGame, options
|
||||
@@ -18,7 +21,7 @@ struct JA_Music_t; // lines 17-17
|
||||
struct JA_Sound_t; // lines 18-18
|
||||
|
||||
// [SINGLETON] Hay que definir las variables estáticas, desde el .h sólo la hemos declarado
|
||||
Resource *Resource::resource_ = nullptr;
|
||||
Resource* Resource::resource_ = nullptr;
|
||||
|
||||
// [SINGLETON] Crearemos el objeto screen con esta función estática
|
||||
void Resource::init() { Resource::resource_ = new Resource(); }
|
||||
@@ -27,14 +30,13 @@ void Resource::init() { Resource::resource_ = new Resource(); }
|
||||
void Resource::destroy() { delete Resource::resource_; }
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto screen y podemos trabajar con él
|
||||
Resource *Resource::get() { return Resource::resource_; }
|
||||
Resource* Resource::get() { return Resource::resource_; }
|
||||
|
||||
// Constructor
|
||||
Resource::Resource() { load(); }
|
||||
|
||||
// Vacia todos los vectores de recursos
|
||||
void Resource::clear()
|
||||
{
|
||||
void Resource::clear() {
|
||||
clearSounds();
|
||||
clearMusics();
|
||||
surfaces_.clear();
|
||||
@@ -45,8 +47,7 @@ void Resource::clear()
|
||||
}
|
||||
|
||||
// Carga todos los recursos
|
||||
void Resource::load()
|
||||
{
|
||||
void Resource::load() {
|
||||
calculateTotal();
|
||||
Screen::get()->show();
|
||||
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
@@ -64,20 +65,16 @@ void Resource::load()
|
||||
}
|
||||
|
||||
// Recarga todos los recursos
|
||||
void Resource::reload()
|
||||
{
|
||||
void Resource::reload() {
|
||||
clear();
|
||||
load();
|
||||
}
|
||||
|
||||
// Obtiene el sonido a partir de un nombre
|
||||
JA_Sound_t *Resource::getSound(const std::string &name)
|
||||
{
|
||||
auto it = std::find_if(sounds_.begin(), sounds_.end(), [&name](const auto &s)
|
||||
{ return s.name == name; });
|
||||
JA_Sound_t* Resource::getSound(const std::string& name) {
|
||||
auto it = std::find_if(sounds_.begin(), sounds_.end(), [&name](const auto& s) { return s.name == name; });
|
||||
|
||||
if (it != sounds_.end())
|
||||
{
|
||||
if (it != sounds_.end()) {
|
||||
return it->sound;
|
||||
}
|
||||
|
||||
@@ -86,13 +83,10 @@ JA_Sound_t *Resource::getSound(const std::string &name)
|
||||
}
|
||||
|
||||
// Obtiene la música a partir de un nombre
|
||||
JA_Music_t *Resource::getMusic(const std::string &name)
|
||||
{
|
||||
auto it = std::find_if(musics_.begin(), musics_.end(), [&name](const auto &m)
|
||||
{ return m.name == name; });
|
||||
JA_Music_t* Resource::getMusic(const std::string& name) {
|
||||
auto it = std::find_if(musics_.begin(), musics_.end(), [&name](const auto& m) { return m.name == name; });
|
||||
|
||||
if (it != musics_.end())
|
||||
{
|
||||
if (it != musics_.end()) {
|
||||
return it->music;
|
||||
}
|
||||
|
||||
@@ -101,13 +95,10 @@ JA_Music_t *Resource::getMusic(const std::string &name)
|
||||
}
|
||||
|
||||
// Obtiene la surface a partir de un nombre
|
||||
std::shared_ptr<Surface> Resource::getSurface(const std::string &name)
|
||||
{
|
||||
auto it = std::find_if(surfaces_.begin(), surfaces_.end(), [&name](const auto &t)
|
||||
{ return t.name == name; });
|
||||
std::shared_ptr<Surface> Resource::getSurface(const std::string& name) {
|
||||
auto it = std::find_if(surfaces_.begin(), surfaces_.end(), [&name](const auto& t) { return t.name == name; });
|
||||
|
||||
if (it != surfaces_.end())
|
||||
{
|
||||
if (it != surfaces_.end()) {
|
||||
return it->surface;
|
||||
}
|
||||
|
||||
@@ -116,13 +107,10 @@ std::shared_ptr<Surface> Resource::getSurface(const std::string &name)
|
||||
}
|
||||
|
||||
// Obtiene la paleta a partir de un nombre
|
||||
Palette Resource::getPalette(const std::string &name)
|
||||
{
|
||||
auto it = std::find_if(palettes_.begin(), palettes_.end(), [&name](const auto &t)
|
||||
{ return t.name == name; });
|
||||
Palette Resource::getPalette(const std::string& name) {
|
||||
auto it = std::find_if(palettes_.begin(), palettes_.end(), [&name](const auto& t) { return t.name == name; });
|
||||
|
||||
if (it != palettes_.end())
|
||||
{
|
||||
if (it != palettes_.end()) {
|
||||
return it->palette;
|
||||
}
|
||||
|
||||
@@ -131,13 +119,10 @@ Palette Resource::getPalette(const std::string &name)
|
||||
}
|
||||
|
||||
// Obtiene el fichero de texto a partir de un nombre
|
||||
std::shared_ptr<TextFile> Resource::getTextFile(const std::string &name)
|
||||
{
|
||||
auto it = std::find_if(text_files_.begin(), text_files_.end(), [&name](const auto &t)
|
||||
{ return t.name == name; });
|
||||
std::shared_ptr<TextFile> Resource::getTextFile(const std::string& name) {
|
||||
auto it = std::find_if(text_files_.begin(), text_files_.end(), [&name](const auto& t) { return t.name == name; });
|
||||
|
||||
if (it != text_files_.end())
|
||||
{
|
||||
if (it != text_files_.end()) {
|
||||
return it->text_file;
|
||||
}
|
||||
|
||||
@@ -146,13 +131,10 @@ std::shared_ptr<TextFile> Resource::getTextFile(const std::string &name)
|
||||
}
|
||||
|
||||
// Obtiene el objeto de texto a partir de un nombre
|
||||
std::shared_ptr<Text> Resource::getText(const std::string &name)
|
||||
{
|
||||
auto it = std::find_if(texts_.begin(), texts_.end(), [&name](const auto &t)
|
||||
{ return t.name == name; });
|
||||
std::shared_ptr<Text> Resource::getText(const std::string& name) {
|
||||
auto it = std::find_if(texts_.begin(), texts_.end(), [&name](const auto& t) { return t.name == name; });
|
||||
|
||||
if (it != texts_.end())
|
||||
{
|
||||
if (it != texts_.end()) {
|
||||
return it->text;
|
||||
}
|
||||
|
||||
@@ -161,13 +143,10 @@ std::shared_ptr<Text> Resource::getText(const std::string &name)
|
||||
}
|
||||
|
||||
// Obtiene la animación a partir de un nombre
|
||||
Animations &Resource::getAnimations(const std::string &name)
|
||||
{
|
||||
auto it = std::find_if(animations_.begin(), animations_.end(), [&name](const auto &a)
|
||||
{ return a.name == name; });
|
||||
Animations& Resource::getAnimations(const std::string& name) {
|
||||
auto it = std::find_if(animations_.begin(), animations_.end(), [&name](const auto& a) { return a.name == name; });
|
||||
|
||||
if (it != animations_.end())
|
||||
{
|
||||
if (it != animations_.end()) {
|
||||
return it->animation;
|
||||
}
|
||||
|
||||
@@ -176,13 +155,10 @@ Animations &Resource::getAnimations(const std::string &name)
|
||||
}
|
||||
|
||||
// Obtiene el mapa de tiles a partir de un nombre
|
||||
std::vector<int> &Resource::getTileMap(const std::string &name)
|
||||
{
|
||||
auto it = std::find_if(tile_maps_.begin(), tile_maps_.end(), [&name](const auto &t)
|
||||
{ return t.name == name; });
|
||||
std::vector<int>& Resource::getTileMap(const std::string& name) {
|
||||
auto it = std::find_if(tile_maps_.begin(), tile_maps_.end(), [&name](const auto& t) { return t.name == name; });
|
||||
|
||||
if (it != tile_maps_.end())
|
||||
{
|
||||
if (it != tile_maps_.end()) {
|
||||
return it->tileMap;
|
||||
}
|
||||
|
||||
@@ -191,13 +167,10 @@ std::vector<int> &Resource::getTileMap(const std::string &name)
|
||||
}
|
||||
|
||||
// Obtiene la habitación a partir de un nombre
|
||||
std::shared_ptr<RoomData> Resource::getRoom(const std::string &name)
|
||||
{
|
||||
auto it = std::find_if(rooms_.begin(), rooms_.end(), [&name](const auto &r)
|
||||
{ return r.name == name; });
|
||||
std::shared_ptr<RoomData> Resource::getRoom(const std::string& name) {
|
||||
auto it = std::find_if(rooms_.begin(), rooms_.end(), [&name](const auto& r) { return r.name == name; });
|
||||
|
||||
if (it != rooms_.end())
|
||||
{
|
||||
if (it != rooms_.end()) {
|
||||
return it->room;
|
||||
}
|
||||
|
||||
@@ -206,20 +179,17 @@ std::shared_ptr<RoomData> Resource::getRoom(const std::string &name)
|
||||
}
|
||||
|
||||
// Obtiene todas las habitaciones
|
||||
std::vector<ResourceRoom> &Resource::getRooms()
|
||||
{
|
||||
std::vector<ResourceRoom>& Resource::getRooms() {
|
||||
return rooms_;
|
||||
}
|
||||
|
||||
// Carga los sonidos
|
||||
void Resource::loadSounds()
|
||||
{
|
||||
void Resource::loadSounds() {
|
||||
std::cout << "\n>> SOUND FILES" << std::endl;
|
||||
auto list = Asset::get()->getListByType(AssetType::SOUND);
|
||||
sounds_.clear();
|
||||
|
||||
for (const auto &l : list)
|
||||
{
|
||||
for (const auto& l : list) {
|
||||
auto name = getFileName(l);
|
||||
sounds_.emplace_back(ResourceSound(name, JA_LoadSound(l.c_str())));
|
||||
printWithDots("Sound : ", name, "[ LOADED ]");
|
||||
@@ -228,14 +198,12 @@ void Resource::loadSounds()
|
||||
}
|
||||
|
||||
// Carga las musicas
|
||||
void Resource::loadMusics()
|
||||
{
|
||||
void Resource::loadMusics() {
|
||||
std::cout << "\n>> MUSIC FILES" << std::endl;
|
||||
auto list = Asset::get()->getListByType(AssetType::MUSIC);
|
||||
musics_.clear();
|
||||
|
||||
for (const auto &l : list)
|
||||
{
|
||||
for (const auto& l : list) {
|
||||
auto name = getFileName(l);
|
||||
musics_.emplace_back(ResourceMusic(name, JA_LoadMusic(l.c_str())));
|
||||
printWithDots("Music : ", name, "[ LOADED ]");
|
||||
@@ -244,14 +212,12 @@ void Resource::loadMusics()
|
||||
}
|
||||
|
||||
// Carga las texturas
|
||||
void Resource::loadSurfaces()
|
||||
{
|
||||
void Resource::loadSurfaces() {
|
||||
std::cout << "\n>> SURFACES" << std::endl;
|
||||
auto list = Asset::get()->getListByType(AssetType::BITMAP);
|
||||
surfaces_.clear();
|
||||
|
||||
for (const auto &l : list)
|
||||
{
|
||||
for (const auto& l : list) {
|
||||
auto name = getFileName(l);
|
||||
surfaces_.emplace_back(ResourceSurface(name, std::make_shared<Surface>(l)));
|
||||
surfaces_.back().surface->setTransparentColor(0);
|
||||
@@ -269,14 +235,12 @@ void Resource::loadSurfaces()
|
||||
}
|
||||
|
||||
// Carga las paletas
|
||||
void Resource::loadPalettes()
|
||||
{
|
||||
void Resource::loadPalettes() {
|
||||
std::cout << "\n>> PALETTES" << std::endl;
|
||||
auto list = Asset::get()->getListByType(AssetType::PALETTE);
|
||||
palettes_.clear();
|
||||
|
||||
for (const auto &l : list)
|
||||
{
|
||||
for (const auto& l : list) {
|
||||
auto name = getFileName(l);
|
||||
palettes_.emplace_back(ResourcePalette(name, readPalFile(l)));
|
||||
updateLoadingProgress();
|
||||
@@ -284,14 +248,12 @@ void Resource::loadPalettes()
|
||||
}
|
||||
|
||||
// Carga los ficheros de texto
|
||||
void Resource::loadTextFiles()
|
||||
{
|
||||
void Resource::loadTextFiles() {
|
||||
std::cout << "\n>> TEXT FILES" << std::endl;
|
||||
auto list = Asset::get()->getListByType(AssetType::FONT);
|
||||
text_files_.clear();
|
||||
|
||||
for (const auto &l : list)
|
||||
{
|
||||
for (const auto& l : list) {
|
||||
auto name = getFileName(l);
|
||||
text_files_.emplace_back(ResourceTextFile(name, loadTextFile(l)));
|
||||
updateLoadingProgress();
|
||||
@@ -299,14 +261,12 @@ void Resource::loadTextFiles()
|
||||
}
|
||||
|
||||
// Carga las animaciones
|
||||
void Resource::loadAnimations()
|
||||
{
|
||||
void Resource::loadAnimations() {
|
||||
std::cout << "\n>> ANIMATIONS" << std::endl;
|
||||
auto list = Asset::get()->getListByType(AssetType::ANIMATION);
|
||||
animations_.clear();
|
||||
|
||||
for (const auto &l : list)
|
||||
{
|
||||
for (const auto& l : list) {
|
||||
auto name = getFileName(l);
|
||||
animations_.emplace_back(ResourceAnimation(name, loadAnimationsFromFile(l)));
|
||||
updateLoadingProgress();
|
||||
@@ -314,14 +274,12 @@ void Resource::loadAnimations()
|
||||
}
|
||||
|
||||
// Carga los mapas de tiles
|
||||
void Resource::loadTileMaps()
|
||||
{
|
||||
void Resource::loadTileMaps() {
|
||||
std::cout << "\n>> TILE MAPS" << std::endl;
|
||||
auto list = Asset::get()->getListByType(AssetType::TILEMAP);
|
||||
tile_maps_.clear();
|
||||
|
||||
for (const auto &l : list)
|
||||
{
|
||||
for (const auto& l : list) {
|
||||
auto name = getFileName(l);
|
||||
tile_maps_.emplace_back(ResourceTileMap(name, loadRoomTileFile(l)));
|
||||
printWithDots("TileMap : ", name, "[ LOADED ]");
|
||||
@@ -330,14 +288,12 @@ void Resource::loadTileMaps()
|
||||
}
|
||||
|
||||
// Carga las habitaciones
|
||||
void Resource::loadRooms()
|
||||
{
|
||||
void Resource::loadRooms() {
|
||||
std::cout << "\n>> ROOMS" << std::endl;
|
||||
auto list = Asset::get()->getListByType(AssetType::ROOM);
|
||||
rooms_.clear();
|
||||
|
||||
for (const auto &l : list)
|
||||
{
|
||||
for (const auto& l : list) {
|
||||
auto name = getFileName(l);
|
||||
rooms_.emplace_back(ResourceRoom(name, std::make_shared<RoomData>(loadRoomFile(l))));
|
||||
printWithDots("Room : ", name, "[ LOADED ]");
|
||||
@@ -345,17 +301,17 @@ void Resource::loadRooms()
|
||||
}
|
||||
}
|
||||
|
||||
void Resource::createText()
|
||||
{
|
||||
struct ResourceInfo
|
||||
{
|
||||
void Resource::createText() {
|
||||
struct ResourceInfo {
|
||||
std::string key; // Identificador del recurso
|
||||
std::string textureFile; // Nombre del archivo de textura
|
||||
std::string textFile; // Nombre del archivo de texto
|
||||
|
||||
// Constructor para facilitar la creación de objetos ResourceInfo
|
||||
ResourceInfo(const std::string &k, const std::string &tFile, const std::string &txtFile)
|
||||
: key(k), textureFile(tFile), textFile(txtFile) {}
|
||||
ResourceInfo(const std::string& k, const std::string& tFile, const std::string& txtFile)
|
||||
: key(k),
|
||||
textureFile(tFile),
|
||||
textFile(txtFile) {}
|
||||
};
|
||||
|
||||
std::cout << "\n>> CREATING TEXT_OBJECTS" << std::endl;
|
||||
@@ -367,23 +323,17 @@ void Resource::createText()
|
||||
{"subatomic", "subatomic.gif", "subatomic.txt"},
|
||||
{"8bithud", "8bithud.gif", "8bithud.txt"}};
|
||||
|
||||
for (const auto &resource : resources)
|
||||
{
|
||||
texts_.emplace_back(ResourceText(resource.key, std::make_shared<Text>(
|
||||
getSurface(resource.textureFile),
|
||||
getTextFile(resource.textFile))));
|
||||
for (const auto& resource : resources) {
|
||||
texts_.emplace_back(ResourceText(resource.key, std::make_shared<Text>(getSurface(resource.textureFile), getTextFile(resource.textFile))));
|
||||
printWithDots("Text : ", resource.key, "[ DONE ]");
|
||||
}
|
||||
}
|
||||
|
||||
// Vacía el vector de sonidos
|
||||
void Resource::clearSounds()
|
||||
{
|
||||
void Resource::clearSounds() {
|
||||
// Itera sobre el vector y libera los recursos asociados a cada JA_Sound_t
|
||||
for (auto &sound : sounds_)
|
||||
{
|
||||
if (sound.sound)
|
||||
{
|
||||
for (auto& sound : sounds_) {
|
||||
if (sound.sound) {
|
||||
JA_DeleteSound(sound.sound);
|
||||
sound.sound = nullptr;
|
||||
}
|
||||
@@ -392,13 +342,10 @@ void Resource::clearSounds()
|
||||
}
|
||||
|
||||
// Vacía el vector de musicas
|
||||
void Resource::clearMusics()
|
||||
{
|
||||
void Resource::clearMusics() {
|
||||
// Itera sobre el vector y libera los recursos asociados a cada JA_Music_t
|
||||
for (auto &music : musics_)
|
||||
{
|
||||
if (music.music)
|
||||
{
|
||||
for (auto& music : musics_) {
|
||||
if (music.music) {
|
||||
JA_DeleteMusic(music.music);
|
||||
music.music = nullptr;
|
||||
}
|
||||
@@ -407,8 +354,7 @@ void Resource::clearMusics()
|
||||
}
|
||||
|
||||
// Calcula el numero de recursos para cargar
|
||||
void Resource::calculateTotal()
|
||||
{
|
||||
void Resource::calculateTotal() {
|
||||
std::vector<AssetType> assetTypes = {
|
||||
AssetType::SOUND,
|
||||
AssetType::MUSIC,
|
||||
@@ -420,8 +366,7 @@ void Resource::calculateTotal()
|
||||
AssetType::ROOM};
|
||||
|
||||
size_t total = 0;
|
||||
for (const auto &assetType : assetTypes)
|
||||
{
|
||||
for (const auto& assetType : assetTypes) {
|
||||
auto list = Asset::get()->getListByType(assetType);
|
||||
total += list.size();
|
||||
}
|
||||
@@ -430,8 +375,7 @@ void Resource::calculateTotal()
|
||||
}
|
||||
|
||||
// Muestra el progreso de carga
|
||||
void Resource::renderProgress()
|
||||
{
|
||||
void Resource::renderProgress() {
|
||||
constexpr int X_PADDING = 10;
|
||||
constexpr int Y_PADDING = 10;
|
||||
constexpr int BAR_HEIGHT = 10;
|
||||
@@ -452,19 +396,15 @@ void Resource::renderProgress()
|
||||
}
|
||||
|
||||
// Comprueba los eventos de la pantalla de carga
|
||||
void Resource::checkEvents()
|
||||
{
|
||||
void Resource::checkEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_QUIT:
|
||||
exit(0);
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
if (event.key.keysym.sym == SDLK_ESCAPE)
|
||||
{
|
||||
if (event.key.keysym.sym == SDLK_ESCAPE) {
|
||||
exit(0);
|
||||
}
|
||||
break;
|
||||
@@ -473,11 +413,9 @@ void Resource::checkEvents()
|
||||
}
|
||||
|
||||
// Actualiza el progreso de carga
|
||||
void Resource::updateLoadingProgress(int steps)
|
||||
{
|
||||
void Resource::updateLoadingProgress(int steps) {
|
||||
count_.add(1);
|
||||
if (count_.loaded % steps == 0 || count_.loaded == count_.total)
|
||||
{
|
||||
if (count_.loaded % steps == 0 || count_.loaded == count_.total) {
|
||||
renderProgress();
|
||||
}
|
||||
checkEvents();
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect, SDL_Point
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint8
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect, SDL_Point
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint8
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "enemy.h" // Para EnemyData
|
||||
#include "item.h" // Para ItemData
|
||||
#include "utils.h" // Para LineHorizontal, LineDiagonal, LineVertical
|
||||
@@ -12,8 +14,7 @@ class SSprite; // lines 12-12
|
||||
class Surface; // lines 13-13
|
||||
struct ScoreboardData; // lines 15-15
|
||||
|
||||
enum class TileType
|
||||
{
|
||||
enum class TileType {
|
||||
EMPTY,
|
||||
WALL,
|
||||
PASSABLE,
|
||||
@@ -23,23 +24,19 @@ enum class TileType
|
||||
ANIMATED
|
||||
};
|
||||
|
||||
enum class RoomBorder : int
|
||||
{
|
||||
enum class RoomBorder : int {
|
||||
TOP = 0,
|
||||
RIGHT = 1,
|
||||
BOTTOM = 2,
|
||||
LEFT = 3
|
||||
};
|
||||
|
||||
|
||||
struct AnimatedTile
|
||||
{
|
||||
struct AnimatedTile {
|
||||
std::shared_ptr<SSprite> sprite; // SSprite para dibujar el tile
|
||||
int x_orig; // Poicion X donde se encuentra el primer tile de la animacion en la tilesheet
|
||||
};
|
||||
|
||||
struct RoomData
|
||||
{
|
||||
struct RoomData {
|
||||
std::string number; // Numero de la habitación
|
||||
std::string name; // Nombre de la habitación
|
||||
std::string bg_color; // Color de fondo de la habitación
|
||||
@@ -59,23 +56,22 @@ struct RoomData
|
||||
};
|
||||
|
||||
// Carga las variables desde un fichero de mapa
|
||||
RoomData loadRoomFile(const std::string &file_path, bool verbose = false);
|
||||
RoomData loadRoomFile(const std::string& file_path, bool verbose = false);
|
||||
|
||||
// Carga las variables y texturas desde un fichero de mapa de tiles
|
||||
std::vector<int> loadRoomTileFile(const std::string &file_path, bool verbose = false);
|
||||
std::vector<int> loadRoomTileFile(const std::string& file_path, bool verbose = false);
|
||||
|
||||
// Asigna variables a una estructura RoomData
|
||||
bool setRoom(RoomData *room, const std::string &key, const std::string &value);
|
||||
bool setRoom(RoomData* room, const std::string& key, const std::string& value);
|
||||
|
||||
// Asigna variables a una estructura EnemyData
|
||||
bool setEnemy(EnemyData *enemy, const std::string &key, const std::string &value);
|
||||
bool setEnemy(EnemyData* enemy, const std::string& key, const std::string& value);
|
||||
|
||||
// Asigna variables a una estructura ItemData
|
||||
bool setItem(ItemData *item, const std::string &key, const std::string &value);
|
||||
bool setItem(ItemData* item, const std::string& key, const std::string& value);
|
||||
|
||||
class Room
|
||||
{
|
||||
private:
|
||||
class Room {
|
||||
private:
|
||||
// Constantes
|
||||
static constexpr int TILE_SIZE_ = 8; // Ancho del tile en pixels
|
||||
static constexpr int MAP_WIDTH_ = 32; // Ancho del mapa en tiles
|
||||
@@ -115,7 +111,7 @@ private:
|
||||
std::vector<LineHorizontal> conveyor_belt_floors_; // Lista con las superficies automaticas de la habitación
|
||||
int tile_set_width_; // Ancho del tileset en tiles
|
||||
|
||||
void initializeRoom(const RoomData &room);
|
||||
void initializeRoom(const RoomData& room);
|
||||
|
||||
// Pinta el mapa de la habitación en la textura
|
||||
void fillMapTexture();
|
||||
@@ -159,15 +155,15 @@ private:
|
||||
// Inicializa las superficies de colision
|
||||
void initRoomSurfaces();
|
||||
|
||||
public:
|
||||
public:
|
||||
// Constructor
|
||||
Room(const std::string &room_path, std::shared_ptr<ScoreboardData> data);
|
||||
Room(const std::string& room_path, std::shared_ptr<ScoreboardData> data);
|
||||
|
||||
// Destructor
|
||||
~Room() = default;
|
||||
|
||||
// Devuelve el nombre de la habitación
|
||||
const std::string &getName() const { return name_; }
|
||||
const std::string& getName() const { return name_; }
|
||||
|
||||
// Devuelve el color de la habitación
|
||||
Uint8 getBGColor() const { return stringToColor(bg_color_); }
|
||||
@@ -194,10 +190,10 @@ public:
|
||||
TileType getTile(SDL_Point point);
|
||||
|
||||
// Indica si hay colision con un enemigo a partir de un rectangulo
|
||||
bool enemyCollision(SDL_Rect &rect);
|
||||
bool enemyCollision(SDL_Rect& rect);
|
||||
|
||||
// Indica si hay colision con un objeto a partir de un rectangulo
|
||||
bool itemCollision(SDL_Rect &rect);
|
||||
bool itemCollision(SDL_Rect& rect);
|
||||
|
||||
// Obten el tamaño del tile
|
||||
int getTileSize() const { return TILE_SIZE_; }
|
||||
@@ -206,37 +202,37 @@ public:
|
||||
int getSlopeHeight(SDL_Point p, TileType slope);
|
||||
|
||||
// Comprueba las colisiones
|
||||
int checkRightSurfaces(SDL_Rect *rect);
|
||||
int checkRightSurfaces(SDL_Rect* rect);
|
||||
|
||||
// Comprueba las colisiones
|
||||
int checkLeftSurfaces(SDL_Rect *rect);
|
||||
int checkLeftSurfaces(SDL_Rect* rect);
|
||||
|
||||
// Comprueba las colisiones
|
||||
int checkTopSurfaces(SDL_Rect *rect);
|
||||
int checkTopSurfaces(SDL_Rect* rect);
|
||||
|
||||
// Comprueba las colisiones
|
||||
int checkBottomSurfaces(SDL_Rect *rect);
|
||||
int checkBottomSurfaces(SDL_Rect* rect);
|
||||
|
||||
// Comprueba las colisiones
|
||||
int checkAutoSurfaces(SDL_Rect *rect);
|
||||
int checkAutoSurfaces(SDL_Rect* rect);
|
||||
|
||||
// Comprueba las colisiones
|
||||
bool checkTopSurfaces(SDL_Point *p);
|
||||
bool checkTopSurfaces(SDL_Point* p);
|
||||
|
||||
// Comprueba las colisiones
|
||||
bool checkAutoSurfaces(SDL_Point *p);
|
||||
bool checkAutoSurfaces(SDL_Point* p);
|
||||
|
||||
// Comprueba las colisiones
|
||||
int checkLeftSlopes(const LineVertical *line);
|
||||
int checkLeftSlopes(const LineVertical* line);
|
||||
|
||||
// Comprueba las colisiones
|
||||
bool checkLeftSlopes(SDL_Point *p);
|
||||
bool checkLeftSlopes(SDL_Point* p);
|
||||
|
||||
// Comprueba las colisiones
|
||||
int checkRightSlopes(const LineVertical *line);
|
||||
int checkRightSlopes(const LineVertical* line);
|
||||
|
||||
// Comprueba las colisiones
|
||||
bool checkRightSlopes(SDL_Point *p);
|
||||
bool checkRightSlopes(SDL_Point* p);
|
||||
|
||||
// Pone el mapa en modo pausa
|
||||
void setPaused(bool value) { is_paused_ = value; };
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
#include "s_moving_sprite.h" // Para SMovingSprite
|
||||
class Surface; // lines 9-9
|
||||
|
||||
struct AnimationData
|
||||
{
|
||||
std::string name; // Nombre de la animacion
|
||||
std::vector<SDL_Rect> frames; // Cada uno de los frames que componen la animación
|
||||
int speed; // Velocidad de la animación
|
||||
int loop; // Indica a que frame vuelve la animación al terminar. -1 para que no vuelva
|
||||
bool completed; // Indica si ha finalizado la animación
|
||||
int current_frame; // Frame actual
|
||||
int counter; // Contador para las animaciones
|
||||
|
||||
AnimationData() : name(std::string()), speed(5), loop(0), completed(false), current_frame(0), counter(0) {}
|
||||
};
|
||||
|
||||
using Animations = std::vector<std::string>;
|
||||
|
||||
// Carga las animaciones en un vector(Animations) desde un fichero
|
||||
Animations loadAnimationsFromFile(const std::string &file_path);
|
||||
|
||||
class SAnimatedSprite : public SMovingSprite
|
||||
{
|
||||
protected:
|
||||
// Variables
|
||||
std::vector<AnimationData> animations_; // Vector con las diferentes animaciones
|
||||
int current_animation_ = 0; // Animacion activa
|
||||
|
||||
// Calcula el frame correspondiente a la animación actual
|
||||
void animate();
|
||||
|
||||
// Carga la animación desde un vector de cadenas
|
||||
void setAnimations(const Animations &animations);
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
SAnimatedSprite(std::shared_ptr<Surface> surface, const std::string &file_path);
|
||||
SAnimatedSprite(std::shared_ptr<Surface> surface, const Animations &animations);
|
||||
explicit SAnimatedSprite(std::shared_ptr<Surface> surface)
|
||||
: SMovingSprite(surface) {}
|
||||
|
||||
// Destructor
|
||||
virtual ~SAnimatedSprite() override = default;
|
||||
|
||||
// Actualiza las variables del objeto
|
||||
void update() override;
|
||||
|
||||
// Comprueba si ha terminado la animación
|
||||
bool animationIsCompleted();
|
||||
|
||||
// Obtiene el indice de la animación a partir del nombre
|
||||
int getIndex(const std::string &name);
|
||||
|
||||
// Establece la animacion actual
|
||||
void setCurrentAnimation(const std::string &name = "default");
|
||||
void setCurrentAnimation(int index = 0);
|
||||
|
||||
// Reinicia la animación
|
||||
void resetAnimation();
|
||||
|
||||
// Establece el frame actual de la animación
|
||||
void setCurrentAnimationFrame(int num);
|
||||
|
||||
// Obtiene el numero de frames de la animación actual
|
||||
int getCurrentAnimationSize() { return static_cast<int>(animations_[current_animation_].frames.size()); }
|
||||
};
|
||||
@@ -1,82 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL2/SDL_render.h> // Para SDL_RendererFlip, SDL_FLIP_HORIZONTAL
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint8
|
||||
#include <memory> // Para shared_ptr
|
||||
#include "s_sprite.h" // Para SSprite
|
||||
class Surface; // lines 8-8
|
||||
|
||||
// Clase SMovingSprite. Añade movimiento y flip al sprite
|
||||
class SMovingSprite : public SSprite
|
||||
{
|
||||
public:
|
||||
protected:
|
||||
float x_; // Posición en el eje X
|
||||
float y_; // Posición en el eje Y
|
||||
|
||||
float vx_ = 0.0f; // Velocidad en el eje X. Cantidad de pixeles a desplazarse
|
||||
float vy_ = 0.0f; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse
|
||||
|
||||
float ax_ = 0.0f; // Aceleración en el eje X. Variación de la velocidad
|
||||
float ay_ = 0.0f; // Aceleración en el eje Y. Variación de la velocidad
|
||||
|
||||
SDL_RendererFlip flip_; // Indica como se voltea el sprite
|
||||
|
||||
// Mueve el sprite
|
||||
void move();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
SMovingSprite(std::shared_ptr<Surface> surface, SDL_Rect pos, SDL_RendererFlip flip);
|
||||
SMovingSprite(std::shared_ptr<Surface> surface, SDL_Rect pos);
|
||||
explicit SMovingSprite(std::shared_ptr<Surface> surface);
|
||||
|
||||
// Destructor
|
||||
virtual ~SMovingSprite() override = default;
|
||||
|
||||
// Actualiza las variables internas del objeto
|
||||
virtual void update();
|
||||
|
||||
// Reinicia todas las variables a cero
|
||||
void clear() override;
|
||||
|
||||
// Muestra el sprite por pantalla
|
||||
void render() override;
|
||||
void render(Uint8 source_color, Uint8 target_color) override;
|
||||
|
||||
// Obtiene la variable
|
||||
float getPosX() const { return x_; }
|
||||
float getPosY() const { return y_; }
|
||||
float getVelX() const { return vx_; }
|
||||
float getVelY() const { return vy_; }
|
||||
float getAccelX() const { return ax_; }
|
||||
float getAccelY() const { return ay_; }
|
||||
|
||||
// Establece la variable
|
||||
void setVelX(float value) { vx_ = value; }
|
||||
void setVelY(float value) { vy_ = value; }
|
||||
void setAccelX(float value) { ax_ = value; }
|
||||
void setAccelY(float value) { ay_ = value; }
|
||||
|
||||
// Establece el valor de la variable
|
||||
void setFlip(SDL_RendererFlip flip) { flip_ = flip; }
|
||||
|
||||
// Gira el sprite horizontalmente
|
||||
void flip() { flip_ = (flip_ == SDL_FLIP_HORIZONTAL) ? SDL_FLIP_NONE : SDL_FLIP_HORIZONTAL; }
|
||||
|
||||
// Obtiene el valor de la variable
|
||||
SDL_RendererFlip getFlip() { return flip_; }
|
||||
|
||||
// Establece la posición y_ el tamaño del objeto
|
||||
void setPos(SDL_Rect rect);
|
||||
|
||||
// Establece el valor de las variables
|
||||
void setPos(float x, float y);
|
||||
|
||||
// Establece el valor de la variable
|
||||
void setPosX(float value);
|
||||
|
||||
// Establece el valor de la variable
|
||||
void setPosY(float value);
|
||||
};
|
||||
@@ -1,70 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect, SDL_Point
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint8
|
||||
#include <memory> // Para shared_ptr
|
||||
class Surface; // lines 5-5
|
||||
|
||||
// Clase SSprite
|
||||
class SSprite
|
||||
{
|
||||
protected:
|
||||
// Variables
|
||||
std::shared_ptr<Surface> surface_; // Surface donde estan todos los dibujos del sprite
|
||||
SDL_Rect pos_; // Posición y tamaño donde dibujar el sprite
|
||||
SDL_Rect clip_; // Rectangulo de origen de la surface que se dibujará en pantalla
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
SSprite(std::shared_ptr<Surface>, int x, int y, int w, int h);
|
||||
SSprite(std::shared_ptr<Surface>, SDL_Rect rect);
|
||||
explicit SSprite(std::shared_ptr<Surface>);
|
||||
|
||||
// Destructor
|
||||
virtual ~SSprite() = default;
|
||||
|
||||
// Muestra el sprite por pantalla
|
||||
virtual void render();
|
||||
virtual void render(Uint8 source_color, Uint8 target_color);
|
||||
|
||||
// Reinicia las variables a cero
|
||||
virtual void clear();
|
||||
|
||||
// Obtiene la posición y el tamaño
|
||||
int getX() const { return pos_.x; }
|
||||
int getY() const { return pos_.y; }
|
||||
int getWidth() const { return pos_.w; }
|
||||
int getHeight() const { return pos_.h; }
|
||||
|
||||
// Devuelve el rectangulo donde está el sprite
|
||||
SDL_Rect getPosition() const { return pos_; }
|
||||
SDL_Rect &getRect() { return pos_; }
|
||||
|
||||
// Establece la posición y el tamaño
|
||||
void setX(int x) { pos_.x = x; }
|
||||
void setY(int y) { pos_.y = y; }
|
||||
void setWidth(int w) { pos_.w = w; }
|
||||
void setHeight(int h) { pos_.h = h; }
|
||||
|
||||
// Establece la posición del objeto
|
||||
void setPosition(int x, int y);
|
||||
void setPosition(SDL_Point p);
|
||||
void setPosition(SDL_Rect r) { pos_ = r; }
|
||||
|
||||
// Aumenta o disminuye la posición
|
||||
void incX(int value) { pos_.x += value; }
|
||||
void incY(int value) { pos_.y += value; }
|
||||
|
||||
// Obtiene el rectangulo que se dibuja de la surface
|
||||
SDL_Rect getClip() const { return clip_; }
|
||||
|
||||
// Establece el rectangulo que se dibuja de la surface
|
||||
void setClip(SDL_Rect rect) { clip_ = rect; }
|
||||
void setClip(int x, int y, int w, int h) { clip_ = (SDL_Rect){x, y, w, h}; }
|
||||
|
||||
// Obtiene un puntero a la surface
|
||||
std::shared_ptr<Surface> getSurface() const { return surface_; }
|
||||
|
||||
// Establece la surface a utilizar
|
||||
void setSurface(std::shared_ptr<Surface> surface) { surface_ = surface; }
|
||||
};
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "scoreboard.h"
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include "defines.h" // Para BLOCK
|
||||
#include "options.h" // Para Options, options, Cheat, OptionsGame
|
||||
#include "resource.h" // Para Resource
|
||||
@@ -14,8 +16,7 @@
|
||||
Scoreboard::Scoreboard(std::shared_ptr<ScoreboardData> data)
|
||||
: item_surface_(Resource::get()->getSurface("items.gif")),
|
||||
data_(data),
|
||||
clock_(ClockData())
|
||||
{
|
||||
clock_(ClockData()) {
|
||||
const int SURFACE_WIDTH_ = options.game.width;
|
||||
constexpr int SURFACE_HEIGHT_ = 6 * BLOCK;
|
||||
|
||||
@@ -38,21 +39,18 @@ Scoreboard::Scoreboard(std::shared_ptr<ScoreboardData> data)
|
||||
|
||||
// Inicializa el vector de colores
|
||||
const std::vector<std::string> COLORS = {"blue", "magenta", "green", "cyan", "yellow", "white", "bright_blue", "bright_magenta", "bright_green", "bright_cyan", "bright_yellow", "bright_white"};
|
||||
for (const auto &color : COLORS)
|
||||
{
|
||||
for (const auto& color : COLORS) {
|
||||
color_.push_back(stringToColor(color));
|
||||
}
|
||||
}
|
||||
|
||||
// Pinta el objeto en pantalla
|
||||
void Scoreboard::render()
|
||||
{
|
||||
void Scoreboard::render() {
|
||||
surface_->render(nullptr, &surface_dest_);
|
||||
}
|
||||
|
||||
// Actualiza las variables del objeto
|
||||
void Scoreboard::update()
|
||||
{
|
||||
void Scoreboard::update() {
|
||||
counter_++;
|
||||
player_sprite_->update();
|
||||
|
||||
@@ -62,16 +60,14 @@ void Scoreboard::update()
|
||||
// Dibuja la textura
|
||||
fillTexture();
|
||||
|
||||
if (!is_paused_)
|
||||
{
|
||||
if (!is_paused_) {
|
||||
// Si está en pausa no se actualiza el reloj
|
||||
clock_ = getTime();
|
||||
}
|
||||
}
|
||||
|
||||
// Obtiene el tiempo transcurrido de partida
|
||||
Scoreboard::ClockData Scoreboard::getTime()
|
||||
{
|
||||
Scoreboard::ClockData Scoreboard::getTime() {
|
||||
const Uint32 timeElapsed = SDL_GetTicks() - data_->ini_clock - paused_time_elapsed_;
|
||||
|
||||
ClockData time;
|
||||
@@ -84,55 +80,43 @@ Scoreboard::ClockData Scoreboard::getTime()
|
||||
}
|
||||
|
||||
// Pone el marcador en modo pausa
|
||||
void Scoreboard::setPaused(bool value)
|
||||
{
|
||||
if (is_paused_ == value)
|
||||
{
|
||||
void Scoreboard::setPaused(bool value) {
|
||||
if (is_paused_ == value) {
|
||||
// Evita ejecutar lógica si el estado no cambia
|
||||
return;
|
||||
}
|
||||
|
||||
is_paused_ = value;
|
||||
|
||||
if (is_paused_)
|
||||
{
|
||||
if (is_paused_) {
|
||||
// Guarda el tiempo actual al pausar
|
||||
paused_time_ = SDL_GetTicks();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Calcula el tiempo pausado acumulado al reanudar
|
||||
paused_time_elapsed_ += SDL_GetTicks() - paused_time_;
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el color de la cantidad de items recogidos
|
||||
void Scoreboard::updateItemsColor()
|
||||
{
|
||||
if (!data_->jail_is_open)
|
||||
{
|
||||
void Scoreboard::updateItemsColor() {
|
||||
if (!data_->jail_is_open) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (counter_ % 20 < 10)
|
||||
{
|
||||
if (counter_ % 20 < 10) {
|
||||
items_color_ = stringToColor("white");
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
items_color_ = stringToColor("magenta");
|
||||
}
|
||||
}
|
||||
|
||||
// Devuelve la cantidad de minutos de juego transcurridos
|
||||
int Scoreboard::getMinutes()
|
||||
{
|
||||
int Scoreboard::getMinutes() {
|
||||
return getTime().minutes;
|
||||
}
|
||||
|
||||
// Dibuja los elementos del marcador en la textura
|
||||
void Scoreboard::fillTexture()
|
||||
{
|
||||
void Scoreboard::fillTexture() {
|
||||
// Empieza a dibujar en la textura
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(surface_);
|
||||
@@ -149,16 +133,14 @@ void Scoreboard::fillTexture()
|
||||
const int frame = desp % 4;
|
||||
player_sprite_->setCurrentAnimationFrame(frame);
|
||||
player_sprite_->setPosY(LINE2);
|
||||
for (int i = 0; i < data_->lives; ++i)
|
||||
{
|
||||
for (int i = 0; i < data_->lives; ++i) {
|
||||
player_sprite_->setPosX(8 + (16 * i) + desp);
|
||||
const int index = i % color_.size();
|
||||
player_sprite_->render(1, color_.at(index));
|
||||
}
|
||||
|
||||
// Muestra si suena la música
|
||||
if (data_->music)
|
||||
{
|
||||
if (data_->music) {
|
||||
const Uint8 c = data_->color;
|
||||
SDL_Rect clip = {0, 8, 8, 8};
|
||||
item_surface_->renderWithColorReplace(20 * BLOCK, LINE2, 1, c, &clip);
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint32, Uint8
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint32, Uint8
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string, basic_string
|
||||
#include <vector> // Para vector
|
||||
class SAnimatedSprite; // lines 10-10
|
||||
class Surface; // lines 11-11
|
||||
|
||||
struct ScoreboardData
|
||||
{
|
||||
struct ScoreboardData {
|
||||
int items; // Lleva la cuenta de los objetos recogidos
|
||||
int lives; // Lleva la cuenta de las vidas restantes del jugador
|
||||
int rooms; // Lleva la cuenta de las habitaciones visitadas
|
||||
@@ -20,18 +20,28 @@ struct ScoreboardData
|
||||
|
||||
// Constructor por defecto
|
||||
ScoreboardData()
|
||||
: items(0), lives(0), rooms(0), music(true), color(0), ini_clock(0), jail_is_open(false) {}
|
||||
: items(0),
|
||||
lives(0),
|
||||
rooms(0),
|
||||
music(true),
|
||||
color(0),
|
||||
ini_clock(0),
|
||||
jail_is_open(false) {}
|
||||
|
||||
// Constructor parametrizado
|
||||
ScoreboardData(int items, int lives, int rooms, bool music, Uint8 color, Uint32 ini_clock, bool jail_is_open)
|
||||
: items(items), lives(lives), rooms(rooms), music(music), color(color), ini_clock(ini_clock), jail_is_open(jail_is_open) {}
|
||||
: items(items),
|
||||
lives(lives),
|
||||
rooms(rooms),
|
||||
music(music),
|
||||
color(color),
|
||||
ini_clock(ini_clock),
|
||||
jail_is_open(jail_is_open) {}
|
||||
};
|
||||
|
||||
class Scoreboard
|
||||
{
|
||||
private:
|
||||
struct ClockData
|
||||
{
|
||||
class Scoreboard {
|
||||
private:
|
||||
struct ClockData {
|
||||
int hours;
|
||||
int minutes;
|
||||
int seconds;
|
||||
@@ -39,11 +49,17 @@ private:
|
||||
|
||||
// Constructor por defecto
|
||||
ClockData()
|
||||
: hours(0), minutes(0), seconds(0), separator(":") {}
|
||||
: hours(0),
|
||||
minutes(0),
|
||||
seconds(0),
|
||||
separator(":") {}
|
||||
|
||||
// Constructor parametrizado
|
||||
ClockData(int h, int m, int s, const std::string &sep)
|
||||
: hours(h), minutes(m), seconds(s), separator(sep) {}
|
||||
ClockData(int h, int m, int s, const std::string& sep)
|
||||
: hours(h),
|
||||
minutes(m),
|
||||
seconds(s),
|
||||
separator(sep) {}
|
||||
};
|
||||
|
||||
// Objetos y punteros
|
||||
@@ -72,7 +88,7 @@ private:
|
||||
// Dibuja los elementos del marcador en la surface
|
||||
void fillTexture();
|
||||
|
||||
public:
|
||||
public:
|
||||
// Constructor
|
||||
explicit Scoreboard(std::shared_ptr<ScoreboardData> data);
|
||||
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
#include "screen.h"
|
||||
#include <SDL2/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL2/SDL_events.h> // Para SDL_DISABLE, SDL_ENABLE
|
||||
#include <SDL2/SDL_mouse.h> // Para SDL_ShowCursor
|
||||
#include <SDL2/SDL_pixels.h> // Para SDL_PIXELFORMAT_ARGB8888, SDL_PIXELFORM...
|
||||
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <SDL3/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL3/SDL_events.h> // Para SDL_DISABLE, SDL_ENABLE
|
||||
#include <SDL3/SDL_mouse.h> // Para SDL_ShowCursor
|
||||
#include <SDL3/SDL_pixels.h> // Para SDL_PIXELFORMAT_ARGB8888, SDL_PIXELFORM...
|
||||
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
||||
#include <ctype.h> // Para toupper
|
||||
|
||||
#include <algorithm> // Para max, min, transform
|
||||
#include <fstream> // Para basic_ostream, operator<<, endl, basic_...
|
||||
#include <iostream> // Para cerr
|
||||
#include <iterator> // Para istreambuf_iterator, operator==
|
||||
#include <string> // Para char_traits, string, operator+, operator==
|
||||
|
||||
#include "asset.h" // Para Asset, AssetType
|
||||
#include "jail_shader.h" // Para init, render
|
||||
#include "mouse.h" // Para updateCursorVisibility
|
||||
@@ -20,32 +23,28 @@
|
||||
#include "text.h" // Para Text
|
||||
|
||||
// [SINGLETON]
|
||||
Screen *Screen::screen_ = nullptr;
|
||||
Screen* Screen::screen_ = nullptr;
|
||||
|
||||
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||
void Screen::init(SDL_Window *window, SDL_Renderer *renderer)
|
||||
{
|
||||
void Screen::init(SDL_Window* window, SDL_Renderer* renderer) {
|
||||
Screen::screen_ = new Screen(window, renderer);
|
||||
}
|
||||
|
||||
// [SINGLETON] Destruiremos el objeto con esta función estática
|
||||
void Screen::destroy()
|
||||
{
|
||||
void Screen::destroy() {
|
||||
delete Screen::screen_;
|
||||
}
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
Screen *Screen::get()
|
||||
{
|
||||
Screen* Screen::get() {
|
||||
return Screen::screen_;
|
||||
}
|
||||
|
||||
// Constructor
|
||||
Screen::Screen(SDL_Window *window, SDL_Renderer *renderer)
|
||||
Screen::Screen(SDL_Window* window, SDL_Renderer* renderer)
|
||||
: window_(window),
|
||||
renderer_(renderer),
|
||||
palettes_(Asset::get()->getListByType(AssetType::PALETTE))
|
||||
{
|
||||
palettes_(Asset::get()->getListByType(AssetType::PALETTE)) {
|
||||
// Inicializa variables
|
||||
SDL_DisplayMode DM;
|
||||
SDL_GetCurrentDisplayMode(0, &DM);
|
||||
@@ -64,22 +63,18 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer)
|
||||
|
||||
// Crea la textura donde se dibujan los graficos del juego
|
||||
game_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, options.game.width, options.game.height);
|
||||
if (!game_texture_)
|
||||
{
|
||||
if (!game_texture_) {
|
||||
// Registrar el error si está habilitado
|
||||
if (options.console)
|
||||
{
|
||||
if (options.console) {
|
||||
std::cerr << "Error: game_texture_ could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Crea la textura donde se dibuja el borde que rodea el area de juego
|
||||
border_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, options.game.width + options.video.border.width * 2, options.game.height + options.video.border.height * 2);
|
||||
if (!border_texture_)
|
||||
{
|
||||
if (!border_texture_) {
|
||||
// Registrar el error si está habilitado
|
||||
if (options.console)
|
||||
{
|
||||
if (options.console) {
|
||||
std::cerr << "Error: border_texture_ could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -88,11 +83,9 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer)
|
||||
const int EXTRA_WIDTH = options.video.border.enabled ? options.video.border.width * 2 : 0;
|
||||
const int EXTRA_HEIGHT = options.video.border.enabled ? options.video.border.height * 2 : 0;
|
||||
shaders_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, options.game.width + EXTRA_WIDTH, options.game.height + EXTRA_HEIGHT);
|
||||
if (!shaders_texture_)
|
||||
{
|
||||
if (!shaders_texture_) {
|
||||
// Registrar el error si está habilitado
|
||||
if (options.console)
|
||||
{
|
||||
if (options.console) {
|
||||
std::cerr << "Error: shaders_texture_ could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -122,16 +115,14 @@ Screen::Screen(SDL_Window *window, SDL_Renderer *renderer)
|
||||
}
|
||||
|
||||
// Destructor
|
||||
Screen::~Screen()
|
||||
{
|
||||
Screen::~Screen() {
|
||||
SDL_DestroyTexture(game_texture_);
|
||||
SDL_DestroyTexture(border_texture_);
|
||||
SDL_DestroyTexture(shaders_texture_);
|
||||
}
|
||||
|
||||
// Limpia el renderer
|
||||
void Screen::clearRenderer(Color color)
|
||||
{
|
||||
void Screen::clearRenderer(Color color) {
|
||||
SDL_SetRenderDrawColor(renderer_, color.r, color.g, color.b, 0xFF);
|
||||
SDL_RenderClear(renderer_);
|
||||
}
|
||||
@@ -140,8 +131,7 @@ void Screen::clearRenderer(Color color)
|
||||
void Screen::start() { setRendererSurface(nullptr); }
|
||||
|
||||
// Vuelca el contenido del renderizador en pantalla
|
||||
void Screen::render()
|
||||
{
|
||||
void Screen::render() {
|
||||
fps_.increment();
|
||||
|
||||
// Renderiza todos los overlays
|
||||
@@ -155,8 +145,7 @@ void Screen::render()
|
||||
}
|
||||
|
||||
// Establece el modo de video
|
||||
void Screen::setVideoMode(int mode)
|
||||
{
|
||||
void Screen::setVideoMode(int mode) {
|
||||
// Actualiza las opciones
|
||||
options.video.mode = mode;
|
||||
|
||||
@@ -170,23 +159,19 @@ void Screen::setVideoMode(int mode)
|
||||
}
|
||||
|
||||
// Camibia entre pantalla completa y ventana
|
||||
void Screen::toggleVideoMode()
|
||||
{
|
||||
void Screen::toggleVideoMode() {
|
||||
options.video.mode = (options.video.mode == 0) ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0;
|
||||
setVideoMode(options.video.mode);
|
||||
}
|
||||
|
||||
// Reduce el tamaño de la ventana
|
||||
bool Screen::decWindowZoom()
|
||||
{
|
||||
if (options.video.mode == 0)
|
||||
{
|
||||
bool Screen::decWindowZoom() {
|
||||
if (options.video.mode == 0) {
|
||||
const int PREVIOUS_ZOOM = options.window.zoom;
|
||||
--options.window.zoom;
|
||||
options.window.zoom = std::max(options.window.zoom, 1);
|
||||
|
||||
if (options.window.zoom != PREVIOUS_ZOOM)
|
||||
{
|
||||
if (options.window.zoom != PREVIOUS_ZOOM) {
|
||||
setVideoMode(options.video.mode);
|
||||
return true;
|
||||
}
|
||||
@@ -196,16 +181,13 @@ bool Screen::decWindowZoom()
|
||||
}
|
||||
|
||||
// Aumenta el tamaño de la ventana
|
||||
bool Screen::incWindowZoom()
|
||||
{
|
||||
if (options.video.mode == 0)
|
||||
{
|
||||
bool Screen::incWindowZoom() {
|
||||
if (options.video.mode == 0) {
|
||||
const int PREVIOUS_ZOOM = options.window.zoom;
|
||||
++options.window.zoom;
|
||||
options.window.zoom = std::min(options.window.zoom, options.window.max_zoom);
|
||||
|
||||
if (options.window.zoom != PREVIOUS_ZOOM)
|
||||
{
|
||||
if (options.window.zoom != PREVIOUS_ZOOM) {
|
||||
setVideoMode(options.video.mode);
|
||||
return true;
|
||||
}
|
||||
@@ -215,55 +197,47 @@ bool Screen::incWindowZoom()
|
||||
}
|
||||
|
||||
// Cambia el color del borde
|
||||
void Screen::setBorderColor(Uint8 color)
|
||||
{
|
||||
void Screen::setBorderColor(Uint8 color) {
|
||||
border_color_ = color;
|
||||
border_surface_->clear(border_color_);
|
||||
}
|
||||
|
||||
// Cambia entre borde visible y no visible
|
||||
void Screen::toggleBorder()
|
||||
{
|
||||
void Screen::toggleBorder() {
|
||||
options.video.border.enabled = !options.video.border.enabled;
|
||||
createShadersTexture();
|
||||
setVideoMode(options.video.mode);
|
||||
}
|
||||
|
||||
// Dibuja las notificaciones
|
||||
void Screen::renderNotifications()
|
||||
{
|
||||
if (notifications_enabled_)
|
||||
{
|
||||
void Screen::renderNotifications() {
|
||||
if (notifications_enabled_) {
|
||||
Notifier::get()->render();
|
||||
}
|
||||
}
|
||||
|
||||
// Cambia el estado de los shaders
|
||||
void Screen::toggleShaders()
|
||||
{
|
||||
void Screen::toggleShaders() {
|
||||
options.video.shaders = !options.video.shaders;
|
||||
setVideoMode(options.video.mode);
|
||||
}
|
||||
|
||||
// Actualiza la lógica de la clase
|
||||
void Screen::update()
|
||||
{
|
||||
void Screen::update() {
|
||||
fps_.calculate(SDL_GetTicks());
|
||||
Notifier::get()->update();
|
||||
Mouse::updateCursorVisibility();
|
||||
}
|
||||
|
||||
// Calcula el tamaño de la ventana
|
||||
void Screen::adjustWindowSize()
|
||||
{
|
||||
void Screen::adjustWindowSize() {
|
||||
window_width_ = options.game.width + (options.video.border.enabled ? options.video.border.width * 2 : 0);
|
||||
window_height_ = options.game.height + (options.video.border.enabled ? options.video.border.height * 2 : 0);
|
||||
|
||||
options.window.max_zoom = getMaxZoom();
|
||||
|
||||
// Establece el nuevo tamaño
|
||||
if (options.video.mode == 0)
|
||||
{
|
||||
if (options.video.mode == 0) {
|
||||
int old_width, old_height;
|
||||
SDL_GetWindowSize(window_, &old_width, &old_height);
|
||||
|
||||
@@ -282,8 +256,7 @@ void Screen::adjustWindowSize()
|
||||
void Screen::adjustRenderLogicalSize() { SDL_RenderSetLogicalSize(renderer_, window_width_, window_height_); }
|
||||
|
||||
// Obtiene el tamaño máximo de zoom posible para la ventana
|
||||
int Screen::getMaxZoom()
|
||||
{
|
||||
int Screen::getMaxZoom() {
|
||||
// Obtiene información sobre la pantalla
|
||||
SDL_DisplayMode DM;
|
||||
SDL_GetCurrentDisplayMode(0, &DM);
|
||||
@@ -298,10 +271,8 @@ int Screen::getMaxZoom()
|
||||
}
|
||||
|
||||
// Reinicia los shaders
|
||||
void Screen::resetShaders()
|
||||
{
|
||||
if (options.video.shaders)
|
||||
{
|
||||
void Screen::resetShaders() {
|
||||
if (options.video.shaders) {
|
||||
const std::string GLSL_FILE = options.video.border.enabled ? "crtpi_240.glsl" : "crtpi_192.glsl";
|
||||
std::ifstream f(Asset::get()->get(GLSL_FILE).c_str());
|
||||
std::string source((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
|
||||
@@ -311,17 +282,14 @@ void Screen::resetShaders()
|
||||
}
|
||||
|
||||
// Establece el renderizador para las surfaces
|
||||
void Screen::setRendererSurface(std::shared_ptr<Surface> surface)
|
||||
{
|
||||
void Screen::setRendererSurface(std::shared_ptr<Surface> surface) {
|
||||
(surface) ? renderer_surface_ = std::make_shared<std::shared_ptr<Surface>>(surface) : renderer_surface_ = std::make_shared<std::shared_ptr<Surface>>(game_surface_);
|
||||
}
|
||||
|
||||
// Cambia la paleta
|
||||
void Screen::nextPalette()
|
||||
{
|
||||
void Screen::nextPalette() {
|
||||
++current_palette_;
|
||||
if (current_palette_ == static_cast<int>(palettes_.size()))
|
||||
{
|
||||
if (current_palette_ == static_cast<int>(palettes_.size())) {
|
||||
current_palette_ = 0;
|
||||
}
|
||||
|
||||
@@ -329,14 +297,10 @@ void Screen::nextPalette()
|
||||
}
|
||||
|
||||
// Cambia la paleta
|
||||
void Screen::previousPalette()
|
||||
{
|
||||
if (current_palette_ > 0)
|
||||
{
|
||||
void Screen::previousPalette() {
|
||||
if (current_palette_ > 0) {
|
||||
--current_palette_;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
current_palette_ = static_cast<Uint8>(palettes_.size() - 1);
|
||||
}
|
||||
|
||||
@@ -344,8 +308,7 @@ void Screen::previousPalette()
|
||||
}
|
||||
|
||||
// Establece la paleta
|
||||
void Screen::setPalete()
|
||||
{
|
||||
void Screen::setPalete() {
|
||||
game_surface_->loadPalette(Resource::get()->getPalette(palettes_.at(current_palette_)));
|
||||
border_surface_->loadPalette(Resource::get()->getPalette(palettes_.at(current_palette_)));
|
||||
|
||||
@@ -353,8 +316,7 @@ void Screen::setPalete()
|
||||
|
||||
// Eliminar ".gif"
|
||||
size_t pos = options.video.palette.find(".pal");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
if (pos != std::string::npos) {
|
||||
options.video.palette.erase(pos, 4);
|
||||
}
|
||||
|
||||
@@ -363,42 +325,32 @@ void Screen::setPalete()
|
||||
}
|
||||
|
||||
// Extrae los nombres de las paletas
|
||||
void Screen::processPaletteList()
|
||||
{
|
||||
for (auto &palette : palettes_)
|
||||
{
|
||||
void Screen::processPaletteList() {
|
||||
for (auto& palette : palettes_) {
|
||||
palette = getFileName(palette);
|
||||
}
|
||||
}
|
||||
|
||||
// Copia la surface a la textura
|
||||
void Screen::surfaceToTexture()
|
||||
{
|
||||
if (options.video.border.enabled)
|
||||
{
|
||||
void Screen::surfaceToTexture() {
|
||||
if (options.video.border.enabled) {
|
||||
border_surface_->copyToTexture(renderer_, border_texture_);
|
||||
game_surface_->copyToTexture(renderer_, border_texture_, nullptr, &game_surface_dstrect_);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
game_surface_->copyToTexture(renderer_, game_texture_);
|
||||
}
|
||||
}
|
||||
|
||||
// Copia la textura al renderizador
|
||||
void Screen::textureToRenderer()
|
||||
{
|
||||
SDL_Texture *texture_to_render = options.video.border.enabled ? border_texture_ : game_texture_;
|
||||
void Screen::textureToRenderer() {
|
||||
SDL_Texture* texture_to_render = options.video.border.enabled ? border_texture_ : game_texture_;
|
||||
|
||||
if (options.video.shaders)
|
||||
{
|
||||
if (options.video.shaders) {
|
||||
SDL_SetRenderTarget(renderer_, shaders_texture_);
|
||||
SDL_RenderCopy(renderer_, texture_to_render, nullptr, nullptr);
|
||||
SDL_SetRenderTarget(renderer_, nullptr);
|
||||
shader::render();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SDL_SetRenderTarget(renderer_, nullptr);
|
||||
SDL_SetRenderDrawColor(renderer_, 0x00, 0x00, 0x00, 0xFF);
|
||||
SDL_RenderClear(renderer_);
|
||||
@@ -408,21 +360,17 @@ void Screen::textureToRenderer()
|
||||
}
|
||||
|
||||
// Renderiza todos los overlays
|
||||
void Screen::renderOverlays()
|
||||
{
|
||||
void Screen::renderOverlays() {
|
||||
renderNotifications();
|
||||
renderInfo();
|
||||
}
|
||||
|
||||
// Localiza la paleta dentro del vector de paletas
|
||||
size_t Screen::findPalette(const std::string &name)
|
||||
{
|
||||
size_t Screen::findPalette(const std::string& name) {
|
||||
std::string upper_name = toUpper(name + ".pal");
|
||||
|
||||
for (size_t i = 0; i < palettes_.size(); ++i)
|
||||
{
|
||||
if (toUpper(getFileName(palettes_[i])) == upper_name)
|
||||
{
|
||||
for (size_t i = 0; i < palettes_.size(); ++i) {
|
||||
if (toUpper(getFileName(palettes_[i])) == upper_name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -430,10 +378,8 @@ size_t Screen::findPalette(const std::string &name)
|
||||
}
|
||||
|
||||
// Recrea la textura para los shaders
|
||||
void Screen::createShadersTexture()
|
||||
{
|
||||
if (shaders_texture_)
|
||||
{
|
||||
void Screen::createShadersTexture() {
|
||||
if (shaders_texture_) {
|
||||
SDL_DestroyTexture(shaders_texture_);
|
||||
}
|
||||
|
||||
@@ -441,21 +387,17 @@ void Screen::createShadersTexture()
|
||||
const int EXTRA_WIDTH = options.video.border.enabled ? options.video.border.width * 2 : 0;
|
||||
const int EXTRA_HEIGHT = options.video.border.enabled ? options.video.border.height * 2 : 0;
|
||||
shaders_texture_ = SDL_CreateTexture(renderer_, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, options.game.width + EXTRA_WIDTH, options.game.height + EXTRA_HEIGHT);
|
||||
if (!shaders_texture_)
|
||||
{
|
||||
if (!shaders_texture_) {
|
||||
// Registrar el error si está habilitado
|
||||
if (options.console)
|
||||
{
|
||||
if (options.console) {
|
||||
std::cerr << "Error: shaders_texture_ could not be created!\nSDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Muestra información por pantalla
|
||||
void Screen::renderInfo()
|
||||
{
|
||||
if (show_debug_info_ && Resource::get())
|
||||
{
|
||||
void Screen::renderInfo() {
|
||||
if (show_debug_info_ && Resource::get()) {
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
auto color = static_cast<Uint8>(PaletteColor::YELLOW);
|
||||
|
||||
@@ -493,6 +435,6 @@ void Screen::setNotificationsEnabled(bool value) { notifications_enabled_ = valu
|
||||
void Screen::toggleDebugInfo() { show_debug_info_ = !show_debug_info_; }
|
||||
|
||||
// Getters
|
||||
SDL_Renderer *Screen::getRenderer() { return renderer_; }
|
||||
SDL_Renderer* Screen::getRenderer() { return renderer_; }
|
||||
std::shared_ptr<Surface> Screen::getRendererSurface() { return (*renderer_surface_); }
|
||||
std::shared_ptr<Surface> Screen::getBorderSurface() { return border_surface_; }
|
||||
@@ -1,49 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_blendmode.h> // Para SDL_BlendMode
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL2/SDL_render.h> // Para SDL_Renderer, SDL_Texture
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint8, Uint32
|
||||
#include <SDL2/SDL_video.h> // Para SDL_Window
|
||||
#include <SDL3/SDL_blendmode.h> // Para SDL_BlendMode
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL3/SDL_render.h> // Para SDL_Renderer, SDL_Texture
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint8, Uint32
|
||||
#include <SDL3/SDL_video.h> // Para SDL_Window
|
||||
#include <stddef.h> // Para size_t
|
||||
|
||||
#include <memory> // Para shared_ptr, __shared_ptr_access
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "utils.h" // Para Color
|
||||
struct Surface;
|
||||
|
||||
// Tipos de filtro
|
||||
enum class ScreenFilter : Uint32
|
||||
{
|
||||
enum class ScreenFilter : Uint32 {
|
||||
NEAREST = 0,
|
||||
LINEAR = 1,
|
||||
};
|
||||
|
||||
class Screen
|
||||
{
|
||||
private:
|
||||
class Screen {
|
||||
private:
|
||||
// Constantes
|
||||
static constexpr int WINDOWS_DECORATIONS_ = 35;
|
||||
|
||||
// Estructuras
|
||||
struct FPS
|
||||
{
|
||||
struct FPS {
|
||||
Uint32 ticks; // Tiempo en milisegundos desde que se comenzó a contar.
|
||||
int frameCount; // Número acumulado de frames en el intervalo.
|
||||
int lastValue; // Número de frames calculado en el último segundo.
|
||||
|
||||
// Constructor para inicializar la estructura.
|
||||
FPS() : ticks(0), frameCount(0), lastValue(0) {}
|
||||
FPS()
|
||||
: ticks(0),
|
||||
frameCount(0),
|
||||
lastValue(0) {}
|
||||
|
||||
// Incrementador que se llama en cada frame.
|
||||
void increment()
|
||||
{
|
||||
void increment() {
|
||||
frameCount++;
|
||||
}
|
||||
|
||||
// Método para calcular y devolver el valor de FPS.
|
||||
int calculate(Uint32 currentTicks)
|
||||
{
|
||||
int calculate(Uint32 currentTicks) {
|
||||
if (currentTicks - ticks >= 1000) // Si ha pasado un segundo o más.
|
||||
{
|
||||
lastValue = frameCount; // Actualizamos el valor del último FPS.
|
||||
@@ -55,14 +55,14 @@ private:
|
||||
};
|
||||
|
||||
// [SINGLETON] Objeto privado
|
||||
static Screen *screen_;
|
||||
static Screen* screen_;
|
||||
|
||||
// Objetos y punteros
|
||||
SDL_Window *window_; // Ventana de la aplicación
|
||||
SDL_Renderer *renderer_; // El renderizador de la ventana
|
||||
SDL_Texture *game_texture_; // Textura donde se dibuja el juego
|
||||
SDL_Texture *border_texture_; // Textura donde se dibuja el borde del juego
|
||||
SDL_Texture *shaders_texture_; // Textura para aplicar los shaders
|
||||
SDL_Window* window_; // Ventana de la aplicación
|
||||
SDL_Renderer* renderer_; // El renderizador de la ventana
|
||||
SDL_Texture* game_texture_; // Textura donde se dibuja el juego
|
||||
SDL_Texture* border_texture_; // Textura donde se dibuja el borde del juego
|
||||
SDL_Texture* shaders_texture_; // Textura para aplicar los shaders
|
||||
std::shared_ptr<Surface> game_surface_; // Surface principal para manejar game_surface_data_
|
||||
std::shared_ptr<Surface> border_surface_; // Surface para pintar el el borde de la pantalla
|
||||
std::shared_ptr<std::shared_ptr<Surface>> renderer_surface_; // Puntero a la Surface que actua
|
||||
@@ -109,7 +109,7 @@ private:
|
||||
void renderOverlays();
|
||||
|
||||
// Localiza la paleta dentro del vector de paletas
|
||||
size_t findPalette(const std::string &name);
|
||||
size_t findPalette(const std::string& name);
|
||||
|
||||
// Recrea la textura para los shaders
|
||||
void createShadersTexture();
|
||||
@@ -118,20 +118,20 @@ private:
|
||||
void renderInfo();
|
||||
|
||||
// Constructor
|
||||
Screen(SDL_Window *window, SDL_Renderer *renderer);
|
||||
Screen(SDL_Window* window, SDL_Renderer* renderer);
|
||||
|
||||
// Destructor
|
||||
~Screen();
|
||||
|
||||
public:
|
||||
public:
|
||||
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||
static void init(SDL_Window *window, SDL_Renderer *renderer);
|
||||
static void init(SDL_Window* window, SDL_Renderer* renderer);
|
||||
|
||||
// [SINGLETON] Destruiremos el objeto con esta función estática
|
||||
static void destroy();
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
static Screen *get();
|
||||
static Screen* get();
|
||||
|
||||
// Limpia el renderer
|
||||
void clearRenderer(Color color = {0x00, 0x00, 0x00});
|
||||
@@ -204,7 +204,7 @@ public:
|
||||
void toggleDebugInfo();
|
||||
|
||||
// Getters
|
||||
SDL_Renderer *getRenderer();
|
||||
SDL_Renderer* getRenderer();
|
||||
std::shared_ptr<Surface> getRendererSurface();
|
||||
std::shared_ptr<Surface> getBorderSurface();
|
||||
};
|
||||
259
source/sections/credits.cpp
Normal file
259
source/sections/credits.cpp
Normal file
@@ -0,0 +1,259 @@
|
||||
#include "credits.h"
|
||||
|
||||
#include <SDL3/SDL_events.h> // Para SDL_PollEvent, SDL_Event
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <algorithm> // Para min
|
||||
|
||||
#include "defines.h" // Para GAME_SPEED, PLAY_AREA_CENTER_X, PLAY_...
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
#include "options.h" // Para Options, options, OptionsGame, Sectio...
|
||||
#include "resource.h" // Para Resource
|
||||
#include "s_animated_sprite.h" // Para SAnimatedSprite
|
||||
#include "screen.h" // Para Screen
|
||||
#include "surface.h" // Para Surface
|
||||
#include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR
|
||||
#include "utils.h" // Para PaletteColor
|
||||
|
||||
// Constructor
|
||||
Credits::Credits()
|
||||
: shining_sprite_(std::make_shared<SAnimatedSprite>(Resource::get()->getSurface("shine.gif"), Resource::get()->getAnimations("shine.ani"))) {
|
||||
// Inicializa variables
|
||||
options.section.section = Section::CREDITS;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
shining_sprite_->setPos({194, 174, 8, 8});
|
||||
|
||||
// Cambia el color del borde
|
||||
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
// Crea la textura para el texto que se escribe en pantalla
|
||||
text_surface_ = std::make_shared<Surface>(options.game.width, options.game.height);
|
||||
|
||||
// Crea la textura para cubrir el rexto
|
||||
cover_surface_ = std::make_shared<Surface>(options.game.width, options.game.height);
|
||||
|
||||
// Escribe el texto en la textura
|
||||
fillTexture();
|
||||
}
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void Credits::checkEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
globalEvents::check(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las entradas
|
||||
void Credits::checkInput() {
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Inicializa los textos
|
||||
void Credits::iniTexts() {
|
||||
#ifndef GAME_CONSOLE
|
||||
std::string keys = "";
|
||||
|
||||
switch (options.keys) {
|
||||
case ControlScheme::CURSOR:
|
||||
keys = "CURSORS";
|
||||
break;
|
||||
case ControlScheme::OPQA:
|
||||
keys = "O,P AND Q";
|
||||
break;
|
||||
case ControlScheme::WASD:
|
||||
keys = "A,D AND W";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
texts_.clear();
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"INSTRUCTIONS:", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"HELP JAILDOC TO GET BACK ALL", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"HIS PROJECTS AND GO TO THE", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"JAIL TO FINISH THEM", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
|
||||
texts_.push_back({"KEYS:", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({keys + " TO MOVE AND JUMP", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"M TO SWITCH THE MUSIC", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"H TO PAUSE THE GAME", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"F1-F2 TO CHANGE WINDOWS SIZE", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"F3 TO SWITCH TO FULLSCREEN", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"B TO TOOGLE THE BORDER SCREEN", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
|
||||
texts_.push_back({"A GAME BY JAILDESIGNER", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({"MADE ON SUMMER/FALL 2022", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
|
||||
texts_.push_back({"I LOVE JAILGAMES! ", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
#else
|
||||
texts.clear();
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"INSTRUCTIONS:", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"HELP JAILDOC TO GET BACK ALL", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"HIS PROJECTS AND GO TO THE", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"JAIL TO FINISH THEM", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
|
||||
texts.push_back({"KEYS:", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"B TO JUMP", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"R TO SWITCH THE MUSIC", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"L TO SWAP THE COLOR PALETTE", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"START TO PAUSE", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"SELECT TO EXIT", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
|
||||
texts.push_back({"A GAME BY JAILDESIGNER", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts.push_back({"MADE ON SUMMER/FALL 2022", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
|
||||
texts.push_back({"I LOVE JAILGAMES! ", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
#endif
|
||||
}
|
||||
|
||||
// Escribe el texto en la textura
|
||||
void Credits::fillTexture() {
|
||||
// Inicializa los textos
|
||||
iniTexts();
|
||||
|
||||
// Rellena la textura de texto
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(text_surface_);
|
||||
text_surface_->clear(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
|
||||
// Escribe el texto en la textura
|
||||
const int SIZE = text->getCharacterSize();
|
||||
int pos_y = 0;
|
||||
|
||||
for (const auto& t : texts_) {
|
||||
text->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, pos_y * SIZE, t.label, 1, t.color);
|
||||
pos_y++;
|
||||
}
|
||||
|
||||
// Escribe el corazón
|
||||
const int TEXT_LENGHT = text->lenght(texts_[22].label, 1) - text->lenght(" ", 1); // Se resta el ultimo caracter que es un espacio
|
||||
const int POS_X = ((PLAY_AREA_WIDTH - TEXT_LENGHT) / 2) + TEXT_LENGHT;
|
||||
text->writeColored(POS_X, 176, "}", static_cast<Uint8>(PaletteColor::BRIGHT_RED));
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
|
||||
// Recoloca el sprite del brillo
|
||||
shining_sprite_->setPosX(POS_X + 2);
|
||||
|
||||
// Rellena la textura que cubre el texto con color transparente
|
||||
cover_surface_->clear(static_cast<Uint8>(PaletteColor::TRANSPARENT));
|
||||
|
||||
// Los primeros 8 pixels crea una malla
|
||||
auto color = static_cast<Uint8>(PaletteColor::BLACK);
|
||||
for (int i = 0; i < 256; i += 2) {
|
||||
cover_surface_->putPixel(i, 0, color);
|
||||
cover_surface_->putPixel(i, 2, color);
|
||||
cover_surface_->putPixel(i, 4, color);
|
||||
cover_surface_->putPixel(i, 6, color);
|
||||
|
||||
cover_surface_->putPixel(i + 1, 5, color);
|
||||
cover_surface_->putPixel(i + 1, 7, color);
|
||||
}
|
||||
|
||||
// El resto se rellena de color sólido
|
||||
SDL_Rect rect = {0, 8, 256, 192};
|
||||
cover_surface_->fillRect(&rect, color);
|
||||
}
|
||||
|
||||
// Actualiza el contador
|
||||
void Credits::updateCounter() {
|
||||
// Incrementa el contador
|
||||
if (counter_enabled_) {
|
||||
counter_++;
|
||||
if (counter_ == 224 || counter_ == 544 || counter_ == 672) {
|
||||
counter_enabled_ = false;
|
||||
}
|
||||
} else {
|
||||
sub_counter_++;
|
||||
if (sub_counter_ == 100) {
|
||||
counter_enabled_ = true;
|
||||
sub_counter_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba si ha terminado la sección
|
||||
if (counter_ > 1200) {
|
||||
options.section.section = Section::DEMO;
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza las variables
|
||||
void Credits::update() {
|
||||
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED) {
|
||||
// Actualiza el contador de ticks
|
||||
ticks_ = SDL_GetTicks();
|
||||
|
||||
// Comprueba las entradas
|
||||
checkInput();
|
||||
|
||||
// Actualiza el contador
|
||||
updateCounter();
|
||||
|
||||
Screen::get()->update();
|
||||
|
||||
// Actualiza el sprite con el brillo
|
||||
if (counter_ > 770) {
|
||||
shining_sprite_->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja en pantalla
|
||||
void Credits::render() {
|
||||
// Prepara para empezar a dibujar en la textura de juego
|
||||
Screen::get()->start();
|
||||
|
||||
// Limpia la pantalla
|
||||
Screen::get()->clearSurface(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
if (counter_ < 1150) {
|
||||
// Dibuja la textura con el texto en pantalla
|
||||
text_surface_->render(0, 0);
|
||||
|
||||
// Dibuja la textura que cubre el texto
|
||||
const int offset = std::min(counter_ / 8, 192 / 2);
|
||||
SDL_Rect srcRect = {0, 0, 256, 192 - (offset * 2)};
|
||||
cover_surface_->render(0, offset * 2, &srcRect);
|
||||
|
||||
// Dibuja el sprite con el brillo
|
||||
shining_sprite_->render(1, static_cast<Uint8>(PaletteColor::BRIGHT_WHITE));
|
||||
}
|
||||
|
||||
// Vuelca el contenido del renderizador en pantalla
|
||||
Screen::get()->render();
|
||||
}
|
||||
|
||||
// Bucle para el logo del juego
|
||||
void Credits::run() {
|
||||
while (options.section.section == Section::CREDITS) {
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
}
|
||||
}
|
||||
60
source/sections/credits.h
Normal file
60
source/sections/credits.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint32, Uint8
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
class SAnimatedSprite; // lines 11-11
|
||||
class Surface;
|
||||
|
||||
class Credits {
|
||||
private:
|
||||
struct Captions {
|
||||
std::string label; // Texto a escribir
|
||||
Uint8 color; // Color del texto
|
||||
};
|
||||
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<Surface> text_surface_; // Textura para dibujar el texto
|
||||
std::shared_ptr<Surface> cover_surface_; // Textura para cubrir el texto
|
||||
std::shared_ptr<SAnimatedSprite> shining_sprite_; // Sprite para el brillo del corazón
|
||||
|
||||
// Variables
|
||||
int counter_ = 0; // Contador
|
||||
bool counter_enabled_ = true; // Indica si esta activo el contador
|
||||
int sub_counter_ = 0; // Contador secundario
|
||||
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
std::vector<Captions> texts_; // Vector con los textos
|
||||
|
||||
// Actualiza las variables
|
||||
void update();
|
||||
|
||||
// Dibuja en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void checkEvents();
|
||||
|
||||
// Comprueba las entradas
|
||||
void checkInput();
|
||||
|
||||
// Actualiza el contador
|
||||
void updateCounter();
|
||||
|
||||
// Inicializa los textos
|
||||
void iniTexts();
|
||||
|
||||
// Escribe el texto en la textura
|
||||
void fillTexture();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Credits();
|
||||
|
||||
// Destructor
|
||||
~Credits() = default;
|
||||
|
||||
// Bucle principal
|
||||
void run();
|
||||
};
|
||||
@@ -1,8 +1,11 @@
|
||||
#include "ending.h"
|
||||
#include <SDL2/SDL_events.h> // Para SDL_PollEvent, SDL_Event
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <SDL3/SDL_events.h> // Para SDL_PollEvent, SDL_Event
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <algorithm> // Para min
|
||||
|
||||
#include "defines.h" // Para GAME_SPEED
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
@@ -21,8 +24,7 @@ Ending::Ending()
|
||||
pre_counter_(0),
|
||||
cover_counter_(0),
|
||||
ticks_(0),
|
||||
current_scene_(0)
|
||||
{
|
||||
current_scene_(0) {
|
||||
options.section.section = Section::ENDING;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
|
||||
@@ -46,11 +48,9 @@ Ending::Ending()
|
||||
}
|
||||
|
||||
// Actualiza el objeto
|
||||
void Ending::update()
|
||||
{
|
||||
void Ending::update() {
|
||||
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED)
|
||||
{
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED) {
|
||||
// Actualiza el contador de ticks
|
||||
ticks_ = SDL_GetTicks();
|
||||
|
||||
@@ -75,8 +75,7 @@ void Ending::update()
|
||||
}
|
||||
|
||||
// Dibuja el final en pantalla
|
||||
void Ending::render()
|
||||
{
|
||||
void Ending::render() {
|
||||
// Prepara para empezar a dibujar en la textura de juego
|
||||
Screen::get()->start();
|
||||
|
||||
@@ -88,10 +87,8 @@ void Ending::render()
|
||||
sprite_pics_.at(current_scene_).cover_sprite->render();
|
||||
|
||||
// Dibuja los textos de la escena
|
||||
for (const auto &ti : scenes_.at(current_scene_).text_index)
|
||||
{
|
||||
if (counter_ > ti.trigger)
|
||||
{
|
||||
for (const auto& ti : scenes_.at(current_scene_).text_index) {
|
||||
if (counter_ > ti.trigger) {
|
||||
sprite_texts_.at(ti.index).image_sprite->render();
|
||||
sprite_texts_.at(ti.index).cover_sprite->render();
|
||||
}
|
||||
@@ -105,24 +102,20 @@ void Ending::render()
|
||||
}
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void Ending::checkEvents()
|
||||
{
|
||||
void Ending::checkEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
while (SDL_PollEvent(&event)) {
|
||||
globalEvents::check(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las entradas
|
||||
void Ending::checkInput()
|
||||
{
|
||||
void Ending::checkInput() {
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Inicializa los textos
|
||||
void Ending::iniTexts()
|
||||
{
|
||||
void Ending::iniTexts() {
|
||||
// Vector con los textos
|
||||
std::vector<TextAndPosition> texts;
|
||||
|
||||
@@ -158,8 +151,7 @@ void Ending::iniTexts()
|
||||
// Crea los sprites
|
||||
sprite_texts_.clear();
|
||||
|
||||
for (const auto &txt : texts)
|
||||
{
|
||||
for (const auto& txt : texts) {
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
|
||||
const int WIDTH = text->lenght(txt.caption, 1) + 2 + 2;
|
||||
@@ -189,8 +181,7 @@ void Ending::iniTexts()
|
||||
// Crea una malla de 8 pixels de alto
|
||||
auto surface = Screen::get()->getRendererSurface();
|
||||
auto color = static_cast<Uint8>(PaletteColor::BLACK);
|
||||
for (int i = 0; i < WIDTH; i += 2)
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i += 2) {
|
||||
surface->putPixel(i, 0, color);
|
||||
surface->putPixel(i, 2, color);
|
||||
surface->putPixel(i, 4, color);
|
||||
@@ -219,8 +210,7 @@ void Ending::iniTexts()
|
||||
}
|
||||
|
||||
// Inicializa las imagenes
|
||||
void Ending::iniPics()
|
||||
{
|
||||
void Ending::iniPics() {
|
||||
// Vector con las rutas y la posición
|
||||
std::vector<TextAndPosition> pics;
|
||||
|
||||
@@ -233,8 +223,7 @@ void Ending::iniPics()
|
||||
// Crea los sprites
|
||||
sprite_pics_.clear();
|
||||
|
||||
for (const auto &pic : pics)
|
||||
{
|
||||
for (const auto& pic : pics) {
|
||||
EndingSurface sp;
|
||||
|
||||
// Crea la texture
|
||||
@@ -258,8 +247,7 @@ void Ending::iniPics()
|
||||
// Crea una malla en los primeros 8 pixels
|
||||
auto surface = Screen::get()->getRendererSurface();
|
||||
auto color = static_cast<Uint8>(PaletteColor::BLACK);
|
||||
for (int i = 0; i < WIDTH; i += 2)
|
||||
{
|
||||
for (int i = 0; i < WIDTH; i += 2) {
|
||||
surface->putPixel(i, 0, color);
|
||||
surface->putPixel(i, 2, color);
|
||||
surface->putPixel(i, 4, color);
|
||||
@@ -288,8 +276,7 @@ void Ending::iniPics()
|
||||
}
|
||||
|
||||
// Inicializa las escenas
|
||||
void Ending::iniScenes()
|
||||
{
|
||||
void Ending::iniScenes() {
|
||||
// Variable para los tiempos
|
||||
int trigger;
|
||||
constexpr int LAPSE = 80;
|
||||
@@ -371,12 +358,10 @@ void Ending::iniScenes()
|
||||
}
|
||||
|
||||
// Bucle principal
|
||||
void Ending::run()
|
||||
{
|
||||
void Ending::run() {
|
||||
JA_PlayMusic(Resource::get()->getMusic("ending1.ogg"));
|
||||
|
||||
while (options.section.section == Section::ENDING)
|
||||
{
|
||||
while (options.section.section == Section::ENDING) {
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
@@ -387,40 +372,28 @@ void Ending::run()
|
||||
}
|
||||
|
||||
// Actualiza los contadores
|
||||
void Ending::updateCounters()
|
||||
{
|
||||
void Ending::updateCounters() {
|
||||
// Incrementa el contador
|
||||
if (pre_counter_ < 200)
|
||||
{
|
||||
if (pre_counter_ < 200) {
|
||||
pre_counter_++;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
counter_++;
|
||||
}
|
||||
|
||||
if (counter_ > scenes_[current_scene_].counter_end - 100)
|
||||
{
|
||||
if (counter_ > scenes_[current_scene_].counter_end - 100) {
|
||||
cover_counter_++;
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza las cortinillas de los elementos
|
||||
void Ending::updateSpriteCovers()
|
||||
{
|
||||
void Ending::updateSpriteCovers() {
|
||||
// Actualiza la cortinilla de los textos
|
||||
if (counter_ % 4 == 0)
|
||||
{
|
||||
for (auto ti : scenes_.at(current_scene_).text_index)
|
||||
{
|
||||
if (counter_ > ti.trigger)
|
||||
{
|
||||
if (sprite_texts_.at(ti.index).cover_clip_desp > 0)
|
||||
{
|
||||
if (counter_ % 4 == 0) {
|
||||
for (auto ti : scenes_.at(current_scene_).text_index) {
|
||||
if (counter_ > ti.trigger) {
|
||||
if (sprite_texts_.at(ti.index).cover_clip_desp > 0) {
|
||||
sprite_texts_.at(ti.index).cover_clip_desp -= 2;
|
||||
}
|
||||
else if (sprite_texts_.at(ti.index).cover_clip_height > 0)
|
||||
{
|
||||
} else if (sprite_texts_.at(ti.index).cover_clip_height > 0) {
|
||||
sprite_texts_.at(ti.index).cover_clip_height -= 2;
|
||||
sprite_texts_.at(ti.index).cover_sprite->setY(sprite_texts_.at(ti.index).cover_sprite->getY() + 2);
|
||||
}
|
||||
@@ -430,17 +403,12 @@ void Ending::updateSpriteCovers()
|
||||
}
|
||||
|
||||
// Actualiza la cortinilla de las imágenes
|
||||
if (counter_ % 2 == 0)
|
||||
{
|
||||
if (sprite_pics_.at(current_scene_).cover_clip_desp > 0)
|
||||
{
|
||||
if (counter_ % 2 == 0) {
|
||||
if (sprite_pics_.at(current_scene_).cover_clip_desp > 0) {
|
||||
sprite_pics_.at(current_scene_).cover_clip_desp -= 2;
|
||||
}
|
||||
else if (sprite_pics_.at(current_scene_).cover_clip_height > 0)
|
||||
{
|
||||
} else if (sprite_pics_.at(current_scene_).cover_clip_height > 0) {
|
||||
sprite_pics_.at(current_scene_).cover_clip_height -= 2;
|
||||
if (sprite_pics_.at(current_scene_).cover_clip_height < 0)
|
||||
{
|
||||
if (sprite_pics_.at(current_scene_).cover_clip_height < 0) {
|
||||
sprite_pics_.at(current_scene_).cover_clip_height = 0;
|
||||
}
|
||||
sprite_pics_.at(current_scene_).cover_sprite->setY(sprite_pics_.at(current_scene_).cover_sprite->getY() + 2);
|
||||
@@ -450,15 +418,12 @@ void Ending::updateSpriteCovers()
|
||||
}
|
||||
|
||||
// Comprueba si se ha de cambiar de escena
|
||||
void Ending::checkChangeScene()
|
||||
{
|
||||
if (counter_ > scenes_[current_scene_].counter_end)
|
||||
{
|
||||
void Ending::checkChangeScene() {
|
||||
if (counter_ > scenes_[current_scene_].counter_end) {
|
||||
current_scene_++;
|
||||
counter_ = 0;
|
||||
cover_counter_ = 0;
|
||||
if (current_scene_ == 5)
|
||||
{
|
||||
if (current_scene_ == 5) {
|
||||
// Termina el bucle
|
||||
options.section.section = Section::ENDING2;
|
||||
|
||||
@@ -470,8 +435,7 @@ void Ending::checkChangeScene()
|
||||
}
|
||||
|
||||
// Rellena la textura para la cortinilla
|
||||
void Ending::fillCoverTexture()
|
||||
{
|
||||
void Ending::fillCoverTexture() {
|
||||
// Rellena la textura que cubre el texto con color transparente
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(cover_surface_);
|
||||
@@ -480,9 +444,7 @@ void Ending::fillCoverTexture()
|
||||
// Los primeros 8 pixels crea una malla
|
||||
const Uint8 color = static_cast<Uint8>(PaletteColor::BLACK);
|
||||
auto surface = Screen::get()->getRendererSurface();
|
||||
for (int i = 0; i < 256; i += 2)
|
||||
{
|
||||
|
||||
for (int i = 0; i < 256; i += 2) {
|
||||
surface->putPixel(i + 0, options.game.height + 0, color);
|
||||
surface->putPixel(i + 1, options.game.height + 1, color);
|
||||
surface->putPixel(i + 0, options.game.height + 2, color);
|
||||
@@ -500,10 +462,8 @@ void Ending::fillCoverTexture()
|
||||
}
|
||||
|
||||
// Dibuja la cortinilla de cambio de escena
|
||||
void Ending::renderCoverTexture()
|
||||
{
|
||||
if (cover_counter_ > 0)
|
||||
{
|
||||
void Ending::renderCoverTexture() {
|
||||
if (cover_counter_ > 0) {
|
||||
// Dibuja la textura que cubre el texto
|
||||
const int OFFSET = std::min(cover_counter_, 100);
|
||||
SDL_Rect srcRect = {0, 200 - (cover_counter_ * 2), 256, OFFSET * 2};
|
||||
@@ -513,10 +473,8 @@ void Ending::renderCoverTexture()
|
||||
}
|
||||
|
||||
// Actualiza el volumen de la musica
|
||||
void Ending::updateMusicVolume()
|
||||
{
|
||||
if (current_scene_ == 4 && cover_counter_ > 0)
|
||||
{
|
||||
void Ending::updateMusicVolume() {
|
||||
if (current_scene_ == 4 && cover_counter_ > 0) {
|
||||
const float step = (100.0f - cover_counter_) / 100.0f;
|
||||
const int volume = 128 * step;
|
||||
JA_SetVolume(volume);
|
||||
103
source/sections/ending.h
Normal file
103
source/sections/ending.h
Normal file
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint32
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
class SSprite; // lines 8-8
|
||||
class Surface; // lines 9-9
|
||||
|
||||
class Ending {
|
||||
private:
|
||||
// Estructuras
|
||||
struct EndingSurface // Estructura con dos texturas y sprites, uno para mostrar y el otro hace de cortinilla
|
||||
{
|
||||
std::shared_ptr<Surface> image_surface; // Surface a mostrar
|
||||
std::shared_ptr<SSprite> image_sprite; // SSprite para mostrar la textura
|
||||
std::shared_ptr<Surface> cover_surface; // Surface que cubre a la otra textura
|
||||
std::shared_ptr<SSprite> cover_sprite; // SSprite para mostrar la textura que cubre a la otra textura
|
||||
int cover_clip_desp; // Desplazamiento del spriteClip de la textura de cobertura
|
||||
int cover_clip_height; // Altura del spriteClip de la textura de cobertura
|
||||
};
|
||||
|
||||
struct TextAndPosition // Estructura con un texto y su posición en el eje Y
|
||||
{
|
||||
std::string caption; // Texto
|
||||
int pos; // Posición
|
||||
};
|
||||
|
||||
struct TextIndex {
|
||||
int index;
|
||||
int trigger;
|
||||
};
|
||||
|
||||
struct SceneData // Estructura para crear cada una de las escenas del final
|
||||
{
|
||||
std::vector<TextIndex> text_index; // Indices del vector de textos a mostrar y su disparador
|
||||
int picture_index; // Indice del vector de imagenes a mostrar
|
||||
int counter_end; // Valor del contador en el que finaliza la escena
|
||||
};
|
||||
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<Surface> cover_surface_; // Surface para cubrir el texto
|
||||
|
||||
// Variables
|
||||
int counter_; // Contador
|
||||
int pre_counter_; // Contador previo
|
||||
int cover_counter_; // Contador para la cortinilla
|
||||
Uint32 ticks_; // Contador de ticks para ajustar la velocidad del programa
|
||||
std::vector<EndingSurface> sprite_texts_; // Vector con los sprites de texto con su cortinilla
|
||||
std::vector<EndingSurface> sprite_pics_; // Vector con los sprites de texto con su cortinilla
|
||||
int current_scene_; // Escena actual
|
||||
std::vector<SceneData> scenes_; // Vector con los textos e imagenes de cada escena
|
||||
|
||||
// Actualiza el objeto
|
||||
void update();
|
||||
|
||||
// Dibuja el final en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void checkEvents();
|
||||
|
||||
// Comprueba las entradas
|
||||
void checkInput();
|
||||
|
||||
// Inicializa los textos
|
||||
void iniTexts();
|
||||
|
||||
// Inicializa las imagenes
|
||||
void iniPics();
|
||||
|
||||
// Inicializa las escenas
|
||||
void iniScenes();
|
||||
|
||||
// Actualiza los contadores
|
||||
void updateCounters();
|
||||
|
||||
// Actualiza las cortinillas de los elementos
|
||||
void updateSpriteCovers();
|
||||
|
||||
// Comprueba si se ha de cambiar de escena
|
||||
void checkChangeScene();
|
||||
|
||||
// Rellena la textura para la cortinilla
|
||||
void fillCoverTexture();
|
||||
|
||||
// Dibuja la cortinilla de cambio de escena
|
||||
void renderCoverTexture();
|
||||
|
||||
// Actualiza el volumen de la musica
|
||||
void updateMusicVolume();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Ending();
|
||||
|
||||
// Destructor
|
||||
~Ending() = default;
|
||||
|
||||
// Bucle principal
|
||||
void run();
|
||||
};
|
||||
@@ -1,8 +1,11 @@
|
||||
#include "ending2.h"
|
||||
#include <SDL2/SDL_events.h> // Para SDL_PollEvent, SDL_Event
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <SDL3/SDL_events.h> // Para SDL_PollEvent, SDL_Event
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <algorithm> // Para max, replace
|
||||
|
||||
#include "defines.h" // Para GAMECANVAS_CENTER_X, GAMECANVAS_CENTER_Y
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
@@ -17,15 +20,14 @@
|
||||
#include "utils.h" // Para PaletteColor, stringToColor
|
||||
|
||||
// Constructor
|
||||
Ending2::Ending2() : state_(EndingState::PRE_CREDITS, SDL_GetTicks(), STATE_PRE_CREDITS_DURATION_)
|
||||
{
|
||||
Ending2::Ending2()
|
||||
: state_(EndingState::PRE_CREDITS, SDL_GetTicks(), STATE_PRE_CREDITS_DURATION_) {
|
||||
options.section.section = Section::ENDING2;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
|
||||
// Inicializa el vector de colores
|
||||
const std::vector<std::string> COLORS = {"white", "yellow", "cyan", "green", "magenta", "red", "blue", "black"};
|
||||
for (const auto &color : COLORS)
|
||||
{
|
||||
for (const auto& color : COLORS) {
|
||||
colors_.push_back(stringToColor(color));
|
||||
}
|
||||
|
||||
@@ -49,11 +51,9 @@ Ending2::Ending2() : state_(EndingState::PRE_CREDITS, SDL_GetTicks(), STATE_PRE_
|
||||
}
|
||||
|
||||
// Actualiza el objeto
|
||||
void Ending2::update()
|
||||
{
|
||||
void Ending2::update() {
|
||||
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED)
|
||||
{
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED) {
|
||||
// Actualiza el contador de ticks
|
||||
ticks_ = SDL_GetTicks();
|
||||
|
||||
@@ -63,12 +63,10 @@ void Ending2::update()
|
||||
// Actualiza el estado
|
||||
updateState();
|
||||
|
||||
switch (state_.state)
|
||||
{
|
||||
switch (state_.state) {
|
||||
case EndingState::CREDITS:
|
||||
// Actualiza los sprites, los textos y los textos del final
|
||||
for (int i = 0; i < 25; ++i)
|
||||
{
|
||||
for (int i = 0; i < 25; ++i) {
|
||||
updateSprites();
|
||||
updateTextSprites();
|
||||
updateTexts();
|
||||
@@ -92,8 +90,7 @@ void Ending2::update()
|
||||
}
|
||||
|
||||
// Dibuja el final en pantalla
|
||||
void Ending2::render()
|
||||
{
|
||||
void Ending2::render() {
|
||||
// Prepara para empezar a dibujar en la surface de juego
|
||||
Screen::get()->start();
|
||||
|
||||
@@ -112,8 +109,7 @@ void Ending2::render()
|
||||
// Dibuja una trama arriba y abajo
|
||||
Uint8 color = static_cast<Uint8>(PaletteColor::BLACK);
|
||||
auto surface = Screen::get()->getRendererSurface();
|
||||
for (int i = 0; i < 256; i += 2)
|
||||
{
|
||||
for (int i = 0; i < 256; i += 2) {
|
||||
surface->putPixel(i + 0, 0, color);
|
||||
surface->putPixel(i + 1, 1, color);
|
||||
surface->putPixel(i + 0, 2, color);
|
||||
@@ -136,28 +132,23 @@ void Ending2::render()
|
||||
}
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void Ending2::checkEvents()
|
||||
{
|
||||
void Ending2::checkEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
while (SDL_PollEvent(&event)) {
|
||||
globalEvents::check(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las entradas
|
||||
void Ending2::checkInput()
|
||||
{
|
||||
void Ending2::checkInput() {
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Bucle principal
|
||||
void Ending2::run()
|
||||
{
|
||||
void Ending2::run() {
|
||||
JA_PlayMusic(Resource::get()->getMusic("ending2.ogg"));
|
||||
|
||||
while (options.section.section == Section::ENDING2)
|
||||
{
|
||||
while (options.section.section == Section::ENDING2) {
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
@@ -168,34 +159,28 @@ void Ending2::run()
|
||||
}
|
||||
|
||||
// Actualiza el estado
|
||||
void Ending2::updateState()
|
||||
{
|
||||
switch (state_.state)
|
||||
{
|
||||
void Ending2::updateState() {
|
||||
switch (state_.state) {
|
||||
case EndingState::PRE_CREDITS:
|
||||
if (state_.hasEnded(EndingState::PRE_CREDITS))
|
||||
{
|
||||
if (state_.hasEnded(EndingState::PRE_CREDITS)) {
|
||||
state_.set(EndingState::CREDITS, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case EndingState::CREDITS:
|
||||
if (texts_.back()->getPosY() <= GAMECANVAS_CENTER_Y)
|
||||
{
|
||||
if (texts_.back()->getPosY() <= GAMECANVAS_CENTER_Y) {
|
||||
state_.set(EndingState::POST_CREDITS, STATE_POST_CREDITS_DURATION_);
|
||||
}
|
||||
break;
|
||||
|
||||
case EndingState::POST_CREDITS:
|
||||
if (state_.hasEnded(EndingState::POST_CREDITS))
|
||||
{
|
||||
if (state_.hasEnded(EndingState::POST_CREDITS)) {
|
||||
state_.set(EndingState::FADING, STATE_FADE_DURATION_);
|
||||
}
|
||||
break;
|
||||
|
||||
case EndingState::FADING:
|
||||
if (state_.hasEnded(EndingState::FADING))
|
||||
{
|
||||
if (state_.hasEnded(EndingState::FADING)) {
|
||||
options.section.section = Section::LOGO;
|
||||
options.section.subsection = Subsection::LOGO_TO_INTRO;
|
||||
}
|
||||
@@ -207,8 +192,7 @@ void Ending2::updateState()
|
||||
}
|
||||
|
||||
// Inicializa la lista de sprites
|
||||
void Ending2::iniSpriteList()
|
||||
{
|
||||
void Ending2::iniSpriteList() {
|
||||
// Reinicia el vector
|
||||
sprite_list_.clear();
|
||||
|
||||
@@ -285,15 +269,13 @@ void Ending2::iniSpriteList()
|
||||
}
|
||||
|
||||
// Carga todos los sprites desde una lista
|
||||
void Ending2::loadSprites()
|
||||
{
|
||||
void Ending2::loadSprites() {
|
||||
// Inicializa variables
|
||||
sprite_max_width_ = 0;
|
||||
sprite_max_height_ = 0;
|
||||
|
||||
// Carga los sprites
|
||||
for (const auto &file : sprite_list_)
|
||||
{
|
||||
for (const auto& file : sprite_list_) {
|
||||
sprites_.emplace_back(std::make_shared<SAnimatedSprite>(Resource::get()->getSurface(file + ".gif"), Resource::get()->getAnimations(file + ".ani")));
|
||||
sprite_max_width_ = std::max(sprites_.back()->getWidth(), sprite_max_width_);
|
||||
sprite_max_height_ = std::max(sprites_.back()->getHeight(), sprite_max_height_);
|
||||
@@ -301,42 +283,33 @@ void Ending2::loadSprites()
|
||||
}
|
||||
|
||||
// Actualiza los sprites
|
||||
void Ending2::updateSprites()
|
||||
{
|
||||
for (auto sprite : sprites_)
|
||||
{
|
||||
void Ending2::updateSprites() {
|
||||
for (auto sprite : sprites_) {
|
||||
sprite->update();
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza los sprites de texto
|
||||
void Ending2::updateTextSprites()
|
||||
{
|
||||
for (auto sprite : sprite_texts_)
|
||||
{
|
||||
void Ending2::updateTextSprites() {
|
||||
for (auto sprite : sprite_texts_) {
|
||||
sprite->update();
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza los sprites de texto del final
|
||||
void Ending2::updateTexts()
|
||||
{
|
||||
for (auto sprite : texts_)
|
||||
{
|
||||
void Ending2::updateTexts() {
|
||||
for (auto sprite : texts_) {
|
||||
sprite->update();
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja los sprites
|
||||
void Ending2::renderSprites()
|
||||
{
|
||||
void Ending2::renderSprites() {
|
||||
const Uint8 colorA = static_cast<Uint8>(PaletteColor::RED);
|
||||
for (auto sprite : sprites_)
|
||||
{
|
||||
for (auto sprite : sprites_) {
|
||||
const bool A = sprite->getRect().y + sprite->getRect().h > 0;
|
||||
const bool B = sprite->getRect().y < options.game.height;
|
||||
if (A && B)
|
||||
{
|
||||
if (A && B) {
|
||||
sprite->render(1, colorA);
|
||||
}
|
||||
}
|
||||
@@ -347,39 +320,31 @@ void Ending2::renderSprites()
|
||||
}
|
||||
|
||||
// Dibuja los sprites con el texto
|
||||
void Ending2::renderSpriteTexts()
|
||||
{
|
||||
void Ending2::renderSpriteTexts() {
|
||||
const Uint8 color = static_cast<Uint8>(PaletteColor::WHITE);
|
||||
for (auto sprite : sprite_texts_)
|
||||
{
|
||||
for (auto sprite : sprite_texts_) {
|
||||
const bool A = sprite->getRect().y + sprite->getRect().h > 0;
|
||||
const bool B = sprite->getRect().y < options.game.height;
|
||||
if (A && B)
|
||||
{
|
||||
if (A && B) {
|
||||
sprite->render(1, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja los sprites con el texto del final
|
||||
void Ending2::renderTexts()
|
||||
{
|
||||
for (auto sprite : texts_)
|
||||
{
|
||||
void Ending2::renderTexts() {
|
||||
for (auto sprite : texts_) {
|
||||
const bool A = sprite->getRect().y + sprite->getRect().h > 0;
|
||||
const bool B = sprite->getRect().y < options.game.height;
|
||||
if (A && B)
|
||||
{
|
||||
if (A && B) {
|
||||
sprite->render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Coloca los sprites en su sito
|
||||
void Ending2::placeSprites()
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>(sprites_.size()); ++i)
|
||||
{
|
||||
void Ending2::placeSprites() {
|
||||
for (int i = 0; i < static_cast<int>(sprites_.size()); ++i) {
|
||||
const int X = i % 2 == 0 ? FIRST_COL_ : SECOND_COL_;
|
||||
const int Y = (i / 1) * (sprite_max_height_ + DIST_SPRITE_TEXT_ + Resource::get()->getText("smb2")->getCharacterSize() + DIST_SPRITE_SPRITE_) + options.game.height + 40;
|
||||
const int W = sprites_.at(i)->getWidth();
|
||||
@@ -399,18 +364,15 @@ void Ending2::placeSprites()
|
||||
}
|
||||
|
||||
// Crea los sprites con las texturas con los textos
|
||||
void Ending2::createSpriteTexts()
|
||||
{
|
||||
void Ending2::createSpriteTexts() {
|
||||
// Crea los sprites de texto a partir de la lista
|
||||
for (int i = 0; i < static_cast<int>(sprite_list_.size()); ++i)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>(sprite_list_.size()); ++i) {
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
|
||||
// Procesa y ajusta el texto del sprite actual
|
||||
std::string txt = sprite_list_[i];
|
||||
std::replace(txt.begin(), txt.end(), '_', ' '); // Reemplaza '_' por ' '
|
||||
if (txt == "player")
|
||||
{
|
||||
if (txt == "player") {
|
||||
txt = "JAILDOCTOR"; // Reemplaza "player" por "JAILDOCTOR"
|
||||
}
|
||||
|
||||
@@ -441,8 +403,7 @@ void Ending2::createSpriteTexts()
|
||||
}
|
||||
|
||||
// Crea los sprites con las texturas con los textos del final
|
||||
void Ending2::createTexts()
|
||||
{
|
||||
void Ending2::createTexts() {
|
||||
// Crea los primeros textos
|
||||
std::vector<std::string> list;
|
||||
list.push_back("STARRING");
|
||||
@@ -450,8 +411,7 @@ void Ending2::createTexts()
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
|
||||
// Crea los sprites de texto a partir de la lista
|
||||
for (int i = 0; i < (int)list.size(); ++i)
|
||||
{
|
||||
for (int i = 0; i < (int)list.size(); ++i) {
|
||||
// Calcula constantes
|
||||
const int w = text->lenght(list[i], 1);
|
||||
const int h = text->getCharacterSize();
|
||||
@@ -480,8 +440,7 @@ void Ending2::createTexts()
|
||||
list.push_back("FOR PLAYING!");
|
||||
|
||||
// Crea los sprites de texto a partir de la lista
|
||||
for (int i = 0; i < (int)list.size(); ++i)
|
||||
{
|
||||
for (int i = 0; i < (int)list.size(); ++i) {
|
||||
// Calcula constantes
|
||||
const int w = text->lenght(list[i], 1);
|
||||
const int h = text->getCharacterSize();
|
||||
@@ -504,17 +463,14 @@ void Ending2::createTexts()
|
||||
}
|
||||
|
||||
// Actualiza el fade final
|
||||
void Ending2::updateFinalFade()
|
||||
{
|
||||
for (auto sprite : texts_)
|
||||
{
|
||||
void Ending2::updateFinalFade() {
|
||||
for (auto sprite : texts_) {
|
||||
sprite->getSurface()->fadeSubPalette(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el volumen de la musica
|
||||
void Ending2::updateMusicVolume()
|
||||
{
|
||||
void Ending2::updateMusicVolume() {
|
||||
// Constante para la duración en milisegundos
|
||||
constexpr Uint32 VOLUME_FADE_DURATION = 3000;
|
||||
|
||||
140
source/sections/ending2.h
Normal file
140
source/sections/ending2.h
Normal file
@@ -0,0 +1,140 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint32, Uint8
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "defines.h" // Para GAMECANVAS_WIDTH, GAMECANVAS_FIRST_QUAR...
|
||||
class SAnimatedSprite; // lines 9-9
|
||||
class SMovingSprite; // lines 10-10
|
||||
|
||||
class Ending2 {
|
||||
private:
|
||||
// Enum para representar los estados del final
|
||||
enum class EndingState : int {
|
||||
PRE_CREDITS, // Estado previo a los créditos
|
||||
CREDITS, // Estado de los créditos
|
||||
POST_CREDITS, // Estado posterior a los créditos
|
||||
FADING, // Estado de fundido de los textos a negrp
|
||||
};
|
||||
|
||||
// Estructura para controlar los estados y su duración
|
||||
struct State {
|
||||
EndingState state; // Estado actual
|
||||
Uint32 init_ticks; // Ticks en los que se inicializó el estado
|
||||
Uint32 duration; // Duración en milisegundos para el estado actual
|
||||
|
||||
// Constructor parametrizado para inicializar la estructura
|
||||
State(EndingState initialState, Uint32 initialTicks, Uint32 stateDuration)
|
||||
: state(initialState),
|
||||
init_ticks(initialTicks),
|
||||
duration(stateDuration) {}
|
||||
|
||||
// Método para comprobar si el estado ha terminado y verifica el nombre del estado
|
||||
bool hasEnded(EndingState expectedState) const {
|
||||
// Comprobar si el estado actual coincide con el estado esperado
|
||||
if (state != expectedState) {
|
||||
return false; // Si no coincide, considerar que no ha terminado
|
||||
}
|
||||
|
||||
// Comprobar si el tiempo transcurrido excede la duración
|
||||
return (SDL_GetTicks() - init_ticks) >= duration;
|
||||
}
|
||||
|
||||
// Método para establecer un nuevo estado
|
||||
void set(EndingState newState, Uint32 newDuration) {
|
||||
state = newState; // Actualizar el estado
|
||||
init_ticks = SDL_GetTicks(); // Reiniciar el tiempo de inicio
|
||||
duration = newDuration; // Actualizar la duración
|
||||
}
|
||||
};
|
||||
|
||||
// Constantes
|
||||
static constexpr int FIRST_COL_ = GAMECANVAS_FIRST_QUARTER_X + (GAMECANVAS_WIDTH / 16); // Primera columna por donde desfilan los sprites
|
||||
static constexpr int SECOND_COL_ = GAMECANVAS_THIRD_QUARTER_X - (GAMECANVAS_WIDTH / 16); // Segunda columna por donde desfilan los sprites
|
||||
static constexpr int DIST_SPRITE_TEXT_ = 8; // Distancia entre el sprite y el texto que lo acompaña
|
||||
static constexpr int DIST_SPRITE_SPRITE_ = 0; // Distancia entre dos sprites de la misma columna
|
||||
static constexpr float SPRITE_DESP_SPEED_ = -0.2f; // Velocidad de desplazamiento de los sprites
|
||||
static constexpr int STATE_PRE_CREDITS_DURATION_ = 3000;
|
||||
static constexpr int STATE_POST_CREDITS_DURATION_ = 5000;
|
||||
static constexpr int STATE_FADE_DURATION_ = 5000;
|
||||
|
||||
// Objetos y punteros
|
||||
std::vector<std::shared_ptr<SAnimatedSprite>> sprites_; // Vector con todos los sprites a dibujar
|
||||
std::vector<std::shared_ptr<SMovingSprite>> sprite_texts_; // Vector con los sprites de texto de los sprites
|
||||
std::vector<std::shared_ptr<SMovingSprite>> texts_; // Vector con los sprites de texto
|
||||
|
||||
// Variables
|
||||
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
std::vector<std::string> sprite_list_; // Lista con todos los sprites a dibujar
|
||||
std::vector<Uint8> colors_; // Vector con los colores para el fade
|
||||
int sprite_max_width_ = 0; // El valor de ancho del sprite mas ancho
|
||||
int sprite_max_height_ = 0; // El valor de alto del sprite mas alto
|
||||
State state_; // Controla el estado de la clase
|
||||
|
||||
// Actualiza el objeto
|
||||
void update();
|
||||
|
||||
// Dibuja el final en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void checkEvents();
|
||||
|
||||
// Comprueba las entradas
|
||||
void checkInput();
|
||||
|
||||
// Actualiza el estado
|
||||
void updateState();
|
||||
|
||||
// Inicializa la lista de sprites
|
||||
void iniSpriteList();
|
||||
|
||||
// Carga todos los sprites desde una lista
|
||||
void loadSprites();
|
||||
|
||||
// Actualiza los sprites
|
||||
void updateSprites();
|
||||
|
||||
// Actualiza los sprites de texto
|
||||
void updateTextSprites();
|
||||
|
||||
// Actualiza los sprites de texto del final
|
||||
void updateTexts();
|
||||
|
||||
// Dibuja los sprites
|
||||
void renderSprites();
|
||||
|
||||
// Dibuja los sprites con el texto
|
||||
void renderSpriteTexts();
|
||||
|
||||
// Dibuja los sprites con el texto del final
|
||||
void renderTexts();
|
||||
|
||||
// Coloca los sprites en su sito
|
||||
void placeSprites();
|
||||
|
||||
// Crea los sprites con las texturas con los textos
|
||||
void createSpriteTexts();
|
||||
|
||||
// Crea los sprites con las texturas con los textos del final
|
||||
void createTexts();
|
||||
|
||||
// Actualiza el fade final
|
||||
void updateFinalFade();
|
||||
|
||||
// Actualiza el volumen de la musica
|
||||
void updateMusicVolume();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Ending2();
|
||||
|
||||
// Destructor
|
||||
~Ending2() = default;
|
||||
|
||||
// Bucle principal
|
||||
void run();
|
||||
};
|
||||
622
source/sections/game.cpp
Normal file
622
source/sections/game.cpp
Normal file
@@ -0,0 +1,622 @@
|
||||
#include "game.h"
|
||||
|
||||
#include <SDL3/SDL_render.h> // Para SDL_FLIP_HORIZONTAL
|
||||
#include <SDL3/SDL_scancode.h> // Para SDL_SCANCODE_7, SDL_SCANCODE_A, SDL_S...
|
||||
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "asset.h" // Para Asset
|
||||
#include "cheevos.h" // Para Cheevos
|
||||
#include "debug.h" // Para Debug
|
||||
#include "defines.h" // Para BLOCK, PLAY_AREA_HEIGHT, RoomBorder::BOTTOM
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
#include "input.h" // Para Input, InputAction, INPUT_DO_NOT_ALLOW_REPEAT
|
||||
#include "item_tracker.h" // Para ItemTracker
|
||||
#include "jail_audio.h" // Para JA_PauseMusic, JA_GetMusicState, JA_P...
|
||||
#include "notifier.h" // Para Notifier, NotificationText, CHEEVO_NO...
|
||||
#include "options.h" // Para Options, options, Cheat, SectionState
|
||||
#include "resource.h" // Para ResourceRoom, Resource
|
||||
#include "room.h" // Para Room, RoomData
|
||||
#include "room_tracker.h" // Para RoomTracker
|
||||
#include "scoreboard.h" // Para ScoreboardData, Scoreboard
|
||||
#include "screen.h" // Para Screen
|
||||
#include "stats.h" // Para Stats
|
||||
#include "surface.h" // Para Surface
|
||||
#include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR
|
||||
#include "utils.h" // Para PaletteColor, stringToColor
|
||||
|
||||
// Constructor
|
||||
Game::Game(GameMode mode)
|
||||
: board_(std::make_shared<ScoreboardData>(0, 9, 0, true, 0, SDL_GetTicks(), options.cheats.jail_is_open == Cheat::CheatState::ENABLED)),
|
||||
scoreboard_(std::make_shared<Scoreboard>(board_)),
|
||||
room_tracker_(std::make_shared<RoomTracker>()),
|
||||
stats_(std::make_shared<Stats>(Asset::get()->get("stats.csv"), Asset::get()->get("stats_buffer.csv"))),
|
||||
mode_(mode),
|
||||
#ifdef DEBUG
|
||||
current_room_("03.room"),
|
||||
spawn_point_(PlayerSpawn(25 * BLOCK, 13 * BLOCK, 0, 0, 0, PlayerState::STANDING, SDL_FLIP_HORIZONTAL))
|
||||
#else
|
||||
current_room_("03.room"),
|
||||
spawn_point_(PlayerSpawn(25 * BLOCK, 13 * BLOCK, 0, 0, 0, PlayerState::STANDING, SDL_FLIP_HORIZONTAL))
|
||||
#endif
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Debug::get()->setEnabled(false);
|
||||
#endif
|
||||
|
||||
// Crea objetos e inicializa variables
|
||||
ItemTracker::init();
|
||||
DEMO_init();
|
||||
room_ = std::make_shared<Room>(current_room_, board_);
|
||||
initPlayer(spawn_point_, room_);
|
||||
initStats();
|
||||
total_items_ = getTotalItems();
|
||||
|
||||
createRoomNameTexture();
|
||||
changeRoom(current_room_);
|
||||
|
||||
Cheevos::get()->enable(!options.cheats.enabled()); // Deshabilita los logros si hay trucos activados
|
||||
Cheevos::get()->clearUnobtainableState();
|
||||
|
||||
options.section.section = (mode_ == GameMode::GAME) ? Section::GAME : Section::DEMO;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
}
|
||||
|
||||
Game::~Game() {
|
||||
ItemTracker::destroy();
|
||||
}
|
||||
|
||||
// Comprueba los eventos de la cola
|
||||
void Game::checkEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
globalEvents::check(event);
|
||||
#ifdef DEBUG
|
||||
checkDebugEvents(event);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba el teclado
|
||||
void Game::checkInput() {
|
||||
if (Input::get()->checkInput(InputAction::TOGGLE_MUSIC, INPUT_DO_NOT_ALLOW_REPEAT)) {
|
||||
board_->music = !board_->music;
|
||||
board_->music ? JA_ResumeMusic() : JA_PauseMusic();
|
||||
Notifier::get()->show({"MUSIC " + std::string(board_->music ? "ENABLED" : "DISABLED")}, NotificationText::CENTER);
|
||||
}
|
||||
|
||||
else if (Input::get()->checkInput(InputAction::PAUSE, INPUT_DO_NOT_ALLOW_REPEAT)) {
|
||||
togglePause();
|
||||
Notifier::get()->show({std::string(paused_ ? "GAME PAUSED" : "GAME RUNNING")}, NotificationText::CENTER);
|
||||
}
|
||||
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Bucle para el juego
|
||||
void Game::run() {
|
||||
keepMusicPlaying();
|
||||
if (!board_->music && mode_ == GameMode::GAME) {
|
||||
JA_PauseMusic();
|
||||
}
|
||||
|
||||
while (options.section.section == Section::GAME || options.section.section == Section::DEMO) {
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
}
|
||||
|
||||
if (mode_ == GameMode::GAME) {
|
||||
JA_StopMusic();
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el juego, las variables, comprueba la entrada, etc.
|
||||
void Game::update() {
|
||||
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED) {
|
||||
// Actualiza el contador de ticks
|
||||
ticks_ = SDL_GetTicks();
|
||||
|
||||
// Comprueba el teclado
|
||||
checkInput();
|
||||
|
||||
#ifdef DEBUG
|
||||
Debug::get()->clear();
|
||||
#endif
|
||||
|
||||
// Actualiza los objetos
|
||||
room_->update();
|
||||
if (mode_ == GameMode::GAME) {
|
||||
player_->update();
|
||||
checkPlayerIsOnBorder();
|
||||
checkPlayerAndItems();
|
||||
checkPlayerAndEnemies();
|
||||
checkIfPlayerIsAlive();
|
||||
checkGameOver();
|
||||
checkEndGame();
|
||||
checkRestoringJail();
|
||||
checkSomeCheevos();
|
||||
}
|
||||
DEMO_checkRoomChange();
|
||||
scoreboard_->update();
|
||||
keepMusicPlaying();
|
||||
updateBlackScreen();
|
||||
|
||||
Screen::get()->update();
|
||||
|
||||
#ifdef DEBUG
|
||||
updateDebugInfo();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Pinta los objetos en pantalla
|
||||
void Game::render() {
|
||||
// Prepara para dibujar el frame
|
||||
Screen::get()->start();
|
||||
|
||||
// Dibuja los elementos del juego en orden
|
||||
room_->renderMap();
|
||||
room_->renderEnemies();
|
||||
room_->renderItems();
|
||||
if (mode_ == GameMode::GAME) {
|
||||
player_->render();
|
||||
}
|
||||
renderRoomName();
|
||||
scoreboard_->render();
|
||||
renderBlackScreen();
|
||||
|
||||
#ifdef DEBUG
|
||||
// Debug info
|
||||
renderDebugInfo();
|
||||
#endif
|
||||
|
||||
// Actualiza la pantalla
|
||||
Screen::get()->render();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// Pasa la información de debug
|
||||
void Game::updateDebugInfo() {
|
||||
Debug::get()->add("X = " + std::to_string(static_cast<int>(player_->x_)) + ", Y = " + std::to_string(static_cast<int>(player_->y_)));
|
||||
Debug::get()->add("VX = " + std::to_string(player_->vx_).substr(0, 4) + ", VY = " + std::to_string(player_->vy_).substr(0, 4));
|
||||
Debug::get()->add("STATE = " + std::to_string(static_cast<int>(player_->state_)));
|
||||
}
|
||||
|
||||
// Pone la información de debug en pantalla
|
||||
void Game::renderDebugInfo() {
|
||||
if (!Debug::get()->getEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto surface = Screen::get()->getRendererSurface();
|
||||
|
||||
// Borra el marcador
|
||||
SDL_Rect rect = {0, 18 * BLOCK, PLAY_AREA_WIDTH, GAMECANVAS_HEIGHT - PLAY_AREA_HEIGHT};
|
||||
surface->fillRect(&rect, static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
// Pinta la rejilla
|
||||
/*for (int i = 0; i < PLAY_AREA_BOTTOM; i += 8)
|
||||
{
|
||||
// Lineas horizontales
|
||||
surface->drawLine(0, i, PLAY_AREA_RIGHT, i, static_cast<Uint8>(PaletteColor::BRIGHT_BLACK));
|
||||
}
|
||||
for (int i = 0; i < PLAY_AREA_RIGHT; i += 8)
|
||||
{
|
||||
// Lineas verticales
|
||||
surface->drawLine(i, 0, i, PLAY_AREA_BOTTOM - 1, static_cast<Uint8>(PaletteColor::BRIGHT_BLACK));
|
||||
}*/
|
||||
|
||||
// Pinta el texto
|
||||
Debug::get()->setPos({1, 18 * 8});
|
||||
Debug::get()->render();
|
||||
}
|
||||
|
||||
// Comprueba los eventos
|
||||
void Game::checkDebugEvents(const SDL_Event& event) {
|
||||
if (event.type == SDL_KEYDOWN && event.key.repeat == 0) {
|
||||
switch (event.key.keysym.scancode) {
|
||||
case SDL_SCANCODE_G:
|
||||
Debug::get()->toggleEnabled();
|
||||
options.cheats.invincible = static_cast<Cheat::CheatState>(Debug::get()->getEnabled());
|
||||
board_->music = !Debug::get()->getEnabled();
|
||||
board_->music ? JA_ResumeMusic() : JA_PauseMusic();
|
||||
break;
|
||||
|
||||
case SDL_SCANCODE_R:
|
||||
Resource::get()->reload();
|
||||
break;
|
||||
|
||||
case SDL_SCANCODE_W:
|
||||
changeRoom(room_->getRoom(RoomBorder::TOP));
|
||||
break;
|
||||
|
||||
case SDL_SCANCODE_A:
|
||||
changeRoom(room_->getRoom(RoomBorder::LEFT));
|
||||
break;
|
||||
|
||||
case SDL_SCANCODE_S:
|
||||
changeRoom(room_->getRoom(RoomBorder::BOTTOM));
|
||||
break;
|
||||
|
||||
case SDL_SCANCODE_D:
|
||||
changeRoom(room_->getRoom(RoomBorder::RIGHT));
|
||||
break;
|
||||
|
||||
case SDL_SCANCODE_7:
|
||||
Notifier::get()->show({"ACHIEVEMENT UNLOCKED!", "I LIKE MY MULTICOLOURED FRIENDS"}, NotificationText::CENTER, CHEEVO_NOTIFICATION_DURATION, -1, false, "F7");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Escribe el nombre de la pantalla
|
||||
void Game::renderRoomName() {
|
||||
// Dibuja la textura con el nombre de la habitación
|
||||
room_name_surface_->render(nullptr, &room_name_rect_);
|
||||
}
|
||||
|
||||
// Cambia de habitación
|
||||
bool Game::changeRoom(const std::string& room_path) {
|
||||
// En las habitaciones los limites tienen la cadena del fichero o un 0 en caso de no limitar con nada
|
||||
if (room_path == "0") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verifica que exista el fichero que se va a cargar
|
||||
if (Asset::get()->get(room_path) != "") {
|
||||
// Crea un objeto habitación nuevo a partir del fichero
|
||||
room_ = std::make_shared<Room>(room_path, board_);
|
||||
|
||||
// Pone el nombre de la habitación en la textura
|
||||
fillRoomNameTexture();
|
||||
|
||||
// Pone el color del marcador en función del color del borde de la habitación
|
||||
setScoreBoardColor();
|
||||
|
||||
if (room_tracker_->addRoom(room_path)) {
|
||||
// Incrementa el contador de habitaciones visitadas
|
||||
board_->rooms++;
|
||||
options.stats.rooms = board_->rooms;
|
||||
|
||||
// Actualiza las estadisticas
|
||||
stats_->addVisit(room_->getName());
|
||||
}
|
||||
|
||||
// Pasa la nueva habitación al jugador
|
||||
player_->setRoom(room_);
|
||||
|
||||
// Cambia la habitación actual
|
||||
current_room_ = room_path;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si el jugador esta en el borde de la pantalla
|
||||
void Game::checkPlayerIsOnBorder() {
|
||||
if (player_->getOnBorder()) {
|
||||
const std::string roomName = room_->getRoom(player_->getBorder());
|
||||
if (changeRoom(roomName)) {
|
||||
player_->switchBorders();
|
||||
spawn_point_ = player_->getSpawnParams();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las colisiones del jugador con los enemigos
|
||||
bool Game::checkPlayerAndEnemies() {
|
||||
const bool death = room_->enemyCollision(player_->getCollider());
|
||||
if (death) {
|
||||
killPlayer();
|
||||
}
|
||||
return death;
|
||||
}
|
||||
|
||||
// Comprueba las colisiones del jugador con los objetos
|
||||
void Game::checkPlayerAndItems() {
|
||||
room_->itemCollision(player_->getCollider());
|
||||
}
|
||||
|
||||
// Comprueba si el jugador esta vivo
|
||||
void Game::checkIfPlayerIsAlive() {
|
||||
if (!player_->isAlive()) {
|
||||
killPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba si ha terminado la partida
|
||||
void Game::checkGameOver() {
|
||||
if (board_->lives < 0 && black_screen_counter_ > 17) {
|
||||
options.section.section = Section::GAME_OVER;
|
||||
}
|
||||
}
|
||||
|
||||
// Mata al jugador
|
||||
void Game::killPlayer() {
|
||||
if (options.cheats.invincible == Cheat::CheatState::ENABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Resta una vida al jugador
|
||||
if (options.cheats.infinite_lives == Cheat::CheatState::DISABLED) {
|
||||
--board_->lives;
|
||||
}
|
||||
|
||||
// Actualiza las estadisticas
|
||||
stats_->addDeath(room_->getName());
|
||||
|
||||
// Invalida el logro de pasarse el juego sin morir
|
||||
Cheevos::get()->setUnobtainable(11);
|
||||
|
||||
// Sonido
|
||||
JA_PlaySound(Resource::get()->getSound("death.wav"));
|
||||
|
||||
// Pone la pantalla en negro un tiempo
|
||||
setBlackScreen();
|
||||
|
||||
// Crea la nueva habitación y el nuevo jugador
|
||||
room_ = std::make_shared<Room>(current_room_, board_);
|
||||
initPlayer(spawn_point_, room_);
|
||||
|
||||
// Pone los objetos en pausa mientras esta la habitación en negro
|
||||
room_->setPaused(true);
|
||||
player_->setPaused(true);
|
||||
}
|
||||
|
||||
// Establece la pantalla en negro
|
||||
void Game::setBlackScreen() {
|
||||
black_screen_ = true;
|
||||
}
|
||||
|
||||
// Actualiza las variables relativas a la pantalla en negro
|
||||
void Game::updateBlackScreen() {
|
||||
if (black_screen_) {
|
||||
black_screen_counter_++;
|
||||
if (black_screen_counter_ > 20) {
|
||||
black_screen_ = false;
|
||||
black_screen_counter_ = 0;
|
||||
|
||||
player_->setPaused(false);
|
||||
room_->setPaused(false);
|
||||
Screen::get()->setBorderColor(room_->getBorderColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja la pantalla negra
|
||||
void Game::renderBlackScreen() {
|
||||
if (black_screen_) {
|
||||
auto const color = static_cast<Uint8>(PaletteColor::BLACK);
|
||||
Screen::get()->setRendererSurface();
|
||||
Screen::get()->clearSurface(color);
|
||||
Screen::get()->setBorderColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
// Pone el color del marcador en función del color del borde de la habitación
|
||||
void Game::setScoreBoardColor() {
|
||||
// Obtiene el color del borde
|
||||
const Uint8 BORDER_COLOR = room_->getBorderColor();
|
||||
|
||||
const bool IS_BLACK = BORDER_COLOR == static_cast<Uint8>(PaletteColor::BLACK);
|
||||
const bool IS_BRIGHT_BLACK = BORDER_COLOR == static_cast<Uint8>(PaletteColor::BRIGHT_BLACK);
|
||||
|
||||
// Si el color del borde es negro o negro brillante cambia el texto del marcador a blanco
|
||||
board_->color = IS_BLACK || IS_BRIGHT_BLACK ? static_cast<Uint8>(PaletteColor::WHITE) : BORDER_COLOR;
|
||||
}
|
||||
|
||||
// Comprueba si ha finalizado el juego
|
||||
bool Game::checkEndGame() {
|
||||
const bool isOnTheRoom = room_->getName() == "THE JAIL"; // Estar en la habitación que toca
|
||||
const bool haveTheItems = board_->items >= int(total_items_ * 0.9f) || options.cheats.jail_is_open == Cheat::CheatState::ENABLED; // Con mas del 90% de los items recogidos
|
||||
const bool isOnTheDoor = player_->getRect().x <= 128; // Y en la ubicación que toca (En la puerta)
|
||||
|
||||
if (haveTheItems) {
|
||||
board_->jail_is_open = true;
|
||||
}
|
||||
|
||||
if (haveTheItems && isOnTheRoom && isOnTheDoor) {
|
||||
// Comprueba los logros de completar el juego
|
||||
checkEndGameCheevos();
|
||||
|
||||
options.section.section = Section::ENDING;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Obtiene la cantidad total de items que hay en el mapeado del juego
|
||||
int Game::getTotalItems() {
|
||||
int items = 0;
|
||||
auto rooms = Resource::get()->getRooms();
|
||||
|
||||
for (const auto& room : rooms) {
|
||||
items += room.room->items.size();
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
// Pone el juego en pausa
|
||||
void Game::togglePause() {
|
||||
paused_ = !paused_;
|
||||
|
||||
player_->setPaused(paused_);
|
||||
room_->setPaused(paused_);
|
||||
scoreboard_->setPaused(paused_);
|
||||
}
|
||||
|
||||
// Da vidas al jugador cuando está en la Jail
|
||||
void Game::checkRestoringJail() {
|
||||
if (room_->getName() != "THE JAIL" || board_->lives == 9) {
|
||||
return;
|
||||
}
|
||||
|
||||
static int counter = 0;
|
||||
|
||||
if (!paused_) {
|
||||
counter++;
|
||||
}
|
||||
|
||||
// Incrementa el numero de vidas
|
||||
if (counter == 100) {
|
||||
counter = 0;
|
||||
board_->lives++;
|
||||
JA_PlaySound(Resource::get()->getSound("death.wav"));
|
||||
|
||||
// Invalida el logro de completar el juego sin entrar a la jail
|
||||
const bool haveTheItems = board_->items >= int(total_items_ * 0.9f);
|
||||
if (!haveTheItems) {
|
||||
Cheevos::get()->setUnobtainable(9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Inicializa el diccionario de las estadísticas
|
||||
void Game::initStats() {
|
||||
auto rooms = Resource::get()->getRooms();
|
||||
|
||||
for (const auto& room : rooms) {
|
||||
stats_->addDictionary(room.room->number, room.room->name);
|
||||
}
|
||||
|
||||
stats_->init();
|
||||
}
|
||||
|
||||
// Crea la textura con el nombre de la habitación
|
||||
void Game::fillRoomNameTexture() {
|
||||
// Pone la textura como destino de renderizado
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(room_name_surface_);
|
||||
|
||||
// Rellena la textura de color
|
||||
room_name_surface_->clear(stringToColor("white"));
|
||||
|
||||
// Escribe el texto en la textura
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, text->getCharacterSize() / 2, room_->getName(), 1, room_->getBGColor());
|
||||
|
||||
// Deja el renderizador por defecto
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
}
|
||||
|
||||
// Comprueba algunos logros
|
||||
void Game::checkSomeCheevos() {
|
||||
auto cheevos = Cheevos::get();
|
||||
|
||||
// Logros sobre la cantidad de items
|
||||
if (board_->items == total_items_) {
|
||||
cheevos->unlock(4);
|
||||
cheevos->unlock(3);
|
||||
cheevos->unlock(2);
|
||||
cheevos->unlock(1);
|
||||
} else if (board_->items >= total_items_ * 0.75f) {
|
||||
cheevos->unlock(3);
|
||||
cheevos->unlock(2);
|
||||
cheevos->unlock(1);
|
||||
} else if (board_->items >= total_items_ * 0.5f) {
|
||||
cheevos->unlock(2);
|
||||
cheevos->unlock(1);
|
||||
} else if (board_->items >= total_items_ * 0.25f) {
|
||||
cheevos->unlock(1);
|
||||
}
|
||||
|
||||
// Logros sobre las habitaciones visitadas
|
||||
if (board_->rooms >= 60) {
|
||||
cheevos->unlock(7);
|
||||
cheevos->unlock(6);
|
||||
cheevos->unlock(5);
|
||||
} else if (board_->rooms >= 40) {
|
||||
cheevos->unlock(6);
|
||||
cheevos->unlock(5);
|
||||
} else if (board_->rooms >= 20) {
|
||||
cheevos->unlock(5);
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba los logros de completar el juego
|
||||
void Game::checkEndGameCheevos() {
|
||||
auto cheevos = Cheevos::get();
|
||||
|
||||
// "Complete the game"
|
||||
cheevos->unlock(8);
|
||||
|
||||
// "Complete the game without entering the jail"
|
||||
cheevos->unlock(9);
|
||||
|
||||
// "Complete the game with all items"
|
||||
if (board_->items == total_items_) {
|
||||
cheevos->unlock(10);
|
||||
}
|
||||
|
||||
// "Complete the game without dying"
|
||||
cheevos->unlock(11);
|
||||
|
||||
// "Complete the game in under 30 minutes"
|
||||
if (scoreboard_->getMinutes() < 30) {
|
||||
cheevos->unlock(12);
|
||||
}
|
||||
}
|
||||
|
||||
// Inicializa al jugador
|
||||
void Game::initPlayer(const PlayerSpawn& spawn_point, std::shared_ptr<Room> room) {
|
||||
std::string player_texture = options.cheats.alternate_skin == Cheat::CheatState::ENABLED ? "player2.gif" : "player.gif";
|
||||
std::string player_animations = options.cheats.alternate_skin == Cheat::CheatState::ENABLED ? "player2.ani" : "player.ani";
|
||||
const PlayerData player(spawn_point, player_texture, player_animations, room);
|
||||
player_ = std::make_shared<Player>(player);
|
||||
}
|
||||
|
||||
// Crea la textura para poner el nombre de la habitación
|
||||
void Game::createRoomNameTexture() {
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
room_name_surface_ = std::make_shared<Surface>(options.game.width, text->getCharacterSize() * 2);
|
||||
|
||||
// Establece el destino de la textura
|
||||
room_name_rect_ = {0, PLAY_AREA_HEIGHT, options.game.width, text->getCharacterSize() * 2};
|
||||
}
|
||||
|
||||
// Hace sonar la música
|
||||
void Game::keepMusicPlaying() {
|
||||
const std::string music_path = mode_ == GameMode::GAME ? "game.ogg" : "title.ogg";
|
||||
|
||||
// Si la música no está sonando
|
||||
if (JA_GetMusicState() == JA_MUSIC_INVALID || JA_GetMusicState() == JA_MUSIC_STOPPED) {
|
||||
JA_PlayMusic(Resource::get()->getMusic(music_path));
|
||||
}
|
||||
}
|
||||
|
||||
// DEMO MODE: Inicializa las variables para el modo demo
|
||||
void Game::DEMO_init() {
|
||||
if (mode_ == GameMode::DEMO) {
|
||||
demo_ = DemoData(0, 400, 0, {"04.room", "54.room", "20.room", "09.room", "05.room", "11.room", "31.room", "44.room"});
|
||||
current_room_ = demo_.rooms.front();
|
||||
}
|
||||
}
|
||||
|
||||
// DEMO MODE: Comprueba si se ha de cambiar de habitación
|
||||
void Game::DEMO_checkRoomChange() {
|
||||
if (mode_ == GameMode::DEMO) {
|
||||
demo_.counter++;
|
||||
if (demo_.counter == demo_.room_time) {
|
||||
demo_.counter = 0;
|
||||
demo_.room_index++;
|
||||
if (demo_.room_index == (int)demo_.rooms.size()) {
|
||||
options.section.section = Section::LOGO;
|
||||
options.section.subsection = Subsection::LOGO_TO_TITLE;
|
||||
} else {
|
||||
changeRoom(demo_.rooms[demo_.room_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
177
source/sections/game.h
Normal file
177
source/sections/game.h
Normal file
@@ -0,0 +1,177 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_events.h> // Para SDL_Event
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint32
|
||||
|
||||
#include <initializer_list> // Para initializer_list
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "player.h" // Para PlayerSpawn
|
||||
class Room; // lines 12-12
|
||||
class RoomTracker; // lines 13-13
|
||||
class Scoreboard; // lines 14-14
|
||||
class Stats; // lines 15-15
|
||||
class Surface;
|
||||
struct ScoreboardData; // lines 16-16
|
||||
|
||||
enum class GameMode {
|
||||
DEMO,
|
||||
GAME
|
||||
};
|
||||
|
||||
class Game {
|
||||
private:
|
||||
// Estructuras
|
||||
struct DemoData {
|
||||
int counter; // Contador para el modo demo
|
||||
int room_time; // Tiempo que se muestra cada habitación
|
||||
int room_index; // Índice para el vector de habitaciones
|
||||
std::vector<std::string> rooms; // Listado con los mapas de la demo
|
||||
|
||||
// Constructor por defecto
|
||||
DemoData()
|
||||
: counter(0),
|
||||
room_time(0),
|
||||
room_index(0),
|
||||
rooms({}) {}
|
||||
|
||||
// Constructor parametrizado
|
||||
DemoData(int counter, int room_time, int room_index, const std::vector<std::string>& rooms)
|
||||
: counter(counter),
|
||||
room_time(room_time),
|
||||
room_index(room_index),
|
||||
rooms(rooms) {}
|
||||
};
|
||||
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<ScoreboardData> board_; // Estructura con los datos del marcador
|
||||
std::shared_ptr<Scoreboard> scoreboard_; // Objeto encargado de gestionar el marcador
|
||||
std::shared_ptr<RoomTracker> room_tracker_; // Lleva el control de las habitaciones visitadas
|
||||
std::shared_ptr<Room> room_; // Objeto encargado de gestionar cada habitación del juego
|
||||
std::shared_ptr<Player> player_; // Objeto con el jugador
|
||||
std::shared_ptr<Stats> stats_; // Objeto encargado de gestionar las estadísticas
|
||||
std::shared_ptr<Surface> room_name_surface_; // Textura para escribir el nombre de la habitación
|
||||
|
||||
// Variables
|
||||
GameMode mode_; // Modo del juego
|
||||
DemoData demo_; // Variables para el modo demo
|
||||
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
std::string current_room_; // Fichero de la habitación actual
|
||||
PlayerSpawn spawn_point_; // Lugar de la habitación donde aparece el jugador
|
||||
bool paused_ = false; // Indica si el juego se encuentra en pausa
|
||||
bool black_screen_ = false; // Indica si la pantalla está en negro. Se utiliza para la muerte del jugador
|
||||
int black_screen_counter_ = 0; // Contador para temporizar la pantalla en negro
|
||||
int total_items_; // Cantidad total de items que hay en el mapeado del juego
|
||||
SDL_Rect room_name_rect_; // Rectangulo donde pintar la textura con el nombre de la habitación
|
||||
|
||||
// Actualiza el juego, las variables, comprueba la entrada, etc.
|
||||
void update();
|
||||
|
||||
// Pinta los objetos en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba los eventos de la cola
|
||||
void checkEvents();
|
||||
|
||||
#ifdef DEBUG
|
||||
// Pone la información de debug en pantalla
|
||||
void updateDebugInfo();
|
||||
|
||||
// Pone la información de debug en pantalla
|
||||
void renderDebugInfo();
|
||||
|
||||
// Comprueba los eventos
|
||||
void checkDebugEvents(const SDL_Event& event);
|
||||
#endif
|
||||
|
||||
// Escribe el nombre de la pantalla
|
||||
void renderRoomName();
|
||||
|
||||
// Cambia de habitación
|
||||
bool changeRoom(const std::string& file);
|
||||
|
||||
// Comprueba el teclado
|
||||
void checkInput();
|
||||
|
||||
// Comprueba si el jugador esta en el borde de la pantalla y actua
|
||||
void checkPlayerIsOnBorder();
|
||||
|
||||
// Comprueba las colisiones del jugador con los enemigos
|
||||
bool checkPlayerAndEnemies();
|
||||
|
||||
// Comprueba las colisiones del jugador con los objetos
|
||||
void checkPlayerAndItems();
|
||||
|
||||
// Comprueba si el jugador esta vivo
|
||||
void checkIfPlayerIsAlive();
|
||||
|
||||
// Comprueba si ha terminado la partida
|
||||
void checkGameOver();
|
||||
|
||||
// Mata al jugador
|
||||
void killPlayer();
|
||||
|
||||
// Establece la pantalla en negro
|
||||
void setBlackScreen();
|
||||
|
||||
// Actualiza las variables relativas a la pantalla en negro
|
||||
void updateBlackScreen();
|
||||
|
||||
// Dibuja la pantalla negra
|
||||
void renderBlackScreen();
|
||||
|
||||
// Pone el color del marcador en función del color del borde de la habitación
|
||||
void setScoreBoardColor();
|
||||
|
||||
// Comprueba si ha finalizado el juego
|
||||
bool checkEndGame();
|
||||
|
||||
// Obtiene la cantidad total de items que hay en el mapeado del juego
|
||||
int getTotalItems();
|
||||
|
||||
// Pone el juego en pausa
|
||||
void togglePause();
|
||||
|
||||
// Da vidas al jugador cuando está en la Jail
|
||||
void checkRestoringJail();
|
||||
|
||||
// Inicializa el diccionario de las estadísticas
|
||||
void initStats();
|
||||
|
||||
// Pone el nombre de la habitación en la textura
|
||||
void fillRoomNameTexture();
|
||||
|
||||
// Comprueba algunos logros
|
||||
void checkSomeCheevos();
|
||||
|
||||
// Comprueba los logros de completar el juego
|
||||
void checkEndGameCheevos();
|
||||
|
||||
// Inicializa al jugador
|
||||
void initPlayer(const PlayerSpawn& spawn_point, std::shared_ptr<Room> room);
|
||||
|
||||
// Crea la textura para poner el nombre de la habitación
|
||||
void createRoomNameTexture();
|
||||
|
||||
// Hace sonar la música
|
||||
void keepMusicPlaying();
|
||||
|
||||
// DEMO MODE: Inicializa las variables para el modo demo
|
||||
void DEMO_init();
|
||||
|
||||
// DEMO MODE: Comprueba si se ha de cambiar de habitación
|
||||
void DEMO_checkRoomChange();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
explicit Game(GameMode mode);
|
||||
|
||||
// Destructor
|
||||
~Game();
|
||||
|
||||
// Bucle para el juego
|
||||
void run();
|
||||
};
|
||||
@@ -1,8 +1,11 @@
|
||||
#include "game_over.h"
|
||||
#include <SDL2/SDL_events.h> // Para SDL_PollEvent, SDL_Event
|
||||
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <SDL3/SDL_events.h> // Para SDL_PollEvent, SDL_Event
|
||||
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <algorithm> // Para min, max
|
||||
#include <string> // Para basic_string, operator+, to_string
|
||||
|
||||
#include "defines.h" // Para GAMECANVAS_CENTER_X, GAME_SPEED
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
@@ -20,8 +23,7 @@ GameOver::GameOver()
|
||||
tv_sprite_(std::make_shared<SAnimatedSprite>(Resource::get()->getSurface("tv.gif"), Resource::get()->getAnimations("tv.ani"))),
|
||||
pre_counter_(0),
|
||||
counter_(0),
|
||||
ticks_(0)
|
||||
{
|
||||
ticks_(0) {
|
||||
options.section.section = Section::GAME_OVER;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
|
||||
@@ -34,19 +36,16 @@ GameOver::GameOver()
|
||||
|
||||
// Inicializa el vector de colores
|
||||
const std::vector<std::string> COLORS = {"white", "yellow", "cyan", "green", "magenta", "red", "blue", "black"};
|
||||
for (const auto &color : COLORS)
|
||||
{
|
||||
for (const auto& color : COLORS) {
|
||||
colors_.push_back(stringToColor(color));
|
||||
}
|
||||
color_ = colors_.back();
|
||||
}
|
||||
|
||||
// Actualiza el objeto
|
||||
void GameOver::update()
|
||||
{
|
||||
void GameOver::update() {
|
||||
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED)
|
||||
{
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED) {
|
||||
// Actualiza el contador de ticks
|
||||
ticks_ = SDL_GetTicks();
|
||||
|
||||
@@ -69,8 +68,7 @@ void GameOver::update()
|
||||
}
|
||||
|
||||
// Dibuja el final en pantalla
|
||||
void GameOver::render()
|
||||
{
|
||||
void GameOver::render() {
|
||||
constexpr int Y = 32;
|
||||
|
||||
Screen::get()->start();
|
||||
@@ -101,26 +99,21 @@ void GameOver::render()
|
||||
}
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void GameOver::checkEvents()
|
||||
{
|
||||
void GameOver::checkEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
while (SDL_PollEvent(&event)) {
|
||||
globalEvents::check(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las entradas
|
||||
void GameOver::checkInput()
|
||||
{
|
||||
void GameOver::checkInput() {
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Bucle principal
|
||||
void GameOver::run()
|
||||
{
|
||||
while (options.section.section == Section::GAME_OVER)
|
||||
{
|
||||
void GameOver::run() {
|
||||
while (options.section.section == Section::GAME_OVER) {
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
@@ -128,18 +121,14 @@ void GameOver::run()
|
||||
}
|
||||
|
||||
// Actualiza el color usado para renderizar los textos e imagenes
|
||||
void GameOver::updateColor()
|
||||
{
|
||||
void GameOver::updateColor() {
|
||||
const int half = COUNTER_SECTION_END_ / 2;
|
||||
|
||||
if (counter_ < half)
|
||||
{
|
||||
if (counter_ < half) {
|
||||
const float STEP = std::min(counter_, COUNTER_FADE_LENGHT_) / (float)COUNTER_FADE_LENGHT_;
|
||||
const int INDEX = (colors_.size() - 1) - int((colors_.size() - 1) * STEP);
|
||||
color_ = colors_[INDEX];
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
const float STEP = std::min(std::max(counter_, COUNTER_INIT_FADE_) - COUNTER_INIT_FADE_, COUNTER_FADE_LENGHT_) / (float)COUNTER_FADE_LENGHT_;
|
||||
const int INDEX = (colors_.size() - 1) * STEP;
|
||||
color_ = colors_[INDEX];
|
||||
@@ -147,34 +136,27 @@ void GameOver::updateColor()
|
||||
}
|
||||
|
||||
// Dibuja los sprites
|
||||
void GameOver::renderSprites()
|
||||
{
|
||||
void GameOver::renderSprites() {
|
||||
player_sprite_->render(1, color_);
|
||||
tv_sprite_->render(1, color_);
|
||||
}
|
||||
|
||||
// Actualiza los contadores
|
||||
void GameOver::updateCounters()
|
||||
{
|
||||
void GameOver::updateCounters() {
|
||||
// Actualiza el contador
|
||||
if (pre_counter_ < 50)
|
||||
{
|
||||
if (pre_counter_ < 50) {
|
||||
pre_counter_++;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
counter_++;
|
||||
}
|
||||
|
||||
// Hace sonar la música
|
||||
if (counter_ == 1)
|
||||
{
|
||||
if (counter_ == 1) {
|
||||
JA_PlayMusic(Resource::get()->getMusic("game_over.ogg"), 0);
|
||||
}
|
||||
|
||||
// Comprueba si ha terminado la sección
|
||||
else if (counter_ == COUNTER_SECTION_END_)
|
||||
{
|
||||
else if (counter_ == COUNTER_SECTION_END_) {
|
||||
options.section.section = Section::LOGO;
|
||||
options.section.subsection = Subsection::LOGO_TO_TITLE;
|
||||
}
|
||||
57
source/sections/game_over.h
Normal file
57
source/sections/game_over.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint8, Uint32
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <vector> // Para vector
|
||||
class SAnimatedSprite; // lines 7-7
|
||||
|
||||
class GameOver {
|
||||
private:
|
||||
// Constantes
|
||||
static constexpr int COUNTER_SECTION_END_ = 400; // Contador: cuando acaba la sección
|
||||
static constexpr int COUNTER_INIT_FADE_ = 310; // Contador: cuando emiepza el fade
|
||||
static constexpr int COUNTER_FADE_LENGHT_ = 20; // Contador: duración del fade
|
||||
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<SAnimatedSprite> player_sprite_; // Sprite con el jugador
|
||||
std::shared_ptr<SAnimatedSprite> tv_sprite_; // Sprite con el televisor
|
||||
|
||||
// Variables
|
||||
int pre_counter_ = 0; // Contador previo
|
||||
int counter_ = 0; // Contador
|
||||
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
std::vector<Uint8> colors_; // Vector con los colores para el fade
|
||||
Uint8 color_; // Color usado para el texto y los sprites
|
||||
|
||||
// Actualiza el objeto
|
||||
void update();
|
||||
|
||||
// Dibuja el final en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void checkEvents();
|
||||
|
||||
// Comprueba las entradas
|
||||
void checkInput();
|
||||
|
||||
// Actualiza el color usado para renderizar los textos e imagenes
|
||||
void updateColor();
|
||||
|
||||
// Dibuja los sprites
|
||||
void renderSprites();
|
||||
|
||||
// Actualiza los contadores
|
||||
void updateCounters();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
GameOver();
|
||||
|
||||
// Destructor
|
||||
~GameOver() = default;
|
||||
|
||||
// Bucle principal
|
||||
void run();
|
||||
};
|
||||
200
source/sections/loading_screen.cpp
Normal file
200
source/sections/loading_screen.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
#include "loading_screen.h"
|
||||
|
||||
#include <SDL3/SDL_events.h> // Para SDL_PollEvent, SDL_Event
|
||||
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
||||
#include <stdlib.h> // Para rand
|
||||
|
||||
#include "defines.h" // Para GAME_SPEED
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
#include "jail_audio.h" // Para JA_PlayMusic, JA_SetVolume, JA_StopMusic
|
||||
#include "options.h" // Para Options, options, SectionState, Options...
|
||||
#include "resource.h" // Para Resource
|
||||
#include "s_sprite.h" // Para SSprite
|
||||
#include "screen.h" // Para Screen
|
||||
#include "surface.h" // Para Surface
|
||||
#include "utils.h" // Para stringToColor, PaletteColor
|
||||
|
||||
// Constructor
|
||||
LoadingScreen::LoadingScreen()
|
||||
: mono_loading_screen_surface_(Resource::get()->getSurface("loading_screen_bn.gif")),
|
||||
color_loading_screen_surface_(Resource::get()->getSurface("loading_screen_color.gif")),
|
||||
mono_loading_screen_sprite_(std::make_shared<SSprite>(mono_loading_screen_surface_, 0, 0, mono_loading_screen_surface_->getWidth(), mono_loading_screen_surface_->getHeight())),
|
||||
color_loading_screen_sprite_(std::make_shared<SSprite>(color_loading_screen_surface_, 0, 0, color_loading_screen_surface_->getWidth(), color_loading_screen_surface_->getHeight())),
|
||||
screen_surface_(std::make_shared<Surface>(options.game.width, options.game.height)) {
|
||||
// Configura la superficie donde se van a pintar los sprites
|
||||
screen_surface_->clear(static_cast<Uint8>(PaletteColor::WHITE));
|
||||
|
||||
// Inicializa variables
|
||||
options.section.section = Section::LOADING_SCREEN;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
|
||||
// Establece el orden de las lineas para imitar el direccionamiento de memoria del spectrum
|
||||
for (int i = 0; i < 192; ++i) {
|
||||
if (i < 64) { // Primer bloque de 2K
|
||||
line_index_[i] = ((i % 8) * 8) + (i / 8);
|
||||
} else if (i < 128) { // Segundo bloque de 2K
|
||||
line_index_[i] = 64 + ((i % 8) * 8) + ((i - 64) / 8);
|
||||
} else { // Tercer bloque de 2K
|
||||
line_index_[i] = 128 + ((i % 8) * 8) + ((i - 128) / 8);
|
||||
}
|
||||
}
|
||||
|
||||
// Cambia el color del borde
|
||||
Screen::get()->setBorderColor(stringToColor("black"));
|
||||
}
|
||||
|
||||
// Destructor
|
||||
LoadingScreen::~LoadingScreen() {
|
||||
JA_StopMusic();
|
||||
}
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void LoadingScreen::checkEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
globalEvents::check(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las entradas
|
||||
void LoadingScreen::checkInput() {
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Gestiona el contador de carga
|
||||
void LoadingScreen::updateLoad() {
|
||||
// Primera parte de la carga, la parte en blanco y negro
|
||||
if (loading_first_part_) {
|
||||
// Cada 5 pasos el load_counter_ se incrementa en uno
|
||||
constexpr int NUM_STEPS = 5;
|
||||
constexpr int STEPS = 51;
|
||||
load_counter_ = counter_ / NUM_STEPS;
|
||||
|
||||
if (load_counter_ < 192) {
|
||||
load_rect_.x = STEPS * (counter_ % NUM_STEPS);
|
||||
load_rect_.y = line_index_[load_counter_];
|
||||
mono_loading_screen_sprite_->setClip(load_rect_);
|
||||
mono_loading_screen_sprite_->setPosition(load_rect_);
|
||||
}
|
||||
// Una vez actualizadas las 192 lineas, pasa a la segunda fase de la carga
|
||||
else if (load_counter_ == 192) {
|
||||
loading_first_part_ = false;
|
||||
load_counter_ = 0;
|
||||
load_rect_ = {0, 0, 16, 8};
|
||||
color_loading_screen_sprite_->setClip(load_rect_);
|
||||
color_loading_screen_sprite_->setPosition(load_rect_);
|
||||
JA_PlayMusic(Resource::get()->getMusic("loading_sound3.ogg"));
|
||||
}
|
||||
}
|
||||
// Segunda parte de la carga, la parte de los bloques en color
|
||||
else {
|
||||
load_counter_ += 2;
|
||||
load_rect_.x = (load_counter_ * 8) % 256;
|
||||
load_rect_.y = (load_counter_ / 32) * 8;
|
||||
color_loading_screen_sprite_->setClip(load_rect_);
|
||||
color_loading_screen_sprite_->setPosition(load_rect_);
|
||||
|
||||
// Comprueba si ha terminado la intro
|
||||
if (load_counter_ >= 768) {
|
||||
options.section.section = Section::TITLE;
|
||||
options.section.subsection = Subsection::TITLE_WITH_LOADING_SCREEN;
|
||||
JA_StopMusic();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gestiona el contador interno
|
||||
void LoadingScreen::updateCounter() {
|
||||
(pre_counter_ >= 50) ? counter_++ : pre_counter_++;
|
||||
|
||||
if (counter_ == 1) {
|
||||
JA_PlayMusic(Resource::get()->getMusic("loading_sound2.ogg"));
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja la pantalla de carga
|
||||
void LoadingScreen::renderLoad() {
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(screen_surface_);
|
||||
loading_first_part_ ? mono_loading_screen_sprite_->render(1, stringToColor("black")) : color_loading_screen_sprite_->render();
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
}
|
||||
|
||||
// Dibuja el efecto de carga en el borde
|
||||
void LoadingScreen::renderBorder() {
|
||||
// Obtiene la Surface del borde
|
||||
auto border = Screen::get()->getBorderSurface();
|
||||
|
||||
// Pinta el borde de color azul
|
||||
border->clear(static_cast<Uint8>(PaletteColor::BLUE));
|
||||
|
||||
// Añade lineas amarillas
|
||||
const Uint8 COLOR = static_cast<Uint8>(PaletteColor::YELLOW);
|
||||
const int WIDTH = options.game.width + (options.video.border.width * 2);
|
||||
const int HEIGHT = options.game.height + (options.video.border.height * 2);
|
||||
bool draw_enabled = rand() % 2 == 0 ? true : false;
|
||||
|
||||
int row = 0;
|
||||
while (row < HEIGHT) {
|
||||
const int ROW_HEIGHT = (rand() % 4) + 3;
|
||||
if (draw_enabled) {
|
||||
for (int i = row; i < row + ROW_HEIGHT; ++i) {
|
||||
border->drawLine(0, i, WIDTH, i, COLOR);
|
||||
}
|
||||
}
|
||||
row += ROW_HEIGHT;
|
||||
draw_enabled = !draw_enabled;
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza las variables
|
||||
void LoadingScreen::update() {
|
||||
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED) {
|
||||
ticks_ = SDL_GetTicks();
|
||||
checkInput();
|
||||
updateCounter();
|
||||
updateLoad();
|
||||
renderLoad();
|
||||
Screen::get()->update();
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja en pantalla
|
||||
void LoadingScreen::render() {
|
||||
if (options.video.border.enabled) {
|
||||
// Dibuja el efecto de carga en el borde
|
||||
renderBorder();
|
||||
}
|
||||
|
||||
// Prepara para empezar a dibujar en la textura de juego
|
||||
Screen::get()->start();
|
||||
Screen::get()->clearSurface(stringToColor("white"));
|
||||
|
||||
// Copia la surface a la surface de Screen
|
||||
screen_surface_->render(0, 0);
|
||||
|
||||
// Vuelca el contenido del renderizador en pantalla
|
||||
Screen::get()->render();
|
||||
}
|
||||
|
||||
// Bucle para el logo del juego
|
||||
void LoadingScreen::run() {
|
||||
// Inicia el sonido de carga
|
||||
JA_SetVolume(64);
|
||||
JA_PlayMusic(Resource::get()->getMusic("loading_sound1.ogg"));
|
||||
|
||||
// Limpia la pantalla
|
||||
Screen::get()->start();
|
||||
Screen::get()->clearRenderer();
|
||||
Screen::get()->render();
|
||||
|
||||
while (options.section.section == Section::LOADING_SCREEN) {
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
}
|
||||
|
||||
JA_SetVolume(128);
|
||||
}
|
||||
61
source/sections/loading_screen.h
Normal file
61
source/sections/loading_screen.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint32
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
class SSprite; // lines 7-7
|
||||
class Surface; // lines 8-8
|
||||
|
||||
class LoadingScreen {
|
||||
private:
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<Surface> mono_loading_screen_surface_; // Surface con la pantalla de carga en blanco y negro
|
||||
std::shared_ptr<Surface> color_loading_screen_surface_; // Surface con la pantalla de carga en color
|
||||
std::shared_ptr<SSprite> mono_loading_screen_sprite_; // SSprite para manejar la textura loadingScreenTexture1
|
||||
std::shared_ptr<SSprite> color_loading_screen_sprite_; // SSprite para manejar la textura loadingScreenTexture2
|
||||
std::shared_ptr<Surface> screen_surface_; // Surface para dibujar la pantalla de carga
|
||||
|
||||
// Variables
|
||||
int pre_counter_ = 0; // Contador previo para realizar una pausa inicial
|
||||
int counter_ = 0; // Contador
|
||||
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
int load_counter_ = 0; // Contador para controlar las cargas
|
||||
bool loading_first_part_ = true; // Para saber en que parte de la carga se encuentra
|
||||
int line_index_[192]; // El orden en el que se procesan las 192 lineas de la pantalla de carga
|
||||
SDL_Rect load_rect_ = {0, 0, 52, 1}; // Rectangulo para dibujar la pantalla de carga
|
||||
|
||||
// Actualiza las variables
|
||||
void update();
|
||||
|
||||
// Dibuja en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void checkEvents();
|
||||
|
||||
// Comprueba las entradas
|
||||
void checkInput();
|
||||
|
||||
// Gestiona el contador interno
|
||||
void updateCounter();
|
||||
|
||||
// Gestiona el contador de carga
|
||||
void updateLoad();
|
||||
|
||||
// Dibuja la pantalla de carga
|
||||
void renderLoad();
|
||||
|
||||
// Dibuja el efecto de carga en el borde
|
||||
void renderBorder();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
LoadingScreen();
|
||||
|
||||
// Destructor
|
||||
~LoadingScreen();
|
||||
|
||||
// Bucle principal
|
||||
void run();
|
||||
};
|
||||
226
source/sections/logo.cpp
Normal file
226
source/sections/logo.cpp
Normal file
@@ -0,0 +1,226 @@
|
||||
#include "logo.h"
|
||||
|
||||
#include <SDL3/SDL_events.h> // Para SDL_PollEvent, SDL_Event
|
||||
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include "defines.h" // Para GAME_SPEED
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
#include "options.h" // Para Options, SectionState, options, Section
|
||||
#include "resource.h" // Para Resource
|
||||
#include "s_sprite.h" // Para SSprite
|
||||
#include "screen.h" // Para Screen
|
||||
#include "surface.h" // Para Surface
|
||||
#include "utils.h" // Para PaletteColor
|
||||
|
||||
// Constructor
|
||||
Logo::Logo()
|
||||
: jailgames_surface_(Resource::get()->getSurface("jailgames.gif")),
|
||||
since_1998_surface_(Resource::get()->getSurface("since_1998.gif")),
|
||||
since_1998_sprite_(std::make_shared<SSprite>(since_1998_surface_, (256 - since_1998_surface_->getWidth()) / 2, 83 + jailgames_surface_->getHeight() + 5, since_1998_surface_->getWidth(), since_1998_surface_->getHeight())) {
|
||||
since_1998_sprite_->setClip(0, 0, since_1998_surface_->getWidth(), since_1998_surface_->getHeight());
|
||||
since_1998_color_ = static_cast<Uint8>(PaletteColor::BLACK);
|
||||
jailgames_color_ = static_cast<Uint8>(PaletteColor::BRIGHT_WHITE);
|
||||
|
||||
// Crea los sprites de cada linea
|
||||
for (int i = 0; i < jailgames_surface_->getHeight(); ++i) {
|
||||
jailgames_sprite_.push_back(std::make_shared<SSprite>(jailgames_surface_, 0, i, jailgames_surface_->getWidth(), 1));
|
||||
jailgames_sprite_.back()->setClip(0, i, jailgames_surface_->getWidth(), 1);
|
||||
jailgames_sprite_.at(i)->setX((i % 2 == 0) ? (256 + (i * 3)) : (-181 - (i * 3)));
|
||||
jailgames_sprite_.at(i)->setY(83 + i);
|
||||
}
|
||||
|
||||
// Inicializa variables
|
||||
options.section.section = Section::LOGO;
|
||||
|
||||
// Inicializa el vector de colores
|
||||
const std::vector<Uint8> COLORS = {
|
||||
static_cast<Uint8>(PaletteColor::BLACK),
|
||||
static_cast<Uint8>(PaletteColor::BLUE),
|
||||
static_cast<Uint8>(PaletteColor::RED),
|
||||
static_cast<Uint8>(PaletteColor::MAGENTA),
|
||||
static_cast<Uint8>(PaletteColor::GREEN),
|
||||
static_cast<Uint8>(PaletteColor::CYAN),
|
||||
static_cast<Uint8>(PaletteColor::YELLOW),
|
||||
static_cast<Uint8>(PaletteColor::BRIGHT_WHITE)};
|
||||
for (const auto& color : COLORS) {
|
||||
color_.push_back(color);
|
||||
}
|
||||
|
||||
// Cambia el color del borde
|
||||
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
}
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void Logo::checkEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
globalEvents::check(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las entradas
|
||||
void Logo::checkInput() {
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Gestiona el logo de JAILGAME
|
||||
void Logo::updateJAILGAMES() {
|
||||
if (counter_ > 30) {
|
||||
for (int i = 1; i < (int)jailgames_sprite_.size(); ++i) {
|
||||
constexpr int SPEED = 8;
|
||||
constexpr int DEST = 37;
|
||||
if (jailgames_sprite_.at(i)->getX() != 37) {
|
||||
if (i % 2 == 0) {
|
||||
jailgames_sprite_.at(i)->incX(-SPEED);
|
||||
if (jailgames_sprite_.at(i)->getX() < DEST) {
|
||||
jailgames_sprite_.at(i)->setX(DEST);
|
||||
}
|
||||
} else {
|
||||
jailgames_sprite_.at(i)->incX(SPEED);
|
||||
if (jailgames_sprite_.at(i)->getX() > DEST) {
|
||||
jailgames_sprite_.at(i)->setX(DEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Gestiona el color de las texturas
|
||||
void Logo::updateTextureColors() {
|
||||
constexpr int INI = 70;
|
||||
constexpr int INC = 4;
|
||||
|
||||
if (counter_ == INI + INC * 0) {
|
||||
since_1998_color_ = color_.at(0);
|
||||
}
|
||||
|
||||
else if (counter_ == INI + INC * 1) {
|
||||
since_1998_color_ = color_.at(1);
|
||||
}
|
||||
|
||||
else if (counter_ == INI + INC * 2) {
|
||||
since_1998_color_ = color_.at(2);
|
||||
}
|
||||
|
||||
else if (counter_ == INI + INC * 3) {
|
||||
since_1998_color_ = color_.at(3);
|
||||
}
|
||||
|
||||
else if (counter_ == INI + INC * 4) {
|
||||
since_1998_color_ = color_.at(4);
|
||||
}
|
||||
|
||||
else if (counter_ == INI + INC * 5) {
|
||||
since_1998_color_ = color_.at(5);
|
||||
}
|
||||
|
||||
else if (counter_ == INI + INC * 6) {
|
||||
since_1998_color_ = color_.at(6);
|
||||
}
|
||||
|
||||
else if (counter_ == INI + INC * 7) {
|
||||
since_1998_color_ = color_.at(7);
|
||||
}
|
||||
|
||||
else if (counter_ == INIT_FADE_ + INC * 0) {
|
||||
jailgames_color_ = color_.at(6);
|
||||
since_1998_color_ = color_.at(6);
|
||||
}
|
||||
|
||||
else if (counter_ == INIT_FADE_ + INC * 1) {
|
||||
jailgames_color_ = color_.at(5);
|
||||
since_1998_color_ = color_.at(5);
|
||||
}
|
||||
|
||||
else if (counter_ == INIT_FADE_ + INC * 2) {
|
||||
jailgames_color_ = color_.at(4);
|
||||
since_1998_color_ = color_.at(4);
|
||||
}
|
||||
|
||||
else if (counter_ == INIT_FADE_ + INC * 3) {
|
||||
jailgames_color_ = color_.at(3);
|
||||
since_1998_color_ = color_.at(3);
|
||||
}
|
||||
|
||||
else if (counter_ == INIT_FADE_ + INC * 4) {
|
||||
jailgames_color_ = color_.at(2);
|
||||
since_1998_color_ = color_.at(2);
|
||||
}
|
||||
|
||||
else if (counter_ == INIT_FADE_ + INC * 5) {
|
||||
jailgames_color_ = color_.at(1);
|
||||
since_1998_color_ = color_.at(1);
|
||||
}
|
||||
|
||||
else if (counter_ == INIT_FADE_ + INC * 6) {
|
||||
jailgames_color_ = color_.at(0);
|
||||
since_1998_color_ = color_.at(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza las variables
|
||||
void Logo::update() {
|
||||
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED) {
|
||||
// Actualiza el contador de ticks
|
||||
ticks_ = SDL_GetTicks();
|
||||
|
||||
// Comprueba las entradas
|
||||
checkInput();
|
||||
|
||||
// Incrementa el contador
|
||||
counter_++;
|
||||
|
||||
// Gestiona el logo de JAILGAME
|
||||
updateJAILGAMES();
|
||||
|
||||
// Gestiona el color de las texturas
|
||||
updateTextureColors();
|
||||
|
||||
// Actualiza el objeto Screen
|
||||
Screen::get()->update();
|
||||
|
||||
// Comprueba si ha terminado el logo
|
||||
if (counter_ == END_LOGO_ + POST_LOGO_) {
|
||||
endSection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja en pantalla
|
||||
void Logo::render() {
|
||||
// Prepara para empezar a dibujar en la textura de juego
|
||||
Screen::get()->start();
|
||||
Screen::get()->clearSurface(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
// Dibuja los objetos
|
||||
for (const auto& s : jailgames_sprite_) {
|
||||
s->render(1, jailgames_color_);
|
||||
}
|
||||
since_1998_sprite_->render(1, since_1998_color_);
|
||||
|
||||
// Vuelca el contenido del renderizador en pantalla
|
||||
Screen::get()->render();
|
||||
}
|
||||
|
||||
// Bucle para el logo del juego
|
||||
void Logo::run() {
|
||||
while (options.section.section == Section::LOGO) {
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
// Termina la sección
|
||||
void Logo::endSection() {
|
||||
if (options.section.subsection == Subsection::LOGO_TO_TITLE) {
|
||||
options.section.section = Section::TITLE;
|
||||
}
|
||||
|
||||
else if (options.section.subsection == Subsection::LOGO_TO_INTRO) {
|
||||
options.section.section = Section::LOADING_SCREEN;
|
||||
}
|
||||
}
|
||||
60
source/sections/logo.h
Normal file
60
source/sections/logo.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint8, Uint32
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <vector> // Para vector
|
||||
class SSprite; // lines 7-7
|
||||
class Surface; // lines 8-8
|
||||
|
||||
class Logo {
|
||||
private:
|
||||
// Constantes
|
||||
static constexpr int INIT_FADE_ = 300; // Tiempo del contador cuando inicia el fade a negro
|
||||
static constexpr int END_LOGO_ = 400; // Tiempo del contador para terminar el logo
|
||||
static constexpr int POST_LOGO_ = 20; // Tiempo que dura el logo con el fade al maximo
|
||||
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<Surface> jailgames_surface_; // Textura con los graficos "JAILGAMES"
|
||||
std::shared_ptr<Surface> since_1998_surface_; // Textura con los graficos "Since 1998"
|
||||
std::vector<std::shared_ptr<SSprite>> jailgames_sprite_; // Vector con los sprites de cada linea que forman el bitmap JAILGAMES
|
||||
std::shared_ptr<SSprite> since_1998_sprite_; // SSprite para manejar la textura2
|
||||
Uint8 jailgames_color_ = 0; // Color para el sprite de "JAILGAMES"
|
||||
Uint8 since_1998_color_ = 0; // Color para el sprite de "Since 1998"
|
||||
|
||||
// Variables
|
||||
std::vector<Uint8> color_; // Vector con los colores para el fade
|
||||
int counter_ = 0; // Contador
|
||||
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
|
||||
// Actualiza las variables
|
||||
void update();
|
||||
|
||||
// Dibuja en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void checkEvents();
|
||||
|
||||
// Comprueba las entradas
|
||||
void checkInput();
|
||||
|
||||
// Gestiona el logo de JAILGAME
|
||||
void updateJAILGAMES();
|
||||
|
||||
// Gestiona el color de las texturas
|
||||
void updateTextureColors();
|
||||
|
||||
// Termina la sección
|
||||
void endSection();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Logo();
|
||||
|
||||
// Destructor
|
||||
~Logo() = default;
|
||||
|
||||
// Bucle principal
|
||||
void run();
|
||||
};
|
||||
334
source/sections/title.cpp
Normal file
334
source/sections/title.cpp
Normal file
@@ -0,0 +1,334 @@
|
||||
#include "title.h"
|
||||
|
||||
#include <SDL3/SDL_events.h> // Para SDL_PollEvent, SDL_Event, SDL_KEYDOWN
|
||||
#include <SDL3/SDL_scancode.h> // Para SDL_SCANCODE_1, SDL_SCANCODE_2
|
||||
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <algorithm> // Para clamp
|
||||
|
||||
#include "cheevos.h" // Para Cheevos, Achievement
|
||||
#include "defines.h" // Para PLAY_AREA_CENTER_X, GAMECANVAS_WIDTH
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
#include "input.h" // Para Input, InputAction, INPUT_DO_NOT_ALLOW_REPEAT, REP...
|
||||
#include "options.h" // Para Options, options, SectionState, Section
|
||||
#include "resource.h" // Para Resource
|
||||
#include "s_sprite.h" // Para SSprite
|
||||
#include "screen.h" // Para Screen
|
||||
#include "surface.h" // Para Surface
|
||||
#include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR
|
||||
#include "utils.h" // Para stringToColor, PaletteColor, playMusic
|
||||
|
||||
// Constructor
|
||||
Title::Title()
|
||||
: title_logo_surface_(Resource::get()->getSurface("title_logo.gif")),
|
||||
title_logo_sprite_(std::make_shared<SSprite>(title_logo_surface_, 29, 9, title_logo_surface_->getWidth(), title_logo_surface_->getHeight())),
|
||||
loading_screen_surface_(Resource::get()->getSurface("loading_screen_color.gif")),
|
||||
loading_screen_sprite_(std::make_shared<SSprite>(loading_screen_surface_, 0, 0, loading_screen_surface_->getWidth(), loading_screen_surface_->getHeight())),
|
||||
bg_surface_(std::make_shared<Surface>(options.game.width, options.game.height)) {
|
||||
// Inicializa variables
|
||||
state_ = options.section.subsection == Subsection::TITLE_WITH_LOADING_SCREEN ? TitleState::SHOW_LOADING_SCREEN : TitleState::SHOW_MENU;
|
||||
options.section.section = Section::TITLE;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
initMarquee();
|
||||
|
||||
// Crea y rellena la textura para mostrar los logros
|
||||
createCheevosTexture();
|
||||
|
||||
// Cambia el color del borde
|
||||
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
// Rellena la textura de fondo con todos los gráficos
|
||||
fillSurface();
|
||||
|
||||
// Inicia la musica
|
||||
playMusic("title.ogg");
|
||||
}
|
||||
|
||||
// Inicializa la marquesina
|
||||
void Title::initMarquee() {
|
||||
letters_.clear();
|
||||
long_text_ = "HEY JAILERS!! IT'S 2022 AND WE'RE STILL ROCKING LIKE IT'S 1998!!! HAVE YOU HEARD IT? JAILGAMES ARE BACK!! YEEESSS BACK!! MORE THAN 10 TITLES ON JAILDOC'S KITCHEN!! THATS A LOOOOOOT OF JAILGAMES, BUT WHICH ONE WILL STRIKE FIRST? THERE IS ALSO A NEW DEVICE TO COME THAT WILL BLOW YOUR MIND WITH JAILGAMES ON THE GO: P.A.C.O. BUT WAIT! WHAT'S THAT BEAUTY I'M SEEING RIGHT OVER THERE?? OOOH THAT TINY MINIASCII IS PURE LOVE!! I WANT TO LICK EVERY BYTE OF IT!! OH SHIT! AND DON'T FORGET TO BRING BACK THOSE OLD AND FAT MS-DOS JAILGAMES TO GITHUB TO KEEP THEM ALIVE!! WHAT WILL BE THE NEXT JAILDOC RELEASE? WHAT WILL BE THE NEXT PROJECT TO COME ALIVE?? OH BABY WE DON'T KNOW BUT HERE YOU CAN FIND THE ANSWER, YOU JUST HAVE TO COMPLETE JAILDOCTOR'S DILEMMA ... COULD YOU?";
|
||||
for (int i = 0; i < (int)long_text_.length(); ++i) {
|
||||
TitleLetter l;
|
||||
l.letter = long_text_.substr(i, 1);
|
||||
l.x = 256;
|
||||
l.enabled = false;
|
||||
letters_.push_back(l);
|
||||
}
|
||||
letters_[0].enabled = true;
|
||||
}
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void Title::checkEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
globalEvents::check(event);
|
||||
|
||||
// Solo se comprueban estas teclas si no está activo el menu de logros
|
||||
if (event.type == SDL_KEYDOWN) {
|
||||
if (!show_cheevos_) {
|
||||
switch (event.key.keysym.scancode) {
|
||||
case SDL_SCANCODE_1:
|
||||
options.section.section = Section::GAME;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
break;
|
||||
|
||||
case SDL_SCANCODE_2:
|
||||
show_cheevos_ = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las entradas
|
||||
void Title::checkInput() {
|
||||
if (show_cheevos_) {
|
||||
if (Input::get()->checkInput(InputAction::DOWN, INPUT_ALLOW_REPEAT)) {
|
||||
moveCheevosList(1);
|
||||
} else if (Input::get()->checkInput(InputAction::UP, INPUT_ALLOW_REPEAT)) {
|
||||
moveCheevosList(0);
|
||||
} else if (Input::get()->checkInput(InputAction::ACCEPT, INPUT_DO_NOT_ALLOW_REPEAT)) {
|
||||
hideCheevosList();
|
||||
counter_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (Input::get()->checkInput(InputAction::ACCEPT, INPUT_DO_NOT_ALLOW_REPEAT)) {
|
||||
if (state_ == TitleState::SHOW_LOADING_SCREEN) {
|
||||
state_ = TitleState::FADE_LOADING_SCREEN;
|
||||
}
|
||||
}
|
||||
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Actualiza la marquesina
|
||||
void Title::updateMarquee() {
|
||||
const auto TEXT = Resource::get()->getText("gauntlet");
|
||||
|
||||
for (int i = 0; i < (int)letters_.size(); ++i) {
|
||||
if (letters_[i].enabled) {
|
||||
letters_[i].x -= marquee_speed_;
|
||||
if (letters_[i].x < -10) {
|
||||
letters_[i].enabled = false;
|
||||
}
|
||||
} else {
|
||||
if (i > 0 && letters_[i - 1].x < 256 && letters_[i - 1].enabled) {
|
||||
letters_[i].enabled = true;
|
||||
letters_[i].x = letters_[i - 1].x + TEXT->lenght(letters_[i - 1].letter) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba si ha terminado la marquesina y la reinicia
|
||||
if (letters_[letters_.size() - 1].x < -10) {
|
||||
// Inicializa la marquesina
|
||||
initMarquee();
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja la marquesina
|
||||
void Title::renderMarquee() {
|
||||
const auto TEXT = Resource::get()->getText("gauntlet");
|
||||
for (const auto& l : letters_) {
|
||||
if (l.enabled) {
|
||||
TEXT->writeColored(l.x, 184, l.letter, static_cast<Uint8>(PaletteColor::BRIGHT_RED));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza las variables
|
||||
void Title::update() {
|
||||
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED) {
|
||||
// Actualiza el contador de ticks
|
||||
ticks_ = SDL_GetTicks();
|
||||
|
||||
// Comprueba las entradas
|
||||
checkInput();
|
||||
|
||||
Screen::get()->update();
|
||||
|
||||
// Incrementa el contador
|
||||
counter_++;
|
||||
|
||||
switch (state_) {
|
||||
case TitleState::SHOW_LOADING_SCREEN:
|
||||
if (counter_ == 500) {
|
||||
counter_ = 0;
|
||||
state_ = TitleState::FADE_LOADING_SCREEN;
|
||||
}
|
||||
break;
|
||||
|
||||
case TitleState::FADE_LOADING_SCREEN:
|
||||
if (counter_ % 4 == 0) {
|
||||
if (loading_screen_surface_->fadeSubPalette()) {
|
||||
counter_ = 0;
|
||||
state_ = TitleState::SHOW_MENU;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TitleState::SHOW_MENU:
|
||||
// Actualiza la marquesina
|
||||
updateMarquee();
|
||||
|
||||
// Si el contador alcanza cierto valor, termina la seccion
|
||||
if (counter_ == 2200) {
|
||||
if (!show_cheevos_) {
|
||||
options.section.section = Section::CREDITS;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja en pantalla
|
||||
void Title::render() {
|
||||
// Prepara para empezar a dibujar en la textura de juego
|
||||
Screen::get()->start();
|
||||
Screen::get()->clearSurface(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
switch (state_) {
|
||||
case TitleState::SHOW_MENU:
|
||||
// Dibuja la textura de fondo
|
||||
bg_surface_->render(0, 0);
|
||||
|
||||
// Dibuja la marquesina
|
||||
renderMarquee();
|
||||
|
||||
// Dibuja la información de logros
|
||||
if (show_cheevos_) {
|
||||
cheevos_sprite_->render();
|
||||
}
|
||||
break;
|
||||
|
||||
case TitleState::SHOW_LOADING_SCREEN:
|
||||
case TitleState::FADE_LOADING_SCREEN:
|
||||
loading_screen_sprite_->render();
|
||||
title_logo_sprite_->render();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Vuelca el contenido del renderizador en pantalla
|
||||
Screen::get()->render();
|
||||
}
|
||||
|
||||
// Bucle para el logo del juego
|
||||
void Title::run() {
|
||||
while (options.section.section == Section::TITLE) {
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
// Desplaza la lista de logros
|
||||
void Title::moveCheevosList(int direction) {
|
||||
// Modifica la posición de la ventana de vista
|
||||
constexpr int SPEED = 2;
|
||||
cheevos_surface_view_.y = direction == 0 ? cheevos_surface_view_.y - SPEED : cheevos_surface_view_.y + SPEED;
|
||||
|
||||
// Ajusta los limites
|
||||
const int BOTTOM = cheevos_surface_->getHeight() - cheevos_surface_view_.h;
|
||||
cheevos_surface_view_.y = std::clamp(cheevos_surface_view_.y, 0, BOTTOM);
|
||||
|
||||
cheevos_sprite_->setClip(cheevos_surface_view_);
|
||||
}
|
||||
|
||||
// Rellena la textura de fondo con todos los gráficos
|
||||
void Title::fillSurface() {
|
||||
// Coloca el puntero del renderizador sobre la textura
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(bg_surface_);
|
||||
|
||||
// Rellena la textura de color
|
||||
bg_surface_->clear(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
// Pinta el gráfico del titulo a partir del sprite
|
||||
title_logo_sprite_->render();
|
||||
|
||||
// Escribe el texto en la textura
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
const Uint8 COLOR = stringToColor("green");
|
||||
const int TEXT_SIZE = text->getCharacterSize();
|
||||
text->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 11 * TEXT_SIZE, "1.PLAY", 1, COLOR);
|
||||
text->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 13 * TEXT_SIZE, "2.ACHIEVEMENTS", 1, COLOR);
|
||||
text->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 15 * TEXT_SIZE, "3.REDEFINE KEYS", 1, COLOR);
|
||||
|
||||
// Devuelve el puntero del renderizador a su sitio
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
}
|
||||
|
||||
// Crea y rellena la textura para mostrar los logros
|
||||
void Title::createCheevosTexture() {
|
||||
// Crea la textura con el listado de logros
|
||||
const auto CHEEVOS_LIST = Cheevos::get()->list();
|
||||
const auto TEXT = Resource::get()->getText("subatomic");
|
||||
constexpr int CHEEVOS_TEXTURE_WIDTH = 200;
|
||||
constexpr int CHEEVOS_TEXTURE_VIEW_HEIGHT = 110 - 8;
|
||||
constexpr int CHEEVOS_TEXTURE_POS_Y = 73;
|
||||
constexpr int CHEEVOS_PADDING = 10;
|
||||
const int CHEEVO_HEIGHT = CHEEVOS_PADDING + (TEXT->getCharacterSize() * 2) + 1;
|
||||
const int CHEEVOS_TEXTURE_HEIGHT = (CHEEVO_HEIGHT * CHEEVOS_LIST.size()) + 2 + TEXT->getCharacterSize() + 8;
|
||||
cheevos_surface_ = std::make_shared<Surface>(CHEEVOS_TEXTURE_WIDTH, CHEEVOS_TEXTURE_HEIGHT);
|
||||
|
||||
// Prepara para dibujar sobre la textura
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(cheevos_surface_);
|
||||
|
||||
// Rellena la textura con color sólido
|
||||
const Uint8 CHEEVOS_BG_COLOR = static_cast<Uint8>(PaletteColor::BLACK);
|
||||
cheevos_surface_->clear(CHEEVOS_BG_COLOR);
|
||||
|
||||
// Escribe la lista de logros en la textura
|
||||
const std::string CHEEVOS_OWNER = "ACHIEVEMENTS";
|
||||
const std::string CHEEVOS_LIST_CAPTION = CHEEVOS_OWNER + " (" + std::to_string(Cheevos::get()->getTotalUnlockedAchievements()) + " / " + std::to_string(Cheevos::get()->size()) + ")";
|
||||
int pos = 2;
|
||||
TEXT->writeDX(TEXT_CENTER | TEXT_COLOR, cheevos_surface_->getWidth() / 2, pos, CHEEVOS_LIST_CAPTION, 1, stringToColor("bright_green"));
|
||||
pos += TEXT->getCharacterSize();
|
||||
const Uint8 CHEEVO_LOCKED_COLOR = stringToColor("white");
|
||||
const Uint8 CHEEVO_UNLOCKED_COLOR = stringToColor("bright_green");
|
||||
constexpr int LINE_X1 = (CHEEVOS_TEXTURE_WIDTH / 7) * 3;
|
||||
constexpr int LINE_X2 = LINE_X1 + ((CHEEVOS_TEXTURE_WIDTH / 7) * 1);
|
||||
|
||||
for (const auto& cheevo : CHEEVOS_LIST) {
|
||||
const Uint8 CHEEVO_COLOR = cheevo.completed ? CHEEVO_UNLOCKED_COLOR : CHEEVO_LOCKED_COLOR;
|
||||
pos += CHEEVOS_PADDING;
|
||||
constexpr int HALF = CHEEVOS_PADDING / 2;
|
||||
cheevos_surface_->drawLine(LINE_X1, pos - HALF - 1, LINE_X2, pos - HALF - 1, CHEEVO_COLOR);
|
||||
TEXT->writeDX(TEXT_CENTER | TEXT_COLOR, CHEEVOS_TEXTURE_WIDTH / 2, pos, cheevo.caption, 1, CHEEVO_COLOR);
|
||||
pos += TEXT->getCharacterSize() + 1;
|
||||
TEXT->writeDX(TEXT_CENTER | TEXT_COLOR, CHEEVOS_TEXTURE_WIDTH / 2, pos, cheevo.description, 1, CHEEVO_COLOR);
|
||||
pos += TEXT->getCharacterSize();
|
||||
}
|
||||
|
||||
// Restablece el RenderSurface
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
|
||||
// Crea el sprite para el listado de logros
|
||||
cheevos_sprite_ = std::make_shared<SSprite>(cheevos_surface_, (GAMECANVAS_WIDTH - cheevos_surface_->getWidth()) / 2, CHEEVOS_TEXTURE_POS_Y, cheevos_surface_->getWidth(), cheevos_surface_->getHeight());
|
||||
cheevos_surface_view_ = {0, 0, cheevos_surface_->getWidth(), CHEEVOS_TEXTURE_VIEW_HEIGHT};
|
||||
cheevos_sprite_->setClip(cheevos_surface_view_);
|
||||
}
|
||||
|
||||
// Oculta la lista de logros
|
||||
void Title::hideCheevosList() {
|
||||
show_cheevos_ = false;
|
||||
cheevos_surface_view_.y = 0;
|
||||
cheevos_sprite_->setClip(cheevos_surface_view_);
|
||||
}
|
||||
87
source/sections/title.h
Normal file
87
source/sections/title.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint32
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
class SSprite; // lines 9-9
|
||||
class Surface; // lines 10-10
|
||||
|
||||
class Title {
|
||||
private:
|
||||
struct TitleLetter {
|
||||
std::string letter; // Letra a escribir
|
||||
int x; // Posición en el eje x
|
||||
bool enabled; // Solo se escriben y mueven si estan habilitadas
|
||||
};
|
||||
|
||||
enum class TitleState {
|
||||
SHOW_LOADING_SCREEN,
|
||||
FADE_LOADING_SCREEN,
|
||||
SHOW_MENU
|
||||
};
|
||||
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<Surface> title_logo_surface_; // Textura con los graficos
|
||||
std::shared_ptr<SSprite> title_logo_sprite_; // SSprite para manejar la surface
|
||||
std::shared_ptr<Surface> loading_screen_surface_; // Surface con los gráficos de la pantalla de carga
|
||||
std::shared_ptr<SSprite> loading_screen_sprite_; // SSprite con los gráficos de la pantalla de carga
|
||||
std::shared_ptr<Surface> bg_surface_; // Textura para dibujar el fondo de la pantalla
|
||||
std::shared_ptr<Surface> cheevos_surface_; // Textura con la lista de logros
|
||||
std::shared_ptr<SSprite> cheevos_sprite_; // SSprite para manejar la surface con la lista de logros
|
||||
|
||||
// Variables
|
||||
int counter_ = 0; // Contador
|
||||
std::string long_text_; // Texto que aparece en la parte inferior del titulo
|
||||
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
std::vector<TitleLetter> letters_; // Vector con las letras de la marquesina
|
||||
int marquee_speed_ = 2; // Velocidad de desplazamiento de la marquesina
|
||||
bool show_cheevos_ = false; // Indica si se muestra por pantalla el listado de logros
|
||||
SDL_Rect cheevos_surface_view_; // Zona visible de la surface con el listado de logros
|
||||
TitleState state_; // Estado en el que se encuentra el bucle principal
|
||||
|
||||
// Actualiza las variables
|
||||
void update();
|
||||
|
||||
// Dibuja en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void checkEvents();
|
||||
|
||||
// Comprueba las entradas
|
||||
void checkInput();
|
||||
|
||||
// Inicializa la marquesina
|
||||
void initMarquee();
|
||||
|
||||
// Actualiza la marquesina
|
||||
void updateMarquee();
|
||||
|
||||
// Dibuja la marquesina
|
||||
void renderMarquee();
|
||||
|
||||
// Desplaza la lista de logros
|
||||
void moveCheevosList(int direction);
|
||||
|
||||
// Rellena la surface de fondo con todos los gráficos
|
||||
void fillSurface();
|
||||
|
||||
// Crea y rellena la surface para mostrar los logros
|
||||
void createCheevosTexture();
|
||||
|
||||
// Oculta la lista de logros
|
||||
void hideCheevosList();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Title();
|
||||
|
||||
// Destructor
|
||||
~Title() = default;
|
||||
|
||||
// Bucle principal
|
||||
void run();
|
||||
};
|
||||
78
source/sprite/surface_animated_sprite.h
Normal file
78
source/sprite/surface_animated_sprite.h
Normal file
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "s_moving_sprite.h" // Para SMovingSprite
|
||||
class Surface; // lines 9-9
|
||||
|
||||
struct AnimationData {
|
||||
std::string name; // Nombre de la animacion
|
||||
std::vector<SDL_Rect> frames; // Cada uno de los frames que componen la animación
|
||||
int speed; // Velocidad de la animación
|
||||
int loop; // Indica a que frame vuelve la animación al terminar. -1 para que no vuelva
|
||||
bool completed; // Indica si ha finalizado la animación
|
||||
int current_frame; // Frame actual
|
||||
int counter; // Contador para las animaciones
|
||||
|
||||
AnimationData()
|
||||
: name(std::string()),
|
||||
speed(5),
|
||||
loop(0),
|
||||
completed(false),
|
||||
current_frame(0),
|
||||
counter(0) {}
|
||||
};
|
||||
|
||||
using Animations = std::vector<std::string>;
|
||||
|
||||
// Carga las animaciones en un vector(Animations) desde un fichero
|
||||
Animations loadAnimationsFromFile(const std::string& file_path);
|
||||
|
||||
class SAnimatedSprite : public SMovingSprite {
|
||||
protected:
|
||||
// Variables
|
||||
std::vector<AnimationData> animations_; // Vector con las diferentes animaciones
|
||||
int current_animation_ = 0; // Animacion activa
|
||||
|
||||
// Calcula el frame correspondiente a la animación actual
|
||||
void animate();
|
||||
|
||||
// Carga la animación desde un vector de cadenas
|
||||
void setAnimations(const Animations& animations);
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
SAnimatedSprite(std::shared_ptr<Surface> surface, const std::string& file_path);
|
||||
SAnimatedSprite(std::shared_ptr<Surface> surface, const Animations& animations);
|
||||
explicit SAnimatedSprite(std::shared_ptr<Surface> surface)
|
||||
: SMovingSprite(surface) {}
|
||||
|
||||
// Destructor
|
||||
virtual ~SAnimatedSprite() override = default;
|
||||
|
||||
// Actualiza las variables del objeto
|
||||
void update() override;
|
||||
|
||||
// Comprueba si ha terminado la animación
|
||||
bool animationIsCompleted();
|
||||
|
||||
// Obtiene el indice de la animación a partir del nombre
|
||||
int getIndex(const std::string& name);
|
||||
|
||||
// Establece la animacion actual
|
||||
void setCurrentAnimation(const std::string& name = "default");
|
||||
void setCurrentAnimation(int index = 0);
|
||||
|
||||
// Reinicia la animación
|
||||
void resetAnimation();
|
||||
|
||||
// Establece el frame actual de la animación
|
||||
void setCurrentAnimationFrame(int num);
|
||||
|
||||
// Obtiene el numero de frames de la animación actual
|
||||
int getCurrentAnimationSize() { return static_cast<int>(animations_[current_animation_].frames.size()); }
|
||||
};
|
||||
83
source/sprite/surface_moving_sprite.h
Normal file
83
source/sprite/surface_moving_sprite.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL3/SDL_render.h> // Para SDL_RendererFlip, SDL_FLIP_HORIZONTAL
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint8
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
|
||||
#include "s_sprite.h" // Para SSprite
|
||||
class Surface; // lines 8-8
|
||||
|
||||
// Clase SMovingSprite. Añade movimiento y flip al sprite
|
||||
class SMovingSprite : public SSprite {
|
||||
public:
|
||||
protected:
|
||||
float x_; // Posición en el eje X
|
||||
float y_; // Posición en el eje Y
|
||||
|
||||
float vx_ = 0.0f; // Velocidad en el eje X. Cantidad de pixeles a desplazarse
|
||||
float vy_ = 0.0f; // Velocidad en el eje Y. Cantidad de pixeles a desplazarse
|
||||
|
||||
float ax_ = 0.0f; // Aceleración en el eje X. Variación de la velocidad
|
||||
float ay_ = 0.0f; // Aceleración en el eje Y. Variación de la velocidad
|
||||
|
||||
SDL_RendererFlip flip_; // Indica como se voltea el sprite
|
||||
|
||||
// Mueve el sprite
|
||||
void move();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
SMovingSprite(std::shared_ptr<Surface> surface, SDL_Rect pos, SDL_RendererFlip flip);
|
||||
SMovingSprite(std::shared_ptr<Surface> surface, SDL_Rect pos);
|
||||
explicit SMovingSprite(std::shared_ptr<Surface> surface);
|
||||
|
||||
// Destructor
|
||||
virtual ~SMovingSprite() override = default;
|
||||
|
||||
// Actualiza las variables internas del objeto
|
||||
virtual void update();
|
||||
|
||||
// Reinicia todas las variables a cero
|
||||
void clear() override;
|
||||
|
||||
// Muestra el sprite por pantalla
|
||||
void render() override;
|
||||
void render(Uint8 source_color, Uint8 target_color) override;
|
||||
|
||||
// Obtiene la variable
|
||||
float getPosX() const { return x_; }
|
||||
float getPosY() const { return y_; }
|
||||
float getVelX() const { return vx_; }
|
||||
float getVelY() const { return vy_; }
|
||||
float getAccelX() const { return ax_; }
|
||||
float getAccelY() const { return ay_; }
|
||||
|
||||
// Establece la variable
|
||||
void setVelX(float value) { vx_ = value; }
|
||||
void setVelY(float value) { vy_ = value; }
|
||||
void setAccelX(float value) { ax_ = value; }
|
||||
void setAccelY(float value) { ay_ = value; }
|
||||
|
||||
// Establece el valor de la variable
|
||||
void setFlip(SDL_RendererFlip flip) { flip_ = flip; }
|
||||
|
||||
// Gira el sprite horizontalmente
|
||||
void flip() { flip_ = (flip_ == SDL_FLIP_HORIZONTAL) ? SDL_FLIP_NONE : SDL_FLIP_HORIZONTAL; }
|
||||
|
||||
// Obtiene el valor de la variable
|
||||
SDL_RendererFlip getFlip() { return flip_; }
|
||||
|
||||
// Establece la posición y_ el tamaño del objeto
|
||||
void setPos(SDL_Rect rect);
|
||||
|
||||
// Establece el valor de las variables
|
||||
void setPos(float x, float y);
|
||||
|
||||
// Establece el valor de la variable
|
||||
void setPosX(float value);
|
||||
|
||||
// Establece el valor de la variable
|
||||
void setPosY(float value);
|
||||
};
|
||||
70
source/sprite/surface_sprite.h
Normal file
70
source/sprite/surface_sprite.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect, SDL_Point
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint8
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
class Surface; // lines 5-5
|
||||
|
||||
// Clase SSprite
|
||||
class SSprite {
|
||||
protected:
|
||||
// Variables
|
||||
std::shared_ptr<Surface> surface_; // Surface donde estan todos los dibujos del sprite
|
||||
SDL_Rect pos_; // Posición y tamaño donde dibujar el sprite
|
||||
SDL_Rect clip_; // Rectangulo de origen de la surface que se dibujará en pantalla
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
SSprite(std::shared_ptr<Surface>, int x, int y, int w, int h);
|
||||
SSprite(std::shared_ptr<Surface>, SDL_Rect rect);
|
||||
explicit SSprite(std::shared_ptr<Surface>);
|
||||
|
||||
// Destructor
|
||||
virtual ~SSprite() = default;
|
||||
|
||||
// Muestra el sprite por pantalla
|
||||
virtual void render();
|
||||
virtual void render(Uint8 source_color, Uint8 target_color);
|
||||
|
||||
// Reinicia las variables a cero
|
||||
virtual void clear();
|
||||
|
||||
// Obtiene la posición y el tamaño
|
||||
int getX() const { return pos_.x; }
|
||||
int getY() const { return pos_.y; }
|
||||
int getWidth() const { return pos_.w; }
|
||||
int getHeight() const { return pos_.h; }
|
||||
|
||||
// Devuelve el rectangulo donde está el sprite
|
||||
SDL_Rect getPosition() const { return pos_; }
|
||||
SDL_Rect& getRect() { return pos_; }
|
||||
|
||||
// Establece la posición y el tamaño
|
||||
void setX(int x) { pos_.x = x; }
|
||||
void setY(int y) { pos_.y = y; }
|
||||
void setWidth(int w) { pos_.w = w; }
|
||||
void setHeight(int h) { pos_.h = h; }
|
||||
|
||||
// Establece la posición del objeto
|
||||
void setPosition(int x, int y);
|
||||
void setPosition(SDL_Point p);
|
||||
void setPosition(SDL_Rect r) { pos_ = r; }
|
||||
|
||||
// Aumenta o disminuye la posición
|
||||
void incX(int value) { pos_.x += value; }
|
||||
void incY(int value) { pos_.y += value; }
|
||||
|
||||
// Obtiene el rectangulo que se dibuja de la surface
|
||||
SDL_Rect getClip() const { return clip_; }
|
||||
|
||||
// Establece el rectangulo que se dibuja de la surface
|
||||
void setClip(SDL_Rect rect) { clip_ = rect; }
|
||||
void setClip(int x, int y, int w, int h) { clip_ = (SDL_Rect){x, y, w, h}; }
|
||||
|
||||
// Obtiene un puntero a la surface
|
||||
std::shared_ptr<Surface> getSurface() const { return surface_; }
|
||||
|
||||
// Establece la surface a utilizar
|
||||
void setSurface(std::shared_ptr<Surface> surface) { surface_ = surface; }
|
||||
};
|
||||
@@ -1,9 +1,11 @@
|
||||
// IWYU pragma: no_include <bits/std_abs.h>
|
||||
#include "surface.h"
|
||||
#include <SDL2/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
||||
#include <cmath> // Para abs
|
||||
|
||||
#include <SDL3/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <algorithm> // Para min, max, copy_n, fill
|
||||
#include <cmath> // Para abs
|
||||
#include <cstdint> // Para uint32_t
|
||||
#include <cstring> // Para memcpy, size_t
|
||||
#include <fstream> // Para basic_ifstream, basic_ostream, basic_ist...
|
||||
@@ -12,16 +14,15 @@
|
||||
#include <sstream> // Para basic_istringstream
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "gif.h" // Para Gif
|
||||
#include "screen.h" // Para Screen
|
||||
|
||||
// Carga una paleta desde un archivo .gif
|
||||
Palette loadPalette(const std::string &file_path)
|
||||
{
|
||||
Palette loadPalette(const std::string& file_path) {
|
||||
// Abrir el archivo en modo binario
|
||||
std::ifstream file(file_path, std::ios::binary | std::ios::ate);
|
||||
if (!file.is_open())
|
||||
{
|
||||
if (!file.is_open()) {
|
||||
throw std::runtime_error("Error opening file: " + file_path);
|
||||
}
|
||||
|
||||
@@ -30,16 +31,14 @@ Palette loadPalette(const std::string &file_path)
|
||||
file.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<Uint8> buffer(size);
|
||||
if (!file.read(reinterpret_cast<char *>(buffer.data()), size))
|
||||
{
|
||||
if (!file.read(reinterpret_cast<char*>(buffer.data()), size)) {
|
||||
throw std::runtime_error("Error reading file: " + file_path);
|
||||
}
|
||||
|
||||
// Cargar la paleta usando los datos del buffer
|
||||
GIF::Gif gif;
|
||||
std::vector<uint32_t> pal = gif.loadPalette(buffer.data());
|
||||
if (pal.empty())
|
||||
{
|
||||
if (pal.empty()) {
|
||||
throw std::runtime_error("No palette found in GIF file: " + file_path);
|
||||
}
|
||||
|
||||
@@ -54,14 +53,12 @@ Palette loadPalette(const std::string &file_path)
|
||||
}
|
||||
|
||||
// Carga una paleta desde un archivo .pal
|
||||
Palette readPalFile(const std::string &file_path)
|
||||
{
|
||||
Palette readPalFile(const std::string& file_path) {
|
||||
Palette palette{};
|
||||
palette.fill(0); // Inicializar todo con 0 (transparente por defecto)
|
||||
|
||||
std::ifstream file(file_path);
|
||||
if (!file.is_open())
|
||||
{
|
||||
if (!file.is_open()) {
|
||||
throw std::runtime_error("No se pudo abrir el archivo .pal");
|
||||
}
|
||||
|
||||
@@ -69,28 +66,24 @@ Palette readPalFile(const std::string &file_path)
|
||||
int line_number = 0;
|
||||
int color_index = 0;
|
||||
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
while (std::getline(file, line)) {
|
||||
++line_number;
|
||||
|
||||
// Ignorar las tres primeras líneas del archivo
|
||||
if (line_number <= 3)
|
||||
{
|
||||
if (line_number <= 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Procesar las líneas restantes con valores RGB
|
||||
std::istringstream ss(line);
|
||||
int r, g, b;
|
||||
if (ss >> r >> g >> b)
|
||||
{
|
||||
if (ss >> r >> g >> b) {
|
||||
// Construir el color ARGB (A = 255 por defecto)
|
||||
Uint32 color = (255 << 24) | (r << 16) | (g << 8) | b;
|
||||
palette[color_index++] = color;
|
||||
|
||||
// Limitar a un máximo de 256 colores (opcional)
|
||||
if (color_index >= 256)
|
||||
{
|
||||
if (color_index >= 256) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -105,9 +98,8 @@ Surface::Surface(int w, int h)
|
||||
: surface_data_(std::make_shared<SurfaceData>(w, h)),
|
||||
transparent_color_(static_cast<Uint8>(PaletteColor::TRANSPARENT)) { initializeSubPalette(sub_palette_); }
|
||||
|
||||
Surface::Surface(const std::string &file_path)
|
||||
: transparent_color_(static_cast<Uint8>(PaletteColor::TRANSPARENT))
|
||||
{
|
||||
Surface::Surface(const std::string& file_path)
|
||||
: transparent_color_(static_cast<Uint8>(PaletteColor::TRANSPARENT)) {
|
||||
SurfaceData loadedData = loadSurface(file_path);
|
||||
surface_data_ = std::make_shared<SurfaceData>(std::move(loadedData));
|
||||
|
||||
@@ -115,12 +107,10 @@ Surface::Surface(const std::string &file_path)
|
||||
}
|
||||
|
||||
// Carga una superficie desde un archivo
|
||||
SurfaceData Surface::loadSurface(const std::string &file_path)
|
||||
{
|
||||
SurfaceData Surface::loadSurface(const std::string& file_path) {
|
||||
// Abrir el archivo usando std::ifstream para manejo automático del recurso
|
||||
std::ifstream file(file_path, std::ios::binary | std::ios::ate);
|
||||
if (!file.is_open())
|
||||
{
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "Error opening file: " << file_path << std::endl;
|
||||
throw std::runtime_error("Error opening file");
|
||||
}
|
||||
@@ -131,8 +121,7 @@ SurfaceData Surface::loadSurface(const std::string &file_path)
|
||||
|
||||
// Leer el contenido del archivo en un buffer
|
||||
std::vector<Uint8> buffer(size);
|
||||
if (!file.read(reinterpret_cast<char *>(buffer.data()), size))
|
||||
{
|
||||
if (!file.read(reinterpret_cast<char*>(buffer.data()), size)) {
|
||||
std::cerr << "Error reading file: " << file_path << std::endl;
|
||||
throw std::runtime_error("Error reading file");
|
||||
}
|
||||
@@ -141,8 +130,7 @@ SurfaceData Surface::loadSurface(const std::string &file_path)
|
||||
GIF::Gif gif;
|
||||
Uint16 w = 0, h = 0;
|
||||
std::vector<Uint8> rawPixels = gif.loadGif(buffer.data(), w, h);
|
||||
if (rawPixels.empty())
|
||||
{
|
||||
if (rawPixels.empty()) {
|
||||
std::cerr << "Error loading GIF from file: " << file_path << std::endl;
|
||||
throw std::runtime_error("Error loading GIF");
|
||||
}
|
||||
@@ -159,36 +147,30 @@ SurfaceData Surface::loadSurface(const std::string &file_path)
|
||||
}
|
||||
|
||||
// Carga una paleta desde un archivo
|
||||
void Surface::loadPalette(const std::string &file_path)
|
||||
{
|
||||
void Surface::loadPalette(const std::string& file_path) {
|
||||
palette_ = ::loadPalette(file_path);
|
||||
}
|
||||
|
||||
// Carga una paleta desde otra paleta
|
||||
void Surface::loadPalette(Palette palette)
|
||||
{
|
||||
void Surface::loadPalette(Palette palette) {
|
||||
palette_ = palette;
|
||||
}
|
||||
|
||||
// Establece un color en la paleta
|
||||
void Surface::setColor(int index, Uint32 color)
|
||||
{
|
||||
void Surface::setColor(int index, Uint32 color) {
|
||||
palette_.at(index) = color;
|
||||
}
|
||||
|
||||
// Rellena la superficie con un color
|
||||
void Surface::clear(Uint8 color)
|
||||
{
|
||||
void Surface::clear(Uint8 color) {
|
||||
const size_t total_pixels = surface_data_->width * surface_data_->height;
|
||||
Uint8 *data_ptr = surface_data_->data.get();
|
||||
Uint8* data_ptr = surface_data_->data.get();
|
||||
std::fill(data_ptr, data_ptr + total_pixels, color);
|
||||
}
|
||||
|
||||
// Pone un pixel en la SurfaceData
|
||||
void Surface::putPixel(int x, int y, Uint8 color)
|
||||
{
|
||||
if (x < 0 || y < 0 || x >= surface_data_->width || y >= surface_data_->height)
|
||||
{
|
||||
void Surface::putPixel(int x, int y, Uint8 color) {
|
||||
if (x < 0 || y < 0 || x >= surface_data_->width || y >= surface_data_->height) {
|
||||
return; // Coordenadas fuera de rango
|
||||
}
|
||||
|
||||
@@ -200,8 +182,7 @@ void Surface::putPixel(int x, int y, Uint8 color)
|
||||
Uint8 Surface::getPixel(int x, int y) { return surface_data_->data.get()[x + y * surface_data_->width]; }
|
||||
|
||||
// Dibuja un rectangulo relleno
|
||||
void Surface::fillRect(const SDL_Rect *rect, Uint8 color)
|
||||
{
|
||||
void Surface::fillRect(const SDL_Rect* rect, Uint8 color) {
|
||||
// Limitar los valores del rectángulo al tamaño de la superficie
|
||||
int x_start = std::max(0, rect->x);
|
||||
int y_start = std::max(0, rect->y);
|
||||
@@ -209,10 +190,8 @@ void Surface::fillRect(const SDL_Rect *rect, Uint8 color)
|
||||
int y_end = std::min(rect->y + rect->h, static_cast<int>(surface_data_->height));
|
||||
|
||||
// Recorrer cada píxel dentro del rectángulo directamente
|
||||
for (int y = y_start; y < y_end; ++y)
|
||||
{
|
||||
for (int x = x_start; x < x_end; ++x)
|
||||
{
|
||||
for (int y = y_start; y < y_end; ++y) {
|
||||
for (int x = x_start; x < x_end; ++x) {
|
||||
const int index = x + y * surface_data_->width;
|
||||
surface_data_->data.get()[index] = color;
|
||||
}
|
||||
@@ -220,8 +199,7 @@ void Surface::fillRect(const SDL_Rect *rect, Uint8 color)
|
||||
}
|
||||
|
||||
// Dibuja el borde de un rectangulo
|
||||
void Surface::drawRectBorder(const SDL_Rect *rect, Uint8 color)
|
||||
{
|
||||
void Surface::drawRectBorder(const SDL_Rect* rect, Uint8 color) {
|
||||
// Limitar los valores del rectángulo al tamaño de la superficie
|
||||
int x_start = std::max(0, rect->x);
|
||||
int y_start = std::max(0, rect->y);
|
||||
@@ -229,8 +207,7 @@ void Surface::drawRectBorder(const SDL_Rect *rect, Uint8 color)
|
||||
int y_end = std::min(rect->y + rect->h, static_cast<int>(surface_data_->height));
|
||||
|
||||
// Dibujar bordes horizontales
|
||||
for (int x = x_start; x < x_end; ++x)
|
||||
{
|
||||
for (int x = x_start; x < x_end; ++x) {
|
||||
// Borde superior
|
||||
const int top_index = x + y_start * surface_data_->width;
|
||||
surface_data_->data.get()[top_index] = color;
|
||||
@@ -241,8 +218,7 @@ void Surface::drawRectBorder(const SDL_Rect *rect, Uint8 color)
|
||||
}
|
||||
|
||||
// Dibujar bordes verticales
|
||||
for (int y = y_start; y < y_end; ++y)
|
||||
{
|
||||
for (int y = y_start; y < y_end; ++y) {
|
||||
// Borde izquierdo
|
||||
const int left_index = x_start + y * surface_data_->width;
|
||||
surface_data_->data.get()[left_index] = color;
|
||||
@@ -254,8 +230,7 @@ void Surface::drawRectBorder(const SDL_Rect *rect, Uint8 color)
|
||||
}
|
||||
|
||||
// Dibuja una linea
|
||||
void Surface::drawLine(int x1, int y1, int x2, int y2, Uint8 color)
|
||||
{
|
||||
void Surface::drawLine(int x1, int y1, int x2, int y2, Uint8 color) {
|
||||
// Calcula las diferencias
|
||||
int dx = std::abs(x2 - x1);
|
||||
int dy = std::abs(y2 - y1);
|
||||
@@ -266,11 +241,9 @@ void Surface::drawLine(int x1, int y1, int x2, int y2, Uint8 color)
|
||||
|
||||
int err = dx - dy;
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
// Asegúrate de no dibujar fuera de los límites de la superficie
|
||||
if (x1 >= 0 && x1 < surface_data_->width && y1 >= 0 && y1 < surface_data_->height)
|
||||
{
|
||||
if (x1 >= 0 && x1 < surface_data_->width && y1 >= 0 && y1 < surface_data_->height) {
|
||||
surface_data_->data.get()[x1 + y1 * surface_data_->width] = color;
|
||||
}
|
||||
|
||||
@@ -279,21 +252,18 @@ void Surface::drawLine(int x1, int y1, int x2, int y2, Uint8 color)
|
||||
break;
|
||||
|
||||
int e2 = 2 * err;
|
||||
if (e2 > -dy)
|
||||
{
|
||||
if (e2 > -dy) {
|
||||
err -= dy;
|
||||
x1 += sx;
|
||||
}
|
||||
if (e2 < dx)
|
||||
{
|
||||
if (e2 < dx) {
|
||||
err += dx;
|
||||
y1 += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::render(int dx, int dy, int sx, int sy, int w, int h)
|
||||
{
|
||||
void Surface::render(int dx, int dy, int sx, int sy, int w, int h) {
|
||||
auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData();
|
||||
|
||||
// Limitar la región para evitar accesos fuera de rango en origen
|
||||
@@ -304,21 +274,16 @@ void Surface::render(int dx, int dy, int sx, int sy, int w, int h)
|
||||
w = std::min(w, surface_data->width - dx);
|
||||
h = std::min(h, surface_data->height - dy);
|
||||
|
||||
for (int iy = 0; iy < h; ++iy)
|
||||
{
|
||||
for (int ix = 0; ix < w; ++ix)
|
||||
{
|
||||
for (int iy = 0; iy < h; ++iy) {
|
||||
for (int ix = 0; ix < w; ++ix) {
|
||||
// Verificar que las coordenadas de destino están dentro de los límites
|
||||
if (int dest_x = dx + ix; dest_x >= 0 && dest_x < surface_data->width)
|
||||
{
|
||||
if (int dest_y = dy + iy; dest_y >= 0 && dest_y < surface_data->height)
|
||||
{
|
||||
if (int dest_x = dx + ix; dest_x >= 0 && dest_x < surface_data->width) {
|
||||
if (int dest_y = dy + iy; dest_y >= 0 && dest_y < surface_data->height) {
|
||||
int src_x = sx + ix;
|
||||
int src_y = sy + iy;
|
||||
|
||||
Uint8 color = surface_data_->data.get()[src_x + src_y * surface_data_->width];
|
||||
if (color != transparent_color_)
|
||||
{
|
||||
if (color != transparent_color_) {
|
||||
surface_data->data.get()[dest_x + dest_y * surface_data->width] = sub_palette_[color];
|
||||
}
|
||||
}
|
||||
@@ -327,8 +292,7 @@ void Surface::render(int dx, int dy, int sx, int sy, int w, int h)
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::render(int x, int y, SDL_Rect *srcRect, SDL_RendererFlip flip)
|
||||
{
|
||||
void Surface::render(int x, int y, SDL_Rect* srcRect, SDL_RendererFlip flip) {
|
||||
auto surface_data_dest = Screen::get()->getRendererSurface()->getSurfaceData();
|
||||
|
||||
// Determina la región de origen (clip) a renderizar
|
||||
@@ -348,10 +312,8 @@ void Surface::render(int x, int y, SDL_Rect *srcRect, SDL_RendererFlip flip)
|
||||
h = std::min(h, surface_data_dest->height - y);
|
||||
|
||||
// Renderiza píxel por píxel aplicando el flip si es necesario
|
||||
for (int iy = 0; iy < h; ++iy)
|
||||
{
|
||||
for (int ix = 0; ix < w; ++ix)
|
||||
{
|
||||
for (int iy = 0; iy < h; ++iy) {
|
||||
for (int ix = 0; ix < w; ++ix) {
|
||||
// Coordenadas de origen
|
||||
int src_x = (flip == SDL_FLIP_HORIZONTAL) ? (sx + w - 1 - ix) : (sx + ix);
|
||||
int src_y = (flip == SDL_FLIP_VERTICAL) ? (sy + h - 1 - iy) : (sy + iy);
|
||||
@@ -361,12 +323,10 @@ void Surface::render(int x, int y, SDL_Rect *srcRect, SDL_RendererFlip flip)
|
||||
int dest_y = y + iy;
|
||||
|
||||
// Verificar que las coordenadas de destino están dentro de los límites
|
||||
if (dest_x >= 0 && dest_x < surface_data_dest->width && dest_y >= 0 && dest_y < surface_data_dest->height)
|
||||
{
|
||||
if (dest_x >= 0 && dest_x < surface_data_dest->width && dest_y >= 0 && dest_y < surface_data_dest->height) {
|
||||
// Copia el píxel si no es transparente
|
||||
Uint8 color = surface_data_->data.get()[src_x + src_y * surface_data_->width];
|
||||
if (color != transparent_color_)
|
||||
{
|
||||
if (color != transparent_color_) {
|
||||
surface_data_dest->data[dest_x + dest_y * surface_data_dest->width] = sub_palette_[color];
|
||||
}
|
||||
}
|
||||
@@ -375,8 +335,7 @@ void Surface::render(int x, int y, SDL_Rect *srcRect, SDL_RendererFlip flip)
|
||||
}
|
||||
|
||||
// Copia una región de la superficie de origen a la de destino
|
||||
void Surface::render(SDL_Rect *srcRect, SDL_Rect *dstRect, SDL_RendererFlip flip)
|
||||
{
|
||||
void Surface::render(SDL_Rect* srcRect, SDL_Rect* dstRect, SDL_RendererFlip flip) {
|
||||
auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData();
|
||||
|
||||
// Si srcRect es nullptr, tomar toda la superficie fuente
|
||||
@@ -392,8 +351,7 @@ void Surface::render(SDL_Rect *srcRect, SDL_Rect *dstRect, SDL_RendererFlip flip
|
||||
int dh = (dstRect) ? dstRect->h : sh;
|
||||
|
||||
// Asegurarse de que srcRect y dstRect tienen las mismas dimensiones
|
||||
if (sw != dw || sh != dh)
|
||||
{
|
||||
if (sw != dw || sh != dh) {
|
||||
dw = sw; // Respetar las dimensiones de srcRect
|
||||
dh = sh;
|
||||
}
|
||||
@@ -408,23 +366,18 @@ void Surface::render(SDL_Rect *srcRect, SDL_Rect *dstRect, SDL_RendererFlip flip
|
||||
int final_height = std::min(sh, dh);
|
||||
|
||||
// Renderiza píxel por píxel aplicando el flip si es necesario
|
||||
for (int iy = 0; iy < final_height; ++iy)
|
||||
{
|
||||
for (int ix = 0; ix < final_width; ++ix)
|
||||
{
|
||||
for (int iy = 0; iy < final_height; ++iy) {
|
||||
for (int ix = 0; ix < final_width; ++ix) {
|
||||
// Coordenadas de origen
|
||||
int src_x = (flip == SDL_FLIP_HORIZONTAL) ? (sx + final_width - 1 - ix) : (sx + ix);
|
||||
int src_y = (flip == SDL_FLIP_VERTICAL) ? (sy + final_height - 1 - iy) : (sy + iy);
|
||||
|
||||
// Coordenadas de destino
|
||||
if (int dest_x = dx + ix; dest_x >= 0 && dest_x < surface_data->width)
|
||||
{
|
||||
if (int dest_y = dy + iy; dest_y >= 0 && dest_y < surface_data->height)
|
||||
{
|
||||
if (int dest_x = dx + ix; dest_x >= 0 && dest_x < surface_data->width) {
|
||||
if (int dest_y = dy + iy; dest_y >= 0 && dest_y < surface_data->height) {
|
||||
// Copiar el píxel si no es transparente
|
||||
Uint8 color = surface_data_->data.get()[src_x + src_y * surface_data_->width];
|
||||
if (color != transparent_color_)
|
||||
{
|
||||
if (color != transparent_color_) {
|
||||
surface_data->data[dest_x + dest_y * surface_data->width] = sub_palette_[color];
|
||||
}
|
||||
}
|
||||
@@ -434,8 +387,7 @@ void Surface::render(SDL_Rect *srcRect, SDL_Rect *dstRect, SDL_RendererFlip flip
|
||||
}
|
||||
|
||||
// Copia una región de la SurfaceData de origen a la SurfaceData de destino reemplazando un color por otro
|
||||
void Surface::renderWithColorReplace(int x, int y, Uint8 source_color, Uint8 target_color, SDL_Rect *srcRect, SDL_RendererFlip flip)
|
||||
{
|
||||
void Surface::renderWithColorReplace(int x, int y, Uint8 source_color, Uint8 target_color, SDL_Rect* srcRect, SDL_RendererFlip flip) {
|
||||
auto surface_data = Screen::get()->getRendererSurface()->getSurfaceData();
|
||||
|
||||
// Determina la región de origen (clip) a renderizar
|
||||
@@ -449,10 +401,8 @@ void Surface::renderWithColorReplace(int x, int y, Uint8 source_color, Uint8 tar
|
||||
h = std::min(h, surface_data_->height - sy);
|
||||
|
||||
// Renderiza píxel por píxel aplicando el flip si es necesario
|
||||
for (int iy = 0; iy < h; ++iy)
|
||||
{
|
||||
for (int ix = 0; ix < w; ++ix)
|
||||
{
|
||||
for (int iy = 0; iy < h; ++iy) {
|
||||
for (int ix = 0; ix < w; ++ix) {
|
||||
// Coordenadas de origen
|
||||
int src_x = (flip == SDL_FLIP_HORIZONTAL) ? (sx + w - 1 - ix) : (sx + ix);
|
||||
int src_y = (flip == SDL_FLIP_VERTICAL) ? (sy + h - 1 - iy) : (sy + iy);
|
||||
@@ -462,15 +412,13 @@ void Surface::renderWithColorReplace(int x, int y, Uint8 source_color, Uint8 tar
|
||||
int dest_y = y + iy;
|
||||
|
||||
// Verifica que las coordenadas de destino estén dentro de los límites
|
||||
if (dest_x < 0 || dest_y < 0 || dest_x >= surface_data->width || dest_y >= surface_data->height)
|
||||
{
|
||||
if (dest_x < 0 || dest_y < 0 || dest_x >= surface_data->width || dest_y >= surface_data->height) {
|
||||
continue; // Saltar píxeles fuera del rango del destino
|
||||
}
|
||||
|
||||
// Copia el píxel si no es transparente
|
||||
Uint8 color = surface_data_->data.get()[src_x + src_y * surface_data_->width];
|
||||
if (color != transparent_color_)
|
||||
{
|
||||
if (color != transparent_color_) {
|
||||
surface_data->data[dest_x + dest_y * surface_data->width] =
|
||||
(color == source_color) ? target_color : color;
|
||||
}
|
||||
@@ -479,34 +427,28 @@ void Surface::renderWithColorReplace(int x, int y, Uint8 source_color, Uint8 tar
|
||||
}
|
||||
|
||||
// Vuelca la superficie a una textura
|
||||
void Surface::copyToTexture(SDL_Renderer *renderer, SDL_Texture *texture)
|
||||
{
|
||||
if (!renderer || !texture || !surface_data_)
|
||||
{
|
||||
void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture) {
|
||||
if (!renderer || !texture || !surface_data_) {
|
||||
throw std::runtime_error("Renderer or texture is null.");
|
||||
}
|
||||
|
||||
if (surface_data_->width <= 0 || surface_data_->height <= 0 || !surface_data_->data.get())
|
||||
{
|
||||
if (surface_data_->width <= 0 || surface_data_->height <= 0 || !surface_data_->data.get()) {
|
||||
throw std::runtime_error("Invalid surface dimensions or data.");
|
||||
}
|
||||
|
||||
Uint32 *pixels = nullptr;
|
||||
Uint32* pixels = nullptr;
|
||||
int pitch = 0;
|
||||
|
||||
// Bloquea la textura para modificar los píxeles directamente
|
||||
if (SDL_LockTexture(texture, nullptr, reinterpret_cast<void **>(&pixels), &pitch) != 0)
|
||||
{
|
||||
if (SDL_LockTexture(texture, nullptr, reinterpret_cast<void**>(&pixels), &pitch) != 0) {
|
||||
throw std::runtime_error("Failed to lock texture: " + std::string(SDL_GetError()));
|
||||
}
|
||||
|
||||
// Convertir `pitch` de bytes a Uint32 (asegurando alineación correcta en hardware)
|
||||
int row_stride = pitch / sizeof(Uint32);
|
||||
|
||||
for (int y = 0; y < surface_data_->height; ++y)
|
||||
{
|
||||
for (int x = 0; x < surface_data_->width; ++x)
|
||||
{
|
||||
for (int y = 0; y < surface_data_->height; ++y) {
|
||||
for (int x = 0; x < surface_data_->width; ++x) {
|
||||
// Calcular la posición correcta en la textura teniendo en cuenta el stride
|
||||
int texture_index = y * row_stride + x;
|
||||
int surface_index = y * surface_data_->width + x;
|
||||
@@ -518,39 +460,32 @@ void Surface::copyToTexture(SDL_Renderer *renderer, SDL_Texture *texture)
|
||||
SDL_UnlockTexture(texture); // Desbloquea la textura
|
||||
|
||||
// Renderiza la textura en la pantalla completa
|
||||
if (SDL_RenderCopy(renderer, texture, nullptr, nullptr) != 0)
|
||||
{
|
||||
if (SDL_RenderCopy(renderer, texture, nullptr, nullptr) != 0) {
|
||||
throw std::runtime_error("Failed to copy texture to renderer: " + std::string(SDL_GetError()));
|
||||
}
|
||||
}
|
||||
|
||||
// Vuelca la superficie a una textura
|
||||
void Surface::copyToTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Rect *srcRect, SDL_Rect *destRect)
|
||||
{
|
||||
if (!renderer || !texture || !surface_data_)
|
||||
{
|
||||
void Surface::copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Rect* srcRect, SDL_Rect* destRect) {
|
||||
if (!renderer || !texture || !surface_data_) {
|
||||
throw std::runtime_error("Renderer or texture is null.");
|
||||
}
|
||||
|
||||
if (surface_data_->width <= 0 || surface_data_->height <= 0 || !surface_data_->data.get())
|
||||
{
|
||||
if (surface_data_->width <= 0 || surface_data_->height <= 0 || !surface_data_->data.get()) {
|
||||
throw std::runtime_error("Invalid surface dimensions or data.");
|
||||
}
|
||||
|
||||
Uint32 *pixels = nullptr;
|
||||
Uint32* pixels = nullptr;
|
||||
int pitch = 0;
|
||||
|
||||
if (SDL_LockTexture(texture, destRect, reinterpret_cast<void **>(&pixels), &pitch) != 0)
|
||||
{
|
||||
if (SDL_LockTexture(texture, destRect, reinterpret_cast<void**>(&pixels), &pitch) != 0) {
|
||||
throw std::runtime_error("Failed to lock texture: " + std::string(SDL_GetError()));
|
||||
}
|
||||
|
||||
int row_stride = pitch / sizeof(Uint32);
|
||||
|
||||
for (int y = 0; y < surface_data_->height; ++y)
|
||||
{
|
||||
for (int x = 0; x < surface_data_->width; ++x)
|
||||
{
|
||||
for (int y = 0; y < surface_data_->height; ++y) {
|
||||
for (int x = 0; x < surface_data_->width; ++x) {
|
||||
int texture_index = y * row_stride + x;
|
||||
int surface_index = y * surface_data_->width + x;
|
||||
|
||||
@@ -561,25 +496,21 @@ void Surface::copyToTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Re
|
||||
SDL_UnlockTexture(texture);
|
||||
|
||||
// Renderiza la textura con los rectángulos especificados
|
||||
if (SDL_RenderCopy(renderer, texture, srcRect, destRect) != 0)
|
||||
{
|
||||
if (SDL_RenderCopy(renderer, texture, srcRect, destRect) != 0) {
|
||||
throw std::runtime_error("Failed to copy texture to renderer: " + std::string(SDL_GetError()));
|
||||
}
|
||||
}
|
||||
|
||||
// Realiza un efecto de fundido en la paleta principal
|
||||
bool Surface::fadePalette()
|
||||
{
|
||||
bool Surface::fadePalette() {
|
||||
// Verificar que el tamaño mínimo de palette_ sea adecuado
|
||||
static constexpr int palette_size = 19;
|
||||
if (sizeof(palette_) / sizeof(palette_[0]) < palette_size)
|
||||
{
|
||||
if (sizeof(palette_) / sizeof(palette_[0]) < palette_size) {
|
||||
throw std::runtime_error("Palette size is insufficient for fadePalette operation.");
|
||||
}
|
||||
|
||||
// Desplazar colores (pares e impares)
|
||||
for (int i = 18; i > 1; --i)
|
||||
{
|
||||
for (int i = 18; i > 1; --i) {
|
||||
palette_[i] = palette_[i - 2];
|
||||
}
|
||||
|
||||
@@ -591,8 +522,7 @@ bool Surface::fadePalette()
|
||||
}
|
||||
|
||||
// Realiza un efecto de fundido en la paleta secundaria
|
||||
bool Surface::fadeSubPalette(Uint32 delay)
|
||||
{
|
||||
bool Surface::fadeSubPalette(Uint32 delay) {
|
||||
// Variable estática para almacenar el último tick
|
||||
static Uint32 last_tick = 0;
|
||||
|
||||
@@ -600,8 +530,7 @@ bool Surface::fadeSubPalette(Uint32 delay)
|
||||
Uint32 current_tick = SDL_GetTicks();
|
||||
|
||||
// Verificar si ha pasado el tiempo de retardo
|
||||
if (current_tick - last_tick < delay)
|
||||
{
|
||||
if (current_tick - last_tick < delay) {
|
||||
return false; // No se realiza el fade
|
||||
}
|
||||
|
||||
@@ -610,14 +539,12 @@ bool Surface::fadeSubPalette(Uint32 delay)
|
||||
|
||||
// Verificar que el tamaño mínimo de sub_palette_ sea adecuado
|
||||
static constexpr int sub_palette_size = 19;
|
||||
if (sizeof(sub_palette_) / sizeof(sub_palette_[0]) < sub_palette_size)
|
||||
{
|
||||
if (sizeof(sub_palette_) / sizeof(sub_palette_[0]) < sub_palette_size) {
|
||||
throw std::runtime_error("Palette size is insufficient for fadePalette operation.");
|
||||
}
|
||||
|
||||
// Desplazar colores (pares e impares)
|
||||
for (int i = 18; i > 1; --i)
|
||||
{
|
||||
for (int i = 18; i > 1; --i) {
|
||||
sub_palette_[i] = sub_palette_[i - 2];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL2/SDL_render.h> // Para SDL_FLIP_NONE, SDL_RendererFlip, SDL_Re...
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint8, Uint16, Uint32
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL3/SDL_render.h> // Para SDL_FLIP_NONE, SDL_RendererFlip, SDL_Re...
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint8, Uint16, Uint32
|
||||
|
||||
#include <array> // Para array
|
||||
#include <memory> // Para default_delete, shared_ptr, __shared_pt...
|
||||
#include <numeric> // Para iota
|
||||
#include <string> // Para string
|
||||
#include <utility> // Para move
|
||||
|
||||
#include "utils.h" // Para PaletteColor
|
||||
|
||||
// Alias
|
||||
@@ -15,69 +17,74 @@ using Palette = std::array<Uint32, 256>;
|
||||
using SubPalette = std::array<Uint8, 256>;
|
||||
|
||||
// Carga una paleta desde un archivo .gif
|
||||
Palette loadPalette(const std::string &file_path);
|
||||
Palette loadPalette(const std::string& file_path);
|
||||
|
||||
// Carga una paleta desde un archivo .pal
|
||||
Palette readPalFile(const std::string &file_path);
|
||||
Palette readPalFile(const std::string& file_path);
|
||||
|
||||
struct SurfaceData
|
||||
{
|
||||
struct SurfaceData {
|
||||
std::shared_ptr<Uint8[]> data; // Usa std::shared_ptr para gestión automática
|
||||
Uint16 width; // Ancho de la imagen
|
||||
Uint16 height; // Alto de la imagen
|
||||
|
||||
// Constructor por defecto
|
||||
SurfaceData() : data(nullptr), width(0), height(0) {}
|
||||
SurfaceData()
|
||||
: data(nullptr),
|
||||
width(0),
|
||||
height(0) {}
|
||||
|
||||
// Constructor que inicializa dimensiones y asigna memoria
|
||||
SurfaceData(Uint16 w, Uint16 h)
|
||||
: data(std::shared_ptr<Uint8[]>(new Uint8[w * h](), std::default_delete<Uint8[]>())), width(w), height(h) {}
|
||||
: data(std::shared_ptr<Uint8[]>(new Uint8[w * h](), std::default_delete<Uint8[]>())),
|
||||
width(w),
|
||||
height(h) {}
|
||||
|
||||
// Constructor para inicializar directamente con datos
|
||||
SurfaceData(Uint16 w, Uint16 h, std::shared_ptr<Uint8[]> pixels)
|
||||
: data(std::move(pixels)), width(w), height(h) {}
|
||||
: data(std::move(pixels)),
|
||||
width(w),
|
||||
height(h) {}
|
||||
|
||||
// Constructor de movimiento
|
||||
SurfaceData(SurfaceData &&other) noexcept = default;
|
||||
SurfaceData(SurfaceData&& other) noexcept = default;
|
||||
|
||||
// Operador de movimiento
|
||||
SurfaceData &operator=(SurfaceData &&other) noexcept = default;
|
||||
SurfaceData& operator=(SurfaceData&& other) noexcept = default;
|
||||
|
||||
// Evita copias accidentales
|
||||
SurfaceData(const SurfaceData &) = delete;
|
||||
SurfaceData &operator=(const SurfaceData &) = delete;
|
||||
SurfaceData(const SurfaceData&) = delete;
|
||||
SurfaceData& operator=(const SurfaceData&) = delete;
|
||||
};
|
||||
|
||||
class Surface
|
||||
{
|
||||
private:
|
||||
class Surface {
|
||||
private:
|
||||
std::shared_ptr<SurfaceData> surface_data_; // Datos a dibujar
|
||||
Palette palette_; // Paleta para volcar la SurfaceData a una Textura
|
||||
SubPalette sub_palette_; // Paleta para reindexar colores
|
||||
int transparent_color_; // Indice de la paleta que se omite en la copia de datos
|
||||
|
||||
public:
|
||||
public:
|
||||
// Constructor
|
||||
Surface(int w, int h);
|
||||
explicit Surface(const std::string &file_path);
|
||||
explicit Surface(const std::string& file_path);
|
||||
|
||||
// Destructor
|
||||
~Surface() = default;
|
||||
|
||||
// Carga una SurfaceData desde un archivo
|
||||
SurfaceData loadSurface(const std::string &file_path);
|
||||
SurfaceData loadSurface(const std::string& file_path);
|
||||
|
||||
// Carga una paleta desde un archivo
|
||||
void loadPalette(const std::string &file_path);
|
||||
void loadPalette(const std::string& file_path);
|
||||
void loadPalette(Palette palette);
|
||||
|
||||
// Copia una región de la SurfaceData de origen a la SurfaceData de destino
|
||||
void render(int dx, int dy, int sx, int sy, int w, int h);
|
||||
void render(int x, int y, SDL_Rect *clip = nullptr, SDL_RendererFlip flip = SDL_FLIP_NONE);
|
||||
void render(SDL_Rect *srcRect = nullptr, SDL_Rect *dstRect = nullptr, SDL_RendererFlip flip = SDL_FLIP_NONE);
|
||||
void render(int x, int y, SDL_Rect* clip = nullptr, SDL_RendererFlip flip = SDL_FLIP_NONE);
|
||||
void render(SDL_Rect* srcRect = nullptr, SDL_Rect* dstRect = nullptr, SDL_RendererFlip flip = SDL_FLIP_NONE);
|
||||
|
||||
// Copia una región de la SurfaceData de origen a la SurfaceData de destino reemplazando un color por otro
|
||||
void renderWithColorReplace(int x, int y, Uint8 source_color = 0, Uint8 target_color = 0, SDL_Rect *srcRect = nullptr, SDL_RendererFlip flip = SDL_FLIP_NONE);
|
||||
void renderWithColorReplace(int x, int y, Uint8 source_color = 0, Uint8 target_color = 0, SDL_Rect* srcRect = nullptr, SDL_RendererFlip flip = SDL_FLIP_NONE);
|
||||
|
||||
// Establece un color en la paleta
|
||||
void setColor(int index, Uint32 color);
|
||||
@@ -86,8 +93,8 @@ public:
|
||||
void clear(Uint8 color);
|
||||
|
||||
// Vuelca la SurfaceData a una textura
|
||||
void copyToTexture(SDL_Renderer *renderer, SDL_Texture *texture);
|
||||
void copyToTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Rect *srcRect, SDL_Rect *destRect);
|
||||
void copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture);
|
||||
void copyToTexture(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Rect* srcRect, SDL_Rect* destRect);
|
||||
|
||||
// Realiza un efecto de fundido en las paletas
|
||||
bool fadePalette();
|
||||
@@ -100,10 +107,10 @@ public:
|
||||
Uint8 getPixel(int x, int y);
|
||||
|
||||
// Dibuja un rectangulo relleno
|
||||
void fillRect(const SDL_Rect *rect, Uint8 color);
|
||||
void fillRect(const SDL_Rect* rect, Uint8 color);
|
||||
|
||||
// Dibuja el borde de un rectangulo
|
||||
void drawRectBorder(const SDL_Rect *rect, Uint8 color);
|
||||
void drawRectBorder(const SDL_Rect* rect, Uint8 color);
|
||||
|
||||
// Dibuja una linea
|
||||
void drawLine(int x1, int y1, int x2, int y2, Uint8 color);
|
||||
@@ -121,8 +128,8 @@ public:
|
||||
void setTransparentColor(Uint8 color = static_cast<Uint8>(PaletteColor::TRANSPARENT)) { transparent_color_ = color; }
|
||||
|
||||
// Paleta
|
||||
void setPalette(const std::array<Uint32, 256> &palette) { palette_ = palette; }
|
||||
void setPalette(const std::array<Uint32, 256>& palette) { palette_ = palette; }
|
||||
|
||||
// Inicializa la sub paleta
|
||||
void initializeSubPalette(SubPalette &palette) { std::iota(palette.begin(), palette.end(), 0); }
|
||||
void initializeSubPalette(SubPalette& palette) { std::iota(palette.begin(), palette.end(), 0); }
|
||||
};
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
#include "text.h"
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
#include <stddef.h> // Para size_t
|
||||
|
||||
#include <fstream> // Para basic_ifstream, basic_istream, basic_ostream
|
||||
#include <iostream> // Para cerr
|
||||
#include <stdexcept> // Para runtime_error
|
||||
|
||||
#include "s_sprite.h" // Para SSprite
|
||||
#include "screen.h" // Para Screen
|
||||
#include "surface.h" // Para Surface
|
||||
#include "utils.h" // Para getFileName, stringToColor, printWithDots
|
||||
|
||||
// Llena una estructuta TextFile desde un fichero
|
||||
std::shared_ptr<TextFile> loadTextFile(const std::string &file_path)
|
||||
{
|
||||
std::shared_ptr<TextFile> loadTextFile(const std::string& file_path) {
|
||||
auto tf = std::make_shared<TextFile>();
|
||||
|
||||
// Inicializa a cero el vector con las coordenadas
|
||||
for (int i = 0; i < 128; ++i)
|
||||
{
|
||||
for (int i = 0; i < 128; ++i) {
|
||||
tf->offset[i].x = 0;
|
||||
tf->offset[i].y = 0;
|
||||
tf->offset[i].w = 0;
|
||||
@@ -27,8 +28,7 @@ std::shared_ptr<TextFile> loadTextFile(const std::string &file_path)
|
||||
// Abre el fichero para leer los valores
|
||||
std::ifstream file(file_path);
|
||||
|
||||
if (file.is_open() && file.good())
|
||||
{
|
||||
if (file.is_open() && file.good()) {
|
||||
std::string buffer;
|
||||
|
||||
// Lee los dos primeros valores del fichero
|
||||
@@ -43,8 +43,7 @@ std::shared_ptr<TextFile> loadTextFile(const std::string &file_path)
|
||||
// lee el resto de datos del fichero
|
||||
auto index = 32;
|
||||
auto line_read = 0;
|
||||
while (std::getline(file, buffer))
|
||||
{
|
||||
while (std::getline(file, buffer)) {
|
||||
// Almacena solo las lineas impares
|
||||
if (line_read % 2 == 1)
|
||||
tf->offset[index++].w = std::stoi(buffer);
|
||||
@@ -60,15 +59,13 @@ std::shared_ptr<TextFile> loadTextFile(const std::string &file_path)
|
||||
}
|
||||
|
||||
// El fichero no se puede abrir
|
||||
else
|
||||
{
|
||||
else {
|
||||
std::cerr << "Error: Fichero no encontrado " << getFileName(file_path) << std::endl;
|
||||
throw std::runtime_error("Fichero no encontrado: " + getFileName(file_path));
|
||||
}
|
||||
|
||||
// Establece las coordenadas para cada caracter ascii de la cadena y su ancho
|
||||
for (int i = 32; i < 128; ++i)
|
||||
{
|
||||
for (int i = 32; i < 128; ++i) {
|
||||
tf->offset[i].x = ((i - 32) % 15) * tf->box_width;
|
||||
tf->offset[i].y = ((i - 32) / 15) * tf->box_height;
|
||||
}
|
||||
@@ -77,16 +74,14 @@ std::shared_ptr<TextFile> loadTextFile(const std::string &file_path)
|
||||
}
|
||||
|
||||
// Constructor
|
||||
Text::Text(std::shared_ptr<Surface> surface, const std::string &text_file)
|
||||
{
|
||||
Text::Text(std::shared_ptr<Surface> surface, const std::string& text_file) {
|
||||
// Carga los offsets desde el fichero
|
||||
auto tf = loadTextFile(text_file);
|
||||
|
||||
// Inicializa variables desde la estructura
|
||||
box_height_ = tf->box_height;
|
||||
box_width_ = tf->box_width;
|
||||
for (int i = 0; i < 128; ++i)
|
||||
{
|
||||
for (int i = 0; i < 128; ++i) {
|
||||
offset_[i].x = tf->offset[i].x;
|
||||
offset_[i].y = tf->offset[i].y;
|
||||
offset_[i].w = tf->offset[i].w;
|
||||
@@ -100,13 +95,11 @@ Text::Text(std::shared_ptr<Surface> surface, const std::string &text_file)
|
||||
}
|
||||
|
||||
// Constructor
|
||||
Text::Text(std::shared_ptr<Surface> surface, std::shared_ptr<TextFile> text_file)
|
||||
{
|
||||
Text::Text(std::shared_ptr<Surface> surface, std::shared_ptr<TextFile> text_file) {
|
||||
// Inicializa variables desde la estructura
|
||||
box_height_ = text_file->box_height;
|
||||
box_width_ = text_file->box_width;
|
||||
for (int i = 0; i < 128; ++i)
|
||||
{
|
||||
for (int i = 0; i < 128; ++i) {
|
||||
offset_[i].x = text_file->offset[i].x;
|
||||
offset_[i].y = text_file->offset[i].y;
|
||||
offset_[i].w = text_file->offset[i].w;
|
||||
@@ -120,16 +113,14 @@ Text::Text(std::shared_ptr<Surface> surface, std::shared_ptr<TextFile> text_file
|
||||
}
|
||||
|
||||
// Escribe texto en pantalla
|
||||
void Text::write(int x, int y, const std::string &text, int kerning, int lenght)
|
||||
{
|
||||
void Text::write(int x, int y, const std::string& text, int kerning, int lenght) {
|
||||
int shift = 0;
|
||||
|
||||
if (lenght == -1)
|
||||
lenght = text.length();
|
||||
|
||||
sprite_->setY(y);
|
||||
for (int i = 0; i < lenght; ++i)
|
||||
{
|
||||
for (int i = 0; i < lenght; ++i) {
|
||||
auto index = static_cast<int>(text[i]);
|
||||
sprite_->setClip(offset_[index].x, offset_[index].y, box_width_, box_height_);
|
||||
sprite_->setX(x + shift);
|
||||
@@ -139,8 +130,7 @@ void Text::write(int x, int y, const std::string &text, int kerning, int lenght)
|
||||
}
|
||||
|
||||
// Escribe el texto en una surface
|
||||
std::shared_ptr<Surface> Text::writeToSurface(const std::string &text, int zoom, int kerning)
|
||||
{
|
||||
std::shared_ptr<Surface> Text::writeToSurface(const std::string& text, int zoom, int kerning) {
|
||||
auto width = lenght(text, kerning) * zoom;
|
||||
auto height = box_height_ * zoom;
|
||||
auto surface = std::make_shared<Surface>(width, height);
|
||||
@@ -154,8 +144,7 @@ std::shared_ptr<Surface> Text::writeToSurface(const std::string &text, int zoom,
|
||||
}
|
||||
|
||||
// Escribe el texto con extras en una surface
|
||||
std::shared_ptr<Surface> Text::writeDXToSurface(Uint8 flags, const std::string &text, int kerning, Uint8 textColor, Uint8 shadow_distance, Uint8 shadow_color, int lenght)
|
||||
{
|
||||
std::shared_ptr<Surface> Text::writeDXToSurface(Uint8 flags, const std::string& text, int kerning, Uint8 textColor, Uint8 shadow_distance, Uint8 shadow_color, int lenght) {
|
||||
auto width = Text::lenght(text, kerning) + shadow_distance;
|
||||
auto height = box_height_ + shadow_distance;
|
||||
auto surface = std::make_shared<Surface>(width, height);
|
||||
@@ -169,18 +158,15 @@ std::shared_ptr<Surface> Text::writeDXToSurface(Uint8 flags, const std::string &
|
||||
}
|
||||
|
||||
// Escribe el texto con colores
|
||||
void Text::writeColored(int x, int y, const std::string &text, Uint8 color, int kerning, int lenght)
|
||||
{
|
||||
void Text::writeColored(int x, int y, const std::string& text, Uint8 color, int kerning, int lenght) {
|
||||
int shift = 0;
|
||||
|
||||
if (lenght == -1)
|
||||
{
|
||||
if (lenght == -1) {
|
||||
lenght = text.length();
|
||||
}
|
||||
|
||||
sprite_->setY(y);
|
||||
for (int i = 0; i < lenght; ++i)
|
||||
{
|
||||
for (int i = 0; i < lenght; ++i) {
|
||||
auto index = static_cast<int>(text[i]);
|
||||
sprite_->setClip(offset_[index].x, offset_[index].y, box_width_, box_height_);
|
||||
sprite_->setX(x + shift);
|
||||
@@ -190,65 +176,52 @@ void Text::writeColored(int x, int y, const std::string &text, Uint8 color, int
|
||||
}
|
||||
|
||||
// Escribe el texto con sombra
|
||||
void Text::writeShadowed(int x, int y, const std::string &text, Uint8 color, Uint8 shadow_distance, int kerning, int lenght)
|
||||
{
|
||||
void Text::writeShadowed(int x, int y, const std::string& text, Uint8 color, Uint8 shadow_distance, int kerning, int lenght) {
|
||||
writeColored(x + shadow_distance, y + shadow_distance, text, color, kerning, lenght);
|
||||
write(x, y, text, kerning, lenght);
|
||||
}
|
||||
|
||||
// Escribe el texto centrado en un punto x
|
||||
void Text::writeCentered(int x, int y, const std::string &text, int kerning, int lenght)
|
||||
{
|
||||
void Text::writeCentered(int x, int y, const std::string& text, int kerning, int lenght) {
|
||||
x -= (Text::lenght(text, kerning) / 2);
|
||||
write(x, y, text, kerning, lenght);
|
||||
}
|
||||
|
||||
// Escribe texto con extras
|
||||
void Text::writeDX(Uint8 flags, int x, int y, const std::string &text, int kerning, Uint8 textColor, Uint8 shadow_distance, Uint8 shadow_color, int lenght)
|
||||
{
|
||||
void Text::writeDX(Uint8 flags, int x, int y, const std::string& text, int kerning, Uint8 textColor, Uint8 shadow_distance, Uint8 shadow_color, int lenght) {
|
||||
const auto centered = ((flags & TEXT_CENTER) == TEXT_CENTER);
|
||||
const auto shadowed = ((flags & TEXT_SHADOW) == TEXT_SHADOW);
|
||||
const auto colored = ((flags & TEXT_COLOR) == TEXT_COLOR);
|
||||
const auto stroked = ((flags & TEXT_STROKE) == TEXT_STROKE);
|
||||
|
||||
if (centered)
|
||||
{
|
||||
if (centered) {
|
||||
x -= (Text::lenght(text, kerning) / 2);
|
||||
}
|
||||
|
||||
if (shadowed)
|
||||
{
|
||||
if (shadowed) {
|
||||
writeColored(x + shadow_distance, y + shadow_distance, text, shadow_color, kerning, lenght);
|
||||
}
|
||||
|
||||
if (stroked)
|
||||
{
|
||||
for (int dist = 1; dist <= shadow_distance; ++dist)
|
||||
{
|
||||
for (int dy = -dist; dy <= dist; ++dy)
|
||||
{
|
||||
for (int dx = -dist; dx <= dist; ++dx)
|
||||
{
|
||||
if (stroked) {
|
||||
for (int dist = 1; dist <= shadow_distance; ++dist) {
|
||||
for (int dy = -dist; dy <= dist; ++dy) {
|
||||
for (int dx = -dist; dx <= dist; ++dx) {
|
||||
writeColored(x + dx, y + dy, text, shadow_color, kerning, lenght);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (colored)
|
||||
{
|
||||
if (colored) {
|
||||
writeColored(x, y, text, textColor, kerning, lenght);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
writeColored(x, y, text, textColor, kerning, lenght);
|
||||
// write(x, y, text, kerning, lenght);
|
||||
}
|
||||
}
|
||||
|
||||
// Obtiene la longitud en pixels de una cadena
|
||||
int Text::lenght(const std::string &text, int kerning) const
|
||||
{
|
||||
int Text::lenght(const std::string& text, int kerning) const {
|
||||
int shift = 0;
|
||||
for (size_t i = 0; i < text.length(); ++i)
|
||||
shift += (offset_[static_cast<int>(text[i])].w + kerning);
|
||||
@@ -258,13 +231,11 @@ int Text::lenght(const std::string &text, int kerning) const
|
||||
}
|
||||
|
||||
// Devuelve el valor de la variable
|
||||
int Text::getCharacterSize() const
|
||||
{
|
||||
int Text::getCharacterSize() const {
|
||||
return box_width_;
|
||||
}
|
||||
|
||||
// Establece si se usa un tamaño fijo de letra
|
||||
void Text::setFixedWidth(bool value)
|
||||
{
|
||||
void Text::setFixedWidth(bool value) {
|
||||
fixed_width_ = value;
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint8
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint8
|
||||
|
||||
#include <memory> // Para shared_ptr, unique_ptr
|
||||
#include <string> // Para string
|
||||
|
||||
#include "s_sprite.h" // Para SSprite
|
||||
class Surface; // lines 8-8
|
||||
|
||||
@@ -11,25 +13,22 @@ constexpr int TEXT_SHADOW = 2;
|
||||
constexpr int TEXT_CENTER = 4;
|
||||
constexpr int TEXT_STROKE = 8;
|
||||
|
||||
struct TextOffset
|
||||
{
|
||||
struct TextOffset {
|
||||
int x, y, w;
|
||||
};
|
||||
|
||||
struct TextFile
|
||||
{
|
||||
struct TextFile {
|
||||
int box_width; // Anchura de la caja de cada caracter en el png
|
||||
int box_height; // Altura de la caja de cada caracter en el png
|
||||
TextOffset offset[128]; // Vector con las posiciones y ancho de cada letra
|
||||
};
|
||||
|
||||
// Llena una estructuta TextFile desde un fichero
|
||||
std::shared_ptr<TextFile> loadTextFile(const std::string &file_path);
|
||||
std::shared_ptr<TextFile> loadTextFile(const std::string& file_path);
|
||||
|
||||
// Clase texto. Pinta texto en pantalla a partir de un bitmap
|
||||
class Text
|
||||
{
|
||||
private:
|
||||
class Text {
|
||||
private:
|
||||
// Objetos y punteros
|
||||
std::unique_ptr<SSprite> sprite_ = nullptr; // Objeto con los graficos para el texto
|
||||
|
||||
@@ -39,37 +38,37 @@ private:
|
||||
bool fixed_width_ = false; // Indica si el texto se ha de escribir con longitud fija en todas las letras
|
||||
TextOffset offset_[128] = {}; // Vector con las posiciones y ancho de cada letra
|
||||
|
||||
public:
|
||||
public:
|
||||
// Constructor
|
||||
Text(std::shared_ptr<Surface> surface, const std::string &text_file);
|
||||
Text(std::shared_ptr<Surface> surface, const std::string& text_file);
|
||||
Text(std::shared_ptr<Surface> surface, std::shared_ptr<TextFile> text_file);
|
||||
|
||||
// Destructor
|
||||
~Text() = default;
|
||||
|
||||
// Escribe el texto en pantalla
|
||||
void write(int x, int y, const std::string &text, int kerning = 1, int lenght = -1);
|
||||
void write(int x, int y, const std::string& text, int kerning = 1, int lenght = -1);
|
||||
|
||||
// Escribe el texto en una textura
|
||||
std::shared_ptr<Surface> writeToSurface(const std::string &text, int zoom = 1, int kerning = 1);
|
||||
std::shared_ptr<Surface> writeToSurface(const std::string& text, int zoom = 1, int kerning = 1);
|
||||
|
||||
// Escribe el texto con extras en una textura
|
||||
std::shared_ptr<Surface> writeDXToSurface(Uint8 flags, const std::string &text, int kerning = 1, Uint8 textColor = Uint8(), Uint8 shadow_distance = 1, Uint8 shadow_color = Uint8(), int lenght = -1);
|
||||
std::shared_ptr<Surface> writeDXToSurface(Uint8 flags, const std::string& text, int kerning = 1, Uint8 textColor = Uint8(), Uint8 shadow_distance = 1, Uint8 shadow_color = Uint8(), int lenght = -1);
|
||||
|
||||
// Escribe el texto con colores
|
||||
void writeColored(int x, int y, const std::string &text, Uint8 color, int kerning = 1, int lenght = -1);
|
||||
void writeColored(int x, int y, const std::string& text, Uint8 color, int kerning = 1, int lenght = -1);
|
||||
|
||||
// Escribe el texto con sombra
|
||||
void writeShadowed(int x, int y, const std::string &text, Uint8 color, Uint8 shadow_distance = 1, int kerning = 1, int lenght = -1);
|
||||
void writeShadowed(int x, int y, const std::string& text, Uint8 color, Uint8 shadow_distance = 1, int kerning = 1, int lenght = -1);
|
||||
|
||||
// Escribe el texto centrado en un punto x
|
||||
void writeCentered(int x, int y, const std::string &text, int kerning = 1, int lenght = -1);
|
||||
void writeCentered(int x, int y, const std::string& text, int kerning = 1, int lenght = -1);
|
||||
|
||||
// Escribe texto con extras
|
||||
void writeDX(Uint8 flags, int x, int y, const std::string &text, int kerning = 1, Uint8 textColor = Uint8(), Uint8 shadow_distance = 1, Uint8 shadow_color = Uint8(), int lenght = -1);
|
||||
void writeDX(Uint8 flags, int x, int y, const std::string& text, int kerning = 1, Uint8 textColor = Uint8(), Uint8 shadow_distance = 1, Uint8 shadow_color = Uint8(), int lenght = -1);
|
||||
|
||||
// Obtiene la longitud en pixels de una cadena
|
||||
int lenght(const std::string &text, int kerning = 1) const;
|
||||
int lenght(const std::string& text, int kerning = 1) const;
|
||||
|
||||
// Devuelve el valor de la variable
|
||||
int getCharacterSize() const;
|
||||
|
||||
@@ -1,60 +1,54 @@
|
||||
|
||||
#include "texture.h"
|
||||
#include <SDL2/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL2/SDL_surface.h> // Para SDL_CreateRGBSurfaceWithFormatFrom
|
||||
|
||||
#include <SDL3/SDL_error.h> // Para SDL_GetError
|
||||
#include <SDL3/SDL_surface.h> // Para SDL_CreateRGBSurfaceWithFormatFrom
|
||||
|
||||
#include <iostream> // Para basic_ostream, operator<<, endl, cout
|
||||
#include <stdexcept> // Para runtime_error
|
||||
#include <string> // Para char_traits, operator<<, string, opera...
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "utils.h" // Para getFileName, Color, printWithDots
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h" // para stbi_failure_reason, stbi_image_free
|
||||
|
||||
// Constructor
|
||||
Texture::Texture(SDL_Renderer *renderer, const std::string &path)
|
||||
Texture::Texture(SDL_Renderer* renderer, const std::string& path)
|
||||
: renderer_(renderer),
|
||||
path_(path)
|
||||
{
|
||||
path_(path) {
|
||||
// Carga el fichero en la textura
|
||||
if (!path_.empty())
|
||||
{
|
||||
if (!path_.empty()) {
|
||||
// Obtiene la extensión
|
||||
const std::string extension = path_.substr(path_.find_last_of(".") + 1);
|
||||
|
||||
// .png
|
||||
if (extension == "png")
|
||||
{
|
||||
if (extension == "png") {
|
||||
loadFromFile(path_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Destructor
|
||||
Texture::~Texture()
|
||||
{
|
||||
Texture::~Texture() {
|
||||
unloadTexture();
|
||||
palettes_.clear();
|
||||
}
|
||||
|
||||
// Carga una imagen desde un fichero
|
||||
bool Texture::loadFromFile(const std::string &file_path)
|
||||
{
|
||||
if (file_path.empty())
|
||||
{
|
||||
bool Texture::loadFromFile(const std::string& file_path) {
|
||||
if (file_path.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int req_format = STBI_rgb_alpha;
|
||||
int width, height, orig_format;
|
||||
unsigned char *data = stbi_load(file_path.c_str(), &width, &height, &orig_format, req_format);
|
||||
if (!data)
|
||||
{
|
||||
unsigned char* data = stbi_load(file_path.c_str(), &width, &height, &orig_format, req_format);
|
||||
if (!data) {
|
||||
std::cerr << "Error: Fichero no encontrado " << getFileName(file_path) << std::endl;
|
||||
throw std::runtime_error("Fichero no encontrado: " + getFileName(file_path));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
printWithDots("Image : ", getFileName(file_path), "[ LOADED ]");
|
||||
}
|
||||
|
||||
@@ -69,24 +63,18 @@ bool Texture::loadFromFile(const std::string &file_path)
|
||||
unloadTexture();
|
||||
|
||||
// La textura final
|
||||
SDL_Texture *newTexture = nullptr;
|
||||
SDL_Texture* newTexture = nullptr;
|
||||
|
||||
// Carga la imagen desde una ruta específica
|
||||
auto loadedSurface = SDL_CreateRGBSurfaceWithFormatFrom(static_cast<void *>(data), width, height, depth, pitch, pixel_format);
|
||||
if (loadedSurface == nullptr)
|
||||
{
|
||||
auto loadedSurface = SDL_CreateRGBSurfaceWithFormatFrom(static_cast<void*>(data), width, height, depth, pitch, pixel_format);
|
||||
if (loadedSurface == nullptr) {
|
||||
std::cout << "Unable to load image " << file_path << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Crea la textura desde los pixels de la surface
|
||||
newTexture = SDL_CreateTextureFromSurface(renderer_, loadedSurface);
|
||||
if (newTexture == nullptr)
|
||||
{
|
||||
if (newTexture == nullptr) {
|
||||
std::cout << "Unable to create texture from " << file_path << "! SDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Obtiene las dimensiones de la imagen
|
||||
width_ = loadedSurface->w;
|
||||
height_ = loadedSurface->h;
|
||||
@@ -103,16 +91,12 @@ bool Texture::loadFromFile(const std::string &file_path)
|
||||
}
|
||||
|
||||
// Crea una textura en blanco
|
||||
bool Texture::createBlank(int width, int height, SDL_PixelFormatEnum format, SDL_TextureAccess access)
|
||||
{
|
||||
bool Texture::createBlank(int width, int height, SDL_PixelFormatEnum format, SDL_TextureAccess access) {
|
||||
// Crea una textura sin inicializar
|
||||
texture_ = SDL_CreateTexture(renderer_, format, access, width, height);
|
||||
if (!texture_)
|
||||
{
|
||||
if (!texture_) {
|
||||
std::cout << "Unable to create blank texture! SDL Error: " << SDL_GetError() << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
width_ = width;
|
||||
height_ = height;
|
||||
}
|
||||
@@ -121,11 +105,9 @@ bool Texture::createBlank(int width, int height, SDL_PixelFormatEnum format, SDL
|
||||
}
|
||||
|
||||
// Libera la memoria de la textura
|
||||
void Texture::unloadTexture()
|
||||
{
|
||||
void Texture::unloadTexture() {
|
||||
// Libera la textura
|
||||
if (texture_)
|
||||
{
|
||||
if (texture_) {
|
||||
SDL_DestroyTexture(texture_);
|
||||
texture_ = nullptr;
|
||||
width_ = 0;
|
||||
@@ -144,21 +126,18 @@ void Texture::setBlendMode(SDL_BlendMode blending) { SDL_SetTextureBlendMode(tex
|
||||
void Texture::setAlpha(Uint8 alpha) { SDL_SetTextureAlphaMod(texture_, alpha); }
|
||||
|
||||
// Renderiza la textura en un punto específico
|
||||
void Texture::render(int x, int y, SDL_Rect *clip, float zoomW, float zoomH, double angle, SDL_Point *center, SDL_RendererFlip flip)
|
||||
{
|
||||
void Texture::render(int x, int y, SDL_Rect* clip, float zoomW, float zoomH, double angle, SDL_Point* center, SDL_RendererFlip flip) {
|
||||
// Establece el destino de renderizado en la pantalla
|
||||
SDL_Rect renderQuad = {x, y, width_, height_};
|
||||
|
||||
// Obtiene las dimesiones del clip de renderizado
|
||||
if (clip != nullptr)
|
||||
{
|
||||
if (clip != nullptr) {
|
||||
renderQuad.w = clip->w;
|
||||
renderQuad.h = clip->h;
|
||||
}
|
||||
|
||||
// Calcula el zoom y las coordenadas
|
||||
if (zoomH != 1.0f || zoomW != 1.0f)
|
||||
{
|
||||
if (zoomH != 1.0f || zoomW != 1.0f) {
|
||||
renderQuad.x = renderQuad.x + (renderQuad.w / 2);
|
||||
renderQuad.y = renderQuad.y + (renderQuad.h / 2);
|
||||
renderQuad.w = renderQuad.w * zoomW;
|
||||
@@ -172,7 +151,7 @@ void Texture::render(int x, int y, SDL_Rect *clip, float zoomW, float zoomH, dou
|
||||
}
|
||||
|
||||
// Establece la textura como objetivo de renderizado
|
||||
void Texture::setAsRenderTarget(SDL_Renderer *renderer) { SDL_SetRenderTarget(renderer, texture_); }
|
||||
void Texture::setAsRenderTarget(SDL_Renderer* renderer) { SDL_SetRenderTarget(renderer, texture_); }
|
||||
|
||||
// Obtiene el ancho de la imagen
|
||||
int Texture::getWidth() { return width_; }
|
||||
@@ -184,7 +163,7 @@ int Texture::getHeight() { return height_; }
|
||||
bool Texture::reLoad() { return loadFromFile(path_); }
|
||||
|
||||
// Obtiene la textura
|
||||
SDL_Texture *Texture::getSDLTexture() { return texture_; }
|
||||
SDL_Texture* Texture::getSDLTexture() { return texture_; }
|
||||
|
||||
// Obtiene el renderizador
|
||||
SDL_Renderer *Texture::getRenderer() { return renderer_; }
|
||||
SDL_Renderer* Texture::getRenderer() { return renderer_; }
|
||||
@@ -1,20 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_blendmode.h> // Para SDL_BlendMode
|
||||
#include <SDL2/SDL_pixels.h> // Para SDL_PIXELFORMAT_RGBA8888, SDL_PixelF...
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Point, SDL_Rect
|
||||
#include <SDL2/SDL_render.h> // Para SDL_Renderer, SDL_FLIP_NONE, SDL_TEX...
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint8, Uint32
|
||||
#include <SDL3/SDL_blendmode.h> // Para SDL_BlendMode
|
||||
#include <SDL3/SDL_pixels.h> // Para SDL_PIXELFORMAT_RGBA8888, SDL_PixelF...
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Point, SDL_Rect
|
||||
#include <SDL3/SDL_render.h> // Para SDL_Renderer, SDL_FLIP_NONE, SDL_TEX...
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint8, Uint32
|
||||
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
struct Color; // lines 11-11
|
||||
|
||||
class Texture
|
||||
{
|
||||
private:
|
||||
class Texture {
|
||||
private:
|
||||
// Objetos y punteros
|
||||
SDL_Renderer *renderer_; // Renderizador donde dibujar la textura
|
||||
SDL_Texture *texture_ = nullptr; // La textura
|
||||
SDL_Renderer* renderer_; // Renderizador donde dibujar la textura
|
||||
SDL_Texture* texture_ = nullptr; // La textura
|
||||
|
||||
// Variables
|
||||
std::string path_; // Ruta de la imagen de la textura
|
||||
@@ -25,15 +25,15 @@ private:
|
||||
// Libera la memoria de la textura
|
||||
void unloadTexture();
|
||||
|
||||
public:
|
||||
public:
|
||||
// Constructor
|
||||
explicit Texture(SDL_Renderer *renderer, const std::string &path = std::string());
|
||||
explicit Texture(SDL_Renderer* renderer, const std::string& path = std::string());
|
||||
|
||||
// Destructor
|
||||
~Texture();
|
||||
|
||||
// Carga una imagen desde un fichero
|
||||
bool loadFromFile(const std::string &path);
|
||||
bool loadFromFile(const std::string& path);
|
||||
|
||||
// Crea una textura en blanco
|
||||
bool createBlank(int width, int height, SDL_PixelFormatEnum format = SDL_PIXELFORMAT_RGBA8888, SDL_TextureAccess = SDL_TEXTUREACCESS_TARGET);
|
||||
@@ -49,10 +49,10 @@ public:
|
||||
void setAlpha(Uint8 alpha);
|
||||
|
||||
// Renderiza la textura en un punto específico
|
||||
void render(int x, int y, SDL_Rect *clip = nullptr, float zoomW = 1, float zoomH = 1, double angle = 0.0, SDL_Point *center = nullptr, SDL_RendererFlip flip = SDL_FLIP_NONE);
|
||||
void render(int x, int y, SDL_Rect* clip = nullptr, float zoomW = 1, float zoomH = 1, double angle = 0.0, SDL_Point* center = nullptr, SDL_RendererFlip flip = SDL_FLIP_NONE);
|
||||
|
||||
// Establece la textura como objetivo de renderizado
|
||||
void setAsRenderTarget(SDL_Renderer *renderer);
|
||||
void setAsRenderTarget(SDL_Renderer* renderer);
|
||||
|
||||
// Obtiene el ancho de la imagen
|
||||
int getWidth();
|
||||
@@ -64,8 +64,8 @@ public:
|
||||
bool reLoad();
|
||||
|
||||
// Obtiene la textura
|
||||
SDL_Texture *getSDLTexture();
|
||||
SDL_Texture* getSDLTexture();
|
||||
|
||||
// Obtiene el renderizador
|
||||
SDL_Renderer *getRenderer();
|
||||
SDL_Renderer* getRenderer();
|
||||
};
|
||||
377
source/title.cpp
377
source/title.cpp
@@ -1,377 +0,0 @@
|
||||
#include "title.h"
|
||||
#include <SDL2/SDL_events.h> // Para SDL_PollEvent, SDL_Event, SDL_KEYDOWN
|
||||
#include <SDL2/SDL_scancode.h> // Para SDL_SCANCODE_1, SDL_SCANCODE_2
|
||||
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
||||
#include <algorithm> // Para clamp
|
||||
#include "cheevos.h" // Para Cheevos, Achievement
|
||||
#include "defines.h" // Para PLAY_AREA_CENTER_X, GAMECANVAS_WIDTH
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
#include "input.h" // Para Input, InputAction, INPUT_DO_NOT_ALLOW_REPEAT, REP...
|
||||
#include "options.h" // Para Options, options, SectionState, Section
|
||||
#include "resource.h" // Para Resource
|
||||
#include "s_sprite.h" // Para SSprite
|
||||
#include "screen.h" // Para Screen
|
||||
#include "surface.h" // Para Surface
|
||||
#include "text.h" // Para Text, TEXT_CENTER, TEXT_COLOR
|
||||
#include "utils.h" // Para stringToColor, PaletteColor, playMusic
|
||||
|
||||
// Constructor
|
||||
Title::Title()
|
||||
: title_logo_surface_(Resource::get()->getSurface("title_logo.gif")),
|
||||
title_logo_sprite_(std::make_shared<SSprite>(title_logo_surface_, 29, 9, title_logo_surface_->getWidth(), title_logo_surface_->getHeight())),
|
||||
loading_screen_surface_(Resource::get()->getSurface("loading_screen_color.gif")),
|
||||
loading_screen_sprite_(std::make_shared<SSprite>(loading_screen_surface_, 0, 0, loading_screen_surface_->getWidth(), loading_screen_surface_->getHeight())),
|
||||
bg_surface_(std::make_shared<Surface>(options.game.width, options.game.height))
|
||||
{
|
||||
// Inicializa variables
|
||||
state_ = options.section.subsection == Subsection::TITLE_WITH_LOADING_SCREEN ? TitleState::SHOW_LOADING_SCREEN : TitleState::SHOW_MENU;
|
||||
options.section.section = Section::TITLE;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
initMarquee();
|
||||
|
||||
// Crea y rellena la textura para mostrar los logros
|
||||
createCheevosTexture();
|
||||
|
||||
// Cambia el color del borde
|
||||
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
// Rellena la textura de fondo con todos los gráficos
|
||||
fillSurface();
|
||||
|
||||
// Inicia la musica
|
||||
playMusic("title.ogg");
|
||||
}
|
||||
|
||||
// Inicializa la marquesina
|
||||
void Title::initMarquee()
|
||||
{
|
||||
letters_.clear();
|
||||
long_text_ = "HEY JAILERS!! IT'S 2022 AND WE'RE STILL ROCKING LIKE IT'S 1998!!! HAVE YOU HEARD IT? JAILGAMES ARE BACK!! YEEESSS BACK!! MORE THAN 10 TITLES ON JAILDOC'S KITCHEN!! THATS A LOOOOOOT OF JAILGAMES, BUT WHICH ONE WILL STRIKE FIRST? THERE IS ALSO A NEW DEVICE TO COME THAT WILL BLOW YOUR MIND WITH JAILGAMES ON THE GO: P.A.C.O. BUT WAIT! WHAT'S THAT BEAUTY I'M SEEING RIGHT OVER THERE?? OOOH THAT TINY MINIASCII IS PURE LOVE!! I WANT TO LICK EVERY BYTE OF IT!! OH SHIT! AND DON'T FORGET TO BRING BACK THOSE OLD AND FAT MS-DOS JAILGAMES TO GITHUB TO KEEP THEM ALIVE!! WHAT WILL BE THE NEXT JAILDOC RELEASE? WHAT WILL BE THE NEXT PROJECT TO COME ALIVE?? OH BABY WE DON'T KNOW BUT HERE YOU CAN FIND THE ANSWER, YOU JUST HAVE TO COMPLETE JAILDOCTOR'S DILEMMA ... COULD YOU?";
|
||||
for (int i = 0; i < (int)long_text_.length(); ++i)
|
||||
{
|
||||
TitleLetter l;
|
||||
l.letter = long_text_.substr(i, 1);
|
||||
l.x = 256;
|
||||
l.enabled = false;
|
||||
letters_.push_back(l);
|
||||
}
|
||||
letters_[0].enabled = true;
|
||||
}
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void Title::checkEvents()
|
||||
{
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event))
|
||||
{
|
||||
globalEvents::check(event);
|
||||
|
||||
// Solo se comprueban estas teclas si no está activo el menu de logros
|
||||
if (event.type == SDL_KEYDOWN)
|
||||
{
|
||||
if (!show_cheevos_)
|
||||
{
|
||||
switch (event.key.keysym.scancode)
|
||||
{
|
||||
case SDL_SCANCODE_1:
|
||||
options.section.section = Section::GAME;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
break;
|
||||
|
||||
case SDL_SCANCODE_2:
|
||||
show_cheevos_ = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las entradas
|
||||
void Title::checkInput()
|
||||
{
|
||||
if (show_cheevos_)
|
||||
{
|
||||
if (Input::get()->checkInput(InputAction::DOWN, INPUT_ALLOW_REPEAT))
|
||||
{
|
||||
moveCheevosList(1);
|
||||
}
|
||||
else if (Input::get()->checkInput(InputAction::UP, INPUT_ALLOW_REPEAT))
|
||||
{
|
||||
moveCheevosList(0);
|
||||
}
|
||||
else if (Input::get()->checkInput(InputAction::ACCEPT, INPUT_DO_NOT_ALLOW_REPEAT))
|
||||
{
|
||||
hideCheevosList();
|
||||
counter_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (Input::get()->checkInput(InputAction::ACCEPT, INPUT_DO_NOT_ALLOW_REPEAT))
|
||||
{
|
||||
if (state_ == TitleState::SHOW_LOADING_SCREEN)
|
||||
{
|
||||
state_ = TitleState::FADE_LOADING_SCREEN;
|
||||
}
|
||||
}
|
||||
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Actualiza la marquesina
|
||||
void Title::updateMarquee()
|
||||
{
|
||||
const auto TEXT = Resource::get()->getText("gauntlet");
|
||||
|
||||
for (int i = 0; i < (int)letters_.size(); ++i)
|
||||
{
|
||||
if (letters_[i].enabled)
|
||||
{
|
||||
letters_[i].x -= marquee_speed_;
|
||||
if (letters_[i].x < -10)
|
||||
{
|
||||
letters_[i].enabled = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i > 0 && letters_[i - 1].x < 256 && letters_[i - 1].enabled)
|
||||
{
|
||||
letters_[i].enabled = true;
|
||||
letters_[i].x = letters_[i - 1].x + TEXT->lenght(letters_[i - 1].letter) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba si ha terminado la marquesina y la reinicia
|
||||
if (letters_[letters_.size() - 1].x < -10)
|
||||
{
|
||||
// Inicializa la marquesina
|
||||
initMarquee();
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja la marquesina
|
||||
void Title::renderMarquee()
|
||||
{
|
||||
const auto TEXT = Resource::get()->getText("gauntlet");
|
||||
for (const auto &l : letters_)
|
||||
{
|
||||
if (l.enabled)
|
||||
{
|
||||
TEXT->writeColored(l.x, 184, l.letter, static_cast<Uint8>(PaletteColor::BRIGHT_RED));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza las variables
|
||||
void Title::update()
|
||||
{
|
||||
// Comprueba que la diferencia de ticks sea mayor a la velocidad del juego
|
||||
if (SDL_GetTicks() - ticks_ > GAME_SPEED)
|
||||
{
|
||||
// Actualiza el contador de ticks
|
||||
ticks_ = SDL_GetTicks();
|
||||
|
||||
// Comprueba las entradas
|
||||
checkInput();
|
||||
|
||||
Screen::get()->update();
|
||||
|
||||
// Incrementa el contador
|
||||
counter_++;
|
||||
|
||||
switch (state_)
|
||||
{
|
||||
case TitleState::SHOW_LOADING_SCREEN:
|
||||
if (counter_ == 500)
|
||||
{
|
||||
counter_ = 0;
|
||||
state_ = TitleState::FADE_LOADING_SCREEN;
|
||||
}
|
||||
break;
|
||||
|
||||
case TitleState::FADE_LOADING_SCREEN:
|
||||
if (counter_ % 4 == 0)
|
||||
{
|
||||
if (loading_screen_surface_->fadeSubPalette())
|
||||
{
|
||||
counter_ = 0;
|
||||
state_ = TitleState::SHOW_MENU;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TitleState::SHOW_MENU:
|
||||
// Actualiza la marquesina
|
||||
updateMarquee();
|
||||
|
||||
// Si el contador alcanza cierto valor, termina la seccion
|
||||
if (counter_ == 2200)
|
||||
{
|
||||
if (!show_cheevos_)
|
||||
{
|
||||
options.section.section = Section::CREDITS;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja en pantalla
|
||||
void Title::render()
|
||||
{
|
||||
// Prepara para empezar a dibujar en la textura de juego
|
||||
Screen::get()->start();
|
||||
Screen::get()->clearSurface(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
switch (state_)
|
||||
{
|
||||
case TitleState::SHOW_MENU:
|
||||
// Dibuja la textura de fondo
|
||||
bg_surface_->render(0, 0);
|
||||
|
||||
// Dibuja la marquesina
|
||||
renderMarquee();
|
||||
|
||||
// Dibuja la información de logros
|
||||
if (show_cheevos_)
|
||||
{
|
||||
cheevos_sprite_->render();
|
||||
}
|
||||
break;
|
||||
|
||||
case TitleState::SHOW_LOADING_SCREEN:
|
||||
case TitleState::FADE_LOADING_SCREEN:
|
||||
loading_screen_sprite_->render();
|
||||
title_logo_sprite_->render();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Vuelca el contenido del renderizador en pantalla
|
||||
Screen::get()->render();
|
||||
}
|
||||
|
||||
// Bucle para el logo del juego
|
||||
void Title::run()
|
||||
{
|
||||
while (options.section.section == Section::TITLE)
|
||||
{
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
// Desplaza la lista de logros
|
||||
void Title::moveCheevosList(int direction)
|
||||
{
|
||||
// Modifica la posición de la ventana de vista
|
||||
constexpr int SPEED = 2;
|
||||
cheevos_surface_view_.y = direction == 0 ? cheevos_surface_view_.y - SPEED : cheevos_surface_view_.y + SPEED;
|
||||
|
||||
// Ajusta los limites
|
||||
const int BOTTOM = cheevos_surface_->getHeight() - cheevos_surface_view_.h;
|
||||
cheevos_surface_view_.y = std::clamp(cheevos_surface_view_.y, 0, BOTTOM);
|
||||
|
||||
cheevos_sprite_->setClip(cheevos_surface_view_);
|
||||
}
|
||||
|
||||
// Rellena la textura de fondo con todos los gráficos
|
||||
void Title::fillSurface()
|
||||
{
|
||||
// Coloca el puntero del renderizador sobre la textura
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(bg_surface_);
|
||||
|
||||
// Rellena la textura de color
|
||||
bg_surface_->clear(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
// Pinta el gráfico del titulo a partir del sprite
|
||||
title_logo_sprite_->render();
|
||||
|
||||
// Escribe el texto en la textura
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
const Uint8 COLOR = stringToColor("green");
|
||||
const int TEXT_SIZE = text->getCharacterSize();
|
||||
text->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 11 * TEXT_SIZE, "1.PLAY", 1, COLOR);
|
||||
text->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 13 * TEXT_SIZE, "2.ACHIEVEMENTS", 1, COLOR);
|
||||
text->writeDX(TEXT_CENTER | TEXT_COLOR, PLAY_AREA_CENTER_X, 15 * TEXT_SIZE, "3.REDEFINE KEYS", 1, COLOR);
|
||||
|
||||
// Devuelve el puntero del renderizador a su sitio
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
}
|
||||
|
||||
// Crea y rellena la textura para mostrar los logros
|
||||
void Title::createCheevosTexture()
|
||||
{
|
||||
// Crea la textura con el listado de logros
|
||||
const auto CHEEVOS_LIST = Cheevos::get()->list();
|
||||
const auto TEXT = Resource::get()->getText("subatomic");
|
||||
constexpr int CHEEVOS_TEXTURE_WIDTH = 200;
|
||||
constexpr int CHEEVOS_TEXTURE_VIEW_HEIGHT = 110 - 8;
|
||||
constexpr int CHEEVOS_TEXTURE_POS_Y = 73;
|
||||
constexpr int CHEEVOS_PADDING = 10;
|
||||
const int CHEEVO_HEIGHT = CHEEVOS_PADDING + (TEXT->getCharacterSize() * 2) + 1;
|
||||
const int CHEEVOS_TEXTURE_HEIGHT = (CHEEVO_HEIGHT * CHEEVOS_LIST.size()) + 2 + TEXT->getCharacterSize() + 8;
|
||||
cheevos_surface_ = std::make_shared<Surface>(CHEEVOS_TEXTURE_WIDTH, CHEEVOS_TEXTURE_HEIGHT);
|
||||
|
||||
// Prepara para dibujar sobre la textura
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(cheevos_surface_);
|
||||
|
||||
// Rellena la textura con color sólido
|
||||
const Uint8 CHEEVOS_BG_COLOR = static_cast<Uint8>(PaletteColor::BLACK);
|
||||
cheevos_surface_->clear(CHEEVOS_BG_COLOR);
|
||||
|
||||
// Escribe la lista de logros en la textura
|
||||
const std::string CHEEVOS_OWNER = "ACHIEVEMENTS";
|
||||
const std::string CHEEVOS_LIST_CAPTION = CHEEVOS_OWNER + " (" + std::to_string(Cheevos::get()->getTotalUnlockedAchievements()) + " / " + std::to_string(Cheevos::get()->size()) + ")";
|
||||
int pos = 2;
|
||||
TEXT->writeDX(TEXT_CENTER | TEXT_COLOR, cheevos_surface_->getWidth() / 2, pos, CHEEVOS_LIST_CAPTION, 1, stringToColor("bright_green"));
|
||||
pos += TEXT->getCharacterSize();
|
||||
const Uint8 CHEEVO_LOCKED_COLOR = stringToColor("white");
|
||||
const Uint8 CHEEVO_UNLOCKED_COLOR = stringToColor("bright_green");
|
||||
constexpr int LINE_X1 = (CHEEVOS_TEXTURE_WIDTH / 7) * 3;
|
||||
constexpr int LINE_X2 = LINE_X1 + ((CHEEVOS_TEXTURE_WIDTH / 7) * 1);
|
||||
|
||||
for (const auto &cheevo : CHEEVOS_LIST)
|
||||
{
|
||||
const Uint8 CHEEVO_COLOR = cheevo.completed ? CHEEVO_UNLOCKED_COLOR : CHEEVO_LOCKED_COLOR;
|
||||
pos += CHEEVOS_PADDING;
|
||||
constexpr int HALF = CHEEVOS_PADDING / 2;
|
||||
cheevos_surface_->drawLine(LINE_X1, pos - HALF - 1, LINE_X2, pos - HALF - 1, CHEEVO_COLOR);
|
||||
TEXT->writeDX(TEXT_CENTER | TEXT_COLOR, CHEEVOS_TEXTURE_WIDTH / 2, pos, cheevo.caption, 1, CHEEVO_COLOR);
|
||||
pos += TEXT->getCharacterSize() + 1;
|
||||
TEXT->writeDX(TEXT_CENTER | TEXT_COLOR, CHEEVOS_TEXTURE_WIDTH / 2, pos, cheevo.description, 1, CHEEVO_COLOR);
|
||||
pos += TEXT->getCharacterSize();
|
||||
}
|
||||
|
||||
// Restablece el RenderSurface
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
|
||||
// Crea el sprite para el listado de logros
|
||||
cheevos_sprite_ = std::make_shared<SSprite>(cheevos_surface_, (GAMECANVAS_WIDTH - cheevos_surface_->getWidth()) / 2, CHEEVOS_TEXTURE_POS_Y, cheevos_surface_->getWidth(), cheevos_surface_->getHeight());
|
||||
cheevos_surface_view_ = {0, 0, cheevos_surface_->getWidth(), CHEEVOS_TEXTURE_VIEW_HEIGHT};
|
||||
cheevos_sprite_->setClip(cheevos_surface_view_);
|
||||
}
|
||||
|
||||
// Oculta la lista de logros
|
||||
void Title::hideCheevosList()
|
||||
{
|
||||
show_cheevos_ = false;
|
||||
cheevos_surface_view_.y = 0;
|
||||
cheevos_sprite_->setClip(cheevos_surface_view_);
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint32
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
class SSprite; // lines 9-9
|
||||
class Surface; // lines 10-10
|
||||
|
||||
class Title
|
||||
{
|
||||
private:
|
||||
struct TitleLetter
|
||||
{
|
||||
std::string letter; // Letra a escribir
|
||||
int x; // Posición en el eje x
|
||||
bool enabled; // Solo se escriben y mueven si estan habilitadas
|
||||
};
|
||||
|
||||
enum class TitleState
|
||||
{
|
||||
SHOW_LOADING_SCREEN,
|
||||
FADE_LOADING_SCREEN,
|
||||
SHOW_MENU
|
||||
};
|
||||
|
||||
// Objetos y punteros
|
||||
std::shared_ptr<Surface> title_logo_surface_; // Textura con los graficos
|
||||
std::shared_ptr<SSprite> title_logo_sprite_; // SSprite para manejar la surface
|
||||
std::shared_ptr<Surface> loading_screen_surface_; // Surface con los gráficos de la pantalla de carga
|
||||
std::shared_ptr<SSprite> loading_screen_sprite_; // SSprite con los gráficos de la pantalla de carga
|
||||
std::shared_ptr<Surface> bg_surface_; // Textura para dibujar el fondo de la pantalla
|
||||
std::shared_ptr<Surface> cheevos_surface_; // Textura con la lista de logros
|
||||
std::shared_ptr<SSprite> cheevos_sprite_; // SSprite para manejar la surface con la lista de logros
|
||||
|
||||
// Variables
|
||||
int counter_ = 0; // Contador
|
||||
std::string long_text_; // Texto que aparece en la parte inferior del titulo
|
||||
Uint32 ticks_ = 0; // Contador de ticks para ajustar la velocidad del programa
|
||||
std::vector<TitleLetter> letters_; // Vector con las letras de la marquesina
|
||||
int marquee_speed_ = 2; // Velocidad de desplazamiento de la marquesina
|
||||
bool show_cheevos_ = false; // Indica si se muestra por pantalla el listado de logros
|
||||
SDL_Rect cheevos_surface_view_; // Zona visible de la surface con el listado de logros
|
||||
TitleState state_; // Estado en el que se encuentra el bucle principal
|
||||
|
||||
// Actualiza las variables
|
||||
void update();
|
||||
|
||||
// Dibuja en pantalla
|
||||
void render();
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void checkEvents();
|
||||
|
||||
// Comprueba las entradas
|
||||
void checkInput();
|
||||
|
||||
// Inicializa la marquesina
|
||||
void initMarquee();
|
||||
|
||||
// Actualiza la marquesina
|
||||
void updateMarquee();
|
||||
|
||||
// Dibuja la marquesina
|
||||
void renderMarquee();
|
||||
|
||||
// Desplaza la lista de logros
|
||||
void moveCheevosList(int direction);
|
||||
|
||||
// Rellena la surface de fondo con todos los gráficos
|
||||
void fillSurface();
|
||||
|
||||
// Crea y rellena la surface para mostrar los logros
|
||||
void createCheevosTexture();
|
||||
|
||||
// Oculta la lista de logros
|
||||
void hideCheevosList();
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
Title();
|
||||
|
||||
// Destructor
|
||||
~Title() = default;
|
||||
|
||||
// Bucle principal
|
||||
void run();
|
||||
};
|
||||
@@ -1,9 +1,12 @@
|
||||
#include "notifier.h"
|
||||
#include <SDL2/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <SDL3/SDL_timer.h> // Para SDL_GetTicks
|
||||
|
||||
#include <algorithm> // Para remove_if
|
||||
#include <iterator> // Para prev
|
||||
#include <string> // Para string, basic_string
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "jail_audio.h" // Para JA_PlaySound
|
||||
#include "options.h" // Para Options, options, NotificationPosition
|
||||
#include "resource.h" // Para Resource
|
||||
@@ -14,28 +17,25 @@
|
||||
#include "utils.h" // Para PaletteColor
|
||||
|
||||
// [SINGLETON]
|
||||
Notifier *Notifier::notifier_ = nullptr;
|
||||
Notifier* Notifier::notifier_ = nullptr;
|
||||
|
||||
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||
void Notifier::init(const std::string &icon_file, const std::string &text)
|
||||
{
|
||||
void Notifier::init(const std::string& icon_file, const std::string& text) {
|
||||
Notifier::notifier_ = new Notifier(icon_file, text);
|
||||
}
|
||||
|
||||
// [SINGLETON] Destruiremos el objeto con esta función estática
|
||||
void Notifier::destroy()
|
||||
{
|
||||
void Notifier::destroy() {
|
||||
delete Notifier::notifier_;
|
||||
}
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
Notifier *Notifier::get()
|
||||
{
|
||||
Notifier* Notifier::get() {
|
||||
return Notifier::notifier_;
|
||||
}
|
||||
|
||||
// Constructor
|
||||
Notifier::Notifier(const std::string &icon_file, const std::string &text)
|
||||
Notifier::Notifier(const std::string& icon_file, const std::string& text)
|
||||
: icon_surface_(!icon_file.empty() ? Resource::get()->getSurface(icon_file) : nullptr),
|
||||
text_(Resource::get()->getText(text)),
|
||||
bg_color_(options.notifications.color),
|
||||
@@ -43,60 +43,47 @@ Notifier::Notifier(const std::string &icon_file, const std::string &text)
|
||||
has_icons_(!icon_file.empty()) {}
|
||||
|
||||
// Dibuja las notificaciones por pantalla
|
||||
void Notifier::render()
|
||||
{
|
||||
for (auto it = notifications_.rbegin(); it != notifications_.rend(); ++it)
|
||||
{
|
||||
void Notifier::render() {
|
||||
for (auto it = notifications_.rbegin(); it != notifications_.rend(); ++it) {
|
||||
it->sprite->render();
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el estado de las notificaiones
|
||||
void Notifier::update()
|
||||
{
|
||||
for (auto ¬ification : notifications_)
|
||||
{
|
||||
void Notifier::update() {
|
||||
for (auto& notification : notifications_) {
|
||||
// Si la notificación anterior está "saliendo", no hagas nada
|
||||
if (!notifications_.empty() && ¬ification != ¬ifications_.front())
|
||||
{
|
||||
const auto &PREVIOUS_NOTIFICATION = *(std::prev(¬ification));
|
||||
if (PREVIOUS_NOTIFICATION.state == NotificationStatus::RISING)
|
||||
{
|
||||
if (!notifications_.empty() && ¬ification != ¬ifications_.front()) {
|
||||
const auto& PREVIOUS_NOTIFICATION = *(std::prev(¬ification));
|
||||
if (PREVIOUS_NOTIFICATION.state == NotificationStatus::RISING) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (notification.state)
|
||||
{
|
||||
case NotificationStatus::RISING:
|
||||
{
|
||||
switch (notification.state) {
|
||||
case NotificationStatus::RISING: {
|
||||
const int DIRECTION = (options.notifications.getVerticalPosition() == NotificationPosition::TOP) ? 1 : -1;
|
||||
notification.rect.y += DIRECTION;
|
||||
|
||||
if (notification.rect.y == notification.y)
|
||||
{
|
||||
if (notification.rect.y == notification.y) {
|
||||
notification.state = NotificationStatus::STAY;
|
||||
notification.start_time = SDL_GetTicks();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NotificationStatus::STAY:
|
||||
{
|
||||
case NotificationStatus::STAY: {
|
||||
notification.elapsed_time = SDL_GetTicks() - notification.start_time;
|
||||
if (notification.elapsed_time >= notification.display_duration)
|
||||
{
|
||||
if (notification.elapsed_time >= notification.display_duration) {
|
||||
notification.state = NotificationStatus::VANISHING;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case NotificationStatus::VANISHING:
|
||||
{
|
||||
case NotificationStatus::VANISHING: {
|
||||
const int DIRECTION = (options.notifications.getVerticalPosition() == NotificationPosition::TOP) ? -1 : 1;
|
||||
notification.rect.y += DIRECTION;
|
||||
|
||||
if (notification.rect.y == notification.y - notification.travel_dist)
|
||||
{
|
||||
if (notification.rect.y == notification.y - notification.travel_dist) {
|
||||
notification.state = NotificationStatus::FINISHED;
|
||||
}
|
||||
break;
|
||||
@@ -116,42 +103,33 @@ void Notifier::update()
|
||||
}
|
||||
|
||||
// Elimina las notificaciones finalizadas
|
||||
void Notifier::clearFinishedNotifications()
|
||||
{
|
||||
void Notifier::clearFinishedNotifications() {
|
||||
notifications_.erase(
|
||||
std::remove_if(notifications_.begin(), notifications_.end(),
|
||||
[](const Notification ¬ification)
|
||||
{
|
||||
std::remove_if(notifications_.begin(), notifications_.end(), [](const Notification& notification) {
|
||||
return notification.state == NotificationStatus::FINISHED;
|
||||
}),
|
||||
notifications_.end());
|
||||
}
|
||||
|
||||
void Notifier::show(std::vector<std::string> texts, NotificationText text_is, Uint32 display_duration, int icon, bool can_be_removed, const std::string &code)
|
||||
{
|
||||
void Notifier::show(std::vector<std::string> texts, NotificationText text_is, Uint32 display_duration, int icon, bool can_be_removed, const std::string& code) {
|
||||
// Si no hay texto, acaba
|
||||
if (texts.empty())
|
||||
{
|
||||
if (texts.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Si las notificaciones no se apilan, elimina las anteriores
|
||||
if (!stack_)
|
||||
{
|
||||
if (!stack_) {
|
||||
clearNotifications();
|
||||
}
|
||||
|
||||
// Elimina las cadenas vacías
|
||||
texts.erase(std::remove_if(texts.begin(), texts.end(), [](const std::string &s)
|
||||
{ return s.empty(); }),
|
||||
texts.erase(std::remove_if(texts.begin(), texts.end(), [](const std::string& s) { return s.empty(); }),
|
||||
texts.end());
|
||||
|
||||
// Encuentra la cadena más larga
|
||||
std::string longest;
|
||||
for (const auto &text : texts)
|
||||
{
|
||||
if (text.length() > longest.length())
|
||||
{
|
||||
for (const auto& text : texts) {
|
||||
if (text.length() > longest.length()) {
|
||||
longest = text;
|
||||
}
|
||||
}
|
||||
@@ -168,8 +146,7 @@ void Notifier::show(std::vector<std::string> texts, NotificationText text_is, Ui
|
||||
|
||||
// Posición horizontal
|
||||
int desp_h = 0;
|
||||
switch (options.notifications.getHorizontalPosition())
|
||||
{
|
||||
switch (options.notifications.getHorizontalPosition()) {
|
||||
case NotificationPosition::LEFT:
|
||||
desp_h = PADDING_OUT_;
|
||||
break;
|
||||
@@ -218,8 +195,7 @@ void Notifier::show(std::vector<std::string> texts, NotificationText text_is, Ui
|
||||
|
||||
// Dibuja el fondo de la notificación
|
||||
SDL_Rect rect;
|
||||
if (SHAPE == NotificationShape::ROUNDED)
|
||||
{
|
||||
if (SHAPE == NotificationShape::ROUNDED) {
|
||||
rect = {4, 0, WIDTH - (4 * 2), HEIGHT};
|
||||
n.surface->fillRect(&rect, bg_color_);
|
||||
|
||||
@@ -233,16 +209,14 @@ void Notifier::show(std::vector<std::string> texts, NotificationText text_is, Ui
|
||||
n.surface->fillRect(&rect, bg_color_);
|
||||
}
|
||||
|
||||
else if (SHAPE == NotificationShape::SQUARED)
|
||||
{
|
||||
else if (SHAPE == NotificationShape::SQUARED) {
|
||||
n.surface->clear(bg_color_);
|
||||
SDL_Rect squared_rect = {0, 0, n.surface->getWidth(), n.surface->getHeight()};
|
||||
n.surface->drawRectBorder(&squared_rect, static_cast<Uint8>(PaletteColor::CYAN));
|
||||
}
|
||||
|
||||
// Dibuja el icono de la notificación
|
||||
if (has_icons_ && icon >= 0 && texts.size() >= 2)
|
||||
{
|
||||
if (has_icons_ && icon >= 0 && texts.size() >= 2) {
|
||||
auto sp = std::make_unique<SSprite>(icon_surface_, (SDL_Rect){0, 0, ICON_SIZE_, ICON_SIZE_});
|
||||
sp->setPosition({PADDING_IN_H, PADDING_IN_V, ICON_SIZE_, ICON_SIZE_});
|
||||
sp->setClip({ICON_SIZE_ * (icon % 10), ICON_SIZE_ * (icon / 10), ICON_SIZE_, ICON_SIZE_});
|
||||
@@ -252,10 +226,8 @@ void Notifier::show(std::vector<std::string> texts, NotificationText text_is, Ui
|
||||
// Escribe el texto de la notificación
|
||||
const Uint8 COLOR = static_cast<Uint8>(PaletteColor::WHITE);
|
||||
int iterator = 0;
|
||||
for (const auto &text : texts)
|
||||
{
|
||||
switch (text_is)
|
||||
{
|
||||
for (const auto& text : texts) {
|
||||
switch (text_is) {
|
||||
case NotificationText::LEFT:
|
||||
text_->writeColored(PADDING_IN_H + ICON_SPACE, PADDING_IN_V + iterator * (text_size + 1), text, COLOR);
|
||||
break;
|
||||
@@ -286,12 +258,9 @@ void Notifier::show(std::vector<std::string> texts, NotificationText text_is, Ui
|
||||
bool Notifier::isActive() { return !notifications_.empty(); }
|
||||
|
||||
// Finaliza y elimnina todas las notificaciones activas
|
||||
void Notifier::clearNotifications()
|
||||
{
|
||||
for (auto ¬ification : notifications_)
|
||||
{
|
||||
if (notification.can_be_removed)
|
||||
{
|
||||
void Notifier::clearNotifications() {
|
||||
for (auto& notification : notifications_) {
|
||||
if (notification.can_be_removed) {
|
||||
notification.state = NotificationStatus::FINISHED;
|
||||
}
|
||||
}
|
||||
@@ -300,11 +269,9 @@ void Notifier::clearNotifications()
|
||||
}
|
||||
|
||||
// Obtiene los códigos de las notificaciones
|
||||
std::vector<std::string> Notifier::getCodes()
|
||||
{
|
||||
std::vector<std::string> Notifier::getCodes() {
|
||||
std::vector<std::string> codes;
|
||||
for (const auto ¬ification : notifications_)
|
||||
{
|
||||
for (const auto& notification : notifications_) {
|
||||
codes.emplace_back(notification.code);
|
||||
}
|
||||
return codes;
|
||||
127
source/ui/notifier.h
Normal file
127
source/ui/notifier.h
Normal file
@@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint32, Uint8
|
||||
|
||||
#include <memory> // Para shared_ptr
|
||||
#include <string> // Para string, basic_string
|
||||
#include <vector> // Para vector
|
||||
class SSprite; // lines 8-8
|
||||
class Surface; // lines 10-10
|
||||
class Text; // lines 9-9
|
||||
|
||||
// Constantes
|
||||
constexpr Uint32 DEFAULT_NOTIFICATION_DURATION = 2000;
|
||||
constexpr Uint32 CHEEVO_NOTIFICATION_DURATION = 4000;
|
||||
|
||||
// Justificado para las notificaciones
|
||||
enum class NotificationText {
|
||||
LEFT,
|
||||
CENTER,
|
||||
};
|
||||
|
||||
class Notifier {
|
||||
private:
|
||||
// Constantes
|
||||
static constexpr int ICON_SIZE_ = 16;
|
||||
static constexpr int PADDING_OUT_ = 0;
|
||||
|
||||
// [SINGLETON] Objeto notifier
|
||||
static Notifier* notifier_;
|
||||
|
||||
enum class NotificationStatus {
|
||||
RISING,
|
||||
STAY,
|
||||
VANISHING,
|
||||
FINISHED,
|
||||
};
|
||||
|
||||
enum class NotificationShape {
|
||||
ROUNDED,
|
||||
SQUARED,
|
||||
};
|
||||
|
||||
struct Notification {
|
||||
std::shared_ptr<Surface> surface; // Superficie asociada a la notificación
|
||||
std::shared_ptr<SSprite> sprite; // Sprite asociado para gráficos o animaciones
|
||||
std::vector<std::string> texts; // Lista de textos incluidos en la notificación
|
||||
NotificationStatus state; // Estado actual de la notificación (RISING, SHOWING, etc.)
|
||||
NotificationShape shape; // Forma de la notificación (ej. SQUARED o ROUNDED)
|
||||
SDL_Rect rect; // Dimensiones y posición de la notificación en pantalla
|
||||
int y; // Posición actual en el eje Y
|
||||
int travel_dist; // Distancia a recorrer (por ejemplo, en animaciones)
|
||||
std::string code; // Código identificador único para esta notificación
|
||||
bool can_be_removed; // Indica si la notificación puede ser eliminada
|
||||
int height; // Altura de la notificación
|
||||
Uint32 start_time; // Momento en que se creó la notificación
|
||||
Uint32 elapsed_time; // Tiempo transcurrido desde la creación
|
||||
Uint32 display_duration; // Duración total para mostrar la notificación
|
||||
|
||||
// Constructor
|
||||
explicit Notification()
|
||||
: surface(nullptr), // Inicializar superficie como nula
|
||||
sprite(nullptr), // Inicializar sprite como nulo
|
||||
texts(), // Inicializar lista de textos vacía
|
||||
state(NotificationStatus::RISING), // Estado inicial como "RISING"
|
||||
shape(NotificationShape::SQUARED), // Forma inicial como "SQUARED"
|
||||
rect{0, 0, 0, 0}, // Rectángulo inicial vacío
|
||||
y(0), // Posición Y inicializada a 0
|
||||
travel_dist(0), // Distancia inicializada a 0
|
||||
code(""), // Código identificador vacío
|
||||
can_be_removed(true), // Inicialmente se puede eliminar
|
||||
height(0), // Altura inicializada a 0
|
||||
start_time(0), // Tiempo de creación inicializado a 0
|
||||
elapsed_time(0), // Tiempo transcurrido inicializado a 0
|
||||
display_duration(0) // Duración inicializada a 0
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<Surface> icon_surface_; // Textura para los iconos de las notificaciones
|
||||
std::shared_ptr<Text> text_; // Objeto para dibujar texto
|
||||
|
||||
// Variables
|
||||
Uint8 bg_color_; // Color de fondo de las notificaciones
|
||||
std::vector<Notification> notifications_; // La lista de notificaciones activas
|
||||
bool stack_; // Indica si las notificaciones se apilan
|
||||
bool has_icons_; // Indica si el notificador tiene textura para iconos
|
||||
|
||||
// Elimina las notificaciones finalizadas
|
||||
void clearFinishedNotifications();
|
||||
|
||||
// Finaliza y elimnina todas las notificaciones activas
|
||||
void clearNotifications();
|
||||
|
||||
// [SINGLETON] Ahora el constructor y el destructor son privados, para no poder crear objetos notifier desde fuera
|
||||
|
||||
// Constructor
|
||||
Notifier(const std::string& icon_file, const std::string& text);
|
||||
|
||||
// Destructor
|
||||
~Notifier() = default;
|
||||
|
||||
public:
|
||||
// [SINGLETON] Crearemos el objeto con esta función estática
|
||||
static void init(const std::string& icon_file, const std::string& text);
|
||||
|
||||
// [SINGLETON] Destruiremos el objeto con esta función estática
|
||||
static void destroy();
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
static Notifier* get();
|
||||
|
||||
// Dibuja las notificaciones por pantalla
|
||||
void render();
|
||||
|
||||
// Actualiza el estado de las notificaiones
|
||||
void update();
|
||||
|
||||
// Muestra una notificación de texto por pantalla
|
||||
void show(std::vector<std::string> texts, NotificationText text_is = NotificationText::LEFT, Uint32 display_duration = DEFAULT_NOTIFICATION_DURATION, int icon = -1, bool can_be_removed = true, const std::string& code = std::string());
|
||||
|
||||
// Indica si hay notificaciones activas
|
||||
bool isActive();
|
||||
|
||||
// Obtiene los códigos de las notificaciones
|
||||
std::vector<std::string> getCodes();
|
||||
};
|
||||
209
source/utils.cpp
209
source/utils.cpp
@@ -1,5 +1,7 @@
|
||||
#include "utils.h"
|
||||
|
||||
#include <stdlib.h> // Para abs
|
||||
|
||||
#include <algorithm> // Para find, transform
|
||||
#include <cctype> // Para tolower
|
||||
#include <cmath> // Para round, abs
|
||||
@@ -9,27 +11,25 @@
|
||||
#include <string> // Para basic_string, string, char_traits, allocator
|
||||
#include <unordered_map> // Para unordered_map, operator==, _Node_const_iter...
|
||||
#include <utility> // Para pair
|
||||
|
||||
#include "jail_audio.h" // Para JA_GetMusicState, JA_Music_state, JA_PlayMusic
|
||||
#include "resource.h" // Para Resource
|
||||
|
||||
// Calcula el cuadrado de la distancia entre dos puntos
|
||||
double distanceSquared(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
double distanceSquared(int x1, int y1, int x2, int y2) {
|
||||
const int deltaX = x2 - x1;
|
||||
const int deltaY = y2 - y1;
|
||||
return deltaX * deltaX + deltaY * deltaY;
|
||||
}
|
||||
|
||||
// Detector de colisiones entre dos circulos
|
||||
bool checkCollision(const Circle &a, const Circle &b)
|
||||
{
|
||||
bool checkCollision(const Circle& a, const Circle& b) {
|
||||
// Calcula el radio total al cuadrado
|
||||
int totalRadiusSquared = a.r + b.r;
|
||||
totalRadiusSquared = totalRadiusSquared * totalRadiusSquared;
|
||||
|
||||
// Si la distancia entre el centro de los circulos es inferior a la suma de sus radios
|
||||
if (distanceSquared(a.x, a.y, b.x, b.y) < (totalRadiusSquared))
|
||||
{
|
||||
if (distanceSquared(a.x, a.y, b.x, b.y) < (totalRadiusSquared)) {
|
||||
// Los circulos han colisionado
|
||||
return true;
|
||||
}
|
||||
@@ -39,42 +39,30 @@ bool checkCollision(const Circle &a, const Circle &b)
|
||||
}
|
||||
|
||||
// Detector de colisiones entre un circulo y un rectangulo
|
||||
bool checkCollision(const Circle &a, const SDL_Rect &b)
|
||||
{
|
||||
bool checkCollision(const Circle& a, const SDL_Rect& b) {
|
||||
// Closest point on collision box
|
||||
int cX, cY;
|
||||
|
||||
// Find closest x offset
|
||||
if (a.x < b.x)
|
||||
{
|
||||
if (a.x < b.x) {
|
||||
cX = b.x;
|
||||
}
|
||||
else if (a.x > b.x + b.w)
|
||||
{
|
||||
} else if (a.x > b.x + b.w) {
|
||||
cX = b.x + b.w;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
cX = a.x;
|
||||
}
|
||||
|
||||
// Find closest y offset
|
||||
if (a.y < b.y)
|
||||
{
|
||||
if (a.y < b.y) {
|
||||
cY = b.y;
|
||||
}
|
||||
else if (a.y > b.y + b.h)
|
||||
{
|
||||
} else if (a.y > b.y + b.h) {
|
||||
cY = b.y + b.h;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
cY = a.y;
|
||||
}
|
||||
|
||||
// If the closest point is inside the circle_t
|
||||
if (distanceSquared(a.x, a.y, cX, cY) < a.r * a.r)
|
||||
{
|
||||
if (distanceSquared(a.x, a.y, cX, cY) < a.r * a.r) {
|
||||
// This box and the circle_t have collided
|
||||
return true;
|
||||
}
|
||||
@@ -84,8 +72,7 @@ bool checkCollision(const Circle &a, const SDL_Rect &b)
|
||||
}
|
||||
|
||||
// Detector de colisiones entre dos rectangulos
|
||||
bool checkCollision(const SDL_Rect &a, const SDL_Rect &b)
|
||||
{
|
||||
bool checkCollision(const SDL_Rect& a, const SDL_Rect& b) {
|
||||
// Calcula las caras del rectangulo a
|
||||
const int leftA = a.x;
|
||||
const int rightA = a.x + a.w;
|
||||
@@ -99,23 +86,19 @@ bool checkCollision(const SDL_Rect &a, const SDL_Rect &b)
|
||||
const int bottomB = b.y + b.h;
|
||||
|
||||
// Si cualquiera de las caras de a está fuera de b
|
||||
if (bottomA <= topB)
|
||||
{
|
||||
if (bottomA <= topB) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (topA >= bottomB)
|
||||
{
|
||||
if (topA >= bottomB) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rightA <= leftB)
|
||||
{
|
||||
if (rightA <= leftB) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (leftA >= rightB)
|
||||
{
|
||||
if (leftA >= rightB) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -124,29 +107,24 @@ bool checkCollision(const SDL_Rect &a, const SDL_Rect &b)
|
||||
}
|
||||
|
||||
// Detector de colisiones entre un punto y un rectangulo
|
||||
bool checkCollision(const SDL_Point &p, const SDL_Rect &r)
|
||||
{
|
||||
bool checkCollision(const SDL_Point& p, const SDL_Rect& r) {
|
||||
// Comprueba si el punto está a la izquierda del rectangulo
|
||||
if (p.x < r.x)
|
||||
{
|
||||
if (p.x < r.x) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si el punto está a la derecha del rectangulo
|
||||
if (p.x > r.x + r.w)
|
||||
{
|
||||
if (p.x > r.x + r.w) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si el punto está por encima del rectangulo
|
||||
if (p.y < r.y)
|
||||
{
|
||||
if (p.y < r.y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si el punto está por debajo del rectangulo
|
||||
if (p.y > r.y + r.h)
|
||||
{
|
||||
if (p.y > r.y + r.h) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -155,29 +133,24 @@ bool checkCollision(const SDL_Point &p, const SDL_Rect &r)
|
||||
}
|
||||
|
||||
// Detector de colisiones entre una linea horizontal y un rectangulo
|
||||
bool checkCollision(const LineHorizontal &l, const SDL_Rect &r)
|
||||
{
|
||||
bool checkCollision(const LineHorizontal& l, const SDL_Rect& r) {
|
||||
// Comprueba si la linea esta por encima del rectangulo
|
||||
if (l.y < r.y)
|
||||
{
|
||||
if (l.y < r.y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si la linea esta por debajo del rectangulo
|
||||
if (l.y >= r.y + r.h)
|
||||
{
|
||||
if (l.y >= r.y + r.h) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si el inicio de la linea esta a la derecha del rectangulo
|
||||
if (l.x1 >= r.x + r.w)
|
||||
{
|
||||
if (l.x1 >= r.x + r.w) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si el final de la linea esta a la izquierda del rectangulo
|
||||
if (l.x2 < r.x)
|
||||
{
|
||||
if (l.x2 < r.x) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -186,29 +159,24 @@ bool checkCollision(const LineHorizontal &l, const SDL_Rect &r)
|
||||
}
|
||||
|
||||
// Detector de colisiones entre una linea vertical y un rectangulo
|
||||
bool checkCollision(const LineVertical &l, const SDL_Rect &r)
|
||||
{
|
||||
bool checkCollision(const LineVertical& l, const SDL_Rect& r) {
|
||||
// Comprueba si la linea esta por la izquierda del rectangulo
|
||||
if (l.x < r.x)
|
||||
{
|
||||
if (l.x < r.x) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si la linea esta por la derecha del rectangulo
|
||||
if (l.x >= r.x + r.w)
|
||||
{
|
||||
if (l.x >= r.x + r.w) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si el inicio de la linea esta debajo del rectangulo
|
||||
if (l.y1 >= r.y + r.h)
|
||||
{
|
||||
if (l.y1 >= r.y + r.h) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si el final de la linea esta encima del rectangulo
|
||||
if (l.y2 < r.y)
|
||||
{
|
||||
if (l.y2 < r.y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -217,29 +185,24 @@ bool checkCollision(const LineVertical &l, const SDL_Rect &r)
|
||||
}
|
||||
|
||||
// Detector de colisiones entre una linea horizontal y un punto
|
||||
bool checkCollision(const LineHorizontal &l, const SDL_Point &p)
|
||||
{
|
||||
bool checkCollision(const LineHorizontal& l, const SDL_Point& p) {
|
||||
// Comprueba si el punto esta sobre la linea
|
||||
if (p.y > l.y)
|
||||
{
|
||||
if (p.y > l.y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si el punto esta bajo la linea
|
||||
if (p.y < l.y)
|
||||
{
|
||||
if (p.y < l.y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si el punto esta a la izquierda de la linea
|
||||
if (p.x < l.x1)
|
||||
{
|
||||
if (p.x < l.x1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si el punto esta a la derecha de la linea
|
||||
if (p.x > l.x2)
|
||||
{
|
||||
if (p.x > l.x2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -248,8 +211,7 @@ bool checkCollision(const LineHorizontal &l, const SDL_Point &p)
|
||||
}
|
||||
|
||||
// Detector de colisiones entre dos lineas
|
||||
SDL_Point checkCollision(const Line &l1, const Line &l2)
|
||||
{
|
||||
SDL_Point checkCollision(const Line& l1, const Line& l2) {
|
||||
const float x1 = l1.x1;
|
||||
const float y1 = l1.y1;
|
||||
const float x2 = l1.x2;
|
||||
@@ -265,8 +227,7 @@ SDL_Point checkCollision(const Line &l1, const Line &l2)
|
||||
float uB = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1));
|
||||
|
||||
// if uA and uB are between 0-1, lines are colliding
|
||||
if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1)
|
||||
{
|
||||
if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
|
||||
// Calcula la intersección
|
||||
const float x = x1 + (uA * (x2 - x1));
|
||||
const float y = y1 + (uA * (y2 - y1));
|
||||
@@ -277,8 +238,7 @@ SDL_Point checkCollision(const Line &l1, const Line &l2)
|
||||
}
|
||||
|
||||
// Detector de colisiones entre dos lineas
|
||||
SDL_Point checkCollision(const LineDiagonal &l1, const LineVertical &l2)
|
||||
{
|
||||
SDL_Point checkCollision(const LineDiagonal& l1, const LineVertical& l2) {
|
||||
const float x1 = l1.x1;
|
||||
const float y1 = l1.y1;
|
||||
const float x2 = l1.x2;
|
||||
@@ -294,8 +254,7 @@ SDL_Point checkCollision(const LineDiagonal &l1, const LineVertical &l2)
|
||||
float uB = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1));
|
||||
|
||||
// if uA and uB are between 0-1, lines are colliding
|
||||
if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1)
|
||||
{
|
||||
if (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) {
|
||||
// Calcula la intersección
|
||||
const float x = x1 + (uA * (x2 - x1));
|
||||
const float y = y1 + (uA * (y2 - y1));
|
||||
@@ -306,12 +265,10 @@ SDL_Point checkCollision(const LineDiagonal &l1, const LineVertical &l2)
|
||||
}
|
||||
|
||||
// Normaliza una linea diagonal
|
||||
void normalizeLine(LineDiagonal &l)
|
||||
{
|
||||
void normalizeLine(LineDiagonal& l) {
|
||||
// Las lineas diagonales van de izquierda a derecha
|
||||
// x2 mayor que x1
|
||||
if (l.x2 < l.x1)
|
||||
{
|
||||
if (l.x2 < l.x1) {
|
||||
const int x = l.x1;
|
||||
const int y = l.y1;
|
||||
l.x1 = l.x2;
|
||||
@@ -322,35 +279,29 @@ void normalizeLine(LineDiagonal &l)
|
||||
}
|
||||
|
||||
// Detector de colisiones entre un punto y una linea diagonal
|
||||
bool checkCollision(const SDL_Point &p, const LineDiagonal &l)
|
||||
{
|
||||
bool checkCollision(const SDL_Point& p, const LineDiagonal& l) {
|
||||
// Comprueba si el punto está en alineado con la linea
|
||||
if (abs(p.x - l.x1) != abs(p.y - l.y1))
|
||||
{
|
||||
if (abs(p.x - l.x1) != abs(p.y - l.y1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si está a la derecha de la linea
|
||||
if (p.x > l.x1 && p.x > l.x2)
|
||||
{
|
||||
if (p.x > l.x1 && p.x > l.x2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si está a la izquierda de la linea
|
||||
if (p.x < l.x1 && p.x < l.x2)
|
||||
{
|
||||
if (p.x < l.x1 && p.x < l.x2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si está por encima de la linea
|
||||
if (p.y > l.y1 && p.y > l.y2)
|
||||
{
|
||||
if (p.y > l.y1 && p.y > l.y2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Comprueba si está por debajo de la linea
|
||||
if (p.y < l.y1 && p.y < l.y2)
|
||||
{
|
||||
if (p.y < l.y1 && p.y < l.y2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -359,8 +310,7 @@ bool checkCollision(const SDL_Point &p, const LineDiagonal &l)
|
||||
}
|
||||
|
||||
// Convierte una cadena a un indice de la paleta
|
||||
Uint8 stringToColor(const std::string &str)
|
||||
{
|
||||
Uint8 stringToColor(const std::string& str) {
|
||||
// Mapas de colores para cada paleta
|
||||
static const std::unordered_map<std::string, Uint8> paletteMap = {
|
||||
{"black", 0},
|
||||
@@ -391,47 +341,37 @@ Uint8 stringToColor(const std::string &str)
|
||||
|
||||
// Busca el color en el mapa
|
||||
auto it = paletteMap.find(str);
|
||||
if (it != paletteMap.end())
|
||||
{
|
||||
if (it != paletteMap.end()) {
|
||||
return it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Si no se encuentra el color, devolvemos negro por defecto
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Convierte una cadena a un entero de forma segura
|
||||
int safeStoi(const std::string &value, int defaultValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
int safeStoi(const std::string& value, int defaultValue) {
|
||||
try {
|
||||
return std::stoi(value);
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
} catch (const std::exception&) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Convierte una cadena a un booleano
|
||||
bool stringToBool(const std::string &str)
|
||||
{
|
||||
bool stringToBool(const std::string& str) {
|
||||
std::string lowerStr = str;
|
||||
std::transform(lowerStr.begin(), lowerStr.end(), lowerStr.begin(), ::tolower);
|
||||
return (lowerStr == "true" || lowerStr == "1" || lowerStr == "yes" || lowerStr == "on");
|
||||
}
|
||||
|
||||
// Convierte un booleano a una cadena
|
||||
std::string boolToString(bool value)
|
||||
{
|
||||
std::string boolToString(bool value) {
|
||||
return value ? "1" : "0";
|
||||
}
|
||||
|
||||
// Compara dos colores
|
||||
bool colorAreEqual(Color color1, Color color2)
|
||||
{
|
||||
bool colorAreEqual(Color color1, Color color2) {
|
||||
const bool r = color1.r == color2.r;
|
||||
const bool g = color1.g == color2.g;
|
||||
const bool b = color1.b == color2.b;
|
||||
@@ -440,37 +380,32 @@ bool colorAreEqual(Color color1, Color color2)
|
||||
}
|
||||
|
||||
// Función para convertir un string a minúsculas
|
||||
std::string toLower(const std::string &str)
|
||||
{
|
||||
std::string toLower(const std::string& str) {
|
||||
std::string lower_str = str;
|
||||
std::transform(lower_str.begin(), lower_str.end(), lower_str.begin(), ::tolower);
|
||||
return lower_str;
|
||||
}
|
||||
|
||||
// Función para convertir un string a mayúsculas
|
||||
std::string toUpper(const std::string &str)
|
||||
{
|
||||
std::string toUpper(const std::string& str) {
|
||||
std::string upper_str = str;
|
||||
std::transform(upper_str.begin(), upper_str.end(), upper_str.begin(), ::toupper);
|
||||
return upper_str;
|
||||
}
|
||||
|
||||
// Obtiene el nombre de un fichero a partir de una ruta completa
|
||||
std::string getFileName(const std::string &path)
|
||||
{
|
||||
std::string getFileName(const std::string& path) {
|
||||
return std::filesystem::path(path).filename().string();
|
||||
}
|
||||
|
||||
// Obtiene la ruta eliminando el nombre del fichero
|
||||
std::string getPath(const std::string &full_path)
|
||||
{
|
||||
std::string getPath(const std::string& full_path) {
|
||||
std::filesystem::path path(full_path);
|
||||
return path.parent_path().string();
|
||||
}
|
||||
|
||||
// Imprime por pantalla una linea de texto de tamaño fijo rellena con puntos
|
||||
void printWithDots(const std::string &text1, const std::string &text2, const std::string &text3)
|
||||
{
|
||||
void printWithDots(const std::string& text1, const std::string& text2, const std::string& text3) {
|
||||
std::cout.setf(std::ios::left, std::ios::adjustfield);
|
||||
std::cout << text1;
|
||||
|
||||
@@ -482,26 +417,22 @@ void printWithDots(const std::string &text1, const std::string &text2, const std
|
||||
}
|
||||
|
||||
// Comprueba si una vector contiene una cadena
|
||||
bool stringInVector(const std::vector<std::string> &vec, const std::string &str)
|
||||
{
|
||||
bool stringInVector(const std::vector<std::string>& vec, const std::string& str) {
|
||||
return std::find(vec.begin(), vec.end(), str) != vec.end();
|
||||
}
|
||||
|
||||
// Hace sonar la música
|
||||
void playMusic(const std::string &music_path)
|
||||
{
|
||||
void playMusic(const std::string& music_path) {
|
||||
// Si la música no está sonando
|
||||
if (JA_GetMusicState() == JA_MUSIC_INVALID || JA_GetMusicState() == JA_MUSIC_STOPPED)
|
||||
{
|
||||
if (JA_GetMusicState() == JA_MUSIC_INVALID || JA_GetMusicState() == JA_MUSIC_STOPPED) {
|
||||
JA_PlayMusic(Resource::get()->getMusic(music_path));
|
||||
}
|
||||
}
|
||||
|
||||
// Rellena una textura de un color
|
||||
void fillTextureWithColor(SDL_Renderer *renderer, SDL_Texture *texture, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
|
||||
{
|
||||
void fillTextureWithColor(SDL_Renderer* renderer, SDL_Texture* texture, Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
|
||||
// Guardar el render target actual
|
||||
SDL_Texture *previous_target = SDL_GetRenderTarget(renderer);
|
||||
SDL_Texture* previous_target = SDL_GetRenderTarget(renderer);
|
||||
|
||||
// Establecer la textura como el render target
|
||||
SDL_SetRenderTarget(renderer, texture);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL2/SDL_rect.h> // Para SDL_Rect, SDL_Point
|
||||
#include <SDL2/SDL_render.h> // Para SDL_Renderer, SDL_Texture
|
||||
#include <SDL2/SDL_stdinc.h> // Para Uint8
|
||||
#include <SDL3/SDL_rect.h> // Para SDL_Rect, SDL_Point
|
||||
#include <SDL3/SDL_render.h> // Para SDL_Renderer, SDL_Texture
|
||||
#include <SDL3/SDL_stdinc.h> // Para Uint8
|
||||
|
||||
#include <string> // Para string
|
||||
#include <vector> // Para vector
|
||||
|
||||
enum class PaletteColor : Uint8
|
||||
{
|
||||
enum class PaletteColor : Uint8 {
|
||||
BLACK = 0,
|
||||
BRIGHT_BLACK = 1,
|
||||
|
||||
@@ -36,96 +36,95 @@ enum class PaletteColor : Uint8
|
||||
};
|
||||
|
||||
// Estructura para definir un circulo
|
||||
struct Circle
|
||||
{
|
||||
struct Circle {
|
||||
int x;
|
||||
int y;
|
||||
int r;
|
||||
};
|
||||
|
||||
// Estructura para definir una linea horizontal
|
||||
struct LineHorizontal
|
||||
{
|
||||
struct LineHorizontal {
|
||||
int x1, x2, y;
|
||||
};
|
||||
|
||||
// Estructura para definir una linea vertical
|
||||
struct LineVertical
|
||||
{
|
||||
struct LineVertical {
|
||||
int x, y1, y2;
|
||||
};
|
||||
|
||||
// Estructura para definir una linea diagonal
|
||||
struct LineDiagonal
|
||||
{
|
||||
struct LineDiagonal {
|
||||
int x1, y1, x2, y2;
|
||||
};
|
||||
|
||||
// Estructura para definir una linea
|
||||
struct Line
|
||||
{
|
||||
struct Line {
|
||||
int x1, y1, x2, y2;
|
||||
};
|
||||
|
||||
// Estructura para definir un color
|
||||
struct Color
|
||||
{
|
||||
struct Color {
|
||||
Uint8 r;
|
||||
Uint8 g;
|
||||
Uint8 b;
|
||||
|
||||
// Constructor por defecto
|
||||
Color() : r(0), g(0), b(0) {}
|
||||
Color()
|
||||
: r(0),
|
||||
g(0),
|
||||
b(0) {}
|
||||
|
||||
// Constructor
|
||||
Color(Uint8 red, Uint8 green, Uint8 blue)
|
||||
: r(red), g(green), b(blue) {}
|
||||
: r(red),
|
||||
g(green),
|
||||
b(blue) {}
|
||||
};
|
||||
|
||||
// Calcula el cuadrado de la distancia entre dos puntos
|
||||
double distanceSquared(int x1, int y1, int x2, int y2);
|
||||
|
||||
// Detector de colisiones entre dos circulos
|
||||
bool checkCollision(const Circle &a, const Circle &b);
|
||||
bool checkCollision(const Circle& a, const Circle& b);
|
||||
|
||||
// Detector de colisiones entre un circulo y un rectangulo
|
||||
bool checkCollision(const Circle &a, const SDL_Rect &b);
|
||||
bool checkCollision(const Circle& a, const SDL_Rect& b);
|
||||
|
||||
// Detector de colisiones entre un dos rectangulos
|
||||
bool checkCollision(const SDL_Rect &a, const SDL_Rect &b);
|
||||
bool checkCollision(const SDL_Rect& a, const SDL_Rect& b);
|
||||
|
||||
// Detector de colisiones entre un punto y un rectangulo
|
||||
bool checkCollision(const SDL_Point &p, const SDL_Rect &r);
|
||||
bool checkCollision(const SDL_Point& p, const SDL_Rect& r);
|
||||
|
||||
// Detector de colisiones entre una linea horizontal y un rectangulo
|
||||
bool checkCollision(const LineHorizontal &l, const SDL_Rect &r);
|
||||
bool checkCollision(const LineHorizontal& l, const SDL_Rect& r);
|
||||
|
||||
// Detector de colisiones entre una linea vertical y un rectangulo
|
||||
bool checkCollision(const LineVertical &l, const SDL_Rect &r);
|
||||
bool checkCollision(const LineVertical& l, const SDL_Rect& r);
|
||||
|
||||
// Detector de colisiones entre una linea horizontal y un punto
|
||||
bool checkCollision(const LineHorizontal &l, const SDL_Point &p);
|
||||
bool checkCollision(const LineHorizontal& l, const SDL_Point& p);
|
||||
|
||||
// Detector de colisiones entre dos lineas
|
||||
SDL_Point checkCollision(const Line &l1, const Line &l2);
|
||||
SDL_Point checkCollision(const Line& l1, const Line& l2);
|
||||
|
||||
// Detector de colisiones entre dos lineas
|
||||
SDL_Point checkCollision(const LineDiagonal &l1, const LineVertical &l2);
|
||||
SDL_Point checkCollision(const LineDiagonal& l1, const LineVertical& l2);
|
||||
|
||||
// Detector de colisiones entre un punto y una linea diagonal
|
||||
bool checkCollision(const SDL_Point &p, const LineDiagonal &l);
|
||||
bool checkCollision(const SDL_Point& p, const LineDiagonal& l);
|
||||
|
||||
// Normaliza una linea diagonal
|
||||
void normalizeLine(LineDiagonal &l);
|
||||
void normalizeLine(LineDiagonal& l);
|
||||
|
||||
// Devuelve un Color a partir de un string
|
||||
Uint8 stringToColor(const std::string &str);
|
||||
Uint8 stringToColor(const std::string& str);
|
||||
|
||||
// Convierte una cadena a un entero de forma segura
|
||||
int safeStoi(const std::string &value, int defaultValue = 0);
|
||||
int safeStoi(const std::string& value, int defaultValue = 0);
|
||||
|
||||
// Convierte una cadena a un booleano
|
||||
bool stringToBool(const std::string &str);
|
||||
bool stringToBool(const std::string& str);
|
||||
|
||||
// Convierte un booleano a una cadena
|
||||
std::string boolToString(bool value);
|
||||
@@ -134,25 +133,25 @@ std::string boolToString(bool value);
|
||||
bool colorAreEqual(Color color1, Color color2);
|
||||
|
||||
// Convierte una cadena a minusculas
|
||||
std::string toLower(const std::string &str);
|
||||
std::string toLower(const std::string& str);
|
||||
|
||||
// Convierte una cadena a mayúsculas
|
||||
std::string toUpper(const std::string &str);
|
||||
std::string toUpper(const std::string& str);
|
||||
|
||||
// Obtiene el nombre de un fichero a partir de una ruta
|
||||
std::string getFileName(const std::string &path);
|
||||
std::string getFileName(const std::string& path);
|
||||
|
||||
// Obtiene la ruta eliminando el nombre del fichero
|
||||
std::string getPath(const std::string &full_path);
|
||||
std::string getPath(const std::string& full_path);
|
||||
|
||||
// Imprime por pantalla una linea de texto de tamaño fijo rellena con puntos
|
||||
void printWithDots(const std::string &text1, const std::string &text2, const std::string &text3);
|
||||
void printWithDots(const std::string& text1, const std::string& text2, const std::string& text3);
|
||||
|
||||
// Comprueba si una vector contiene una cadena
|
||||
bool stringInVector(const std::vector<std::string> &vec, const std::string &str);
|
||||
bool stringInVector(const std::vector<std::string>& vec, const std::string& str);
|
||||
|
||||
// Hace sonar la música
|
||||
void playMusic(const std::string &music_path);
|
||||
void playMusic(const std::string& music_path);
|
||||
|
||||
// Rellena una textura de un color
|
||||
void fillTextureWithColor(SDL_Renderer *renderer, SDL_Texture *texture, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
|
||||
void fillTextureWithColor(SDL_Renderer* renderer, SDL_Texture* texture, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
|
||||
6
source/version.h.in
Normal file
6
source/version.h.in
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace Version {
|
||||
constexpr const char* GIT_HASH = "@GIT_HASH@";
|
||||
constexpr const char* APP_NAME = "Coffee Crisis Arcade Edition";
|
||||
}
|
||||
Reference in New Issue
Block a user