123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- """
- 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 : C4044457
- # Test Case Title : Verify that when two objects with different materials collide, the restitution combine works
- # fmt: off
- class Tests():
- enter_game_mode = ("Entered game mode", "Failed to enter game mode")
- find_ramp = ("Ramp entity found", "Ramp entity not found")
- find_box_minimum = ("Box entity 'minimum' found", "Box entity 'minimum' not found")
- find_box_multiply = ("Box entity 'multiply' found", "Box entity 'multiply' not found")
- find_box_average = ("Box entity 'average' found", "Box entity 'average' not found")
- find_box_maximum = ("Box entity 'maximum' found", "Box entity 'maximum' not found")
- box_fell_minimum = ("Box 'minimum' fell", "Box 'minimum' did not fall")
- box_fell_multiply = ("Box 'multiply' fell", "Box 'multiply' did not fall")
- box_fell_average = ("Box 'average' fell", "Box 'average' did not fall")
- box_fell_maximum = ("Box 'maximum' fell", "Box 'maximum' did not fall")
- box_hit_ramp_minimum = ("Box 'minimum' hit the ramp", "Box 'minimum' did not hit the ramp before timeout")
- box_hit_ramp_multiply = ("Box 'multiply' hit the ramp", "Box 'multiply' did not hit the ramp before timeout")
- box_hit_ramp_average = ("Box 'average' hit the ramp", "Box 'average' did not hit the ramp before timeout")
- box_hit_ramp_maximum = ("Box 'maximum' hit the ramp", "Box 'maximum' did not hit the ramp before timeout")
- box_peaked_minimum = ("Box 'minimum' reached its max height", "Box 'minimum' did not reach its' max height before timeout")
- box_peaked_multiply = ("Box 'multiply' reached its max height", "Box 'multiply' did not reach its' max height before timeout")
- box_peaked_average = ("Box 'average' reached its max height", "Box 'average' did not reach its' max height before timeout")
- box_peaked_maximum = ("Box 'maximum' reached its max height", "Box 'maximum' did not reach its' max height before timeout")
- minimum_equals_multiply = ("Box 'minimum' and 'multiply' bounced equal heights", "Box 'minimum' and 'multiply' did not bounce equal heights")
- distance_ordered = ("Boxes with greater restitution values bounced higher", "Boxes with greater restitution values did not bounce higher")
- exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
- # fmt: on
- def Material_RestitutionCombine():
- """
- Summary:
- Level Description:
- Four boxes sit above a horizontal 'ramp'. Gravity on each rigidbody component is set to disabled.
- The boxes are identical, save for their physX material.
- A new material library was created with 4 materials, minimum, multiply, average, and maximum.
- Each material has its 'restitution combine' mode assigned as named; as well as the following properties:
- dynamic friction: 0.1
- static friction: 0.1
- restitution: 0.1
- An additional material was created for the ramp entity. It has the following properties:
- dynamic friction: 1.0
- static friction: 1.0
- restitution: 1.0
- friction combine: Average
- Each box is assigned its corresponding material
- Each box also has a PhysX box collider with default settings
- Expected Behavior:
- For each box, this script will enable gravity, then wait for the box to collide with the ramp.
- It then measures the height of the bounce relative to when it first came in contact with the ramp.
- When the z component of the box's velocity reaches zero (or below zero), the box latches its bounce height.
- The box is then frozen in place and the steps run for the next box in the list.
- Boxes with greater restitution combine mode retain more energy between collisions, therefore bouncing higher.
- minimum: 0.1 vs 1 -> 0.1
- multiply: 0.1 * 1 -> 0.1
- average: (0.1 + 1) / 2 -> 0.55
- maximum: 0.1 vs 1 -> 1
- Test Steps:
- 1) Open level
- 2) Enter game mode
- 3) Find the ramp
- For each box:
- 4) Find the box
- 5) Drop the box
- 6) Ensure the box collides with the ramp
- 7) Ensure the box reaches its peak height
- 8) Special case: assert that minimum and multiply bounce the same height
- 9) Assert that greater restitution combine modes bounce higher
- 10) Exit game mode
- 11) 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
- import azlmbr.legacy.general as general
- import azlmbr.bus as bus
- import azlmbr.math as lymath
- DISTANCE_TOLERANCE = 0.005
- TIMEOUT = 5
- class Box:
- def __init__(self, name, valid_test, fell_test, hit_ramp_test, peaked_test):
- self.name = name
- self.id = general.find_game_entity(name)
- self.start_position = self.get_position()
- self.hit_ramp = False
- self.hit_ramp_position = None
- self.bounce_height = 0.0
- self.valid_test = valid_test
- self.fell_test = fell_test
- self.hit_ramp_test = hit_ramp_test
- self.peaked_test = peaked_test
- self.set_gravity_enabled(False)
- def get_position(self):
- return azlmbr.components.TransformBus(bus.Event, "GetWorldTranslation", self.id)
- def get_velocity(self):
- return azlmbr.physics.RigidBodyRequestBus(bus.Event, "GetLinearVelocity", self.id)
- def set_velocity(self, value):
- return azlmbr.physics.RigidBodyRequestBus(bus.Event, "SetLinearVelocity", self.id, value)
- def set_gravity_enabled(self, value):
- azlmbr.physics.RigidBodyRequestBus(bus.Event, "SetGravityEnabled", self.id, value)
- def on_collision_begin(args):
- other_id = args[0]
- for box in all_boxes:
- if box.id.Equal(other_id):
- box.hit_ramp_position = box.get_position()
- box.hit_ramp = True
- def reached_max_height(box):
- current_position = box.get_position()
- current_height = current_position.z - box.hit_ramp_position.z
- current_linear_velocity = box.get_velocity()
- if current_linear_velocity.z > 0.0:
- box.bounce_height = current_height
- return False
- else:
- Report.info("Box {} reached {:.3f}M high".format(box.name, box.bounce_height))
- return True
- def is_falling(box):
- return box.get_velocity().z < 0.0
- def float_is_close(value, target, tolerance):
- return abs(value - target) <= tolerance
- helper.init_idle()
- # 1) Open level
- helper.open_level("Physics", "Material_RestitutionCombine")
- # 2) Enter game mode
- helper.enter_game_mode(Tests.enter_game_mode)
- # fmt: off
- # Set up our boxes
- box_minimum = Box(
- name = "Minimum",
- valid_test = Tests.find_box_minimum,
- fell_test = Tests.box_fell_minimum,
- hit_ramp_test = Tests.box_hit_ramp_minimum,
- peaked_test = Tests.box_peaked_minimum,
- )
- box_multiply = Box(
- name = "Multiply",
- valid_test = Tests.find_box_multiply,
- fell_test = Tests.box_fell_multiply,
- hit_ramp_test = Tests.box_hit_ramp_multiply,
- peaked_test = Tests.box_peaked_multiply,
- )
- box_average = Box(
- name = "Average",
- valid_test = Tests.find_box_average,
- fell_test = Tests.box_fell_average,
- hit_ramp_test = Tests.box_hit_ramp_average,
- peaked_test = Tests.box_peaked_average,
- )
- box_maximum = Box(
- name = "Maximum",
- valid_test = Tests.find_box_maximum,
- fell_test = Tests.box_fell_maximum,
- hit_ramp_test = Tests.box_hit_ramp_maximum,
- peaked_test = Tests.box_peaked_maximum,
- )
- all_boxes = (box_minimum, box_multiply, box_average, box_maximum)
- # fmt: on
- # 3) Find the ramp
- ramp_id = general.find_game_entity("Ramp")
- Report.critical_result(Tests.find_ramp, ramp_id.IsValid())
- handler = azlmbr.physics.CollisionNotificationBusHandler()
- handler.connect(ramp_id)
- handler.add_callback("OnCollisionBegin", on_collision_begin)
- for box in all_boxes:
- Report.info("********Dropping Box {}********".format(box.name))
- # 4) Find the box
- Report.critical_result(box.valid_test, box.id.IsValid())
- # 5) Drop the box
- box.set_gravity_enabled(True)
- Report.critical_result(box.fell_test, helper.wait_for_condition(lambda: is_falling(box), TIMEOUT))
- # 6) Wait for the box to hit the ground
- Report.result(box.hit_ramp_test, helper.wait_for_condition(lambda: box.hit_ramp, TIMEOUT))
- # 7) Measure the bounce height
- Report.result(box.peaked_test, helper.wait_for_condition(lambda: reached_max_height(box), TIMEOUT))
- # Freeze the box so it does not interfere with the other boxes
- box.set_velocity(lymath.Vector3(0.0, 0.0, 0.0))
- box.set_gravity_enabled(False)
- # 8) Special case: assert that minimum and multiply bounce the same height
- boxes_are_close = float_is_close(box_minimum.bounce_height, box_multiply.bounce_height, DISTANCE_TOLERANCE)
- Report.result(Tests.minimum_equals_multiply, boxes_are_close)
- # 9) Assert that greater coefficients result in higher bounces
- distance_ordered = (
- boxes_are_close and box_minimum.bounce_height < box_average.bounce_height < box_maximum.bounce_height
- )
- Report.result(Tests.distance_ordered, distance_ordered)
- # 10) 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(Material_RestitutionCombine)
|