ScriptCanvas_CollisionEvents.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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 : C12712452
  7. # Test Case Title : Verify ScriptCanvas Collision Events
  8. # fmt: off
  9. class Tests:
  10. enter_game_mode = ("Entered game mode", "Failed to enter game mode")
  11. terrain_found_valid = ("PhysX Terrain found and validated", "PhysX Terrain not found and validated")
  12. sphere_found_valid = ("Sphere found and validated", "Sphere not found and validated")
  13. begin_signal_found_valid = ("Begin Signal found and validated", "Begin Signal not found and validated")
  14. persist_signal_found_valid = ("Persist Signal found and validated", "Persist Signal not found and validated")
  15. end_signal_found_valid = ("End Signal found and validated", "End Signal not found and validated")
  16. sphere_above_terrain = ("Sphere is above terrain", "Sphere is not above terrain")
  17. sphere_gravity_enabled = ("Gravity is enabled on Sphere", "Gravity is not enabled on Sphere")
  18. sphere_started_bouncing = ("Sphere started bouncing", "Sphere did not start bouncing")
  19. sphere_stopped_bouncing = ("Sphere stopped bouncing", "Sphere did not stop bouncing")
  20. event_records_match = ("Event records match", "Event records do not match")
  21. exit_game_mode = ("Exited game mode", "Failed to exit game mode")
  22. # fmt: on
  23. def ScriptCanvas_CollisionEvents():
  24. """
  25. Summary:
  26. This script runs an automated test to verify that the Script Canvas nodes "On Collision Begin", "On Collision
  27. Persist", and "On Collision End" will function as intended for the entity to which their Script Canvas is attached.
  28. Level Description:
  29. A sphere (entity: Sphere) is above a terrain (entity: PhysX Terrain). The sphere has a PhysX Rigid Body, a PhysX
  30. Collider with shape Sphere, and gravity enabled. The sphere has a Script Canvas attached to it which will toggle the
  31. activation of three signal entities (entity: Begin Signal), (entity: Persist Signal), and (entity: End Signal).
  32. Begin Signal's activation will toggle (switch from activated to deactivated or vice versa) when a collision begins
  33. with the sphere, Persist Signal's activation will toggle when a collision persists with the sphere, and End Signal's
  34. activation will toggle when a collision ends with the sphere.
  35. Expected behavior:
  36. The sphere will fall toward and collide with the terrain. The sphere will bounce until it comes to rest. The Script
  37. Canvas will cause the signal entities to activate and deactivate in the same pattern as the collision events which
  38. occur on the sphere.
  39. Test Steps:
  40. 1) Open level and enter game mode
  41. 2) Retrieve and validate entities
  42. 3) Check that the sphere is above the terrain
  43. 4) Check that gravity is enabled on the sphere
  44. 5) Wait for the initial collision between the sphere and the terrain or timeout
  45. 6) Wait for the sphere to stop bouncing
  46. 7 Check that the event records match
  47. 8) 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. # Setup path
  55. import os
  56. import sys
  57. import azlmbr.legacy.general as general
  58. import azlmbr.bus
  59. import azlmbr.components
  60. import azlmbr.entity
  61. import azlmbr.physics
  62. from editor_python_test_tools.utils import Report
  63. from editor_python_test_tools.utils import TestHelper as helper
  64. # Constants
  65. TIME_OUT_SECONDS = 3.0
  66. TERRAIN_START_Z = 32.0
  67. SPHERE_RADIUS = 1.0
  68. class Entity:
  69. def __init__(self, name, found_valid_test):
  70. self.name = name
  71. self.id = general.find_game_entity(name)
  72. self.found_valid_test = found_valid_test
  73. class Sphere(Entity):
  74. def __init__(self, name, found_valid_test, event_records_match_test):
  75. Entity.__init__(self, name, found_valid_test)
  76. self.event_records_match_test = event_records_match_test
  77. self.collided = False
  78. self.stopped_bouncing = False
  79. self.collision_event_record = []
  80. self.script_canvas_event_record = []
  81. # Set up collision notification handler
  82. self.handler = azlmbr.physics.CollisionNotificationBusHandler()
  83. self.handler.connect(self.id)
  84. self.handler.add_callback("OnCollisionBegin", self.on_collision_begin)
  85. self.handler.add_callback("OnCollisionPersist", self.on_collision_persist)
  86. self.handler.add_callback("OnCollisionEnd", self.on_collision_end)
  87. def get_z_position(self):
  88. z_position = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldZ", self.id)
  89. Report.info("{}'s z-position: {}".format(self.name, z_position))
  90. return z_position
  91. def is_gravity_enabled(self):
  92. return azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "IsGravityEnabled", self.id)
  93. # Set up reporting of the event records and whether they match
  94. def match_event_records(self):
  95. Report.info("{} collision event record: {}".format(self.name, self.collision_event_record))
  96. Report.info("Script Canvas event record: {}".format(self.script_canvas_event_record))
  97. return self.collision_event_record == self.script_canvas_event_record
  98. # Set up collision event detection and update collision event record
  99. def on_collision(self, event, other_id):
  100. if not self.collided:
  101. self.collided = True
  102. other_name = azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "GetEntityName", other_id)
  103. Report.info("{} collision {}s with {}".format(self.name, event, other_name))
  104. self.collision_event_record.append(event)
  105. def on_collision_begin(self, args):
  106. self.on_collision("begin", args[0])
  107. def on_collision_persist(self, args):
  108. self.on_collision("persist", args[0])
  109. def on_collision_end(self, args):
  110. self.on_collision("end", args[0])
  111. # Set up detection of the sphere coming to rest
  112. def bouncing_stopped(self):
  113. if not azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "IsAwake", self.id):
  114. self.stopped_bouncing = True
  115. return self.stopped_bouncing
  116. class SignalEntity(Entity):
  117. def __init__(self, name, found_valid_test, monitored_entity, event):
  118. Entity.__init__(self, name, found_valid_test)
  119. self.monitored_entity = monitored_entity
  120. self.event = event
  121. # Set up activation and deactivation notification handler
  122. self.handler = azlmbr.entity.EntityBusHandler()
  123. self.handler.connect(self.id)
  124. self.handler.add_callback("OnEntityActivated", self.on_entity_activated)
  125. self.handler.add_callback("OnEntityDeactivated", self.on_entity_deactivated)
  126. # Set up activation and deactivation detection and update Script Canvas event record
  127. def on_entity_activated(self, args):
  128. self.monitored_entity.script_canvas_event_record.append(self.event)
  129. def on_entity_deactivated(self, args):
  130. self.monitored_entity.script_canvas_event_record.append(self.event)
  131. # 1) Open level and enter game mode
  132. helper.init_idle()
  133. helper.open_level("Physics", "ScriptCanvas_CollisionEvents")
  134. helper.enter_game_mode(Tests.enter_game_mode)
  135. # 2) Retrieve and validate entities
  136. terrain = Entity("PhysX Terrain", Tests.terrain_found_valid)
  137. sphere = Sphere("Sphere", Tests.sphere_found_valid, Tests.event_records_match)
  138. begin_signal = SignalEntity("Begin Signal", Tests.begin_signal_found_valid, sphere, "begin")
  139. persist_signal = SignalEntity("Persist Signal", Tests.persist_signal_found_valid, sphere, "persist")
  140. end_signal = SignalEntity("End Signal", Tests.end_signal_found_valid, sphere, "end")
  141. entities = [terrain, sphere, begin_signal, persist_signal, end_signal]
  142. for entity in entities:
  143. Report.critical_result(entity.found_valid_test, entity.id.IsValid())
  144. # 3) Check that the sphere is above the terrain
  145. Report.critical_result(Tests.sphere_above_terrain, sphere.get_z_position() - SPHERE_RADIUS > TERRAIN_START_Z)
  146. # 4) Check that gravity is enabled on the sphere
  147. Report.critical_result(Tests.sphere_gravity_enabled, sphere.is_gravity_enabled())
  148. # 5) Wait for the initial collision between the sphere and the terrain or timeout
  149. helper.wait_for_condition(lambda: sphere.collided, TIME_OUT_SECONDS)
  150. Report.critical_result(Tests.sphere_started_bouncing, sphere.collided)
  151. # 6) Wait for the sphere to stop bouncing
  152. helper.wait_for_condition(sphere.bouncing_stopped, TIME_OUT_SECONDS)
  153. Report.result(Tests.sphere_stopped_bouncing, sphere.stopped_bouncing)
  154. # 7 Check that the event records match
  155. Report.result(Tests.event_records_match, sphere.match_event_records())
  156. # 8) Exit game mode and close editor
  157. helper.exit_game_mode(Tests.exit_game_mode)
  158. if __name__ == "__main__":
  159. from editor_python_test_tools.utils import Report
  160. Report.start_test(ScriptCanvas_CollisionEvents)