Merge pull request #561 from nekomatata/physics-test-collision-pairs

Add collision pairs test to 2D/3D physics tests
This commit is contained in:
Aaron Franke
2020-12-19 11:59:26 -06:00
committed by GitHub
17 changed files with 944 additions and 95 deletions

View File

@@ -9,13 +9,16 @@ var _timer_started = false
var _wait_physics_ticks_counter = 0
class Line:
var pos_start
var pos_end
class Circle2D:
extends Node2D
var center
var radius
var color
var _lines = []
func _draw():
draw_circle(center, radius, color)
var _drawn_nodes = []
func _physics_process(_delta):
@@ -25,23 +28,37 @@ func _physics_process(_delta):
emit_signal("wait_done")
func _draw():
for line in _lines:
draw_line(line.pos_start, line.pos_end, line.color, 1.5)
func add_line(pos_start, pos_end, color):
var line = Line.new()
line.pos_start = pos_start
line.pos_end = pos_end
line.color = color
_lines.push_back(line)
update()
var line = Line2D.new()
line.points = [pos_start, pos_end]
line.width = 1.5
line.default_color = color
_drawn_nodes.push_back(line)
add_child(line)
func clear_lines():
_lines.clear()
update()
func add_circle(pos, radius, color):
var circle = Circle2D.new()
circle.center = pos
circle.radius = radius
circle.color = color
_drawn_nodes.push_back(circle)
add_child(circle)
func add_shape(shape, transform, color):
var collision = CollisionShape2D.new()
collision.shape = shape
collision.transform = transform
collision.modulate = color
_drawn_nodes.push_back(collision)
add_child(collision)
func clear_drawn_nodes():
for node in _drawn_nodes:
node.queue_free()
_drawn_nodes.clear()
func create_rigidbody_box(size):

View File

@@ -14,6 +14,10 @@ var _tests = [
"id": "Functional Tests/Box Pyramid",
"path": "res://tests/functional/test_pyramid.tscn",
},
{
"id": "Functional Tests/Collision Pairs",
"path": "res://tests/functional/test_collision_pairs.tscn",
},
{
"id": "Functional Tests/Raycasting",
"path": "res://tests/functional/test_raycasting.tscn",

View File

@@ -0,0 +1,206 @@
extends Test
const OPTION_TYPE_RECTANGLE = "Collision type/Rectangle (1)"
const OPTION_TYPE_SPHERE = "Collision type/Sphere (2)"
const OPTION_TYPE_CAPSULE = "Collision type/Capsule (3)"
const OPTION_TYPE_CONVEX_POLYGON = "Collision type/Convex Polygon (4)"
const OPTION_TYPE_CONCAVE_SEGMENTS = "Collision type/Concave Segments (5)"
const OPTION_SHAPE_RECTANGLE = "Shape type/Rectangle"
const OPTION_SHAPE_SPHERE = "Shape type/Sphere"
const OPTION_SHAPE_CAPSULE = "Shape type/Capsule"
const OPTION_SHAPE_CONVEX_POLYGON = "Shape type/Convex Polygon"
const OPTION_SHAPE_CONCAVE_POLYGON = "Shape type/Concave Polygon"
const OPTION_SHAPE_CONCAVE_SEGMENTS = "Shape type/Concave Segments"
const OFFSET_RANGE = 120.0
export(Vector2) var offset = Vector2.ZERO
var _update_collision = false
var _collision_test_index = 0
var _current_offset = Vector2.ZERO
var _collision_shapes = []
func _ready():
_initialize_collision_shapes()
$Options.add_menu_item(OPTION_TYPE_RECTANGLE)
$Options.add_menu_item(OPTION_TYPE_SPHERE)
$Options.add_menu_item(OPTION_TYPE_CAPSULE)
$Options.add_menu_item(OPTION_TYPE_CONVEX_POLYGON)
$Options.add_menu_item(OPTION_TYPE_CONCAVE_SEGMENTS)
$Options.add_menu_item(OPTION_SHAPE_RECTANGLE, true, true)
$Options.add_menu_item(OPTION_SHAPE_SPHERE, true, true)
$Options.add_menu_item(OPTION_SHAPE_CAPSULE, true, true)
$Options.add_menu_item(OPTION_SHAPE_CONVEX_POLYGON, true, true)
$Options.add_menu_item(OPTION_SHAPE_CONCAVE_POLYGON, true, true)
$Options.add_menu_item(OPTION_SHAPE_CONCAVE_SEGMENTS, true, true)
$Options.connect("option_selected", self, "_on_option_selected")
$Options.connect("option_changed", self, "_on_option_changed")
yield(start_timer(0.5), "timeout")
if is_timer_canceled():
return
_update_collision = true
func _input(event):
var key_event = event as InputEventKey
if (key_event and not key_event.pressed):
if (key_event.scancode == KEY_1):
_on_option_selected(OPTION_TYPE_RECTANGLE)
elif (key_event.scancode == KEY_2):
_on_option_selected(OPTION_TYPE_SPHERE)
elif (key_event.scancode == KEY_3):
_on_option_selected(OPTION_TYPE_CAPSULE)
elif (key_event.scancode == KEY_4):
_on_option_selected(OPTION_TYPE_CONVEX_POLYGON)
elif (key_event.scancode == KEY_5):
_on_option_selected(OPTION_TYPE_CONCAVE_SEGMENTS)
func _physics_process(_delta):
if not _update_collision:
return
_update_collision = false
_do_collision_test()
func set_h_offset(value):
offset.x = value * OFFSET_RANGE
_update_collision = true
func set_v_offset(value):
offset.y = -value * OFFSET_RANGE
_update_collision = true
func _initialize_collision_shapes():
_collision_shapes.clear()
for node in $Shapes.get_children():
var body = node as PhysicsBody2D
var shape = body.shape_owner_get_shape(0, 0)
shape.resource_name = node.name.substr("RigidBody".length())
_collision_shapes.push_back(shape)
func _do_collision_test():
clear_drawn_nodes()
var shape = _collision_shapes[_collision_test_index]
Log.print_log("* Start %s collision tests..." % shape.resource_name)
var shape_query = Physics2DShapeQueryParameters.new()
shape_query.set_shape(shape)
var shape_scale = Vector2(0.5, 0.5)
shape_query.transform = Transform2D.IDENTITY.scaled(shape_scale)
for node in $Shapes.get_children():
if not node.visible:
continue
var body = node as PhysicsBody2D
var space_state = body.get_world_2d().direct_space_state
Log.print_log("* Testing: %s" % body.name)
var center = body.position
# Collision at the center inside.
var res = _add_collision(space_state, center, shape, shape_query)
Log.print_log("Collision center inside: %s" % ("NO HIT" if res.empty() else "HIT"))
Log.print_log("* Done.")
func _add_collision(space_state, pos, shape, shape_query):
shape_query.transform.origin = pos + offset
var results = space_state.collide_shape(shape_query)
var color
if results.empty():
color = Color.white.darkened(0.5)
else:
color = Color.green
# Draw collision query shape.
add_shape(shape, shape_query.transform, color)
# Draw contact positions.
for contact_pos in results:
add_circle(contact_pos, 1.0, Color.red)
return results
func _on_option_selected(option):
match option:
OPTION_TYPE_RECTANGLE:
_collision_test_index = _find_type_index("Rectangle")
_update_collision = true
OPTION_TYPE_SPHERE:
_collision_test_index = _find_type_index("Sphere")
_update_collision = true
OPTION_TYPE_CAPSULE:
_collision_test_index = _find_type_index("Capsule")
_update_collision = true
OPTION_TYPE_CONVEX_POLYGON:
_collision_test_index = _find_type_index("ConvexPolygon")
_update_collision = true
OPTION_TYPE_CONCAVE_SEGMENTS:
_collision_test_index = _find_type_index("ConcaveSegments")
_update_collision = true
func _find_type_index(type_name):
for type_index in _collision_shapes.size():
var type_shape = _collision_shapes[type_index]
if type_shape.resource_name.find(type_name) > -1:
return type_index
Log.print_error("Invalid collision type: " + type_name)
return -1
func _on_option_changed(option, checked):
var node
match option:
OPTION_SHAPE_RECTANGLE:
node = _find_shape_node("Rectangle")
OPTION_SHAPE_SPHERE:
node = _find_shape_node("Sphere")
OPTION_SHAPE_CAPSULE:
node = _find_shape_node("Capsule")
OPTION_SHAPE_CONVEX_POLYGON:
node = _find_shape_node("ConvexPolygon")
OPTION_SHAPE_CONCAVE_POLYGON:
node = _find_shape_node("ConcavePolygon")
OPTION_SHAPE_CONCAVE_SEGMENTS:
node = _find_shape_node("ConcaveSegments")
if node:
node.visible = checked
node.get_child(0).disabled = not checked
_update_collision = true
func _find_shape_node(type_name):
var node = $Shapes.find_node("RigidBody%s" % type_name)
if not node:
Log.print_error("Invalid shape type: " + type_name)
return node

View File

@@ -0,0 +1,149 @@
[gd_scene load_steps=8 format=2]
[ext_resource path="res://tests/functional/test_collision_pairs.gd" type="Script" id=1]
[ext_resource path="res://assets/godot-head.png" type="Texture" id=2]
[ext_resource path="res://tests/test_options.tscn" type="PackedScene" id=3]
[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 40, 60 )
[sub_resource type="CircleShape2D" id=2]
radius = 60.0
[sub_resource type="CapsuleShape2D" id=3]
radius = 30.0
height = 50.0
[sub_resource type="ConcavePolygonShape2D" id=4]
segments = PoolVector2Array( -5.93512, -43.2195, 6.44476, -42.9695, 6.44476, -42.9695, 11.127, -54.3941, 11.127, -54.3941, 26.9528, -49.4309, 26.9528, -49.4309, 26.2037, -36.508, 26.2037, -36.508, 37.5346, -28.1737, 37.5346, -28.1737, 47.6282, -34.3806, 47.6282, -34.3806, 58.0427, -20.9631, 58.0427, -20.9631, 51.113, -10.2876, 51.113, -10.2876, 50.9869, 35.2694, 50.9869, 35.2694, 38.8, 47.5, 38.8, 47.5, 15.9852, 54.3613, 15.9852, 54.3613, -14.9507, 54.1845, -14.9507, 54.1845, -36.5, 48.1, -36.5, 48.1, -50.4828, 36.33, -50.4828, 36.33, -51.3668, -9.98545, -51.3668, -9.98545, -57.8889, -20.5885, -57.8889, -20.5885, -46.9473, -34.7342, -46.9473, -34.7342, -37.4014, -28.547, -37.4014, -28.547, -26.0876, -37.0323, -26.0876, -37.0323, -26.9862, -49.15, -26.9862, -49.15, -11.4152, -54.5332, -11.4152, -54.5332, -5.93512, -43.2195 )
[node name="Test" type="Node2D"]
script = ExtResource( 1 )
[node name="Options" parent="." instance=ExtResource( 3 )]
[node name="Shapes" type="Node2D" parent="."]
z_index = -1
z_as_relative = false
[node name="RigidBodyRectangle" type="RigidBody2D" parent="Shapes"]
position = Vector2( 114.877, 248.76 )
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodyRectangle"]
rotation = -1.19206
scale = Vector2( 1.2, 1.2 )
shape = SubResource( 1 )
[node name="RigidBodySphere" type="RigidBody2D" parent="Shapes"]
position = Vector2( 314.894, 257.658 )
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodySphere"]
shape = SubResource( 2 )
[node name="RigidBodyCapsule" type="RigidBody2D" parent="Shapes"]
position = Vector2( 465.629, 261.204 )
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodyCapsule"]
rotation = -0.202458
scale = Vector2( 1.2, 1.2 )
shape = SubResource( 3 )
[node name="RigidBodyConvexPolygon" type="RigidBody2D" parent="Shapes"]
position = Vector2( 613.385, 252.771 )
mode = 1
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Shapes/RigidBodyConvexPolygon"]
polygon = PoolVector2Array( 10.7, -54.5, 28.3596, -49.4067, 47.6282, -34.3806, 57.9717, -20.9447, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -58.0115, -20.515, -46.9473, -34.7342, -26.0876, -50.1138, -11.4152, -54.5332 )
[node name="GodotIcon" type="Sprite" parent="Shapes/RigidBodyConvexPolygon"]
modulate = Color( 1, 1, 1, 0.392157 )
texture = ExtResource( 2 )
[node name="RigidBodyConcavePolygon" type="RigidBody2D" parent="Shapes"]
position = Vector2( 771.159, 252.771 )
mode = 1
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Shapes/RigidBodyConcavePolygon"]
polygon = PoolVector2Array( -5.93512, -43.2195, 6.44476, -42.9695, 11.127, -54.3941, 26.9528, -49.4309, 26.2037, -36.508, 37.5346, -28.1737, 47.6282, -34.3806, 58.0427, -20.9631, 51.113, -10.2876, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -51.3668, -9.98545, -57.8889, -20.5885, -46.9473, -34.7342, -37.4014, -28.547, -26.0876, -37.0323, -26.9862, -49.15, -11.4152, -54.5332 )
[node name="GodotIcon" type="Sprite" parent="Shapes/RigidBodyConcavePolygon"]
modulate = Color( 1, 1, 1, 0.392157 )
texture = ExtResource( 2 )
[node name="RigidBodyConcaveSegments" type="RigidBody2D" parent="Shapes"]
position = Vector2( 930.097, 252.771 )
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodyConcaveSegments"]
shape = SubResource( 4 )
[node name="GodotIcon" type="Sprite" parent="Shapes/RigidBodyConcaveSegments"]
modulate = Color( 1, 1, 1, 0.392157 )
texture = ExtResource( 2 )
[node name="Controls" type="VBoxContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 25.3619
margin_top = 416.765
margin_right = 218.362
margin_bottom = 458.765
custom_constants/separation = 10
__meta__ = {
"_edit_use_anchors_": false
}
[node name="OffsetH" type="HBoxContainer" parent="Controls"]
margin_right = 193.0
margin_bottom = 16.0
custom_constants/separation = 20
alignment = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="Controls/OffsetH"]
margin_top = 1.0
margin_right = 53.0
margin_bottom = 15.0
text = "Offset H"
[node name="HSlider" type="HSlider" parent="Controls/OffsetH"]
margin_left = 73.0
margin_right = 193.0
margin_bottom = 16.0
rect_min_size = Vector2( 120, 0 )
min_value = -1.0
max_value = 1.0
step = 0.01
[node name="OffsetV" type="HBoxContainer" parent="Controls"]
margin_top = 26.0
margin_right = 193.0
margin_bottom = 42.0
custom_constants/separation = 20
alignment = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="Controls/OffsetV"]
margin_left = 2.0
margin_top = 1.0
margin_right = 53.0
margin_bottom = 15.0
text = "Offset V"
[node name="HSlider" type="HSlider" parent="Controls/OffsetV"]
margin_left = 73.0
margin_right = 193.0
margin_bottom = 16.0
rect_min_size = Vector2( 120, 0 )
min_value = -1.0
max_value = 1.0
step = 0.01
[connection signal="value_changed" from="Controls/OffsetH/HSlider" to="." method="set_h_offset"]
[connection signal="value_changed" from="Controls/OffsetV/HSlider" to="." method="set_v_offset"]

