Overhaul physics test organization (#3684)

* Moved files

Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk>

* Fixes for moved files

Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk>

* Removed tmp file

Signed-off-by: Garcia Ruiz <aljanru@amazon.co.uk>

Co-authored-by: Garcia Ruiz <aljanru@amazon.co.uk>
This commit is contained in:
AMZN-AlexOteiza
2021-08-31 10:04:24 +01:00
committed by GitHub
parent d784ff8c57
commit 77e630085b
161 changed files with 316 additions and 1333 deletions
@@ -0,0 +1,76 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
# Test case ID : C100000
# Test Case Title : Check that Gravity works
# fmt:off
class Tests():
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
find_ball = ("Entity Ball found", "Ball not found")
gravity_started_disabled = ("Gravity started disabled", "Gravity didn't start disabled")
gravity_set_enabled = ("Gravity has been enabled", "Gravity wasn't enabled")
ball_fell = ("Ball fell", "Ball didn't fall")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
# fmt:on
def C100000_RigidBody_EnablingGravityWorksPoC():
import os
import sys
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
import azlmbr.legacy.general as general
import azlmbr.bus
helper.init_idle()
helper.open_level("Physics", "EnablingGravityWorks")
helper.enter_game_mode(Tests.enter_game_mode)
# 3) Retrieve entities
general.idle_wait_frames(1)
ball_id = general.find_game_entity("Ball")
Report.critical_result(Tests.find_ball, ball_id.IsValid(), "Entity must be found")
# 4) Make sure gravity is off from the start
gravity_enabled = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "IsGravityEnabled", ball_id)
Report.critical_result(Tests.gravity_started_disabled, not gravity_enabled)
# 5) Get the Z position before enabling the physics
class Ball:
z_start = None
Ball.z_start = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldZ", ball_id)
# 6) Activate gravity
Report.info("Enabling Gravity")
azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "ForceAwake", ball_id)
azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "SetGravityEnabled", ball_id, True)
gravity_enabled = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "IsGravityEnabled", ball_id)
def ball_fell():
"""
This is an example function to use with TestHelper.wait_for_condition
It may take no parameters and it contains no wait_idle_* because that is
already handled in TestHelper.wait_for_condition
"""
z_end = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldZ", ball_id)
return Ball.z_start > z_end
# 7) Validate ball fell by ensuring z is decreasing
fell_down = helper.wait_for_condition(ball_fell, 1.0)
Report.result(Tests.ball_fell, fell_down)
helper.exit_game_mode(Tests.exit_game_mode)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C100000_RigidBody_EnablingGravityWorksPoC)
@@ -0,0 +1,83 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
# Test case ID : C111111
# Test Case Title : Check that Gravity works
# fmt:off
class Tests:
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
find_ball = ("Entity Ball found", "Ball not found")
find_terrain = ("Entity Terrain found", "Terrain not found")
gravity_started_disabled = ("Gravity started disabled", "Gravity didn't start disabled")
gravity_set_enabled = ("Gravity has been enabled", "Gravity wasn't enabled")
ball_fell = ("Ball fell", "Ball didn't fall")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
# fmt:on
def C111111_RigidBody_EnablingGravityWorksUsingNotificationsPoC():
# Setup path
import os
import sys
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
import azlmbr.legacy.general as general
import azlmbr.bus
helper.init_idle()
# 1) Open level
helper.open_level("Physics", "EnablingGravityWorks")
# 2) Enter game mode
helper.enter_game_mode(Tests.enter_game_mode)
# 3) Retrieve entities
ball_id = general.find_game_entity("Ball")
Report.result(Tests.find_ball, ball_id.IsValid())
terrain_id = general.find_game_entity("Terrain")
Report.result(Tests.find_terrain, terrain_id.IsValid())
# 4) Make sure gravity is off from the start
gravity_enabled = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "IsGravityEnabled", ball_id)
Report.result(Tests.gravity_started_disabled, not gravity_enabled)
# 5) Activate gravity
Report.info("Enabling Gravity")
azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "ForceAwake", ball_id)
azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "SetGravityEnabled", ball_id, True)
gravity_enabled = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "IsGravityEnabled", ball_id)
Report.result(Tests.gravity_set_enabled, gravity_enabled)
# 6) Listen to collision events seconds so it falls down
class TouchGround:
value = False
def on_collision_begin(args):
other_id = args[0]
if other_id.Equal(terrain_id):
Report.info("Touched ground")
TouchGround.value = True
handler = azlmbr.physics.CollisionNotificationBusHandler()
handler.connect(ball_id)
handler.add_callback("OnCollisionBegin", on_collision_begin)
helper.wait_for_condition(lambda: TouchGround.value, 3.0)
Report.result(Tests.ball_fell, TouchGround.value)
# 7) Exit game mode
helper.exit_game_mode(Tests.exit_game_mode)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C111111_RigidBody_EnablingGravityWorksUsingNotificationsPoC)
@@ -0,0 +1,84 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
# Test case ID : C14861498
# Test Case Title : Confirm that when a PhysXCollider has no physics asset, the physics asset collider \
# shape throw an error
# fmt:off
class Tests():
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
found_entity = ("Entity was found", "Entity WAS NOT found")
warning_message_logged = ("The expected warning was logged", "The expected message was not logged")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
# fmt:on
def C14861498_ConfirmError_NoPxMesh():
"""
Summary:
This test looks for the presence of an error when an entity with a PhysXCollider has no physics mesh, but has its
collider shape set to a physics mesh.
Level Description:
One entity with a PhysXCollider with the collider shape set to "physics asset" and no actual physics mesh.
That's it!
Steps:
1) Load the level / enter game mode
2) Find the entity
3) Look for warning
4) Exit game mode
5) Close the editor
[Log Monitor] make sure error lines are present in the log
Expected Behavior:
The editor should open, load the level and (seemingly) instantly close. The two error lines specified should
print to the log.
:return: None
"""
import os
import sys
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
from editor_python_test_tools.utils import Tracer
import azlmbr.legacy.general as general
helper.init_idle()
with Tracer() as warning_tracer:
def has_physx_warning():
return warning_tracer.has_warnings and any(
'PhysX' in warningInfo.window and
'EditorColliderComponent' in warningInfo.message for warningInfo in warning_tracer.warnings)
# 1) Load level / enter game mode
helper.open_level("Physics", "C14861498_ConfirmError_NoPxMesh")
helper.enter_game_mode(Tests.enter_game_mode)
# 2) Find game entity
id = general.find_game_entity("test_entity")
Report.result(Tests.found_entity, id.IsValid())
# 3) Look for warning
helper.wait_for_condition(has_physx_warning, 1.0)
Report.result(Tests.warning_message_logged, has_physx_warning())
# 4) Exit game mode
helper.exit_game_mode(Tests.exit_game_mode)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C14861498_ConfirmError_NoPxMesh)
@@ -0,0 +1,72 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
Test case ID : C14861500
Test Case Title : Verify Default shape is Physics Asset
"""
# fmt: off
class Tests():
create_collider_entity = ("Created Collider Entity", "Failed to create Collider Entity")
add_physx_collider = ("PhysX Collider added", "Failed to add PhysX Collider")
shape_is_correct = ("PhysX Collider Shape is correct", "PhysX Collider Shape is not PhysicsAsset")
# fmt: on
def C14861500_DefaultSetting_ColliderShape():
"""
Summary:
Check the default for Shape on the PhysX Collider component
Expected Behavior:
When adding the PhysX Collider, the default Shape should be PhysX Asset
Test Steps:
1) Load empty level
2) Create an entity to hold the PhysX Shape Collider component
3) Add the PhysX Collider component
4) Check value of Shape property on PhysX Collider
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Helper Files
from editor_python_test_tools.editor_entity_utils import EditorEntity as Entity
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
# Open 3D Engine Imports
import azlmbr.legacy.general as general
PHYSICS_ASSET_INDEX = 7 # Hardcoded enum index value for Shape property
helper.init_idle()
# 1) Load empty level
helper.open_level("Physics", "Base")
# 2) Create an entity to hold the PhysX Shape Collider component
collider_entity = Entity.create_editor_entity("Collider")
Report.result(Tests.create_collider_entity, collider_entity.id.IsValid())
# 3) Add the PhysX Collider component
test_component = collider_entity.add_component("PhysX Collider")
Report.result(Tests.add_physx_collider, collider_entity.has_component("PhysX Collider"))
# 4) Check value of Shape property on PhysX Collider
value_to_test = test_component.get_component_property_value("Shape Configuration|Shape")
Report.result(Tests.shape_is_correct, value_to_test == PHYSICS_ASSET_INDEX)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C14861500_DefaultSetting_ColliderShape)
@@ -0,0 +1,93 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
Test case ID : C14861501
Test Case Title : Verify PxMesh is auto-assigned when Collider component is added after Rendering Mesh component
"""
# fmt: off
class Tests():
create_entity = ("Created test entity", "Failed to create test entity")
mesh_added = ("Added Mesh component", "Failed to add Mesh component")
physx_collider_added = ("Added PhysX Collider component", "Failed to add PhysX Collider component")
assign_mesh_asset = ("Assigned Mesh asset to Mesh component", "Failed to assign mesh asset to Mesh component")
automatic_shape_change = ("Shape was changed automatically", "Shape failed to change automatically")
# fmt: on
def C14861501_PhysXCollider_RenderMeshAutoAssigned():
"""
Summary:
Create entity with Mesh component and assign a render mesh to the Mesh component. Add Physics Collider component
and Verify that the physics mesh asset is auto-assigned.
Expected Behavior:
The physics asset in PhysX Collider component is auto-assigned
Test Steps:
1) Load the empty level
2) Create an entity
3) Add Mesh component
4) Assign a render mesh asset to Mesh component (the fbx mesh having both Static mesh and PhysX collision Mesh)
5) Add PhysX Collider component
6) The physics asset in PhysX Collider component is auto-assigned.
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Builtins
import os
# Helper Files
from editor_python_test_tools.editor_entity_utils import EditorEntity as Entity
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
from editor_python_test_tools.asset_utils import Asset
# Asset paths
STATIC_MESH = os.path.join("assets", "c14861501_physxcollider_rendermeshautoassigned", "spherebot", "r0-b_body.azmodel")
PHYSX_MESH = os.path.join(
"assets", "c14861501_physxcollider_rendermeshautoassigned", "spherebot", "r0-b_body.pxmesh"
)
helper.init_idle()
# 1) Load the empty level
helper.open_level("Physics", "Base")
# 2) Create an entity
test_entity = Entity.create_editor_entity("test_entity")
Report.result(Tests.create_entity, test_entity.id.IsValid())
# 3) Add Mesh component
mesh_component = test_entity.add_component("Mesh")
Report.result(Tests.mesh_added, test_entity.has_component("Mesh"))
# 4) Assign a render mesh asset to Mesh component (the fbx mesh having both Static mesh and PhysX collision Mesh)
mesh_asset = Asset.find_asset_by_path(STATIC_MESH)
mesh_component.set_component_property_value("Controller|Configuration|Mesh Asset", mesh_asset.id)
mesh_asset.id = mesh_component.get_component_property_value("Controller|Configuration|Mesh Asset")
Report.result(Tests.assign_mesh_asset, mesh_asset.get_path() == STATIC_MESH.replace(os.sep, "/"))
# 5) Add PhysX Collider component
test_component = test_entity.add_component("PhysX Collider")
Report.result(Tests.physx_collider_added, test_entity.has_component("PhysX Collider"))
# 6) The physics asset in PhysX Collider component is auto-assigned.
asset_id = test_component.get_component_property_value("Shape Configuration|Asset|PhysX Mesh")
test_asset = Asset(asset_id)
Report.result(Tests.automatic_shape_change, test_asset.get_path() == PHYSX_MESH.replace(os.sep, "/"))
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C14861501_PhysXCollider_RenderMeshAutoAssigned)
@@ -0,0 +1,95 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
Test case ID : C14861502
Test Case Title : Verify PxMesh is auto-assigned in collider when Mesh is assigned in Rendering Mesh component
"""
# fmt: off
class Tests():
create_entity = ("Created test entity", "Failed to create test entity")
mesh_added = ("Added Mesh component", "Failed to add Mesh component")
physx_collider_added = ("Added PhysX Collider component", "Failed to add PhysX Collider component")
shape_default_at_start = ("Shape was correct initially", "Default shape was not correct")
automatic_shape_change = ("Shape was changed automatically", "Shape failed to change automatically")
# fmt: on
def C14861502_PhysXCollider_AssetAutoAssigned():
"""
Summary:
Create entity with Mesh and PhysX Collider components, then assign a render mesh to the Mesh component
Expected Behavior:
The physics asset in PhysX Collider component is auto-assigned after adding the render mesh
Test Steps:
1) Load the empty level
2) Create an entity
3) Add Mesh and PhysX Collider component
4) Verify no physics asset is auto-assigned.
5) Assign a render mesh asset to Mesh component (the fbx mesh having both Static mesh and PhysX collision Mesh)
6) The physics asset in PhysX Collider component is auto-assigned.
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Builtins
import os
# Helper Files
from editor_python_test_tools.editor_entity_utils import EditorEntity as Entity
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
from editor_python_test_tools.asset_utils import Asset
# Open 3D Engine Imports
import azlmbr.legacy.general as general
MESH_ASSET_PATH = os.path.join("Objects", "SphereBot", "r0-b_body.azmodel")
MESH_PROPERTY_PATH = "Controller|Configuration|Mesh Asset"
TESTED_PROPERTY_PATH = "Shape Configuration|Asset|PhysX Mesh"
helper.init_idle()
# 1) Load the empty level
helper.open_level("Physics", "Base")
# 2) Create an entity
test_entity = Entity.create_editor_entity("test_entity")
Report.result(Tests.create_entity, test_entity.id.IsValid())
# 3) Add Mesh and PhysX Collider component
mesh_component = test_entity.add_component("Mesh")
Report.result(Tests.mesh_added, test_entity.has_component("Mesh"))
test_component = test_entity.add_component("PhysX Collider")
Report.result(Tests.physx_collider_added, test_entity.has_component("PhysX Collider"))
# 4) Verify no physics asset is auto-assigned
value_to_test = test_component.get_component_property_value(TESTED_PROPERTY_PATH)
Report.result(Tests.shape_default_at_start, value_to_test == azlmbr.asset.AssetId())
# 5) Assign a render mesh asset to Mesh component (the fbx mesh having both Static mesh and PhysX collision Mesh)
asset_value = Asset.find_asset_by_path(MESH_ASSET_PATH)
mesh_component.set_component_property_value(MESH_PROPERTY_PATH, asset_value.id)
# 6) The physics asset in PhysX Collider component is auto-assigned.
general.idle_wait(1.0) # Gives the script a moment for the value to update before grabbing it
value_to_test = test_component.get_component_property_value(TESTED_PROPERTY_PATH)
asset = Asset(value_to_test)
Report.result(Tests.automatic_shape_change, "r0-b_body" in asset.get_path())
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C14861502_PhysXCollider_AssetAutoAssigned)
@@ -0,0 +1,104 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
Test case ID : C14861504
Test Case Title : Verify if Rendering Mesh does not have a PhysX Collision Mesh fbx, then PxMesh is not auto-assigned
"""
# fmt: off
class Tests():
create_entity = ("Created test entity", "Failed to create test entity")
mesh_added = ("Added Mesh component", "Failed to add Mesh component")
physx_collider_added = ("Added PhysX Collider component", "Failed to add PhysX Collider component")
assign_mesh_asset = ("Assigned Mesh asset to Mesh component", "Failed to assign mesh asset to Mesh component")
shape_not_assigned = ("Shape is not auto assigned", "Shape auto assigned unexpectedly")
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
warnings_found = ("Warnings found in logs", "No warnings found in logs")
# fmt: on
def C14861504_RenderMeshAsset_WithNoPxAsset():
"""
Summary:
Create entity with Mesh component and assign a render mesh that has no physics asset to the Mesh component.
Add Physics Collider component and Verify that the physics mesh asset is not auto-assigned.
Expected Behavior:
Following warning is logged in Game mode:
"(PhysX) - EditorColliderComponent::BuildGameEntity. No asset assigned to Collider Component. Entity: <Entity Name>"
Test Steps:
1) Load the empty level
2) Create an entity
3) Add Mesh component
4) Assign a render mesh asset to Mesh component (the fbx mesh having only Static mesh and no PxMesh)
5) Add PhysX Collider component
6) The physics asset in PhysX Collider component is not auto-assigned.
7) Enter GameMode and check for warnings
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Builtins
import os
# Helper Files
from editor_python_test_tools.editor_entity_utils import EditorEntity as Entity
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
from editor_python_test_tools.utils import Tracer
from editor_python_test_tools.asset_utils import Asset
# Open 3D Engine Imports
import azlmbr.asset as azasset
# Asset paths
STATIC_MESH = os.path.join("assets", "c14861504_rendermeshasset_withnopxasset", "test_asset.azmodel")
helper.init_idle()
# 1) Load the empty level
helper.open_level("Physics", "Base")
# 2) Create an entity
test_entity = Entity.create_editor_entity("test_entity")
Report.result(Tests.create_entity, test_entity.id.IsValid())
# 3) Add Mesh component
mesh_component = test_entity.add_component("Mesh")
Report.result(Tests.mesh_added, test_entity.has_component("Mesh"))
# 4) Assign a render mesh asset to Mesh component (the fbx mesh having both Static mesh and PhysX collision Mesh)
mesh_asset = Asset.find_asset_by_path(STATIC_MESH)
mesh_component.set_component_property_value("Controller|Configuration|Mesh Asset", mesh_asset.id)
mesh_asset.id = mesh_component.get_component_property_value("Controller|Configuration|Mesh Asset")
Report.result(Tests.assign_mesh_asset, mesh_asset.get_path() == STATIC_MESH.replace(os.sep, "/"))
# 5) Add PhysX Collider component
test_component = test_entity.add_component("PhysX Collider")
Report.result(Tests.physx_collider_added, test_entity.has_component("PhysX Collider"))
# 6) The physics asset in PhysX Collider component is not auto-assigned.
asset_id = test_component.get_component_property_value("Shape Configuration|Asset|PhysX Mesh")
# Comparing asset_id with Null/Invalid asset azlmbr.asset.AssetId() to check that asset is not auto assigned
Report.result(Tests.shape_not_assigned, asset_id == azasset.AssetId())
# 7) Enter GameMode and check for warnings
with Tracer() as section_tracer:
helper.enter_game_mode(Tests.enter_game_mode)
# Checking if warning exist and the exact warning is caught in the expected lines in Test file
Report.result(Tests.warnings_found, section_tracer.has_warnings)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C14861504_RenderMeshAsset_WithNoPxAsset)
@@ -0,0 +1,94 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
Test case ID : C19578018
Test Case Title : Verify that a shape collider component with no shape component indicates a missing service
"""
# fmt: off
class Tests():
create_collider_entity = ("Created Collider Entity", "Failed to create Collider Entity")
add_physx_shape_collider = ("PhysX Shape Collider added", "Failed to add PhysX Shape Collider")
collider_component_inactive = ("Collider component is Inactive", "Collider component is Active")
add_shape_component = ("Shape component added", "Failed to add Shape component")
collider_component_active = ("Collider component is active", "Collider component is inactive")
# fmt: on
def C19578018_ShapeColliderWithNoShapeComponent():
"""
Summary:
Create an Entity with PhysX Shape Collider component and verify that PhysX Shape Collider Component
is inactive without shape component.
Expected Behavior:
The PhysX Shape Collider component should be inactive.
Verify that after a shape component is added, the warning goes away.
Test Steps:
1) Load the level
2) Add an entity with a PhysX Shape Collider component.
3) Validate Collider Entity
4) Validate PhysX Shape Collider component is inactive.
5) Add Shape component to Entity
6) Validate PhysX Shape Collider component is Active.
7) Close the editor
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Built-in Imports
# Helper Imports
from editor_python_test_tools.utils import Report
from editor_python_test_tools.editor_entity_utils import EditorEntity
from editor_python_test_tools.utils import TestHelper as helper
# Open 3D Engine Imports
import azlmbr.bus as bus
import azlmbr.editor as editor
def is_component_active(component_id) -> bool:
"""
Used to check if component is Active
:return: boolean, True if component is active, else False
"""
return editor.EditorComponentAPIBus(bus.Broadcast, "IsComponentEnabled", component_id)
helper.init_idle()
# 1) Load the level
helper.open_level("Physics", "Base")
# 2) Add an entity with a PhysX Shape Collider component.
collider = EditorEntity.create_editor_entity("Collider")
physx_component = collider.add_component("PhysX Shape Collider")
# 3) Validate Collider Entity
Report.result(Tests.create_collider_entity, collider.id.IsValid())
# 4) Validate PhysX Shape Collider component is inactive.
Report.result(Tests.add_physx_shape_collider, collider.has_component("PhysX Shape Collider"))
Report.result(Tests.collider_component_inactive, not is_component_active(physx_component.id))
# 5) Add Shape component to Entity
collider.add_component("Box Shape")
Report.result(Tests.add_shape_component, collider.has_component("Box Shape"))
# 6) Validate PhysX Shape Collider component is Active.
Report.result(Tests.collider_component_active, is_component_active(physx_component.id))
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C19578018_ShapeColliderWithNoShapeComponent)
@@ -0,0 +1,92 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
Test case ID : C19578021
Test Case Title : Verify that a shape collider component may be added to an entity along with one or more PhysX collider components
"""
# fmt: off
class Tests():
create_collider_entity = ("Created Collider Entity", "Failed to create Collider Entity")
add_physx_shape_collider = ("PhysX Shape Collider added", "Failed to add PhysX Shape Collider")
add_box_shape = ("Box Shape added", "Failed to add Box Shape")
add_physx_collider = ("PhysX Collider added", "Failed to add PhysX Collider")
no_warnings_found = ("Trace found no warnings", "One or more components has been removed")
# fmt: on
def C19578021_ShapeCollider_CanBeAdded():
"""
Summary:
Adding a PhysX Collider component when a PhysX Shape Collider and Box Shape components are already present
Expected Behavior:
When adding the PhysX Collider, there should be no warnings in the entity outliner
Test Steps:
1) Load the empty level
2) Create an entity
3) Add the PhysX Shape Collider and a Box Shape components
4) Start the Tracer to catch any warnings while adding the PhysX Collider
5) Add the PhysX Collider component
6) Verify there are no warnings in the entity outliner
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Helper Files
from editor_python_test_tools.editor_entity_utils import EditorEntity as Entity
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
from editor_python_test_tools.utils import Tracer
# Open 3D Engine Imports
import azlmbr.legacy.general as general
helper.init_idle()
# 1) Load the empty level
helper.open_level("Physics", "Base")
# 2) Create an entity
collider_entity = Entity.create_editor_entity("Collider")
Report.result(Tests.create_collider_entity, collider_entity.id.IsValid())
# 3) Add the PhysX Shape Collider and a Box Shape components
collider_entity.add_component("PhysX Shape Collider")
Report.result(Tests.add_physx_shape_collider, collider_entity.has_component("PhysX Shape Collider"))
collider_entity.add_component("Box Shape")
Report.result(Tests.add_box_shape, collider_entity.has_component("Box Shape"))
# 4) Start the Tracer to catch any warnings while adding the PhysX Collider
with Tracer() as section_tracer:
# 5) Add the PhysX Collider component
collider_entity.add_component("PhysX Collider")
Report.result(Tests.add_physx_collider, collider_entity.has_component("PhysX Collider"))
# 6) Verify there are no warnings in the entity outliner
success_condition = not section_tracer.has_warnings and not section_tracer.has_errors
Report.result(Tests.no_warnings_found, success_condition)
if not success_condition:
exception_str = ""
if section_tracer.has_warnings:
exception_str += f"Warnings found: {section_tracer.warnings}\n"
if section_tracer.has_errors:
exception_str += f"Errors found: {section_tracer.errors}"
Report.failure(exception_str)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C19578021_ShapeCollider_CanBeAdded)
@@ -0,0 +1,98 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
Test case ID : C19723164
Test Case Title : Verify that if we had 512 shape colliders in the level, the level does not crash
"""
# fmt: off
class Tests():
all_entities_created = ("All 512 entities have been created", "Failed to create all 512 entities")
game_mode_entered = ("Entered Game Mode", "Failed to enter Game Mode")
game_mode_exited = ("Exited Game Mode", "Failed to exit Game Mode")
# fmt: on
def C19723164_ShapeColliders_WontCrashEditor():
"""
Summary:
Create 512 entities with shape colliders and verify stability
Expected Behavior:
After 512 Shape Collider entities exist, the editor should not crash or dip in FPS
Test Steps:
1) Load the empty level
2) Create 512 entities with PhysX Shape Collider and Sphere Shape components
3) Enter/Exit game mode and wait to see if editor crashes
4) Close the editor
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Helper Files
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
from editor_python_test_tools.editor_entity_utils import EditorEntity as Entity
# Open 3D Engine Imports
import azlmbr.legacy.general as general
def idle_editor_for_check():
"""
This will be used to verify that the editor has not crashed by increasing the duration the editor is kept open
"""
# Enter game mode
helper.enter_game_mode(Tests.game_mode_entered)
# Wait 60 frames
general.idle_wait_frames(60)
# Exit game mode
helper.exit_game_mode(Tests.game_mode_exited)
# Wait 60 frames more
general.idle_wait_frames(60)
helper.init_idle()
# 1) Load the empty level
helper.open_level("Physics", "Base")
# 2) Create 512 entities with PhysX Shape Collider and Sphere Shape components
entity_failure = False
for i in range(1, 513):
# Create Entity
entity = Entity.create_editor_entity(f"Entity_{i}")
# Add components
entity.add_component("PhysX Shape Collider")
if i % 3 == 0:
shape_component_name = "Capsule Shape"
elif i % 2 == 0:
shape_component_name = "Box Shape"
else:
shape_component_name = "Sphere Shape"
entity.add_component(shape_component_name)
# Verify the entity contains the components
components_added = entity.has_component("PhysX Shape Collider") and entity.has_component(shape_component_name)
if not components_added:
entity_failure = True
Report.info(f"Entity_{i} failed to add either PhysX Shape Collider or {shape_component_name}")
Report.result(Tests.all_entities_created, not entity_failure)
# 3) Enter/Exit game mode and wait to see if editor crashes
idle_editor_for_check()
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C19723164_ShapeColliders_WontCrashEditor)
@@ -0,0 +1,136 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
# Test case ID : C24308873
# Test Case Title : Check that cylinder shape collider collides with terrain
# A cylinder is suspended slightly over PhysX Terrain to check that it collides when dropped
# fmt: off
class Tests():
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
find_cylinder = ("Cylinder entity found", "Cylinder entity not found")
create_terrain = ("Terrain entity created successfully", "Failed to create Terrain Entity")
find_terrain = ("Terrain entity found", "Terrain entity not found")
add_physx_shape_collider = ("Added PhysX Shape Collider", "Failed to add PhysX Shape Collider")
add_box_shape = ("Added Box Shape", "Failed to add Box Shape")
cylinder_above_terrain = ("Cylinder position above ground", "Cylinder is not above the ground")
time_out = ("No time out occurred", "A time out occurred, please validate level setup")
touched_ground = ("Touched ground before time out", "Did not touch ground before time out")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
# fmt: on
def C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain():
"""
Summary:
Runs a test to make sure that a PhysX Rigid Body and Cylinder Shape Collider can successfully collide with a PhysX Terrain entity.
Level Description:
A cylinder with rigid body and collider is positioned above a PhysX terrain.
Expected Outcome:
Once game mode is entered, the cylinder should fall toward and collide with the terrain.
Steps:
1) Open level and create terrain Entity.
2) Enter Game Mode.
3) Retrieve entities and positions
4) Wait for cylinder to collide with terrain OR time out
5) Exit game mode
6) Close the editor
:return:
"""
import os
import sys
from editor_python_test_tools.editor_entity_utils import EditorEntity
import azlmbr.legacy.general as general
import azlmbr.bus
import azlmbr.math as math
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
# Global time out
TIME_OUT = 1.0
# 1) Open level
helper.init_idle()
helper.open_level("Physics", "C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain")
# Create terrain entity
terrain = EditorEntity.create_editor_entity_at([30.0, 30.0, 33.96], "Terrain")
Report.result(Tests.create_terrain, terrain.id.IsValid())
terrain.add_component("PhysX Shape Collider")
Report.result(Tests.add_physx_shape_collider, terrain.has_component("PhysX Shape Collider"))
box_shape_component = terrain.add_component("Box Shape")
Report.result(Tests.add_box_shape, terrain.has_component("Box Shape"))
box_shape_component.set_component_property_value("Box Shape|Box Configuration|Dimensions",
math.Vector3(1024.0, 1024.0, 0.01))
# 2)Enter game mode
helper.enter_game_mode(Tests.enter_game_mode)
# 3) Retrieve entities and positions
cylinder_id = general.find_game_entity("PhysX_Cylinder")
Report.critical_result(Tests.find_cylinder, cylinder_id.IsValid())
terrain_id = general.find_game_entity("Terrain")
Report.critical_result(Tests.find_terrain, terrain_id.IsValid())
cylinder_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", cylinder_id)
#Cylinder position is 64,84,35
terrain_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", terrain_id)
Report.info_vector3(cylinder_pos, "Cylinder:")
Report.info_vector3(terrain_pos, "Terrain:")
Report.critical_result(
Tests.cylinder_above_terrain,
(cylinder_pos.z - terrain_pos.z) > 0.5,
"Please make sure the cylinder entity is set above the terrain",
)
# Enable gravity (just in case it is not enabled)
if not azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "IsGravityEnabled", cylinder_id):
azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "SetGravityEnabled", cylinder_id, True)
class TouchGround:
value = False
# Collision event handler
def on_collision_begin(args):
other_id = args[0]
if other_id.Equal(terrain_id):
Report.info("Touched ground")
TouchGround.value = True
# Assign event handler to cylinder
handler = azlmbr.physics.CollisionNotificationBusHandler()
handler.connect(cylinder_id)
handler.add_callback("OnCollisionBegin", on_collision_begin)
# 4) Wait for the cylinder to hit the ground OR time out
test_completed = helper.wait_for_condition((lambda: TouchGround.value), TIME_OUT)
Report.critical_result(Tests.time_out, test_completed)
Report.result(Tests.touched_ground, TouchGround.value)
# 5) Exit game mode
helper.exit_game_mode(Tests.exit_game_mode)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C24308873_CylinderShapeCollider_CollidesWithPhysXTerrain)
@@ -0,0 +1,361 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
# Test case ID : C3510644
# Test Case Title : Check that the collision layer and collision group of the terrain can be changed
# and the collision behavior of the terrain changes accordingly
# fmt: off
class Tests:
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
box_1_a_valid = ("Box 1 A has been validated", "Box 1 A COULD NOT be validated")
box_2_a_valid = ("Box 2 A has been validated", "Box 2 A COULD NOT be validated")
terrain_a_valid = ("Terrain A has been validated", "Terrain A COULD NOT be validated")
box_1_b_valid = ("Box 1 B has been validated", "Box 1 B COULD NOT be validated")
box_2_b_valid = ("Box 2 B has been validated", "Box 2 B COULD NOT be validated")
terrain_b_valid = ("Terrain B has been validated", "Terrain B COULD NOT be validated")
box_1_a_pos_found = ("Box 1 A position found", "Box 1 A position NOT found")
box_2_a_pos_found = ("Box 2 A position found", "Box 2 A position NOT found")
terrain_a_pos_found = ("Terrain A position found", "Terrain A position NOT found")
box_1_b_pos_found = ("Box 1 B position found", "Box 1 B position NOT found")
box_2_b_pos_found = ("Box 2 B position found", "Box 2 B position NOT found")
terrain_b_pos_found = ("Terrain B position found", "Terrain B position NOT found")
box_1_a_did_collide_with_terrain = ("Box 1 A did collide with terrain", "Box 1 A DID NOT collide with terrain")
box_1_a_did_not_pass_through_terrain = ("Box 1 A did not fall past the terrain", "Box 1 A DID fall past the terrain")
box_2_a_did_not_collide_with_terrain = ("Box 2 A did not collide with terrain", "Box 2 A DID collide with terrain")
box_2_a_did_pass_through_terrain = ("Box 2 A did fall past the terrain", "Box 2 A DID NOT fall past the terrain")
box_1_b_did_not_collide_with_terrain = ("Box 1 B did not collide with terrain", "Box 1 B DID collide with terrain")
box_1_b_did_pass_through_terrain = ("Box 1 B did fall past the terrain", "Box 1 B DID NOT fall past the terrain")
box_2_b_did_collide_with_terrain = ("Box 2 B did collide with terrain", "Box 2 B DID NOT collide with terrain")
box_2_b_did_not_pass_through_terrain = ("Box 2 B did not fall past the terrain", "Box 2 B DID fall past the terrain")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
# fmt: on
def C3510644_Collider_CollisionGroups():
# type: () -> None
"""
Summary:
Runs an automated test to ensure PhysX collision groups dictate whether collisions happen or not.
The test has two phases (A and B) for testing collision groups under different circumstances. Phase A
is run first and upon success Phase B starts.
Level Description:
Entities can be divided into 2 groups for the two phases, A and B. Each phase has identical entities with exception
to Terrain, where Terrain_A has a collision group/layer set for demo_group1/demo1 and Terrain_B has a collision
group/layer set for demo_group2/demo2.
Each Phase has two boxes, Box_1 and Box_2, where each box has it's collision group/layer set to it's number
(1 or 2). Each box is positioned just above the Terrain with gravity enabled.
All entities for Phase B are deactivated by default. If Phase A is setup and executed successfully it's
entities are deactivated and Phase B's entities are activated and validated before running the Phase B test.
Expected behavior:
When Phase A starts, it's two boxes should fall toward the terrain. Once the boxes' behavior is validated the
entities from Phase A are deactivated and Phase B's entities are activated. Like in Phase A, the boxes in Phase B
should fall towards the terrain. If all goes as expected Box_1_A and Box_2_B should collide with teh terrain, and
Box_2A and Box_1_B should fall through the terrain.
Test Steps:
0) [Define helper classes and functions]
1) Load the level
2) Enter game mode
3) Retrieve and validate entities
4) Phase A
a) set up
b) execute test
c) log results (deactivate Phase A entities)
5) Phase B
a) set up (activate Phase B entities)
b) execute test
c) log results
6) close editor
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
- The level for this test uses two PhysX Terrains and must be run with cmdline argument "-autotest_mode"
to suppress the warning for having multiple terrains.
:return: None
"""
import os
import sys
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
import azlmbr.legacy.general as general
import azlmbr.bus
import azlmbr
# ******* Helper Classes ********
# Phase A's test results
class PhaseATestData:
total_results = 2
box_1_collided = False
box_1_fell_through = True
box_2_collided = False
box_2_fell_through = False
box_1 = None
box_2 = None
terrain = None
box_1_pos = None
box_2_pos = None
terrain_pos = None
@staticmethod
# Quick check for validating results for Phase A
def valid():
return (
PhaseATestData.box_1_collided
and PhaseATestData.box_2_fell_through
and not PhaseATestData.box_1_fell_through
and not PhaseATestData.box_2_collided
)
# Phase B's test results
class PhaseBTestData:
total_results = 2
box_1_collided = False
box_1_fell_through = False
box_2_collided = False
box_2_fell_through = True
box_1 = None
box_2 = None
terrain = None
box_1_pos = None
box_2_pos = None
terrain_pos = None
@staticmethod
# Quick check for validating results for Phase B
def valid():
return (
not PhaseBTestData.box_1_collided
and not PhaseBTestData.box_2_fell_through
and PhaseBTestData.box_1_fell_through
and PhaseBTestData.box_2_collided
)
# **** Helper Functions ****
# ** Validation helpers **
# Attempts to validate an entity based on the name parameter
def validate_entity(entity_name, msg_tuple):
# type: (str, (str, str)) -> EntityId
entity_id = general.find_game_entity(entity_name)
Report.critical_result(msg_tuple, entity_id.IsValid())
return entity_id
# Attempts to retrieve an entity's initial position and logs result
def validate_initial_position(entity_id, msg_tuple):
# type: (EntityId, (str, str)) -> azlmbr.math.Vector3
# Attempts to validate and return the entity's initial position.
# logs the result to Report.result() using the tuple parameter
pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", entity_id)
valid = not (pos is None or pos.IsZero())
entity_name = azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "GetEntityName", entity_id)
Report.critical_result(msg_tuple, valid)
Report.info_vector3(pos, "{} initial position:".format(entity_name))
return pos
# ** Phase completion checks checks **
# Checks if we are done collecting data for phase A
def done_collecting_results_a():
# type: () -> bool
# Update positions
PhaseATestData.box_1_pos = azlmbr.components.TransformBus(
azlmbr.bus.Event, "GetWorldTranslation", PhaseATestData.box_1
)
PhaseATestData.box_2_pos = azlmbr.components.TransformBus(
azlmbr.bus.Event, "GetWorldTranslation", PhaseATestData.box_2
)
# Check for boxes to fall through terrain
if PhaseATestData.box_1_pos.z < PhaseATestData.terrain_pos.z:
PhaseATestData.box_1_fell_through = True
else:
PhaseATestData.box_1_fell_through = False
if PhaseATestData.box_2_pos.z < PhaseATestData.terrain_pos.z:
PhaseATestData.box_2_fell_through = True
else:
PhaseATestData.box_2_fell_through = False
results = 0
if PhaseATestData.box_1_collided or PhaseATestData.box_1_fell_through:
results += 1
if PhaseATestData.box_2_collided or PhaseATestData.box_2_fell_through:
results += 1
return results == PhaseATestData.total_results
# Checks if we are done collecting data for phase B
def done_collecting_results_b():
# type: () -> bool
# Update positions
PhaseBTestData.box_1_pos = azlmbr.components.TransformBus(
azlmbr.bus.Event, "GetWorldTranslation", PhaseBTestData.box_1
)
PhaseBTestData.box_2_pos = azlmbr.components.TransformBus(
azlmbr.bus.Event, "GetWorldTranslation", PhaseBTestData.box_2
)
# Check for boxes to fall through terrain
if PhaseBTestData.box_1_pos.z < PhaseBTestData.terrain_pos.z:
PhaseBTestData.box_1_fell_through = True
else:
PhaseBTestData.box_1_fell_through = False
if PhaseBTestData.box_2_pos.z < PhaseBTestData.terrain_pos.z:
PhaseBTestData.box_2_fell_through = True
else:
PhaseBTestData.box_2_fell_through = False
results = 0
if PhaseBTestData.box_1_collided or PhaseBTestData.box_1_fell_through:
results += 1
if PhaseBTestData.box_2_collided or PhaseBTestData.box_2_fell_through:
results += 1
return results == PhaseBTestData.total_results
# **** Event Handlers ****
# Collision even handler for Phase A
def on_collision_begin_a(args):
# type: ([EntityId]) -> None
collider_id = args[0]
if (not PhaseATestData.box_1_collided) and PhaseATestData.box_1.Equal(collider_id):
Report.info("Box_1_A / Terrain_A collision detected")
PhaseATestData.box_1_collided = True
if (not PhaseATestData.box_2_collided) and PhaseATestData.box_2.Equal(collider_id):
Report.info("Box_2_A / Terrain_A collision detected")
PhaseATestData.box_2_collided = True
# Collision event handler for Phase B
def on_collision_begin_b(args):
# type: ([EntityId]) -> None
collider_id = args[0]
if (not PhaseBTestData.box_1_collided) and PhaseBTestData.box_1.Equal(collider_id):
Report.info("Box_1_B / Terrain_B collision detected")
PhaseBTestData.box_1_collided = True
if (not PhaseBTestData.box_2_collided) and PhaseBTestData.box_2.Equal(collider_id):
Report.info("Box_2_B / Terrain_B collision detected")
PhaseBTestData.box_2_collided = True
TIME_OUT = 1.5
# 1) Open level
helper.init_idle()
helper.open_level("Physics", "C3510644_Collider_CollisionGroups")
# 2) Enter game mode
helper.enter_game_mode(Tests.enter_game_mode)
# 3) Retrieve and validate entities
PhaseATestData.box_1 = validate_entity("Box_1_A", Tests.box_1_a_valid)
PhaseATestData.box_2 = validate_entity("Box_2_A", Tests.box_2_a_valid)
PhaseATestData.terrain = validate_entity("Terrain_Entity_A", Tests.terrain_a_valid)
PhaseBTestData.box_1 = validate_entity("Box_1_B", Tests.box_1_b_valid)
PhaseBTestData.box_2 = validate_entity("Box_2_B", Tests.box_2_b_valid)
PhaseBTestData.terrain = validate_entity("Terrain_Entity_B", Tests.terrain_b_valid)
# Make sure Phase B objects are disabled
azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "DeactivateGameEntity", PhaseBTestData.box_1)
azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "DeactivateGameEntity", PhaseBTestData.box_2)
azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "DeactivateGameEntity", PhaseBTestData.terrain)
# 4) *********** Phase A *****************
# 4.a) ** Set Up **
Report.info(" **** Beginning Phase A **** ")
# Locate Phase A entities
PhaseATestData.box_1_pos = validate_initial_position(PhaseATestData.box_1, Tests.box_1_a_pos_found)
PhaseATestData.box_2_pos = validate_initial_position(PhaseATestData.box_2, Tests.box_2_a_pos_found)
PhaseATestData.terrain_pos = validate_initial_position(PhaseATestData.terrain, Tests.terrain_a_pos_found)
# Assign Phase A event handler
handler_a = azlmbr.physics.CollisionNotificationBusHandler()
handler_a.connect(PhaseATestData.terrain)
handler_a.add_callback("OnCollisionBegin", on_collision_begin_a)
# 4.b) Execute Phase A
if not helper.wait_for_condition(done_collecting_results_a, TIME_OUT):
Report.info("Phase A timed out: make sure the level is set up properly or adjust time out threshold")
# 4.c) Log results for Phase A
Report.result(Tests.box_1_a_did_collide_with_terrain, PhaseATestData.box_1_collided)
Report.result(Tests.box_1_a_did_not_pass_through_terrain, not PhaseATestData.box_1_fell_through)
Report.info_vector3(PhaseATestData.box_1_pos, "Box_1_A's final position:")
Report.result(Tests.box_2_a_did_pass_through_terrain, PhaseATestData.box_2_fell_through)
Report.result(Tests.box_2_a_did_not_collide_with_terrain, not PhaseATestData.box_2_collided)
Report.info_vector3(PhaseATestData.box_2_pos, "Box_2_A's final position:")
if not PhaseATestData.valid():
Report.info("Phase A failed test")
# Deactivate entities for Phase A
azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "DeactivateGameEntity", PhaseATestData.box_1)
azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "DeactivateGameEntity", PhaseATestData.box_2)
azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "DeactivateGameEntity", PhaseATestData.terrain)
# 5) *********** Phase B *****************
# 5.a) ** Set Up **
Report.info(" *** Beginning Phase B *** ")
# Activate entities for Phase B
azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "ActivateGameEntity", PhaseBTestData.box_1)
azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "ActivateGameEntity", PhaseBTestData.box_2)
azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "ActivateGameEntity", PhaseBTestData.terrain)
# Initialize positions for Phase B
PhaseBTestData.box_1_pos = validate_initial_position(PhaseBTestData.box_1, Tests.box_1_b_pos_found)
PhaseBTestData.box_2_pos = validate_initial_position(PhaseBTestData.box_2, Tests.box_2_b_pos_found)
PhaseBTestData.terrain_pos = validate_initial_position(PhaseBTestData.terrain, Tests.terrain_b_pos_found)
# Assign Phase B event handler
handler_b = azlmbr.physics.CollisionNotificationBusHandler()
handler_b.connect(PhaseBTestData.terrain)
handler_b.add_callback("OnCollisionBegin", on_collision_begin_b)
# 5.b) Execute Phase B
if not helper.wait_for_condition(done_collecting_results_b, TIME_OUT):
Report.info("Phase B timed out: make sure the level is set up properly or adjust time out threshold")
# 5.c) Log results for Phase B
Report.result(Tests.box_1_b_did_not_collide_with_terrain, not PhaseBTestData.box_1_collided)
Report.result(Tests.box_1_b_did_pass_through_terrain, PhaseBTestData.box_1_fell_through)
Report.info_vector3(PhaseBTestData.box_1_pos, "Box_1_B's final position:")
Report.result(Tests.box_2_b_did_not_pass_through_terrain, not PhaseBTestData.box_2_fell_through)
Report.result(Tests.box_2_b_did_collide_with_terrain, PhaseBTestData.box_2_collided)
Report.info_vector3(PhaseBTestData.box_2_pos, "Box_2_B's final position:")
if not PhaseBTestData.valid():
Report.info("Phase B failed test")
# 6) Exit Game mode
helper.exit_game_mode(Tests.exit_game_mode)
Report.info(" **** TEST FINISHED ****")
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C3510644_Collider_CollisionGroups)
@@ -0,0 +1,109 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
Test case ID : C4044695
Test Case Title : Verify that when you add a multiple surface fbx in PxMesh in PhysxCollider,
multiple number of Material Slots populate in the Materials Section
"""
# fmt: off
class Tests():
create_entity = ("Created test entity", "Failed to create test entity")
mesh_added = ("Added Mesh component", "Failed to add Mesh component")
physx_collider_added = ("Added PhysX Collider component", "Failed to add PhysX Collider component")
shape_is_correct = ("PhysX Collider Shape is correct", "PhysX Collider Shape is not PhysicsAsset")
assign_mesh_asset = ("Assigned Mesh asset to Mesh component", "Failed to assign mesh asset to Mesh component")
assign_px_mesh_asset = ("Assigned PxMesh asset to Collider component", "Failed to assign PxMesh asset to Collider component")
count_mesh_surface = ("Multiple slots show under materials", "Failed to show required surface materials")
# fmt: on
def C4044695_PhysXCollider_AddMultipleSurfaceFbx():
"""
Summary:
Create entity with Mesh and PhysX Collider components and assign a fbx file in both the components.
Verify that the fbx is properly fitting the mesh.
Expected Behavior:
1) The fbx is properly fitting the mesh.
2) Multiple material slots show up under Materials section in the PhysX Collider component and that
they correspond to the number of surfaces as designed in the mesh.
Test Steps:
1) Load the empty level
2) Create an entity
3) Add Mesh and Physics collider components
4) Select the PhysicsAsset shape in the PhysX Collider component
5) Assign the fbx file in PhysX Mesh and Mesh component
6) Check if multiple material slots show up under Materials section in the PhysX Collider component
:return: None
"""
# Builtins
import os
# Helper Files
from editor_python_test_tools.editor_entity_utils import EditorEntity as Entity
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
from editor_python_test_tools.asset_utils import Asset
# Constants
PHYSICS_ASSET_INDEX = 7 # Hardcoded enum index value for Shape property
SURFACE_TAG_COUNT = 4 # Number of surface tags included in used asset
# Asset paths
STATIC_MESH = os.path.join("assets", "c4044695_physxcollider_addmultiplesurfacefbx", "test.azmodel")
PHYSX_MESH = os.path.join("assets", "c4044695_physxcollider_addmultiplesurfacefbx", "test.pxmesh")
helper.init_idle()
# 1) Load the empty level
helper.open_level("Physics", "Base")
# 2) Create an entity
test_entity = Entity.create_editor_entity("test_entity")
Report.result(Tests.create_entity, test_entity.id.IsValid())
# 3) Add Mesh and Physics collider components
mesh_component = test_entity.add_component("Mesh")
Report.result(Tests.mesh_added, test_entity.has_component("Mesh"))
collider_component = test_entity.add_component("PhysX Collider")
Report.result(Tests.physx_collider_added, test_entity.has_component("PhysX Collider"))
# 4) Select the PhysicsAsset shape in the PhysX Collider component
collider_component.set_component_property_value("Shape Configuration|Shape", PHYSICS_ASSET_INDEX)
value_to_test = collider_component.get_component_property_value("Shape Configuration|Shape")
Report.result(Tests.shape_is_correct, value_to_test == PHYSICS_ASSET_INDEX)
# 5) Assign the fbx file in PhysX Mesh and Mesh component
px_asset = Asset.find_asset_by_path(PHYSX_MESH)
collider_component.set_component_property_value("Shape Configuration|Asset|PhysX Mesh", px_asset.id)
px_asset.id = collider_component.get_component_property_value("Shape Configuration|Asset|PhysX Mesh")
Report.result(Tests.assign_px_mesh_asset, px_asset.get_path() == PHYSX_MESH.replace(os.sep, "/"))
mesh_asset = Asset.find_asset_by_path(STATIC_MESH)
mesh_component.set_component_property_value("Controller|Configuration|Mesh Asset", mesh_asset.id)
mesh_asset.id = mesh_component.get_component_property_value("Controller|Configuration|Mesh Asset")
Report.result(Tests.assign_mesh_asset, mesh_asset.get_path() == STATIC_MESH.replace(os.sep, "/"))
# 6) Check if multiple material slots show up under Materials section in the PhysX Collider component
pte = collider_component.get_property_tree()
def get_surface_count():
count = pte.get_container_count("Collider Configuration|Physics Materials|Slots")
return count.GetValue()
Report.result(
Tests.count_mesh_surface, helper.wait_for_condition(lambda: get_surface_count() == SURFACE_TAG_COUNT, 1.0)
)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C4044695_PhysXCollider_AddMultipleSurfaceFbx)
@@ -0,0 +1,83 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
# Test case ID : C4976227
# Test Case Title : Validate that a Collision Group can be added
# Level has entity with custom collision group added.
# If level enters game mode, collision group addition is validated.
# fmt: off
class Tests:
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
find_sphere = ("Sphere entity found", "Sphere entity not found")
collision_group = ("Collision group addition validated", "Collision group addition not valid")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
# fmt: on
def C4976227_Collider_NewGroup():
"""
Summary:
Runs an automated test to ensure that a collision group can be added.
Level Description:
Sphere (Entity) - PhysX Collider(shape:sphere): Collision Layer (Default), Collides With (Test_Group)
Test_Group (Collision Group) - Collision Group that is custom made for this test.
Requires a custom ".physxconfiguration" file in addition to the level file
Expected Behavior:
When game mode is entered the entity id should be valid and position should be found
Test Steps:
1) Open Level
2) Enter game mode
3) Validate entities
4) Exit game mode
5) Close Editor
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
import os
import sys
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
import azlmbr.legacy.general as general
import azlmbr.bus
helper.init_idle()
# 1) Open Level
helper.open_level("Physics", "C4976227_Collider_NewGroup")
# 2) Enter game mode
helper.enter_game_mode(Tests.enter_game_mode)
# 3) Validate entities
sphere_id = general.find_game_entity("Sphere")
Report.result(Tests.find_sphere, sphere_id.IsValid())
sphere_position = None
sphere_position = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", sphere_id)
Report.result(Tests.collision_group, sphere_id.isValid() and sphere_position != None)
# 4) Exit game mode
helper.exit_game_mode(Tests.exit_game_mode)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C4976227_Collider_NewGroup)
@@ -0,0 +1,86 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
Test case ID : C4976236
Test Case Title : Verify that you can add the physX collider component to an entity
without it throwing an error or warning
"""
# fmt: off
class Tests():
create_test_entity = ("Entity created successfully", "Failed to create Entity")
add_physx_collider = ("PhysX Collider component added", "Failed to add PhysX Collider component")
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
no_errors_and_warnings_found = ("No errors and warnings found", "Found errors and warnings")
exit_game_mode = ("Exited game mode", "Failed to exit game mode")
# fmt: on
def C4976236_AddPhysxColliderComponent():
"""
Summary:
Opens an empty level and creates an Entity with PhysX Collider. Verify that editor remains stable in Game mode.
Expected Behavior:
The Editor is stable there are no warnings or errors.
Test Steps:
1) Load the level
2) Create test entity
3) Start the Tracer to catch any errors and warnings
4) Add the PhysX Collider component and change shape to box
5) Enter game mode
6) Verify there are no errors and warnings in the logs
7) Exit game mode
8) Close the editor
:return: None
"""
# Helper file Imports
from editor_python_test_tools.editor_entity_utils import EditorEntity
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
from editor_python_test_tools.utils import Tracer
from editor_python_test_tools.asset_utils import Asset
helper.init_idle()
# 1) Load the level
helper.open_level("Physics", "Base")
# 2) Create test entity
test_entity = EditorEntity.create_editor_entity("TestEntity")
Report.result(Tests.create_test_entity, test_entity.id.IsValid())
# 3) Start the Tracer to catch any errors and warnings
with Tracer() as section_tracer:
# 4) Add the PhysX Collider component and change shape to box
collider_component = test_entity.add_component("PhysX Collider")
Report.result(Tests.add_physx_collider, test_entity.has_component("PhysX Collider"))
collider_component.set_component_property_value('Shape Configuration|Shape', azlmbr.physics.ShapeType_Box)
# 5) Enter game mode
helper.enter_game_mode(Tests.enter_game_mode)
# 6) Verify there are no errors and warnings in the logs
success_condition = not (section_tracer.has_errors or section_tracer.has_warnings)
Report.result(Tests.no_errors_and_warnings_found, success_condition)
if not success_condition:
if section_tracer.has_warnings:
Report.info(f"Warnings found: {section_tracer.warnings}")
if section_tracer.has_errors:
Report.info(f"Errors found: {section_tracer.errors}")
# 7) Exit game mode
helper.exit_game_mode(Tests.exit_game_mode)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C4976236_AddPhysxColliderComponent)
@@ -0,0 +1,187 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
# Test case ID : C4976242
# Test Case Title : Assign same collision layer and same collision group to two entities and
# verify that they collide or not
# fmt: off
class Tests():
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
find_moving = ("Moving entity found", "Moving entity not found")
find_stationary = ("Stationary entity found", "Stationary entity not found")
find_terrain = ("Terrain entity found", "Terrain entity not found")
stationary_above_terrain = ("Stationary is above terrain", "Stationary is not above terrain")
moving_above_stationary = ("Moving is above stationary", "Moving is not above stationary")
gravity_works = ("Moving Sphere fell down", "Moving Sphere did not fall")
collisions = ("Collision occurred in between entities", "Collision did not occur between entities")
falls_below_terrain_height = ("Moving is below terrain", "Moving did not fall below terrain before timeout")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
# fmt: on
def C4976242_Collision_SameCollisionlayerSameCollisiongroup():
"""
Summary:
Open a Project that already has two entities with same collision layer and same collision group and verify collision
Level Description:
Moving and Stationary entities are created in level with same collision layer and same collision group.
Moving entity is placed above the Stationary entity.Terrain is placed below the Stationary entity.
So Moving and Stationary entities collide with each other and they go through terrain after collision.
Expected Behavior:
The Moving and Stationary entities should collide with each other.After Collision,they go through terrain.
Test Steps:
1) Open level and Enter game mode
2) Retrieve and validate Entities
3) Get the starting z position of the Moving entity,Stationary entity and Terrain
4) Check and report that the entities are at the correct heights before collision
5) Check that the gravity works and the Moving entity falls down
6) Check Spheres collide only with each other, but not with terrain
7) Check Moving Entity should be below terrain after collision
8) Exit game mode
9) Close the editor
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
import os
import sys
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
import azlmbr.legacy.general as general
import azlmbr.bus
# Constants
TIMEOUT = 2.0
TERRAIN_HEIGHT = 32.0 # Default height of the terrain
MIN_BELOW_TERRAIN = 0.5 # Minimum height below terrain the sphere must be in order to be 'under' it
CLOSE_ENOUGH_THRESHOLD = 0.0001
helper.init_idle()
# 1) Open level and Enter game mode
helper.open_level("Physics", "C4976242_Collision_SameCollisionlayerSameCollisiongroup")
helper.enter_game_mode(Tests.enter_game_mode)
# 2) Retrieve and validate Entities
moving_id = general.find_game_entity("Sphere_Moving")
Report.critical_result(Tests.find_moving, moving_id.IsValid())
stationary_id = general.find_game_entity("Sphere_Stationary")
Report.critical_result(Tests.find_stationary, stationary_id.IsValid())
terrain_id = general.find_game_entity("Terrain")
Report.critical_result(Tests.find_terrain, terrain_id.IsValid())
# 3) Get the starting z position of the Moving entity,Stationary entity and Terrain
class Sphere:
"""
Class to hold values for test checks.
Attributes:
start_position_z: The initial z position of the sphere
position_z : The z position of the sphere
fell : When the sphere falls any distance below its original position, the value should be set True
below_terrain : When the box falls below the specified terrain height, the value should be set True
"""
start_position_z = None
position_z = None
fell = False
below_terrain = False
Sphere.start_position_z = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldZ", moving_id)
stationary_start_z = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldZ", stationary_id)
# 4)Check and report that the entities are at the correct heights before collision
Report.info(
"Terrain Height: {} \n Stationary Sphere height: {} \n Moving Sphere height: {}".format(
TERRAIN_HEIGHT, stationary_start_z, Sphere.start_position_z
)
)
Report.result(Tests.stationary_above_terrain, TERRAIN_HEIGHT < (stationary_start_z - CLOSE_ENOUGH_THRESHOLD))
Report.result(
Tests.moving_above_stationary, stationary_start_z < (Sphere.start_position_z - CLOSE_ENOUGH_THRESHOLD)
)
# 5)Check that the gravity works and the Moving entity falls down
def sphere_fell():
if not Sphere.fell:
Sphere.position_z = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldZ", moving_id)
if Sphere.position_z < (Sphere.start_position_z - CLOSE_ENOUGH_THRESHOLD):
Report.info("Sphere position is now lower than the starting position")
Sphere.fell = True
return Sphere.fell
helper.wait_for_condition(sphere_fell, TIMEOUT)
Report.result(Tests.gravity_works, Sphere.fell)
# 6) Check Spheres collide only with each other, but not with terrain
class Collision:
entity_collision = False
terrain_collision = False
class CollisionHandler:
def __init__(self, id, func):
self.id = id
self.func = func
self.create_collision_handler()
def on_collision_begin(self, args):
self.func(args[0])
def create_collision_handler(self):
self.handler = azlmbr.physics.CollisionNotificationBusHandler()
self.handler.connect(self.id)
self.handler.add_callback("OnCollisionBegin", self.on_collision_begin)
def on_collision_terrain(other_id):
Collision.terrain_collision = True
Report.info("Collision occured in between Moving or Stationary entity with Terrain")
def on_moving_entity_collision(other_id):
if other_id.Equal(stationary_id):
Collision.entity_collision = True
# collision handler for entities
CollisionHandler(terrain_id, on_collision_terrain)
CollisionHandler(moving_id, on_moving_entity_collision)
# wait till timeout to check for any collisions happening in the level
helper.wait_for_condition(lambda: Collision.entity_collision, TIMEOUT)
Report.result(Tests.collisions, Collision.entity_collision and not Collision.terrain_collision)
# 7)Check Moving Entity should be below terrain after collision
def sphere_below_terrain():
if not Sphere.below_terrain:
Sphere.position_z = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldZ", moving_id)
if Sphere.position_z < (TERRAIN_HEIGHT - MIN_BELOW_TERRAIN):
Sphere.below_terrain = True
return Sphere.below_terrain
sphere_under_terrain = helper.wait_for_condition(sphere_below_terrain, TIMEOUT)
Report.result(Tests.falls_below_terrain_height, sphere_under_terrain)
# 8) Exit game mode
helper.exit_game_mode(Tests.exit_game_mode)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C4976242_Collision_SameCollisionlayerSameCollisiongroup)
@@ -0,0 +1,126 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
# Test case ID : C4976243
# Test Case Title : Assign different collision layers and same collision group
# (such that this group has both these collision layers enabled) to two entities and verify that they collide
# fmt: off
class Tests():
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
find_terrain = ("Terrain found", "Terrain not found")
find_entity1 = ("Entity1 found", "Entity1 not found")
find_entity2 = ("Entity2 found", "Entity2 not found")
gravity_enabled = ("Gravity is enabled", "Gravity is disabled")
gravity_disabled = ("Gravity is disabled", "Gravity is enabled")
collision_occurance = ("Entity1 and Entity2 collided", "Entity1 and Entity2 did not collide")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
# fmt: on
def C4976243_Collision_SameCollisionGroupDiffCollisionLayers():
"""
Summary:
Assign different collision layers and same collision group (such that this group has both these
collision layers enabled) to two entities and verify that they collide
Level Description:
Entity1 (entity) - Entity with components PhysX Rigid Body, PhysX Collider, Terrain and Rendering Mesh
"Collision Layer" as "A" and "Collides with" as "B" with gravity enabled.
Entity1 is placed exactly above Terrain and Entity2 along z axis
Entity2 (entity) - Entity with components PhysX Rigid Body, PhysX Collider, Terrain and Rendering Mesh
"Collision Layer" as "Default" and "Collides with" as "B" with gravity disabled
Entity2 is placed exactly in between the Terrain and Entity1 along z axis
Terrain (entity) - Entity with Terrain component.
"Collision Layer" as "Default" and "Collides with" as "All"
Expected Behavior:
Created entities should collide with each other.
We are checking created entities collided (Entity1 and Entity2)
Test Steps:
1) Open level
2) Enter game mode
3) Retrieve and validate entities
4) Check if gravity is enabled for entity1 and disabled for entity2
5) Create collision event handlers
6) Check for collisions between entities
7) Exit game mode
8) Close the editor
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
import os
import sys
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
import azlmbr.legacy.general as general
import azlmbr.bus
# Constants
TIMEOUT = 2 # waits for 2 secs to verify if the collision occured
helper.init_idle()
# 1) Open level
helper.open_level("Physics", "C4976243_Collision_SameCollisionGroupDiffCollisionLayers")
# 2) Enter game mode
helper.enter_game_mode(Tests.enter_game_mode)
# 3) Retrieve and validate entities
terrain_id = general.find_game_entity("Terrain")
Report.info(dir(terrain_id))
entity1_id = general.find_game_entity("Entity1")
entity2_id = general.find_game_entity("Entity2")
Report.critical_result(Tests.find_terrain, terrain_id.IsValid())
Report.critical_result(Tests.find_entity1, entity1_id.IsValid())
Report.critical_result(Tests.find_entity2, entity2_id.IsValid())
# 4) Check if gravity is enabled for entity1 and disabled for entity2
is_gravity_enabled = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "IsGravityEnabled", entity1_id)
Report.info("Gravity check for entity1")
Report.result(Tests.gravity_enabled, is_gravity_enabled)
is_gravity_enabled = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "IsGravityEnabled", entity2_id)
Report.info("Gravity check for entity2")
Report.result(Tests.gravity_disabled, not is_gravity_enabled)
class Collision:
entity_collision = False
# 5) Create collision event handler
def on_collision_begin(args):
if args[0].Equal(entity1_id):
Report.info("Collision occurred")
Collision.entity_collision = True
handler = azlmbr.physics.CollisionNotificationBusHandler()
handler.connect(entity2_id)
handler.add_callback("OnCollisionBegin", on_collision_begin)
# 6) Check for collisions between entities
helper.wait_for_condition(lambda: Collision.entity_collision, TIMEOUT)
Report.critical_result(Tests.collision_occurance, Collision.entity_collision)
# 7) Exit game mode
helper.exit_game_mode(Tests.exit_game_mode)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C4976243_Collision_SameCollisionGroupDiffCollisionLayers)
@@ -0,0 +1,184 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
# Test case ID : C4976244
# Test Case Title : Checks that two entities of similar custom layer collide
# fmt: off
class Tests:
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
moving_sphere_found = ("Moving sphere found", "Moving sphere not found")
stationary_sphere_found = ("Stationary sphere found", "Stationary sphere not found")
velocities_before_collision_valid = ("Sphere velocities are valid", "Sphere velocities are not valid")
orientation_before_collision = ("Both spheres are aligned properly", "Spheres are not aligned properly")
spheres_collided = ("Collision was detected", "A collision was not detected")
orientation_after_collision = ("Spheres are aligned properly", "Spheres are not aligned properly")
velocities_after_collision_valid = ("Velocity after collision valid", "Velocity after collision not valid")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
# fmt: on
def C4976244_Collider_SameGroupSameLayerCollision():
# type: () -> None
"""
Summary:
Runs an automated test to ensure to rigid bodies on similar collision layer and group collide.
Level Description:
Moving Sphere (Entity) - On the same x axis as the Stationary Sphere, moving in the positive x direction;
has sphere shaped PhysX Collider, PhysX Rigid Body, Sphere Shape. Collision Group All, layer A
Stationary Sphere (Entity) - On the same x axis as the Moving Sphere;
has sphere shaped PhysX Collider, PhysX Rigid Body, Sphere Shape Collision Group All, layer A
Expected Behavior: The moving sphere will move torward the stationary sphere in the positive x direction
and collide with it. Both spheres will then separate and move in opposite directions.
Test Steps:
1) Load the level
2) Enter Game Mode
3) Validate entities
4) Validate positions and velocities
5) Start handlers
6) Wait for collision
7) Validated and logs results
8) Exit Game Mode
9) Close the editor
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
import os
import sys
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
import azlmbr.legacy.general as general
import azlmbr.bus
# Constants
TIMEOUT = 1
FLOAT_THRESHOLD = sys.float_info.epsilon
# Helper functions
# Callback function for the collision handler
def on_collision_begin(args):
# type (list) -> None
Report.info("Collision Occurred")
other_id = args[0]
if other_id.Equal(moving_sphere.id):
stationary_sphere.collision_happened = True
class Entity:
def __init__(self, name):
self.id = general.find_game_entity(name)
self.name = name
self.initial_velocity = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "GetLinearVelocity", self.id)
self.final_velocity = None
self.initial_position = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", self.id)
self.final_position = None
self.collision_happened = False
Report.info_vector3(self.initial_position, "{} initial position: ".format(self.name))
Report.info_vector3(self.initial_velocity, "{} initial velocity: ".format(self.name))
def get_final_position_and_velocity(self):
# type () -> None
self.final_velocity = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "GetLinearVelocity", self.id)
self.final_position = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", self.id)
def report_final_values(self):
# type () -> None
Report.info_vector3(self.final_position, "{} final position: ".format(self.name))
Report.info_vector3(self.final_velocity, "{} final velocity: ".format(self.name))
def moving_in_x_direction(self, positive_x_direction):
# type (bool) -> bool
velocity_vector = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "GetLinearVelocity", self.id)
if positive_x_direction:
correct_direction = velocity_vector.x > 0
else:
correct_direction = velocity_vector.x < 0
return (
correct_direction and abs(velocity_vector.y) < FLOAT_THRESHOLD and abs(velocity_vector.z) < FLOAT_THRESHOLD
)
# Checks if spheres are in the correct orientation
def validate_positions(moving_entity_position, stationary_entity_position):
# type (Vector3, Vector3) -> bool
return (
abs(moving_entity_position.z - stationary_entity_position.z) < FLOAT_THRESHOLD
and abs(moving_entity_position.y - stationary_entity_position.y) < FLOAT_THRESHOLD
and moving_entity_position.x < stationary_entity_position.x
)
# Main Script
# 1) Load the level
helper.init_idle()
helper.open_level("physics", "C4976244_Collider_SameGroupSameLayerCollision")
# 2) Enter Game Mode
helper.enter_game_mode(Tests.enter_game_mode)
# 3) Validate entities
moving_sphere = Entity("Moving_Sphere")
stationary_sphere = Entity("Stationary_Sphere")
Report.critical_result(Tests.moving_sphere_found, moving_sphere.id.isValid())
Report.critical_result(Tests.stationary_sphere_found, stationary_sphere.id.isValid())
# 4) Validate positions and velocities
Report.critical_result(
Tests.orientation_before_collision,
validate_positions(moving_sphere.initial_position, stationary_sphere.initial_position),
)
Report.critical_result(
Tests.velocities_before_collision_valid,
moving_sphere.moving_in_x_direction(positive_x_direction = True)
and stationary_sphere.initial_velocity.IsZero(FLOAT_THRESHOLD),
)
# 5) Start handler
handler = azlmbr.physics.CollisionNotificationBusHandler()
handler.connect(stationary_sphere.id)
handler.add_callback("OnCollisionBegin", on_collision_begin)
# 6) Wait for collision
helper.wait_for_condition(lambda: stationary_sphere.collision_happened, TIMEOUT)
# 7) Validated and logs results
Report.result(Tests.spheres_collided, stationary_sphere.collision_happened)
moving_sphere.get_final_position_and_velocity()
stationary_sphere.get_final_position_and_velocity()
Report.result(
Tests.orientation_after_collision,
validate_positions(moving_sphere.final_position, stationary_sphere.final_position),
)
Report.result(
Tests.velocities_after_collision_valid,
moving_sphere.moving_in_x_direction(positive_x_direction = False) and stationary_sphere.moving_in_x_direction(positive_x_direction = True)
)
moving_sphere.report_final_values()
stationary_sphere.report_final_values()
# 8) Exit Game Mode
helper.exit_game_mode(Tests.exit_game_mode)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C4976244_Collider_SameGroupSameLayerCollision)
@@ -0,0 +1,222 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
# Test case ID : C4976245
# Test Case Title : Check that two entities of collision group "None" do not collide,
# even though they have the same collision layer
# fmt: off
class Tests:
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
moving_entity_found = ("Moving entity found", "Moving entity not found")
stationary_entity_found = ("Stationary entity found", "Stationary entity not found")
moving_pos_found = ("Moving sphere position found", "Moving sphere position not found")
stationary_pos_found = ("Stationary sphere position found", "Stationary sphere position not found")
spheres_share_x_axis = ("Both spheres are aligned properly", "Spheres are not aligned properly")
spheres_not_collided = ("No collision was detected", "A collision was detected")
spheres_switched_sides = ("The moving sphere passed through the other", "Moving sphere did not pass through")
no_y_movement = ("There was no Y movement", "Some Y movement was detected")
no_z_movement = ("There was no Z movement", "Some Z movement was detected")
timed_out = ("Test did not time out", "Test TIMED OUT")
stationary_didnt_move = ("Stationary sphere did not move", "Stationary sphere moved")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
# fmt: on
def C4976245_PhysXCollider_CollisionLayerTest():
# type: () -> None
"""
Summary:
Runs an automated test to ensure to rigid bodies on the same collision layer, but no collision group
DO NOT collide.
Level Description:
Moving (entity) - a spherical entity (colored yellow) that is set up with a collision layer of "demo1"
collision group of "None" gravity as disabled and an initial velocity of (3, 0, 0).
Stationary (entity) - a spherical entity (colored purple) that is set up with a collision layer of "demo1"
collision group of "None" gravity disabled, and is positioned at location (+2, 0, 0) relative to
Moving's starting position with no initial velocity.
Expected Behavior:
When game mode is entered, Moving will begin moving in the positive X direction. The entity should pass through
Stationary with no collision detection triggered.
Test Steps:
1) Loads the level / Enter game mode
2) Retrieve test entities
3) Ensures that the test objects (Moving and Stationary) are located
4) set up variables and handlers
5) Wait for Moving to pass through Stationary
6) Logs results
7) Close the editor
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
import os
import sys
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
import azlmbr.legacy.general as general
import azlmbr.bus
# **** Helper class ****
class Sphere:
def __init__(self, name):
self.id = None
self.name = name
self.initial_pos = None
self.current_position = None
# Tests the deltas for for significant change. Prints a message to log if change is detected.
# returns True if no change detected between both deltas-- False otherwise
def no_movement(delta_moving, delta_stationary, axis):
result = True
if delta_moving > CLOSE_ENOUGH_THRESHOLD:
Report.info("Moving entity {} movement detected. This should not happen".format(axis))
result = False
if delta_stationary > CLOSE_ENOUGH_THRESHOLD:
Report.info("Stationary entity {} movement detected. This should not happen".format(axis))
result = False
return result
# *** Executable Code ***
# Constants
TIME_OUT = 1.5
CLOSE_ENOUGH_THRESHOLD = 0.0001
SPHERE_RADIUS = 0.5 # Radius of both sphere entities
COMPARISON_BUFFER = 0.2 # used for position comparisons to offset game physics anomalies
# 1) Open level / Enter game mode
helper.init_idle()
helper.open_level("Physics", "C4976245_PhysxCollider_CollisionLayerTest")
helper.enter_game_mode(Tests.enter_game_mode)
# 2) Retrieve/validate entities
moving = Sphere("Moving")
moving.id = general.find_game_entity(moving.name)
Report.critical_result(Tests.moving_entity_found, moving.id.IsValid())
stationary = Sphere("Stationary")
stationary.id = general.find_game_entity(stationary.name)
Report.critical_result(Tests.stationary_entity_found, stationary.id.IsValid())
# 3) Log starting positions
moving.initial_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", moving.id)
stationary.initial_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", stationary.id)
# Ensure that spheres are aligned properly along the y and z axises (so x axis movement will cause collision)
spheres_aligned = (abs(moving.initial_pos.y - stationary.initial_pos.y) < SPHERE_RADIUS) and (
abs(moving.initial_pos.z - stationary.initial_pos.z) < SPHERE_RADIUS
)
# Report critical level integrity results
Report.critical_result(Tests.moving_pos_found, moving.initial_pos is not None and not moving.initial_pos.IsZero())
Report.critical_result(
Tests.stationary_pos_found, stationary.initial_pos is not None and not moving.initial_pos.IsZero()
)
Report.critical_result(
Tests.spheres_share_x_axis,
spheres_aligned,
"Please check the level to make sure Moving Sphere and Stationary Sphere share y and z positions",
)
# 4) Set up variables and handler for observing force region interaction
class TestData:
collision_occurred = False
spheres_switched = False
# Force Region Event Handler
def on_collision_begin(args):
collider_id = args[0]
if collider_id.Equal(moving.id):
if not TestData.collision_occurred:
TestData.collision_occurred = True
Report.info("Collision detected")
# Assign the handler
handler = azlmbr.physics.CollisionNotificationBusHandler()
handler.connect(stationary.id)
handler.add_callback("OnCollisionBegin", on_collision_begin)
moving.current_pos = moving.initial_pos
stationary.current_pos = stationary.initial_pos
# Tests if we are done collecting results and can exit the test
def done_collecting_results():
if not TestData.collision_occurred:
moving.current_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", moving.id)
stationary.current_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", stationary.id)
if moving.current_pos.x > (stationary.current_pos.x + COMPARISON_BUFFER):
# Moving sphere passed the stationary sphere's x coordinate
TestData.spheres_switched = True
return True
else:
# A collision was detected
Report.info("A collision was detected unfortunately")
return True
return False
# 5) Wait for results to be collected or for time out
Report.result(Tests.timed_out, helper.wait_for_condition(done_collecting_results, TIME_OUT))
# 6) Log results
Report.result(Tests.spheres_switched_sides, TestData.spheres_switched)
Report.result(Tests.spheres_not_collided, not TestData.collision_occurred)
# Look for movement in Y direction. Report results
no_movement_y = no_movement(
abs(moving.initial_pos.y - moving.current_pos.y), abs(stationary.initial_pos.y - stationary.current_pos.y), "Y"
)
Report.result(Tests.no_y_movement, no_movement_y)
# Look for movement in Z direction. Report results
no_movement_z = no_movement(
abs(moving.initial_pos.z - moving.current_pos.z), abs(stationary.initial_pos.z - stationary.current_pos.z), "Z"
)
Report.result(Tests.no_z_movement, no_movement_z)
Report.result(Tests.stationary_didnt_move, stationary.current_pos.Equal(stationary.initial_pos))
# Collected data dump
Report.info(" ********** Collected Data ***************")
Report.info("Moving sphere's positions:")
Report.info_vector3(moving.initial_pos, " initial:")
Report.info_vector3(moving.current_pos, " final:")
Report.info("*****************************")
Report.info("Stationary sphere's positions:")
Report.info_vector3(stationary.initial_pos, " initial:")
Report.info_vector3(stationary.current_pos, " final:")
Report.info("*****************************")
# 7) Exit Game mode
helper.exit_game_mode(Tests.exit_game_mode)
Report.info("*** FINISHED TEST ***")
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C4976245_PhysXCollider_CollisionLayerTest)
@@ -0,0 +1,230 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
# Test case ID : C4982593
# Test Case Title : Check that two entities with different collision groups and layers do not collide.
# fmt: off
class Tests:
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
moving_entity_found = ("Moving entity found", "Moving entity not found")
stationary_entity_found = ("Stationary entity found", "Stationary entity not found")
moving_pos_found = ("Moving sphere position found", "Moving sphere position not found")
stationary_pos_found = ("Stationary sphere position found", "Stationary sphere position not found")
spheres_share_x_axis = ("Both spheres are aligned properly", "Spheres are not aligned properly")
spheres_not_collided = ("No collision was detected", "A collision was detected")
spheres_switched_sides = ("The moving sphere passed through the other", "Moving sphere did not pass through")
no_y_movement = ("There was no Y movement", "Some Y movement was detected")
no_z_movement = ("There was no Z movement", "Some Z movement was detected")
timed_out = ("Test did not time out", "Test TIMED OUT")
stationary_didnt_move = ("Stationary sphere did not move", "Stationary sphere moved")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
# fmt: on
def C4982593_PhysXCollider_CollisionLayerTest():
# type: () -> None
"""
Summary:
Runs an automated test to ensure to rigid bodies on the different collision group and collision layer
DO NOT collide.
Level Description:
Moving (entity) - a spherical entity (colored yellow) that is set up with a collision layer of "demo1"
collision group of "demo_group1" gravity as disabled and an initial velocity of (3, 0, 0).
Stationary (entity) - a spherical entity (colored purple) that is set up with a collision layer of "demo2"
collision group of "demo_group2" gravity disabled, and is positioned at location (+2, 0, 0) relative to
Moving's starting position.
Expected Behavior:
When game mode is entered, Moving will begin moving in the positive X direction. The entity should pass through
Stationary with no collision detection triggered.
Test Steps:
1) Loads the level / Enter game mode
2) Retrieve test entities
3) Ensures that the test objects (Moving and Stationary) are located
3.5) set up variables and handlers
4) Wait for Moving to pass through Stationary
5) Logs results
6) Close the editor
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
import os
import sys
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
import azlmbr.legacy.general as general
import azlmbr.bus
# **** Helper class ****
class Sphere:
def __init__(self, name):
self.id = None
self.name = name
self.initial_pos = None
self.current_position = None
# Tests for significant change between a set of float pairs
# returns a list of booleans where the i-th index hold the result for the i-th float pair
def detect_significant_change(float_pairs):
# type: ([(float, float)]) -> [bool]
return [abs(p[0] - p[1]) >= CLOSE_ENOUGH_THRESHOLD for p in float_pairs]
# *** Executable Code ***
# Constants
TIME_OUT = 1.5
CLOSE_ENOUGH_THRESHOLD = 0.0001
SPHERE_RADIUS = 0.5 # Radius of both sphere entities
# 1) Open level / Enter game mode
helper.init_idle()
helper.open_level("Physics", "C4982593_PhysxCollider_CollisionLayerTest")
helper.enter_game_mode(Tests.enter_game_mode)
# 2) Retrieve/validate entities
moving = Sphere("Moving")
moving.id = general.find_game_entity(moving.name)
Report.critical_result(Tests.moving_entity_found, moving.id.IsValid())
stationary = Sphere("Stationary")
stationary.id = general.find_game_entity(stationary.name)
Report.critical_result(Tests.stationary_entity_found, stationary.id.IsValid())
# 3) Log starting positions
moving.initial_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", moving.id)
stationary.initial_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", stationary.id)
# Ensure that spheres are aligned properly along the y and z axises (so x axis movement will cause collision)
spheres_aligned = (abs(moving.initial_pos.y - stationary.initial_pos.y) < SPHERE_RADIUS) and (
abs(moving.initial_pos.z - stationary.initial_pos.z) < SPHERE_RADIUS
)
# Report critical level integrity results
Report.critical_result(Tests.moving_pos_found, moving.initial_pos is not None and not moving.initial_pos.IsZero())
Report.critical_result(
Tests.stationary_pos_found, stationary.initial_pos is not None and not moving.initial_pos.IsZero()
)
Report.critical_result(
Tests.spheres_share_x_axis,
spheres_aligned,
"Please check the level to make sure Moving Sphere and Stationary Sphere share y and z positions",
)
# 3.5) Set up variables and handler for observing force region interaction
class TestData:
collision_occurred = False
spheres_switched = False
# Force Region Event Handler
def on_collision_begin(args):
collider_id = args[0]
if collider_id.Equal(moving.id):
if not TestData.collision_occurred:
TestData.collision_occurred = True
Report.info("Collision detected")
# Assign the handler
handler = azlmbr.physics.CollisionNotificationBusHandler()
handler.connect(stationary.id)
handler.add_callback("OnCollisionBegin", on_collision_begin)
moving.current_pos = moving.initial_pos
stationary.current_pos = stationary.initial_pos
# Tests if we are done collecting results and can exit the test
def done_collecting_results():
COMPARISON_BUFFER = 0.2
if not TestData.collision_occurred:
moving.current_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", moving.id)
stationary.current_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", stationary.id)
if moving.current_pos.x > stationary.current_pos.x + COMPARISON_BUFFER:
# Moving sphere passed the stationary sphere's x coordinate
TestData.spheres_switched = True
return True
else:
# A collision was detected
Report.info("A collision was detected unfortunately")
return True
return False
# 4) Wait for results to be collected or for time out
Report.result(Tests.timed_out, helper.wait_for_condition(done_collecting_results, TIME_OUT))
# 5) Log results
Report.result(Tests.spheres_switched_sides, TestData.spheres_switched)
Report.result(Tests.spheres_not_collided, not TestData.collision_occurred)
# Look for movement in Y direction. Report results
y_movement = detect_significant_change(
[(moving.initial_pos.y, moving.current_pos.y), (stationary.initial_pos.y, stationary.current_pos.y)]
)
if not any(y_movement):
Report.success(Tests.no_y_movement)
else:
Report.failure(Tests.no_y_movement)
if y_movement[0]:
Report.info("Moving entity Y movement detected. This should not happen")
if y_movement[1]:
Report.info("Stationary entity Y movement detected. This should not happen")
# Look for movement in Z direction. Report Results
z_movement = detect_significant_change(
[(moving.initial_pos.z, moving.current_pos.z), (stationary.initial_pos.z, stationary.current_pos.z)]
)
if not any(z_movement):
Report.success(Tests.no_z_movement)
else:
Report.failure(Tests.no_z_movement)
if z_movement[0]:
Report.info("Moving entity Z movement detected. This should not happen")
if z_movement[1]:
Report.info("Stationary entity Z movement detected. This should not happen")
Report.result(Tests.stationary_didnt_move, stationary.current_pos.Equal(stationary.initial_pos))
# Collected data dump
Report.info(" ********** Collected Data ***************")
Report.info("Moving sphere's positions:")
Report.info_vector3(moving.initial_pos, " initial:")
Report.info_vector3(moving.current_pos, " final:")
Report.info("*****************************")
Report.info("Stationary sphere's positions:")
Report.info_vector3(stationary.initial_pos, " initial:")
Report.info_vector3(stationary.current_pos, " final:")
Report.info("*****************************")
# 6) Exit Game mode
helper.exit_game_mode(Tests.exit_game_mode)
Report.info("*** FINISHED TEST ***")
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C4982593_PhysXCollider_CollisionLayerTest)
@@ -0,0 +1,233 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
# Test Case ID : C4982595
# Test Case Title : Verify that when the Trigger Checkbox is ticked, the object no longer collides with another object
# but simply passes through it
# fmt: off
class Tests:
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
sphere_found_valid = ("Sphere found and validated", "Failed to find and validate Sphere")
trigger_box_found_valid = ("Trigger Box found and validated", "Failed to find and validate Trigger Box")
physical_box_found_valid = ("Physical Box found and validated", "Failed to find and validate Physical Box")
sphere_gravity_disabled = ("Gravity is disabled on Sphere", "Gravity is enabled on Sphere")
sphere_positive_initial_x_velocity = ("Sphere has positive initial x-velocity", "Sphere does not have positive initial x-velocity")
sphere_entered_trigger_box = ("Sphere entered Trigger Box", "Sphere did not enter Trigger Box")
sphere_exited_trigger_box = ("Sphere exited Trigger Box", "Sphere did not exit Trigger Box")
sphere_passed_through_trigger_box = ("Sphere passed through Trigger Box", "Sphere did not pass through Trigger Box")
sphere_collided_with_physical_box = ("Sphere collided with Physical Box", "Sphere did not collide with Physical Box")
sphere_bounced_back = ("Sphere bounced back from Physical Box", "Sphere did not bounce back from Physical Box")
sphere_did_not_pass_through_physical_box = ("Sphere did not pass through Physical Box", "Sphere passed through Physical Box")
exit_game_mode = ("Exited game mode", "Failed to exit game mode")
# fmt: on
def C4982595_Collider_TriggerDisablesCollision():
"""
Summary:
This script runs an automated test to verify that when an entity's PhysX collider is set as a trigger, the entity no
longer collides with another entity.
Level Description:
Entity: Sphere: PhysX Rigid Body, PhysX Collider with sphere shape, and Mesh with sphere asset
Gravity disabled, Radius 1.0, Initial linear x-velocity +30 m/s, Position (36.0, 36.0, 36.0)
Entity: Trigger Box: PhysX Collider with box shape, and Mesh with cube asset
Trigger enabled, Dimensions (2.0, 2.0, 2.0), Z-offset 1.0, Position (42.0, 36.0, 35.0)
Entity: Physical Box: PhysX Collider with box shape, and Mesh with cube asset
Dimensions (2.0, 2.0, 2.0), Z-offset 1.0, Position (48.0, 36.0, 35.0)
The entities are aligned along the x-axis as follows:
_ _
O ---> !_! |_|
Sphere Trigger Box Physical Box
Expected behavior:
The sphere will pass through the trigger box, collide with the physical box, and bounce back without passing through
the physical box.
Test Steps:
1) Open level and enter game mode
2) Retrieve and validate entities
3) Check that gravity is disabled on the sphere
4) Check that the sphere has positive initial x-velocity
5) Wait for the sphere to enter the trigger box
6) Wait for the sphere to exit the trigger box
7) Check that the sphere passed through the trigger box
8) Wait for the sphere to collide with the physical box
9) Wait for the sphere to stop colliding with the physical box and check that the sphere bounced back
10) Check that the sphere did not pass through the physical box
11) Exit game mode and close editor
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Setup path
import os
import sys
import azlmbr.legacy.general as general
import azlmbr.bus
import azlmbr.components
import azlmbr.physics
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
TIME_OUT_SECONDS = 3.0
SPHERE_RADIUS = 1.0
BOX_X_DIMENSION = 2.0
BOX_X_RADIUS = BOX_X_DIMENSION / 2
CLOSE_ENOUGH_BUFFER = 0.1
class Entity:
def __init__(self, name, found_valid_test):
self.name = name
self.id = general.find_game_entity(name)
self.found_valid_test = found_valid_test
def get_x_position(self):
position = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", self.id)
Report.info_vector3(position, "{}'s position:".format(self.name))
return position.x
class Sphere(Entity):
def __init__(self, name, found_valid_test):
Entity.__init__(self, name, found_valid_test)
self.initial_x_velocity = self.get_x_velocity()
# Trigger state values
self.entered_trigger_target = False
self.trigger_enter_position = None
self.exited_trigger_target = False
self.trigger_exit_position = None
self.passed_through_trigger_target = False
# Collision state values
self.began_collision_with_collision_target = False
self.ended_collision_with_collision_target = False
self.bounced_back = False
self.did_not_pass_through_collision_target = None
def is_gravity_disabled(self):
return not azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "IsGravityEnabled", self.id)
def get_x_velocity(self):
velocity = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "GetLinearVelocity", self.id)
Report.info_vector3(velocity, "{}'s velocity:".format(self.name))
return velocity.x
class TriggerBox(Entity):
def __init__(self, name, found_valid_test, trigger_target):
Entity.__init__(self, name, found_valid_test)
self.trigger_target = trigger_target
# Set up trigger notification handler
self.handler = azlmbr.physics.TriggerNotificationBusHandler()
self.handler.connect(self.id)
self.handler.add_callback("OnTriggerEnter", self.on_trigger_enter)
self.handler.add_callback("OnTriggerExit", self.on_trigger_exit)
def on_trigger_enter(self, args):
other_id = args[0]
if other_id.Equal(self.trigger_target.id) and not self.trigger_target.entered_trigger_target:
self.trigger_target.trigger_enter_position = self.trigger_target.get_x_position()
self.trigger_target.entered_trigger_target = True
def on_trigger_exit(self, args):
other_id = args[0]
if other_id.Equal(self.trigger_target.id) and not self.trigger_target.exited_trigger_target:
self.trigger_target.trigger_exit_position = self.trigger_target.get_x_position()
self.trigger_target.exited_trigger_target = True
# Check that the sphere's position traveled at least the approximate x-length of the box measured from
# the point on the sphere where it entered the trigger to the point on the sphere where it exited
if (
self.trigger_target.trigger_exit_position - SPHERE_RADIUS + CLOSE_ENOUGH_BUFFER
>= self.trigger_target.trigger_enter_position + BOX_X_DIMENSION + SPHERE_RADIUS
):
self.trigger_target.passed_through_trigger_target = True
class PhysicalBox(Entity):
def __init__(self, name, found_valid_test, collision_target):
Entity.__init__(self, name, found_valid_test)
self.collision_target = collision_target
# Set up collision notification handler
self.collision_handler = azlmbr.physics.CollisionNotificationBusHandler()
self.collision_handler.connect(self.id)
self.collision_handler.add_callback("OnCollisionBegin", self.on_collision_begin)
self.collision_handler.add_callback("OnCollisionEnd", self.on_collision_end)
def on_collision_begin(self, args):
other_id = args[0]
if other_id.Equal(self.collision_target.id):
self.collision_target.began_collision_with_collision_target = True
def on_collision_end(self, args):
other_id = args[0]
if other_id.Equal(self.collision_target.id):
self.collision_target.ended_collision_with_collision_target = True
# Check that the sphere reversed its x-direction
if self.collision_target.get_x_velocity() < 0:
self.collision_target.bounced_back = True
# Check that the whole sphere is to the negative x-direction of the box
if sphere.get_x_position() + SPHERE_RADIUS <= physical_box.get_x_position() - BOX_X_RADIUS:
self.collision_target.did_not_pass_through_collision_target = True
# 1) Open level and enter game mode
helper.init_idle()
helper.open_level("Physics", "C4982595_Collider_TriggerDisablesCollision")
helper.enter_game_mode(Tests.enter_game_mode)
# 2) Retrieve and validate entities
sphere = Sphere("Sphere", Tests.sphere_found_valid)
trigger_box = TriggerBox("Trigger Box", Tests.trigger_box_found_valid, trigger_target=sphere)
physical_box = PhysicalBox("Physical Box", Tests.physical_box_found_valid, collision_target=sphere)
entities = (sphere, trigger_box, physical_box)
for entity in entities:
Report.critical_result(entity.found_valid_test, entity.id.IsValid())
# 3) Check that gravity is disabled on the sphere
Report.critical_result(Tests.sphere_gravity_disabled, sphere.is_gravity_disabled())
# 4) Check that the sphere has positive initial x-velocity
Report.critical_result(Tests.sphere_positive_initial_x_velocity, sphere.initial_x_velocity > 0)
# 5) Wait for the sphere to enter the trigger box
helper.wait_for_condition(lambda: sphere.entered_trigger_target, TIME_OUT_SECONDS)
Report.critical_result(Tests.sphere_entered_trigger_box, sphere.entered_trigger_target)
# 6) Wait for the sphere to exit the trigger box
helper.wait_for_condition(lambda: sphere.exited_trigger_target, TIME_OUT_SECONDS)
Report.critical_result(Tests.sphere_exited_trigger_box, sphere.exited_trigger_target)
# 7) Check that the sphere passed through the trigger box
Report.critical_result(Tests.sphere_passed_through_trigger_box, sphere.passed_through_trigger_target)
# 8) Wait for the sphere to collide with the physical box
helper.wait_for_condition(lambda: sphere.began_collision_with_collision_target, TIME_OUT_SECONDS)
Report.critical_result(Tests.sphere_collided_with_physical_box, sphere.began_collision_with_collision_target)
# 9) Wait for the sphere to stop colliding with the physical box and check that the sphere bounced back
helper.wait_for_condition(lambda: sphere.ended_collision_with_collision_target, TIME_OUT_SECONDS)
Report.result(Tests.sphere_bounced_back, sphere.bounced_back)
# 10) Check that the sphere did not pass through the physical box
Report.result(Tests.sphere_did_not_pass_through_physical_box, sphere.did_not_pass_through_collision_target)
# 11) Exit game mode and close editor
helper.exit_game_mode(Tests.exit_game_mode)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C4982595_Collider_TriggerDisablesCollision)
@@ -0,0 +1,334 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
# Test case ID : C4982797
# Test Case Title : Check that collision offsets trigger collision events,
# not entity transform locations
# fmt: off
class Tests:
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
boxes_found = ("All boxes were validated", "Couldn't validate at least one box")
spheres_found = ("All spheres were validated", "Not all the spheres could be validated")
test_completed = ("The test completed", "The test timed out")
target_spheres_passed = ("All spheres intended to collide with Target Boxes DID", "At least one sphere intended to collide with a Target Box DID NOT")
pass_spheres_passed = ("All spheres intended to pass through Target Boxes DID", "At least one sphere intended to pass through a Target Box DID NOT")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
# fmt: on
def C4982797_Collider_ColliderOffset():
# type: () -> None
"""
Summary:
Runs an automated test to ensure that PhysXCollider offsets work properly. Collisions should be
calculated based on the location of the colliders, not the geometry of the entity's Transform
Level Description:
There are five classes of entities in the level: Target Spheres, Pass Spheres, Target Boxes, Pass Boxes
and Fail Boxes. All entities have gravity disabled, are positioned above the terrain, and have the same
collision group/layer (Default/All).
Target Boxes: These are the actual boxes that have their colliders offset. There are three of these
boxes, one for each offset axis (rightly labeled Box_[X, Y, or Z]_Target).
Target Spheres: These spheres are positioned near the Target Boxes' collision offset areas. These entities are
initialized with a velocity that will send them on course to collide with the collision geometry for the
Target Boxes. They are appropriately labeled for which Target box they are to collide with
Sphere_[X, Y, or Z]_Target
Pass Spheres: The spheres are positioned near the Target Boxes as well, and are also initialized with a velocity
that will will send them towards their Target Box. The difference here is that they aligned to "collide"
with their Target Box's actual transform (not their collider offset). They too are appropriately named
Sphere_[X, Y, or Z]_Pass
Pass Boxes: Pass Boxes are positioned on the other side of the Pass Spheres from their target Box. They serve
as a trigger to register that the Pass Sphere successfully passed through the respective Target Box's
transform geometry. They are rightfully named Box_[X, Y, or Z]_Pass
Fail Boxes: Fail boxes (like Pass Boxes) are positioned on the other side of their respective Target Box,
but they are arranged opposite the Target Sphere (rather than the Pass Sphere). They act as a fail safe
if the Target Sphere happens the pass through the Target Box's collider offset. They are named following the
same convention: Box_[X, Y, or Z]_Fail
Note: All boxes are set to "kinematic" so they do not move when a collision happens.
Expected Behavior:
Upon entering game mode, the spheres should follow their initial velocities. The Target Spheres should collide and
bounce off of the Target Boxes' collision offsets, and the Pass Spheres should pass through the visible transforms
of their Target Boxes and collide with their respective Pass Boxes.
Test Steps:
1) Loads the level
2) Enters game mode
3) Retrieve and validate entities
4) Ensures that the test objects are located
5) Wait for test to complete or time out
6) Log the results
7) Exit game mode and editor
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# System imports
import os
import sys
# Internal editor imports
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
import azlmbr.legacy.general as general
import azlmbr.bus
import azlmbr
# ******** Global Variables ********
# Entity data organization class
class EntityData:
def __init__(self, name):
self.name = name
self.id = None
self.init_pos = None
self.current_pos = None
self.result = None
# fmt: off
# Establish entity sets
target_spheres = [EntityData("Sphere_X_Target"), EntityData("Sphere_Y_Target"), EntityData("Sphere_Z_Target")]
pass_spheres = [EntityData("Sphere_X_Pass"), EntityData("Sphere_Y_Pass"), EntityData("Sphere_Z_Pass")]
target_boxes = [EntityData("Box_X_Target"), EntityData("Box_Y_Target"), EntityData("Box_Z_Target")]
pass_boxes = [EntityData("Box_X_Pass"), EntityData("Box_Y_Pass"), EntityData("Box_Z_Pass")]
fail_boxes = [EntityData("Box_X_Fail"), EntityData("Box_Y_Fail"), EntityData("Box_Z_Fail")]
all_spheres = target_spheres + pass_spheres
all_boxes = pass_boxes + fail_boxes + target_boxes
all_entities = all_spheres + all_boxes
# Maps a Sphere to its last anticipated collision/position (by name)
final_expected_collisions = {
"Sphere_X_Target": "Box_X_Fail",
"Sphere_Y_Target": "Box_Y_Fail",
"Sphere_Z_Target": "Box_Z_Fail",
"Sphere_X_Pass": "Box_X_Pass",
"Sphere_Y_Pass": "Box_Y_Pass",
"Sphere_Z_Pass": "Box_Z_Pass",
}
# Possible results
PASS = "pass"
FAIL = "fail"
TARGET = "target"
# fmt: on
# ******** Helper Functions ********
# Validate entities' IDs and initial positions.
# Fast Fails if there are any problems retrieving vital information
def validate_entities(entity_list, test_tuple):
# type: ([EntityData], (str, str)) -> None
passed = True
for entity in entity_list:
valid = True
entity.id = general.find_game_entity(entity.name)
if not entity.id.IsValid():
valid = False
Report.info("Entity: {} could not be validated".format(entity.name))
entity.init_pos = entity.current_pos = azlmbr.components.TransformBus(
azlmbr.bus.Event, "GetWorldTranslation", entity.id
)
if entity.init_pos is None or entity.init_pos.IsZero():
valid = False
Report.info("Entity: {}'s initial position could not be found".format(entity.name))
if not valid:
passed = False
break
Report.critical_result(test_tuple, passed)
# Updates entities' current position
def update_positions(entity_list):
# type: ([EntityData]) -> None
for entity in entity_list:
entity.current_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", entity.id)
# Looks for implicit failure cases for moving spheres
# by checking if they have moved through their "final expected collision" object
def check_for_failure(sphere_entities):
# type: ([EntityData]) -> None
for sphere in sphere_entities:
expected_name = final_expected_collisions[sphere.name]
expected_entity_list = [entity for entity in all_entities if entity.name == expected_name]
if len(expected_entity_list) == 0:
# Just in case we can't find the entity's "final expected collision" entity
Report.info("Failed finding {} in expected entities list:".format(expected_name))
Report.info(" {}".format(expected_entity_list))
helper.fail_fast()
expected_entity = expected_entity_list[0]
if sphere.result != FAIL and has_passed_through(sphere, expected_entity):
sphere.result = FAIL
Report.info("{} has unexpectedly passed through {}".format(sphere.name, expected_name))
# Checks for unexpected movement in stationary objects
# Fast Fails and writes to the log if there is a difference between initial position and current position
def check_for_unexpected_movement(entity_list):
# type: ([EntityData]) -> None
for entity in entity_list:
if not entity.init_pos.IsClose(entity.current_pos, CLOSE_ENOUGH_THRESHOLD):
helper.fail_fast("{} has unexpectedly moved".format(entity.name))
# Verifies the results for the entities passed in.
# Returns a count of the verified results
def verify_results(entity_list, expected_result):
# type: ([EntityData], str) -> int
results_verified = 0
for entity in entity_list:
if entity.result == expected_result:
results_verified += 1
else:
Report.info("{} had unexpected result: {}".format(entity.name, entity.result))
return results_verified
# Batch assign event handlers
def set_handlers(entity_list, callback, event="OnCollisionBegin"):
# type: ([EntityData], function, str) -> [handler]
handlers = []
for entity in entity_list:
handler = azlmbr.physics.CollisionNotificationBusHandler()
handler.connect(entity.id)
handler.add_callback(event, callback)
handlers.append(handler)
return handlers
# Checks to see if we are done collecting results for the test
def done_collecting_results(entity_list, num_results):
# type: ([EntityData], int) -> bool
result_count = 0
for entity in entity_list:
if entity.result is not None:
result_count += 1
# When all spheres have a result we are done
return result_count == num_results
# Checks if a moving entity has passed through a stationary entity.
# There is an assumption that the stationary entity should not have substantial movement
def has_passed_through(moving_entity, stationary_entity):
# type: (EntityData, EntityData) -> bool
init_diff = stationary_entity.init_pos.Subtract(moving_entity.init_pos).Unary()
current_diff = stationary_entity.current_pos.Subtract(moving_entity.current_pos).Unary()
angle = init_diff.AngleSafeDeg(current_diff)
# Angle > 90 degrees represents a change of sides
result = angle > 90.0
return result
def test_completed():
update_positions(all_entities)
check_for_failure(all_spheres)
check_for_unexpected_movement(all_boxes)
return done_collecting_results(all_spheres, TOTAL_SPHERES)
# ******** Event Handlers ********
# General collision handler
def on_collision_begin(collider_id, result):
# type: (EntityId, str) -> None
for sphere in all_spheres:
if sphere.id.Equal(collider_id):
Report.info("Entity: {} collided with a {} box".format(sphere.name, result))
if result is FAIL or sphere.result is None:
# Set result if not set yet OR the result is a failure (failure overrides success)
sphere.result = result
return
# It wasn't a sphere that collided, something went wrong
if collider_id.IsValid():
entity_name = azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "GetEntityName", collider_id)
Report.info("{} box collided with unexpected entity: {}".format(result, entity_name))
# Fail Box collision event handler
def on_collision_begin_fail_box(args):
# type: ([EntityId, ...]) -> None
on_collision_begin(args[0], FAIL)
# Success Box Collision Event Handler
def on_collision_begin_pass_box(args):
# type: ([EntityId, ...]) -> None
on_collision_begin(args[0], PASS)
# Target box collision event handler
def on_collision_begin_target_box(args):
# type: ([EntityId, ...]) -> None
on_collision_begin(args[0], TARGET)
# ******** Execution Code *********
# Local Constants
TIME_OUT = 2.0
CLOSE_ENOUGH_THRESHOLD = 0.1
TOTAL_TARGET_SPHERES = 3
TOTAL_PASS_SPHERES = 3
TOTAL_SPHERES = TOTAL_TARGET_SPHERES + TOTAL_PASS_SPHERES
helper.init_idle()
# 1) Open level
helper.open_level("Physics", "C4982797_Collider_ColliderOffset")
# 2) Enter game mode
helper.enter_game_mode(Tests.enter_game_mode)
# 3) Retrieve and validate entities
validate_entities(all_boxes, Tests.boxes_found)
validate_entities(all_spheres, Tests.spheres_found)
# Assign handlers
handlers = []
handlers = handlers + set_handlers(fail_boxes, on_collision_begin_fail_box)
handlers = handlers + set_handlers(pass_boxes, on_collision_begin_pass_box)
handlers = handlers + set_handlers(target_boxes, on_collision_begin_target_box)
# 4) Wait for either time out or for the test to complete
Report.result(Tests.test_completed, helper.wait_for_condition(test_completed, TIME_OUT))
# 5) Log results
# Verify entities results
pass_spheres_passed = verify_results(pass_spheres, PASS)
target_spheres_passed = verify_results(target_spheres, TARGET)
# Report results
Report.result(Tests.target_spheres_passed, target_spheres_passed == TOTAL_TARGET_SPHERES)
Report.result(Tests.pass_spheres_passed, pass_spheres_passed == TOTAL_PASS_SPHERES)
# Data dump at bottom of log
Report.info("******** Collected Data *********")
for entity in all_entities:
Report.info("Entity: {}".format(entity.name))
Report.info_vector3(entity.init_pos, " Initial position:")
Report.info_vector3(entity.current_pos, " Final position:")
Report.info(" Result: {}".format(entity.result))
Report.info("********************************")
# 6) Exit Game mode
helper.exit_game_mode(Tests.exit_game_mode)
Report.info("*** FINISHED TEST ***")
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C4982797_Collider_ColliderOffset)
@@ -0,0 +1,302 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
# Test case ID : C4982798
# Test Case Title : Verify that when the x,y,z values are defined in the offset, the collider frame
# rotates from its original orientation in the direction defined by the x,y,z units
import os
import sys
# fmt: off
class Tests:
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
boxes_found = ("All boxes were found", "Couldn't find at least one box")
spheres_found = ("All spheres were found", "Not all the spheres could be found")
test_completed = ("The test completed", "The test timed out")
target_spheres_passed = ("All spheres intended to collide with Target Boxes DID", "At least one sphere intended to collide with a Target Box DID NOT")
pass_thru_spheres_passed = ("All spheres intended to pass through Target Boxes DID", "At least one sphere intended to pass through a Target Box DID NOT")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
# fmt: on
def C4982798_Collider_ColliderRotationOffset():
# type: () -> None
"""
Summary:
Runs an automated test to ensure that PhysXCollider rotational offsets work properly. Collisions should be
calculated based on the location of the colliders, including their rotational offsets in x, y, and/or z
Level Description:
There are five classes of entities in the level: Target Spheres, Pass Spheres, Target Boxes, Pass Boxes
and Fail Boxes. All entities have gravity disabled, are positioned above the terrain, and have the same
collision group/layer (Default/All).
Target Boxes: These are the actual boxes that have their collider offsets rotated by 90 degrees.
There are three of these boxes, one for each rotation axis (rightly labeled Box_[X, Y, or Z]_Target).
Target Spheres: These spheres are positioned near the Target Boxes' rotated collision areas. These entities are
initialized with a velocity that will send them on course to collide with the collision geometry for the
Target Boxes. They are appropriately labeled for which Target box they are to collide with
Sphere_[X, Y, or Z]_Target
Pass Thru Spheres: These spheres are positioned near the Target Boxes as well, and are also initialized with a
velocity that will will send them towards their Target Box. The difference here is that they are aligned to
"collide" with their Target Box's actual transform (not their rotated collider). They too are appropriately
named Sphere_[X, Y, or Z]_Pass
Pass Thru Boxes: Pass Boxes are positioned on the other side of the Pass Spheres from their target Box. They serve
as a trigger to register that the Pass Sphere successfully passed through the respective Target Box's
transform geometry. They are rightfully named Box_[X, Y, or Z]_Pass
Fail Boxes: Fail boxes (like Pass Boxes) are positioned on the other side of their respective Target Box,
but they are arranged opposite the Target Sphere (rather than the Pass Sphere). They act as a fail condition
if the Target Sphere happens the pass through the Target Box's rotated collider. They are named following the
same convention: Box_[X, Y, or Z]_Fail
Note: All boxes are set to "kinematic" so they do not move when a collision happens.
Expected Behavior:
Upon entering game mode, the spheres should follow their initial velocities. The Target Spheres should collide and
bounce off of the Target Boxes' rotated colliders, and the Pass Spheres should pass through the visible transforms
of their Target Boxes and collide with their respective Pass Boxes.
Test Steps:
1) Loads the level
2) Enters game mode
3) Retrieve and validate entities and starting locations
4) Wait for test to complete or time out
5) Log the results
6) Exit game mode and editor
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Internal editor imports
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
import azlmbr.legacy.general as general
import azlmbr.bus
import azlmbr
# ******** Global Variables ********
# Entity data organization class
class EntityData:
def __init__(self, name):
self.name = name
self.id = None
self.init_pos = None
self.current_pos = None
self.result = None
# fmt: off
# Establish entity sets
target_spheres = [EntityData("Sphere_X_Target"), EntityData("Sphere_Y_Target"), EntityData("Sphere_Z_Target")]
pass_thru_spheres = [EntityData("Sphere_X_Pass_Thru"), EntityData("Sphere_Y_Pass_Thru"), EntityData("Sphere_Z_Pass_Thru")]
target_boxes = [EntityData("Box_X_Target"), EntityData("Box_Y_Target"), EntityData("Box_Z_Target")]
pass_thru_boxes = [EntityData("Box_X_Pass_Thru"), EntityData("Box_Y_Pass_Thru"), EntityData("Box_Z_Pass_Thru")]
fail_boxes = [EntityData("Box_X_Fail"), EntityData("Box_Y_Fail"), EntityData("Box_Z_Fail")]
all_spheres = target_spheres + pass_thru_spheres
all_boxes = pass_thru_boxes + fail_boxes + target_boxes
all_entities = all_spheres + all_boxes
# Possible results
PASS_THRU = "pass thru"
FAIL = "fail"
TARGET = "target"
# fmt: on
# ******** Helper Functions ********
# Retrieve entities' IDs and initial positions.
# Fast Fails if there are any problems retrieving vital information
def retrieve_entities(entity_list, test_tuple):
# type: ([EntityData], (str, str)) -> None
passed = True
for entity in entity_list:
valid = True
entity.id = general.find_game_entity(entity.name)
if not entity.id.IsValid():
valid = False
Report.info("Entity: {} could not be found".format(entity.name))
entity.init_pos = entity.current_pos = azlmbr.components.TransformBus(
azlmbr.bus.Event, "GetWorldTranslation", entity.id
)
if entity.init_pos is None or entity.init_pos.IsZero():
valid = False
Report.info("Entity: {}'s initial position could not be found".format(entity.name))
if not valid:
passed = False
break
Report.critical_result(test_tuple, passed)
# Updates entities' current position
def refresh_positions(entity_list):
# type: ([EntityData]) -> None
for entity in entity_list:
entity.current_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", entity.id)
# Checks for unexpected movement in stationary objects
# Fast Fails and writes to the log if there is a difference between initial position and current position
def check_for_unexpected_movement(entity_list):
# type: ([EntityData]) -> None
for entity in entity_list:
if not entity.init_pos.IsClose(entity.current_pos, CLOSE_ENOUGH_THRESHOLD):
helper.fail_fast("{} has unexpectedly moved".format(entity.name))
# Verifies the results for the entities passed in.
# Returns a count of the verified results
def verify_results(entity_list, expected_result):
# type: ([EntityData], str) -> int
results_verified = 0
for entity in entity_list:
if entity.result == expected_result:
results_verified += 1
else:
Report.info("{} had unexpected result:".format(entity.name))
Report.info(" expected: {}".format(expected_result))
Report.info(" found: {}".format(entity.result))
return results_verified
# Batch assign event handlers
def set_handlers(entity_list, callback, event="OnCollisionBegin"):
# type: ([EntityData], function, str) -> [handler]
handlers = []
for entity in entity_list:
handler = azlmbr.physics.CollisionNotificationBusHandler()
handler.connect(entity.id)
handler.add_callback(event, callback)
handlers.append(handler)
return handlers
# Checks to see if we are done collecting results for the test
def done_collecting_results(entity_list, num_results):
# type: ([EntityData], int) -> bool
result_count = 0
for entity in entity_list:
if entity.result is not None:
result_count += 1
# When all spheres have a result we are done
return result_count == num_results
# Callback function to be passed to wait_for_condition
# Updates game entities' data, checks for failures and unexpected results,
# then returns True if we are done observing the test.
def test_completed():
refresh_positions(all_entities)
# check_for_failure(all_spheres)
check_for_unexpected_movement(all_boxes)
return done_collecting_results(all_spheres, TOTAL_SPHERES)
# ******** Event Handlers ********
# General collision handler
def on_collision_begin(collider_id, result):
# type: (EntityId, str) -> None
for sphere in all_spheres:
if sphere.id.Equal(collider_id):
Report.info("Entity: {} collided with a {} box".format(sphere.name, result))
if result is FAIL or sphere.result is None:
# Set result if not set yet OR the result is a failure (failure overrides success)
sphere.result = result
return
# It wasn't a sphere that collided, something went wrong
if collider_id.IsValid():
entity_name = azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "GetEntityName", collider_id)
Report.info("{} box collided with unexpected entity: {}".format(result, entity_name))
# Fail Box collision event handler
def on_collision_begin_fail_box(args):
# type: ([EntityId, ...]) -> None
on_collision_begin(args[0], FAIL)
# Success Box Collision Event Handler
def on_collision_begin_pass_thru_box(args):
# type: ([EntityId, ...]) -> None
on_collision_begin(args[0], PASS_THRU)
# Target box collision event handler
def on_collision_begin_target_box(args):
# type: ([EntityId, ...]) -> None
on_collision_begin(args[0], TARGET)
# ******** Execution Code *********
# Local Constants
TIME_OUT = 2.0
CLOSE_ENOUGH_THRESHOLD = 0.0001
TOTAL_TARGET_SPHERES = 3
TOTAL_PASS_THRU_SPHERES = 3
TOTAL_SPHERES = TOTAL_TARGET_SPHERES + TOTAL_PASS_THRU_SPHERES
helper.init_idle()
# 1) Open level
helper.open_level("Physics", "C4982798_Collider_ColliderRotationOffset")
# 2) Enter game mode
helper.enter_game_mode(Tests.enter_game_mode)
# 3) Retrieve and validate entities
retrieve_entities(all_boxes, Tests.boxes_found)
retrieve_entities(all_spheres, Tests.spheres_found)
# Assign handlers
handlers = []
handlers.extend(set_handlers(fail_boxes, on_collision_begin_fail_box))
handlers.extend(set_handlers(pass_thru_boxes, on_collision_begin_pass_thru_box))
handlers.extend(set_handlers(target_boxes, on_collision_begin_target_box))
# 4) Wait for either time out or for the test to complete
Report.result(Tests.test_completed, helper.wait_for_condition(test_completed, TIME_OUT))
# 5) Log results
# Verify entities results
pass_thru_spheres_passed = verify_results(pass_thru_spheres, PASS_THRU)
target_spheres_passed = verify_results(target_spheres, TARGET)
# Report results
Report.result(Tests.target_spheres_passed, target_spheres_passed == TOTAL_TARGET_SPHERES)
Report.result(Tests.pass_thru_spheres_passed, pass_thru_spheres_passed == TOTAL_PASS_THRU_SPHERES)
# Data dump at bottom of log
Report.info("******** Collected Data *********")
for entity in all_entities:
Report.info("Entity: {}".format(entity.name))
Report.info_vector3(entity.init_pos, " Initial position:")
Report.info_vector3(entity.current_pos, " Final position:")
Report.info(" Result: {}".format(entity.result))
Report.info("********************************")
# 6) Exit Game mode
helper.exit_game_mode(Tests.exit_game_mode)
Report.info("*** FINISHED TEST ***")
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C4982798_Collider_ColliderRotationOffset)
@@ -0,0 +1,93 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
Test case ID : C4982800
Test Case Title : Verify that the shape Sphere can be selected from the drop downlist and the value for its radius can be set
"""
# fmt: off
class Tests():
entity_created = ("Test Entity created successfully", "Failed to create Test Entity")
collider_added = ("PhysX Collider added successfully", "Failed to add PhysX Collider")
collider_shape_changed = ("PhysX Collider shape changed successfully", "Failed change PhysX Collider shape")
shape_dimensions_changed = ("Shape dimensions modified successfully", "Failed to modify Shape dimensions")
# fmt: on
def C4982800_PhysXColliderShape_CanBeSelected():
"""
Summary:
Adding PhysX Collider and Shape components to test entity, then attempting to modify the shape's dimensions
Expected Behavior:
Sphere shape can be selected for the Shape Component and the value for Radius can be changed
Test Steps:
1) Load the empty level
2) Create the test entity
3) Add PhysX Collider component to test entity
4) Change the PhysX Collider shape and store the original dimensions
5) Modify the dimensions
6) Verify they have been changed
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Helper Files
from editor_python_test_tools.editor_entity_utils import EditorEntity as Entity
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
# Open 3D Engine Imports
import azlmbr.math as math
SPHERE_SHAPETYPE_ENUM = 0
DIMENSION_TO_SET = 2.5
DIMENSION_SIZE_TOLERANCE = 0.5
helper.init_idle()
# 1) Load the empty level
helper.open_level("Physics", "Base")
# 2) Create the test entity
test_entity = Entity.create_editor_entity("Test Entity")
Report.result(Tests.entity_created, test_entity.id.IsValid())
# 3) Add PhysX Collider component to test entity
test_component = test_entity.add_component("PhysX Collider")
Report.result(Tests.collider_added, test_entity.has_component("PhysX Collider"))
# 4) Change the PhysX Collider shape and store the original dimensions
test_component.set_component_property_value("Shape Configuration|Shape", SPHERE_SHAPETYPE_ENUM)
add_check = test_component.get_component_property_value("Shape Configuration|Shape") == SPHERE_SHAPETYPE_ENUM
Report.result(Tests.collider_shape_changed, add_check)
# 5) Modify the dimensions
test_component.set_component_property_value("Shape Configuration|Sphere|Radius", DIMENSION_TO_SET)
# 6) Verify they have been changed
modified_dimensions = test_component.get_component_property_value("Shape Configuration|Sphere|Radius")
dimensions_successfully_modified = math.Math_IsClose(
DIMENSION_TO_SET, modified_dimensions, DIMENSION_SIZE_TOLERANCE
)
if not dimensions_successfully_modified:
assert (
False
), f"The modified value was not within the allowed tolerance\nExpected:{DIMENSION_TO_SET}\nActual: {modified_dimensions}"
Report.result(Tests.shape_dimensions_changed, dimensions_successfully_modified)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C4982800_PhysXColliderShape_CanBeSelected)
@@ -0,0 +1,105 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
Test case ID : C4982801
Test Case Title : Verify that the shape Box can be selected from drop downlist and the value for its dimensions in x,y,z can be set after that
"""
# fmt: off
class Tests():
entity_created = ("Test Entity created successfully", "Failed to create Test Entity")
collider_added = ("PhysX Collider added successfully", "Failed to add PhysX Collider")
collider_shape_changed = ("PhysX Collider shape changed successfully", "Failed change PhysX Collider shape")
shape_dimensions_changed = ("Shape dimensions modified successfully", "Failed to modify Shape dimensions")
# fmt: on
def C4982801_PhysXColliderShape_CanBeSelected():
"""
Summary:
Adding PhysX Collider and Shape components to test entity, then attempting to modify the shape's dimensions
Expected Behavior:
Box shape can be selected for the Shape Component and the value for X, Y, and Z dimensions can be changed
Test Steps:
1) Load the empty level
2) Create the test entity
3) Add PhysX Collider component to test entity
4) Change the PhysX Collider shape and store the original dimensions
5) Modify the dimensions
6) Verify they have been changed
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Helper Files
from editor_python_test_tools.editor_entity_utils import EditorEntity as Entity
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
# Open 3D Engine Imports
import azlmbr.math as math
BOX_SHAPETYPE_ENUM = 1
SET_SIZE = 2.5
SIZE_TOLERANCE = 0.5
def check_dimensions_changed(set_dimension_value, modified_dimensions, tolerance):
def compare_values(value_name, set_value, grabbed_value, tolerance):
within_tolerance = math.Math_IsClose(set_value, grabbed_value, tolerance)
if not within_tolerance:
assert (
False
), f"The modified value for {value_name} was not within the allowed tolerance\nExpected:{set_value}\nActual: {grabbed_value}"
return within_tolerance
# Check for X, Y, & Z values
x_value = compare_values("x_value", set_dimension_value, modified_dimensions.x, tolerance)
y_value = compare_values("y_value", set_dimension_value, modified_dimensions.y, tolerance)
z_value = compare_values("z_value", set_dimension_value, modified_dimensions.z, tolerance)
return x_value and y_value and z_value
helper.init_idle()
# 1) Load the empty level
helper.open_level("Physics", "Base")
# 2) Create the test entity
test_entity = Entity.create_editor_entity("Test Entity")
Report.result(Tests.entity_created, test_entity.id.IsValid())
# 3) Add PhysX Collider component to test entity
test_component = test_entity.add_component("PhysX Collider")
Report.result(Tests.collider_added, test_entity.has_component("PhysX Collider"))
# 4) Change the PhysX Collider shape and store the original dimensions
test_component.set_component_property_value("Shape Configuration|Shape", BOX_SHAPETYPE_ENUM)
add_check = test_component.get_component_property_value("Shape Configuration|Shape") == BOX_SHAPETYPE_ENUM
Report.result(Tests.collider_shape_changed, add_check)
# 5) Modify the dimensions
Report.info(f"Attempting to set XYZ values to {SET_SIZE}")
test_component.set_component_property_value(
"Shape Configuration|Box|Dimensions", math.Vector3(SET_SIZE, SET_SIZE, SET_SIZE)
)
mod_dimensions = test_component.get_component_property_value("Shape Configuration|Box|Dimensions")
# 6) Verify they have been changed
dimensions_successfully_changed = check_dimensions_changed(SET_SIZE, mod_dimensions, SIZE_TOLERANCE)
Report.result(Tests.shape_dimensions_changed, dimensions_successfully_changed)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C4982801_PhysXColliderShape_CanBeSelected)
@@ -0,0 +1,105 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
Test case ID : C4982802
Test Case Title : Verify that the shape capsule can be selected from drop downlist and the value for its height and radius can be set after that
"""
# fmt: off
class Tests():
entity_created = ("Test Entity created successfully", "Failed to create Test Entity")
collider_added = ("PhysX Collider added successfully", "Failed to add PhysX Collider")
collider_shape_changed = ("PhysX Collider shape changed successfully", "Failed change PhysX Collider shape")
shape_dimensions_changed = ("Shape dimensions modified successfully", "Failed to modify Shape dimensions")
# fmt: on
def C4982802_PhysXColliderShape_CanBeSelected():
"""
Summary:
Adding PhysX Collider and Shape components to test entity, then attempting to modify the shape's dimensions
Expected Behavior:
Capsule shape can be selected for the Shape Component and the value for Height and Radius can be changed
Test Steps:
1) Load the empty level
2) Create the test entity
3) Add PhysX Collider component to test entity
4) Change the PhysX Collider shape
5) Modify the dimensions
6) Verify they have been changed
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Helper Files
from editor_python_test_tools.editor_entity_utils import EditorEntity as Entity
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
# Open 3D Engine Imports
import azlmbr.math as math
CAPSULE_SHAPETYPE_ENUM = 2
# Note from Editor Console: Height must exceed twice the radius in capsule configuration
SIZE_RADIUS = 4.0
SIZE_HEIGHT = SIZE_RADIUS * 2 + 1.0
SIZE_TOLERANCE = 0.5
def change_dimension_value(component, component_property_path, value):
Report.info(f"Attempting to set value for {component_property_path} to {value}")
component.set_component_property_value(component_property_path, value)
returning_value = component.get_component_property_value(component_property_path)
Report.info(f"Value for {component_property_path} is currently {returning_value}")
return returning_value
def check_dimension_change(value_name, value_set, grabbed_value, tolerance):
within_tolerance = math.Math_IsClose(value_set, grabbed_value, tolerance)
if not within_tolerance:
assert (
False
), f"The modified value for {value_name} was not within the allowed tolerance\nExpected:{value_set}\nActual: {grabbed_value}"
return within_tolerance
helper.init_idle()
# 1) Load the empty level
helper.open_level("Physics", "Base")
# 2) Create the test entity
test_entity = Entity.create_editor_entity("Test Entity")
Report.result(Tests.entity_created, test_entity.id.IsValid())
# 3) Add PhysX Collider component to test entity
test_component = test_entity.add_component("PhysX Collider")
Report.result(Tests.collider_added, test_entity.has_component("PhysX Collider"))
# 4) Change the PhysX Collider shape
test_component.set_component_property_value("Shape Configuration|Shape", CAPSULE_SHAPETYPE_ENUM)
add_check = test_component.get_component_property_value("Shape Configuration|Shape") == CAPSULE_SHAPETYPE_ENUM
Report.result(Tests.collider_shape_changed, add_check)
# 5) Modify the dimensions
mod_height = change_dimension_value(test_component, "Shape Configuration|Capsule|Height", SIZE_HEIGHT)
mod_radius = change_dimension_value(test_component, "Shape Configuration|Capsule|Radius", SIZE_RADIUS)
# 6) Verify they have been changed
resulting_check = check_dimension_change(
"Height", SIZE_HEIGHT, mod_height, SIZE_TOLERANCE
) and check_dimension_change("Radius", SIZE_RADIUS, mod_radius, SIZE_TOLERANCE)
Report.result(Tests.shape_dimensions_changed, resulting_check)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C4982802_PhysXColliderShape_CanBeSelected)
@@ -0,0 +1,143 @@
"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
Test case ID : C4982803
Test Case Title : Verify that when the shape Physics Asset is selected,
PxMesh option gets enabled and a Px Mesh can be selected and assigned to the object
"""
# fmt: off
class Tests():
create_collider_entity = ("Entity created successfully", "Failed to create Entity")
mesh_added = ("Added Mesh component", "Failed to add Mesh component")
physx_collider_added = ("Added PhysX Collider component", "Failed to add PhysX Collider component")
physx_rigid_body_added = ("Added PhysX Rigid Body component", "Failed to add PhysX Rigid Body component")
add_physics_asset_shape = ("Added shape as physics asset", "Failed to add shape ")
assign_fbx_mesh = ("Assigned fbx mesh", "Failed to assign fbx mesh")
create_terrain = ("Terrain entity created successfully", "Failed to create Terrain Entity")
add_physx_shape_collider = ("Added PhysX Shape Collider", "Failed to add PhysX Shape Collider")
add_box_shape = ("Added Box Shape", "Failed to add Box Shape")
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
exit_game_mode = ("Exited game mode", "Failed to exit game mode")
test_collision = ("Entity collided with terrain", "Failed to collide with terrain")
# fmt: on
def C4982803_Enable_PxMesh_Option():
"""
Summary:
Load level with Entity above ground having PhysX Collider, PhysX Rigid Body and Mesh components.
Verify that the entity falls on the ground and collides with the terrain when fbx convex mesh is added to collider.
Expected Behavior:
The entity falls on the ground and collides with the terrain.
Test Steps:
1) Load the level
2) Create test entity above the ground
3) Add PhysX Collider, PhysX Rigid Body and Mesh components.
4) Add the Shape as PhysicsAsset and select fbx convex mesh in PhysX Collider component.
5) Create terrain entity with physx terrain
6) Enter game mode
7) Verify that the entity falls on the ground and collides with the terrain.
Note:
- This test file must be called from the Open 3D Engine Editor command terminal
- Any passed and failed tests are written to the Editor.log file.
Parsing the file or running a log_monitor are required to observe the test results.
:return: None
"""
# Builtins
import os
# Helper Files
from editor_python_test_tools.editor_entity_utils import EditorEntity
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
from editor_python_test_tools.asset_utils import Asset
import azlmbr.math as math
# Open 3D Engine Imports
import azlmbr
import azlmbr.legacy.general as general
# Constants
PHYSICS_ASSET_INDEX = 7 # Hardcoded enum index value for Shape property
MESH_ASSET_PATH = os.path.join("assets", "c4982803_enable_pxmesh_option", "spherebot", "r0-b_body.pxmesh")
TIMEOUT = 2.0
helper.init_idle()
# 1) Load the level
helper.open_level("Physics", "Base")
# 2) Create test entity
collider = EditorEntity.create_editor_entity_at([512.0, 512.0, 33.0], "Collider")
Report.result(Tests.create_collider_entity, collider.id.IsValid())
# 3) Add PhysX Collider, PhysX Rigid Body and Mesh components.
collider_component = collider.add_component("PhysX Collider")
Report.result(Tests.physx_collider_added, collider.has_component("PhysX Collider"))
collider.add_component("PhysX Rigid Body")
Report.result(Tests.physx_rigid_body_added, collider.has_component("PhysX Rigid Body"))
collider.add_component("Mesh")
Report.result(Tests.mesh_added, collider.has_component("Mesh"))
# 4) Add the Shape as PhysicsAsset and select fbx convex mesh in PhysX Collider component.
collider_component.set_component_property_value("Shape Configuration|Shape", PHYSICS_ASSET_INDEX)
value_to_test = collider_component.get_component_property_value("Shape Configuration|Shape")
Report.result(Tests.add_physics_asset_shape, value_to_test == PHYSICS_ASSET_INDEX)
mesh_asset = Asset.find_asset_by_path(MESH_ASSET_PATH)
collider_component.set_component_property_value("Shape Configuration|Asset|PhysX Mesh", mesh_asset.id)
mesh_asset.id = collider_component.get_component_property_value("Shape Configuration|Asset|PhysX Mesh")
Report.result(Tests.assign_fbx_mesh, mesh_asset.get_path() == MESH_ASSET_PATH.replace(os.sep, "/"))
# 5) Create terrain entity with physx terrain
terrain = EditorEntity.create_editor_entity_at([512.0, 512.0, 31.0], "Terrain")
Report.result(Tests.create_terrain, terrain.id.IsValid())
terrain.add_component("PhysX Shape Collider")
Report.result(Tests.add_physx_shape_collider, terrain.has_component("PhysX Shape Collider"))
box_shape_component = terrain.add_component("Box Shape")
Report.result(Tests.add_box_shape, terrain.has_component("Box Shape"))
box_shape_component.set_component_property_value("Box Shape|Box Configuration|Dimensions",
math.Vector3(1024.0, 1024.0, 1.0))
# 6) Enter game mode
helper.enter_game_mode(Tests.enter_game_mode)
# 7) Verify that the entity falls on the ground and collides with the terrain
class Collider:
id = general.find_game_entity("Collider")
touched_ground = False
terrain_id = general.find_game_entity("Terrain")
def on_collision_begin(args):
other_id = args[0]
if other_id.Equal(terrain_id):
Report.info("Touched ground")
Collider.touched_ground = True
handler = azlmbr.physics.CollisionNotificationBusHandler()
handler.connect(Collider.id)
handler.add_callback("OnCollisionBegin", on_collision_begin)
helper.wait_for_condition(lambda: Collider.touched_ground, TIMEOUT)
Report.result(Tests.test_collision, Collider.touched_ground)
# 8) Exit game mode
helper.exit_game_mode(Tests.exit_game_mode)
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(C4982803_Enable_PxMesh_Option)