Separating state out of the location

This commit is contained in:
Vladislav Khorev committed 2026-10-30 14:56:24 +06:00
1 parent 5e9a663812
commit 297bd7377f
45 files changed
+2114 -778

No files matched your search

+181
View File
@@ -0,0 +1,181 @@
#include "InteractiveObjectState.h"
#include <algorithm>
#include <utility>
namespace FRG {
void InteractiveObjectState::moveTo(
const Eigen::Vector3f& target, float durationSec, std::string onCompleteName)
{
if (isAnimating) return;
AnimTask task;
task.type = AnimTask::Type::Move;
task.startPos = position;
task.startRotY = rotationY;
task.startScale = scale;
task.targetPos = target;
task.targetRotY = rotationY;
task.targetScale = scale;
task.durationMs = durationSec * 1000.f;
task.onCompleteName = std::move(onCompleteName);
animTask = std::move(task);
isAnimating = true;
}
void InteractiveObjectState::rotateTo(
float targetRotY, float durationSec, std::string onCompleteName)
{
if (isAnimating) return;
AnimTask task;
task.type = AnimTask::Type::Rotate;
task.startPos = position;
task.startRotY = rotationY;
task.startScale = scale;
task.targetPos = position;
task.targetRotY = targetRotY;
task.targetScale = scale;
task.durationMs = durationSec * 1000.f;
task.onCompleteName = std::move(onCompleteName);
animTask = std::move(task);
isAnimating = true;
}
void InteractiveObjectState::scaleTo(
float targetScale, float durationSec, std::string onCompleteName)
{
if (isAnimating) return;
AnimTask task;
task.type = AnimTask::Type::Scale;
task.startPos = position;
task.startRotY = rotationY;
task.startScale = scale;
task.targetPos = position;
task.targetRotY = rotationY;
task.targetScale = targetScale;
task.durationMs = durationSec * 1000.f;
task.onCompleteName = std::move(onCompleteName);
animTask = std::move(task);
isAnimating = true;
}
void InteractiveObjectState::fadeTo(
float targetAlpha, float durationSec, std::string onCompleteName)
{
if (isAnimating) return;
AnimTask task;
task.type = AnimTask::Type::Fade;
task.startPos = position;
task.startRotY = rotationY;
task.startScale = alpha;
task.targetPos = position;
task.targetRotY = rotationY;
task.targetScale = targetAlpha;
task.durationMs = durationSec * 1000.f;
task.onCompleteName = std::move(onCompleteName);
animTask = std::move(task);
isAnimating = true;
}
InteractiveObjectUpdateEvents InteractiveObjectState::update(std::int64_t deltaMs)
{
InteractiveObjectUpdateEvents events;
if (!isAnimating || !animTask) return events;
AnimTask& task = *animTask;
task.elapsedMs += static_cast<float>(deltaMs);
const float duration = (std::max)(task.durationMs, 0.001f);
const float t = (std::min)(task.elapsedMs / duration, 1.0f);
switch (task.type) {
case AnimTask::Type::Move:
position = task.startPos + (task.targetPos - task.startPos) * t;
break;
case AnimTask::Type::Rotate:
rotationY = task.startRotY + (task.targetRotY - task.startRotY) * t;
break;
case AnimTask::Type::Scale:
scale = task.startScale + (task.targetScale - task.startScale) * t;
break;
case AnimTask::Type::Fade:
alpha = task.startScale + (task.targetScale - task.startScale) * t;
break;
}
if (t < 1.0f) return events;
position = task.targetPos;
rotationY = task.targetRotY;
if (task.type == AnimTask::Type::Fade)
alpha = task.targetScale;
else
scale = task.targetScale;
events.onCompleteName = std::move(task.onCompleteName);
animTask.reset();
isAnimating = false;
return events;
}
void InteractiveObjectState::save(nlohmann::json& out) const
{
out["positionX"] = position.x();
out["positionY"] = position.y();
out["positionZ"] = position.z();
out["rotationY"] = rotationY;
out["scale"] = scale;
out["alpha"] = alpha;
out["isActive"] = isActive;
out["isAnimating"] = isAnimating;
if (isAnimating && animTask) {
out["animTask"] = {
{"type", static_cast<int>(animTask->type)},
{"startPosX", animTask->startPos.x()},
{"startPosY", animTask->startPos.y()},
{"startPosZ", animTask->startPos.z()},
{"startRotY", animTask->startRotY},
{"startScale", animTask->startScale},
{"targetPosX", animTask->targetPos.x()},
{"targetPosY", animTask->targetPos.y()},
{"targetPosZ", animTask->targetPos.z()},
{"targetRotY", animTask->targetRotY},
{"targetScale", animTask->targetScale},
{"durationMs", animTask->durationMs},
{"elapsedMs", animTask->elapsedMs},
{"onCompleteName", animTask->onCompleteName}};
}
}
void InteractiveObjectState::load(const nlohmann::json& in)
{
position.x() = in.value("positionX", position.x());
position.y() = in.value("positionY", position.y());
position.z() = in.value("positionZ", position.z());
rotationY = in.value("rotationY", rotationY);
scale = in.value("scale", scale);
alpha = in.value("alpha", alpha);
isActive = in.value("isActive", isActive);
isAnimating = in.value("isAnimating", false);
animTask.reset();
if (!isAnimating || !in.contains("animTask") ||
!in["animTask"].is_object()) {
return;
}
const auto& value = in["animTask"];
AnimTask task;
task.type = static_cast<AnimTask::Type>(value.value("type", 0));
task.startPos = {value.value("startPosX", 0.f),
value.value("startPosY", 0.f), value.value("startPosZ", 0.f)};
task.startRotY = value.value("startRotY", 0.f);
task.startScale = value.value("startScale", 1.f);
task.targetPos = {value.value("targetPosX", 0.f),
value.value("targetPosY", 0.f), value.value("targetPosZ", 0.f)};
task.targetRotY = value.value("targetRotY", 0.f);
task.targetScale = value.value("targetScale", 1.f);
task.durationMs = value.value("durationMs", 1000.f);
task.elapsedMs = value.value("elapsedMs", 0.f);
task.onCompleteName =
value.value("onCompleteName", std::string());
animTask = std::move(task);
}
} // namespace FRG