468 lines
17 KiB
C++
468 lines
17 KiB
C++
#include <gtest/gtest.h>
|
|
|
|
#include <XCEngine/Components/BoxColliderComponent.h>
|
|
#include <XCEngine/Components/CapsuleColliderComponent.h>
|
|
#include <XCEngine/Components/GameObject.h>
|
|
#include <XCEngine/Components/RigidbodyComponent.h>
|
|
#include <XCEngine/Components/SphereColliderComponent.h>
|
|
#include <XCEngine/Physics/PhysicsWorld.h>
|
|
#include <XCEngine/Scene/Scene.h>
|
|
|
|
namespace {
|
|
|
|
TEST(PhysicsWorld_Test, DefaultWorldStartsUninitialized) {
|
|
XCEngine::Physics::PhysicsWorld world;
|
|
|
|
EXPECT_FALSE(world.IsInitialized());
|
|
EXPECT_EQ(world.GetNativeActorCount(), 0u);
|
|
EXPECT_EQ(world.GetNativeShapeCount(), 0u);
|
|
}
|
|
|
|
TEST(PhysicsWorld_Test, InitializeStoresCreateInfoWithoutMarkingWorldReadyYet) {
|
|
XCEngine::Components::Scene scene("PhysicsScene");
|
|
XCEngine::Physics::PhysicsWorld world;
|
|
XCEngine::Physics::PhysicsWorldCreateInfo createInfo;
|
|
createInfo.scene = &scene;
|
|
createInfo.gravity = XCEngine::Math::Vector3(0.0f, -3.5f, 0.0f);
|
|
|
|
const bool expectedInitialized = XCEngine::Physics::PhysicsWorld::IsPhysXAvailable();
|
|
|
|
EXPECT_EQ(world.Initialize(createInfo), expectedInitialized);
|
|
EXPECT_EQ(world.IsInitialized(), expectedInitialized);
|
|
EXPECT_EQ(world.GetCreateInfo().scene, &scene);
|
|
EXPECT_EQ(world.GetCreateInfo().gravity, XCEngine::Math::Vector3(0.0f, -3.5f, 0.0f));
|
|
}
|
|
|
|
TEST(PhysicsWorld_Test, StepWithoutInitializationIsNoOp) {
|
|
XCEngine::Physics::PhysicsWorld world;
|
|
|
|
world.Step(0.016f);
|
|
|
|
EXPECT_FALSE(world.IsInitialized());
|
|
}
|
|
|
|
TEST(PhysicsWorld_Test, InitializeBuildsNativeActorsFromSceneComponents) {
|
|
using namespace XCEngine::Components;
|
|
|
|
Scene scene("PhysicsScene");
|
|
GameObject* ground = scene.CreateGameObject("Ground");
|
|
ground->AddComponent<BoxColliderComponent>();
|
|
|
|
GameObject* player = scene.CreateGameObject("Player");
|
|
player->AddComponent<RigidbodyComponent>();
|
|
player->AddComponent<SphereColliderComponent>();
|
|
|
|
GameObject* childTrigger = scene.CreateGameObject("ChildTrigger", player);
|
|
childTrigger->AddComponent<CapsuleColliderComponent>();
|
|
|
|
XCEngine::Physics::PhysicsWorld world;
|
|
XCEngine::Physics::PhysicsWorldCreateInfo createInfo = {};
|
|
createInfo.scene = &scene;
|
|
|
|
const bool expectedInitialized = XCEngine::Physics::PhysicsWorld::IsPhysXAvailable();
|
|
ASSERT_EQ(world.Initialize(createInfo), expectedInitialized);
|
|
EXPECT_EQ(world.GetTrackedRigidbodyCount(), 1u);
|
|
EXPECT_EQ(world.GetTrackedColliderCount(), 3u);
|
|
|
|
if (!expectedInitialized) {
|
|
EXPECT_EQ(world.GetNativeActorCount(), 0u);
|
|
EXPECT_EQ(world.GetNativeShapeCount(), 0u);
|
|
return;
|
|
}
|
|
|
|
EXPECT_EQ(world.GetNativeActorCount(), 2u);
|
|
EXPECT_EQ(world.GetNativeShapeCount(), 3u);
|
|
}
|
|
|
|
TEST(PhysicsWorld_Test, ComponentChangesRebuildNativeActorOwnership) {
|
|
using namespace XCEngine::Components;
|
|
|
|
Scene scene("PhysicsScene");
|
|
GameObject* player = scene.CreateGameObject("Player");
|
|
player->AddComponent<RigidbodyComponent>();
|
|
SphereColliderComponent* playerSphere = player->AddComponent<SphereColliderComponent>();
|
|
BoxColliderComponent* playerBox = player->AddComponent<BoxColliderComponent>();
|
|
|
|
GameObject* child = scene.CreateGameObject("Child", player);
|
|
child->AddComponent<CapsuleColliderComponent>();
|
|
|
|
XCEngine::Physics::PhysicsWorld world;
|
|
XCEngine::Physics::PhysicsWorldCreateInfo createInfo = {};
|
|
createInfo.scene = &scene;
|
|
|
|
const bool expectedInitialized = XCEngine::Physics::PhysicsWorld::IsPhysXAvailable();
|
|
ASSERT_EQ(world.Initialize(createInfo), expectedInitialized);
|
|
|
|
EXPECT_EQ(world.GetTrackedRigidbodyCount(), 1u);
|
|
EXPECT_EQ(world.GetTrackedColliderCount(), 3u);
|
|
|
|
if (!expectedInitialized) {
|
|
return;
|
|
}
|
|
|
|
EXPECT_EQ(world.GetNativeActorCount(), 1u);
|
|
EXPECT_EQ(world.GetNativeShapeCount(), 3u);
|
|
|
|
ASSERT_TRUE(player->RemoveComponent(playerBox));
|
|
EXPECT_EQ(world.GetTrackedRigidbodyCount(), 1u);
|
|
EXPECT_EQ(world.GetTrackedColliderCount(), 2u);
|
|
EXPECT_EQ(world.GetNativeActorCount(), 1u);
|
|
EXPECT_EQ(world.GetNativeShapeCount(), 2u);
|
|
|
|
child->AddComponent<RigidbodyComponent>();
|
|
EXPECT_EQ(world.GetTrackedRigidbodyCount(), 2u);
|
|
EXPECT_EQ(world.GetTrackedColliderCount(), 2u);
|
|
EXPECT_EQ(world.GetNativeActorCount(), 2u);
|
|
EXPECT_EQ(world.GetNativeShapeCount(), 2u);
|
|
|
|
scene.DestroyGameObject(player);
|
|
EXPECT_EQ(world.GetTrackedRigidbodyCount(), 0u);
|
|
EXPECT_EQ(world.GetTrackedColliderCount(), 0u);
|
|
EXPECT_EQ(world.GetNativeActorCount(), 0u);
|
|
EXPECT_EQ(world.GetNativeShapeCount(), 0u);
|
|
|
|
(void)playerSphere;
|
|
}
|
|
|
|
TEST(PhysicsWorld_Test, DynamicSimulationWritesBackTransform) {
|
|
using namespace XCEngine::Components;
|
|
|
|
if (!XCEngine::Physics::PhysicsWorld::IsPhysXAvailable()) {
|
|
GTEST_SKIP() << "PhysX backend is not available in this build.";
|
|
}
|
|
|
|
Scene scene("PhysicsScene");
|
|
|
|
GameObject* ground = scene.CreateGameObject("Ground");
|
|
ground->GetTransform()->SetPosition(XCEngine::Math::Vector3(0.0f, -0.5f, 0.0f));
|
|
BoxColliderComponent* groundCollider = ground->AddComponent<BoxColliderComponent>();
|
|
groundCollider->SetSize(XCEngine::Math::Vector3(20.0f, 1.0f, 20.0f));
|
|
|
|
GameObject* ball = scene.CreateGameObject("Ball");
|
|
ball->GetTransform()->SetPosition(XCEngine::Math::Vector3(0.0f, 4.0f, 0.0f));
|
|
RigidbodyComponent* rigidbody = ball->AddComponent<RigidbodyComponent>();
|
|
rigidbody->SetBodyType(XCEngine::Physics::PhysicsBodyType::Dynamic);
|
|
rigidbody->SetMass(1.0f);
|
|
rigidbody->SetUseGravity(true);
|
|
SphereColliderComponent* sphere = ball->AddComponent<SphereColliderComponent>();
|
|
sphere->SetRadius(0.5f);
|
|
|
|
XCEngine::Physics::PhysicsWorld world;
|
|
XCEngine::Physics::PhysicsWorldCreateInfo createInfo = {};
|
|
createInfo.scene = &scene;
|
|
ASSERT_TRUE(world.Initialize(createInfo));
|
|
|
|
const float initialY = ball->GetTransform()->GetPosition().y;
|
|
for (int index = 0; index < 30; ++index) {
|
|
world.Step(1.0f / 60.0f);
|
|
}
|
|
|
|
EXPECT_LT(ball->GetTransform()->GetPosition().y, initialY - 0.1f);
|
|
}
|
|
|
|
TEST(PhysicsWorld_Test, RaycastHitsClosestCollider) {
|
|
using namespace XCEngine::Components;
|
|
|
|
Scene scene("PhysicsScene");
|
|
|
|
GameObject* ground = scene.CreateGameObject("Ground");
|
|
ground->GetTransform()->SetPosition(XCEngine::Math::Vector3(0.0f, -0.5f, 0.0f));
|
|
BoxColliderComponent* groundCollider = ground->AddComponent<BoxColliderComponent>();
|
|
groundCollider->SetSize(XCEngine::Math::Vector3(20.0f, 1.0f, 20.0f));
|
|
|
|
GameObject* target = scene.CreateGameObject("Target");
|
|
target->GetTransform()->SetPosition(XCEngine::Math::Vector3(0.0f, 2.0f, 0.0f));
|
|
SphereColliderComponent* sphereCollider = target->AddComponent<SphereColliderComponent>();
|
|
sphereCollider->SetRadius(0.5f);
|
|
|
|
XCEngine::Physics::PhysicsWorld world;
|
|
XCEngine::Physics::PhysicsWorldCreateInfo createInfo = {};
|
|
createInfo.scene = &scene;
|
|
|
|
const bool expectedInitialized = XCEngine::Physics::PhysicsWorld::IsPhysXAvailable();
|
|
ASSERT_EQ(world.Initialize(createInfo), expectedInitialized);
|
|
|
|
XCEngine::Physics::RaycastHit hit;
|
|
const bool result = world.Raycast(
|
|
XCEngine::Math::Vector3(0.0f, 5.0f, 0.0f),
|
|
XCEngine::Math::Vector3::Down(),
|
|
10.0f,
|
|
hit);
|
|
|
|
if (!expectedInitialized) {
|
|
EXPECT_FALSE(result);
|
|
EXPECT_EQ(hit.gameObject, nullptr);
|
|
return;
|
|
}
|
|
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(hit.gameObject, target);
|
|
EXPECT_NEAR(hit.distance, 2.5f, 0.02f);
|
|
EXPECT_NEAR(hit.point.x, 0.0f, 0.001f);
|
|
EXPECT_NEAR(hit.point.y, 2.5f, 0.02f);
|
|
EXPECT_NEAR(hit.point.z, 0.0f, 0.001f);
|
|
EXPECT_NEAR(hit.normal.x, 0.0f, 0.001f);
|
|
EXPECT_NEAR(hit.normal.y, 1.0f, 0.02f);
|
|
EXPECT_NEAR(hit.normal.z, 0.0f, 0.001f);
|
|
EXPECT_FALSE(hit.isTrigger);
|
|
}
|
|
|
|
TEST(PhysicsWorld_Test, RaycastMissClearsHitOutput) {
|
|
using namespace XCEngine::Components;
|
|
|
|
Scene scene("PhysicsScene");
|
|
GameObject* target = scene.CreateGameObject("Target");
|
|
target->AddComponent<BoxColliderComponent>();
|
|
|
|
XCEngine::Physics::PhysicsWorld world;
|
|
XCEngine::Physics::PhysicsWorldCreateInfo createInfo = {};
|
|
createInfo.scene = &scene;
|
|
|
|
const bool expectedInitialized = XCEngine::Physics::PhysicsWorld::IsPhysXAvailable();
|
|
ASSERT_EQ(world.Initialize(createInfo), expectedInitialized);
|
|
|
|
XCEngine::Physics::RaycastHit hit;
|
|
hit.gameObject = target;
|
|
hit.point = XCEngine::Math::Vector3::One();
|
|
hit.normal = XCEngine::Math::Vector3::Up();
|
|
hit.distance = 123.0f;
|
|
hit.isTrigger = true;
|
|
|
|
const bool result = world.Raycast(
|
|
XCEngine::Math::Vector3(0.0f, 5.0f, 0.0f),
|
|
XCEngine::Math::Vector3::Up(),
|
|
10.0f,
|
|
hit);
|
|
|
|
EXPECT_FALSE(result);
|
|
EXPECT_EQ(hit.gameObject, nullptr);
|
|
EXPECT_EQ(hit.point, XCEngine::Math::Vector3::Zero());
|
|
EXPECT_EQ(hit.normal, XCEngine::Math::Vector3::Zero());
|
|
EXPECT_FLOAT_EQ(hit.distance, 0.0f);
|
|
EXPECT_FALSE(hit.isTrigger);
|
|
}
|
|
|
|
TEST(PhysicsWorld_Test, RaycastCanHitTriggerCollider) {
|
|
using namespace XCEngine::Components;
|
|
|
|
Scene scene("PhysicsScene");
|
|
GameObject* trigger = scene.CreateGameObject("Trigger");
|
|
SphereColliderComponent* sphereCollider = trigger->AddComponent<SphereColliderComponent>();
|
|
sphereCollider->SetRadius(1.0f);
|
|
sphereCollider->SetTrigger(true);
|
|
|
|
XCEngine::Physics::PhysicsWorld world;
|
|
XCEngine::Physics::PhysicsWorldCreateInfo createInfo = {};
|
|
createInfo.scene = &scene;
|
|
|
|
const bool expectedInitialized = XCEngine::Physics::PhysicsWorld::IsPhysXAvailable();
|
|
ASSERT_EQ(world.Initialize(createInfo), expectedInitialized);
|
|
|
|
XCEngine::Physics::RaycastHit hit;
|
|
const bool result = world.Raycast(
|
|
XCEngine::Math::Vector3(0.0f, 0.0f, -5.0f),
|
|
XCEngine::Math::Vector3::Forward(),
|
|
10.0f,
|
|
hit);
|
|
|
|
if (!expectedInitialized) {
|
|
EXPECT_FALSE(result);
|
|
EXPECT_EQ(hit.gameObject, nullptr);
|
|
return;
|
|
}
|
|
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(hit.gameObject, trigger);
|
|
EXPECT_NEAR(hit.distance, 4.0f, 0.02f);
|
|
EXPECT_TRUE(hit.isTrigger);
|
|
EXPECT_NEAR(hit.normal.x, 0.0f, 0.001f);
|
|
EXPECT_NEAR(hit.normal.y, 0.0f, 0.001f);
|
|
EXPECT_NEAR(hit.normal.z, -1.0f, 0.02f);
|
|
}
|
|
|
|
TEST(PhysicsWorld_Test, RuntimeColliderGeometryChangesUpdateRaycast) {
|
|
using namespace XCEngine::Components;
|
|
|
|
Scene scene("PhysicsScene");
|
|
GameObject* target = scene.CreateGameObject("Target");
|
|
BoxColliderComponent* boxCollider = target->AddComponent<BoxColliderComponent>();
|
|
boxCollider->SetSize(XCEngine::Math::Vector3(1.0f, 1.0f, 1.0f));
|
|
|
|
XCEngine::Physics::PhysicsWorld world;
|
|
XCEngine::Physics::PhysicsWorldCreateInfo createInfo = {};
|
|
createInfo.scene = &scene;
|
|
|
|
const bool expectedInitialized = XCEngine::Physics::PhysicsWorld::IsPhysXAvailable();
|
|
ASSERT_EQ(world.Initialize(createInfo), expectedInitialized);
|
|
|
|
XCEngine::Physics::RaycastHit hit;
|
|
EXPECT_FALSE(world.Raycast(
|
|
XCEngine::Math::Vector3(0.0f, 1.5f, -5.0f),
|
|
XCEngine::Math::Vector3::Forward(),
|
|
10.0f,
|
|
hit));
|
|
|
|
boxCollider->SetSize(XCEngine::Math::Vector3(1.0f, 4.0f, 1.0f));
|
|
|
|
const bool result = world.Raycast(
|
|
XCEngine::Math::Vector3(0.0f, 1.5f, -5.0f),
|
|
XCEngine::Math::Vector3::Forward(),
|
|
10.0f,
|
|
hit);
|
|
|
|
if (!expectedInitialized) {
|
|
EXPECT_FALSE(result);
|
|
EXPECT_EQ(hit.gameObject, nullptr);
|
|
return;
|
|
}
|
|
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(hit.gameObject, target);
|
|
EXPECT_NEAR(hit.distance, 4.5f, 0.02f);
|
|
}
|
|
|
|
TEST(PhysicsWorld_Test, RuntimeTriggerFlagChangesUpdateRaycastHit) {
|
|
using namespace XCEngine::Components;
|
|
|
|
Scene scene("PhysicsScene");
|
|
GameObject* target = scene.CreateGameObject("Target");
|
|
SphereColliderComponent* sphereCollider = target->AddComponent<SphereColliderComponent>();
|
|
sphereCollider->SetRadius(1.0f);
|
|
|
|
XCEngine::Physics::PhysicsWorld world;
|
|
XCEngine::Physics::PhysicsWorldCreateInfo createInfo = {};
|
|
createInfo.scene = &scene;
|
|
|
|
const bool expectedInitialized = XCEngine::Physics::PhysicsWorld::IsPhysXAvailable();
|
|
ASSERT_EQ(world.Initialize(createInfo), expectedInitialized);
|
|
|
|
sphereCollider->SetTrigger(true);
|
|
|
|
XCEngine::Physics::RaycastHit hit;
|
|
const bool result = world.Raycast(
|
|
XCEngine::Math::Vector3(0.0f, 0.0f, -5.0f),
|
|
XCEngine::Math::Vector3::Forward(),
|
|
10.0f,
|
|
hit);
|
|
|
|
if (!expectedInitialized) {
|
|
EXPECT_FALSE(result);
|
|
EXPECT_EQ(hit.gameObject, nullptr);
|
|
return;
|
|
}
|
|
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(hit.gameObject, target);
|
|
EXPECT_TRUE(hit.isTrigger);
|
|
}
|
|
|
|
TEST(PhysicsWorld_Test, RuntimeBodyTypeChangesRebuildActorAndEnableSimulation) {
|
|
using namespace XCEngine::Components;
|
|
|
|
if (!XCEngine::Physics::PhysicsWorld::IsPhysXAvailable()) {
|
|
GTEST_SKIP() << "PhysX backend is not available in this build.";
|
|
}
|
|
|
|
Scene scene("PhysicsScene");
|
|
|
|
GameObject* ground = scene.CreateGameObject("Ground");
|
|
ground->GetTransform()->SetPosition(XCEngine::Math::Vector3(0.0f, -0.5f, 0.0f));
|
|
BoxColliderComponent* groundCollider = ground->AddComponent<BoxColliderComponent>();
|
|
groundCollider->SetSize(XCEngine::Math::Vector3(20.0f, 1.0f, 20.0f));
|
|
|
|
GameObject* body = scene.CreateGameObject("Body");
|
|
body->GetTransform()->SetPosition(XCEngine::Math::Vector3(0.0f, 4.0f, 0.0f));
|
|
RigidbodyComponent* rigidbody = body->AddComponent<RigidbodyComponent>();
|
|
rigidbody->SetBodyType(XCEngine::Physics::PhysicsBodyType::Static);
|
|
SphereColliderComponent* sphereCollider = body->AddComponent<SphereColliderComponent>();
|
|
sphereCollider->SetRadius(0.5f);
|
|
|
|
XCEngine::Physics::PhysicsWorld world;
|
|
XCEngine::Physics::PhysicsWorldCreateInfo createInfo = {};
|
|
createInfo.scene = &scene;
|
|
ASSERT_TRUE(world.Initialize(createInfo));
|
|
ASSERT_EQ(world.GetNativeActorCount(), 2u);
|
|
|
|
const float initialY = body->GetTransform()->GetPosition().y;
|
|
world.Step(1.0f / 60.0f);
|
|
EXPECT_NEAR(body->GetTransform()->GetPosition().y, initialY, 0.001f);
|
|
|
|
rigidbody->SetBodyType(XCEngine::Physics::PhysicsBodyType::Dynamic);
|
|
world.Step(1.0f / 60.0f);
|
|
EXPECT_EQ(world.GetNativeActorCount(), 2u);
|
|
|
|
for (int index = 0; index < 30; ++index) {
|
|
world.Step(1.0f / 60.0f);
|
|
}
|
|
|
|
EXPECT_LT(body->GetTransform()->GetPosition().y, initialY - 0.1f);
|
|
}
|
|
|
|
TEST(PhysicsWorld_Test, RuntimeLinearVelocityMovesDynamicBody) {
|
|
using namespace XCEngine::Components;
|
|
|
|
if (!XCEngine::Physics::PhysicsWorld::IsPhysXAvailable()) {
|
|
GTEST_SKIP() << "PhysX backend is not available in this build.";
|
|
}
|
|
|
|
Scene scene("PhysicsScene");
|
|
GameObject* body = scene.CreateGameObject("Body");
|
|
body->GetTransform()->SetPosition(XCEngine::Math::Vector3(0.0f, 1.0f, 0.0f));
|
|
RigidbodyComponent* rigidbody = body->AddComponent<RigidbodyComponent>();
|
|
rigidbody->SetBodyType(XCEngine::Physics::PhysicsBodyType::Dynamic);
|
|
rigidbody->SetUseGravity(false);
|
|
rigidbody->SetLinearVelocity(XCEngine::Math::Vector3(0.0f, 2.0f, 0.0f));
|
|
SphereColliderComponent* sphereCollider = body->AddComponent<SphereColliderComponent>();
|
|
sphereCollider->SetRadius(0.5f);
|
|
|
|
XCEngine::Physics::PhysicsWorld world;
|
|
XCEngine::Physics::PhysicsWorldCreateInfo createInfo = {};
|
|
createInfo.scene = &scene;
|
|
ASSERT_TRUE(world.Initialize(createInfo));
|
|
|
|
const float initialY = body->GetTransform()->GetPosition().y;
|
|
for (int index = 0; index < 30; ++index) {
|
|
world.Step(1.0f / 60.0f);
|
|
}
|
|
|
|
EXPECT_GT(body->GetTransform()->GetPosition().y, initialY + 0.9f);
|
|
EXPECT_NEAR(rigidbody->GetLinearVelocity().y, 2.0f, 0.02f);
|
|
}
|
|
|
|
TEST(PhysicsWorld_Test, AddForceImpulseMovesDynamicBody) {
|
|
using namespace XCEngine::Components;
|
|
|
|
if (!XCEngine::Physics::PhysicsWorld::IsPhysXAvailable()) {
|
|
GTEST_SKIP() << "PhysX backend is not available in this build.";
|
|
}
|
|
|
|
Scene scene("PhysicsScene");
|
|
GameObject* body = scene.CreateGameObject("Body");
|
|
body->GetTransform()->SetPosition(XCEngine::Math::Vector3(0.0f, 1.0f, 0.0f));
|
|
RigidbodyComponent* rigidbody = body->AddComponent<RigidbodyComponent>();
|
|
rigidbody->SetBodyType(XCEngine::Physics::PhysicsBodyType::Dynamic);
|
|
rigidbody->SetUseGravity(false);
|
|
rigidbody->SetMass(1.0f);
|
|
SphereColliderComponent* sphereCollider = body->AddComponent<SphereColliderComponent>();
|
|
sphereCollider->SetRadius(0.5f);
|
|
|
|
XCEngine::Physics::PhysicsWorld world;
|
|
XCEngine::Physics::PhysicsWorldCreateInfo createInfo = {};
|
|
createInfo.scene = &scene;
|
|
ASSERT_TRUE(world.Initialize(createInfo));
|
|
|
|
const float initialY = body->GetTransform()->GetPosition().y;
|
|
rigidbody->AddForce(
|
|
XCEngine::Math::Vector3(0.0f, 3.0f, 0.0f),
|
|
XCEngine::Physics::PhysicsForceMode::Impulse);
|
|
|
|
for (int index = 0; index < 10; ++index) {
|
|
world.Step(1.0f / 60.0f);
|
|
}
|
|
|
|
EXPECT_GT(body->GetTransform()->GetPosition().y, initialY + 0.35f);
|
|
EXPECT_NEAR(rigidbody->GetLinearVelocity().y, 3.0f, 0.02f);
|
|
}
|
|
|
|
} // namespace
|