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:
+76
@@ -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)
|
||||
+83
@@ -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)
|
||||
+72
@@ -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)
|
||||
+93
@@ -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)
|
||||
+95
@@ -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)
|
||||
+104
@@ -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)
|
||||
+94
@@ -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)
|
||||
+92
@@ -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)
|
||||
+98
@@ -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)
|
||||
+136
@@ -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)
|
||||
+361
@@ -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)
|
||||
+109
@@ -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)
|
||||
+86
@@ -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)
|
||||
+187
@@ -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)
|
||||
+126
@@ -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)
|
||||
+184
@@ -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)
|
||||
+222
@@ -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)
|
||||
+230
@@ -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)
|
||||
+233
@@ -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)
|
||||
+334
@@ -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)
|
||||
+302
@@ -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)
|
||||
+93
@@ -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)
|
||||
+105
@@ -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)
|
||||
+105
@@ -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)
|
||||
Reference in New Issue
Block a user