add support for joystick time based dependents

# Description
fix for joystick controlled timelines not updating the time

# Details
If a state machine has a timeline controlling a nested remapped animation through keyframes,
and that timeline is itself controlled by a joystick
our update cycle would not apply the time updated by the joystick because the advance cycle has passed.
This PR looks for joystick controlled animations, and stores which objects are nested remapped animations to advance them while they are being applied.

Diffs=
038bd34aee add support for joystick time based dependents (#9272)

Co-authored-by: hernan <hernan@rive.app>
This commit is contained in:
bodymovin
2025-04-07 16:49:09 +00:00
parent da39c5608d
commit 141d621786
6 changed files with 62 additions and 1 deletions

View File

@@ -1 +1 @@
a70f0f84dda65ddd956b1229b9530aed37f44b18
038bd34aee08546d1395c93c9696d273488ff586

View File

@@ -3,6 +3,7 @@
#include "rive/generated/joystick_base.hpp"
#include "rive/intrinsically_sizeable.hpp"
#include "rive/joystick_flags.hpp"
#include "rive/animation/nested_remap_animation.hpp"
#include "rive/math/mat2d.hpp"
#include <stdio.h>
@@ -32,6 +33,8 @@ public:
bool canApplyBeforeUpdate() const { return m_handleSource == nullptr; }
void addDependents(Artboard* artboard);
Vec2D measureLayout(float width,
LayoutMeasureMode widthMode,
float height,
@@ -51,6 +54,9 @@ private:
LinearAnimation* m_xAnimation = nullptr;
LinearAnimation* m_yAnimation = nullptr;
TransformComponent* m_handleSource = nullptr;
std::vector<NestedRemapAnimation*> m_dependents;
void addAnimationDependents(Artboard* artboard, LinearAnimation* animation);
};
} // namespace rive

View File

@@ -252,6 +252,7 @@ StatusCode Artboard::initialize()
{
m_JoysticksApplyBeforeUpdate = false;
}
joystick->addDependents(this);
m_Joysticks.push_back(joystick);
break;
}

View File

@@ -1,6 +1,7 @@
#include "rive/joystick.hpp"
#include "rive/artboard.hpp"
#include "rive/transform_component.hpp"
#include "rive/animation/keyed_object.hpp"
using namespace rive;
@@ -95,6 +96,10 @@ void Joystick::apply(Artboard* artboard) const
((isJoystickFlagged(JoystickFlags::invertY) ? -y() : y()) + 1.0f) /
2.0f * m_yAnimation->durationSeconds());
}
for (const auto& nestedRemapAnimation : m_dependents)
{
nestedRemapAnimation->advance(0, false);
}
}
Vec2D Joystick::measureLayout(float width,
@@ -134,4 +139,32 @@ void Joystick::widthChanged()
void Joystick::heightChanged()
{
artboard()->addDirt(ComponentDirt::Components);
}
void Joystick::addAnimationDependents(Artboard* artboard,
LinearAnimation* animation)
{
auto totalObjects = animation->numKeyedObjects();
for (int i = 0; i < totalObjects; i++)
{
auto object = animation->getObject(i);
auto coreObject = artboard->resolve(object->objectId());
if (coreObject != nullptr && coreObject->is<NestedRemapAnimation>())
{
m_dependents.push_back(coreObject->as<NestedRemapAnimation>());
}
}
}
void Joystick::addDependents(Artboard* artboard)
{
if (m_yAnimation != nullptr)
{
addAnimationDependents(artboard, m_yAnimation);
}
if (m_xAnimation != nullptr)
{
addAnimationDependents(artboard, m_xAnimation);
}
}

Binary file not shown.

View File

@@ -68,4 +68,25 @@ TEST_CASE("nested artboards with one shot animations will not main "
REQUIRE(stateMachine->advanceAndApply(0.1f) == true);
// animation has ended and no events to report
REQUIRE(stateMachine->advanceAndApply(0.1f) == false);
}
TEST_CASE(
"nested artboard remapped timelines controlled by a timeline controlled "
"itself by a joystick correctly apply the time after the joystick ran",
"[nested]")
{
auto file = ReadRiveFile("assets/joystick_nested_remap.riv");
auto artboard = file->artboard("parent")->instance();
artboard->advance(0.0f);
auto stateMachine = artboard->stateMachineAt(0);
REQUIRE(artboard->find<rive::NestedArtboard>("child") != nullptr);
auto child = artboard->find<rive::NestedArtboard>("child");
auto nestedArtboardArtboard = child->artboardInstance();
REQUIRE(nestedArtboardArtboard != nullptr);
auto rect = nestedArtboardArtboard->find<rive::Shape>("rect");
REQUIRE(rect != nullptr);
REQUIRE(rect->x() == 250.0f);
}