Add One Way Collision for 2D Physics tests

This commit is contained in:
PouleyKetchoupp
2020-12-31 16:32:04 -07:00
parent 289d658baa
commit 6a738c1ede
6 changed files with 556 additions and 3 deletions

View File

@@ -18,6 +18,10 @@ var _tests = [
"id": "Functional Tests/Collision Pairs",
"path": "res://tests/functional/test_collision_pairs.tscn",
},
{
"id": "Functional Tests/One Way Collision",
"path": "res://tests/functional/test_one_way_collision.tscn",
},
{
"id": "Functional Tests/Joints",
"path": "res://tests/functional/test_joints.tscn",

View File

@@ -0,0 +1,277 @@
extends Test
tool
const OPTION_OBJECT_TYPE_RIGIDBODY = "Object type/Rigid body (1)"
const OPTION_OBJECT_TYPE_KINEMATIC = "Object type/Kinematic body (2)"
const OPTION_TEST_CASE_ALL_ANGLES = "Test case/Around the clock (0)"
const TEST_ALL_ANGLES_STEP = 15.0
const TEST_ALL_ANGLES_MAX = 344.0
export(float, 32, 128, 0.1) var _platform_size = 64.0 setget _set_platform_size
export(float, 0, 360, 0.1) var _platform_angle = 0.0 setget _set_platform_angle
export(float, 0, 360, 0.1) var _body_angle = 0.0 setget _set_rigidbody_angle
export(Vector2) var _body_velocity = Vector2(400.0, 0.0)
export(bool) var _use_kinematic_body = false
var _rigid_body_template = null
var _kinematic_body_template = null
var _moving_body = null
var _contact_detected = false
var _target_entered = false
var _test_passed = false
var _test_step = 0
var _test_all_angles = false
var _lock_controls = false
func _ready():
if not Engine.editor_hint:
$Options.add_menu_item(OPTION_OBJECT_TYPE_RIGIDBODY, true, not _use_kinematic_body, true)
$Options.add_menu_item(OPTION_OBJECT_TYPE_KINEMATIC, true, _use_kinematic_body, true)
$Options.add_menu_item(OPTION_TEST_CASE_ALL_ANGLES)
$Options.connect("option_selected", self, "_on_option_selected")
$Controls/PlatformSize/HSlider.value = _platform_size
$Controls/PlatformAngle/HSlider.value = _platform_angle
$Controls/BodyAngle/HSlider.value = _body_angle
$TargetArea2D.connect("body_entered", self, "_on_target_entered")
$Timer.connect("timeout", self, "_on_timeout")
_rigid_body_template = $RigidBody2D
remove_child(_rigid_body_template)
_kinematic_body_template = $KinematicBody2D
remove_child(_kinematic_body_template)
_start_test()
func _process(_delta):
if not Engine.editor_hint:
if Input.is_action_just_pressed("ui_accept"):
_reset_test(false)
func _physics_process(_delta):
if not Engine.editor_hint:
if _moving_body and _use_kinematic_body:
_moving_body.move_and_slide(_body_velocity)
if _moving_body.get_slide_count() > 0:
var colliding_body = _moving_body.get_slide_collision(0).collider
_on_contact_detected(colliding_body)
func _input(event):
var key_event = event as InputEventKey
if key_event and not key_event.pressed:
if key_event.scancode == KEY_0:
_on_option_selected(OPTION_TEST_CASE_ALL_ANGLES)
if key_event.scancode == KEY_1:
_on_option_selected(OPTION_OBJECT_TYPE_RIGIDBODY)
elif key_event.scancode == KEY_2:
_on_option_selected(OPTION_OBJECT_TYPE_KINEMATIC)
func _exit_tree():
if not Engine.editor_hint:
_rigid_body_template.free()
_kinematic_body_template.free()
func _set_platform_size(value):
if _lock_controls:
return
if value == _platform_size:
return
_platform_size = value
if is_inside_tree():
$OneWayRigidBody2D/CollisionShape2D.shape.extents.x = value
if not Engine.editor_hint:
# Bug: need to re-add when changing shape.
var platform = $OneWayRigidBody2D
var child_index = platform.get_index()
remove_child(platform)
add_child(platform)
move_child(platform, child_index)
_reset_test()
func _set_platform_angle(value):
if _lock_controls:
return
if value == _platform_angle:
return
_platform_angle = value
if is_inside_tree():
$OneWayRigidBody2D.rotation = deg2rad(value)
if not Engine.editor_hint:
_reset_test()
func _set_rigidbody_angle(value):
if _lock_controls:
return
if value == _body_angle:
return
_body_angle = value
if is_inside_tree():
if Engine.editor_hint:
$RigidBody2D.rotation = deg2rad(value)
$KinematicBody2D.rotation = deg2rad(value)
else:
if _moving_body:
_moving_body.rotation = deg2rad(value)
_rigid_body_template.rotation = deg2rad(value)
_kinematic_body_template.rotation = deg2rad(value)
_reset_test()
func _on_option_selected(option):
match option:
OPTION_OBJECT_TYPE_KINEMATIC:
_use_kinematic_body = true
_reset_test()
OPTION_OBJECT_TYPE_RIGIDBODY:
_use_kinematic_body = false
_reset_test()
OPTION_TEST_CASE_ALL_ANGLES:
_test_all_angles = true
_reset_test(false)
func _start_test():
var test_label = "Testing: "
if _use_kinematic_body:
test_label += _kinematic_body_template.name
_moving_body = _kinematic_body_template.duplicate()
else:
test_label += _rigid_body_template.name
_moving_body = _rigid_body_template.duplicate()
_moving_body.linear_velocity = _body_velocity
_moving_body.connect("body_entered", self, "_on_contact_detected")
add_child(_moving_body)
if _test_all_angles:
test_label += " - All angles"
$LabelTestType.text = test_label
_contact_detected = false
_target_entered = false
_test_passed = false
_test_step += 1
$Timer.start()
$LabelResult.text = "..."
$LabelResult.self_modulate = Color.white
func _reset_test(cancel_test = true):
$Timer.stop()
_test_step = 0
if _test_all_angles:
if cancel_test:
Log.print_log("*** Stop around the clock tests")
_test_all_angles = false
else:
Log.print_log("*** Start around the clock tests")
$OneWayRigidBody2D.rotation = deg2rad(_platform_angle)
_lock_controls = true
$Controls/PlatformAngle/HSlider.value = _platform_angle
_lock_controls = false
_next_test(true)
func _next_test(force_start = false):
if _moving_body:
remove_child(_moving_body)
_moving_body.queue_free()
_moving_body = null
if _test_all_angles:
var angle = rad2deg($OneWayRigidBody2D.rotation)
if angle >= _platform_angle + TEST_ALL_ANGLES_MAX:
$OneWayRigidBody2D.rotation = deg2rad(_platform_angle)
_lock_controls = true
$Controls/PlatformAngle/HSlider.value = _platform_angle
_lock_controls = false
Log.print_log("*** Done all angles")
else:
angle = _platform_angle + _test_step * TEST_ALL_ANGLES_STEP
$OneWayRigidBody2D.rotation = deg2rad(angle)
_lock_controls = true
$Controls/PlatformAngle/HSlider.value = angle
_lock_controls = false
_start_test()
elif force_start:
_start_test()
func _on_contact_detected(_body):
if _contact_detected or _target_entered:
return
_contact_detected = true
_test_passed = _should_collide()
_set_result()
_on_timeout()
func _on_target_entered(_body):
if _contact_detected or _target_entered:
return
_target_entered = true
_test_passed = not _should_collide()
_set_result()
_on_timeout()
func _should_collide():
var platform_rotation = round(rad2deg($OneWayRigidBody2D.rotation))
var angle = fposmod(platform_rotation, 360)
return angle > 180
func _on_timeout():
if not _contact_detected and not _target_entered:
Log.print_log("Test TIMEOUT")
_set_result()
$Timer.stop()
yield(get_tree().create_timer(0.5), "timeout")
_next_test()
func _set_result():
var result = ""
if _test_passed:
result = "PASSED"
$LabelResult.self_modulate = Color.green
else:
result = "FAILED"
$LabelResult.self_modulate = Color.red
$LabelResult.text = result
var platform_angle = rad2deg($OneWayRigidBody2D.rotation)
result += ": size=%.1f, angle=%.1f, body angle=%.1f" % [_platform_size, platform_angle, _body_angle]
Log.print_log("Test %s" % result)

View File

@@ -0,0 +1,243 @@
[gd_scene load_steps=9 format=2]
[ext_resource path="res://tests/functional/test_one_way_collision.gd" type="Script" id=1]
[ext_resource path="res://icon.png" type="Texture" id=2]
[ext_resource path="res://tests/test_options.tscn" type="PackedScene" id=3]
[ext_resource path="res://utils/label_slider_value.gd" type="Script" id=4]
[ext_resource path="res://utils/slider.gd" type="Script" id=5]
[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 32, 32 )
[sub_resource type="RectangleShape2D" id=2]
extents = Vector2( 64, 32 )
[sub_resource type="RectangleShape2D" id=3]
extents = Vector2( 32, 32 )
[node name="Test" type="Node2D"]
script = ExtResource( 1 )
[node name="LabelTestType" type="Label" parent="."]
margin_left = 14.0
margin_top = 79.0
margin_right = 145.0
margin_bottom = 93.0
text = "Testing: "
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Options" parent="." instance=ExtResource( 3 )]
[node name="Controls" type="VBoxContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 25.3619
margin_top = 416.765
margin_right = 265.362
margin_bottom = 484.765
custom_constants/separation = 10
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PlatformSize" type="HBoxContainer" parent="Controls"]
margin_right = 432.0
margin_bottom = 16.0
custom_constants/separation = 20
alignment = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="Controls/PlatformSize"]
margin_left = 8.0
margin_top = 1.0
margin_right = 92.0
margin_bottom = 15.0
text = "Platform size"
[node name="HSlider" type="HSlider" parent="Controls/PlatformSize"]
margin_left = 112.0
margin_right = 312.0
margin_bottom = 16.0
rect_min_size = Vector2( 200, 0 )
min_value = 32.0
max_value = 128.0
value = 64.0
script = ExtResource( 5 )
[node name="LabelValue" type="Label" parent="Controls/PlatformSize"]
margin_left = 332.0
margin_top = 1.0
margin_right = 432.0
margin_bottom = 15.0
rect_min_size = Vector2( 100, 0 )
text = "64.0"
script = ExtResource( 4 )
[node name="PlatformAngle" type="HBoxContainer" parent="Controls"]
margin_top = 26.0
margin_right = 432.0
margin_bottom = 42.0
custom_constants/separation = 20
alignment = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="Controls/PlatformAngle"]
margin_top = 1.0
margin_right = 92.0
margin_bottom = 15.0
text = "Platform angle"
[node name="HSlider" type="HSlider" parent="Controls/PlatformAngle"]
margin_left = 112.0
margin_right = 312.0
margin_bottom = 16.0
rect_min_size = Vector2( 200, 0 )
max_value = 360.0
script = ExtResource( 5 )
snap_step = 5.0
[node name="LabelValue" type="Label" parent="Controls/PlatformAngle"]
margin_left = 332.0
margin_top = 1.0
margin_right = 432.0
margin_bottom = 15.0
rect_min_size = Vector2( 100, 0 )
text = "0.0"
script = ExtResource( 4 )
[node name="BodyAngle" type="HBoxContainer" parent="Controls"]
margin_top = 52.0
margin_right = 432.0
margin_bottom = 68.0
custom_constants/separation = 20
alignment = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="Controls/BodyAngle"]
margin_left = 22.0
margin_top = 1.0
margin_right = 92.0
margin_bottom = 15.0
text = "Body angle"
[node name="HSlider" type="HSlider" parent="Controls/BodyAngle"]
margin_left = 112.0
margin_right = 312.0
margin_bottom = 16.0
rect_min_size = Vector2( 200, 0 )
max_value = 360.0
script = ExtResource( 5 )
snap_step = 5.0
[node name="LabelValue" type="Label" parent="Controls/BodyAngle"]
margin_left = 332.0
margin_top = 1.0
margin_right = 432.0
margin_bottom = 15.0
rect_min_size = Vector2( 100, 0 )
text = "0.0"
script = ExtResource( 4 )
[node name="LabelResultTitle" type="Label" parent="."]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = 34.1273
margin_top = 251.131
margin_right = 88.1273
margin_bottom = 265.131
text = "RESULT: "
align = 1
valign = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LabelResult" type="Label" parent="."]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = 34.1273
margin_top = 266.131
margin_right = 88.1273
margin_bottom = 280.131
text = "..."
align = 1
valign = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LabelRestart" type="Label" parent="."]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = 34.1273
margin_top = 304.841
margin_right = 139.127
margin_bottom = 318.841
text = "SPACE - RESTART"
align = 1
valign = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Timer" type="Timer" parent="."]
wait_time = 5.0
one_shot = true
[node name="TargetArea2D" type="Area2D" parent="."]
position = Vector2( 724, 300 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="TargetArea2D"]
shape = SubResource( 1 )
[node name="OneWayRigidBody2D" type="RigidBody2D" parent="."]
position = Vector2( 512, 300 )
mode = 3
[node name="CollisionShape2D" type="CollisionShape2D" parent="OneWayRigidBody2D"]
shape = SubResource( 2 )
one_way_collision = true
[node name="RigidBody2D" type="RigidBody2D" parent="."]
position = Vector2( 300, 300 )
collision_mask = 2147483649
gravity_scale = 0.0
contacts_reported = 1
contact_monitor = true
[node name="Sprite" type="Sprite" parent="RigidBody2D"]
self_modulate = Color( 1, 1, 1, 0.501961 )
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 2 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="RigidBody2D"]
shape = SubResource( 3 )
[node name="KinematicBody2D" type="KinematicBody2D" parent="."]
position = Vector2( 300, 300 )
collision_mask = 2147483649
[node name="Sprite" type="Sprite" parent="KinematicBody2D"]
self_modulate = Color( 1, 1, 1, 0.501961 )
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 2 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="KinematicBody2D"]
shape = SubResource( 3 )
[connection signal="value_changed" from="Controls/PlatformSize/HSlider" to="." method="_set_platform_size"]
[connection signal="value_changed" from="Controls/PlatformAngle/HSlider" to="." method="_set_platform_angle"]
[connection signal="value_changed" from="Controls/BodyAngle/HSlider" to="." method="_set_rigidbody_angle"]

