123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
- // SPDX-License-Identifier: MIT
- #include "UnitTestFramework.h"
- #include "PhysicsTestContext.h"
- #include "Layers.h"
- #include "LoggingContactListener.h"
- #include "LoggingBodyActivationListener.h"
- TEST_SUITE("MotionQualityLinearCastTests")
- {
- static const float cBoxExtent = 0.5f;
- static const float cFrequency = 60.0f;
- static const Vec3 cVelocity(2.0f * cFrequency, 0, 0); // High enough velocity to step 2 meters in a single simulation step
- static const Vec3 cPos1(-1, 0, 0);
- static const Vec3 cPos2(1, 0, 0);
- // Two boxes colliding in the center, each has enough velocity to tunnel though in 1 step
- TEST_CASE("TestDiscreteBoxVsDiscreteBox")
- {
- PhysicsTestContext c(1.0f / cFrequency, 1, 1);
- c.ZeroGravity();
- // Register listener
- LoggingContactListener listener;
- c.GetSystem()->SetContactListener(&listener);
- Body &box1 = c.CreateBox(cPos1, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, Vec3::sReplicate(cBoxExtent));
- box1.SetLinearVelocity(cVelocity);
- // Test that the inner radius of the box makes sense (used internally by linear cast)
- CHECK_APPROX_EQUAL(box1.GetShape()->GetInnerRadius(), cBoxExtent);
- Body &box2 = c.CreateBox(cPos2, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, Vec3::sReplicate(cBoxExtent));
- box2.SetLinearVelocity(-cVelocity);
- c.SimulateSingleStep();
- // No collisions should be reported and the bodies should have moved according to their velocity (tunneling through eachother)
- CHECK(listener.GetEntryCount() == 0);
- CHECK_APPROX_EQUAL(box1.GetPosition(), cPos1 + cVelocity / cFrequency);
- CHECK_APPROX_EQUAL(box1.GetLinearVelocity(), cVelocity);
- CHECK_APPROX_EQUAL(box1.GetAngularVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box2.GetPosition(), cPos2 - cVelocity / cFrequency);
- CHECK_APPROX_EQUAL(box2.GetLinearVelocity(), -cVelocity);
- CHECK_APPROX_EQUAL(box2.GetAngularVelocity(), Vec3::sZero());
- }
- // Two boxes colliding in the center, each has enough velocity to step over the other in 1 step, restitution = 1
- TEST_CASE("TestLinearCastBoxVsLinearCastBoxElastic")
- {
- PhysicsTestContext c(1.0f / cFrequency, 1, 1);
- c.ZeroGravity();
- const float cPenetrationSlop = c.GetSystem()->GetPhysicsSettings().mPenetrationSlop;
- // Register listener
- LoggingContactListener listener;
- c.GetSystem()->SetContactListener(&listener);
- Body &box1 = c.CreateBox(cPos1, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::LinearCast, Layers::MOVING, Vec3::sReplicate(cBoxExtent));
- box1.SetLinearVelocity(cVelocity);
- box1.SetRestitution(1.0f);
- Body &box2 = c.CreateBox(cPos2, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::LinearCast, Layers::MOVING, Vec3::sReplicate(cBoxExtent));
- box2.SetLinearVelocity(-cVelocity);
- box2.SetRestitution(1.0f);
- c.SimulateSingleStep();
- // The bodies should have collided and the velocities reversed
- CHECK(listener.GetEntryCount() == 2);
- CHECK(listener.Contains(LoggingContactListener::EType::Validate, box1.GetID(), box2.GetID()));
- CHECK(listener.Contains(LoggingContactListener::EType::Add, box1.GetID(), box2.GetID()));
- CHECK_APPROX_EQUAL(box1.GetPosition(), Vec3(-cBoxExtent, 0, 0), cPenetrationSlop);
- CHECK_APPROX_EQUAL(box1.GetLinearVelocity(), -cVelocity);
- CHECK_APPROX_EQUAL(box1.GetAngularVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box2.GetPosition(), Vec3(cBoxExtent, 0, 0), cPenetrationSlop);
- CHECK_APPROX_EQUAL(box2.GetLinearVelocity(), cVelocity);
- CHECK_APPROX_EQUAL(box2.GetAngularVelocity(), Vec3::sZero());
- listener.Clear();
- c.SimulateSingleStep();
- // In the second step the bodies should have moved away, but since they were initially overlapping we should have a contact persist callback
- CHECK(listener.GetEntryCount() == 2);
- CHECK(listener.Contains(LoggingContactListener::EType::Validate, box1.GetID(), box2.GetID()));
- CHECK(listener.Contains(LoggingContactListener::EType::Persist, box1.GetID(), box2.GetID()));
- CHECK_APPROX_EQUAL(box1.GetPosition(), Vec3(-cBoxExtent, 0, 0) - cVelocity / cFrequency, cPenetrationSlop);
- CHECK_APPROX_EQUAL(box1.GetLinearVelocity(), -cVelocity);
- CHECK_APPROX_EQUAL(box1.GetAngularVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box2.GetPosition(), Vec3(cBoxExtent, 0, 0) + cVelocity / cFrequency, cPenetrationSlop);
- CHECK_APPROX_EQUAL(box2.GetLinearVelocity(), cVelocity);
- CHECK_APPROX_EQUAL(box2.GetAngularVelocity(), Vec3::sZero());
- listener.Clear();
- c.SimulateSingleStep();
- // In the third step the bodies have separated and a contact remove callback should have been received
- CHECK(listener.GetEntryCount() == 1);
- CHECK(listener.Contains(LoggingContactListener::EType::Remove, box1.GetID(), box2.GetID()));
- CHECK_APPROX_EQUAL(box1.GetPosition(), Vec3(-cBoxExtent, 0, 0) - 2.0f * cVelocity / cFrequency, cPenetrationSlop);
- CHECK_APPROX_EQUAL(box1.GetLinearVelocity(), -cVelocity);
- CHECK_APPROX_EQUAL(box1.GetAngularVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box2.GetPosition(), Vec3(cBoxExtent, 0, 0) + 2.0f * cVelocity / cFrequency, cPenetrationSlop);
- CHECK_APPROX_EQUAL(box2.GetLinearVelocity(), cVelocity);
- CHECK_APPROX_EQUAL(box2.GetAngularVelocity(), Vec3::sZero());
- }
- // Two boxes colliding in the center, each has enough velocity to step over the other in 1 step, restitution = 0
- TEST_CASE("TestLinearCastBoxVsLinearCastBoxInelastic")
- {
- PhysicsTestContext c(1.0f / cFrequency, 1, 1);
- c.ZeroGravity();
- const float cPenetrationSlop = c.GetSystem()->GetPhysicsSettings().mPenetrationSlop;
- // Register listener
- LoggingContactListener listener;
- c.GetSystem()->SetContactListener(&listener);
- Body &box1 = c.CreateBox(cPos1, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::LinearCast, Layers::MOVING, Vec3::sReplicate(cBoxExtent));
- box1.SetLinearVelocity(cVelocity);
- Body &box2 = c.CreateBox(cPos2, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::LinearCast, Layers::MOVING, Vec3::sReplicate(cBoxExtent));
- box2.SetLinearVelocity(-cVelocity);
- c.SimulateSingleStep();
- // The bodies should have collided and both are stopped
- CHECK(listener.GetEntryCount() == 2);
- CHECK(listener.Contains(LoggingContactListener::EType::Validate, box1.GetID(), box2.GetID()));
- CHECK(listener.Contains(LoggingContactListener::EType::Add, box1.GetID(), box2.GetID()));
- CHECK_APPROX_EQUAL(box1.GetPosition(), Vec3(-cBoxExtent, 0, 0), cPenetrationSlop);
- CHECK_APPROX_EQUAL(box1.GetLinearVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box1.GetAngularVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box2.GetPosition(), Vec3(cBoxExtent, 0, 0), cPenetrationSlop);
- CHECK_APPROX_EQUAL(box2.GetLinearVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box2.GetAngularVelocity(), Vec3::sZero());
- // The bodies should persist to contact as they are not moving
- for (int i = 0; i < 10; ++i)
- {
- listener.Clear();
- c.SimulateSingleStep();
- if (i == 0)
- {
- // Only in the first step we will receive a validate callback since after this step the contact cache will be used
- CHECK(listener.GetEntryCount() == 2);
- CHECK(listener.Contains(LoggingContactListener::EType::Validate, box1.GetID(), box2.GetID()));
- }
- else
- CHECK(listener.GetEntryCount() == 1);
- CHECK(listener.Contains(LoggingContactListener::EType::Persist, box1.GetID(), box2.GetID()));
- CHECK_APPROX_EQUAL(box1.GetPosition(), Vec3(-cBoxExtent, 0, 0), cPenetrationSlop);
- CHECK_APPROX_EQUAL(box1.GetLinearVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box1.GetAngularVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box2.GetPosition(), Vec3(cBoxExtent, 0, 0), cPenetrationSlop);
- CHECK_APPROX_EQUAL(box2.GetLinearVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box2.GetAngularVelocity(), Vec3::sZero());
- }
- }
- // Two boxes colliding in the center, linear cast vs inactive linear cast
- TEST_CASE("TestLinearCastBoxVsInactiveLinearCastBox")
- {
- PhysicsTestContext c(1.0f / cFrequency, 1, 1);
- c.ZeroGravity();
- const float cPenetrationSlop = c.GetSystem()->GetPhysicsSettings().mPenetrationSlop;
- // Register listener
- LoggingContactListener listener;
- c.GetSystem()->SetContactListener(&listener);
- LoggingBodyActivationListener activation;
- c.GetSystem()->SetBodyActivationListener(&activation);
- Body &box1 = c.CreateBox(cPos1, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::LinearCast, Layers::MOVING, Vec3::sReplicate(cBoxExtent));
- box1.SetLinearVelocity(cVelocity);
- Body &box2 = c.CreateBox(cPos2, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::LinearCast, Layers::MOVING, Vec3::sReplicate(cBoxExtent), EActivation::DontActivate);
- CHECK(!box2.IsActive());
- c.SimulateSingleStep();
- // The bodies should have collided and body 2 should be activated, have velocity, but not moved in this step
- CHECK(listener.GetEntryCount() == 2);
- CHECK(listener.Contains(LoggingContactListener::EType::Validate, box1.GetID(), box2.GetID()));
- CHECK(listener.Contains(LoggingContactListener::EType::Add, box1.GetID(), box2.GetID()));
- Vec3 new_velocity = 0.5f * cVelocity;
- CHECK_APPROX_EQUAL(box1.GetPosition(), cPos2 - Vec3(2.0f * cBoxExtent, 0, 0), cPenetrationSlop);
- CHECK_APPROX_EQUAL(box1.GetLinearVelocity(), new_velocity);
- CHECK_APPROX_EQUAL(box1.GetAngularVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box2.GetPosition(), cPos2);
- CHECK_APPROX_EQUAL(box2.GetLinearVelocity(), new_velocity);
- CHECK_APPROX_EQUAL(box2.GetAngularVelocity(), Vec3::sZero());
- CHECK(box2.IsActive());
- CHECK(activation.Contains(LoggingBodyActivationListener::EType::Activated, box2.GetID()));
- listener.Clear();
- c.SimulateSingleStep();
- // In the next step body 2 should have started to move
- CHECK(listener.GetEntryCount() == 2);
- CHECK(listener.Contains(LoggingContactListener::EType::Validate, box1.GetID(), box2.GetID()));
- CHECK(listener.Contains(LoggingContactListener::EType::Persist, box1.GetID(), box2.GetID()));
- CHECK_APPROX_EQUAL(box1.GetPosition(), cPos2 - Vec3(2.0f * cBoxExtent, 0, 0) + new_velocity / cFrequency, cPenetrationSlop);
- CHECK_APPROX_EQUAL(box1.GetLinearVelocity(), new_velocity);
- CHECK_APPROX_EQUAL(box1.GetAngularVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box2.GetPosition(), cPos2 + new_velocity / cFrequency);
- CHECK_APPROX_EQUAL(box2.GetLinearVelocity(), new_velocity);
- CHECK_APPROX_EQUAL(box2.GetAngularVelocity(), Vec3::sZero());
- }
- // Two boxes colliding in the center, linear cast vs inactive discrete
- TEST_CASE("TestLinearCastBoxVsInactiveDiscreteBox")
- {
- PhysicsTestContext c(1.0f / cFrequency, 1, 1);
- c.ZeroGravity();
- const float cPenetrationSlop = c.GetSystem()->GetPhysicsSettings().mPenetrationSlop;
- // Register listener
- LoggingContactListener listener;
- c.GetSystem()->SetContactListener(&listener);
- LoggingBodyActivationListener activation;
- c.GetSystem()->SetBodyActivationListener(&activation);
- Body &box1 = c.CreateBox(cPos1, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::LinearCast, Layers::MOVING, Vec3::sReplicate(cBoxExtent));
- box1.SetLinearVelocity(cVelocity);
- Body &box2 = c.CreateBox(cPos2, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, Vec3::sReplicate(cBoxExtent), EActivation::DontActivate);
- CHECK(!box2.IsActive());
- c.SimulateSingleStep();
- // The bodies should have collided and body 2 should be activated, have velocity, but not moved in this step
- CHECK(listener.GetEntryCount() == 2);
- CHECK(listener.Contains(LoggingContactListener::EType::Validate, box1.GetID(), box2.GetID()));
- CHECK(listener.Contains(LoggingContactListener::EType::Add, box1.GetID(), box2.GetID()));
- Vec3 new_velocity = 0.5f * cVelocity;
- CHECK_APPROX_EQUAL(box1.GetPosition(), cPos2 - Vec3(2.0f * cBoxExtent, 0, 0), cPenetrationSlop);
- CHECK_APPROX_EQUAL(box1.GetLinearVelocity(), new_velocity);
- CHECK_APPROX_EQUAL(box1.GetAngularVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box2.GetPosition(), cPos2);
- CHECK_APPROX_EQUAL(box2.GetLinearVelocity(), new_velocity);
- CHECK_APPROX_EQUAL(box2.GetAngularVelocity(), Vec3::sZero());
- CHECK(box2.IsActive());
- CHECK(activation.Contains(LoggingBodyActivationListener::EType::Activated, box2.GetID()));
- listener.Clear();
- c.SimulateSingleStep();
- // In the next step body 2 should have started to move
- CHECK(listener.GetEntryCount() == 2);
- CHECK(listener.Contains(LoggingContactListener::EType::Validate, box1.GetID(), box2.GetID()));
- CHECK(listener.Contains(LoggingContactListener::EType::Persist, box1.GetID(), box2.GetID()));
- CHECK_APPROX_EQUAL(box1.GetPosition(), cPos2 - Vec3(2.0f * cBoxExtent, 0, 0) + new_velocity / cFrequency, cPenetrationSlop);
- CHECK_APPROX_EQUAL(box1.GetLinearVelocity(), new_velocity);
- CHECK_APPROX_EQUAL(box1.GetAngularVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box2.GetPosition(), cPos2 + new_velocity / cFrequency);
- CHECK_APPROX_EQUAL(box2.GetLinearVelocity(), new_velocity);
- CHECK_APPROX_EQUAL(box2.GetAngularVelocity(), Vec3::sZero());
- }
- // Two boxes colliding under an angle, linear cast vs inactive discrete
- TEST_CASE("TestLinearCastBoxVsInactiveDiscreteBoxAngled")
- {
- const Vec3 cAngledOffset1(1, 0, -2);
- const Vec3 cAngledVelocity = -cFrequency * 2 * cAngledOffset1;
- PhysicsTestContext c(1.0f / cFrequency, 1, 1);
- c.ZeroGravity();
- const float cPenetrationSlop = c.GetSystem()->GetPhysicsSettings().mPenetrationSlop;
- // Register listener
- LoggingContactListener listener;
- c.GetSystem()->SetContactListener(&listener);
- LoggingBodyActivationListener activation;
- c.GetSystem()->SetBodyActivationListener(&activation);
- // Make sure box1 exactly hits the face of box2 in the center
- Vec3 pos1 = Vec3(2.0f * cBoxExtent, 0, 0) + cAngledOffset1;
- Body &box1 = c.CreateBox(pos1, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::LinearCast, Layers::MOVING, Vec3::sReplicate(cBoxExtent));
- box1.SetLinearVelocity(cAngledVelocity);
- box1.SetRestitution(1.0f);
- box1.SetFriction(0.0f);
- Body &box2 = c.CreateBox(Vec3::sZero(), Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, Vec3::sReplicate(cBoxExtent), EActivation::DontActivate);
- box2.SetRestitution(1.0f);
- box2.SetFriction(0.0f);
- CHECK(!box2.IsActive());
- c.SimulateSingleStep();
- // The bodies should have collided and body 2 should be activated, have inherited the x velocity of body 1, but not moved in this step. Body 1 should have lost all of its velocity in x direction.
- CHECK(listener.GetEntryCount() == 2);
- CHECK(listener.Contains(LoggingContactListener::EType::Validate, box1.GetID(), box2.GetID()));
- CHECK(listener.Contains(LoggingContactListener::EType::Add, box1.GetID(), box2.GetID()));
- Vec3 new_velocity1 = Vec3(0, 0, cAngledVelocity.GetZ());
- Vec3 new_velocity2 = Vec3(cAngledVelocity.GetX(), 0, 0);
- CHECK_APPROX_EQUAL(box1.GetPosition(), Vec3(2.0f * cBoxExtent, 0, 0), 2.3f * cPenetrationSlop); // We're moving 2x as fast in the z direction and the slop is allowed in x direction: sqrt(1^2 + 2^2) ~ 2.3
- CHECK_APPROX_EQUAL(box1.GetLinearVelocity(), new_velocity1, 1.0e-4f);
- CHECK_APPROX_EQUAL(box1.GetAngularVelocity(), Vec3::sZero(), 2.0e-4f);
- CHECK_APPROX_EQUAL(box2.GetPosition(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box2.GetLinearVelocity(), new_velocity2, 1.0e-4f);
- CHECK_APPROX_EQUAL(box2.GetAngularVelocity(), Vec3::sZero(), 2.0e-4f);
- CHECK(box2.IsActive());
- CHECK(activation.Contains(LoggingBodyActivationListener::EType::Activated, box2.GetID()));
- }
- // Two boxes colliding in the center, linear cast vs fast moving discrete, should tunnel through because all discrete bodies are moved before linear cast bodies are tested
- TEST_CASE("TestLinearCastBoxVsFastDiscreteBox")
- {
- PhysicsTestContext c(1.0f / cFrequency, 1, 1);
- c.ZeroGravity();
- // Register listener
- LoggingContactListener listener;
- c.GetSystem()->SetContactListener(&listener);
- Body &box1 = c.CreateBox(cPos1, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::LinearCast, Layers::MOVING, Vec3::sReplicate(cBoxExtent));
- box1.SetLinearVelocity(cVelocity);
- Body &box2 = c.CreateBox(cPos2, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, Vec3::sReplicate(cBoxExtent));
- box2.SetLinearVelocity(-cVelocity);
- c.SimulateSingleStep();
- // No collisions should be reported and the bodies should have moved according to their velocity (tunneling through eachother)
- CHECK(listener.GetEntryCount() == 0);
- CHECK_APPROX_EQUAL(box1.GetPosition(), cPos1 + cVelocity / cFrequency);
- CHECK_APPROX_EQUAL(box1.GetLinearVelocity(), cVelocity);
- CHECK_APPROX_EQUAL(box1.GetAngularVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box2.GetPosition(), cPos2 - cVelocity / cFrequency);
- CHECK_APPROX_EQUAL(box2.GetLinearVelocity(), -cVelocity);
- CHECK_APPROX_EQUAL(box2.GetAngularVelocity(), Vec3::sZero());
- }
- // Two boxes colliding in the center, linear cast vs moving discrete, discrete is slow enough not to tunnel through linear cast body
- TEST_CASE("TestLinearCastBoxVsSlowDiscreteBox")
- {
- PhysicsTestContext c(1.0f / cFrequency, 1, 1);
- c.ZeroGravity();
- const float cPenetrationSlop = c.GetSystem()->GetPhysicsSettings().mPenetrationSlop;
- // Register listener
- LoggingContactListener listener;
- c.GetSystem()->SetContactListener(&listener);
- Body &box1 = c.CreateBox(cPos1, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::LinearCast, Layers::MOVING, Vec3::sReplicate(cBoxExtent));
- box1.SetLinearVelocity(cVelocity);
- // In 1 step it should move -0.1 meter on the X axis
- const Vec3 cBox2Velocity = Vec3(-0.1f * cFrequency, 0, 0);
- Body &box2 = c.CreateBox(cPos2, Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, Vec3::sReplicate(cBoxExtent));
- box2.SetLinearVelocity(cBox2Velocity);
- c.SimulateSingleStep();
- // The bodies should have collided and body 2 should have moved according to its discrete step
- CHECK(listener.GetEntryCount() == 2);
- CHECK(listener.Contains(LoggingContactListener::EType::Validate, box1.GetID(), box2.GetID()));
- CHECK(listener.Contains(LoggingContactListener::EType::Add, box1.GetID(), box2.GetID()));
- Vec3 new_pos2 = cPos2 + cBox2Velocity / cFrequency;
- Vec3 new_velocity = 0.5f * (cVelocity + cBox2Velocity);
- CHECK_APPROX_EQUAL(box1.GetPosition(), new_pos2 - Vec3(2.0f * cBoxExtent, 0, 0), cPenetrationSlop);
- CHECK_APPROX_EQUAL(box1.GetLinearVelocity(), new_velocity);
- CHECK_APPROX_EQUAL(box1.GetAngularVelocity(), Vec3::sZero());
- CHECK_APPROX_EQUAL(box2.GetPosition(), new_pos2);
- CHECK_APPROX_EQUAL(box2.GetLinearVelocity(), new_velocity);
- CHECK_APPROX_EQUAL(box2.GetAngularVelocity(), Vec3::sZero());
- }
- }
|