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.
231 lines
9.6 KiB
Python
231 lines
9.6 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 ID : C5959760
|
|
# Test Case Title : Check that force region (capsule) exerts point force
|
|
|
|
|
|
|
|
# fmt: off
|
|
class Tests:
|
|
enter_game_mode = ("Entered game mode", "Failed to enter game mode")
|
|
box_entity_found = ("Box was found in game", "Box COULD NOT be found in game")
|
|
capsule_entity_found = ("Capsule was found in game", "Capsule COULD NOT be found in game")
|
|
box_pos_found = ("Box position found", "Box position not found")
|
|
capsule_pos_found = ("Capsule position found", "Capsule position not found")
|
|
force_region_entered = ("Force region entered", "Force region never entered")
|
|
force_exertion_predicted = ("Force exerted was predictable", "The force exerted WAS NOT predicted")
|
|
box_fell = ("Box fell", "The box did not fall")
|
|
box_was_pushed_x_z = ("Box moved positive X, Z", "Box DID NOT move in positive X, Z direction")
|
|
box_no_y_movement = ("Box had no substantial Y movement", "Box HAD substantial Y movement")
|
|
capsule_no_move = ("Capsule did not move", "Capsule DID move")
|
|
exit_game_mode = ("Exited game mode", "Couldn't exit game mode")
|
|
time_out = ("Test did not time out", "Test DID time out")
|
|
|
|
# fmt: on
|
|
|
|
|
|
def C5959760_PhysXForceRegion_PointForceExertion():
|
|
# type: () -> None
|
|
"""
|
|
Summary:
|
|
Runs an automated test to ensure point force from a capsule force region is exerted on rigid body objects.
|
|
|
|
Level Description:
|
|
A cube (entity: Box) set above a capsule force region (entity: Capsule). The Capsule was assigned point force
|
|
with magnitude set to 1000. The Box has been set for "gravity enabled"
|
|
|
|
Expected behavior:
|
|
The Box will fall (due to gravity) into the Capsule's force region. The force region should exert the point
|
|
force on the Box, applying a positive X and Z force of substantial magnitude.
|
|
|
|
Test Steps:
|
|
1) Loads the level / Enters game mode
|
|
2) Retrieve entities
|
|
3) Ensures that the test objects (Box and Capsule) are located
|
|
3.5) set up variables and handlers for monitoring results
|
|
4) Waits for the box to fall into the force region
|
|
or for time out if something unexpected happens
|
|
5) Logs results
|
|
6) Closes 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
|
|
|
|
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.legacy.general as general
|
|
import azlmbr.bus
|
|
|
|
# Global constants
|
|
CLOSE_ENOUGH = 0.001
|
|
TIME_OUT = 1.5
|
|
|
|
# Base class
|
|
class EntityBase:
|
|
def __init__(self, name):
|
|
self.name = name
|
|
self.id = None
|
|
self.initial_pos = None
|
|
self.current_pos = None
|
|
|
|
# Box child class of EntityBase
|
|
class Box(EntityBase):
|
|
def __init__(self, name):
|
|
EntityBase.__init__(self, name)
|
|
self.triggered_pos = None
|
|
self.fell = False
|
|
self.force_observed = False
|
|
|
|
def check_for_fall(self):
|
|
FALL_BUFFER = 0.2
|
|
if not self.fell:
|
|
self.fell = (
|
|
self.initial_pos.z > self.current_pos.z + FALL_BUFFER
|
|
and abs(self.initial_pos.x - self.current_pos.x) < CLOSE_ENOUGH
|
|
and abs(self.initial_pos.y - self.current_pos.y) < CLOSE_ENOUGH
|
|
)
|
|
return self.fell
|
|
|
|
def check_for_force(self):
|
|
FORCE_BUFFER = 0.2
|
|
if not self.force_observed:
|
|
self.force_observed = (
|
|
self.current_pos.z > self.triggered_pos.z + FORCE_BUFFER
|
|
and self.current_pos.x > self.triggered_pos.x
|
|
and abs(self.triggered_pos.y - self.current_pos.y) < CLOSE_ENOUGH
|
|
)
|
|
return self.force_observed
|
|
|
|
# Force Region child class of EntityBase
|
|
class ForceRegion(EntityBase):
|
|
def __init__(self, name):
|
|
EntityBase.__init__(self, name)
|
|
self.expected_force_magnitude = None
|
|
self.actual_force_vector = None
|
|
self.actual_force_magnitude = None
|
|
self.forced_entity = None
|
|
self.triggered = False
|
|
|
|
# 1) Open level / Enter game mode
|
|
helper.init_idle()
|
|
helper.open_level("Physics", "C5959760_PhysXForceRegion_PointForceExertion")
|
|
helper.enter_game_mode(Tests.enter_game_mode)
|
|
|
|
# 2) Retrieve entities
|
|
box = Box("Box")
|
|
box.id = general.find_game_entity(box.name)
|
|
capsule = ForceRegion("Capsule")
|
|
capsule.id = general.find_game_entity(capsule.name)
|
|
|
|
Report.critical_result(Tests.box_entity_found, box.id.IsValid())
|
|
Report.critical_result(Tests.capsule_entity_found, capsule.id.IsValid())
|
|
|
|
# 3) Log positions for Box and Capsule
|
|
box.initial_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", box.id)
|
|
capsule.initial_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", capsule.id)
|
|
box.current_pos = box.initial_pos
|
|
capsule.current_pos = capsule.initial_pos
|
|
|
|
# validate and print positions to confirm objects were found
|
|
Report.critical_result(Tests.box_pos_found, box.initial_pos is not None and not box.initial_pos.IsZero())
|
|
Report.critical_result(
|
|
Tests.capsule_pos_found, capsule.initial_pos is not None and not capsule.initial_pos.IsZero()
|
|
)
|
|
capsule.expected_force_magnitude = azlmbr.physics.ForcePointRequestBus(azlmbr.bus.Event, "GetMagnitude", capsule.id)
|
|
|
|
# 3.5) set up handler
|
|
|
|
# Force Region Event Handler
|
|
def on_force_calculated(args):
|
|
|
|
# Only store data for first force region calculation
|
|
if not capsule.triggered and capsule.id.Equal(args[0]):
|
|
capsule.triggered = True
|
|
capsule.forced_entity = args[1]
|
|
capsule.actual_force_vector = args[2]
|
|
capsule.actual_force_magnitude = args[3]
|
|
if capsule.forced_entity.Equal(box.id):
|
|
box.triggered_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", box.id)
|
|
Report.info("Force Region exerted force on {}".format(box.name))
|
|
|
|
# Assign the handler
|
|
handler = azlmbr.physics.ForceRegionNotificationBusHandler()
|
|
handler.connect(None)
|
|
handler.add_callback("OnCalculateNetForce", on_force_calculated)
|
|
|
|
def done_collecting_results():
|
|
# Update entity positions
|
|
capsule.current_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", capsule.id)
|
|
box.current_pos = azlmbr.components.TransformBus(azlmbr.bus.Event, "GetWorldTranslation", box.id)
|
|
# Check for three "test complete" conditions
|
|
# ! Careful ordering for logic short circuiting. DO NOT SWAP ORDER !
|
|
return box.check_for_fall() and capsule.triggered and box.check_for_force()
|
|
|
|
# 4) wait for force region entry or time out
|
|
test_completed = helper.wait_for_condition(done_collecting_results, TIME_OUT)
|
|
Report.critical_result(Tests.time_out, test_completed)
|
|
|
|
# 5) Report findings
|
|
Report.result(Tests.box_fell, box.fell)
|
|
Report.result(Tests.force_region_entered, capsule.triggered)
|
|
Report.result(
|
|
Tests.force_exertion_predicted,
|
|
abs(capsule.expected_force_magnitude - capsule.actual_force_magnitude) < CLOSE_ENOUGH,
|
|
)
|
|
Report.result(Tests.box_was_pushed_x_z, box.force_observed)
|
|
Report.result(Tests.box_no_y_movement, abs(box.initial_pos.y - box.current_pos.y) < CLOSE_ENOUGH)
|
|
Report.result(Tests.capsule_no_move, capsule.initial_pos.IsClose(capsule.current_pos))
|
|
|
|
# Collected Data Dump
|
|
Report.info("******* Collected Data *******")
|
|
Report.info("Entity: {}".format(box.name))
|
|
Report.info_vector3(box.initial_pos, " Initial Position:")
|
|
Report.info_vector3(box.triggered_pos, " Trigger Position:")
|
|
Report.info_vector3(box.current_pos, " Final Position:")
|
|
Report.info(" Fell: {}".format(box.fell))
|
|
Report.info(" Force Observed: {}".format(box.force_observed))
|
|
Report.info("******************************")
|
|
Report.info("Entity: {}".format(capsule.name))
|
|
Report.info_vector3(capsule.initial_pos, " Initial Position:")
|
|
Report.info_vector3(capsule.current_pos, " Final Position:")
|
|
Report.info(" Expected Force Magnitude: {:.2f}".format(capsule.expected_force_magnitude))
|
|
Report.info_vector3(capsule.actual_force_vector, " Actual Force Vector:", capsule.actual_force_magnitude)
|
|
Report.info(" Triggered: {}".format(capsule.triggered))
|
|
Report.info(
|
|
" Triggered Entity: {}".format(
|
|
azlmbr.entity.GameEntityContextRequestBus(azlmbr.bus.Broadcast, "GetEntityName", capsule.forced_entity)
|
|
)
|
|
)
|
|
|
|
Report.info("******************************")
|
|
|
|
# 6) Exit Game mode
|
|
helper.exit_game_mode(Tests.exit_game_mode)
|
|
Report.info("*** FINISHED TEST ***")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import ImportPathHelper as imports
|
|
imports.init()
|
|
|
|
from editor_python_test_tools.utils import Report
|
|
Report.start_test(C5959760_PhysXForceRegion_PointForceExertion)
|