View File

@@ -13,22 +13,23 @@ func _ready():
func _physics_process(_delta):
if !_do_raycasts:
if not _do_raycasts:
return
_do_raycasts = false
Log.print_log("* Start Raycasting...")
clear_lines()
clear_drawn_nodes()
for shape in $Shapes.get_children():
var body = shape as PhysicsBody2D
for node in $Shapes.get_children():
var body = node as PhysicsBody2D
var space_state = body.get_world_2d().direct_space_state
var body_name = body.name.substr("RigidBody".length())
Log.print_log("* Testing: %s" % body.name)
Log.print_log("* Testing: %s" % body_name)
var center = body.global_transform.origin
var center = body.position
# Raycast entering from the top.
var res = _add_raycast(space_state, center - Vector2(0, 100), center)

View File

@@ -1,4 +1,4 @@
[gd_scene load_steps=6 format=2]
[gd_scene load_steps=7 format=2]
[ext_resource path="res://assets/godot-head.png" type="Texture" id=1]
[ext_resource path="res://tests/functional/test_raycasting.gd" type="Script" id=2]
@@ -6,12 +6,15 @@
[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 40, 60 )
[sub_resource type="CircleShape2D" id=3]
radius = 60.0
[sub_resource type="CapsuleShape2D" id=2]
radius = 30.0
height = 50.0
[sub_resource type="CircleShape2D" id=3]
radius = 60.0
[sub_resource type="ConcavePolygonShape2D" id=4]
segments = PoolVector2Array( -5.93512, -43.2195, 6.44476, -42.9695, 6.44476, -42.9695, 11.127, -54.3941, 11.127, -54.3941, 26.9528, -49.4309, 26.9528, -49.4309, 26.2037, -36.508, 26.2037, -36.508, 37.5346, -28.1737, 37.5346, -28.1737, 47.6282, -34.3806, 47.6282, -34.3806, 58.0427, -20.9631, 58.0427, -20.9631, 51.113, -10.2876, 51.113, -10.2876, 50.9869, 35.2694, 50.9869, 35.2694, 38.8, 47.5, 38.8, 47.5, 15.9852, 54.3613, 15.9852, 54.3613, -14.9507, 54.1845, -14.9507, 54.1845, -36.5, 48.1, -36.5, 48.1, -50.4828, 36.33, -50.4828, 36.33, -51.3668, -9.98545, -51.3668, -9.98545, -57.8889, -20.5885, -57.8889, -20.5885, -46.9473, -34.7342, -46.9473, -34.7342, -37.4014, -28.547, -37.4014, -28.547, -26.0876, -37.0323, -26.0876, -37.0323, -26.9862, -49.15, -26.9862, -49.15, -11.4152, -54.5332, -11.4152, -54.5332, -5.93512, -43.2195 )
[node name="Test" type="Node2D"]
script = ExtResource( 2 )
@@ -22,47 +25,58 @@ z_as_relative = false
[node name="RigidBodyRectangle" type="RigidBody2D" parent="Shapes"]
position = Vector2( 114.877, 248.76 )
mode = 3
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodyRectangle"]
rotation = -1.19206
scale = Vector2( 1.5, 1.5 )
scale = Vector2( 1.2, 1.2 )
shape = SubResource( 1 )
[node name="RigidBodySphere" type="RigidBody2D" parent="Shapes"]
position = Vector2( 314.894, 257.658 )
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodySphere"]
shape = SubResource( 3 )
[node name="RigidBodyCapsule" type="RigidBody2D" parent="Shapes"]
position = Vector2( 313.583, 261.204 )
mode = 3
position = Vector2( 465.629, 261.204 )
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodyCapsule"]
rotation = -0.202458
scale = Vector2( 1.5, 1.5 )
scale = Vector2( 1.2, 1.2 )
shape = SubResource( 2 )
[node name="RigidBodyConcavePolygon" type="RigidBody2D" parent="Shapes"]
position = Vector2( 514.899, 252.771 )
mode = 3
[node name="GodotIcon" type="Sprite" parent="Shapes/RigidBodyConcavePolygon"]
modulate = Color( 1, 1, 1, 0.392157 )
texture = ExtResource( 1 )
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Shapes/RigidBodyConcavePolygon"]
polygon = PoolVector2Array( -5.93512, -43.2195, 6.44476, -42.9695, 11.127, -54.3941, 26.9528, -49.4309, 26.2037, -36.508, 37.5346, -28.1737, 47.6282, -34.3806, 58.0427, -20.9631, 51.113, -10.2876, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -51.3668, -9.98545, -57.8889, -20.5885, -46.9473, -34.7342, -37.4014, -28.547, -26.0876, -37.0323, -26.9862, -49.15, -11.4152, -54.5332 )
[node name="RigidBodyConvexPolygon" type="RigidBody2D" parent="Shapes"]
position = Vector2( 738.975, 252.771 )
mode = 3
position = Vector2( 613.385, 252.771 )
mode = 1
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Shapes/RigidBodyConvexPolygon"]
polygon = PoolVector2Array( 10.7, -54.5, 28.3596, -49.4067, 47.6282, -34.3806, 57.9717, -20.9447, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -58.0115, -20.515, -46.9473, -34.7342, -26.0876, -50.1138, -11.4152, -54.5332 )
[node name="GodotIcon" type="Sprite" parent="Shapes/RigidBodyConvexPolygon"]
modulate = Color( 1, 1, 1, 0.392157 )
texture = ExtResource( 1 )
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Shapes/RigidBodyConvexPolygon"]
polygon = PoolVector2Array( 10.7, -54.5, 28.3596, -49.4067, 47.6282, -34.3806, 57.9717, -20.9447, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -58.0115, -20.515, -46.9473, -34.7342, -26.0876, -50.1138, -11.4152, -54.5332 )
[node name="RigidBodyConcavePolygon" type="RigidBody2D" parent="Shapes"]
position = Vector2( 771.159, 252.771 )
mode = 1
[node name="RigidBodySphere" type="RigidBody2D" parent="Shapes"]
position = Vector2( 917.136, 270.868 )
mode = 3
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Shapes/RigidBodyConcavePolygon"]
polygon = PoolVector2Array( -5.93512, -43.2195, 6.44476, -42.9695, 11.127, -54.3941, 26.9528, -49.4309, 26.2037, -36.508, 37.5346, -28.1737, 47.6282, -34.3806, 58.0427, -20.9631, 51.113, -10.2876, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -51.3668, -9.98545, -57.8889, -20.5885, -46.9473, -34.7342, -37.4014, -28.547, -26.0876, -37.0323, -26.9862, -49.15, -11.4152, -54.5332 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodySphere"]
shape = SubResource( 3 )
[node name="GodotIcon" type="Sprite" parent="Shapes/RigidBodyConcavePolygon"]
modulate = Color( 1, 1, 1, 0.392157 )
texture = ExtResource( 1 )
[node name="RigidBodyConcaveSegments" type="RigidBody2D" parent="Shapes"]
position = Vector2( 930.097, 252.771 )
mode = 1
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodyConcaveSegments"]
shape = SubResource( 4 )
[node name="GodotIcon" type="Sprite" parent="Shapes/RigidBodyConcaveSegments"]
modulate = Color( 1, 1, 1, 0.392157 )
texture = ExtResource( 1 )

View File

@@ -36,25 +36,27 @@ shape = SubResource( 2 )
[node name="RigidBodyConcavePolygon" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 683.614, 132.749 )
[node name="GodotIcon" type="Sprite" parent="DynamicShapes/RigidBodyConcavePolygon"]
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 1 )
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="DynamicShapes/RigidBodyConcavePolygon"]
scale = Vector2( 0.5, 0.5 )
polygon = PoolVector2Array( -5.93512, -43.2195, 6.44476, -42.9695, 11.127, -54.3941, 26.9528, -49.4309, 26.2037, -36.508, 37.5346, -28.1737, 47.6282, -34.3806, 58.0427, -20.9631, 51.113, -10.2876, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -51.3668, -9.98545, -57.8889, -20.5885, -46.9473, -34.7342, -37.4014, -28.547, -26.0876, -37.0323, -26.9862, -49.15, -11.4152, -54.5332 )
[node name="RigidBodyConvexPolygon" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 473.536, 134.336 )
[node name="GodotIcon" type="Sprite" parent="DynamicShapes/RigidBodyConvexPolygon"]
[node name="GodotIcon" type="Sprite" parent="DynamicShapes/RigidBodyConcavePolygon"]
self_modulate = Color( 1, 1, 1, 0.392157 )
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 1 )
[node name="RigidBodyConvexPolygon" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 473.536, 134.336 )
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="DynamicShapes/RigidBodyConvexPolygon"]
scale = Vector2( 0.5, 0.5 )
polygon = PoolVector2Array( 10.7, -54.5, 28.3596, -49.4067, 47.6282, -34.3806, 57.9717, -20.9447, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -58.0115, -20.515, -46.9473, -34.7342, -26.0876, -50.1138, -11.4152, -54.5332 )
[node name="GodotIcon" type="Sprite" parent="DynamicShapes/RigidBodyConvexPolygon"]
self_modulate = Color( 1, 1, 1, 0.392157 )
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 1 )
[node name="RigidBodySphere" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 919.968, 115.129 )

