Extra2D/Tests/test_action.cpp

623 lines
16 KiB
C++
Raw Normal View History

/**
* @file test_action.cpp
* @brief Action
*
*
*/
#include "test_framework.h"
#include <extra2d/act/act.h>
#include <extra2d/act/act_instant.h>
#include <extra2d/act/act_move.h>
#include <extra2d/act/act_rotate.h>
#include <extra2d/act/act_scale.h>
#include <extra2d/act/act_fade.h>
#include <extra2d/act/act_composite.h>
#include <extra2d/node/node.h>
#include <extra2d/core/math_extended.h>
#include <cmath>
using namespace extra2d;
using namespace extra2d::test;
namespace {
constexpr f32 EPSILON = 0.001f;
bool vec2Equal(const Vec2& a, const Vec2& b, f32 eps = EPSILON) {
return std::abs(a.x - b.x) < eps && std::abs(a.y - b.y) < eps;
}
}
// ---------------------------------------------------------------------------
// Act 基础类测试
// ---------------------------------------------------------------------------
TEST(Act, Tag) {
auto node = ptr::make<Node>();
class TestAct : public Act {
public:
bool done() const override { return true; }
void update(f32 t) override {}
Act* clone() const override { return new TestAct(); }
Act* reverse() const override { return new TestAct(); }
};
TestAct act;
TEST_ASSERT_EQ(-1, act.tag());
act.tag(42);
TEST_ASSERT_EQ(42, act.tag());
}
// ---------------------------------------------------------------------------
// ActInstant 测试
// ---------------------------------------------------------------------------
TEST(ActInstant, Done) {
CallFunc act([](){});
TEST_ASSERT_TRUE(act.done());
}
TEST(CallFunc, Execute) {
auto node = ptr::make<Node>();
bool called = false;
CallFunc act([&called](){ called = true; });
act.start(node.get());
act.step(0.016f);
TEST_ASSERT_TRUE(called);
}
TEST(Place, SetPosition) {
auto node = ptr::make<Node>();
node->setPos(0, 0);
Place act(Vec2(100, 200));
act.start(node.get());
act.step(0.016f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(100, 200)));
}
TEST(Show, SetVisible) {
auto node = ptr::make<Node>();
node->setVisible(false);
Show act;
act.start(node.get());
act.step(0.016f);
TEST_ASSERT_TRUE(node->visible());
}
TEST(Hide, SetInvisible) {
auto node = ptr::make<Node>();
node->setVisible(true);
Hide act;
act.start(node.get());
act.step(0.016f);
TEST_ASSERT_FALSE(node->visible());
}
// ---------------------------------------------------------------------------
// ActInterval 基础测试
// ---------------------------------------------------------------------------
TEST(ActInterval, Duration) {
MoveTo act(2.0f, Vec2(100, 100));
TEST_ASSERT_TRUE(std::abs(act.dur() - 2.0f) < EPSILON);
TEST_ASSERT_FALSE(act.done());
}
TEST(ActInterval, Elapsed) {
MoveTo act(1.0f, Vec2(100, 100));
TEST_ASSERT_TRUE(std::abs(act.elap()) < EPSILON);
act.step(0.5f);
TEST_ASSERT_TRUE(std::abs(act.elap() - 0.5f) < EPSILON);
}
TEST(ActInterval, Done) {
MoveTo act(1.0f, Vec2(100, 100));
TEST_ASSERT_FALSE(act.done());
act.step(1.0f);
TEST_ASSERT_TRUE(act.done());
act.step(0.5f);
TEST_ASSERT_TRUE(act.done());
}
// ---------------------------------------------------------------------------
// MoveTo/MoveBy 测试
// ---------------------------------------------------------------------------
TEST(MoveTo, MoveToPosition) {
auto node = ptr::make<Node>();
node->setPos(0, 0);
MoveTo act(1.0f, Vec2(100, 200));
act.start(node.get());
act.update(0.0f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(0, 0)));
act.update(0.5f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(50, 100)));
act.update(1.0f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(100, 200)));
}
TEST(MoveBy, MoveByOffset) {
auto node = ptr::make<Node>();
node->setPos(50, 50);
MoveBy act(1.0f, Vec2(100, 100));
act.start(node.get());
act.update(0.0f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(50, 50)));
act.update(1.0f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(150, 150)));
}
TEST(MoveTo, Clone) {
MoveTo act(2.0f, Vec2(100, 200));
act.tag(42);
Act* cloned = act.clone();
TEST_ASSERT_NOT_NULL(cloned);
TEST_ASSERT_EQ(42, cloned->tag());
MoveTo* clonedMove = dynamic_cast<MoveTo*>(cloned);
TEST_ASSERT_NOT_NULL(clonedMove);
delete cloned;
}
TEST(MoveBy, Reverse) {
MoveBy act(1.0f, Vec2(100, 100));
Act* reversed = act.reverse();
TEST_ASSERT_NOT_NULL(reversed);
MoveBy* reversedMove = dynamic_cast<MoveBy*>(reversed);
TEST_ASSERT_NOT_NULL(reversedMove);
delete reversed;
}
// ---------------------------------------------------------------------------
// RotTo/RotBy 测试
// ---------------------------------------------------------------------------
TEST(RotTo, RotateToAngle) {
auto node = ptr::make<Node>();
node->setRot(0);
RotTo act(1.0f, 90.0f);
act.start(node.get());
act.update(0.0f);
TEST_ASSERT_TRUE(std::abs(node->rot) < EPSILON);
act.update(0.5f);
TEST_ASSERT_TRUE(std::abs(node->rot - 45.0f) < EPSILON);
act.update(1.0f);
TEST_ASSERT_TRUE(std::abs(node->rot - 90.0f) < EPSILON);
}
TEST(RotBy, RotateByAngle) {
auto node = ptr::make<Node>();
node->setRot(45.0f);
RotBy act(1.0f, 90.0f);
act.start(node.get());
act.update(0.0f);
TEST_ASSERT_TRUE(std::abs(node->rot - 45.0f) < EPSILON);
act.update(1.0f);
TEST_ASSERT_TRUE(std::abs(node->rot - 135.0f) < EPSILON);
}
// ---------------------------------------------------------------------------
// ScaleTo/ScaleBy 测试
// ---------------------------------------------------------------------------
TEST(ScaleTo, ScaleToValue) {
auto node = ptr::make<Node>();
node->setScale(1.0f);
ScaleTo act(1.0f, 2.0f);
act.start(node.get());
act.update(0.0f);
TEST_ASSERT_TRUE(vec2Equal(node->scale, Vec2(1, 1)));
act.update(0.5f);
TEST_ASSERT_TRUE(vec2Equal(node->scale, Vec2(1.5f, 1.5f)));
act.update(1.0f);
TEST_ASSERT_TRUE(vec2Equal(node->scale, Vec2(2, 2)));
}
TEST(ScaleBy, ScaleByValue) {
auto node = ptr::make<Node>();
node->setScale(1.0f);
ScaleBy act(1.0f, 2.0f);
act.start(node.get());
act.update(1.0f);
TEST_ASSERT_TRUE(vec2Equal(node->scale, Vec2(2, 2)));
}
TEST(ScaleTo, ScaleXY) {
auto node = ptr::make<Node>();
node->setScale(1.0f);
ScaleTo act(1.0f, Vec2(2.0f, 3.0f));
act.start(node.get());
act.update(1.0f);
TEST_ASSERT_TRUE(vec2Equal(node->scale, Vec2(2, 3)));
}
// ---------------------------------------------------------------------------
// FadeTo/FadeIn/FadeOut 测试
// ---------------------------------------------------------------------------
TEST(FadeTo, FadeToOpacity) {
auto node = ptr::make<Node>();
FadeTo act(1.0f, 0.5f);
act.start(node.get());
act.update(0.0f);
act.update(1.0f);
}
TEST(FadeIn, FadeIn) {
auto node = ptr::make<Node>();
FadeIn act(1.0f);
act.start(node.get());
act.update(1.0f);
}
TEST(FadeOut, FadeOut) {
auto node = ptr::make<Node>();
FadeOut act(1.0f);
act.start(node.get());
act.update(1.0f);
}
// ---------------------------------------------------------------------------
// Easing 函数测试
// ---------------------------------------------------------------------------
TEST(Easing, Linear) {
TEST_ASSERT_TRUE(std::abs(ActInterval::easeLinear(0.0f) - 0.0f) < EPSILON);
TEST_ASSERT_TRUE(std::abs(ActInterval::easeLinear(0.5f) - 0.5f) < EPSILON);
TEST_ASSERT_TRUE(std::abs(ActInterval::easeLinear(1.0f) - 1.0f) < EPSILON);
}
TEST(Easing, EaseIn) {
TEST_ASSERT_TRUE(std::abs(ActInterval::easeIn(0.0f) - 0.0f) < EPSILON);
TEST_ASSERT_TRUE(std::abs(ActInterval::easeIn(0.5f) - 0.25f) < EPSILON);
TEST_ASSERT_TRUE(std::abs(ActInterval::easeIn(1.0f) - 1.0f) < EPSILON);
}
TEST(Easing, EaseOut) {
TEST_ASSERT_TRUE(std::abs(ActInterval::easeOut(0.0f) - 0.0f) < EPSILON);
TEST_ASSERT_TRUE(std::abs(ActInterval::easeOut(0.5f) - 0.75f) < EPSILON);
TEST_ASSERT_TRUE(std::abs(ActInterval::easeOut(1.0f) - 1.0f) < EPSILON);
}
TEST(Easing, EaseInOut) {
TEST_ASSERT_TRUE(std::abs(ActInterval::easeInOut(0.0f) - 0.0f) < EPSILON);
TEST_ASSERT_TRUE(std::abs(ActInterval::easeInOut(0.25f) - 0.125f) < EPSILON);
TEST_ASSERT_TRUE(std::abs(ActInterval::easeInOut(0.5f) - 0.5f) < EPSILON);
TEST_ASSERT_TRUE(std::abs(ActInterval::easeInOut(0.75f) - 0.875f) < EPSILON);
TEST_ASSERT_TRUE(std::abs(ActInterval::easeInOut(1.0f) - 1.0f) < EPSILON);
}
TEST(Easing, EaseBackIn) {
f32 result = ActInterval::easeBackIn(0.5f);
TEST_ASSERT_TRUE(result < 0.5f);
}
TEST(Easing, EaseBackOut) {
f32 result = ActInterval::easeBackOut(0.5f);
TEST_ASSERT_TRUE(result > 0.5f);
}
TEST(Easing, EaseBounceOut) {
TEST_ASSERT_TRUE(std::abs(ActInterval::easeBounceOut(0.0f) - 0.0f) < EPSILON);
TEST_ASSERT_TRUE(std::abs(ActInterval::easeBounceOut(1.0f) - 1.0f) < EPSILON);
}
TEST(Easing, EaseElasticOut) {
TEST_ASSERT_TRUE(std::abs(ActInterval::easeElasticOut(0.0f) - 0.0f) < EPSILON);
TEST_ASSERT_TRUE(std::abs(ActInterval::easeElasticOut(1.0f) - 1.0f) < EPSILON);
}
// ---------------------------------------------------------------------------
// Seq 序列动作测试
// ---------------------------------------------------------------------------
TEST(Seq, Sequence) {
auto node = ptr::make<Node>();
node->setPos(0, 0);
auto seq = Seq::create(
new MoveTo(0.5f, Vec2(100, 0)),
new MoveTo(0.5f, Vec2(100, 100))
);
seq->start(node.get());
seq->step(0.0f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(0, 0)));
seq->step(0.5f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(100, 0)));
seq->step(0.5f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(100, 100)));
TEST_ASSERT_TRUE(seq->done());
delete seq;
}
TEST(Seq, SingleAction) {
auto node = ptr::make<Node>();
node->setPos(0, 0);
auto seq = Seq::create(
new MoveTo(0.5f, Vec2(100, 0))
);
seq->start(node.get());
seq->step(0.5f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(100, 0)));
TEST_ASSERT_TRUE(seq->done());
delete seq;
}
// ---------------------------------------------------------------------------
// Spawn 并行动作测试
// ---------------------------------------------------------------------------
TEST(Spawn, Parallel) {
auto node = ptr::make<Node>();
node->setPos(0, 0);
node->setRot(0);
auto spawn = Spawn::create(
new MoveTo(1.0f, Vec2(100, 100)),
new RotTo(1.0f, 90.0f)
);
spawn->start(node.get());
spawn->step(0.5f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(50, 50)));
TEST_ASSERT_TRUE(std::abs(node->rot - 45.0f) < EPSILON);
spawn->step(0.5f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(100, 100)));
TEST_ASSERT_TRUE(std::abs(node->rot - 90.0f) < EPSILON);
TEST_ASSERT_TRUE(spawn->done());
delete spawn;
}
// ---------------------------------------------------------------------------
// Repeat 重复动作测试
// ---------------------------------------------------------------------------
TEST(Repeat, RepeatTimes) {
auto node = ptr::make<Node>();
node->setPos(0, 0);
auto repeat = new Repeat(new MoveBy(0.5f, Vec2(100, 0)), 3);
repeat->start(node.get());
for (int i = 0; i < 3; ++i) {
repeat->step(0.5f);
}
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(300, 0)));
TEST_ASSERT_TRUE(repeat->done());
delete repeat;
}
// ---------------------------------------------------------------------------
// RepeatForever 无限重复测试
// ---------------------------------------------------------------------------
TEST(RepeatForever, NeverDone) {
auto node = ptr::make<Node>();
node->setPos(0, 0);
auto repeat = new RepeatForever(new MoveBy(1.0f, Vec2(100, 0)));
repeat->start(node.get());
for (int i = 0; i < 10; ++i) {
repeat->step(1.0f);
TEST_ASSERT_FALSE(repeat->done());
}
TEST_ASSERT_TRUE(node->pos.x > 900);
delete repeat;
}
// ---------------------------------------------------------------------------
// Speed 速度控制测试
// ---------------------------------------------------------------------------
TEST(Speed, DoubleSpeed) {
auto node = ptr::make<Node>();
node->setPos(0, 0);
auto speed = new Speed(new MoveTo(2.0f, Vec2(100, 0)), 2.0f);
speed->start(node.get());
speed->step(0.5f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(50, 0)));
speed->step(0.5f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(100, 0)));
TEST_ASSERT_TRUE(speed->done());
delete speed;
}
TEST(Speed, HalfSpeed) {
auto node = ptr::make<Node>();
node->setPos(0, 0);
auto speed = new Speed(new MoveTo(1.0f, Vec2(100, 0)), 0.5f);
speed->start(node.get());
speed->step(1.0f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(50, 0)));
TEST_ASSERT_FALSE(speed->done());
speed->step(1.0f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(100, 0)));
TEST_ASSERT_TRUE(speed->done());
delete speed;
}
// ---------------------------------------------------------------------------
// Node 动作管理测试
// ---------------------------------------------------------------------------
TEST(Node, RunAction) {
auto node = ptr::make<Node>();
node->setPos(0, 0);
MoveTo* act = new MoveTo(1.0f, Vec2(100, 100));
Act* returned = node->run(act);
TEST_ASSERT_EQ(act, returned);
TEST_ASSERT_EQ(1, node->runningActs());
}
TEST(Node, StopAction) {
auto node = ptr::make<Node>();
node->setPos(0, 0);
MoveTo* act = new MoveTo(1.0f, Vec2(100, 100));
act->tag(42);
node->run(act);
node->stop(act);
TEST_ASSERT_EQ(0, node->runningActs());
}
TEST(Node, StopByTag) {
auto node = ptr::make<Node>();
MoveTo* act = new MoveTo(1.0f, Vec2(100, 100));
act->tag(42);
node->run(act);
node->stopByTag(42);
TEST_ASSERT_EQ(0, node->runningActs());
}
TEST(Node, StopAll) {
auto node = ptr::make<Node>();
node->run(new MoveTo(1.0f, Vec2(100, 0)));
node->run(new RotTo(1.0f, 90.0f));
node->run(new ScaleTo(1.0f, 2.0f));
TEST_ASSERT_EQ(3, node->runningActs());
node->stopAll();
TEST_ASSERT_EQ(0, node->runningActs());
}
TEST(Node, GetActByTag) {
auto node = ptr::make<Node>();
MoveTo* act = new MoveTo(1.0f, Vec2(100, 100));
act->tag(42);
node->run(act);
Act* found = node->getActByTag(42);
TEST_ASSERT_EQ(act, found);
Act* notFound = node->getActByTag(999);
TEST_ASSERT_NULL(notFound);
}
TEST(Node, UpdateActions) {
auto node = ptr::make<Node>();
node->setPos(0, 0);
node->run(new MoveTo(1.0f, Vec2(100, 0)));
node->updateActs(0.5f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(50, 0)));
node->updateActs(0.5f);
TEST_ASSERT_TRUE(vec2Equal(node->pos, Vec2(100, 0)));
}
// ---------------------------------------------------------------------------
// 自定义缓动测试
// ---------------------------------------------------------------------------
TEST(ActInterval, CustomEasing) {
auto node = ptr::make<Node>();
node->setPos(0, 0);
MoveTo act(1.0f, Vec2(100, 0));
act.ease([](f32 t) { return t * t * t; });
act.start(node.get());
act.step(0.5f);
TEST_ASSERT_TRUE(std::abs(node->pos.x - 12.5f) < EPSILON);
}