reestructuració
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
// IWYU pragma: no_include <bits/std_abs.h>
|
||||
#include "path_sprite.hpp"
|
||||
|
||||
#include <cmath> // Para abs
|
||||
#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{.x = static_cast<float>(value), .y = fixed_pos});
|
||||
break;
|
||||
case PathType::VERTICAL:
|
||||
v.emplace_back(SDL_FPoint{.x = fixed_pos, .y = 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();
|
||||
}
|
||||
}
|
||||
|
||||
// Determina el tipo de centrado basado en el tipo de path
|
||||
auto PathSprite::determineCenteringType(const Path& path, bool centered) -> PathCentered {
|
||||
if (!centered) {
|
||||
return PathCentered::NONE;
|
||||
}
|
||||
|
||||
if (path.is_point_path) {
|
||||
// Lógica de centrado para paths por PUNTOS
|
||||
if (!path.spots.empty()) {
|
||||
// Si X es constante, es un path Vertical, centramos en X
|
||||
return (path.spots.back().x == path.spots.front().x) ? PathCentered::ON_X : PathCentered::ON_Y;
|
||||
}
|
||||
return PathCentered::NONE;
|
||||
}
|
||||
|
||||
// Lógica de centrado para paths GENERADOS
|
||||
// Si el tipo es Vertical, centramos en X
|
||||
return (path.type == PathType::VERTICAL) ? PathCentered::ON_X : PathCentered::ON_Y;
|
||||
}
|
||||
|
||||
// Aplica centrado en el eje X (para paths verticales)
|
||||
void PathSprite::centerPathOnX(Path& path, float offset) {
|
||||
if (path.is_point_path) {
|
||||
const float X_BASE = !path.spots.empty() ? path.spots.front().x : 0.0F;
|
||||
const float X = X_BASE - 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 -= offset;
|
||||
}
|
||||
}
|
||||
|
||||
// Aplica centrado en el eje Y (para paths horizontales)
|
||||
void PathSprite::centerPathOnY(Path& path, float offset) {
|
||||
if (path.is_point_path) {
|
||||
const float Y_BASE = !path.spots.empty() ? path.spots.front().y : 0.0F;
|
||||
const float Y = Y_BASE - 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 -= offset;
|
||||
}
|
||||
}
|
||||
|
||||
// Añade un recorrido
|
||||
void PathSprite::addPath(Path path, bool centered) {
|
||||
PathCentered path_centered = determineCenteringType(path, centered);
|
||||
|
||||
switch (path_centered) {
|
||||
case PathCentered::ON_X:
|
||||
centerPathOnX(path, pos_.w / 2.0F);
|
||||
break;
|
||||
case PathCentered::ON_Y:
|
||||
centerPathOnY(path, pos_.h / 2.0F);
|
||||
break;
|
||||
case PathCentered::NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
paths_.emplace_back(std::move(path));
|
||||
}
|
||||
|
||||
// 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 = {.x = path.start_pos, .y = path.fixed_pos};
|
||||
} else {
|
||||
initial_pos = {.x = path.fixed_pos, .y = 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 (std::cmp_greater_equal(path.counter, 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 = {.x = current_pos, .y = path.fixed_pos};
|
||||
} else {
|
||||
position = {.x = path.fixed_pos, .y = 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 (std::cmp_greater_equal(current_path_, paths_.size())) {
|
||||
has_finished_ = true;
|
||||
current_path_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Indica si ha terminado todos los recorridos
|
||||
auto PathSprite::hasFinished() const -> bool { return has_finished_; }
|
||||
Reference in New Issue
Block a user