156 lines
4.1 KiB
C++
156 lines
4.1 KiB
C++
#include <gtest/gtest.h>
|
|
|
|
#include <XCEngine/Components/Component.h>
|
|
#include <XCEngine/Components/GameObject.h>
|
|
#include <XCEngine/Scene/RuntimeLoop.h>
|
|
#include <XCEngine/Scene/Scene.h>
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
using namespace XCEngine::Components;
|
|
|
|
namespace {
|
|
|
|
struct RuntimeLoopCounters {
|
|
int startCount = 0;
|
|
int fixedUpdateCount = 0;
|
|
int updateCount = 0;
|
|
int lateUpdateCount = 0;
|
|
};
|
|
|
|
class RuntimeLoopObserverComponent : public Component {
|
|
public:
|
|
explicit RuntimeLoopObserverComponent(RuntimeLoopCounters* counters)
|
|
: m_counters(counters) {
|
|
}
|
|
|
|
std::string GetName() const override {
|
|
return "RuntimeLoopObserver";
|
|
}
|
|
|
|
void Start() override {
|
|
if (m_counters) {
|
|
++m_counters->startCount;
|
|
}
|
|
}
|
|
|
|
void FixedUpdate() override {
|
|
if (m_counters) {
|
|
++m_counters->fixedUpdateCount;
|
|
}
|
|
}
|
|
|
|
void Update(float deltaTime) override {
|
|
(void)deltaTime;
|
|
if (m_counters) {
|
|
++m_counters->updateCount;
|
|
}
|
|
}
|
|
|
|
void LateUpdate(float deltaTime) override {
|
|
(void)deltaTime;
|
|
if (m_counters) {
|
|
++m_counters->lateUpdateCount;
|
|
}
|
|
}
|
|
|
|
private:
|
|
RuntimeLoopCounters* m_counters = nullptr;
|
|
};
|
|
|
|
class RuntimeLoopTest : public ::testing::Test {
|
|
protected:
|
|
Scene* CreateScene(const std::string& name = "RuntimeLoopScene") {
|
|
m_scene = std::make_unique<Scene>(name);
|
|
return m_scene.get();
|
|
}
|
|
|
|
RuntimeLoopCounters counters;
|
|
std::unique_ptr<Scene> m_scene;
|
|
};
|
|
|
|
TEST_F(RuntimeLoopTest, AccumulatesFixedUpdatesAcrossFramesAndRunsVariableUpdatesEveryTick) {
|
|
RuntimeLoop loop({0.02f, 0.1f, 4});
|
|
Scene* scene = CreateScene();
|
|
GameObject* host = scene->CreateGameObject("Host");
|
|
host->AddComponent<RuntimeLoopObserverComponent>(&counters);
|
|
|
|
loop.Start(scene);
|
|
|
|
loop.Tick(0.01f);
|
|
EXPECT_EQ(counters.fixedUpdateCount, 0);
|
|
EXPECT_EQ(counters.startCount, 1);
|
|
EXPECT_EQ(counters.updateCount, 1);
|
|
EXPECT_EQ(counters.lateUpdateCount, 1);
|
|
|
|
loop.Tick(0.01f);
|
|
EXPECT_EQ(counters.fixedUpdateCount, 1);
|
|
EXPECT_EQ(counters.startCount, 1);
|
|
EXPECT_EQ(counters.updateCount, 2);
|
|
EXPECT_EQ(counters.lateUpdateCount, 2);
|
|
}
|
|
|
|
TEST_F(RuntimeLoopTest, ClampAndFixedStepLimitPreventExcessiveCatchUp) {
|
|
RuntimeLoop loop({0.02f, 0.05f, 2});
|
|
Scene* scene = CreateScene();
|
|
GameObject* host = scene->CreateGameObject("Host");
|
|
host->AddComponent<RuntimeLoopObserverComponent>(&counters);
|
|
|
|
loop.Start(scene);
|
|
loop.Tick(1.0f);
|
|
|
|
EXPECT_EQ(counters.fixedUpdateCount, 2);
|
|
EXPECT_EQ(counters.startCount, 1);
|
|
EXPECT_EQ(counters.updateCount, 1);
|
|
EXPECT_EQ(counters.lateUpdateCount, 1);
|
|
EXPECT_NEAR(loop.GetFixedAccumulator(), 0.01f, 1e-4f);
|
|
}
|
|
|
|
TEST_F(RuntimeLoopTest, PauseSkipsAutomaticTicksUntilStepFrameIsRequested) {
|
|
RuntimeLoop loop({0.02f, 0.1f, 4});
|
|
Scene* scene = CreateScene();
|
|
GameObject* host = scene->CreateGameObject("Host");
|
|
host->AddComponent<RuntimeLoopObserverComponent>(&counters);
|
|
|
|
loop.Start(scene);
|
|
loop.Pause();
|
|
|
|
loop.Tick(0.025f);
|
|
EXPECT_EQ(counters.fixedUpdateCount, 0);
|
|
EXPECT_EQ(counters.startCount, 0);
|
|
EXPECT_EQ(counters.updateCount, 0);
|
|
EXPECT_EQ(counters.lateUpdateCount, 0);
|
|
|
|
loop.StepFrame();
|
|
loop.Tick(0.025f);
|
|
EXPECT_EQ(counters.fixedUpdateCount, 1);
|
|
EXPECT_EQ(counters.startCount, 1);
|
|
EXPECT_EQ(counters.updateCount, 1);
|
|
EXPECT_EQ(counters.lateUpdateCount, 1);
|
|
EXPECT_TRUE(loop.IsPaused());
|
|
}
|
|
|
|
TEST_F(RuntimeLoopTest, ResumeRestoresAutomaticTickProgressionAfterPause) {
|
|
RuntimeLoop loop({0.02f, 0.1f, 4});
|
|
Scene* scene = CreateScene();
|
|
GameObject* host = scene->CreateGameObject("Host");
|
|
host->AddComponent<RuntimeLoopObserverComponent>(&counters);
|
|
|
|
loop.Start(scene);
|
|
loop.Pause();
|
|
loop.Tick(0.025f);
|
|
EXPECT_EQ(counters.updateCount, 0);
|
|
|
|
loop.Resume();
|
|
EXPECT_FALSE(loop.IsPaused());
|
|
loop.Tick(0.025f);
|
|
|
|
EXPECT_EQ(counters.startCount, 1);
|
|
EXPECT_EQ(counters.fixedUpdateCount, 1);
|
|
EXPECT_EQ(counters.updateCount, 1);
|
|
EXPECT_EQ(counters.lateUpdateCount, 1);
|
|
}
|
|
|
|
} // namespace
|