Merge pull request #7041 from aws-lumberyard-dev/quad-collider-2

Support for quad shape in PhysX shape collider component
monroegm-disable-blank-issue-2
greerdv 4 years ago committed by GitHub
commit be877373f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -22,6 +22,7 @@
#include <LmbrCentral/Shape/SphereShapeComponentBus.h>
#include <LmbrCentral/Shape/CylinderShapeComponentBus.h>
#include <LmbrCentral/Shape/PolygonPrismShapeComponentBus.h>
#include <LmbrCentral/Shape/QuadShapeComponentBus.h>
#include <PhysX/SystemComponentBus.h>
#include <Source/Utils.h>
#include <AzCore/Math/Geometry2DUtils.h>
@ -54,7 +55,7 @@ namespace PhysX
m_colliderConfig.SetPropertyVisibility(Physics::ColliderConfiguration::Offset, false);
}
AZ::Crc32 EditorShapeColliderComponent::SubdivisionCountVisibility()
AZ::Crc32 EditorShapeColliderComponent::SubdivisionCountVisibility() const
{
if (m_shapeType == ShapeType::Cylinder)
{
@ -64,6 +65,17 @@ namespace PhysX
return AZ::Edit::PropertyVisibility::Hide;
}
AZ::Crc32 EditorShapeColliderComponent::SingleSidedVisibility() const
{
if ((m_shapeType == ShapeType::QuadSingleSided || m_shapeType == ShapeType::QuadDoubleSided)
&& GetEntity()->FindComponent<EditorRigidBodyComponent>() == nullptr)
{
return AZ::Edit::PropertyVisibility::Show;
}
return AZ::Edit::PropertyVisibility::Hide;
}
void EditorShapeColliderComponent::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
@ -74,6 +86,7 @@ namespace PhysX
->Field("DebugDrawSettings", &EditorShapeColliderComponent::m_colliderDebugDraw)
->Field("ShapeConfigs", &EditorShapeColliderComponent::m_shapeConfigs)
->Field("SubdivisionCount", &EditorShapeColliderComponent::m_subdivisionCount)
->Field("SingleSided", &EditorShapeColliderComponent::m_singleSided)
;
if (auto editContext = serializeContext->GetEditContext())
@ -100,6 +113,10 @@ namespace PhysX
->Attribute(AZ::Edit::Attributes::Max, Utils::MaxFrustumSubdivisions)
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorShapeColliderComponent::OnSubdivisionCountChange)
->Attribute(AZ::Edit::Attributes::Visibility, &EditorShapeColliderComponent::SubdivisionCountVisibility)
->DataElement(AZ::Edit::UIHandlers::Default, &EditorShapeColliderComponent::m_singleSided, "Single sided",
"If enabled, planar shapes will only collide from one direction (not valid for shapes attached to dynamic rigid bodies)")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorShapeColliderComponent::OnSingleSidedChange)
->Attribute(AZ::Edit::Attributes::Visibility, &EditorShapeColliderComponent::SingleSidedVisibility)
;
}
}
@ -107,16 +124,16 @@ namespace PhysX
void EditorShapeColliderComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("PhysicsWorldBodyService", 0x944da0cc));
provided.push_back(AZ_CRC("PhysXColliderService", 0x4ff43f7c));
provided.push_back(AZ_CRC("PhysXTriggerService", 0x3a117d7b));
provided.push_back(AZ_CRC("PhysXShapeColliderService", 0x98a7e779));
provided.push_back(AZ_CRC_CE("PhysicsWorldBodyService"));
provided.push_back(AZ_CRC_CE("PhysXColliderService"));
provided.push_back(AZ_CRC_CE("PhysXTriggerService"));
provided.push_back(AZ_CRC_CE("PhysXShapeColliderService"));
}
void EditorShapeColliderComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("TransformService", 0x8ee22c50));
required.push_back(AZ_CRC("ShapeService", 0xe86aa5fe));
required.push_back(AZ_CRC_CE("TransformService"));
required.push_back(AZ_CRC_CE("ShapeService"));
}
void EditorShapeColliderComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
@ -126,7 +143,6 @@ namespace PhysX
incompatible.push_back(AZ_CRC_CE("AxisAlignedBoxShapeService"));
incompatible.push_back(AZ_CRC_CE("CompoundShapeService"));
incompatible.push_back(AZ_CRC_CE("DiskShapeService"));
incompatible.push_back(AZ_CRC_CE("QuadShapeService"));
incompatible.push_back(AZ_CRC_CE("TubeShapeService"));
incompatible.push_back(AZ_CRC_CE("ReferenceShapeService"));
}
@ -206,6 +222,12 @@ namespace PhysX
break;
}
case ShapeType::QuadSingleSided:
case ShapeType::QuadDoubleSided:
{
// a quad shape has no interior, just return an empty vector of sample points
break;
}
default:
AZ_WarningOnce("PhysX Shape Collider Component", false, "Unsupported shape type in UpdateCachedSamplePoints");
break;
@ -331,6 +353,11 @@ namespace PhysX
UpdateCylinderConfig(uniformScale);
}
else if (shapeCrc == ShapeConstants::Quad)
{
UpdateQuadConfig(overallScale);
}
else
{
m_shapeType = !shapeCrc ? ShapeType::None : ShapeType::Unsupported;
@ -354,6 +381,59 @@ namespace PhysX
m_geometryCache.m_boxDimensions = scale * boxDimensions;
}
void EditorShapeColliderComponent::UpdateQuadConfig(const AZ::Vector3& scale)
{
LmbrCentral::QuadShapeConfig quadShapeConfig;
LmbrCentral::QuadShapeComponentRequestBus::EventResult(quadShapeConfig, GetEntityId(),
&LmbrCentral::QuadShapeComponentRequests::GetQuadConfiguration);
const float minDimension = 1e-3f; // used to prevent the dimensions being 0 in any direction
const float xDim = AZ::GetMax(minDimension, quadShapeConfig.m_width);
const float yDim = AZ::GetMax(minDimension, quadShapeConfig.m_height);
if (m_singleSided)
{
AZStd::vector<AZ::u8> cookedData;
constexpr AZ::u32 vertexCount = 4;
const AZ::Vector3 vertices[vertexCount] =
{
AZ::Vector3(-0.5f * xDim, -0.5f * yDim, 0.0f),
AZ::Vector3(-0.5f * xDim, 0.5f * yDim, 0.0f),
AZ::Vector3(0.5f * xDim, 0.5f * yDim, 0.0f),
AZ::Vector3(0.5f * xDim, -0.5f * yDim, 0.0f),
};
constexpr AZ::u32 indexCount = 6;
const AZ::u32 indices[indexCount] =
{
0, 2, 1,
0, 3, 2
};
bool cookingResult = false;
Physics::SystemRequestBus::BroadcastResult(cookingResult, &Physics::SystemRequests::CookTriangleMeshToMemory,
vertices, vertexCount, indices, indexCount, cookedData);
Physics::CookedMeshShapeConfiguration shapeConfig;
shapeConfig.SetCookedMeshData(cookedData.data(), cookedData.size(),
Physics::CookedMeshShapeConfiguration::MeshType::TriangleMesh);
shapeConfig.m_scale = scale;
SetShapeConfig(ShapeType::QuadSingleSided, shapeConfig);
}
else
{
// it's not possible to create a perfectly 2d convex in PhysX, so the best we can do is a very thin box
const float zDim = AZ::GetMax(minDimension, 1e-3f * AZ::GetMin(xDim, yDim));
const AZ::Vector3 boxDimensions(xDim, yDim, zDim);
SetShapeConfig(ShapeType::QuadDoubleSided, Physics::BoxShapeConfiguration(boxDimensions));
m_shapeConfigs.back()->m_scale = scale;
}
}
void EditorShapeColliderComponent::UpdateCapsuleConfig(const AZ::Vector3& scale)
{
LmbrCentral::CapsuleShapeConfig lmbrCentralCapsuleShapeConfig;
@ -425,6 +505,12 @@ namespace PhysX
}
}
void EditorShapeColliderComponent::OnSingleSidedChange()
{
UpdateShapeConfigs();
CreateStaticEditorCollider();
}
AZ::u32 EditorShapeColliderComponent::OnSubdivisionCountChange()
{
const AZ::Vector3 uniformScale = Utils::GetUniformScale(GetEntityId());
@ -615,7 +701,9 @@ namespace PhysX
m_editorSceneHandle = m_sceneInterface->GetSceneHandle(AzPhysics::EditorPhysicsSceneName);
}
UpdateSingleSidedSettings();
UpdateShapeConfigs();
UpdateTriggerSettings();
// Debug drawing
m_colliderDebugDraw.Connect(GetEntityId());
@ -767,6 +855,7 @@ namespace PhysX
if (changeReason == LmbrCentral::ShapeComponentNotifications::ShapeChangeReasons::ShapeChanged)
{
UpdateShapeConfigs();
UpdateTriggerSettings();
CreateStaticEditorCollider();
Physics::ColliderComponentEventBus::Event(GetEntityId(), &Physics::ColliderComponentEvents::OnColliderChanged);
@ -849,4 +938,46 @@ namespace PhysX
{
return m_colliderConfig.m_isTrigger;
}
void EditorShapeColliderComponent::UpdateTriggerSettings()
{
if (m_shapeType == ShapeType::QuadSingleSided || m_shapeType == ShapeType::QuadDoubleSided)
{
if (!m_previousIsTrigger.has_value())
{
m_previousIsTrigger = m_colliderConfig.m_isTrigger;
m_colliderConfig.m_isTrigger = false;
}
m_colliderConfig.SetPropertyVisibility(Physics::ColliderConfiguration::PropertyVisibility::IsTrigger, false);
}
else
{
if (m_previousIsTrigger.has_value())
{
m_colliderConfig.m_isTrigger = m_previousIsTrigger.value();
m_previousIsTrigger.reset();
}
m_colliderConfig.SetPropertyVisibility(Physics::ColliderConfiguration::PropertyVisibility::IsTrigger, true);
}
}
void EditorShapeColliderComponent::UpdateSingleSidedSettings()
{
if (GetEntity()->FindComponent<EditorRigidBodyComponent>())
{
if (!m_previousSingleSided.has_value())
{
m_previousSingleSided = m_singleSided;
}
m_singleSided = false;
}
else
{
if (m_previousSingleSided.has_value())
{
m_singleSided = m_previousSingleSided.value();
m_previousSingleSided.reset();
}
}
}
} // namespace PhysX