View File

@@ -50,21 +50,23 @@ shape = SubResource( 3 )
[node name="RigidBodyConvexPolygon" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 300, 1024 )
[node name="GodotIcon" type="Sprite" parent="DynamicShapes/RigidBodyConvexPolygon"]
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 3 )
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="DynamicShapes/RigidBodyConvexPolygon"]
scale = Vector2( 0.5, 0.5 )
polygon = PoolVector2Array( 10.7, -54.5, 28.3596, -49.4067, 47.6282, -34.3806, 57.9717, -20.9447, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -58.0115, -20.515, -46.9473, -34.7342, -26.0876, -50.1138, -11.4152, -54.5332 )
[node name="RigidBodyConcavePolygon" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 400, 1024 )
[node name="GodotIcon" type="Sprite" parent="DynamicShapes/RigidBodyConcavePolygon"]
[node name="GodotIcon" type="Sprite" parent="DynamicShapes/RigidBodyConvexPolygon"]
self_modulate = Color( 1, 1, 1, 0.392157 )
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 3 )
[node name="RigidBodyConcavePolygon" type="RigidBody2D" parent="DynamicShapes"]
position = Vector2( 400, 1024 )
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="DynamicShapes/RigidBodyConcavePolygon"]
scale = Vector2( 0.5, 0.5 )
polygon = PoolVector2Array( -5.93512, -43.2195, 6.44476, -42.9695, 11.127, -54.3941, 26.9528, -49.4309, 26.2037, -36.508, 37.5346, -28.1737, 47.6282, -34.3806, 58.0427, -20.9631, 51.113, -10.2876, 50.9869, 35.2694, 38.8, 47.5, 15.9852, 54.3613, -14.9507, 54.1845, -36.5, 48.1, -50.4828, 36.33, -51.3668, -9.98545, -57.8889, -20.5885, -46.9473, -34.7342, -37.4014, -28.547, -26.0876, -37.0323, -26.9862, -49.15, -11.4152, -54.5332 )
[node name="GodotIcon" type="Sprite" parent="DynamicShapes/RigidBodyConcavePolygon"]
self_modulate = Color( 1, 1, 1, 0.392157 )
scale = Vector2( 0.5, 0.5 )
texture = ExtResource( 3 )

