Material_EmptyLibraryUsesDefault.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. """
  2. Copyright (c) Contributors to the Open 3D Engine Project.
  3. For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. SPDX-License-Identifier: Apache-2.0 OR MIT
  5. """
  6. # Test Case ID : C4044694
  7. # Test Case Title : Verify that if we add an empty Material library in Collider Component, the object continues to use Default material values
  8. # fmt: off
  9. class Tests:
  10. enter_game_mode = ("Entered game mode", "Failed to enter game mode")
  11. find_terrain = ("The Terrain was found", "The Terrain was not found")
  12. find_default_box = ("'default_box' was found", "'default_box' was not found")
  13. find_empty_box = ("'empty_box' was found", "'empty_box' was not found")
  14. find_default_sphere = ("'default_sphere' was found", "'default_sphere' was not found")
  15. find_empty_sphere = ("'empty_sphere' was found", "'empty_sphere' was not found")
  16. boxes_moved = ("All boxes moved", "Boxes failed to move")
  17. boxes_at_rest = ("All boxes came to rest", "Boxes failed to come to rest")
  18. default_sphere_bounced = ("'default_sphere' bounced", "'default_sphere' did not bounce")
  19. empty_sphere_bounced = ("'empty_sphere' bounced", "'empty_sphere' did not bounce")
  20. default_box_equals_empty = ("'default_box' and 'empty_box' traveled the same distance", "'default_box' and 'empty_box' did not travel the same distance")
  21. default_sphere_equals_empty = ("'default_sphere' and 'empty_sphere' bounce heights were equal", "'default_sphere' and 'empty_sphere' bounce heights were not equal")
  22. exit_game_mode = ("Exited game mode", "Failed to exit game mode")
  23. # fmt: on
  24. def Material_EmptyLibraryUsesDefault():
  25. """
  26. Summary:
  27. Runs an automated test to verify that an object with an empty Material library in a Collider Component continues to
  28. use the default material values
  29. Level Description:
  30. There are 5 entities.
  31. One terrain entity ('terrain') with PhysX Terrain,
  32. Two sphere entities ('empty_sphere' and 'default_sphere') with PhysX Rigid Body and PhysX Sphere Collider,
  33. Two box entities ('empty_box' and 'default_box') with PhysX Rigid Body and PhysX Box Collider,
  34. The spheres are positioned above the terrain, and the boxes are placed on the terrain.
  35. The "empty" entities are assigned a material library that contains no materials. The "default" entities are assigned
  36. the default material from the default material library.
  37. Expected behavior:
  38. The spheres fall and bounce the same height.
  39. The boxes are pushed and travel the same distance.
  40. Test Steps:
  41. 1) Open level and enter game mode
  42. 2) Find entities
  43. 3) Wait for spheres to bounce
  44. 4) Compare 'default_sphere' to 'empty_sphere'
  45. 5) Push the boxes and wait for them to come to rest
  46. 6) Compare 'default_box' to 'empty_box'
  47. 7) Exit game mode and close editor
  48. Note:
  49. - This test file must be called from the Open 3D Engine Editor command terminal
  50. - Any passed and failed tests are written to the Editor.log file.
  51. Parsing the file or running a log_monitor are required to observe the test results.
  52. :return: None
  53. """
  54. import os
  55. import sys
  56. import azlmbr.legacy.general as general
  57. import azlmbr.bus as bus
  58. import azlmbr.components
  59. import azlmbr.physics
  60. import azlmbr.math as lymath
  61. from editor_python_test_tools.utils import Report
  62. from editor_python_test_tools.utils import TestHelper as helper
  63. FORCE_IMPULSE = lymath.Vector3(5.0, 0.0, 0.0)
  64. TIMEOUT = 3.0
  65. DISTANCE_TOLERANCE = 0.001
  66. class Entity:
  67. def __init__(self, name):
  68. self.name = name
  69. self.id = general.find_game_entity(self.name)
  70. @property
  71. def position(self):
  72. return azlmbr.components.TransformBus(bus.Event, "GetWorldTranslation", self.id)
  73. class Box(Entity):
  74. def __init__(self, name):
  75. Entity.__init__(self, name)
  76. self.start_position = self.position
  77. def is_stationary(self):
  78. velocity = azlmbr.physics.RigidBodyRequestBus(bus.Event, "GetLinearVelocity", self.id)
  79. return velocity.IsZero()
  80. def push(self):
  81. azlmbr.physics.RigidBodyRequestBus(bus.Event, "ApplyLinearImpulse", self.id, FORCE_IMPULSE)
  82. class Sphere(Entity):
  83. def __init__(self, name):
  84. Entity.__init__(self, name)
  85. self.hit_terrain_position = None
  86. self.hit_terrain = False
  87. self.max_bounce = 0.0
  88. self.reached_max_bounce = False
  89. def on_collision_enter(args):
  90. entering = args[0]
  91. for sphere in [default_sphere, empty_sphere]:
  92. if sphere.id.Equal(entering):
  93. if not sphere.hit_terrain:
  94. sphere.hit_terrain_position = sphere.position
  95. sphere.hit_terrain = True
  96. # region wait_for_condition() functions
  97. def wait_for_bounce():
  98. for sphere in [default_sphere, empty_sphere]:
  99. if sphere.hit_terrain:
  100. current_bounce_height = sphere.position.z - sphere.hit_terrain_position.z
  101. if current_bounce_height >= sphere.max_bounce:
  102. sphere.max_bounce = current_bounce_height
  103. elif sphere.max_bounce > 0.0:
  104. sphere.reached_max_bounce = True
  105. return default_sphere.reached_max_bounce and empty_sphere.reached_max_bounce
  106. def boxes_moved():
  107. return not default_box.is_stationary() and not empty_box.is_stationary()
  108. def boxes_are_stationary():
  109. return default_box.is_stationary() and empty_box.is_stationary()
  110. # endregion
  111. # 1) Open level and enter game mode
  112. helper.init_idle()
  113. helper.open_level("Physics", "Material_EmptyLibraryUsesDefault")
  114. helper.enter_game_mode(Tests.enter_game_mode)
  115. # 2) Find entities
  116. terrain_id = general.find_game_entity("terrain")
  117. default_box = Box("default_box")
  118. empty_box = Box("empty_box")
  119. default_sphere = Sphere("default_sphere")
  120. empty_sphere = Sphere("empty_sphere")
  121. Report.result(Tests.find_terrain, terrain_id.IsValid())
  122. Report.result(Tests.find_default_box, default_box.id.IsValid())
  123. Report.result(Tests.find_empty_box, empty_box.id.IsValid())
  124. Report.result(Tests.find_default_sphere, default_sphere.id.IsValid())
  125. Report.result(Tests.find_empty_sphere, empty_sphere.id.IsValid())
  126. # Setup terrain collision handler
  127. handler = azlmbr.physics.CollisionNotificationBusHandler()
  128. handler.connect(terrain_id)
  129. handler.add_callback("OnCollisionBegin", on_collision_enter)
  130. # 3) Wait for spheres to bounce
  131. helper.wait_for_condition(wait_for_bounce, TIMEOUT)
  132. Report.result(Tests.default_sphere_bounced, default_sphere.reached_max_bounce)
  133. Report.result(Tests.empty_sphere_bounced, empty_sphere.reached_max_bounce)
  134. # 4) Compare 'default_sphere' to 'empty_sphere'
  135. sphere_bounces_equal = lymath.Math_IsClose(default_sphere.max_bounce, empty_sphere.max_bounce, DISTANCE_TOLERANCE)
  136. Report.result(Tests.default_sphere_equals_empty, sphere_bounces_equal)
  137. # 5) Push the boxes and wait for them to come to rest
  138. default_box.push()
  139. empty_box.push()
  140. Report.result(Tests.boxes_moved, helper.wait_for_condition(boxes_moved, TIMEOUT))
  141. Report.result(Tests.boxes_at_rest, helper.wait_for_condition(boxes_are_stationary, TIMEOUT))
  142. # 6) Compare 'default_box' to 'empty_box'
  143. default_distance = default_box.position.GetDistance(default_box.start_position)
  144. empty_distance = empty_box.position.GetDistance(empty_box.start_position)
  145. box_distances_equal = lymath.Math_IsClose(default_distance, empty_distance, DISTANCE_TOLERANCE)
  146. Report.result(Tests.default_box_equals_empty, box_distances_equal)
  147. # 7) Exit game mode and close editor
  148. helper.exit_game_mode(Tests.exit_game_mode)
  149. if __name__ == "__main__":
  150. from editor_python_test_tools.utils import Report
  151. Report.start_test(Material_EmptyLibraryUsesDefault)