226 lines
6.7 KiB
C++
226 lines
6.7 KiB
C++
#include "game/entities/moving_platform.hpp"
|
|
|
|
#include <cmath> // Para std::sqrt
|
|
#include <cstdlib> // Para rand
|
|
|
|
#include "core/rendering/sprite/animated_sprite.hpp" // Para AnimatedSprite
|
|
#include "core/resources/resource_cache.hpp" // Para Resource
|
|
#include "utils/easing_functions.hpp" // Para Easing::*
|
|
|
|
// Resuelve el nombre de un easing a su función
|
|
auto MovingPlatform::resolveEasing(const std::string& name) -> EasingFunc {
|
|
if (name == "quadIn") { return Easing::quadIn; }
|
|
if (name == "quadOut") { return Easing::quadOut; }
|
|
if (name == "quadInOut") { return Easing::quadInOut; }
|
|
if (name == "cubicIn") { return Easing::cubicIn; }
|
|
if (name == "cubicOut") { return Easing::cubicOut; }
|
|
if (name == "cubicInOut") { return Easing::cubicInOut; }
|
|
if (name == "sineIn") { return Easing::sineIn; }
|
|
if (name == "sineOut") { return Easing::sineOut; }
|
|
if (name == "sineInOut") { return Easing::sineInOut; }
|
|
return Easing::linear;
|
|
}
|
|
|
|
// Constructor
|
|
MovingPlatform::MovingPlatform(const Data& data)
|
|
: sprite_(std::make_shared<AnimatedSprite>(Resource::Cache::get()->getAnimationData(data.animation_path))),
|
|
path_(data.path),
|
|
speed_(data.speed),
|
|
loop_mode_(data.loop),
|
|
easing_(resolveEasing(data.easing)) {
|
|
// Flags del SolidActor: jump-through desde abajo, carry al Player encima.
|
|
// NOTA: sin BLOCKS_PLAYER, las plataformas móviles no bloquean lateralmente
|
|
// ni por arriba. ONEWAY_TOP hace que los sweeps verticales solo las vean
|
|
// al caer desde arriba.
|
|
flags_ = CARRY_ON_TOP | ONEWAY_TOP;
|
|
|
|
// Colocar el sprite en el primer waypoint
|
|
if (!path_.empty()) {
|
|
sprite_->setPosX(path_[0].x);
|
|
sprite_->setPosY(path_[0].y);
|
|
}
|
|
|
|
aabb_ = getRect();
|
|
|
|
// Frame inicial
|
|
sprite_->setCurrentAnimationFrame((data.frame == -1) ? (rand() % sprite_->getCurrentAnimationSize()) : data.frame);
|
|
|
|
// Calcular longitud del primer segmento
|
|
recalcSegmentLength();
|
|
}
|
|
|
|
// Índice del waypoint origen del segmento actual
|
|
auto MovingPlatform::getSegmentFrom() const -> int {
|
|
if (direction_ == 1) {
|
|
return current_segment_;
|
|
}
|
|
// Pingpong retrocediendo: segmento N va de path[N+1] a path[N]
|
|
return current_segment_ + 1;
|
|
}
|
|
|
|
// Índice del waypoint destino del segmento actual
|
|
auto MovingPlatform::getSegmentTo() const -> int {
|
|
if (direction_ == 1) {
|
|
if (loop_mode_ == LoopMode::CIRCULAR) {
|
|
return (current_segment_ + 1) % static_cast<int>(path_.size());
|
|
}
|
|
return current_segment_ + 1;
|
|
}
|
|
// Pingpong retrocediendo
|
|
return current_segment_;
|
|
}
|
|
|
|
// Recalcula la longitud del segmento actual
|
|
void MovingPlatform::recalcSegmentLength() {
|
|
if (path_.size() < 2) {
|
|
segment_length_ = 0.0F;
|
|
return;
|
|
}
|
|
|
|
int from = getSegmentFrom();
|
|
int to = getSegmentTo();
|
|
|
|
float dx = path_[to].x - path_[from].x;
|
|
float dy = path_[to].y - path_[from].y;
|
|
segment_length_ = std::sqrt((dx * dx) + (dy * dy));
|
|
}
|
|
|
|
// Avanza al siguiente segmento
|
|
void MovingPlatform::advanceSegment() {
|
|
int path_size = static_cast<int>(path_.size());
|
|
|
|
if (loop_mode_ == LoopMode::PINGPONG) {
|
|
if (direction_ == 1) {
|
|
if (current_segment_ + 1 >= path_size - 1) {
|
|
// Llegamos al final, invertir dirección
|
|
direction_ = -1;
|
|
current_segment_ = path_size - 2;
|
|
} else {
|
|
current_segment_++;
|
|
}
|
|
} else {
|
|
if (current_segment_ <= 0) {
|
|
// Llegamos al inicio, invertir dirección
|
|
direction_ = 1;
|
|
current_segment_ = 0;
|
|
} else {
|
|
current_segment_--;
|
|
}
|
|
}
|
|
} else {
|
|
// CIRCULAR
|
|
current_segment_ = (current_segment_ + 1) % path_size;
|
|
}
|
|
|
|
segment_progress_ = 0.0F;
|
|
recalcSegmentLength();
|
|
}
|
|
|
|
// Actualiza posición de la plataforma siguiendo la ruta
|
|
void MovingPlatform::update(float delta_time) {
|
|
sprite_->animate(delta_time);
|
|
|
|
if (path_.size() < 2) {
|
|
last_delta_.x = 0.0F;
|
|
last_delta_.y = 0.0F;
|
|
return;
|
|
}
|
|
|
|
float old_x = sprite_->getPosX();
|
|
float old_y = sprite_->getPosY();
|
|
|
|
// Si estamos esperando en un waypoint
|
|
if (waiting_) {
|
|
wait_timer_ -= delta_time;
|
|
if (wait_timer_ <= 0.0F) {
|
|
waiting_ = false;
|
|
advanceSegment();
|
|
} else {
|
|
last_delta_.x = 0.0F;
|
|
last_delta_.y = 0.0F;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Avanzar por el segmento
|
|
if (segment_length_ > 0.0F) {
|
|
float distance = speed_ * delta_time;
|
|
float delta_progress = distance / segment_length_;
|
|
segment_progress_ += delta_progress;
|
|
} else {
|
|
// Segmento de longitud 0: saltar al siguiente
|
|
segment_progress_ = 1.0F;
|
|
}
|
|
|
|
// Comprobar si llegamos al final del segmento
|
|
if (segment_progress_ >= 1.0F) {
|
|
segment_progress_ = 1.0F;
|
|
|
|
// Colocar en el waypoint destino exacto
|
|
int to = getSegmentTo();
|
|
sprite_->setPosX(path_[to].x);
|
|
sprite_->setPosY(path_[to].y);
|
|
|
|
// Comprobar si hay espera en este waypoint
|
|
if (path_[to].wait > 0.0F) {
|
|
waiting_ = true;
|
|
wait_timer_ = path_[to].wait;
|
|
} else {
|
|
advanceSegment();
|
|
}
|
|
} else {
|
|
// Interpolar posición con easing
|
|
float t = easing_(segment_progress_);
|
|
int from = getSegmentFrom();
|
|
int to = getSegmentTo();
|
|
|
|
float new_x = path_[from].x + ((path_[to].x - path_[from].x) * t);
|
|
float new_y = path_[from].y + ((path_[to].y - path_[from].y) * t);
|
|
sprite_->setPosX(new_x);
|
|
sprite_->setPosY(new_y);
|
|
}
|
|
|
|
last_delta_.x = sprite_->getPosX() - old_x;
|
|
last_delta_.y = sprite_->getPosY() - old_y;
|
|
aabb_ = getRect();
|
|
}
|
|
|
|
// Pinta la plataforma en pantalla
|
|
void MovingPlatform::render() {
|
|
sprite_->render();
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
// Solo actualiza la animación sin mover la plataforma
|
|
void MovingPlatform::updateAnimation(float delta_time) {
|
|
sprite_->animate(delta_time);
|
|
}
|
|
|
|
// Resetea la plataforma a su posición inicial (para editor)
|
|
void MovingPlatform::resetToInitialPosition(const Data& data) {
|
|
path_ = data.path;
|
|
speed_ = data.speed;
|
|
loop_mode_ = data.loop;
|
|
easing_ = resolveEasing(data.easing);
|
|
|
|
current_segment_ = 0;
|
|
direction_ = 1;
|
|
segment_progress_ = 0.0F;
|
|
waiting_ = false;
|
|
wait_timer_ = 0.0F;
|
|
|
|
if (!path_.empty()) {
|
|
sprite_->setPosX(path_[0].x);
|
|
sprite_->setPosY(path_[0].y);
|
|
}
|
|
|
|
aabb_ = getRect();
|
|
recalcSegmentLength();
|
|
}
|
|
#endif
|
|
|
|
// Devuelve el rectangulo que contiene a la plataforma
|
|
auto MovingPlatform::getRect() -> SDL_FRect {
|
|
return sprite_->getRect();
|
|
}
|