@ -41,6 +41,8 @@ namespace PhysX
Sphere,
PolygonPrism,
Cylinder,
QuadDoubleSided,
QuadSingleSided,
Unsupported
};
@ -89,6 +91,7 @@ namespace PhysX
AZ::u32 OnConfigurationChanged();
void UpdateShapeConfigs();
void UpdateBoxConfig(const AZ::Vector3& scale);
void UpdateQuadConfig(const AZ::Vector3& scale);
void UpdateCapsuleConfig(const AZ::Vector3& scale);
void UpdateSphereConfig(const AZ::Vector3& scale);
void UpdateCylinderConfig(const AZ::Vector3& scale);
@ -102,7 +105,9 @@ namespace PhysX
void RefreshUiProperties();
AZ::u32 OnSubdivisionCountChange();
AZ::Crc32 SubdivisionCountVisibility();
AZ::Crc32 SubdivisionCountVisibility() const;
void OnSingleSidedChange();
AZ::Crc32 SingleSidedVisibility() const;
// AZ::Component
void Activate() override;
@ -137,6 +142,9 @@ namespace PhysX
AZ::Aabb GetColliderShapeAabb() override;
bool IsTrigger() override;
void UpdateTriggerSettings();
void UpdateSingleSidedSettings();
Physics::ColliderConfiguration m_colliderConfig; //!< Stores collision layers, whether the collider is a trigger, etc.
DebugDraw::Collider m_colliderDebugDraw; //!< Handles drawing the collider based on global and local
AzPhysics::SceneInterface* m_sceneInterface = nullptr;
@ -151,6 +159,9 @@ namespace PhysX
//! @note 16 is the number of subdivisions in the debug cylinder that is loaded as a mesh (not generated procedurally)
AZ::u8 m_subdivisionCount = 16;
mutable GeometryCache m_geometryCache; //!< Cached data for generating sample points inside the attached shape.
AZStd::optional<bool> m_previousIsTrigger; //!< Stores the previous trigger setting if the shape is changed to one which does not support triggers.
bool m_singleSided = false; //!< Used for 2d shapes like quad which may be treated as either single or doubled sided.
AZStd::optional<bool> m_previousSingleSided; //!< Stores the previous single sided setting when unable to support single-sided shapes (such as when used with a dynamic rigid body).
AzPhysics::SystemEvents::OnConfigurationChangedEvent::Handler m_physXConfigChangedHandler;
AzPhysics::SystemEvents::OnMaterialLibraryChangedEvent::Handler m_onMaterialLibraryChangedEventHandler;

