forked from jaildesigner-jailgames/jaildoctors_dilemma
197 lines
5.6 KiB
C++
197 lines
5.6 KiB
C++
#include "game/ui/console.hpp"
|
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
#include <string> // Para string
|
|
|
|
#include "core/rendering/screen.hpp" // Para Screen
|
|
#include "core/rendering/sprite/sprite.hpp" // Para Sprite
|
|
#include "core/rendering/surface.hpp" // Para Surface
|
|
#include "core/rendering/text.hpp" // Para Text
|
|
#include "core/resources/resource_cache.hpp" // Para Resource
|
|
#include "game/options.hpp" // Para Options
|
|
|
|
// [SINGLETON]
|
|
Console* Console::console = nullptr;
|
|
|
|
// [SINGLETON]
|
|
void Console::init(const std::string& font_name) {
|
|
Console::console = new Console(font_name);
|
|
}
|
|
|
|
// [SINGLETON]
|
|
void Console::destroy() {
|
|
delete Console::console;
|
|
Console::console = nullptr;
|
|
}
|
|
|
|
// [SINGLETON]
|
|
auto Console::get() -> Console* {
|
|
return Console::console;
|
|
}
|
|
|
|
// Constructor
|
|
Console::Console(const std::string& font_name)
|
|
: text_(Resource::Cache::get()->getText(font_name)) {
|
|
const int TEXT_SIZE = 6;
|
|
const int PADDING_IN_V = TEXT_SIZE / 2;
|
|
height_ = static_cast<float>((TEXT_SIZE * 2) + (PADDING_IN_V * 2));
|
|
y_ = -height_;
|
|
|
|
buildSurface();
|
|
}
|
|
|
|
// Crea la Surface con el aspecto visual de la consola
|
|
void Console::buildSurface() {
|
|
const float WIDTH = Options::game.width;
|
|
|
|
surface_ = std::make_shared<Surface>(WIDTH, height_);
|
|
|
|
// Posición inicial (fuera de pantalla por arriba)
|
|
SDL_FRect sprite_rect = {.x = 0, .y = y_, .w = WIDTH, .h = height_};
|
|
sprite_ = std::make_shared<Sprite>(surface_, sprite_rect);
|
|
|
|
// Dibujo inicial del texto
|
|
redrawText();
|
|
}
|
|
|
|
// Redibuja el texto dinámico sobre la surface (fondo + borde + líneas)
|
|
void Console::redrawText() {
|
|
const float WIDTH = Options::game.width;
|
|
const int TEXT_SIZE = 6;
|
|
const int PADDING_IN_H = TEXT_SIZE;
|
|
const int PADDING_IN_V = TEXT_SIZE / 2;
|
|
|
|
auto previous_renderer = Screen::get()->getRendererSurface();
|
|
Screen::get()->setRendererSurface(surface_);
|
|
|
|
// Fondo y borde
|
|
surface_->clear(BG_COLOR);
|
|
SDL_FRect rect = {.x = 0, .y = 0, .w = WIDTH, .h = height_};
|
|
surface_->drawRectBorder(&rect, BORDER_COLOR);
|
|
|
|
// Línea 1: mensajes
|
|
text_->writeColored(PADDING_IN_H, PADDING_IN_V, msg_line_, MSG_COLOR);
|
|
|
|
// Línea 2: prompt + input + cursor
|
|
const bool SHOW_CURSOR = cursor_visible_ && (static_cast<int>(input_line_.size()) < MAX_INPUT_CHARS);
|
|
const std::string INPUT_STR = "> " + input_line_ + (SHOW_CURSOR ? "_" : "");
|
|
text_->writeColored(PADDING_IN_H, PADDING_IN_V + TEXT_SIZE, INPUT_STR, BORDER_COLOR);
|
|
|
|
Screen::get()->setRendererSurface(previous_renderer);
|
|
}
|
|
|
|
// Actualiza la animación de la consola
|
|
void Console::update(float delta_time) {
|
|
if (status_ == Status::HIDDEN) {
|
|
return;
|
|
}
|
|
|
|
// Parpadeo del cursor (solo cuando activa)
|
|
if (status_ == Status::ACTIVE) {
|
|
cursor_timer_ += delta_time;
|
|
const float THRESHOLD = cursor_visible_ ? CURSOR_ON_TIME : CURSOR_OFF_TIME;
|
|
if (cursor_timer_ >= THRESHOLD) {
|
|
cursor_timer_ = 0.0F;
|
|
cursor_visible_ = !cursor_visible_;
|
|
}
|
|
}
|
|
|
|
// Redibujar texto cada frame
|
|
redrawText();
|
|
|
|
switch (status_) {
|
|
case Status::RISING: {
|
|
y_ += SLIDE_SPEED * delta_time;
|
|
if (y_ >= 0.0F) {
|
|
y_ = 0.0F;
|
|
status_ = Status::ACTIVE;
|
|
}
|
|
break;
|
|
}
|
|
case Status::VANISHING: {
|
|
y_ -= SLIDE_SPEED * delta_time;
|
|
if (y_ <= -height_) {
|
|
y_ = -height_;
|
|
status_ = Status::HIDDEN;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
SDL_FRect rect = {.x = 0, .y = y_, .w = Options::game.width, .h = height_};
|
|
sprite_->setPosition(rect);
|
|
}
|
|
|
|
// Renderiza la consola
|
|
void Console::render() {
|
|
if (status_ == Status::HIDDEN) {
|
|
return;
|
|
}
|
|
sprite_->render();
|
|
}
|
|
|
|
// Activa o desactiva la consola
|
|
void Console::toggle() {
|
|
switch (status_) {
|
|
case Status::HIDDEN:
|
|
status_ = Status::RISING;
|
|
input_line_.clear();
|
|
cursor_timer_ = 0.0F;
|
|
cursor_visible_ = true;
|
|
SDL_StartTextInput(SDL_GetKeyboardFocus());
|
|
break;
|
|
case Status::ACTIVE:
|
|
status_ = Status::VANISHING;
|
|
SDL_StopTextInput(SDL_GetKeyboardFocus());
|
|
break;
|
|
default:
|
|
// Durante RISING o VANISHING no se hace nada
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Procesa el evento SDL: entrada de texto, Backspace, Enter
|
|
void Console::handleEvent(const SDL_Event& event) {
|
|
if (status_ != Status::ACTIVE) { return; }
|
|
|
|
if (event.type == SDL_EVENT_TEXT_INPUT) {
|
|
if (static_cast<int>(input_line_.size()) < MAX_INPUT_CHARS) {
|
|
input_line_ += event.text.text;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (event.type == SDL_EVENT_KEY_DOWN) {
|
|
if (event.key.scancode == SDL_SCANCODE_BACKSPACE && !input_line_.empty()) {
|
|
input_line_.pop_back();
|
|
} else if (event.key.scancode == SDL_SCANCODE_RETURN ||
|
|
event.key.scancode == SDL_SCANCODE_KP_ENTER) {
|
|
processCommand();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ejecuta el comando introducido y reinicia la línea de input
|
|
void Console::processCommand() {
|
|
if (!input_line_.empty()) {
|
|
msg_line_ = "OK";
|
|
}
|
|
input_line_.clear();
|
|
cursor_timer_ = 0.0F;
|
|
cursor_visible_ = true;
|
|
}
|
|
|
|
// Indica si la consola está activa (visible o en animación)
|
|
auto Console::isActive() -> bool {
|
|
return status_ != Status::HIDDEN;
|
|
}
|
|
|
|
// Devuelve los píxeles visibles de la consola (sincronizado con la animación)
|
|
auto Console::getVisibleHeight() -> int {
|
|
if (status_ == Status::HIDDEN) { return 0; }
|
|
return static_cast<int>(y_ + height_);
|
|
}
|