View File

@@ -3,9 +3,10 @@ extends MenuButton
signal option_selected(item_path)
signal option_changed(item_path, checked)
func add_menu_item(item_path):
func add_menu_item(item_path, checkbox = false, checked = false):
var path_elements = item_path.split("/", false)
var path_element_count = path_elements.size()
assert(path_element_count > 0)
@@ -17,7 +18,12 @@ func add_menu_item(item_path):
path += popup_label + "/"
popup = _add_popup(popup, path, popup_label)
_add_item(popup, path_elements[path_element_count - 1])
var label = path_elements[path_element_count - 1]
if checkbox:
popup.add_check_item(label)
popup.set_item_checked(popup.get_item_count() - 1, checked)
else:
popup.add_item(label)
func _add_item(parent_popup, label):
@@ -33,6 +39,7 @@ func _add_popup(parent_popup, path, label):
var popup_menu = PopupMenu.new()
popup_menu.name = label
popup_menu.hide_on_checkable_item_selection = false
parent_popup.add_child(popup_menu)
parent_popup.add_submenu_item(label, label)
@@ -44,4 +51,10 @@ 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)
emit_signal("option_selected", item_path)
if 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)
else:
emit_signal("option_selected", item_path)

View File

@@ -1,6 +1,7 @@
class_name Test
extends Node
signal wait_done()
var _timer
@@ -8,6 +9,8 @@ var _timer_started = false
var _wait_physics_ticks_counter = 0
var _drawn_nodes = []
func _physics_process(_delta):
if (_wait_physics_ticks_counter > 0):
@@ -16,6 +19,47 @@ func _physics_process(_delta):
emit_signal("wait_done")
func add_sphere(pos, radius, color):
var sphere = MeshInstance.new()
var sphere_mesh = SphereMesh.new()
sphere_mesh.radius = radius
sphere_mesh.height = radius * 2.0
sphere.mesh = sphere_mesh
var material = SpatialMaterial.new()
material.flags_unshaded = true
material.albedo_color = color
sphere.material_override = material
_drawn_nodes.push_back(sphere)
add_child(sphere)
sphere.global_transform.origin = pos
func add_shape(shape, transform, color):
var collision = CollisionShape.new()
collision.shape = shape
_drawn_nodes.push_back(collision)
add_child(collision)
var mesh_instance = collision.get_child(0)
var material = SpatialMaterial.new()
material.flags_unshaded = true
material.albedo_color = color
mesh_instance.material_override = material
collision.global_transform = transform
func clear_drawn_nodes():
for node in _drawn_nodes:
node.queue_free()
_drawn_nodes.clear()
func create_rigidbody_box(size):
var template_shape = BoxShape.new()
template_shape.extents = 0.5 * size

View File

