Files
coffee_crisis_arcade_edition/source/path_sprite.cpp

223 lines
7.6 KiB
C++

// IWYU pragma: no_include <bits/std_abs.h>
#include "path_sprite.h"
#include <functional> // Para function
#include <utility> // Para move
// Constructor para paths por puntos (convertido a segundos)
Path::Path(const std::vector<SDL_FPoint> &spots_init, float waiting_time_s_init)
: spots(spots_init), is_point_path(true) {
waiting_time_s = waiting_time_s_init;
}
// Devuelve un vector con los puntos que conforman la ruta
auto createPath(float start, float end, PathType type, float fixed_pos, int steps, const std::function<double(double)> &easing_function) -> std::vector<SDL_FPoint> {
std::vector<SDL_FPoint> v;
v.reserve(steps);
for (int i = 0; i < steps; ++i) {
double t = static_cast<double>(i) / (steps - 1);
double value = start + ((end - start) * easing_function(t));
if ((start > 0 && end < 0) || (start < 0 && end > 0)) {
value = start + (end > 0 ? 1 : -1) * std::abs(end - start) * easing_function(t);
}
switch (type) {
case PathType::HORIZONTAL:
v.emplace_back(SDL_FPoint{static_cast<float>(value), fixed_pos});
break;
case PathType::VERTICAL:
v.emplace_back(SDL_FPoint{fixed_pos, static_cast<float>(value)});
break;
default:
break;
}
}
return v;
}
// Actualiza la posición y comprueba si ha llegado a su destino
void PathSprite::update(float delta_time) {
if (enabled_ && !has_finished_) {
moveThroughCurrentPath(delta_time);
goToNextPathOrDie();
}
}
// Muestra el sprite por pantalla
void PathSprite::render() {
if (enabled_) {
Sprite::render();
}
}
// Añade un recorrido
void PathSprite::addPath(Path path, bool centered) {
PathCentered path_centered = PathCentered::NONE;
if (centered) {
if (path.is_point_path) {
// Lógica de centrado para paths por PUNTOS (como antes)
if (!path.spots.empty()) {
// Si X es constante, es un path Vertical, centramos en X
path_centered = (path.spots.back().x == path.spots.front().x) ? PathCentered::ON_X : PathCentered::ON_Y;
}
} else {
// Lógica de centrado para paths GENERADOS (por duración)
// Si el tipo es Vertical, centramos en X
path_centered = (path.type == PathType::VERTICAL) ? PathCentered::ON_X : PathCentered::ON_Y;
}
}
switch (path_centered) {
case PathCentered::ON_X: {
// Centrar en el eje X (para paths Verticales)
const float X_offset = pos_.w / 2.0f; // Asume que pos_.w está inicializado por el constructor de Sprite
if (path.is_point_path) {
const float X_base = !path.spots.empty() ? path.spots.front().x : 0.0f;
const float X = X_base - X_offset;
for (auto &spot : path.spots) {
spot.x = X;
}
} else {
// Es un path generado, ajustamos la posición fija (que es X)
path.fixed_pos -= X_offset;
}
paths_.emplace_back(std::move(path)); // Usamos std::move
break;
}
case PathCentered::ON_Y: {
// Centrar en el eje Y (para paths Horizontales)
const float Y_offset = pos_.h / 2.0f; // Asume que pos_.h está inicializado
if (path.is_point_path) {
const float Y_base = !path.spots.empty() ? path.spots.front().y : 0.0f;
const float Y = Y_base - Y_offset;
for (auto &spot : path.spots) {
spot.y = Y;
}
} else {
// Es un path generado, ajustamos la posición fija (que es Y)
path.fixed_pos -= Y_offset;
}
paths_.emplace_back(std::move(path)); // Usamos std::move
break;
}
default:
// Sin centrado
paths_.emplace_back(std::move(path)); // Usamos std::move
break;
}
}
// Añade un recorrido generado (en segundos)
void PathSprite::addPath(float start, float end, PathType type, float fixed_pos, float duration_s, const std::function<double(double)> &easing_function, float waiting_time_s) {
paths_.emplace_back(start, end, type, fixed_pos, duration_s, waiting_time_s, easing_function);
}
// Añade un recorrido por puntos (en segundos)
void PathSprite::addPath(const std::vector<SDL_FPoint> &spots, float waiting_time_s) {
paths_.emplace_back(spots, waiting_time_s);
}
// Habilita el objeto
void PathSprite::enable() {
if (paths_.empty() || enabled_) {
return;
}
enabled_ = true;
// Establece la posición inicial
auto &path = paths_.at(current_path_);
if (path.is_point_path) {
const auto &p = path.spots.at(path.counter);
setPosition(p);
} else {
// Para paths generados, establecer posición inicial
SDL_FPoint initial_pos;
if (path.type == PathType::HORIZONTAL) {
initial_pos = {path.start_pos, path.fixed_pos};
} else {
initial_pos = {path.fixed_pos, path.start_pos};
}
setPosition(initial_pos);
}
}
// Coloca el sprite en los diferentes puntos del recorrido
void PathSprite::moveThroughCurrentPath(float delta_time) {
auto &path = paths_.at(current_path_);
if (path.is_point_path) {
// Lógica para paths por puntos (compatibilidad)
const auto &p = path.spots.at(path.counter);
setPosition(p);
if (!path.on_destination) {
++path.counter;
if (path.counter >= static_cast<int>(path.spots.size())) {
path.on_destination = true;
path.counter = static_cast<int>(path.spots.size()) - 1;
}
}
if (path.on_destination) {
path.waiting_elapsed += delta_time;
if (path.waiting_elapsed >= path.waiting_time_s) {
path.finished = true;
}
}
} else {
// Lógica para paths generados en tiempo real
if (!path.on_destination) {
path.elapsed_time += delta_time;
// Calcular progreso (0.0 a 1.0)
float progress = path.elapsed_time / path.duration_s;
if (progress >= 1.0f) {
progress = 1.0f;
path.on_destination = true;
}
// Aplicar función de easing
double eased_progress = path.easing_function(progress);
// Calcular posición actual
float current_pos = path.start_pos + (path.end_pos - path.start_pos) * static_cast<float>(eased_progress);
// Establecer posición según el tipo
SDL_FPoint position;
if (path.type == PathType::HORIZONTAL) {
position = {current_pos, path.fixed_pos};
} else {
position = {path.fixed_pos, current_pos};
}
setPosition(position);
} else {
// Esperar en destino
path.waiting_elapsed += delta_time;
if (path.waiting_elapsed >= path.waiting_time_s) {
path.finished = true;
}
}
}
}
// Cambia de recorrido o finaliza
void PathSprite::goToNextPathOrDie() {
// Comprueba si ha terminado el recorrdo actual
if (paths_.at(current_path_).finished) {
++current_path_;
}
// Comprueba si quedan mas recorridos
if (current_path_ >= static_cast<int>(paths_.size())) {
has_finished_ = true;
current_path_ = 0;
}
}
// Indica si ha terminado todos los recorridos
auto PathSprite::hasFinished() const -> bool { return has_finished_; }