test(editor): verify physics play session runtime closure

This commit is contained in:
2026-04-15 17:51:22 +08:00
parent 308fbd0aac
commit 9654f4d91a
3 changed files with 69 additions and 0 deletions

View File

@@ -5,8 +5,12 @@
#include "Core/PlaySessionController.h"
#include "Commands/EntityCommands.h"
#include <XCEngine/Components/BoxColliderComponent.h>
#include <XCEngine/Components/RigidbodyComponent.h>
#include <XCEngine/Components/SphereColliderComponent.h>
#include <XCEngine/Core/Math/Vector3.h>
#include <XCEngine/Input/InputManager.h>
#include <XCEngine/Physics/PhysicsWorld.h>
namespace XCEngine::Editor {
namespace {
@@ -274,5 +278,68 @@ TEST_F(PlaySessionControllerTest, RuntimeSceneUndoRedoRebindsPlaySessionBeforeSt
EXPECT_EQ(m_context.GetSceneManager().GetEntity(runtimeEntityId), nullptr);
}
TEST_F(PlaySessionControllerTest, PlayModeCreatesRuntimePhysicsWorldAndRestoresEditorSnapshotAfterSimulation) {
if (!::XCEngine::Physics::PhysicsWorld::IsPhysXAvailable()) {
GTEST_SKIP() << "PhysX is not available in this configuration.";
}
auto* ground = m_context.GetSceneManager().CreateEntity("Ground");
ASSERT_NE(ground, nullptr);
ground->GetTransform()->SetLocalPosition(Math::Vector3(0.0f, -1.0f, 0.0f));
auto* groundCollider = ground->AddComponent<::XCEngine::Components::BoxColliderComponent>();
ASSERT_NE(groundCollider, nullptr);
groundCollider->SetSize(Math::Vector3(10.0f, 1.0f, 10.0f));
auto* ball = m_context.GetSceneManager().CreateEntity("Ball");
ASSERT_NE(ball, nullptr);
const uint64_t ballId = ball->GetID();
ball->GetTransform()->SetLocalPosition(Math::Vector3(0.0f, 5.0f, 0.0f));
auto* rigidbody = ball->AddComponent<::XCEngine::Components::RigidbodyComponent>();
ASSERT_NE(rigidbody, nullptr);
rigidbody->SetUseGravity(true);
rigidbody->SetLinearDamping(0.0f);
rigidbody->SetAngularDamping(0.0f);
auto* sphereCollider = ball->AddComponent<::XCEngine::Components::SphereColliderComponent>();
ASSERT_NE(sphereCollider, nullptr);
sphereCollider->SetRadius(0.5f);
const bool dirtyStateBeforePlay = m_context.GetSceneManager().IsSceneDirty();
ASSERT_TRUE(m_controller.StartPlay(m_context));
ASSERT_EQ(m_context.GetRuntimeMode(), EditorRuntimeMode::Play);
::XCEngine::Physics::PhysicsWorld* physicsWorld = m_controller.GetRuntimePhysicsWorld();
ASSERT_NE(physicsWorld, nullptr);
EXPECT_TRUE(physicsWorld->IsInitialized());
EXPECT_EQ(physicsWorld->GetTrackedRigidbodyCount(), 1u);
EXPECT_EQ(physicsWorld->GetTrackedColliderCount(), 2u);
auto* runtimeBall = m_context.GetSceneManager().GetEntity(ballId);
ASSERT_NE(runtimeBall, nullptr);
const float initialRuntimeY = runtimeBall->GetTransform()->GetLocalPosition().y;
for (int i = 0; i < 10; ++i) {
m_controller.Update(m_context, 0.05f);
}
runtimeBall = m_context.GetSceneManager().GetEntity(ballId);
ASSERT_NE(runtimeBall, nullptr);
const float simulatedRuntimeY = runtimeBall->GetTransform()->GetLocalPosition().y;
EXPECT_LT(simulatedRuntimeY, initialRuntimeY);
EXPECT_EQ(m_context.GetSceneManager().IsSceneDirty(), dirtyStateBeforePlay);
ASSERT_TRUE(m_controller.StopPlay(m_context));
EXPECT_EQ(m_context.GetRuntimeMode(), EditorRuntimeMode::Edit);
EXPECT_EQ(m_controller.GetRuntimePhysicsWorld(), nullptr);
EXPECT_EQ(m_context.GetSceneManager().IsSceneDirty(), dirtyStateBeforePlay);
auto* restoredBall = m_context.GetSceneManager().GetEntity(ballId);
ASSERT_NE(restoredBall, nullptr);
const Math::Vector3 restoredPosition = restoredBall->GetTransform()->GetLocalPosition();
EXPECT_NEAR(restoredPosition.x, 0.0f, 1e-4f);
EXPECT_NEAR(restoredPosition.y, 5.0f, 1e-4f);
EXPECT_NEAR(restoredPosition.z, 0.0f, 1e-4f);
}
} // namespace
} // namespace XCEngine::Editor