@ -30,6 +30,7 @@ namespace PhysX
static const AZ::Crc32 Sphere = AZ_CRC("Sphere", 0x55f96687);
static const AZ::Crc32 PolygonPrism = AZ_CRC("PolygonPrism", 0xd6b50036);
static const AZ::Crc32 Cylinder = AZ_CRC("Cylinder", 0x9b045bea);
static const AZ::Crc32 Quad = AZ_CRC("QuadShape", 0x40d75e14);
} // namespace ShapeConstants
/// Component that provides a collider based on geometry from a shape component.

@ -23,6 +23,7 @@
#include <LmbrCentral/Shape/PolygonPrismShapeComponentBus.h>
#include <LmbrCentral/Shape/SphereShapeComponentBus.h>
#include <LmbrCentral/Shape/CompoundShapeComponentBus.h>
#include <LmbrCentral/Shape/QuadShapeComponentBus.h>
#include <PhysX/ForceRegionComponentBus.h>
#include <PhysX/PhysXLocks.h>
#include <PhysX/SystemComponentBus.h>
@ -452,21 +453,55 @@ namespace PhysXEditorTests
EXPECT_TRUE(aabb.GetMin().IsClose(translation - 0.5f * scale * boxDimensions));
}
void SetTrigger(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent, bool isTrigger)
void SetBoolValueOnComponent(AZ::Component* component, AZ::Crc32 name, bool value)
{
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
AzToolsFramework::InstanceDataHierarchy instanceDataHierarchy;
instanceDataHierarchy.AddRootInstance(editorShapeColliderComponent);
instanceDataHierarchy.AddRootInstance(component);
instanceDataHierarchy.Build(serializeContext, AZ::SerializeContext::ENUM_ACCESS_FOR_WRITE);
AzToolsFramework::InstanceDataHierarchy::InstanceDataNode* instanceNode =
instanceDataHierarchy.FindNodeByPartialAddress({ AZ_CRC("Trigger", 0x1a6b0f5d) });
instanceDataHierarchy.FindNodeByPartialAddress({ name });
if (instanceNode)
{
instanceNode->Write<bool>(isTrigger);
instanceNode->Write<bool>(value);
}
}
void SetTrigger(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent, bool isTrigger)
{
SetBoolValueOnComponent(editorShapeColliderComponent, AZ_CRC_CE("Trigger"), isTrigger);
}
bool GetBoolValueFromComponent(AZ::Component* component, AZ::Crc32 name)
{
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
AzToolsFramework::InstanceDataHierarchy instanceDataHierarchy;
instanceDataHierarchy.AddRootInstance(component);
instanceDataHierarchy.Build(serializeContext, AZ::SerializeContext::ENUM_ACCESS_FOR_READ);
AzToolsFramework::InstanceDataHierarchy::InstanceDataNode* instanceNode =
instanceDataHierarchy.FindNodeByPartialAddress({ name });
bool value = false;
instanceNode->Read<bool>(value);
return value;
}
bool IsTrigger(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent)
{
return GetBoolValueFromComponent(editorShapeColliderComponent, AZ_CRC_CE("Trigger"));
}
void SetSingleSided(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent, bool singleSided)
{
SetBoolValueOnComponent(editorShapeColliderComponent, AZ_CRC_CE("SingleSided"), singleSided);
}
bool IsSingleSided(PhysX::EditorShapeColliderComponent* editorShapeColliderComponent)
{
return GetBoolValueFromComponent(editorShapeColliderComponent, AZ_CRC_CE("SingleSided"));
}
EntityPtr CreateRigidBox(const AZ::Vector3& boxDimensions, const AZ::Vector3& position)
{
EntityPtr rigidBodyEditorEntity = CreateInactiveEditorEntity("RigidBodyEditorEntity");
@ -566,4 +601,147 @@ namespace PhysXEditorTests
EXPECT_THAT(aabb.GetMin(), UnitTest::IsClose(-0.5f * boxDimensions * parentScale));
}
class PhysXEditorParamBoolFixture
: public ::testing::WithParamInterface<bool>
, public PhysXEditorFixture
{
};
TEST_P(PhysXEditorParamBoolFixture, EditorShapeColliderComponent_ShapeColliderWithQuadShapeNonUniformlyScalesCorrectly)
{
// test both single and double-sided quad colliders
bool singleSided = GetParam();
EntityPtr editorEntity = CreateInactiveEditorEntity("QuadEntity");
editorEntity->CreateComponent(LmbrCentral::EditorQuadShapeComponentTypeId);
auto* shapeColliderComponent = editorEntity->CreateComponent<PhysX::EditorShapeColliderComponent>();
SetSingleSided(shapeColliderComponent, singleSided);
editorEntity->CreateComponent<AzToolsFramework::Components::EditorNonUniformScaleComponent>();
const auto entityId = editorEntity->GetId();
editorEntity->Activate();
LmbrCentral::QuadShapeComponentRequestBus::Event(entityId, &LmbrCentral::QuadShapeComponentRequests::SetQuadWidth, 1.2f);
LmbrCentral::QuadShapeComponentRequestBus::Event(entityId, &LmbrCentral::QuadShapeComponentRequests::SetQuadHeight, 0.8f);
// update the transform scale and non-uniform scale
AZ::TransformBus::Event(entityId, &AZ::TransformBus::Events::SetLocalUniformScale, 3.0f);
AZ::NonUniformScaleRequestBus::Event(entityId, &AZ::NonUniformScaleRequests::SetScale, AZ::Vector3(1.5f, 0.5f, 1.0f));
// make a game entity and check that its AABB is as expected
EntityPtr gameEntity = CreateActiveGameEntityFromEditorEntity(editorEntity.get());
AZ::Aabb aabb = gameEntity->FindComponent<PhysX::StaticRigidBodyComponent>()->GetAabb();
EXPECT_NEAR(aabb.GetMin().GetX(), -2.7f, 1e-3f);
EXPECT_NEAR(aabb.GetMin().GetY(), -0.6f, 1e-3f);
EXPECT_NEAR(aabb.GetMax().GetX(), 2.7f, 1e-3f);
EXPECT_NEAR(aabb.GetMax().GetY(), 0.6f, 1e-3f);
}
TEST_P(PhysXEditorParamBoolFixture, EditorShapeColliderComponent_TriggerSettingIsRememberedWhenSwitchingToQuadAndBack)
{
bool initialTriggerSetting = GetParam();
// create an editor entity with a box component (which does support trigger)
EntityPtr editorEntity = CreateInactiveEditorEntity("QuadEntity");
auto* boxShapeComponent = editorEntity->CreateComponent(LmbrCentral::EditorBoxShapeComponentTypeId);
auto* shapeColliderComponent = editorEntity->CreateComponent<PhysX::EditorShapeColliderComponent>();
SetTrigger(shapeColliderComponent, initialTriggerSetting);
editorEntity->Activate();
// the trigger setting should be what it was set to
EXPECT_EQ(IsTrigger(shapeColliderComponent), initialTriggerSetting);
// deactivate the entity and swap the box for a quad (which does not support trigger)
editorEntity->Deactivate();
editorEntity->RemoveComponent(boxShapeComponent);
auto* quadShapeComponent = editorEntity->CreateComponent(LmbrCentral::EditorQuadShapeComponentTypeId);
editorEntity->Activate();
// the trigger setting should now be false, because quad shape does not support triggers
EXPECT_FALSE(IsTrigger(shapeColliderComponent));
// swap back to a box shape
editorEntity->Deactivate();
editorEntity->RemoveComponent(quadShapeComponent);
editorEntity->AddComponent(boxShapeComponent);
editorEntity->Activate();
// the original trigger setting should have been remembered
EXPECT_EQ(IsTrigger(shapeColliderComponent), initialTriggerSetting);
// the quad shape component is no longer attached to the entity so won't be automatically cleared up
delete quadShapeComponent;
}
TEST_P(PhysXEditorParamBoolFixture, EditorShapeColliderComponent_SingleSidedSettingIsRememberedWhenAddingAndRemovingRigidBody)
{
bool initialSingleSidedSetting = GetParam();
// create an editor entity without a rigid body (that means both single-sided and double-sided quads are valid)
EntityPtr editorEntity = CreateInactiveEditorEntity("QuadEntity");
editorEntity->CreateComponent(LmbrCentral::EditorQuadShapeComponentTypeId);
auto* shapeColliderComponent = editorEntity->CreateComponent<PhysX::EditorShapeColliderComponent>();
SetSingleSided(shapeColliderComponent, initialSingleSidedSetting);
editorEntity->Activate();
// verify that the single sided setting matches the initial value
EXPECT_EQ(IsSingleSided(shapeColliderComponent), initialSingleSidedSetting);
// add an editor rigid body component (this should mean single-sided quads are not supported)
editorEntity->Deactivate();
auto rigidBodyComponent = editorEntity->CreateComponent<PhysX::EditorRigidBodyComponent>();
editorEntity->Activate();
EXPECT_FALSE(IsSingleSided(shapeColliderComponent));
// remove the editor rigid body component (the previous single-sided setting should be restored)
editorEntity->Deactivate();
editorEntity->RemoveComponent(rigidBodyComponent);
editorEntity->Activate();
EXPECT_EQ(IsSingleSided(shapeColliderComponent), initialSingleSidedSetting);
// the rigid body component is no longer attached to the entity so won't be automatically cleared up
delete rigidBodyComponent;
}
INSTANTIATE_TEST_CASE_P(PhysXEditorTest, PhysXEditorParamBoolFixture, ::testing::Bool());
TEST_F(PhysXEditorFixture, EditorShapeColliderComponent_SingleSidedQuadDoesNotCollideFromBelow)
{
// create an editor entity without a rigid body (that means both single-sided and double-sided quads are valid), positioned at the origin
EntityPtr editorQuadEntity = CreateInactiveEditorEntity("QuadEntity");
editorQuadEntity->CreateComponent(LmbrCentral::EditorQuadShapeComponentTypeId);
auto* shapeColliderComponent = editorQuadEntity->CreateComponent<PhysX::EditorShapeColliderComponent>();
SetSingleSided(shapeColliderComponent, true);
editorQuadEntity->Activate();
LmbrCentral::QuadShapeComponentRequestBus::Event(editorQuadEntity->GetId(), &LmbrCentral::QuadShapeComponentRequests::SetQuadHeight, 10.0f);
LmbrCentral::QuadShapeComponentRequestBus::Event(editorQuadEntity->GetId(), &LmbrCentral::QuadShapeComponentRequests::SetQuadWidth, 10.0f);
// add a second entity with a box collider and a rigid body, positioned below the quad
EntityPtr editorBoxEntity = CreateInactiveEditorEntity("BoxEntity");
editorBoxEntity->CreateComponent(LmbrCentral::BoxShapeComponentTypeId);
editorBoxEntity->CreateComponent<PhysX::EditorShapeColliderComponent>();
editorBoxEntity->CreateComponent<PhysX::EditorRigidBodyComponent>();
editorBoxEntity->Activate();
AZ::TransformBus::Event(editorBoxEntity->GetId(), &AZ::TransformBus::Events::SetWorldTranslation, -AZ::Vector3::CreateAxisZ());
EntityPtr gameQuadEntity = CreateActiveGameEntityFromEditorEntity(editorQuadEntity.get());
EntityPtr gameBoxEntity = CreateActiveGameEntityFromEditorEntity(editorBoxEntity.get());
// give the box enough upward velocity to rise above the level of the quad
// simulate for enough time that the box would have reached the top of its trajectory and fallen back past the starting point if
// it hadn't collided with the top of the quad
const int numTimesteps = 100;
Physics::RigidBodyRequestBus::Event(gameBoxEntity->GetId(), &Physics::RigidBodyRequests::SetLinearVelocity, AZ::Vector3::CreateAxisZ(6.0f));
PhysX::TestUtils::UpdateScene(m_defaultScene, AzPhysics::SystemConfiguration::DefaultFixedTimestep, numTimesteps);
// the box should travel through the base of the quad because it has no collision from that direction
// and land on the top surface of the quad, which does have collision
float finalHeight = 0.0f;
AZ::TransformBus::EventResult(finalHeight, gameBoxEntity->GetId(), &AZ::TransformBus::Events::GetWorldZ);
EXPECT_GT(finalHeight, 0.0f);
}
} // namespace PhysXEditorTests

Loading…
Cancel
Save