You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/AutomatedTesting/Gem/PythonTests/physics/C13352089_RigidBodies_MaxAn...

293 lines
13 KiB
Python

"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# Test case ID : C13352089
# Test Case Title : Verify that maximum angular velocity interacts correctly with initial angular velocity
# fmt: off
class Tests:
# level
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
trigger_touch_times = ("Bar5 rotated more than bar6", "Bar5 did not stop more slowly than bar6")
rotation_duration = ("Bar5 stopped faster than bar6", "Bar5 did not stop faster than bar6")
# bar 1
bar1_gravity_disabled = ("Bar1 : Gravity is disabled", "Bar1 : Gravity is not disabled")
bar1_found = ("Bar1 : Found entity", "Bar1 : Entity not found")
bar1_rotation = ("Bar1 : Rotated on X axis", "Bar1 : Unexpected rotation")
bar1_angular_velocity = ("Bar1 : Expected angular velocity", "Bar1 : Unexpected angular velocity")
# bar 2
bar2_gravity_disabled = ("Bar2 : Gravity is disabled", "Bar2 : Gravity is not disabled")
bar2_found = ("Bar2 : Found entity", "Bar2 : Entity not found")
bar2_rotation = ("Bar2 : Rotated on X axis", "Bar2 : Unexpected rotation")
bar2_angular_velocity = ("Bar2 : Expected angular velocity", "Bar2 : Unexpected angular velocity")
# bar 3
bar3_gravity_disabled = ("Bar3 : Gravity is disabled", "Bar3 : Gravity is not disabled")
bar3_found = ("Bar3 : Found entity", "Bar3 : Entity not found")
bar3_rotation = ("Bar3 : Rotated on X axis", "Bar3 : Unexpected rotation")
bar3_angular_velocity = ("Bar3 : Expected angular velocity", "Bar3 : Unexpected angular velocity")
# bar 4
bar4_gravity_disabled = ("Bar4 : Gravity is disabled", "Bar4 : Gravity is not disabled")
bar4_found = ("Bar4 : Found entity", "Bar4 : Entity not found")
bar4_rotation = ("Bar4 : Did not rotate", "Bar4 : Unexpected rotation")
bar4_angular_velocity = ("Bar4 : Expected angular velocity", "Bar4 : Unexpected angular velocity")
# bar 5
bar5_gravity_disabled = ("Bar5 : Gravity is disabled", "Bar5 : Gravity is not disabled")
bar5_found = ("Bar5 : Found entity", "Bar5 : Entity not found")
bar5_rotation = ("Bar5 : Rotated on X axis", "Bar5 : Unexpected rotation")
bar5_angular_velocity = ("Bar5 : Expected angular velocity", "Bar5 : Unexpected angular velocity")
# bar 6
bar6_gravity_disabled = ("Bar6 : Gravity is disabled", "Bar6 : Gravity is not disabled")
bar6_found = ("Bar6 : Found entity", "Bar6 : Entity not found")
bar6_rotation = ("Bar6 : Rotated on X axis", "Bar6 : Unexpected rotation")
bar6_angular_velocity = ("Bar6 : Expected angular velocity", "Bar6 : Unexpected angular velocity")
# trigger for bar 5
bar5_trigger_found = ("Trigger for bar5 : Found entity", "Trigger for bar5 : Entity not found")
# trigger for bar 6
bar6_trigger_found = ("Trigger for bar6 : Found entity", "Trigger for bar6 : Entity not found")
did_not_timeout = ("Should_wait did not time out", "Should wait timed out")
# fmt: on
def C13352089_RigidBodies_MaxAngularVelocity():
"""
Summary:
Runs an automated test to ensure maximum angular velocity and angular damping interact correctly with
initial angular velocity
Level Description:
bars:
6 PhysX Rigid Bodies with PhysX Shape Collider (Box Shape, Dimensions: X=1, Y=1, Z=5), gravity disabled,
start asleep, positioned above terrain
bar 1: Initial Angular Velocity = 10 rad/s, Max Angular Velocity = 5 rad/s, Angular Damping = 0.0
bar 2: Initial Angular Velocity = 10 rad/s, Max Angular Velocity = 10 rad/s, Angular Damping = 0.0
bar 3: Initial Angular Velocity = 20 rad/s, Max Angular Velocity = 20 rad/s, Angular Damping = 0.0
bar 4: Initial Angular Velocity = 20 rad/s, Max Angular Velocity = 0 rad/s, Angular Damping = 0.0
bar 5: Initial Angular Velocity = 20 rad/s, Max Angular Velocity = 20 rad/s, Angular Damping = 2.0
bar 6: Initial Angular Velocity = 20 rad/s, Max Angular Velocity = 20 rad/s, Angular Damping = 5.0
triggers:
2 PhysX Shape Collider (Box Shape), gravity disabled, trigger enabled, start asleep
trigger for bar 5: positioned above terrain, in front of bar 5
trigger for bar 6: positioned above terrain, in front of bar 6
Expected Behavior:
bar 1: Should rotate at 5 rad/s on X axis
bar 2: Should rotate at 10 rad/s on X axis
bar 3: Should rotate at 20 rad/s on X axis
bar 4: Should not rotate at all
bar 5: Should start rotating at 20 rad/s on X axis and stop slowly (touching its trigger several times)
bar 6: Should start rotating at 20 rad/s on X axis but stop quickly (touching its trigger 0 or very few times)
Test Steps:
1) Loads the level
2) Enters game mode
3) Set up bars values
4) Loop for each bar
4.1) Find the bar
4.2) Validate ID
4.3) Activate the bar
4.4) Validate and log its position
4.5) Confirm gravity is disabled for the bar
4.6) Log bar's initial rotation
4.7) Log bar's angular damping
4.8) Log bar's angular velocity
4.9) Set up trigger if the bar has one
4.10) Wait for each bar to rotate or stop rotating
4.11) Log current location
4.12) Validate rotation based on expected behavior
4.13) Destroy bar (and its trigger)
5) Compare trigger touch times for bar5 and bar6
6) Exit game mode
7) Close editor
"""
import os
import sys
import math
import time
import ImportPathHelper as imports
imports.init()
from editor_python_test_tools.utils import Report
from editor_python_test_tools.utils import TestHelper as helper
import azlmbr.math as lymath
import azlmbr.legacy.general as general
import azlmbr.bus
# Constants
ANGULAR_VELOCITY_TOLERANCE = 0.05
TIME_OUT = 15.0
ROTATION_TOLERANCE = 0.001
def is_close(x, y, tolerance=ANGULAR_VELOCITY_TOLERANCE):
return abs(x - y) < tolerance
def is_angle_close(x, y):
r = (math.sin(x) - math.sin(y)) * (math.sin(x) - math.sin(y)) + (math.cos(x) - math.cos(y)) * (
math.cos(x) - math.cos(y)
)
diff = math.acos((2.0 - r) / 2.0)
return abs(diff) <= ROTATION_TOLERANCE
class Entity: # Parent class for bars and triggers
def __init__(self, name):
self.name = name
self.validate_ID()
self.activate_entity()
def validate_ID(self):
self.id = general.find_game_entity(self.name)
found_tuple = Tests.__dict__[self.name + "_found"]
Report.critical_result(found_tuple, self.id.IsValid())
def activate_entity(self):
Report.info("Activating Entity : " + self.name)
azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "ActivateGameEntity", self.id)
general.idle_wait_frames(1)
self.rotation_start_time = time.time()
class Bar(Entity):
def __init__(self, name, init_ang_velocity_on_X, max_ang_velocity, has_trigger=False):
# 1) Validate ID, then activate Bar
Entity.__init__(self, name)
self.rotation_duration = 999999.9
self.init_angular_velocity = lymath.Vector3(init_ang_velocity_on_X, 0.0, 0.0)
self.max_angular_velocity = max_ang_velocity
self.max_valid_velocity = min(self.max_angular_velocity, self.init_angular_velocity.GetLength())
self.angular_damping = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "GetAngularDamping", self.id)
# ) Log initial rotation
self.init_rotation = self.get_rotation()
# ) Verify gravity is disabled for bar
self.validate_gravity_is_disabled()
# ) Validate angular velocity according to max angular velocity
self.validate_angular_velocity()
# ) Setup trigger
if has_trigger:
self.touched_trigger = 0
self.setup_trigger()
def validate_gravity_is_disabled(self):
gravity_enabled = azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "IsGravityEnabled", self.id)
gravity_tuple = Tests.__dict__[self.name + "_gravity_disabled"]
Report.result(gravity_tuple, not gravity_enabled)
def setup_trigger(self):
self.trigger = Entity(self.name + "_trigger")
self.trigger.handler = azlmbr.physics.TriggerNotificationBusHandler()
self.trigger.handler.connect(self.trigger.id)
self.trigger.handler.add_callback("OnTriggerEnter", self.count_touch_times)
def get_angular_velocity(self):
return azlmbr.physics.RigidBodyRequestBus(azlmbr.bus.Event, "GetAngularVelocity", self.id)
def get_rotation(self):
return azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldRotation", self.id)
def validate_angular_velocity(self):
general.idle_wait_frames(10)
self.angular_velocity = self.get_angular_velocity()
angular_velocity_tuple = Tests.__dict__[self.name + "_angular_velocity"]
if self.angular_damping == 0:
velocity_is_valid = is_close(self.angular_velocity.GetLength(), self.max_valid_velocity)
else:
velocity_is_valid = self.max_valid_velocity >= self.angular_velocity.GetLength() >= 0.0
Report.result(angular_velocity_tuple, velocity_is_valid)
def validate_rotation(self):
self.rotation = self.get_rotation()
rotated_on_x = not is_angle_close(self.init_rotation.x, self.rotation.x)
rotated_on_y = not is_angle_close(self.init_rotation.y, self.rotation.y)
rotated_on_z = not is_angle_close(self.init_rotation.z, self.rotation.z)
if self.max_valid_velocity != 0:
return rotated_on_x and not rotated_on_y and not rotated_on_z
else:
return not rotated_on_x and not rotated_on_y and not rotated_on_z
def has_waited_enough(self):
if self.angular_damping > 0:
# Bar5 or bar6 should stop rotating to consider their movement as done
if self.get_angular_velocity().IsZero():
self.rotation_duration = time.time() - self.rotation_start_time
return True
elif self.angular_damping == 0:
# Bar1, bar2, bar3 or bar4
return True
return False
def count_touch_times(self, args):
entering_entity_id = args[0]
if entering_entity_id.Equal(self.id):
Report.info(self.name + " touched " + self.trigger.name)
self.touched_trigger += 1
helper.init_idle()
# 1) Load the level
helper.open_level("Physics", "C13352089_RigidBodies_MaxAngularVelocity")
# 2) Enter game mode
helper.enter_game_mode(Tests.enter_game_mode)
# 3) Init bars values
bars = [
Bar(name="bar1", init_ang_velocity_on_X=10.0, max_ang_velocity=5),
Bar(name="bar2", init_ang_velocity_on_X=10.0, max_ang_velocity=20),
Bar(name="bar3", init_ang_velocity_on_X=20.0, max_ang_velocity=20),
Bar(name="bar4", init_ang_velocity_on_X=20.0, max_ang_velocity=0,),
Bar(name="bar5", init_ang_velocity_on_X=20.0, max_ang_velocity=20, has_trigger=True,),
Bar(name="bar6", init_ang_velocity_on_X=20.0, max_ang_velocity=20, has_trigger=True,),
]
# 4.10) Wait
Report.critical_result(
Tests.did_not_timeout,
helper.wait_for_condition(lambda: all([bar.has_waited_enough() for bar in bars]), TIME_OUT),
)
# 4.12) Validate rotation
for bar in bars:
Report.result(Tests.__dict__["{}_rotation".format(bar.name)], bar.validate_rotation())
# 5) Compare number of times bar5 and bar6 touched their trigger
Report.result(Tests.trigger_touch_times, bars[4].touched_trigger > bars[5].touched_trigger)
Report.info(bars[4].rotation_duration)
Report.info(bars[5].rotation_duration)
Report.result(Tests.rotation_duration, bars[4].rotation_duration > bars[5].rotation_duration)
# 6) Exit Game mode
helper.exit_game_mode(Tests.exit_game_mode)
if __name__ == "__main__":
import ImportPathHelper as imports
imports.init()
from editor_python_test_tools.utils import Report
Report.start_test(C13352089_RigidBodies_MaxAngularVelocity)