diff --git a/3d/physics_tests/project.godot b/3d/physics_tests/project.godot index 6f5bf4f7..f90f57d4 100644 --- a/3d/physics_tests/project.godot +++ b/3d/physics_tests/project.godot @@ -26,7 +26,7 @@ _global_script_class_icons={ [application] -config/name="Physics Tests" +config/name="3D Physics Tests" run/main_scene="res://main.tscn" config/icon="res://icon.png" @@ -71,5 +71,5 @@ restart_test={ [rendering] quality/driver/driver_name="GLES2" -environment/default_clear_color=Color( 0, 0, 0, 1 ) +environment/default_clear_color=Color( 0.184314, 0.184314, 0.184314, 1 ) quality/filters/msaa=2 diff --git a/3d/physics_tests/test.gd b/3d/physics_tests/test.gd index 848ab247..96a0ea94 100644 --- a/3d/physics_tests/test.gd +++ b/3d/physics_tests/test.gd @@ -1,10 +1,33 @@ class_name Test extends Node +signal wait_done() var _timer var _timer_started = false +var _wait_physics_ticks_counter = 0 + + +func _physics_process(_delta): + if (_wait_physics_ticks_counter > 0): + _wait_physics_ticks_counter -= 1 + if (_wait_physics_ticks_counter == 0): + emit_signal("wait_done") + + +func create_rigidbody_box(size): + var template_shape = BoxShape.new() + template_shape.extents = 0.5 * size + + var template_collision = CollisionShape.new() + template_collision.shape = template_shape + + var template_body = RigidBody.new() + template_body.add_child(template_collision) + + return template_body + func start_timer(timeout): if _timer == null: @@ -32,5 +55,10 @@ func is_timer_canceled(): return _timer.paused +func wait_for_physics_ticks(tick_count): + _wait_physics_ticks_counter = tick_count + return self + + func _on_timer_done(): _timer_started = false diff --git a/3d/physics_tests/tests.gd b/3d/physics_tests/tests.gd index d8a6cf8b..d75cc9f4 100644 --- a/3d/physics_tests/tests.gd +++ b/3d/physics_tests/tests.gd @@ -14,6 +14,22 @@ var _tests = [ "id": "Functional Tests/Friction", "path": "res://tests/functional/test_friction.tscn", }, + { + "id": "Functional Tests/Box Stack", + "path": "res://tests/functional/test_stack.tscn", + }, + { + "id": "Functional Tests/Box Pyramid", + "path": "res://tests/functional/test_pyramid.tscn", + }, + { + "id": "Functional Tests/Raycasting", + "path": "res://tests/functional/test_raycasting.tscn", + }, + { + "id": "Performance Tests/Broadphase", + "path": "res://tests/performance/test_perf_broadphase.tscn", + }, { "id": "Performance Tests/Contacts", "path": "res://tests/performance/test_perf_contacts.tscn", diff --git a/3d/physics_tests/tests/functional/test_pyramid.gd b/3d/physics_tests/tests/functional/test_pyramid.gd new file mode 100644 index 00000000..673d35cd --- /dev/null +++ b/3d/physics_tests/tests/functional/test_pyramid.gd @@ -0,0 +1,58 @@ +extends Test + + +export(int, 1, 100) var height = 10 +export(int, 1, 100) var width_max = 100 +export(int, 1, 100) var depth_max = 1 +export(Vector3) var box_size = Vector3(1.0, 1.0, 1.0) +export(Vector3) var box_spacing = Vector3(0.0, 0.0, 0.0) + + +func _ready(): + _create_pyramid() + + +func _create_pyramid(): + var root_node = $Pyramid + + var template_shape = BoxShape.new() + template_shape.extents = 0.5 * box_size + + var template_collision = CollisionShape.new() + template_collision.shape = template_shape + + var template_body = RigidBody.new() + template_body.add_child(template_collision) + + var pos_y = 0.5 * box_size.y + box_spacing.y + + for level in height: + var level_index = height - level - 1 + var num_boxes = 2 * level_index + 1 + var num_boxes_width = min(num_boxes, width_max) + var num_boxes_depth = min(num_boxes, depth_max) + + var row_node = Spatial.new() + row_node.transform.origin = Vector3(0.0, pos_y, 0.0) + row_node.name = "Row%02d" % (level + 1) + root_node.add_child(row_node) + + var pos_x = -0.5 * (num_boxes_width - 1) * (box_size.x + box_spacing.x) + + for box_index_x in num_boxes_width: + var pos_z = -0.5 * (num_boxes_depth - 1) * (box_size.z + box_spacing.z) + + for box_index_z in num_boxes_depth: + var box_index = box_index_x * box_index_z + var box = template_body.duplicate() + box.transform.origin = Vector3(pos_x, 0.0, pos_z) + box.name = "Box%02d" % (box_index + 1) + row_node.add_child(box) + + pos_z += box_size.z + box_spacing.z + + pos_x += box_size.x + box_spacing.x + + pos_y += box_size.y + box_spacing.y + + template_body.queue_free() diff --git a/3d/physics_tests/tests/functional/test_pyramid.tscn b/3d/physics_tests/tests/functional/test_pyramid.tscn new file mode 100644 index 00000000..5ef9442b --- /dev/null +++ b/3d/physics_tests/tests/functional/test_pyramid.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://tests/functional/test_pyramid.gd" type="Script" id=1] +[ext_resource path="res://tests/static_scene_plane.tscn" type="PackedScene" id=2] +[ext_resource path="res://utils/camera_orbit.gd" type="Script" id=4] + +[node name="Test" type="Spatial"] +script = ExtResource( 1 ) + +[node name="Pyramid" type="Spatial" parent="."] + +[node name="StaticBodyPlane" parent="." instance=ExtResource( 2 )] + +[node name="Camera" type="Camera" parent="."] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 6.62348, 22.9474 ) +script = ExtResource( 4 ) diff --git a/3d/physics_tests/tests/functional/test_raycasting.gd b/3d/physics_tests/tests/functional/test_raycasting.gd new file mode 100644 index 00000000..ac56f906 --- /dev/null +++ b/3d/physics_tests/tests/functional/test_raycasting.gd @@ -0,0 +1,78 @@ +extends Test + + +var _do_raycasts = false + +onready var _raycast_visuals = ImmediateGeometry.new() + + +func _ready(): + var material = SpatialMaterial.new() + material.flags_unshaded = true + material.vertex_color_use_as_albedo = true + _raycast_visuals.material_override = material + + add_child(_raycast_visuals) + move_child(_raycast_visuals, get_child_count()) + + yield(start_timer(0.5), "timeout") + if is_timer_canceled(): + return + + _do_raycasts = true + + +func _physics_process(_delta): + if !_do_raycasts: + return + + _do_raycasts = false + + Log.print_log("* Start Raycasting...") + + _raycast_visuals.clear() + _raycast_visuals.begin(Mesh.PRIMITIVE_LINES) + + for shape in $Shapes.get_children(): + var body = shape as PhysicsBody + var space_state = body.get_world().direct_space_state + + Log.print_log("* Testing: %s" % body.name) + + var center = body.global_transform.origin + + # Raycast entering from the top. + var res = _add_raycast(space_state, center + Vector3(0.0, 2.0, 0.0), center) + Log.print_log("Raycast in: %s" % ("HIT" if res else "NO HIT")) + + # Raycast exiting from inside. + center.x -= 0.2 + res = _add_raycast(space_state, center, center - Vector3(0.0, 3.0, 0.0)) + Log.print_log("Raycast out: %s" % ("HIT" if res else "NO HIT")) + + # Raycast all inside. + center.x += 0.4 + res = _add_raycast(space_state, center, center - Vector3(0.0, 0.8, 0.0)) + Log.print_log("Raycast inside: %s" % ("HIT" if res else "NO HIT")) + + _raycast_visuals.end() + + +func _add_raycast(space_state, pos_start, pos_end): + var result = space_state.intersect_ray(pos_start, pos_end) + if result: + _raycast_visuals.set_color(Color.green) + else: + _raycast_visuals.set_color(Color.red.darkened(0.5)) + + # Draw raycast line. + _raycast_visuals.add_vertex(pos_start) + _raycast_visuals.add_vertex(pos_end) + + # Draw raycast arrow. + _raycast_visuals.add_vertex(pos_end) + _raycast_visuals.add_vertex(pos_end + Vector3(-0.05, 0.1, 0.0)) + _raycast_visuals.add_vertex(pos_end) + _raycast_visuals.add_vertex(pos_end + Vector3(0.05, 0.1, 0.0)) + + return result diff --git a/3d/physics_tests/tests/functional/test_raycasting.tscn b/3d/physics_tests/tests/functional/test_raycasting.tscn new file mode 100644 index 00000000..52b3599d --- /dev/null +++ b/3d/physics_tests/tests/functional/test_raycasting.tscn @@ -0,0 +1,74 @@ +[gd_scene load_steps=10 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_raycasting.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] + +[sub_resource type="BoxShape" id=1] + +[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 ) + +[sub_resource type="SphereShape" id=5] + +[node name="Test" type="Spatial"] +script = ExtResource( 2 ) + +[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="RigidBodyCapsule" 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/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"] +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="RigidBodyConvex" type="RigidBody" parent="Shapes"] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 3, -0.210678, 0 ) +mode = 3 + +[node name="CollisionShape" type="CollisionShape" parent="Shapes/RigidBodyConvex"] +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 ) + +[node name="CollisionShape" type="CollisionShape" parent="Shapes/StaticBodyHead"] +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 ) diff --git a/3d/physics_tests/tests/functional/test_stack.gd b/3d/physics_tests/tests/functional/test_stack.gd new file mode 100644 index 00000000..0af325c4 --- /dev/null +++ b/3d/physics_tests/tests/functional/test_stack.gd @@ -0,0 +1,53 @@ +extends Test + + +export(int, 1, 100) var height = 10 +export(int, 1, 100) var width = 1 +export(int, 1, 100) var depth = 1 +export(Vector3) var box_size = Vector3(1.0, 1.0, 1.0) +export(Vector3) var box_spacing = Vector3(0.0, 0.0, 0.0) + + +func _ready(): + _create_stack() + + +func _create_stack(): + var root_node = $Stack + + var template_shape = BoxShape.new() + template_shape.extents = 0.5 * box_size + + var template_collision = CollisionShape.new() + template_collision.shape = template_shape + + var template_body = RigidBody.new() + template_body.add_child(template_collision) + + var pos_y = 0.5 * box_size.y + box_spacing.y + + for level in height: + var row_node = Spatial.new() + row_node.transform.origin = Vector3(0.0, pos_y, 0.0) + row_node.name = "Row%02d" % (level + 1) + root_node.add_child(row_node) + + var pos_x = -0.5 * (width - 1) * (box_size.x + box_spacing.x) + + for box_index_x in width: + var pos_z = -0.5 * (depth - 1) * (box_size.z + box_spacing.z) + + for box_index_z in depth: + var box_index = box_index_x * box_index_z + var box = template_body.duplicate() + box.transform.origin = Vector3(pos_x, 0.0, pos_z) + box.name = "Box%02d" % (box_index + 1) + row_node.add_child(box) + + pos_z += box_size.z + box_spacing.z + + pos_x += box_size.x + box_spacing.x + + pos_y += box_size.y + box_spacing.y + + template_body.queue_free() diff --git a/3d/physics_tests/tests/functional/test_stack.tscn b/3d/physics_tests/tests/functional/test_stack.tscn new file mode 100644 index 00000000..8e6da324 --- /dev/null +++ b/3d/physics_tests/tests/functional/test_stack.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://tests/functional/test_stack.gd" type="Script" id=1] +[ext_resource path="res://tests/static_scene_plane.tscn" type="PackedScene" id=2] +[ext_resource path="res://utils/camera_orbit.gd" type="Script" id=4] + +[node name="Test" type="Spatial"] +script = ExtResource( 1 ) + +[node name="Stack" type="Spatial" parent="."] + +[node name="StaticBodyPlane" parent="." instance=ExtResource( 2 )] + +[node name="Camera" type="Camera" parent="."] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4.53602, 12.2684 ) +script = ExtResource( 4 ) diff --git a/3d/physics_tests/tests/performance/test_perf_broadphase.gd b/3d/physics_tests/tests/performance/test_perf_broadphase.gd new file mode 100644 index 00000000..0673d0e8 --- /dev/null +++ b/3d/physics_tests/tests/performance/test_perf_broadphase.gd @@ -0,0 +1,155 @@ +extends Test + + +const BOX_SIZE = Vector3(0.8, 0.8, 0.8) +const BOX_SPACE = Vector3(1.0, 1.0, 1.0) + +export(int, 1, 1000) var row_size = 20 +export(int, 1, 1000) var column_size = 20 +export(int, 1, 1000) var depth_size = 20 + +var _objects = [] + +var _log_physics = false +var _log_physics_time = 0 +var _log_physics_time_start = 0 + + +func _ready(): + _create_objects() + + _log_physics_start() + yield(wait_for_physics_ticks(5), "wait_done") + _log_physics_stop() + + yield(start_timer(1.0), "timeout") + if is_timer_canceled(): + return + + _add_objects() + + _log_physics_start() + yield(wait_for_physics_ticks(5), "wait_done") + _log_physics_stop() + + yield(start_timer(1.0), "timeout") + if is_timer_canceled(): + return + + _move_objects() + + _log_physics_start() + yield(wait_for_physics_ticks(5), "wait_done") + _log_physics_stop() + + yield(start_timer(1.0), "timeout") + if is_timer_canceled(): + return + + _remove_objects() + + _log_physics_start() + yield(wait_for_physics_ticks(5), "wait_done") + _log_physics_stop() + + yield(start_timer(1.0), "timeout") + if is_timer_canceled(): + return + + Log.print_log("* Done.") + + +func _exit_tree(): + for object in _objects: + object.free() + + +func _physics_process(_delta): + if _log_physics: + var time = OS.get_ticks_usec() + var time_delta = time - _log_physics_time + var time_total = time - _log_physics_time_start + _log_physics_time = time + Log.print_log(" Physics Tick: %.3f ms (total = %.3f ms)" % [0.001 * time_delta, 0.001 * time_total]) + + +func _log_physics_start(): + _log_physics = true + _log_physics_time_start = OS.get_ticks_usec() + _log_physics_time = _log_physics_time_start + + +func _log_physics_stop(): + _log_physics = false + + +func _create_objects(): + _objects.clear() + + var template_body = create_rigidbody_box(BOX_SIZE) + template_body.gravity_scale = 0.0 + + Log.print_log("* Creating objects...") + var timer = OS.get_ticks_usec() + + var pos_x = -0.5 * (row_size - 1) * BOX_SPACE.x + + for row in row_size: + var pos_y = -0.5 * (column_size - 1) * BOX_SPACE.y + + for column in column_size: + var pos_z = -0.5 * (depth_size - 1) * BOX_SPACE.z + + for depth in depth_size: + var box = template_body.duplicate() + box.transform.origin = Vector3(pos_x, pos_y, pos_z) + box.name = "Box%03d" % (row * column + 1) + _objects.push_back(box) + + pos_z += BOX_SPACE.z + + pos_y += BOX_SPACE.y + + pos_x += BOX_SPACE.x + + timer = OS.get_ticks_usec() - timer + Log.print_log(" Create Time: %.3f ms" % (0.001 * timer)) + + template_body.queue_free() + + +func _add_objects(): + var root_node = $Objects + + Log.print_log("* Adding objects...") + var timer = OS.get_ticks_usec() + + for object in _objects: + root_node.add_child(object) + + timer = OS.get_ticks_usec() - timer + Log.print_log(" Add Time: %.3f ms" % (0.001 * timer)) + + +func _move_objects(): + Log.print_log("* Moving objects...") + var timer = OS.get_ticks_usec() + + for object in _objects: + object.transform.origin += BOX_SPACE + + timer = OS.get_ticks_usec() - timer + Log.print_log(" Move Time: %.3f ms" % (0.001 * timer)) + + +func _remove_objects(): + var root_node = $Objects + + Log.print_log("* Removing objects...") + var timer = OS.get_ticks_usec() + + for object in _objects: + root_node.remove_child(object) + + timer = OS.get_ticks_usec() - timer + Log.print_log(" Remove Time: %.3f ms" % (0.001 * timer)) diff --git a/3d/physics_tests/tests/performance/test_perf_broadphase.tscn b/3d/physics_tests/tests/performance/test_perf_broadphase.tscn new file mode 100644 index 00000000..b9ca979c --- /dev/null +++ b/3d/physics_tests/tests/performance/test_perf_broadphase.tscn @@ -0,0 +1,13 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://tests/performance/test_perf_broadphase.gd" type="Script" id=1] +[ext_resource path="res://utils/camera_orbit.gd" type="Script" id=5] + +[node name="Test" type="Spatial"] +script = ExtResource( 1 ) + +[node name="Objects" type="Spatial" parent="."] + +[node name="Camera" type="Camera" parent="."] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 29.8407 ) +script = ExtResource( 5 ) diff --git a/3d/physics_tests/tests/performance/test_perf_contacts.gd b/3d/physics_tests/tests/performance/test_perf_contacts.gd index dbe5e221..ed5244f5 100644 --- a/3d/physics_tests/tests/performance/test_perf_contacts.gd +++ b/3d/physics_tests/tests/performance/test_perf_contacts.gd @@ -10,7 +10,7 @@ const OPTION_TYPE_SPHERE = "Shape type/Sphere" export(Array) var spawns = Array() export(int) var spawn_count = 100 -export(int, 1, 10) var spawn_multipiler = 5 +export(int, 1, 10) var spawn_multiplier = 5 var _object_templates = [] @@ -36,6 +36,11 @@ func _ready(): _start_all_types() +func _exit_tree(): + for object_template in _object_templates: + object_template.free() + + func _on_option_selected(option): cancel_timer() @@ -123,9 +128,10 @@ func _spawn_objects(type_index): Log.print_log("* Spawning: " + template_node.name) - for _index in range(spawn_multipiler): - for _node_index in spawn_count / spawn_multipiler: + for _index in range(spawn_multiplier): + for _node_index in spawn_count / spawn_multiplier: var node = template_node.duplicate() as Spatial + node.transform.origin = Vector3.ZERO spawn_parent.add_child(node) diff --git a/3d/physics_tests/tests/static_scene.tscn b/3d/physics_tests/tests/static_scene.tscn index cd668c31..3e20b2a0 100644 --- a/3d/physics_tests/tests/static_scene.tscn +++ b/3d/physics_tests/tests/static_scene.tscn @@ -1,25 +1,12 @@ -[gd_scene load_steps=5 format=2] +[gd_scene load_steps=4 format=2] [ext_resource path="res://assets/robot_head/godot3_robot_head_collision.tres" type="Shape" id=1] [ext_resource path="res://assets/robot_head/godot3_robot_head.mesh" type="ArrayMesh" id=2] - -[sub_resource type="PlaneMesh" id=1] - -[sub_resource type="ConcavePolygonShape" id=2] -data = PoolVector3Array( -1, 0, 1, 1, 0, -1, 1, 0, 1, -1, 0, 1, -1, 0, -1, 1, 0, -1 ) +[ext_resource path="res://tests/static_scene_plane.tscn" type="PackedScene" id=3] [node name="StaticScene" type="Spatial"] -[node name="StaticBodyPlane" type="StaticBody" parent="."] - -[node name="MeshInstance" type="MeshInstance" parent="StaticBodyPlane"] -transform = Transform( 50, 0, 0, 0, 1, 0, 0, 0, 50, 0, 0, 0 ) -mesh = SubResource( 1 ) -material/0 = null - -[node name="CollisionShape" type="CollisionShape" parent="StaticBodyPlane"] -transform = Transform( 50, 0, 0, 0, 1, 0, 0, 0, 50, 0, 0, 0 ) -shape = SubResource( 2 ) +[node name="StaticBodyPlane" parent="." instance=ExtResource( 3 )] [node name="StaticBodyHead" type="StaticBody" parent="."] transform = Transform( 10, 0, 0, 0, 8.66025, 5, 0, -5, 8.66025, 0, -11.1389, 2.29332 ) diff --git a/3d/physics_tests/tests/static_scene_plane.tscn b/3d/physics_tests/tests/static_scene_plane.tscn new file mode 100644 index 00000000..c0c35c98 --- /dev/null +++ b/3d/physics_tests/tests/static_scene_plane.tscn @@ -0,0 +1,17 @@ +[gd_scene load_steps=3 format=2] + +[sub_resource type="PlaneMesh" id=1] + +[sub_resource type="ConcavePolygonShape" id=2] +data = PoolVector3Array( -1, 0, 1, 1, 0, -1, 1, 0, 1, -1, 0, 1, -1, 0, -1, 1, 0, -1 ) + +[node name="StaticBodyPlane" type="StaticBody"] + +[node name="MeshInstance" type="MeshInstance" parent="."] +transform = Transform( 50, 0, 0, 0, 1, 0, 0, 0, 50, 0, 0, 0 ) +mesh = SubResource( 1 ) +material/0 = null + +[node name="CollisionShape" type="CollisionShape" parent="."] +transform = Transform( 50, 0, 0, 0, 1, 0, 0, 0, 50, 0, 0, 0 ) +shape = SubResource( 2 ) diff --git a/3d/physics_tests/utils/container_log.gd b/3d/physics_tests/utils/container_log.gd index 97d20ca1..2baff145 100644 --- a/3d/physics_tests/utils/container_log.gd +++ b/3d/physics_tests/utils/container_log.gd @@ -13,6 +13,10 @@ func _enter_tree(): remove_child(_entry_template) +func _exit_tree(): + _entry_template.free() + + func clear(): while get_child_count(): var entry = get_child(get_child_count() - 1)