@@ -22,6 +22,10 @@ var _tests = [
"id": "Functional Tests/Box Pyramid",
"path": "res://tests/functional/test_pyramid.tscn",
},
{
"id": "Functional Tests/Collision Pairs",
"path": "res://tests/functional/test_collision_pairs.tscn",
},
{
"id": "Functional Tests/Raycasting",
"path": "res://tests/functional/test_raycasting.tscn",

View File

@@ -0,0 +1,211 @@
extends Test
const OPTION_TYPE_BOX = "Collision type/Box (1)"
const OPTION_TYPE_SPHERE = "Collision type/Sphere (2)"
const OPTION_TYPE_CAPSULE = "Collision type/Capsule (3)"
const OPTION_TYPE_CYLINDER = "Collision type/Cylinder (4)"
const OPTION_TYPE_CONVEX_POLYGON = "Collision type/Convex Polygon (5)"
const OPTION_SHAPE_BOX = "Shape type/Box"
const OPTION_SHAPE_SPHERE = "Shape type/Sphere"
const OPTION_SHAPE_CAPSULE = "Shape type/Capsule"
const OPTION_SHAPE_CYLINDER = "Shape type/Cylinder"
const OPTION_SHAPE_CONVEX_POLYGON = "Shape type/Convex Polygon"
const OPTION_SHAPE_CONCAVE_POLYGON = "Shape type/Concave Polygon"
const OFFSET_RANGE = 3.0
export(Vector3) var offset = Vector3.ZERO
var _update_collision = false
var _collision_test_index = 0
var _current_offset = Vector3.ZERO
var _collision_shapes = []
func _ready():
_initialize_collision_shapes()
$Options.add_menu_item(OPTION_TYPE_BOX)
$Options.add_menu_item(OPTION_TYPE_SPHERE)
$Options.add_menu_item(OPTION_TYPE_CAPSULE)
$Options.add_menu_item(OPTION_TYPE_CYLINDER)
$Options.add_menu_item(OPTION_TYPE_CONVEX_POLYGON)
$Options.add_menu_item(OPTION_SHAPE_BOX, true, true)
$Options.add_menu_item(OPTION_SHAPE_SPHERE, true, true)
$Options.add_menu_item(OPTION_SHAPE_CAPSULE, true, true)
$Options.add_menu_item(OPTION_SHAPE_CYLINDER, true, true)
$Options.add_menu_item(OPTION_SHAPE_CONVEX_POLYGON, true, true)
$Options.add_menu_item(OPTION_SHAPE_CONCAVE_POLYGON, true, true)
$Options.connect("option_selected", self, "_on_option_selected")
$Options.connect("option_changed", self, "_on_option_changed")
yield(start_timer(0.5), "timeout")
if is_timer_canceled():
return
_update_collision = true
func _input(event):
var key_event = event as InputEventKey
if (key_event and not key_event.pressed):
if (key_event.scancode == KEY_1):
_on_option_selected(OPTION_TYPE_BOX)
elif (key_event.scancode == KEY_2):
_on_option_selected(OPTION_TYPE_SPHERE)
elif (key_event.scancode == KEY_3):
_on_option_selected(OPTION_TYPE_CAPSULE)
elif (key_event.scancode == KEY_4):
_on_option_selected(OPTION_TYPE_CYLINDER)
elif (key_event.scancode == KEY_5):
_on_option_selected(OPTION_TYPE_CONVEX_POLYGON)
func _physics_process(_delta):
if not _update_collision:
return
_update_collision = false
_do_collision_test()
func set_x_offset(value):
offset.x = value * OFFSET_RANGE
_update_collision = true
func set_y_offset(value):
offset.y = value * OFFSET_RANGE
_update_collision = true
func set_z_offset(value):
offset.z = value * OFFSET_RANGE
_update_collision = true
func _initialize_collision_shapes():
_collision_shapes.clear()
for node in $Shapes.get_children():
var body = node as PhysicsBody
var shape = body.shape_owner_get_shape(0, 0)
shape.resource_name = node.name.substr("RigidBody".length())
_collision_shapes.push_back(shape)
func _do_collision_test():
clear_drawn_nodes()
var shape = _collision_shapes[_collision_test_index]
Log.print_log("* Start %s collision tests..." % shape.resource_name)
var shape_query = PhysicsShapeQueryParameters.new()
shape_query.set_shape(shape)
var shape_scale = Vector3(0.5, 0.5, 0.5)
shape_query.transform = Transform.IDENTITY.scaled(shape_scale)
for node in $Shapes.get_children():
if not node.visible:
continue
var body = node as PhysicsBody
var space_state = body.get_world().direct_space_state
Log.print_log("* Testing: %s" % body.name)
var center = body.global_transform.origin
# Collision at the center inside.
var res = _add_collision(space_state, center, shape, shape_query)
Log.print_log("Collision center inside: %s" % ("NO HIT" if res.empty() else "HIT"))
Log.print_log("* Done.")
func _add_collision(space_state, pos, shape, shape_query):
shape_query.transform.origin = pos + offset
var results = space_state.collide_shape(shape_query)
var color
if results.empty():
color = Color.white.darkened(0.5)
else:
color = Color.green
# Draw collision query shape.
add_shape(shape, shape_query.transform, color)
# Draw contact positions.
for contact_pos in results:
add_sphere(contact_pos, 0.05, Color.red)
return results
func _on_option_selected(option):
match option:
OPTION_TYPE_BOX:
_collision_test_index = _find_type_index("Box")
_update_collision = true
OPTION_TYPE_SPHERE:
_collision_test_index = _find_type_index("Sphere")
_update_collision = true
OPTION_TYPE_CAPSULE:
_collision_test_index = _find_type_index("Capsule")
_update_collision = true
OPTION_TYPE_CYLINDER:
_collision_test_index = _find_type_index("Cylinder")
_update_collision = true
OPTION_TYPE_CONVEX_POLYGON:
_collision_test_index = _find_type_index("ConvexPolygon")
_update_collision = true
func _find_type_index(type_name):
for type_index in _collision_shapes.size():
var type_shape = _collision_shapes[type_index]
if type_shape.resource_name.find(type_name) > -1:
return type_index
Log.print_error("Invalid collision type: " + type_name)
return -1
func _on_option_changed(option, checked):
var node
match option:
OPTION_SHAPE_BOX:
node = _find_shape_node("Box")
OPTION_SHAPE_SPHERE:
node = _find_shape_node("Sphere")
OPTION_SHAPE_CAPSULE:
node = _find_shape_node("Capsule")
OPTION_SHAPE_CYLINDER:
node = _find_shape_node("Cylinder")
OPTION_SHAPE_CONVEX_POLYGON:
node = _find_shape_node("ConvexPolygon")
OPTION_SHAPE_CONCAVE_POLYGON:
node = _find_shape_node("ConcavePolygon")
if node:
node.visible = checked
node.get_child(0).disabled = not checked
_update_collision = true
func _find_shape_node(type_name):
var node = $Shapes.find_node("RigidBody%s" % type_name)
if not node:
Log.print_error("Invalid shape type: " + type_name)
return node

View File

@@ -0,0 +1,169 @@
[gd_scene load_steps=11 format=2]
[ext_resource path="res://assets/robot_head/godot3_robot_head_collision.tres" type="Shape" id=1]
[ext_resource path="res://tests/functional/test_collision_pairs.gd" type="Script" id=2]
[ext_resource path="res://utils/exception_cylinder.gd" type="Script" id=3]
[ext_resource path="res://utils/camera_orbit.gd" type="Script" id=4]
[ext_resource path="res://tests/test_options.tscn" type="PackedScene" id=5]
[sub_resource type="BoxShape" id=1]
[sub_resource type="SphereShape" id=5]
[sub_resource type="CapsuleShape" id=2]
[sub_resource type="CylinderShape" id=3]
[sub_resource type="ConvexPolygonShape" id=4]
points = PoolVector3Array( -0.7, 0, -0.7, -0.3, 0, 0.8, 0.8, 0, -0.3, 0, -1, 0 )
[node name="Test" type="Spatial"]
script = ExtResource( 2 )
[node name="Options" parent="." instance=ExtResource( 5 )]
[node name="Controls" type="VBoxContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 25.0
margin_top = 417.0
margin_right = -806.0
margin_bottom = -141.0
custom_constants/separation = 10
__meta__ = {
"_edit_use_anchors_": false
}
[node name="OffsetX" type="HBoxContainer" parent="Controls"]
margin_right = 193.0
margin_bottom = 16.0
custom_constants/separation = 20
alignment = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="Controls/OffsetX"]
margin_left = 2.0
margin_top = 1.0
margin_right = 53.0
margin_bottom = 15.0
text = "Offset X"
[node name="HSlider" type="HSlider" parent="Controls/OffsetX"]
margin_left = 73.0
margin_right = 193.0
margin_bottom = 16.0
rect_min_size = Vector2( 120, 0 )
min_value = -1.0
max_value = 1.0
step = 0.01
[node name="OffsetY" type="HBoxContainer" parent="Controls"]
margin_top = 26.0
margin_right = 193.0
margin_bottom = 42.0
custom_constants/separation = 20
alignment = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="Controls/OffsetY"]
margin_left = 3.0
margin_top = 1.0
margin_right = 53.0
margin_bottom = 15.0
text = "Offset Y"
[node name="HSlider" type="HSlider" parent="Controls/OffsetY"]
margin_left = 73.0
margin_right = 193.0
margin_bottom = 16.0
rect_min_size = Vector2( 120, 0 )
min_value = -1.0
max_value = 1.0
step = 0.01
[node name="OffsetZ" type="HBoxContainer" parent="Controls"]
margin_top = 52.0
margin_right = 193.0
margin_bottom = 68.0
custom_constants/separation = 20
alignment = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="Controls/OffsetZ"]
margin_left = 2.0
margin_top = 1.0
margin_right = 53.0
margin_bottom = 15.0
text = "Offset Z"
[node name="HSlider" type="HSlider" parent="Controls/OffsetZ"]
margin_left = 73.0
margin_right = 193.0
margin_bottom = 16.0
rect_min_size = Vector2( 120, 0 )
min_value = -1.0
max_value = 1.0
step = 0.01
[node name="Shapes" type="Spatial" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 9.35591, 0 )
[node name="RigidBodyBox" type="RigidBody" parent="Shapes"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -6, 0, 0 )
mode = 3
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodyBox"]
transform = Transform( 0.579556, 0.0885213, 0.145926, 0, 0.939693, -0.205212, -0.155291, 0.330366, 0.544604, 0, 0, 0 )
shape = SubResource( 1 )
[node name="RigidBodySphere" type="RigidBody" parent="Shapes"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0, 0 )
mode = 3
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodySphere"]
transform = Transform( 1.2, 0, 0, 0, 1.2, 0, 0, 0, 1.2, 0, 0, 0 )
shape = SubResource( 5 )
[node name="RigidBodyCapsule" type="RigidBody" parent="Shapes"]
mode = 3
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodyCapsule"]
transform = Transform( 0.8, 0, 0, 0, -1.30337e-07, -0.8, 0, 0.8, -1.30337e-07, 0, 0, 0 )
shape = SubResource( 2 )
[node name="RigidBodyCylinder" type="RigidBody" parent="Shapes"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0 )
mode = 3
script = ExtResource( 3 )
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodyCylinder"]
transform = Transform( 0.772741, -0.258819, 2.59821e-08, 0.2, 0.933013, -0.207055, 0.0535898, 0.25, 0.772741, 0, 0, 0 )
shape = SubResource( 3 )
[node name="RigidBodyConvexPolygon" type="RigidBody" parent="Shapes"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 6, -0.211, 0 )
mode = 3
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodyConvexPolygon"]
transform = Transform( 2, 0, 0, 0, 2.89766, -0.517939, 0, 0.776908, 1.93177, 0, 0.3533, 0 )
shape = SubResource( 4 )
[node name="RigidBodyConcavePolygon" type="StaticBody" parent="Shapes"]
transform = Transform( 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, -6, 3.93357 )
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodyConcavePolygon"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0 )
shape = ExtResource( 1 )
[node name="Camera" type="Camera" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 5.8667, 11.8164 )
script = ExtResource( 4 )
[connection signal="value_changed" from="Controls/OffsetX/HSlider" to="." method="set_x_offset"]
[connection signal="value_changed" from="Controls/OffsetY/HSlider" to="." method="set_y_offset"]
[connection signal="value_changed" from="Controls/OffsetZ/HSlider" to="." method="set_z_offset"]

