feat(act): 改进动作系统的更新逻辑和功能
- 重构动作序列(Seq)的step方法,支持更精确的时间分割处理 - 为Spawn和Repeat动作添加step方法实现 - 改进RepeatForever的step方法,防止无限循环 - 为MoveTo/MoveBy动作添加标签复制功能 - 在Node类中暴露comps_成员给SceneGraph访问 - 修复测试用例中的动作调用方式 - 添加Vec2的乘法运算符重载
This commit is contained in:
parent
d1d03520ff
commit
6396a0b5d5
|
|
@ -32,6 +32,8 @@ protected:
|
||||||
Node* target_ = nullptr;
|
Node* target_ = nullptr;
|
||||||
Node* origTarget_ = nullptr;
|
Node* origTarget_ = nullptr;
|
||||||
i32 tag_ = -1;
|
i32 tag_ = -1;
|
||||||
|
|
||||||
|
void copyTagTo(Act* other) const { other->tag_ = tag_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class ActInstant : public Act {
|
class ActInstant : public Act {
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ public:
|
||||||
|
|
||||||
void start(Node* t) override;
|
void start(Node* t) override;
|
||||||
void stop() override;
|
void stop() override;
|
||||||
|
void step(f32 dt) override;
|
||||||
void update(f32 t) override;
|
void update(f32 t) override;
|
||||||
Act* clone() const override;
|
Act* clone() const override;
|
||||||
Act* reverse() const override;
|
Act* reverse() const override;
|
||||||
|
|
@ -72,6 +73,7 @@ public:
|
||||||
bool done() const override;
|
bool done() const override;
|
||||||
void start(Node* t) override;
|
void start(Node* t) override;
|
||||||
void stop() override;
|
void stop() override;
|
||||||
|
void step(f32 dt) override;
|
||||||
void update(f32 t) override;
|
void update(f32 t) override;
|
||||||
Act* clone() const override;
|
Act* clone() const override;
|
||||||
Act* reverse() const override;
|
Act* reverse() const override;
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,16 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Act* clone() const override { return new MoveTo(dur_, end_); }
|
Act* clone() const override {
|
||||||
Act* reverse() const override { return new MoveTo(dur_, start_); }
|
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:
|
private:
|
||||||
Vec2 start_;
|
Vec2 start_;
|
||||||
|
|
@ -44,8 +52,16 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Act* clone() const override { return new MoveBy(dur_, dlt_); }
|
Act* clone() const override {
|
||||||
Act* reverse() const override { return new MoveBy(dur_, -dlt_); }
|
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:
|
private:
|
||||||
Vec2 dlt_;
|
Vec2 dlt_;
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ public:
|
||||||
|
|
||||||
void update(f32 t) override {
|
void update(f32 t) override {
|
||||||
if (target_) {
|
if (target_) {
|
||||||
target_->scale = start_ + dlt_ * t;
|
target_->scale = start_ * Vec2::lerp(Vec2(1, 1), dlt_, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ struct Vec2 {
|
||||||
Vec2 operator-(const Vec2 &v) const { return {x - v.x, y - v.y}; }
|
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/(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 { return {-x, -y}; }
|
||||||
|
|
||||||
Vec2 &operator+=(const Vec2 &v) {
|
Vec2 &operator+=(const Vec2 &v) {
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
class Node : public std::enable_shared_from_this<Node> {
|
class Node : public std::enable_shared_from_this<Node> {
|
||||||
|
friend class SceneGraph;
|
||||||
public:
|
public:
|
||||||
virtual ~Node();
|
virtual ~Node();
|
||||||
|
|
||||||
|
|
@ -150,8 +151,6 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual Vec2 defaultAnchor() const { return Vec2(0.5f, 0.5f); }
|
virtual Vec2 defaultAnchor() const { return Vec2(0.5f, 0.5f); }
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<Unique<Comp>> comps_;
|
std::vector<Unique<Comp>> comps_;
|
||||||
Node* parent_ = nullptr;
|
Node* parent_ = nullptr;
|
||||||
std::vector<Ref<Node>> children_;
|
std::vector<Ref<Node>> children_;
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ Seq* Seq::createFromArray(std::initializer_list<Act*> acts) {
|
||||||
void Seq::start(Node* t) {
|
void Seq::start(Node* t) {
|
||||||
ActInterval::start(t);
|
ActInterval::start(t);
|
||||||
curIdx_ = 0;
|
curIdx_ = 0;
|
||||||
|
split_ = 0.0f;
|
||||||
if (!acts_.empty()) {
|
if (!acts_.empty()) {
|
||||||
acts_[0]->start(t);
|
acts_[0]->start(t);
|
||||||
}
|
}
|
||||||
|
|
@ -56,22 +57,32 @@ void Seq::step(f32 dt) {
|
||||||
|
|
||||||
elap_ += dt;
|
elap_ += dt;
|
||||||
|
|
||||||
while (curIdx_ < acts_.size()) {
|
f32 remainingDt = dt;
|
||||||
|
|
||||||
|
while (curIdx_ < acts_.size() && remainingDt > 0) {
|
||||||
auto* cur = acts_[curIdx_];
|
auto* cur = acts_[curIdx_];
|
||||||
if (auto* interval = dynamic_cast<ActInterval*>(cur)) {
|
if (auto* interval = dynamic_cast<ActInterval*>(cur)) {
|
||||||
interval->step(dt);
|
f32 neededDt = interval->dur() - interval->elap();
|
||||||
if (!interval->done()) {
|
if (remainingDt >= neededDt) {
|
||||||
return;
|
interval->step(neededDt);
|
||||||
}
|
remainingDt -= neededDt;
|
||||||
cur->stop();
|
cur->stop();
|
||||||
} else {
|
|
||||||
cur->step(dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
curIdx_++;
|
curIdx_++;
|
||||||
if (curIdx_ < acts_.size()) {
|
if (curIdx_ < acts_.size()) {
|
||||||
acts_[curIdx_]->start(target_);
|
acts_[curIdx_]->start(target_);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
interval->step(remainingDt);
|
||||||
|
remainingDt = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cur->step(remainingDt);
|
||||||
|
remainingDt = 0;
|
||||||
|
curIdx_++;
|
||||||
|
if (curIdx_ < acts_.size()) {
|
||||||
|
acts_[curIdx_]->start(target_);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,6 +154,20 @@ void Spawn::stop() {
|
||||||
ActInterval::stop();
|
ActInterval::stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Spawn::step(f32 dt) {
|
||||||
|
elap_ += dt;
|
||||||
|
|
||||||
|
for (auto* a : acts_) {
|
||||||
|
if (auto* interval = dynamic_cast<ActInterval*>(a)) {
|
||||||
|
if (!interval->done()) {
|
||||||
|
interval->step(dt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
a->step(dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Spawn::update(f32 t) {
|
void Spawn::update(f32 t) {
|
||||||
for (auto* a : acts_) {
|
for (auto* a : acts_) {
|
||||||
if (auto* interval = dynamic_cast<ActInterval*>(a)) {
|
if (auto* interval = dynamic_cast<ActInterval*>(a)) {
|
||||||
|
|
@ -211,6 +236,27 @@ void Repeat::stop() {
|
||||||
ActInterval::stop();
|
ActInterval::stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Repeat::step(f32 dt) {
|
||||||
|
if (!inner_) {
|
||||||
|
elap_ = dur_;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
elap_ += dt;
|
||||||
|
|
||||||
|
if (auto* interval = dynamic_cast<ActInterval*>(inner_)) {
|
||||||
|
interval->step(dt);
|
||||||
|
|
||||||
|
if (interval->done()) {
|
||||||
|
cnt_++;
|
||||||
|
if (!done()) {
|
||||||
|
inner_->stop();
|
||||||
|
inner_->start(target_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Repeat::update(f32 t) {
|
void Repeat::update(f32 t) {
|
||||||
if (!inner_) return;
|
if (!inner_) return;
|
||||||
|
|
||||||
|
|
@ -250,18 +296,31 @@ void RepeatForever::start(Node* t) {
|
||||||
void RepeatForever::step(f32 dt) {
|
void RepeatForever::step(f32 dt) {
|
||||||
if (!inner_) return;
|
if (!inner_) return;
|
||||||
|
|
||||||
elap_ += dt;
|
|
||||||
|
|
||||||
if (dur_ > 0) {
|
if (dur_ > 0) {
|
||||||
while (elap_ >= dur_) {
|
f32 remainingDt = dt;
|
||||||
elap_ -= dur_;
|
int maxIterations = 100;
|
||||||
|
int iterations = 0;
|
||||||
|
|
||||||
|
while (remainingDt > 0.0001f && iterations < maxIterations) {
|
||||||
|
iterations++;
|
||||||
|
if (auto* interval = dynamic_cast<ActInterval*>(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_->stop();
|
||||||
inner_->start(target_);
|
inner_->start(target_);
|
||||||
|
} else {
|
||||||
|
interval->step(remainingDt);
|
||||||
|
remainingDt = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inner_->step(remainingDt);
|
||||||
|
remainingDt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto* interval = dynamic_cast<ActInterval*>(inner_)) {
|
|
||||||
f32 t = elap_ / dur_;
|
|
||||||
interval->update(interval->easeTime(t));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,7 @@ Mat3 Node::local() const {
|
||||||
Mat3 m(1.0f);
|
Mat3 m(1.0f);
|
||||||
|
|
||||||
m = glm::translate(m, pos.toGlm());
|
m = glm::translate(m, pos.toGlm());
|
||||||
|
m = glm::rotate(m, rot * DEG_TO_RAD);
|
||||||
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::scale(m, scale.toGlm());
|
m = glm::scale(m, scale.toGlm());
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ void SceneGraph::traverseRecursive(Node* node, const std::function<void(Node*)>&
|
||||||
void SceneGraph::update(f32 dt) {
|
void SceneGraph::update(f32 dt) {
|
||||||
traverse([dt](Node* node) {
|
traverse([dt](Node* node) {
|
||||||
node->onUpdate(dt);
|
node->onUpdate(dt);
|
||||||
|
node->updateActs(dt);
|
||||||
node->updateComps(dt);
|
node->updateComps(dt);
|
||||||
node->lateUpdateComps(dt);
|
node->lateUpdateComps(dt);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -378,13 +378,13 @@ TEST(Seq, Sequence) {
|
||||||
|
|
||||||
seq->start(node.get());
|
seq->start(node.get());
|
||||||
|
|
||||||
seq->update(0.0f);
|
seq->step(0.0f);
|
||||||
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(0, 0)));
|
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)));
|
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(vec2Equal(node->pos, Vec2(100, 100)));
|
||||||
|
|
||||||
TEST_ASSERT_TRUE(seq->done());
|
TEST_ASSERT_TRUE(seq->done());
|
||||||
|
|
@ -402,7 +402,7 @@ TEST(Seq, SingleAction) {
|
||||||
|
|
||||||
seq->start(node.get());
|
seq->start(node.get());
|
||||||
|
|
||||||
seq->update(0.5f);
|
seq->step(0.5f);
|
||||||
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(100, 0)));
|
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(100, 0)));
|
||||||
|
|
||||||
TEST_ASSERT_TRUE(seq->done());
|
TEST_ASSERT_TRUE(seq->done());
|
||||||
|
|
@ -426,11 +426,11 @@ TEST(Spawn, Parallel) {
|
||||||
|
|
||||||
spawn->start(node.get());
|
spawn->start(node.get());
|
||||||
|
|
||||||
spawn->update(0.5f);
|
spawn->step(0.5f);
|
||||||
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(50, 50)));
|
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(50, 50)));
|
||||||
TEST_ASSERT_TRUE(std::abs(node->rot - 45.0f) < EPSILON);
|
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(vec2Equal(node->pos, Vec2(100, 100)));
|
||||||
TEST_ASSERT_TRUE(std::abs(node->rot - 90.0f) < EPSILON);
|
TEST_ASSERT_TRUE(std::abs(node->rot - 90.0f) < EPSILON);
|
||||||
|
|
||||||
|
|
@ -452,7 +452,7 @@ TEST(Repeat, RepeatTimes) {
|
||||||
repeat->start(node.get());
|
repeat->start(node.get());
|
||||||
|
|
||||||
for (int i = 0; i < 3; ++i) {
|
for (int i = 0; i < 3; ++i) {
|
||||||
repeat->update(0.5f);
|
repeat->step(0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(300, 0)));
|
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(300, 0)));
|
||||||
|
|
@ -474,7 +474,7 @@ TEST(RepeatForever, NeverDone) {
|
||||||
repeat->start(node.get());
|
repeat->start(node.get());
|
||||||
|
|
||||||
for (int i = 0; i < 10; ++i) {
|
for (int i = 0; i < 10; ++i) {
|
||||||
repeat->update(1.0f);
|
repeat->step(1.0f);
|
||||||
TEST_ASSERT_FALSE(repeat->done());
|
TEST_ASSERT_FALSE(repeat->done());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -617,6 +617,6 @@ TEST(ActInterval, CustomEasing) {
|
||||||
act.ease([](f32 t) { return t * t * t; });
|
act.ease([](f32 t) { return t * t * t; });
|
||||||
act.start(node.get());
|
act.start(node.get());
|
||||||
|
|
||||||
act.update(0.5f);
|
act.step(0.5f);
|
||||||
TEST_ASSERT_TRUE(std::abs(node->pos.x - 12.5f) < EPSILON);
|
TEST_ASSERT_TRUE(std::abs(node->pos.x - 12.5f) < EPSILON);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -267,13 +267,22 @@ TEST(Director, MultipleSceneSwitches) {
|
||||||
scene1->setName("Scene1");
|
scene1->setName("Scene1");
|
||||||
director.run(scene1);
|
director.run(scene1);
|
||||||
|
|
||||||
|
std::vector<Ref<TestScene>> scenes;
|
||||||
|
scenes.push_back(scene1);
|
||||||
|
|
||||||
for (int i = 0; i < 5; ++i) {
|
for (int i = 0; i < 5; ++i) {
|
||||||
auto newScene = ptr::make<TestScene>();
|
auto newScene = ptr::make<TestScene>();
|
||||||
newScene->setName("Scene" + std::to_string(i + 2));
|
newScene->setName("Scene" + std::to_string(i + 2));
|
||||||
director.replace(newScene);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -294,6 +294,10 @@ public:
|
||||||
|
|
||||||
int value;
|
int value;
|
||||||
|
|
||||||
|
void onInit() override {
|
||||||
|
anchor = defaultAnchor();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Vec2 defaultAnchor() const override { return Vec2(0.0f, 0.0f); }
|
Vec2 defaultAnchor() const override { return Vec2(0.0f, 0.0f); }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue