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/tests/tick/Tick_CharacterGameplayCompo...

100 lines
4.9 KiB
Python

"""
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 Title : Verify that an entity with a character gameplay component moves smoothly.
"""
# fmt: off
class Tests():
create_entity = ("Created test entity", "Failed to create test entity")
character_controller_added = ("Added PhysX Character Controller component", "Failed to add PhysX Character Controller component")
character_gameplay_added = ("Added PhysX Character Gameplay component", "Failed to add PhysX Character Gameplay component")
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
exit_game_mode = ("Exited game mode", "Failed to exit game mode")
character_motion_smooth = ("Character motion passed smoothness threshold", "Failed to meet smoothness threshold for character motion")
# fmt: on
def Tick_CharacterGameplayComponentMotionIsSmooth():
"""
Summary:
Create entity with PhysX Character Controller and PhysX Character Gameplay components.
Verify that the motion of the character controller under gravity is smooth.
Expected Behavior:
1) The motion of the character controller under gravity is a smooth curve, rather than an erratic/jittery movement.
Test Steps:
1) Load the empty level
2) Create an entity
3) Add a PhysX Character Controller Component and PhysX Character Gameplay component
4) Enter game mode and collect data for the character controller's z co-ordinate and the time values for a series of frames
5) Check if the motion of the character controller was sufficiently smooth
:return: None
"""
# imports
import os
import azlmbr.legacy.general as general
import azlmbr.math as math
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
import numpy as np
# constants
COEFFICIENT_OF_DETERMINATION_THRESHOLD = 1 - 1e-4 # curves with values below this are not considered sufficiently smooth
helper.init_idle()
# 1) Load the empty level
helper.open_level("", "Base")
# 2) Create an entity
test_entity = Entity.create_editor_entity("test_entity")
Report.result(Tests.create_entity, test_entity.id.IsValid())
azlmbr.components.TransformBus(
azlmbr.bus.Event, "SetWorldTranslation", test_entity.id, math.Vector3(0.0, 0.0, 0.0))
# 3) Add character controller and character gameplay components
character_controller_component = test_entity.add_component("PhysX Character Controller")
Report.result(Tests.character_controller_added, test_entity.has_component("PhysX Character Controller"))
character_gameplay_component = test_entity.add_component("PhysX Character Gameplay")
Report.result(Tests.character_gameplay_added, test_entity.has_component("PhysX Character Gameplay"))
# 4) Enter game mode and collect data for the rigid body's z co-ordinate and the time values for a series of frames
t = []
z = []
helper.enter_game_mode(Tests.enter_game_mode)
general.idle_wait_frames(1)
game_entity_id = general.find_game_entity("test_entity")
for frame in range(100):
t.append(azlmbr.components.TickRequestBus(azlmbr.bus.Broadcast, "GetTimeAtCurrentTick").GetSeconds())
z.append(azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldZ", game_entity_id))
general.idle_wait_frames(1)
helper.exit_game_mode(Tests.exit_game_mode)
# 5) Test that the z vs t curve is sufficiently smooth (if the interpolation is not working well, the curve will be less smooth)
# normalize the t and z data
t = np.array(t) - np.mean(t)
z = np.array(z) - np.mean(z)
# fit a polynomial to the z vs t curve
fit = np.poly1d(np.polyfit(t, z, 4))
residual = fit(t) - z
# calculate the coefficient of determination (a measure of how closely the polynomial curve fits the data)
# if the coefficient is very close to 1, then the curve fits the data very well, suggesting that the rigid body motion is smooth
# if the coefficient is significantly less than 1, then the z values vary more erratically relative to the smooth curve,
# indicating that the motion of the rigid body is not smooth
coefficient_of_determination = (1 - np.sum(residual * residual) / np.sum(z * z))
Report.result(Tests.character_motion_smooth, bool(coefficient_of_determination > COEFFICIENT_OF_DETERMINATION_THRESHOLD))
if __name__ == "__main__":
from editor_python_test_tools.utils import Report
Report.start_test(Tick_CharacterGameplayComponentMotionIsSmooth)