View File

@@ -23,7 +23,7 @@ func _ready():
func _physics_process(_delta):
if !_do_raycasts:
if not _do_raycasts:
return
_do_raycasts = false

View File

@@ -7,6 +7,8 @@
[sub_resource type="BoxShape" id=1]
[sub_resource type="SphereShape" id=5]
[sub_resource type="CapsuleShape" id=2]
[sub_resource type="CylinderShape" id=3]
@@ -14,8 +16,6 @@
[sub_resource type="ConvexPolygonShape" id=4]
points = PoolVector3Array( -0.7, 0, -0.7, -0.3, 0, 0.8, 0.8, 0, -0.3, 0, -1, 0 )
[sub_resource type="SphereShape" id=5]
[node name="Test" type="Spatial"]
script = ExtResource( 2 )
@@ -30,15 +30,23 @@ mode = 3
transform = Transform( 0.579556, 0.0885213, 0.145926, 0, 0.939693, -0.205212, -0.155291, 0.330366, 0.544604, 0, 0, 0 )
shape = SubResource( 1 )
[node name="RigidBodyCapsule" type="RigidBody" parent="Shapes"]
[node name="RigidBodySphere" type="RigidBody" parent="Shapes"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0, 0 )
mode = 3
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodySphere"]
transform = Transform( 1.2, 0, 0, 0, 1.2, 0, 0, 0, 1.2, 0, 0, 0 )
shape = SubResource( 5 )
[node name="RigidBodyCapsule" type="RigidBody" parent="Shapes"]
mode = 3
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodyCapsule"]
transform = Transform( 0.8, 0, 0, 0, -1.30337e-07, -0.8, 0, 0.8, -1.30337e-07, 0, 0, 0 )
shape = SubResource( 2 )
[node name="RigidBodyCylinder" type="RigidBody" parent="Shapes"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0 )
mode = 3
script = ExtResource( 3 )
@@ -46,22 +54,14 @@ script = ExtResource( 3 )
transform = Transform( 0.772741, -0.258819, 2.59821e-08, 0.2, 0.933013, -0.207055, 0.0535898, 0.25, 0.772741, 0, 0, 0 )
shape = SubResource( 3 )
[node name="RigidBodyConvex" type="RigidBody" parent="Shapes"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 3, -0.210678, 0 )
[node name="RigidBodyConvexPolygon" type="RigidBody" parent="Shapes"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 6, -0.211, 0 )
mode = 3
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodyConvex"]
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodyConvexPolygon"]
transform = Transform( 2, 0, 0, 0, 2.89766, -0.517939, 0, 0.776908, 1.93177, 0, 0.3533, 0 )
shape = SubResource( 4 )
[node name="RigidBodySphere" type="RigidBody" parent="Shapes"]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 6, 0, 0 )
mode = 3
[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodySphere"]
transform = Transform( 1.2, 0, 0, 0, 1.2, 0, 0, 0, 1.2, 0, 0, 0 )
shape = SubResource( 5 )
[node name="StaticBodyHead" type="StaticBody" parent="Shapes"]
transform = Transform( 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, -6, 3.93357 )

View File

@@ -3,12 +3,12 @@ extends Test
const OPTION_TYPE_ALL = "Shape type/All"
const OPTION_TYPE_BOX = "Shape type/Box"
const OPTION_TYPE_SPHERE = "Shape type/Sphere"
const OPTION_TYPE_CAPSULE = "Shape type/Capsule"
const OPTION_TYPE_CYLINDER = "Shape type/Cylinder"
const OPTION_TYPE_CONVEX = "Shape type/Convex"
const OPTION_TYPE_SPHERE = "Shape type/Sphere"
export(Array) var spawns = Array()
export(Array) var spawns = Array()
export(int) var spawn_count = 100
export(int, 1, 10) var spawn_multiplier = 5
@@ -27,10 +27,10 @@ func _ready():
$Options.add_menu_item(OPTION_TYPE_ALL)
$Options.add_menu_item(OPTION_TYPE_BOX)
$Options.add_menu_item(OPTION_TYPE_SPHERE)
$Options.add_menu_item(OPTION_TYPE_CAPSULE)
$Options.add_menu_item(OPTION_TYPE_CYLINDER)
$Options.add_menu_item(OPTION_TYPE_CONVEX)
$Options.add_menu_item(OPTION_TYPE_SPHERE)
$Options.connect("option_selected", self, "_on_option_selected")
_start_all_types()
@@ -51,14 +51,14 @@ func _on_option_selected(option):
_start_all_types()
OPTION_TYPE_BOX:
_start_type(_find_type_index("Box"))
OPTION_TYPE_SPHERE:
_start_type(_find_type_index("Sphere"))
OPTION_TYPE_CAPSULE:
_start_type(_find_type_index("Capsule"))
OPTION_TYPE_CYLINDER:
_start_type(_find_type_index("Cylinder"))
OPTION_TYPE_CONVEX:
_start_type(_find_type_index("Convex"))
OPTION_TYPE_SPHERE:
_start_type(_find_type_index("Sphere"))
func _find_type_index(type_name):

View File

@@ -3,9 +3,10 @@ extends MenuButton
signal option_selected(item_path)
signal option_changed(item_path, checked)
func add_menu_item(item_path):
func add_menu_item(item_path, checkbox = false, checked = false):
var path_elements = item_path.split("/", false)
var path_element_count = path_elements.size()
assert(path_element_count > 0)
@@ -17,7 +18,12 @@ func add_menu_item(item_path):
path += popup_label + "/"
popup = _add_popup(popup, path, popup_label)
_add_item(popup, path_elements[path_element_count - 1])
var label = path_elements[path_element_count - 1]
if checkbox:
popup.add_check_item(label)
popup.set_item_checked(popup.get_item_count() - 1, checked)
else:
popup.add_item(label)
func _add_item(parent_popup, label):
@@ -33,6 +39,7 @@ func _add_popup(parent_popup, path, label):
var popup_menu = PopupMenu.new()
popup_menu.name = label
popup_menu.hide_on_checkable_item_selection = false
parent_popup.add_child(popup_menu)
parent_popup.add_submenu_item(label, label)
@@ -44,4 +51,10 @@ 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)
emit_signal("option_selected", item_path)
if 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)
else:
emit_signal("option_selected", item_path)