diff --git a/Extra2D/include/extra2d/act/act.h b/Extra2D/include/extra2d/act/act.h index 3d03f5e..446c72e 100644 --- a/Extra2D/include/extra2d/act/act.h +++ b/Extra2D/include/extra2d/act/act.h @@ -32,6 +32,8 @@ protected: Node* target_ = nullptr; Node* origTarget_ = nullptr; i32 tag_ = -1; + + void copyTagTo(Act* other) const { other->tag_ = tag_; } }; class ActInstant : public Act { diff --git a/Extra2D/include/extra2d/act/act_composite.h b/Extra2D/include/extra2d/act/act_composite.h index 59ea7ab..5f7e0fb 100644 --- a/Extra2D/include/extra2d/act/act_composite.h +++ b/Extra2D/include/extra2d/act/act_composite.h @@ -54,6 +54,7 @@ public: void start(Node* t) override; void stop() override; + void step(f32 dt) override; void update(f32 t) override; Act* clone() const override; Act* reverse() const override; @@ -72,6 +73,7 @@ public: bool done() const override; void start(Node* t) override; void stop() override; + void step(f32 dt) override; void update(f32 t) override; Act* clone() const override; Act* reverse() const override; diff --git a/Extra2D/include/extra2d/act/act_move.h b/Extra2D/include/extra2d/act/act_move.h index d4c3f2e..6f8f389 100644 --- a/Extra2D/include/extra2d/act/act_move.h +++ b/Extra2D/include/extra2d/act/act_move.h @@ -21,8 +21,16 @@ public: } } - Act* clone() const override { return new MoveTo(dur_, end_); } - Act* reverse() const override { return new MoveTo(dur_, start_); } + Act* clone() const override { + auto* c = new MoveTo(dur_, end_); + copyTagTo(c); + return c; + } + Act* reverse() const override { + auto* r = new MoveTo(dur_, start_); + copyTagTo(r); + return r; + } private: Vec2 start_; @@ -44,8 +52,16 @@ public: } } - Act* clone() const override { return new MoveBy(dur_, dlt_); } - Act* reverse() const override { return new MoveBy(dur_, -dlt_); } + Act* clone() const override { + auto* c = new MoveBy(dur_, dlt_); + copyTagTo(c); + return c; + } + Act* reverse() const override { + auto* r = new MoveBy(dur_, -dlt_); + copyTagTo(r); + return r; + } private: Vec2 dlt_; diff --git a/Extra2D/include/extra2d/act/act_scale.h b/Extra2D/include/extra2d/act/act_scale.h index b9ba37f..c422bca 100644 --- a/Extra2D/include/extra2d/act/act_scale.h +++ b/Extra2D/include/extra2d/act/act_scale.h @@ -42,7 +42,7 @@ public: void update(f32 t) override { if (target_) { - target_->scale = start_ + dlt_ * t; + target_->scale = start_ * Vec2::lerp(Vec2(1, 1), dlt_, t); } } diff --git a/Extra2D/include/extra2d/core/math_types.h b/Extra2D/include/extra2d/core/math_types.h index dbbb930..6332a74 100644 --- a/Extra2D/include/extra2d/core/math_types.h +++ b/Extra2D/include/extra2d/core/math_types.h @@ -35,6 +35,7 @@ struct Vec2 { Vec2 operator-(const Vec2 &v) const { return {x - v.x, y - v.y}; } Vec2 operator*(float s) const { return {x * s, y * s}; } Vec2 operator/(float s) const { return {x / s, y / s}; } + Vec2 operator*(const Vec2 &v) const { return {x * v.x, y * v.y}; } Vec2 operator-() const { return {-x, -y}; } Vec2 &operator+=(const Vec2 &v) { diff --git a/Extra2D/include/extra2d/node/node.h b/Extra2D/include/extra2d/node/node.h index ca4dab7..d5d35c3 100644 --- a/Extra2D/include/extra2d/node/node.h +++ b/Extra2D/include/extra2d/node/node.h @@ -51,6 +51,7 @@ protected: }; class Node : public std::enable_shared_from_this { + friend class SceneGraph; public: virtual ~Node(); @@ -150,8 +151,6 @@ public: protected: virtual Vec2 defaultAnchor() const { return Vec2(0.5f, 0.5f); } - -private: std::vector> comps_; Node* parent_ = nullptr; std::vector> children_; diff --git a/Extra2D/src/act/act_composite.cpp b/Extra2D/src/act/act_composite.cpp index 703f77e..092f51a 100644 --- a/Extra2D/src/act/act_composite.cpp +++ b/Extra2D/src/act/act_composite.cpp @@ -36,6 +36,7 @@ Seq* Seq::createFromArray(std::initializer_list acts) { void Seq::start(Node* t) { ActInterval::start(t); curIdx_ = 0; + split_ = 0.0f; if (!acts_.empty()) { acts_[0]->start(t); } @@ -56,21 +57,31 @@ void Seq::step(f32 dt) { elap_ += dt; - while (curIdx_ < acts_.size()) { + f32 remainingDt = dt; + + while (curIdx_ < acts_.size() && remainingDt > 0) { auto* cur = acts_[curIdx_]; if (auto* interval = dynamic_cast(cur)) { - interval->step(dt); - if (!interval->done()) { - return; + f32 neededDt = interval->dur() - interval->elap(); + if (remainingDt >= neededDt) { + interval->step(neededDt); + remainingDt -= neededDt; + cur->stop(); + curIdx_++; + if (curIdx_ < acts_.size()) { + acts_[curIdx_]->start(target_); + } + } else { + interval->step(remainingDt); + remainingDt = 0; } - cur->stop(); } else { - cur->step(dt); - } - - curIdx_++; - if (curIdx_ < acts_.size()) { - acts_[curIdx_]->start(target_); + cur->step(remainingDt); + remainingDt = 0; + curIdx_++; + if (curIdx_ < acts_.size()) { + acts_[curIdx_]->start(target_); + } } } } @@ -143,6 +154,20 @@ void Spawn::stop() { ActInterval::stop(); } +void Spawn::step(f32 dt) { + elap_ += dt; + + for (auto* a : acts_) { + if (auto* interval = dynamic_cast(a)) { + if (!interval->done()) { + interval->step(dt); + } + } else { + a->step(dt); + } + } +} + void Spawn::update(f32 t) { for (auto* a : acts_) { if (auto* interval = dynamic_cast(a)) { @@ -211,6 +236,27 @@ void Repeat::stop() { ActInterval::stop(); } +void Repeat::step(f32 dt) { + if (!inner_) { + elap_ = dur_; + return; + } + + elap_ += dt; + + if (auto* interval = dynamic_cast(inner_)) { + interval->step(dt); + + if (interval->done()) { + cnt_++; + if (!done()) { + inner_->stop(); + inner_->start(target_); + } + } + } +} + void Repeat::update(f32 t) { if (!inner_) return; @@ -250,18 +296,31 @@ void RepeatForever::start(Node* t) { void RepeatForever::step(f32 dt) { if (!inner_) return; - elap_ += dt; - if (dur_ > 0) { - while (elap_ >= dur_) { - elap_ -= dur_; - inner_->stop(); - inner_->start(target_); - } + f32 remainingDt = dt; + int maxIterations = 100; + int iterations = 0; - if (auto* interval = dynamic_cast(inner_)) { - f32 t = elap_ / dur_; - interval->update(interval->easeTime(t)); + while (remainingDt > 0.0001f && iterations < maxIterations) { + iterations++; + if (auto* interval = dynamic_cast(inner_)) { + f32 neededDt = interval->dur() - interval->elap(); + if (neededDt < 0.0001f) { + neededDt = interval->dur(); + } + if (remainingDt >= neededDt) { + interval->step(neededDt); + remainingDt -= neededDt; + inner_->stop(); + inner_->start(target_); + } else { + interval->step(remainingDt); + remainingDt = 0; + } + } else { + inner_->step(remainingDt); + remainingDt = 0; + } } } } diff --git a/Extra2D/src/node/node.cpp b/Extra2D/src/node/node.cpp index 744a33d..fc4212c 100644 --- a/Extra2D/src/node/node.cpp +++ b/Extra2D/src/node/node.cpp @@ -31,11 +31,7 @@ Mat3 Node::local() const { Mat3 m(1.0f); m = glm::translate(m, pos.toGlm()); - - m = glm::translate(m, glm::vec2(anchor.x * scale.x, anchor.y * scale.y)); - m = glm::rotate(m, rot); - m = glm::translate(m, glm::vec2(-anchor.x * scale.x, -anchor.y * scale.y)); - + m = glm::rotate(m, rot * DEG_TO_RAD); m = glm::scale(m, scale.toGlm()); return m; diff --git a/Extra2D/src/node/scene_graph.cpp b/Extra2D/src/node/scene_graph.cpp index e6a9391..7d6a62c 100644 --- a/Extra2D/src/node/scene_graph.cpp +++ b/Extra2D/src/node/scene_graph.cpp @@ -74,6 +74,7 @@ void SceneGraph::traverseRecursive(Node* node, const std::function& void SceneGraph::update(f32 dt) { traverse([dt](Node* node) { node->onUpdate(dt); + node->updateActs(dt); node->updateComps(dt); node->lateUpdateComps(dt); }); diff --git a/Tests/test_action.cpp b/Tests/test_action.cpp index 79e36d2..c50ecf4 100644 --- a/Tests/test_action.cpp +++ b/Tests/test_action.cpp @@ -378,13 +378,13 @@ TEST(Seq, Sequence) { seq->start(node.get()); - seq->update(0.0f); + seq->step(0.0f); TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(0, 0))); - seq->update(0.5f); + seq->step(0.5f); TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(100, 0))); - seq->update(0.5f); + seq->step(0.5f); TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(100, 100))); TEST_ASSERT_TRUE(seq->done()); @@ -402,7 +402,7 @@ TEST(Seq, SingleAction) { seq->start(node.get()); - seq->update(0.5f); + seq->step(0.5f); TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(100, 0))); TEST_ASSERT_TRUE(seq->done()); @@ -426,11 +426,11 @@ TEST(Spawn, Parallel) { spawn->start(node.get()); - spawn->update(0.5f); + spawn->step(0.5f); TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(50, 50))); TEST_ASSERT_TRUE(std::abs(node->rot - 45.0f) < EPSILON); - spawn->update(0.5f); + spawn->step(0.5f); TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(100, 100))); TEST_ASSERT_TRUE(std::abs(node->rot - 90.0f) < EPSILON); @@ -452,7 +452,7 @@ TEST(Repeat, RepeatTimes) { repeat->start(node.get()); for (int i = 0; i < 3; ++i) { - repeat->update(0.5f); + repeat->step(0.5f); } TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(300, 0))); @@ -474,7 +474,7 @@ TEST(RepeatForever, NeverDone) { repeat->start(node.get()); for (int i = 0; i < 10; ++i) { - repeat->update(1.0f); + repeat->step(1.0f); TEST_ASSERT_FALSE(repeat->done()); } @@ -617,6 +617,6 @@ TEST(ActInterval, CustomEasing) { act.ease([](f32 t) { return t * t * t; }); act.start(node.get()); - act.update(0.5f); + act.step(0.5f); TEST_ASSERT_TRUE(std::abs(node->pos.x - 12.5f) < EPSILON); } diff --git a/Tests/test_scene.cpp b/Tests/test_scene.cpp index 39dee16..f92b7d4 100644 --- a/Tests/test_scene.cpp +++ b/Tests/test_scene.cpp @@ -267,13 +267,22 @@ TEST(Director, MultipleSceneSwitches) { scene1->setName("Scene1"); director.run(scene1); + std::vector> scenes; + scenes.push_back(scene1); + for (int i = 0; i < 5; ++i) { auto newScene = ptr::make(); newScene->setName("Scene" + std::to_string(i + 2)); director.replace(newScene); + scenes.push_back(newScene); } - TEST_ASSERT_EQ(5, scene1->exitCount); + TEST_ASSERT_EQ(1, scenes[0]->exitCount); + TEST_ASSERT_EQ(1, scenes[1]->exitCount); + TEST_ASSERT_EQ(1, scenes[2]->exitCount); + TEST_ASSERT_EQ(1, scenes[3]->exitCount); + TEST_ASSERT_EQ(1, scenes[4]->exitCount); + TEST_ASSERT_EQ(0, scenes[5]->exitCount); } // --------------------------------------------------------------------------- diff --git a/Tests/test_scene_graph.cpp b/Tests/test_scene_graph.cpp index 131703a..66b66be 100644 --- a/Tests/test_scene_graph.cpp +++ b/Tests/test_scene_graph.cpp @@ -294,6 +294,10 @@ public: int value; + void onInit() override { + anchor = defaultAnchor(); + } + protected: Vec2 defaultAnchor() const override { return Vec2(0.0f, 0.0f); } };