View File

@@ -0,0 +1,7 @@
extends Label
tool
func _process(_delta):
var slider = get_node("../HSlider")
text = "%.1f" % slider.value

View File

@@ -6,7 +6,7 @@ signal option_selected(item_path)
signal option_changed(item_path, checked)
func add_menu_item(item_path, checkbox = false, checked = false):
func add_menu_item(item_path, checkbox = false, checked = false, radio = false):
var path_elements = item_path.split("/", false)
var path_element_count = path_elements.size()
assert(path_element_count > 0)
@@ -19,7 +19,10 @@ func add_menu_item(item_path, checkbox = false, checked = false):
popup = _add_popup(popup, path, popup_label)
var label = path_elements[path_element_count - 1]
if checkbox:
if radio:
popup.add_radio_check_item(label)
popup.set_item_checked(popup.get_item_count() - 1, checked)
elif checkbox:
popup.add_check_item(label)
popup.set_item_checked(popup.get_item_count() - 1, checked)
else:
@@ -52,7 +55,15 @@ func _add_popup(parent_popup, path, label):
func _on_item_pressed(item_index, popup_menu, path):
var item_path = path + popup_menu.get_item_text(item_index)
if popup_menu.is_item_checkable(item_index):
if popup_menu.is_item_radio_checkable(item_index):
var checked = popup_menu.is_item_checked(item_index)
if not checked:
popup_menu.set_item_checked(item_index, true)
for other_index in popup_menu.get_item_count():
if other_index != item_index:
popup_menu.set_item_checked(other_index, false)
emit_signal("option_selected", item_path)
elif popup_menu.is_item_checkable(item_index):
var checked = not popup_menu.is_item_checked(item_index)
popup_menu.set_item_checked(item_index, checked)
emit_signal("option_changed", item_path, checked)

View File

@@ -0,0 +1,11 @@
extends Slider
export(float) var snap_step = 1.0
func _process(_delta):
if Input.is_key_pressed(KEY_SHIFT):
step = 0.1
else:
step = snap_step