forked from jaildesigner-jailgames/jaildoctors_dilemma
creada carpeta source2
This commit is contained in:
257
source2/Game/Scenes/credits.cpp
Normal file
257
source2/Game/Scenes/credits.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
#include "credits.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#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 "screen.h" // Para Screen
|
||||
#include "sprite/surface_animated_sprite.h" // Para SAnimatedSprite
|
||||
#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_FRect 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_FRect srcRect = {0.0F, 0.0F, 256.0F, 192.0F - (offset * 2.0F)};
|
||||
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
source2/Game/Scenes/credits.h
Normal file
60
source2/Game/Scenes/credits.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#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();
|
||||
};
|
||||
480
source2/Game/Scenes/ending.cpp
Normal file
480
source2/Game/Scenes/ending.cpp
Normal file
@@ -0,0 +1,480 @@
|
||||
#include "ending.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <algorithm> // Para min
|
||||
|
||||
#include "defines.h" // Para GAME_SPEED
|
||||
#include "external/jail_audio.h" // Para JA_SetVolume, JA_PlayMusic, JA_StopMusic
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
#include "options.h" // Para Options, options, OptionsGame, SectionS...
|
||||
#include "resource.h" // Para Resource
|
||||
#include "screen.h" // Para Screen
|
||||
#include "sprite/surface_sprite.h" // Para SSprite
|
||||
#include "surface.h" // Para Surface
|
||||
#include "text.h" // Para Text, TEXT_STROKE
|
||||
#include "utils.h" // Para PaletteColor
|
||||
|
||||
// Constructor
|
||||
Ending::Ending()
|
||||
: counter_(-1),
|
||||
pre_counter_(0),
|
||||
cover_counter_(0),
|
||||
ticks_(0),
|
||||
current_scene_(0) {
|
||||
options.section.section = Section::ENDING;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
|
||||
// Inicializa los textos
|
||||
iniTexts();
|
||||
|
||||
// Inicializa las imagenes
|
||||
iniPics();
|
||||
|
||||
// Inicializa las escenas
|
||||
iniScenes();
|
||||
|
||||
// Cambia el color del borde
|
||||
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
// Crea la textura para cubrir el texto
|
||||
cover_surface_ = std::make_shared<Surface>(options.game.width, options.game.height + 8);
|
||||
|
||||
// Rellena la textura para la cortinilla
|
||||
fillCoverTexture();
|
||||
}
|
||||
|
||||
// Actualiza el objeto
|
||||
void Ending::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
|
||||
updateCounters();
|
||||
|
||||
// Actualiza las cortinillas de los elementos
|
||||
updateSpriteCovers();
|
||||
|
||||
// Comprueba si se ha de cambiar de escena
|
||||
checkChangeScene();
|
||||
|
||||
// Actualiza el volumen de la musica
|
||||
updateMusicVolume();
|
||||
|
||||
// Actualiza el objeto Screen
|
||||
Screen::get()->update();
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja el final en pantalla
|
||||
void Ending::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));
|
||||
|
||||
// Dibuja las imagenes de la escena
|
||||
sprite_pics_.at(current_scene_).image_sprite->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) {
|
||||
sprite_texts_.at(ti.index).image_sprite->render();
|
||||
sprite_texts_.at(ti.index).cover_sprite->render();
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja la cortinilla de cambio de escena
|
||||
renderCoverTexture();
|
||||
|
||||
// Vuelca el contenido del renderizador en pantalla
|
||||
Screen::get()->render();
|
||||
}
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void Ending::checkEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
globalEvents::check(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las entradas
|
||||
void Ending::checkInput() {
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Inicializa los textos
|
||||
void Ending::iniTexts() {
|
||||
// Vector con los textos
|
||||
std::vector<TextAndPosition> texts;
|
||||
|
||||
// Escena #0
|
||||
texts.push_back({"HE FINALLY MANAGED", 32});
|
||||
texts.push_back({"TO GET TO THE JAIL", 42});
|
||||
texts.push_back({"WITH ALL HIS PROJECTS", 142});
|
||||
texts.push_back({"READY TO BE FREED", 152});
|
||||
|
||||
// Escena #1
|
||||
texts.push_back({"ALL THE JAILERS WERE THERE", 1});
|
||||
texts.push_back({"WAITING FOR THE JAILGAMES", 11});
|
||||
texts.push_back({"TO BE RELEASED", 21});
|
||||
|
||||
texts.push_back({"THERE WERE EVEN BARRULLS AND", 161});
|
||||
texts.push_back({"BEGINNERS AMONG THE CROWD", 171});
|
||||
|
||||
texts.push_back({"BRY WAS CRYING...", 181});
|
||||
|
||||
// Escena #2
|
||||
texts.push_back({"BUT SUDDENLY SOMETHING", 19});
|
||||
texts.push_back({"CAUGHT HIS ATTENTION", 29});
|
||||
|
||||
// Escena #3
|
||||
texts.push_back({"A PILE OF JUNK!", 36});
|
||||
texts.push_back({"FULL OF NON WORKING TRASH!!", 46});
|
||||
|
||||
// Escena #4
|
||||
texts.push_back({"AND THEN,", 36});
|
||||
texts.push_back({"FOURTY NEW PROJECTS", 46});
|
||||
texts.push_back({"WERE BORN...", 158});
|
||||
|
||||
// Crea los sprites
|
||||
sprite_texts_.clear();
|
||||
|
||||
for (const auto& txt : texts) {
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
|
||||
const float WIDTH = text->lenght(txt.caption, 1) + 2 + 2;
|
||||
const float HEIGHT = text->getCharacterSize() + 2 + 2;
|
||||
auto text_color = static_cast<Uint8>(PaletteColor::WHITE);
|
||||
auto shadow_color = static_cast<Uint8>(PaletteColor::BLACK);
|
||||
|
||||
EndingSurface st;
|
||||
|
||||
// Crea la textura
|
||||
st.image_surface = std::make_shared<Surface>(WIDTH, HEIGHT);
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(st.image_surface);
|
||||
text->writeDX(TEXT_STROKE, 2, 2, txt.caption, 1, text_color, 2, shadow_color);
|
||||
|
||||
// Crea el sprite
|
||||
st.image_sprite = std::make_shared<SSprite>(st.image_surface, 0, 0, st.image_surface->getWidth(), st.image_surface->getHeight());
|
||||
st.image_sprite->setPosition((options.game.width - st.image_surface->getWidth()) / 2, txt.pos);
|
||||
|
||||
// Crea la cover_surface
|
||||
st.cover_surface = std::make_shared<Surface>(WIDTH, HEIGHT + 8);
|
||||
Screen::get()->setRendererSurface(st.cover_surface);
|
||||
|
||||
// Rellena la cover_surface con color transparente
|
||||
st.cover_surface->clear(static_cast<Uint8>(PaletteColor::TRANSPARENT));
|
||||
|
||||
// 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) {
|
||||
surface->putPixel(i, 0, color);
|
||||
surface->putPixel(i, 2, color);
|
||||
surface->putPixel(i, 4, color);
|
||||
surface->putPixel(i, 6, color);
|
||||
|
||||
surface->putPixel(i + 1, 5, color);
|
||||
surface->putPixel(i + 1, 7, color);
|
||||
}
|
||||
|
||||
// El resto se rellena de color sólido
|
||||
SDL_FRect rect = {0, 8, WIDTH, HEIGHT};
|
||||
surface->fillRect(&rect, color);
|
||||
|
||||
// Crea el sprite
|
||||
st.cover_sprite = std::make_shared<SSprite>(st.cover_surface, 0, 0, st.cover_surface->getWidth(), st.cover_surface->getHeight() - 8);
|
||||
st.cover_sprite->setPosition((options.game.width - st.cover_surface->getWidth()) / 2, txt.pos);
|
||||
st.cover_sprite->setClip(0, 8, st.cover_surface->getWidth(), st.cover_surface->getHeight());
|
||||
|
||||
// Inicializa variables
|
||||
st.cover_clip_desp = 8;
|
||||
st.cover_clip_height = HEIGHT;
|
||||
|
||||
sprite_texts_.push_back(st);
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
}
|
||||
}
|
||||
|
||||
// Inicializa las imagenes
|
||||
void Ending::iniPics() {
|
||||
// Vector con las rutas y la posición
|
||||
std::vector<TextAndPosition> pics;
|
||||
|
||||
pics.push_back({"ending1.gif", 48});
|
||||
pics.push_back({"ending2.gif", 26});
|
||||
pics.push_back({"ending3.gif", 29});
|
||||
pics.push_back({"ending4.gif", 63});
|
||||
pics.push_back({"ending5.gif", 53});
|
||||
|
||||
// Crea los sprites
|
||||
sprite_pics_.clear();
|
||||
|
||||
for (const auto& pic : pics) {
|
||||
EndingSurface sp;
|
||||
|
||||
// Crea la texture
|
||||
sp.image_surface = Resource::get()->getSurface(pic.caption);
|
||||
sp.image_surface->setTransparentColor();
|
||||
const float WIDTH = sp.image_surface->getWidth();
|
||||
const float HEIGHT = sp.image_surface->getHeight();
|
||||
|
||||
// Crea el sprite
|
||||
sp.image_sprite = std::make_shared<SSprite>(sp.image_surface, 0, 0, WIDTH, HEIGHT);
|
||||
sp.image_sprite->setPosition((options.game.width - WIDTH) / 2, pic.pos);
|
||||
|
||||
// Crea la cover_surface
|
||||
sp.cover_surface = std::make_shared<Surface>(WIDTH, HEIGHT + 8);
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(sp.cover_surface);
|
||||
|
||||
// Rellena la cover_surface con color transparente
|
||||
sp.cover_surface->clear(static_cast<Uint8>(PaletteColor::TRANSPARENT));
|
||||
|
||||
// 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) {
|
||||
surface->putPixel(i, 0, color);
|
||||
surface->putPixel(i, 2, color);
|
||||
surface->putPixel(i, 4, color);
|
||||
surface->putPixel(i, 6, color);
|
||||
|
||||
surface->putPixel(i + 1, 5, color);
|
||||
surface->putPixel(i + 1, 7, color);
|
||||
}
|
||||
|
||||
// El resto se rellena de color sólido
|
||||
SDL_FRect rect = {0.0F, 8.0F, WIDTH, HEIGHT};
|
||||
surface->fillRect(&rect, color);
|
||||
|
||||
// Crea el sprite
|
||||
sp.cover_sprite = std::make_shared<SSprite>(sp.cover_surface, 0, 0, sp.cover_surface->getWidth(), sp.cover_surface->getHeight() - 8);
|
||||
sp.cover_sprite->setPosition((options.game.width - sp.cover_surface->getWidth()) / 2, pic.pos);
|
||||
sp.cover_sprite->setClip(0, 8, sp.cover_surface->getWidth(), sp.cover_surface->getHeight());
|
||||
|
||||
// Inicializa variables
|
||||
sp.cover_clip_desp = 8;
|
||||
sp.cover_clip_height = HEIGHT;
|
||||
|
||||
sprite_pics_.push_back(sp);
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
}
|
||||
}
|
||||
|
||||
// Inicializa las escenas
|
||||
void Ending::iniScenes() {
|
||||
// Variable para los tiempos
|
||||
int trigger;
|
||||
constexpr int LAPSE = 80;
|
||||
|
||||
// Crea el contenedor
|
||||
SceneData sc;
|
||||
|
||||
// Inicializa el vector
|
||||
scenes_.clear();
|
||||
|
||||
// Crea la escena #0
|
||||
sc.counter_end = 1000;
|
||||
sc.picture_index = 0;
|
||||
sc.text_index.clear();
|
||||
trigger = 85 * 2;
|
||||
trigger += LAPSE;
|
||||
sc.text_index.push_back({0, trigger});
|
||||
trigger += LAPSE;
|
||||
sc.text_index.push_back({1, trigger});
|
||||
trigger += LAPSE * 3;
|
||||
sc.text_index.push_back({2, trigger});
|
||||
trigger += LAPSE;
|
||||
sc.text_index.push_back({3, trigger});
|
||||
scenes_.push_back(sc);
|
||||
|
||||
// Crea la escena #1
|
||||
sc.counter_end = 1400;
|
||||
sc.picture_index = 1;
|
||||
sc.text_index.clear();
|
||||
trigger = 140 * 2;
|
||||
trigger += LAPSE;
|
||||
sc.text_index.push_back({4, trigger});
|
||||
trigger += LAPSE;
|
||||
sc.text_index.push_back({5, trigger});
|
||||
trigger += LAPSE;
|
||||
sc.text_index.push_back({6, trigger});
|
||||
trigger += LAPSE * 3;
|
||||
sc.text_index.push_back({7, trigger});
|
||||
trigger += LAPSE;
|
||||
sc.text_index.push_back({8, trigger});
|
||||
trigger += LAPSE * 3;
|
||||
sc.text_index.push_back({9, trigger});
|
||||
scenes_.push_back(sc);
|
||||
|
||||
// Crea la escena #2
|
||||
sc.counter_end = 1000;
|
||||
sc.picture_index = 2;
|
||||
sc.text_index.clear();
|
||||
trigger = 148 / 2;
|
||||
trigger += LAPSE;
|
||||
sc.text_index.push_back({10, trigger});
|
||||
trigger += LAPSE;
|
||||
sc.text_index.push_back({11, trigger});
|
||||
scenes_.push_back(sc);
|
||||
|
||||
// Crea la escena #3
|
||||
sc.counter_end = 800;
|
||||
sc.picture_index = 3;
|
||||
sc.text_index.clear();
|
||||
trigger = 87 / 2;
|
||||
trigger += LAPSE;
|
||||
sc.text_index.push_back({12, trigger});
|
||||
trigger += LAPSE / 2;
|
||||
sc.text_index.push_back({13, trigger});
|
||||
scenes_.push_back(sc);
|
||||
|
||||
// Crea la escena #4
|
||||
sc.counter_end = 1000;
|
||||
sc.picture_index = 4;
|
||||
sc.text_index.clear();
|
||||
trigger = 91 * 2;
|
||||
trigger += LAPSE;
|
||||
sc.text_index.push_back({14, trigger});
|
||||
trigger += LAPSE * 2;
|
||||
sc.text_index.push_back({15, trigger});
|
||||
trigger += LAPSE * 3;
|
||||
sc.text_index.push_back({16, trigger});
|
||||
scenes_.push_back(sc);
|
||||
}
|
||||
|
||||
// Bucle principal
|
||||
void Ending::run() {
|
||||
JA_PlayMusic(Resource::get()->getMusic("ending1.ogg"));
|
||||
|
||||
while (options.section.section == Section::ENDING) {
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
}
|
||||
|
||||
JA_StopMusic();
|
||||
JA_SetVolume(128);
|
||||
}
|
||||
|
||||
// Actualiza los contadores
|
||||
void Ending::updateCounters() {
|
||||
// Incrementa el contador
|
||||
if (pre_counter_ < 200) {
|
||||
pre_counter_++;
|
||||
} else {
|
||||
counter_++;
|
||||
}
|
||||
|
||||
if (counter_ > scenes_[current_scene_].counter_end - 100) {
|
||||
cover_counter_++;
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza las cortinillas de los elementos
|
||||
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) {
|
||||
sprite_texts_.at(ti.index).cover_clip_desp -= 2;
|
||||
} 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);
|
||||
}
|
||||
sprite_texts_.at(ti.index).cover_sprite->setClip(0, sprite_texts_.at(ti.index).cover_clip_desp, sprite_texts_.at(ti.index).cover_sprite->getWidth(), sprite_texts_.at(ti.index).cover_clip_height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza la cortinilla de las imágenes
|
||||
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) {
|
||||
sprite_pics_.at(current_scene_).cover_clip_height -= 2;
|
||||
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);
|
||||
}
|
||||
sprite_pics_.at(current_scene_).cover_sprite->setClip(0, sprite_pics_.at(current_scene_).cover_clip_desp, sprite_pics_.at(current_scene_).cover_sprite->getWidth(), sprite_pics_.at(current_scene_).cover_clip_height);
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba si se ha de cambiar de escena
|
||||
void Ending::checkChangeScene() {
|
||||
if (counter_ > scenes_[current_scene_].counter_end) {
|
||||
current_scene_++;
|
||||
counter_ = 0;
|
||||
cover_counter_ = 0;
|
||||
if (current_scene_ == 5) {
|
||||
// Termina el bucle
|
||||
options.section.section = Section::ENDING2;
|
||||
|
||||
// Mantiene los valores anteriores
|
||||
current_scene_ = 4;
|
||||
cover_counter_ = 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rellena la textura para la cortinilla
|
||||
void Ending::fillCoverTexture() {
|
||||
// Rellena la textura que cubre el texto con color transparente
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(cover_surface_);
|
||||
cover_surface_->clear(static_cast<Uint8>(PaletteColor::TRANSPARENT));
|
||||
|
||||
// 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) {
|
||||
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);
|
||||
surface->putPixel(i + 1, options.game.height + 3, color);
|
||||
|
||||
surface->putPixel(i, options.game.height + 4, color);
|
||||
surface->putPixel(i, options.game.height + 6, color);
|
||||
}
|
||||
|
||||
// El resto se rellena de color sólido
|
||||
SDL_FRect rect = {0, 0, 256, options.game.height};
|
||||
surface->fillRect(&rect, color);
|
||||
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
}
|
||||
|
||||
// Dibuja la cortinilla de cambio de escena
|
||||
void Ending::renderCoverTexture() {
|
||||
if (cover_counter_ > 0) {
|
||||
// Dibuja la textura que cubre el texto
|
||||
const int OFFSET = std::min(cover_counter_, 100);
|
||||
SDL_FRect srcRect = {0.0F, 200.0F - (cover_counter_ * 2.0F), 256.0F, OFFSET * 2.0F};
|
||||
SDL_FRect dstRect = {0.0F, 0.0F, 256.0F, OFFSET * 2.0F};
|
||||
cover_surface_->render(&srcRect, &dstRect);
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el volumen de la musica
|
||||
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
source2/Game/Scenes/ending.h
Normal file
103
source2/Game/Scenes/ending.h
Normal file
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#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();
|
||||
};
|
||||
492
source2/Game/Scenes/ending2.cpp
Normal file
492
source2/Game/Scenes/ending2.cpp
Normal file
@@ -0,0 +1,492 @@
|
||||
#include "ending2.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <algorithm> // Para max, replace
|
||||
|
||||
#include "defines.h" // Para GAMECANVAS_CENTER_X, GAMECANVAS_CENTER_Y
|
||||
#include "external/jail_audio.h" // Para JA_SetVolume, JA_PlayMusic, JA_StopMusic
|
||||
#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 "screen.h" // Para Screen
|
||||
#include "sprite/surface_animated_sprite.h" // Para SAnimatedSprite
|
||||
#include "sprite/surface_moving_sprite.h" // Para SMovingSprite
|
||||
#include "surface.h" // Para Surface
|
||||
#include "text.h" // Para Text
|
||||
#include "utils.h" // Para PaletteColor, stringToColor
|
||||
|
||||
// Constructor
|
||||
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) {
|
||||
colors_.push_back(stringToColor(color));
|
||||
}
|
||||
|
||||
// Cambia el color del borde
|
||||
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
// Inicializa la lista de sprites
|
||||
iniSpriteList();
|
||||
|
||||
// Carga todos los sprites desde una lista
|
||||
loadSprites();
|
||||
|
||||
// Coloca los sprites en su sito
|
||||
placeSprites();
|
||||
|
||||
// Crea los sprites con las texturas con los textos
|
||||
createSpriteTexts();
|
||||
|
||||
// Crea los sprites con las texturas con los textos del final
|
||||
createTexts();
|
||||
}
|
||||
|
||||
// Actualiza el objeto
|
||||
void Ending2::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 estado
|
||||
updateState();
|
||||
|
||||
switch (state_.state) {
|
||||
case EndingState::CREDITS:
|
||||
// Actualiza los sprites, los textos y los textos del final
|
||||
for (int i = 0; i < 25; ++i) {
|
||||
updateSprites();
|
||||
updateTextSprites();
|
||||
updateTexts();
|
||||
}
|
||||
break;
|
||||
|
||||
case EndingState::FADING:
|
||||
// Actualiza el fade final y el volumen de la música
|
||||
updateFinalFade();
|
||||
updateMusicVolume();
|
||||
break;
|
||||
|
||||
default:
|
||||
// No hacer nada si el estado no corresponde a un caso manejado
|
||||
break;
|
||||
}
|
||||
|
||||
// Actualiza el objeto
|
||||
Screen::get()->update();
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja el final en pantalla
|
||||
void Ending2::render() {
|
||||
// Prepara para empezar a dibujar en la surface de juego
|
||||
Screen::get()->start();
|
||||
|
||||
// Limpia la pantalla
|
||||
Screen::get()->clearSurface(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
// Dibuja los sprites
|
||||
renderSprites();
|
||||
|
||||
// Dibuja los sprites con el texto
|
||||
renderSpriteTexts();
|
||||
|
||||
// Dibuja los sprites con el texto del final
|
||||
renderTexts();
|
||||
|
||||
// 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) {
|
||||
surface->putPixel(i + 0, 0, color);
|
||||
surface->putPixel(i + 1, 1, color);
|
||||
surface->putPixel(i + 0, 2, color);
|
||||
surface->putPixel(i + 1, 3, color);
|
||||
|
||||
surface->putPixel(i, 4, color);
|
||||
surface->putPixel(i, 6, color);
|
||||
|
||||
surface->putPixel(i + 0, 191, color);
|
||||
surface->putPixel(i + 1, 190, color);
|
||||
surface->putPixel(i + 0, 189, color);
|
||||
surface->putPixel(i + 1, 188, color);
|
||||
|
||||
surface->putPixel(i, 187, color);
|
||||
surface->putPixel(i, 185, color);
|
||||
}
|
||||
|
||||
// Vuelca el contenido del renderizador en pantalla
|
||||
Screen::get()->render();
|
||||
}
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void Ending2::checkEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
globalEvents::check(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las entradas
|
||||
void Ending2::checkInput() {
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Bucle principal
|
||||
void Ending2::run() {
|
||||
JA_PlayMusic(Resource::get()->getMusic("ending2.ogg"));
|
||||
|
||||
while (options.section.section == Section::ENDING2) {
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
}
|
||||
|
||||
JA_StopMusic();
|
||||
JA_SetVolume(128);
|
||||
}
|
||||
|
||||
// Actualiza el estado
|
||||
void Ending2::updateState() {
|
||||
switch (state_.state) {
|
||||
case 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) {
|
||||
state_.set(EndingState::POST_CREDITS, STATE_POST_CREDITS_DURATION_);
|
||||
}
|
||||
break;
|
||||
|
||||
case 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)) {
|
||||
options.section.section = Section::LOGO;
|
||||
options.section.subsection = Subsection::LOGO_TO_INTRO;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Inicializa la lista de sprites
|
||||
void Ending2::iniSpriteList() {
|
||||
// Reinicia el vector
|
||||
sprite_list_.clear();
|
||||
|
||||
// Añade los valores
|
||||
sprite_list_.push_back("bin");
|
||||
sprite_list_.push_back("floppy");
|
||||
sprite_list_.push_back("bird");
|
||||
sprite_list_.push_back("chip");
|
||||
sprite_list_.push_back("jeannine");
|
||||
sprite_list_.push_back("spark");
|
||||
sprite_list_.push_back("code");
|
||||
sprite_list_.push_back("paco");
|
||||
sprite_list_.push_back("elsa");
|
||||
sprite_list_.push_back("z80");
|
||||
|
||||
sprite_list_.push_back("bell");
|
||||
sprite_list_.push_back("dong");
|
||||
|
||||
sprite_list_.push_back("amstrad_cs");
|
||||
sprite_list_.push_back("breakout");
|
||||
|
||||
sprite_list_.push_back("flying_arounder");
|
||||
sprite_list_.push_back("stopped_arounder");
|
||||
sprite_list_.push_back("walking_arounder");
|
||||
sprite_list_.push_back("arounders_door");
|
||||
sprite_list_.push_back("arounders_machine");
|
||||
|
||||
sprite_list_.push_back("abad");
|
||||
sprite_list_.push_back("abad_bell");
|
||||
sprite_list_.push_back("lord_abad");
|
||||
|
||||
sprite_list_.push_back("bat");
|
||||
sprite_list_.push_back("batman_bell");
|
||||
sprite_list_.push_back("batman_fire");
|
||||
sprite_list_.push_back("batman");
|
||||
|
||||
sprite_list_.push_back("demon");
|
||||
sprite_list_.push_back("heavy");
|
||||
sprite_list_.push_back("dimallas");
|
||||
sprite_list_.push_back("guitar");
|
||||
|
||||
sprite_list_.push_back("jailbattle_alien");
|
||||
sprite_list_.push_back("jailbattle_human");
|
||||
|
||||
sprite_list_.push_back("jailer_#1");
|
||||
sprite_list_.push_back("jailer_#2");
|
||||
sprite_list_.push_back("jailer_#3");
|
||||
sprite_list_.push_back("bry");
|
||||
sprite_list_.push_back("upv_student");
|
||||
|
||||
sprite_list_.push_back("lamp");
|
||||
sprite_list_.push_back("robot");
|
||||
sprite_list_.push_back("congo");
|
||||
sprite_list_.push_back("crosshair");
|
||||
sprite_list_.push_back("tree_thing");
|
||||
|
||||
sprite_list_.push_back("matatunos");
|
||||
sprite_list_.push_back("tuno");
|
||||
|
||||
sprite_list_.push_back("mummy");
|
||||
sprite_list_.push_back("sam");
|
||||
|
||||
sprite_list_.push_back("qvoid");
|
||||
sprite_list_.push_back("sigmasua");
|
||||
|
||||
sprite_list_.push_back("tv_panel");
|
||||
sprite_list_.push_back("tv");
|
||||
|
||||
sprite_list_.push_back("spider");
|
||||
sprite_list_.push_back("shock");
|
||||
sprite_list_.push_back("wave");
|
||||
|
||||
sprite_list_.push_back("player");
|
||||
}
|
||||
|
||||
// Carga todos los sprites desde una lista
|
||||
void Ending2::loadSprites() {
|
||||
// Inicializa variables
|
||||
sprite_max_width_ = 0;
|
||||
sprite_max_height_ = 0;
|
||||
|
||||
// Carga los sprites
|
||||
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_);
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza los sprites
|
||||
void Ending2::updateSprites() {
|
||||
for (auto sprite : sprites_) {
|
||||
sprite->update();
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza los sprites de texto
|
||||
void Ending2::updateTextSprites() {
|
||||
for (auto sprite : sprite_texts_) {
|
||||
sprite->update();
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza los sprites de texto del final
|
||||
void Ending2::updateTexts() {
|
||||
for (auto sprite : texts_) {
|
||||
sprite->update();
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja los sprites
|
||||
void Ending2::renderSprites() {
|
||||
const Uint8 colorA = static_cast<Uint8>(PaletteColor::RED);
|
||||
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) {
|
||||
sprite->render(1, colorA);
|
||||
}
|
||||
}
|
||||
|
||||
// Pinta el ultimo elemento de otro color
|
||||
const Uint8 colorB = static_cast<Uint8>(PaletteColor::WHITE);
|
||||
sprites_.back()->render(1, colorB);
|
||||
}
|
||||
|
||||
// Dibuja los sprites con el texto
|
||||
void Ending2::renderSpriteTexts() {
|
||||
const Uint8 color = static_cast<Uint8>(PaletteColor::WHITE);
|
||||
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) {
|
||||
sprite->render(1, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja los sprites con el texto del final
|
||||
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) {
|
||||
sprite->render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Coloca los sprites en su sito
|
||||
void Ending2::placeSprites() {
|
||||
for (int i = 0; i < static_cast<int>(sprites_.size()); ++i) {
|
||||
const float X = i % 2 == 0 ? FIRST_COL_ : SECOND_COL_;
|
||||
const float Y = (i / 1) * (sprite_max_height_ + DIST_SPRITE_TEXT_ + Resource::get()->getText("smb2")->getCharacterSize() + DIST_SPRITE_SPRITE_) + options.game.height + 40;
|
||||
const float W = sprites_.at(i)->getWidth();
|
||||
const float H = sprites_.at(i)->getHeight();
|
||||
const float DX = -(W / 2);
|
||||
const float DY = sprite_max_height_ - H;
|
||||
|
||||
sprites_.at(i)->setPos({X + DX, Y + DY, W, H});
|
||||
sprites_.at(i)->setVelY(SPRITE_DESP_SPEED_);
|
||||
}
|
||||
|
||||
// Recoloca el sprite del jugador, que es el último de la lista
|
||||
const float X = (options.game.width - sprites_.back()->getWidth()) / 2;
|
||||
const float Y = sprites_.back()->getPosY() + sprite_max_height_ * 2;
|
||||
sprites_.back()->setPos(X, Y);
|
||||
sprites_.back()->setCurrentAnimation("walk");
|
||||
}
|
||||
|
||||
// Crea los sprites con las texturas con los textos
|
||||
void Ending2::createSpriteTexts() {
|
||||
// Crea los sprites de texto a partir de la lista
|
||||
for (size_t i = 0; i < 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") {
|
||||
txt = "JAILDOCTOR"; // Reemplaza "player" por "JAILDOCTOR"
|
||||
}
|
||||
|
||||
// Calcula las dimensiones del texto
|
||||
const float W = text->lenght(txt, 1);
|
||||
const float H = text->getCharacterSize();
|
||||
|
||||
// Determina la columna y la posición X del texto
|
||||
const float X = (i == sprite_list_.size() - 1)
|
||||
? (GAMECANVAS_CENTER_X - (W / 2))
|
||||
: ((i % 2 == 0 ? FIRST_COL_ : SECOND_COL_) - (W / 2));
|
||||
|
||||
// Calcula la posición Y del texto en base a la posición y altura del sprite
|
||||
const float Y = sprites_.at(i)->getPosY() + sprites_.at(i)->getHeight() + DIST_SPRITE_TEXT_;
|
||||
|
||||
// Crea la surface
|
||||
auto surface = std::make_shared<Surface>(W, H);
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(surface);
|
||||
text->write(0, 0, txt);
|
||||
|
||||
// Crea el sprite
|
||||
SDL_FRect pos = {X, Y, W, H};
|
||||
sprite_texts_.emplace_back(std::make_shared<SMovingSprite>(surface, pos));
|
||||
sprite_texts_.back()->setVelY(SPRITE_DESP_SPEED_);
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
}
|
||||
}
|
||||
|
||||
// Crea los sprites con las texturas con los textos del final
|
||||
void Ending2::createTexts() {
|
||||
// Crea los primeros textos
|
||||
std::vector<std::string> list;
|
||||
list.push_back("STARRING");
|
||||
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
|
||||
// Crea los sprites de texto a partir de la lista
|
||||
for (size_t i = 0; i < list.size(); ++i) {
|
||||
// Calcula constantes
|
||||
const float W = text->lenght(list[i], 1);
|
||||
const float H = text->getCharacterSize();
|
||||
const float X = GAMECANVAS_CENTER_X;
|
||||
const float DX = -(W / 2);
|
||||
const float Y = options.game.height + (text->getCharacterSize() * (i * 2));
|
||||
|
||||
// Crea la surface
|
||||
auto surface = std::make_shared<Surface>(W, H);
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(surface);
|
||||
text->write(0, 0, list[i]);
|
||||
|
||||
// Crea el sprite
|
||||
SDL_FRect pos = {X + DX, Y, W, H};
|
||||
texts_.emplace_back(std::make_shared<SMovingSprite>(surface, pos));
|
||||
texts_.back()->setVelY(SPRITE_DESP_SPEED_);
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
}
|
||||
|
||||
// Crea los últimos textos
|
||||
// El primer texto va a continuación del ultimo spriteText
|
||||
const int START = sprite_texts_.back()->getPosY() + text->getCharacterSize() * 15;
|
||||
list.clear();
|
||||
list.push_back("THANK YOU");
|
||||
list.push_back("FOR PLAYING!");
|
||||
|
||||
// Crea los sprites de texto a partir de la lista
|
||||
for (size_t i = 0; i < list.size(); ++i) {
|
||||
// Calcula constantes
|
||||
const float W = text->lenght(list[i], 1);
|
||||
const float H = text->getCharacterSize();
|
||||
const float X = GAMECANVAS_CENTER_X;
|
||||
const float DX = -(W / 2);
|
||||
const float Y = START + (text->getCharacterSize() * (i * 2));
|
||||
|
||||
// Crea la surface
|
||||
auto surface = std::make_shared<Surface>(W, H);
|
||||
auto previuos_renderer = Screen::get()->getRendererSurface();
|
||||
Screen::get()->setRendererSurface(surface);
|
||||
text->write(0, 0, list[i]);
|
||||
|
||||
// Crea el sprite
|
||||
SDL_FRect pos = {X + DX, Y, W, H};
|
||||
texts_.emplace_back(std::make_shared<SMovingSprite>(surface, pos));
|
||||
texts_.back()->setVelY(SPRITE_DESP_SPEED_);
|
||||
Screen::get()->setRendererSurface(previuos_renderer);
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el fade final
|
||||
void Ending2::updateFinalFade() {
|
||||
for (auto sprite : texts_) {
|
||||
sprite->getSurface()->fadeSubPalette(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el volumen de la musica
|
||||
void Ending2::updateMusicVolume() {
|
||||
// Constante para la duración en milisegundos
|
||||
constexpr Uint32 VOLUME_FADE_DURATION = 3000;
|
||||
|
||||
// Tiempo actual
|
||||
const Uint32 CURRENT_TICKS = SDL_GetTicks();
|
||||
|
||||
// Calcular el tiempo transcurrido desde init_ticks
|
||||
Uint32 elapsed_ticks = CURRENT_TICKS - state_.init_ticks;
|
||||
|
||||
// Limitar el tiempo máximo a la duración definida
|
||||
elapsed_ticks = std::min(elapsed_ticks, VOLUME_FADE_DURATION);
|
||||
|
||||
// Calcular el step basado en la duración
|
||||
const float STEP = (static_cast<float>(VOLUME_FADE_DURATION) - elapsed_ticks) / VOLUME_FADE_DURATION;
|
||||
|
||||
// Calcular el volumen en función del step
|
||||
const int VOLUME = static_cast<int>(128 * STEP);
|
||||
|
||||
// Actualizar el volumen
|
||||
JA_SetVolume(VOLUME);
|
||||
}
|
||||
140
source2/Game/Scenes/ending2.h
Normal file
140
source2/Game/Scenes/ending2.h
Normal file
@@ -0,0 +1,140 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#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
|
||||
float sprite_max_width_ = 0; // El valor de ancho del sprite mas ancho
|
||||
float 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();
|
||||
};
|
||||
620
source2/Game/Scenes/game.cpp
Normal file
620
source2/Game/Scenes/game.cpp
Normal file
@@ -0,0 +1,620 @@
|
||||
#include "game.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#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 "external/jail_audio.h" // Para JA_PauseMusic, JA_GetMusicState, JA_P...
|
||||
#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 "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 "ui/notifier.h" // Para Notifier, NotificationText, CHEEVO_NO...
|
||||
#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_FRect 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_EVENT_KEY_DOWN && event.key.repeat == 0) {
|
||||
switch (event.key.key) {
|
||||
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.0F, PLAY_AREA_HEIGHT, options.game.width, text->getCharacterSize() * 2.0F};
|
||||
}
|
||||
|
||||
// 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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
175
source2/Game/Scenes/game.h
Normal file
175
source2/Game/Scenes/game.h
Normal file
@@ -0,0 +1,175 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#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_FRect 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();
|
||||
};
|
||||
162
source2/Game/Scenes/game_over.cpp
Normal file
162
source2/Game/Scenes/game_over.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
#include "game_over.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <algorithm> // Para min, max
|
||||
#include <string> // Para basic_string, operator+, to_string
|
||||
|
||||
#include "defines.h" // Para GAMECANVAS_CENTER_X, GAME_SPEED
|
||||
#include "external/jail_audio.h" // Para JA_PlayMusic
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
#include "options.h" // Para Options, options, OptionsStats, Secti...
|
||||
#include "resource.h" // Para Resource
|
||||
#include "screen.h" // Para Screen
|
||||
#include "sprite/surface_animated_sprite.h" // Para SAnimatedSprite
|
||||
#include "text.h" // Para TEXT_CENTER, TEXT_COLOR, Text
|
||||
#include "utils.h" // Para PaletteColor, stringToColor
|
||||
|
||||
// Constructor
|
||||
GameOver::GameOver()
|
||||
: player_sprite_(std::make_shared<SAnimatedSprite>(Resource::get()->getSurface("player_game_over.gif"), Resource::get()->getAnimations("player_game_over.ani"))),
|
||||
tv_sprite_(std::make_shared<SAnimatedSprite>(Resource::get()->getSurface("tv.gif"), Resource::get()->getAnimations("tv.ani"))),
|
||||
pre_counter_(0),
|
||||
counter_(0),
|
||||
ticks_(0) {
|
||||
options.section.section = Section::GAME_OVER;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
|
||||
player_sprite_->setPosX(GAMECANVAS_CENTER_X + 10);
|
||||
player_sprite_->setPosY(30);
|
||||
tv_sprite_->setPosX(GAMECANVAS_CENTER_X - tv_sprite_->getWidth() - 10);
|
||||
tv_sprite_->setPosY(30);
|
||||
|
||||
Screen::get()->setBorderColor(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
// Inicializa el vector de colores
|
||||
const std::vector<std::string> COLORS = {"white", "yellow", "cyan", "green", "magenta", "red", "blue", "black"};
|
||||
for (const auto& color : COLORS) {
|
||||
colors_.push_back(stringToColor(color));
|
||||
}
|
||||
color_ = colors_.back();
|
||||
}
|
||||
|
||||
// Actualiza el objeto
|
||||
void GameOver::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 color usado para renderizar los textos e imagenes
|
||||
updateColor();
|
||||
|
||||
// Actualiza los contadores
|
||||
updateCounters();
|
||||
|
||||
// Actualiza los dos sprites
|
||||
player_sprite_->update();
|
||||
tv_sprite_->update();
|
||||
|
||||
// Actualiza el objeto Screen
|
||||
Screen::get()->update();
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja el final en pantalla
|
||||
void GameOver::render() {
|
||||
constexpr int Y = 32;
|
||||
|
||||
Screen::get()->start();
|
||||
Screen::get()->clearSurface(static_cast<Uint8>(PaletteColor::BLACK));
|
||||
|
||||
auto text = Resource::get()->getText("smb2");
|
||||
|
||||
// Escribe el texto de GAME OVER
|
||||
text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, Y, "G A M E O V E R", 1, color_);
|
||||
|
||||
// Dibuja los sprites
|
||||
player_sprite_->setPosY(Y + 30);
|
||||
tv_sprite_->setPosY(Y + 30);
|
||||
renderSprites();
|
||||
|
||||
// Escribe el texto con las habitaciones y los items
|
||||
const std::string ITEMS_TEXT = std::to_string(options.stats.items / 100) + std::to_string((options.stats.items % 100) / 10) + std::to_string(options.stats.items % 10);
|
||||
const std::string ROOMS_TEXT = std::to_string(options.stats.rooms / 100) + std::to_string((options.stats.rooms % 100) / 10) + std::to_string(options.stats.rooms % 10);
|
||||
text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, Y + 80, "ITEMS: " + ITEMS_TEXT, 1, color_);
|
||||
text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, Y + 90, "ROOMS: " + ROOMS_TEXT, 1, color_);
|
||||
|
||||
// Escribe el texto con "Tu peor pesadilla"
|
||||
text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, Y + 110, "YOUR WORST NIGHTMARE IS", 1, color_);
|
||||
text->writeDX(TEXT_CENTER | TEXT_COLOR, GAMECANVAS_CENTER_X, Y + 120, options.stats.worst_nightmare, 1, color_);
|
||||
|
||||
// Vuelca el contenido del renderizador en pantalla
|
||||
Screen::get()->render();
|
||||
}
|
||||
|
||||
// Comprueba el manejador de eventos
|
||||
void GameOver::checkEvents() {
|
||||
SDL_Event event;
|
||||
while (SDL_PollEvent(&event)) {
|
||||
globalEvents::check(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Comprueba las entradas
|
||||
void GameOver::checkInput() {
|
||||
globalInputs::check();
|
||||
}
|
||||
|
||||
// Bucle principal
|
||||
void GameOver::run() {
|
||||
while (options.section.section == Section::GAME_OVER) {
|
||||
update();
|
||||
checkEvents();
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
// Actualiza el color usado para renderizar los textos e imagenes
|
||||
void GameOver::updateColor() {
|
||||
const int half = COUNTER_SECTION_END_ / 2;
|
||||
|
||||
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 {
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
// Dibuja los sprites
|
||||
void GameOver::renderSprites() {
|
||||
player_sprite_->render(1, color_);
|
||||
tv_sprite_->render(1, color_);
|
||||
}
|
||||
|
||||
// Actualiza los contadores
|
||||
void GameOver::updateCounters() {
|
||||
// Actualiza el contador
|
||||
if (pre_counter_ < 50) {
|
||||
pre_counter_++;
|
||||
} else {
|
||||
counter_++;
|
||||
}
|
||||
|
||||
// Hace sonar la música
|
||||
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_) {
|
||||
options.section.section = Section::LOGO;
|
||||
options.section.subsection = Subsection::LOGO_TO_TITLE;
|
||||
}
|
||||
}
|
||||
57
source2/Game/Scenes/game_over.h
Normal file
57
source2/Game/Scenes/game_over.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#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();
|
||||
};
|
||||
199
source2/Game/Scenes/loading_screen.cpp
Normal file
199
source2/Game/Scenes/loading_screen.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
#include "loading_screen.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <stdlib.h> // Para rand
|
||||
|
||||
#include "defines.h" // Para GAME_SPEED
|
||||
#include "external/jail_audio.h" // Para JA_PlayMusic, JA_SetVolume, JA_StopMusic
|
||||
#include "global_events.h" // Para check
|
||||
#include "global_inputs.h" // Para check
|
||||
#include "options.h" // Para Options, options, SectionState, Options...
|
||||
#include "resource.h" // Para Resource
|
||||
#include "screen.h" // Para Screen
|
||||
#include "sprite/surface_sprite.h" // Para SSprite
|
||||
#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);
|
||||
}
|
||||
60
source2/Game/Scenes/loading_screen.h
Normal file
60
source2/Game/Scenes/loading_screen.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#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_FRect 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();
|
||||
};
|
||||
225
source2/Game/Scenes/logo.cpp
Normal file
225
source2/Game/Scenes/logo.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
#include "logo.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#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 "screen.h" // Para Screen
|
||||
#include "sprite/surface_sprite.h" // Para SSprite
|
||||
#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
source2/Game/Scenes/logo.h
Normal file
60
source2/Game/Scenes/logo.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#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();
|
||||
};
|
||||
332
source2/Game/Scenes/title.cpp
Normal file
332
source2/Game/Scenes/title.cpp
Normal file
@@ -0,0 +1,332 @@
|
||||
#include "title.h"
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#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 "screen.h" // Para Screen
|
||||
#include "sprite/surface_sprite.h" // Para SSprite
|
||||
#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_EVENT_KEY_DOWN) {
|
||||
if (!show_cheevos_) {
|
||||
switch (event.key.key) {
|
||||
case SDLK_1:
|
||||
options.section.section = Section::GAME;
|
||||
options.section.subsection = Subsection::NONE;
|
||||
break;
|
||||
|
||||
case SDLK_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 float BOTTOM = cheevos_surface_->getHeight() - cheevos_surface_view_.h;
|
||||
cheevos_surface_view_.y = std::clamp(cheevos_surface_view_.y, 0.0F, 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_);
|
||||
}
|
||||
86
source2/Game/Scenes/title.h
Normal file
86
source2/Game/Scenes/title.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#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_FRect 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();
|
||||
};
|
||||
Reference in New Issue
Block a user