Skip to content

Actions

The action system provides simple time-based tweens. Actions run through ActionRunner, which is automatically added to a node when you call runAction(). You can attach per-frame callbacks with Action::onUpdate().

using namespace snowpulse;

auto* node = scene()->createNode("runner");
scene()->rootNode()->addChild(node);
auto action = Actions::moveX(120.0f, 0.4f);
action->onUpdate([](Node* owner, float dt) {
    (void)owner;
    (void)dt;
});
node->runAction(std::move(action));

Easing functions are provided by EaseType.

runAction() transfers ownership to the node's ActionRunner. Its returned Action* is a non-owning, short-lived handle: it becomes invalid as soon as the action completes or the runner is cleared. Register onUpdate() and onComplete() before transferring the action when possible. onUpdate() also runs on the final update, and onComplete() runs during completion before the action is removed.

Call node->stopAllActions() to clear active and pending actions; cleared actions do not invoke onComplete(). Pointer-based actions such as valueTo() and colorTo() do not own their destination, so that storage must remain valid until the action finishes or is stopped.

Move Actions

moveTo tweens all axes, while moveX/Y/Z target a single axis.

using namespace snowpulse;

auto* node = scene()->createNode("moving_item");
scene()->rootNode()->addChild(node);
node->runAction(Actions::moveTo({ 200.0f, 100.0f, 0.0f }, 0.5f, EaseType::OutCubic));
node->runAction(Actions::moveX(120.0f, 0.25f, EaseType::OutQuad));
node->runAction(Actions::moveY(-80.0f, 0.2f));
node->runAction(Actions::moveZ(40.0f, 0.3f));

Rotate Actions

using namespace snowpulse;

auto* node = scene()->createNode("spinner");
scene()->rootNode()->addChild(node);
node->runAction(Actions::rotateTo({ 0.0f, 0.0f, 180.0f }, 0.6f, EaseType::OutBack));
node->runAction(Actions::rotateX(15.0f, 0.2f));
node->runAction(Actions::rotateY(25.0f, 0.2f));
node->runAction(Actions::rotateZ(360.0f, 1.0f, EaseType::Linear));

Scale Actions

using namespace snowpulse;

auto* node = scene()->createNode("pulse");
scene()->rootNode()->addChild(node);
node->runAction(Actions::scaleTo({ 1.5f, 1.5f, 1.0f }, 0.3f, EaseType::OutBack));
node->runAction(Actions::scaleX(2.0f, 0.2f));
node->runAction(Actions::scaleY(0.5f, 0.2f));
node->runAction(Actions::scaleZ(1.2f, 0.2f));

Color Actions

using namespace snowpulse;

auto* node = scene()->createNode("sprite");
scene()->rootNode()->addChild(node);
auto* sprite = node->addComponent<SpriteRenderer>();
sprite->color = { 1.0f, 1.0f, 1.0f, 1.0f };

node->runAction(Actions::colorTo(&sprite->color, { 1.0f, 0.4f, 0.4f, 1.0f }, 0.4f, EaseType::OutQuad));
node->runAction(Actions::colorChannel(&sprite->color, ColorChannel::A, 0.2f, 0.3f));

Value Actions

Keep tweened values in storage that outlives the action, such as members of an attached component:

class AnimatedValues final : public snowpulse::Script {
public:
    void onStart() override {
        owner()->runAction(snowpulse::Actions::valueTo(
            &_level, 1.0f, 0.6f, snowpulse::EaseType::OutCubic));
        owner()->runAction(snowpulse::Actions::valueTo(
            &_offset, { 12.0f, -8.0f, 0.0f }, 0.4f,
            snowpulse::EaseType::OutQuad));
    }

private:
    float _level = 0.0f;
    glm::vec3 _offset { 0.0f, 0.0f, 0.0f };
};

auto* node = scene()->createNode("animated_values");
node->addComponent<AnimatedValues>();
scene()->rootNode()->addChild(node);

Delay Action

using namespace snowpulse;

auto* node = scene()->createNode("delayed");
scene()->rootNode()->addChild(node);

auto delay = Actions::delay(0.4f);
delay->onComplete([]() {
    // Continue after the delay.
});
node->runAction(std::move(delay));

Sequence Action

using namespace snowpulse;

auto* node = scene()->createNode("combo");
scene()->rootNode()->addChild(node);

auto seq = Actions::sequence();
seq->add(Actions::moveY(80.0f, 0.25f, EaseType::OutQuad));
seq->add(Actions::delay(0.1f));
seq->add(Actions::scaleTo({ 1.2f, 1.2f, 1.0f }, 0.2f, EaseType::OutBack),
         []() { printf("Scale done!\n"); });
node->runAction(std::move(seq));

Parallel Action

ParallelAction completes when its first (anchor) action finishes. Any other actions that are still running are deferred back to the node's ActionRunner to finish independently.

using namespace snowpulse;

auto* node = scene()->createNode("combo");
scene()->rootNode()->addChild(node);

auto par = Actions::parallel();
par->add(Actions::moveX(140.0f, 0.3f, EaseType::OutCubic));  // anchor
par->add(Actions::scaleTo({ 1.4f, 1.4f, 1.0f }, 0.6f, EaseType::OutBack));
par->add(Actions::rotateZ(180.0f, 0.6f, EaseType::OutQuad));
node->runAction(std::move(par));