mirror of
https://github.com/godotengine/godot-demo-projects.git
synced 2025-12-16 13:30:07 +01:00
Add demo: Physics Tests 2D
Similar to its 3D counterpart, with tests using 2D physics.
This commit is contained in:
18
2d/physics_tests/README.md
Normal file
18
2d/physics_tests/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# 2D Physics Tests
|
||||
|
||||
This demo contains a series of tests for the 2D
|
||||
physics engine.
|
||||
|
||||
They can be used for different purpose:
|
||||
- Functional tests to check for regressions and
|
||||
behavior of the 2D physics engine
|
||||
- Performance tests to evaluate performance
|
||||
of the 2D physics engine
|
||||
|
||||
Language: GDScript
|
||||
|
||||
Renderer: GLES 2
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||
BIN
2d/physics_tests/assets/godot-head.png
Normal file
BIN
2d/physics_tests/assets/godot-head.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.4 KiB |
34
2d/physics_tests/assets/godot-head.png.import
Normal file
34
2d/physics_tests/assets/godot-head.png.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/godot-head.png-cc6844293d74c4f45ec6c4ab08de67ee.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/godot-head.png"
|
||||
dest_files=[ "res://.import/godot-head.png-cc6844293d74c4f45ec6c4ab08de67ee.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
||||
BIN
2d/physics_tests/icon.png
Normal file
BIN
2d/physics_tests/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.3 KiB |
34
2d/physics_tests/icon.png.import
Normal file
34
2d/physics_tests/icon.png.import
Normal file
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.png"
|
||||
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
||||
174
2d/physics_tests/main.tscn
Normal file
174
2d/physics_tests/main.tscn
Normal file
@@ -0,0 +1,174 @@
|
||||
[gd_scene load_steps=10 format=2]
|
||||
|
||||
[ext_resource path="res://utils/label_fps.gd" type="Script" id=1]
|
||||
[ext_resource path="res://utils/label_version.gd" type="Script" id=2]
|
||||
[ext_resource path="res://utils/label_engine.gd" type="Script" id=3]
|
||||
[ext_resource path="res://tests_menu.gd" type="Script" id=4]
|
||||
[ext_resource path="res://utils/label_test.gd" type="Script" id=5]
|
||||
[ext_resource path="res://utils/container_log.gd" type="Script" id=10]
|
||||
[ext_resource path="res://utils/scroll_log.gd" type="Script" id=11]
|
||||
[ext_resource path="res://tests.gd" type="Script" id=12]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id=1]
|
||||
bg_color = Color( 0, 0, 0, 0.176471 )
|
||||
|
||||
[node name="Main" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
script = ExtResource( 12 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="TestsMenu" type="MenuButton" parent="."]
|
||||
margin_left = 10.0
|
||||
margin_top = 10.0
|
||||
margin_right = 125.0
|
||||
margin_bottom = 30.0
|
||||
text = "TESTS"
|
||||
flat = false
|
||||
script = ExtResource( 4 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="LabelControls" type="Label" parent="."]
|
||||
margin_left = 157.0
|
||||
margin_top = 13.0
|
||||
margin_right = 646.0
|
||||
margin_bottom = 27.0
|
||||
text = "R - RESTART / D - TOGGLE COLLISION / F - TOGGLE FULL SCREEN / ESC - QUIT"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="LabelFPS" type="Label" parent="."]
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 10.0
|
||||
margin_top = -19.0
|
||||
margin_right = 50.0
|
||||
margin_bottom = -5.0
|
||||
text = "FPS: 0"
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="LabelEngine" type="Label" parent="."]
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 10.0
|
||||
margin_top = -39.0
|
||||
margin_right = 50.0
|
||||
margin_bottom = -25.0
|
||||
text = "Physics engine:"
|
||||
script = ExtResource( 3 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="LabelVersion" type="Label" parent="."]
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 10.0
|
||||
margin_top = -59.0
|
||||
margin_right = 50.0
|
||||
margin_bottom = -45.0
|
||||
text = "Godot Version:"
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="LabelTest" type="Label" parent="."]
|
||||
anchor_top = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 10.0
|
||||
margin_top = -79.0
|
||||
margin_right = 50.0
|
||||
margin_bottom = -65.0
|
||||
text = "Test:"
|
||||
script = ExtResource( 5 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="PanelLog" type="Panel" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -428.0
|
||||
margin_top = -125.0
|
||||
custom_styles/panel = SubResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ButtonClear" type="Button" parent="PanelLog"]
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -48.0
|
||||
margin_top = -25.0
|
||||
margin_right = -5.0
|
||||
margin_bottom = -5.0
|
||||
focus_mode = 0
|
||||
enabled_focus_mode = 0
|
||||
text = "clear"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="CheckBoxScroll" type="CheckBox" parent="PanelLog"]
|
||||
anchor_left = 1.0
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -150.0
|
||||
margin_top = -27.0
|
||||
margin_right = -54.0
|
||||
margin_bottom = -3.0
|
||||
focus_mode = 0
|
||||
pressed = true
|
||||
enabled_focus_mode = 0
|
||||
text = "auto-scroll"
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ScrollLog" type="ScrollContainer" parent="PanelLog"]
|
||||
margin_left = 10.0
|
||||
margin_top = 5.0
|
||||
margin_right = 418.0
|
||||
margin_bottom = 94.0
|
||||
scroll_horizontal_enabled = false
|
||||
script = ExtResource( 11 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
auto_scroll = true
|
||||
|
||||
[node name="VBoxLog" type="VBoxContainer" parent="PanelLog/ScrollLog"]
|
||||
margin_right = 408.0
|
||||
margin_bottom = 89.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
alignment = 2
|
||||
script = ExtResource( 10 )
|
||||
|
||||
[node name="LabelLog" type="Label" parent="PanelLog/ScrollLog/VBoxLog"]
|
||||
margin_top = 75.0
|
||||
margin_right = 408.0
|
||||
margin_bottom = 89.0
|
||||
text = "Log start"
|
||||
valign = 2
|
||||
max_lines_visible = 5
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
[connection signal="pressed" from="PanelLog/ButtonClear" to="PanelLog/ScrollLog/VBoxLog" method="clear"]
|
||||
[connection signal="toggled" from="PanelLog/CheckBoxScroll" to="PanelLog/ScrollLog" method="set_auto_scroll"]
|
||||
75
2d/physics_tests/project.godot
Normal file
75
2d/physics_tests/project.godot
Normal file
@@ -0,0 +1,75 @@
|
||||
; Engine configuration file.
|
||||
; It's best edited using the editor UI and not directly,
|
||||
; since the parameters that go here are not all obvious.
|
||||
;
|
||||
; Format:
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=4
|
||||
|
||||
_global_script_classes=[ {
|
||||
"base": "MenuButton",
|
||||
"class": "OptionMenu",
|
||||
"language": "GDScript",
|
||||
"path": "res://utils/option_menu.gd"
|
||||
}, {
|
||||
"base": "Node2D",
|
||||
"class": "Test",
|
||||
"language": "GDScript",
|
||||
"path": "res://test.gd"
|
||||
} ]
|
||||
_global_script_class_icons={
|
||||
"OptionMenu": "",
|
||||
"Test": ""
|
||||
}
|
||||
|
||||
[application]
|
||||
|
||||
config/name="2D Physics Tests"
|
||||
run/main_scene="res://main.tscn"
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[autoload]
|
||||
|
||||
Log="*res://utils/system_log.gd"
|
||||
System="*res://utils/system.gd"
|
||||
|
||||
[debug]
|
||||
|
||||
gdscript/warnings/return_value_discarded=false
|
||||
|
||||
[display]
|
||||
|
||||
window/dpi/allow_hidpi=true
|
||||
window/stretch/mode="2d"
|
||||
window/stretch/aspect="expand"
|
||||
|
||||
[input]
|
||||
|
||||
toggle_full_screen={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":70,"unicode":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
exit={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777217,"unicode":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
toggle_debug_collision={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"unicode":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
restart_test={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":82,"unicode":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
[rendering]
|
||||
|
||||
quality/driver/driver_name="GLES2"
|
||||
environment/default_clear_color=Color( 0.184314, 0.184314, 0.184314, 1 )
|
||||
quality/filters/msaa=2
|
||||
0
2d/physics_tests/screenshots/.gdignore
Normal file
0
2d/physics_tests/screenshots/.gdignore
Normal file
BIN
2d/physics_tests/screenshots/screenshot.png
Normal file
BIN
2d/physics_tests/screenshots/screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 162 KiB |
92
2d/physics_tests/test.gd
Normal file
92
2d/physics_tests/test.gd
Normal file
@@ -0,0 +1,92 @@
|
||||
class_name Test
|
||||
extends Node2D
|
||||
|
||||
|
||||
signal wait_done()
|
||||
|
||||
var _timer
|
||||
var _timer_started = false
|
||||
|
||||
var _wait_physics_ticks_counter = 0
|
||||
|
||||
|
||||
class Line:
|
||||
var pos_start
|
||||
var pos_end
|
||||
var color
|
||||
|
||||
var _lines = []
|
||||
|
||||
|
||||
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 _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()
|
||||
|
||||
|
||||
func clear_lines():
|
||||
_lines.clear()
|
||||
update()
|
||||
|
||||
|
||||
func create_rigidbody_box(size):
|
||||
var template_shape = RectangleShape2D.new()
|
||||
template_shape.extents = 0.5 * size
|
||||
|
||||
var template_collision = CollisionShape2D.new()
|
||||
template_collision.shape = template_shape
|
||||
|
||||
var template_body = RigidBody2D.new()
|
||||
template_body.add_child(template_collision)
|
||||
|
||||
return template_body
|
||||
|
||||
|
||||
func start_timer(timeout):
|
||||
if _timer == null:
|
||||
_timer = Timer.new()
|
||||
_timer.one_shot = true
|
||||
add_child(_timer)
|
||||
_timer.connect("timeout", self, "_on_timer_done")
|
||||
else:
|
||||
cancel_timer()
|
||||
|
||||
_timer.start(timeout)
|
||||
_timer_started = true
|
||||
|
||||
return _timer
|
||||
|
||||
|
||||
func cancel_timer():
|
||||
if _timer_started:
|
||||
_timer.paused = true
|
||||
_timer.emit_signal("timeout")
|
||||
_timer.paused = false
|
||||
|
||||
|
||||
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
|
||||
35
2d/physics_tests/tests.gd
Normal file
35
2d/physics_tests/tests.gd
Normal file
@@ -0,0 +1,35 @@
|
||||
extends Node
|
||||
|
||||
|
||||
var _tests = [
|
||||
{
|
||||
"id": "Functional Tests/Shapes",
|
||||
"path": "res://tests/functional/test_shapes.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",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
func _ready():
|
||||
var test_menu = $TestsMenu
|
||||
for test in _tests:
|
||||
test_menu.add_test(test.id, test.path)
|
||||
10
2d/physics_tests/tests/dynamic_box.tscn
Normal file
10
2d/physics_tests/tests/dynamic_box.tscn
Normal file
@@ -0,0 +1,10 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id=1]
|
||||
extents = Vector2( 20, 20 )
|
||||
|
||||
[node name="StackBox" type="RigidBody2D"]
|
||||
position = Vector2( -180, -20 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
shape = SubResource( 1 )
|
||||
41
2d/physics_tests/tests/functional/test_pyramid.gd
Normal file
41
2d/physics_tests/tests/functional/test_pyramid.gd
Normal file
@@ -0,0 +1,41 @@
|
||||
extends Test
|
||||
|
||||
|
||||
export(int, 1, 100) var height = 10
|
||||
export(Vector2) var box_size = Vector2(40.0, 40.0)
|
||||
export(Vector2) var box_spacing = Vector2(0.0, 0.0)
|
||||
|
||||
|
||||
func _ready():
|
||||
_create_pyramid()
|
||||
|
||||
|
||||
func _create_pyramid():
|
||||
var root_node = $Pyramid
|
||||
|
||||
var template_body = create_rigidbody_box(box_size)
|
||||
|
||||
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 row_node = Node2D.new()
|
||||
row_node.position = Vector2(0.0, pos_y)
|
||||
row_node.name = "Row%02d" % (level + 1)
|
||||
root_node.add_child(row_node)
|
||||
|
||||
var pos_x = -0.5 * (num_boxes - 1) * (box_size.x + box_spacing.x)
|
||||
|
||||
for box_index in num_boxes:
|
||||
var box = template_body.duplicate()
|
||||
box.position = Vector2(pos_x, 0.0)
|
||||
box.name = "Box%02d" % (box_index + 1)
|
||||
row_node.add_child(box)
|
||||
|
||||
pos_x += box_size.x + box_spacing.x
|
||||
|
||||
pos_y -= box_size.y + box_spacing.y
|
||||
|
||||
template_body.queue_free()
|
||||
12
2d/physics_tests/tests/functional/test_pyramid.tscn
Normal file
12
2d/physics_tests/tests/functional/test_pyramid.tscn
Normal file
@@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://tests/functional/test_pyramid.gd" type="Script" id=1]
|
||||
[ext_resource path="res://tests/static_scene_flat.tscn" type="PackedScene" id=2]
|
||||
|
||||
[node name="Test" type="Node2D"]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Pyramid" type="Node2D" parent="."]
|
||||
position = Vector2( 512, 500 )
|
||||
|
||||
[node name="StaticSceneFlat" parent="." instance=ExtResource( 2 )]
|
||||
69
2d/physics_tests/tests/functional/test_raycasting.gd
Normal file
69
2d/physics_tests/tests/functional/test_raycasting.gd
Normal file
@@ -0,0 +1,69 @@
|
||||
extends Test
|
||||
|
||||
|
||||
var _do_raycasts = false
|
||||
|
||||
|
||||
func _ready():
|
||||
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...")
|
||||
|
||||
clear_lines()
|
||||
|
||||
for shape in $Shapes.get_children():
|
||||
var body = shape as PhysicsBody2D
|
||||
var space_state = body.get_world_2d().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 - Vector2(0, 100), center)
|
||||
Log.print_log("Raycast in: %s" % ("HIT" if res else "NO HIT"))
|
||||
|
||||
# Raycast exiting from inside.
|
||||
center.x -= 20
|
||||
res = _add_raycast(space_state, center, center + Vector2(0, 200))
|
||||
Log.print_log("Raycast out: %s" % ("HIT" if res else "NO HIT"))
|
||||
|
||||
# Raycast all inside.
|
||||
center.x += 40
|
||||
res = _add_raycast(space_state, center, center + Vector2(0, 40))
|
||||
Log.print_log("Raycast inside: %s" % ("HIT" if res else "NO HIT"))
|
||||
|
||||
if body.name.ends_with("ConcavePolygon"):
|
||||
# Raycast inside an internal face.
|
||||
center.x += 20
|
||||
res = _add_raycast(space_state, center, center + Vector2(0, 40))
|
||||
Log.print_log("Raycast inside face: %s" % ("HIT" if res else "NO HIT"))
|
||||
|
||||
|
||||
func _add_raycast(space_state, pos_start, pos_end):
|
||||
var result = space_state.intersect_ray(pos_start, pos_end)
|
||||
var color
|
||||
if result:
|
||||
color = Color.green
|
||||
else:
|
||||
color = Color.red.darkened(0.5)
|
||||
|
||||
# Draw raycast line.
|
||||
add_line(pos_start, pos_end, color)
|
||||
|
||||
# Draw raycast arrow.
|
||||
add_line(pos_end, pos_end + Vector2(-5, -10), color)
|
||||
add_line(pos_end, pos_end + Vector2(5, -10), color)
|
||||
|
||||
return result
|
||||
68
2d/physics_tests/tests/functional/test_raycasting.tscn
Normal file
68
2d/physics_tests/tests/functional/test_raycasting.tscn
Normal file
@@ -0,0 +1,68 @@
|
||||
[gd_scene load_steps=6 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]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id=1]
|
||||
extents = Vector2( 40, 60 )
|
||||
|
||||
[sub_resource type="CapsuleShape2D" id=2]
|
||||
radius = 30.0
|
||||
height = 50.0
|
||||
|
||||
[sub_resource type="CircleShape2D" id=3]
|
||||
radius = 60.0
|
||||
|
||||
[node name="Test" type="Node2D"]
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[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 = 3
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodyRectangle"]
|
||||
rotation = -1.19206
|
||||
scale = Vector2( 1.5, 1.5 )
|
||||
shape = SubResource( 1 )
|
||||
|
||||
[node name="RigidBodyCapsule" type="RigidBody2D" parent="Shapes"]
|
||||
position = Vector2( 313.583, 261.204 )
|
||||
mode = 3
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodyCapsule"]
|
||||
rotation = -0.202458
|
||||
scale = Vector2( 1.5, 1.5 )
|
||||
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
|
||||
|
||||
[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="RigidBodySphere" type="RigidBody2D" parent="Shapes"]
|
||||
position = Vector2( 917.136, 270.868 )
|
||||
mode = 3
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Shapes/RigidBodySphere"]
|
||||
shape = SubResource( 3 )
|
||||
64
2d/physics_tests/tests/functional/test_shapes.tscn
Normal file
64
2d/physics_tests/tests/functional/test_shapes.tscn
Normal file
@@ -0,0 +1,64 @@
|
||||
[gd_scene load_steps=7 format=2]
|
||||
|
||||
[ext_resource path="res://assets/godot-head.png" type="Texture" id=1]
|
||||
[ext_resource path="res://test.gd" type="Script" id=2]
|
||||
[ext_resource path="res://tests/static_scene.tscn" type="PackedScene" id=6]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id=1]
|
||||
extents = Vector2( 20, 30 )
|
||||
|
||||
[sub_resource type="CapsuleShape2D" id=2]
|
||||
radius = 20.0
|
||||
height = 30.0
|
||||
|
||||
[sub_resource type="CircleShape2D" id=3]
|
||||
radius = 30.0
|
||||
|
||||
[node name="Test" type="Node2D"]
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[node name="DynamicShapes" type="Node2D" parent="."]
|
||||
|
||||
[node name="RigidBodyRectangle" type="RigidBody2D" parent="DynamicShapes"]
|
||||
position = Vector2( 96, 127 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="DynamicShapes/RigidBodyRectangle"]
|
||||
rotation = 0.675442
|
||||
shape = SubResource( 1 )
|
||||
|
||||
[node name="RigidBodyCapsule" type="RigidBody2D" parent="DynamicShapes"]
|
||||
position = Vector2( 270.165, 139.444 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="DynamicShapes/RigidBodyCapsule"]
|
||||
rotation = -0.202458
|
||||
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"]
|
||||
scale = Vector2( 0.5, 0.5 )
|
||||
texture = ExtResource( 1 )
|
||||
|
||||
[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="RigidBodySphere" type="RigidBody2D" parent="DynamicShapes"]
|
||||
position = Vector2( 919.968, 115.129 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="DynamicShapes/RigidBodySphere"]
|
||||
shape = SubResource( 3 )
|
||||
|
||||
[node name="StaticScene" parent="." instance=ExtResource( 6 )]
|
||||
39
2d/physics_tests/tests/functional/test_stack.gd
Normal file
39
2d/physics_tests/tests/functional/test_stack.gd
Normal file
@@ -0,0 +1,39 @@
|
||||
extends Test
|
||||
|
||||
|
||||
export(int) var height = 10
|
||||
export(int) var width = 1
|
||||
export(Vector2) var box_size = Vector2(40.0, 40.0)
|
||||
export(Vector2) var box_spacing = Vector2(0.0, 0.0)
|
||||
|
||||
|
||||
func _ready():
|
||||
_create_stack()
|
||||
|
||||
|
||||
func _create_stack():
|
||||
var root_node = $Stack
|
||||
|
||||
var template_body = create_rigidbody_box(box_size)
|
||||
|
||||
var pos_y = -0.5 * box_size.y - box_spacing.y
|
||||
|
||||
for level in height:
|
||||
var row_node = Node2D.new()
|
||||
row_node.position = Vector2(0.0, pos_y)
|
||||
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 in width:
|
||||
var box = template_body.duplicate()
|
||||
box.position = Vector2(pos_x, 0.0)
|
||||
box.name = "Box%02d" % (box_index + 1)
|
||||
row_node.add_child(box)
|
||||
|
||||
pos_x += box_size.x + box_spacing.x
|
||||
|
||||
pos_y -= box_size.y + box_spacing.y
|
||||
|
||||
template_body.queue_free()
|
||||
12
2d/physics_tests/tests/functional/test_stack.tscn
Normal file
12
2d/physics_tests/tests/functional/test_stack.tscn
Normal file
@@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://tests/functional/test_stack.gd" type="Script" id=1]
|
||||
[ext_resource path="res://tests/static_scene_flat.tscn" type="PackedScene" id=2]
|
||||
|
||||
[node name="Test" type="Node2D"]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Stack" type="Node2D" parent="."]
|
||||
position = Vector2( 512, 500 )
|
||||
|
||||
[node name="StaticSceneFlat" parent="." instance=ExtResource( 2 )]
|
||||
149
2d/physics_tests/tests/performance/test_perf_broadphase.gd
Normal file
149
2d/physics_tests/tests/performance/test_perf_broadphase.gd
Normal file
@@ -0,0 +1,149 @@
|
||||
extends Test
|
||||
|
||||
|
||||
const BOX_SIZE = Vector2(40, 40)
|
||||
const BOX_SPACE = Vector2(50, 50)
|
||||
|
||||
export(int, 1, 1000) var row_size = 100
|
||||
export(int, 1, 1000) var column_size = 100
|
||||
|
||||
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 box = template_body.duplicate()
|
||||
box.position = Vector2(pos_x, pos_y)
|
||||
box.name = "Box%03d" % (row * column + 1)
|
||||
_objects.push_back(box)
|
||||
|
||||
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.position += 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))
|
||||
@@ -0,0 +1,9 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://tests/performance/test_perf_broadphase.gd" type="Script" id=1]
|
||||
|
||||
[node name="Test" type="Node2D"]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Objects" type="Node2D" parent="."]
|
||||
position = Vector2( 512, 300 )
|
||||
161
2d/physics_tests/tests/performance/test_perf_contacts.gd
Normal file
161
2d/physics_tests/tests/performance/test_perf_contacts.gd
Normal file
@@ -0,0 +1,161 @@
|
||||
extends Test
|
||||
|
||||
|
||||
const OPTION_TYPE_ALL = "Shape type/All"
|
||||
const OPTION_TYPE_RECTANGLE = "Shape type/Rectangle"
|
||||
const OPTION_TYPE_SPHERE = "Shape type/Sphere"
|
||||
const OPTION_TYPE_CAPSULE = "Shape type/Capsule"
|
||||
const OPTION_TYPE_CONVEX_POLYGON = "Shape type/Convex Polygon"
|
||||
const OPTION_TYPE_CONCAVE_POLYGON = "Shape type/Concave Polygon"
|
||||
export(Array) var spawns = Array()
|
||||
|
||||
export(int) var spawn_count = 100
|
||||
export(int, 1, 10) var spawn_multiplier = 5
|
||||
|
||||
var _object_templates = []
|
||||
|
||||
|
||||
func _ready():
|
||||
yield(start_timer(0.5), "timeout")
|
||||
if is_timer_canceled():
|
||||
return
|
||||
|
||||
while $DynamicShapes.get_child_count():
|
||||
var type_node = $DynamicShapes.get_child(0)
|
||||
type_node.position = Vector2.ZERO
|
||||
_object_templates.push_back(type_node)
|
||||
$DynamicShapes.remove_child(type_node)
|
||||
|
||||
$Options.add_menu_item(OPTION_TYPE_ALL)
|
||||
$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_POLYGON)
|
||||
$Options.connect("option_selected", self, "_on_option_selected")
|
||||
|
||||
_start_all_types()
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
for object_template in _object_templates:
|
||||
object_template.free()
|
||||
|
||||
|
||||
func _on_option_selected(option):
|
||||
cancel_timer()
|
||||
|
||||
_despawn_objects()
|
||||
|
||||
match option:
|
||||
OPTION_TYPE_ALL:
|
||||
_start_all_types()
|
||||
OPTION_TYPE_RECTANGLE:
|
||||
_start_type(_find_type_index("Rectangle"))
|
||||
OPTION_TYPE_SPHERE:
|
||||
_start_type(_find_type_index("Sphere"))
|
||||
OPTION_TYPE_CAPSULE:
|
||||
_start_type(_find_type_index("Capsule"))
|
||||
OPTION_TYPE_CONVEX_POLYGON:
|
||||
_start_type(_find_type_index("ConvexPolygon"))
|
||||
OPTION_TYPE_CONCAVE_POLYGON:
|
||||
_start_type(_find_type_index("ConcavePolygon"))
|
||||
|
||||
|
||||
func _find_type_index(type_name):
|
||||
for type_index in _object_templates.size():
|
||||
var type_node = _object_templates[type_index]
|
||||
if type_node.name.find(type_name) > -1:
|
||||
return type_index
|
||||
|
||||
Log.print_error("Invalid shape type: " + type_name)
|
||||
return -1
|
||||
|
||||
|
||||
func _start_type(type_index):
|
||||
if type_index < 0:
|
||||
return
|
||||
if type_index >= _object_templates.size():
|
||||
return
|
||||
|
||||
yield(start_timer(1.0), "timeout")
|
||||
if is_timer_canceled():
|
||||
return
|
||||
|
||||
_spawn_objects(type_index)
|
||||
|
||||
yield(start_timer(1.0), "timeout")
|
||||
if is_timer_canceled():
|
||||
return
|
||||
|
||||
_activate_objects()
|
||||
|
||||
yield(start_timer(5.0), "timeout")
|
||||
if is_timer_canceled():
|
||||
return
|
||||
|
||||
_despawn_objects()
|
||||
|
||||
Log.print_log("* Done.")
|
||||
|
||||
|
||||
func _start_all_types():
|
||||
for type_index in _object_templates.size():
|
||||
yield(start_timer(1.0), "timeout")
|
||||
if is_timer_canceled():
|
||||
return
|
||||
|
||||
_spawn_objects(type_index)
|
||||
|
||||
yield(start_timer(1.0), "timeout")
|
||||
if is_timer_canceled():
|
||||
return
|
||||
|
||||
_activate_objects()
|
||||
|
||||
yield(start_timer(5.0), "timeout")
|
||||
if is_timer_canceled():
|
||||
return
|
||||
|
||||
_despawn_objects()
|
||||
|
||||
Log.print_log("* Done.")
|
||||
|
||||
|
||||
func _spawn_objects(type_index):
|
||||
var template_node = _object_templates[type_index]
|
||||
for spawn in spawns:
|
||||
var spawn_parent = get_node(spawn)
|
||||
|
||||
Log.print_log("* Spawning: " + template_node.name)
|
||||
|
||||
for _index in range(spawn_multiplier):
|
||||
for _node_index in spawn_count / spawn_multiplier:
|
||||
var node = template_node.duplicate() as Node2D
|
||||
spawn_parent.add_child(node)
|
||||
|
||||
|
||||
func _activate_objects():
|
||||
var spawn_parent = $SpawnTarget1
|
||||
|
||||
Log.print_log("* Activating")
|
||||
|
||||
for node_index in spawn_parent.get_child_count():
|
||||
var node = spawn_parent.get_child(node_index) as RigidBody2D
|
||||
node.set_sleeping(false)
|
||||
|
||||
|
||||
func _despawn_objects():
|
||||
for spawn in spawns:
|
||||
var spawn_parent = get_node(spawn)
|
||||
|
||||
if spawn_parent.get_child_count() == 0:
|
||||
return
|
||||
|
||||
Log.print_log("* Despawning")
|
||||
|
||||
while spawn_parent.get_child_count():
|
||||
var node_index = spawn_parent.get_child_count() - 1
|
||||
var node = spawn_parent.get_child(node_index)
|
||||
spawn_parent.remove_child(node)
|
||||
node.queue_free()
|
||||
70
2d/physics_tests/tests/performance/test_perf_contacts.tscn
Normal file
70
2d/physics_tests/tests/performance/test_perf_contacts.tscn
Normal file
@@ -0,0 +1,70 @@
|
||||
[gd_scene load_steps=8 format=2]
|
||||
|
||||
[ext_resource path="res://tests/static_scene.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://tests/performance/test_perf_contacts.gd" type="Script" id=2]
|
||||
[ext_resource path="res://assets/godot-head.png" type="Texture" id=3]
|
||||
[ext_resource path="res://tests/test_options.tscn" type="PackedScene" id=4]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id=1]
|
||||
extents = Vector2( 20, 30 )
|
||||
|
||||
[sub_resource type="CircleShape2D" id=2]
|
||||
radius = 30.0
|
||||
|
||||
[sub_resource type="CapsuleShape2D" id=3]
|
||||
radius = 20.0
|
||||
height = 30.0
|
||||
|
||||
[node name="Test" type="Node2D"]
|
||||
script = ExtResource( 2 )
|
||||
spawns = [ NodePath("SpawnTarget1") ]
|
||||
|
||||
[node name="Options" parent="." instance=ExtResource( 4 )]
|
||||
|
||||
[node name="SpawnTarget1" type="Node2D" parent="."]
|
||||
position = Vector2( 512, 400 )
|
||||
|
||||
[node name="StaticScene" parent="." instance=ExtResource( 1 )]
|
||||
position = Vector2( 0, 125.017 )
|
||||
|
||||
[node name="DynamicShapes" type="Node2D" parent="."]
|
||||
|
||||
[node name="RigidBodyRectangle" type="RigidBody2D" parent="DynamicShapes"]
|
||||
position = Vector2( 0, 1024 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="DynamicShapes/RigidBodyRectangle"]
|
||||
shape = SubResource( 1 )
|
||||
|
||||
[node name="RigidBodySphere" type="RigidBody2D" parent="DynamicShapes"]
|
||||
position = Vector2( 100, 1024 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="DynamicShapes/RigidBodySphere"]
|
||||
shape = SubResource( 2 )
|
||||
|
||||
[node name="RigidBodyCapsule" type="RigidBody2D" parent="DynamicShapes"]
|
||||
position = Vector2( 200, 1024 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="DynamicShapes/RigidBodyCapsule"]
|
||||
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"]
|
||||
scale = Vector2( 0.5, 0.5 )
|
||||
texture = ExtResource( 3 )
|
||||
|
||||
[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 )
|
||||
10
2d/physics_tests/tests/static_scene.tscn
Normal file
10
2d/physics_tests/tests/static_scene.tscn
Normal file
@@ -0,0 +1,10 @@
|
||||
[gd_scene format=2]
|
||||
|
||||
[node name="StaticScene" type="Node2D"]
|
||||
|
||||
[node name="StaticBodyPolygon" type="StaticBody2D" parent="."]
|
||||
position = Vector2( -7.85718, 399.596 )
|
||||
|
||||
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="StaticBodyPolygon"]
|
||||
build_mode = 1
|
||||
polygon = PoolVector2Array( 16.3331, -129.432, 154.006, -20.0078, 292.354, 30.3943, 447.054, 33.9161, 584.899, -14.7955, 751.156, -15.5179, 894.098, -65.4518, 1000.73, -209.127, 1037.77, -398.823, 1029.92, 253.327, 6.2309, 261.185, 7.35339, -398.823 )
|
||||
12
2d/physics_tests/tests/static_scene_flat.tscn
Normal file
12
2d/physics_tests/tests/static_scene_flat.tscn
Normal file
@@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id=1]
|
||||
extents = Vector2( 512, 50 )
|
||||
|
||||
[node name="StaticSceneFlat" type="Node2D"]
|
||||
|
||||
[node name="StaticBodyPolygon" type="StaticBody2D" parent="."]
|
||||
position = Vector2( 512, 550 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="StaticBodyPolygon"]
|
||||
shape = SubResource( 1 )
|
||||
16
2d/physics_tests/tests/test_options.tscn
Normal file
16
2d/physics_tests/tests/test_options.tscn
Normal file
@@ -0,0 +1,16 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://utils/option_menu.gd" type="Script" id=1]
|
||||
|
||||
[node name="Options" type="MenuButton"]
|
||||
margin_left = 10.0
|
||||
margin_top = 106.719
|
||||
margin_right = 125.0
|
||||
margin_bottom = 126.719
|
||||
text = "TEST OPTIONS"
|
||||
flat = false
|
||||
align = 0
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
54
2d/physics_tests/tests_menu.gd
Normal file
54
2d/physics_tests/tests_menu.gd
Normal file
@@ -0,0 +1,54 @@
|
||||
extends OptionMenu
|
||||
|
||||
|
||||
class TestData:
|
||||
var id
|
||||
var scene_path
|
||||
|
||||
|
||||
var _test_list = []
|
||||
|
||||
var _current_test = null
|
||||
var _current_test_scene = null
|
||||
|
||||
|
||||
func _ready():
|
||||
connect("option_selected", self, "_on_option_selected")
|
||||
|
||||
|
||||
func _process(_delta):
|
||||
if Input.is_action_just_pressed("restart_test"):
|
||||
if _current_test:
|
||||
_start_test(_current_test)
|
||||
|
||||
|
||||
func add_test(id, scene_path):
|
||||
var test_data = TestData.new()
|
||||
test_data.id = id
|
||||
test_data.scene_path = scene_path
|
||||
_test_list.append(test_data)
|
||||
|
||||
add_menu_item(id)
|
||||
|
||||
|
||||
func _on_option_selected(item_path):
|
||||
for test in _test_list:
|
||||
if test.id == item_path:
|
||||
_start_test(test)
|
||||
|
||||
|
||||
func _start_test(test):
|
||||
_current_test = test
|
||||
|
||||
if _current_test_scene:
|
||||
_current_test_scene.queue_free()
|
||||
_current_test_scene = null
|
||||
|
||||
Log.print_log("*** STARTING TEST: " + test.id)
|
||||
var scene = load(test.scene_path)
|
||||
_current_test_scene = scene.instance()
|
||||
get_tree().root.add_child(_current_test_scene)
|
||||
get_tree().root.move_child(_current_test_scene, 0)
|
||||
|
||||
var label_test = get_node("../LabelTest")
|
||||
label_test.test_name = test.id
|
||||
41
2d/physics_tests/utils/container_log.gd
Normal file
41
2d/physics_tests/utils/container_log.gd
Normal file
@@ -0,0 +1,41 @@
|
||||
extends Control
|
||||
|
||||
|
||||
const MAX_ENTRIES = 100
|
||||
|
||||
var _entry_template
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
Log.connect("entry_logged", self, "_on_log_entry")
|
||||
|
||||
_entry_template = get_child(0) as Label
|
||||
remove_child(_entry_template)
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
_entry_template.free()
|
||||
|
||||
|
||||
func clear():
|
||||
while get_child_count():
|
||||
var entry = get_child(get_child_count() - 1)
|
||||
remove_child(entry)
|
||||
entry.queue_free()
|
||||
|
||||
|
||||
func _on_log_entry(message, type):
|
||||
var new_entry = _entry_template.duplicate() as Label
|
||||
|
||||
new_entry.set_text(message)
|
||||
if type == Log.LogType.ERROR:
|
||||
new_entry.modulate = Color.red
|
||||
else:
|
||||
new_entry.modulate = Color.white
|
||||
|
||||
if get_child_count() >= MAX_ENTRIES:
|
||||
var first_entry = get_child(0) as Label
|
||||
remove_child(first_entry)
|
||||
first_entry.queue_free()
|
||||
|
||||
add_child(new_entry)
|
||||
12
2d/physics_tests/utils/label_engine.gd
Normal file
12
2d/physics_tests/utils/label_engine.gd
Normal file
@@ -0,0 +1,12 @@
|
||||
extends Label
|
||||
|
||||
|
||||
func _process(_delta):
|
||||
var engine_name = ""
|
||||
match System.get_physics_engine():
|
||||
System.PhysicsEngine.GODOT_PHYSICS:
|
||||
engine_name = "Godot Physics"
|
||||
System.PhysicsEngine.OTHER:
|
||||
var engine_setting = ProjectSettings.get_setting("physics/2d/physics_engine")
|
||||
engine_name = "Other (%s)" % engine_setting
|
||||
set_text("Physics engine: %s" % engine_name)
|
||||
5
2d/physics_tests/utils/label_fps.gd
Normal file
5
2d/physics_tests/utils/label_fps.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends Label
|
||||
|
||||
|
||||
func _process(_delta):
|
||||
set_text("FPS: %d" % Engine.get_frames_per_second())
|
||||
13
2d/physics_tests/utils/label_test.gd
Normal file
13
2d/physics_tests/utils/label_test.gd
Normal file
@@ -0,0 +1,13 @@
|
||||
extends Label
|
||||
|
||||
|
||||
var test_name setget _set_test_name
|
||||
|
||||
|
||||
func _ready():
|
||||
set_text("Select a test from the menu to start it")
|
||||
|
||||
|
||||
func _set_test_name(value):
|
||||
test_name = value
|
||||
set_text("Test: %s" % test_name)
|
||||
5
2d/physics_tests/utils/label_version.gd
Normal file
5
2d/physics_tests/utils/label_version.gd
Normal file
@@ -0,0 +1,5 @@
|
||||
extends Label
|
||||
|
||||
|
||||
func _process(_delta):
|
||||
set_text("Godot Version: %s" % Engine.get_version_info().string)
|
||||
47
2d/physics_tests/utils/option_menu.gd
Normal file
47
2d/physics_tests/utils/option_menu.gd
Normal file
@@ -0,0 +1,47 @@
|
||||
class_name OptionMenu
|
||||
extends MenuButton
|
||||
|
||||
|
||||
signal option_selected(item_path)
|
||||
|
||||
|
||||
func add_menu_item(item_path):
|
||||
var path_elements = item_path.split("/", false)
|
||||
var path_element_count = path_elements.size()
|
||||
assert(path_element_count > 0)
|
||||
|
||||
var path = ""
|
||||
var popup = get_popup()
|
||||
for element_index in path_element_count - 1:
|
||||
var popup_label = path_elements[element_index]
|
||||
path += popup_label + "/"
|
||||
popup = _add_popup(popup, path, popup_label)
|
||||
|
||||
_add_item(popup, path_elements[path_element_count - 1])
|
||||
|
||||
|
||||
func _add_item(parent_popup, label):
|
||||
parent_popup.add_item(label)
|
||||
|
||||
|
||||
func _add_popup(parent_popup, path, label):
|
||||
if parent_popup.has_node(label):
|
||||
var popup_node = parent_popup.get_node(label)
|
||||
var popup_menu = popup_node as PopupMenu
|
||||
assert(popup_menu)
|
||||
return popup_menu
|
||||
|
||||
var popup_menu = PopupMenu.new()
|
||||
popup_menu.name = label
|
||||
|
||||
parent_popup.add_child(popup_menu)
|
||||
parent_popup.add_submenu_item(label, label)
|
||||
|
||||
popup_menu.connect("index_pressed", self, "_on_item_pressed", [popup_menu, path])
|
||||
|
||||
return popup_menu
|
||||
|
||||
|
||||
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)
|
||||
14
2d/physics_tests/utils/scroll_log.gd
Normal file
14
2d/physics_tests/utils/scroll_log.gd
Normal file
@@ -0,0 +1,14 @@
|
||||
extends ScrollContainer
|
||||
|
||||
|
||||
export(bool) var auto_scroll = false setget set_auto_scroll
|
||||
|
||||
|
||||
func _process(_delta):
|
||||
if auto_scroll:
|
||||
var scrollbar = get_v_scrollbar()
|
||||
scrollbar.value = scrollbar.max_value
|
||||
|
||||
|
||||
func set_auto_scroll(value):
|
||||
auto_scroll = value
|
||||
50
2d/physics_tests/utils/system.gd
Normal file
50
2d/physics_tests/utils/system.gd
Normal file
@@ -0,0 +1,50 @@
|
||||
extends Node
|
||||
|
||||
|
||||
enum PhysicsEngine {
|
||||
GODOT_PHYSICS,
|
||||
OTHER,
|
||||
}
|
||||
|
||||
var _engine = PhysicsEngine.OTHER
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
get_tree().debug_collisions_hint = true
|
||||
|
||||
var engine_string = ProjectSettings.get_setting("physics/2d/physics_engine")
|
||||
match engine_string:
|
||||
"DEFAULT":
|
||||
_engine = PhysicsEngine.GODOT_PHYSICS
|
||||
"GodotPhysics":
|
||||
_engine = PhysicsEngine.GODOT_PHYSICS
|
||||
_:
|
||||
_engine = PhysicsEngine.OTHER
|
||||
|
||||
|
||||
func _process(_delta):
|
||||
if Input.is_action_just_pressed("toggle_full_screen"):
|
||||
OS.window_fullscreen = not OS.window_fullscreen
|
||||
|
||||
if Input.is_action_just_pressed("toggle_debug_collision"):
|
||||
var debug_collision_enabled = not _is_debug_collision_enabled()
|
||||
_set_debug_collision_enabled(debug_collision_enabled)
|
||||
if debug_collision_enabled:
|
||||
Log.print_log("Debug Collision ON")
|
||||
else:
|
||||
Log.print_log("Debug Collision OFF")
|
||||
|
||||
if Input.is_action_just_pressed("exit"):
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
func get_physics_engine():
|
||||
return _engine
|
||||
|
||||
|
||||
func _set_debug_collision_enabled(enabled):
|
||||
get_tree().debug_collisions_hint = enabled
|
||||
|
||||
|
||||
func _is_debug_collision_enabled():
|
||||
return get_tree().debug_collisions_hint
|
||||
20
2d/physics_tests/utils/system_log.gd
Normal file
20
2d/physics_tests/utils/system_log.gd
Normal file
@@ -0,0 +1,20 @@
|
||||
extends Node
|
||||
|
||||
|
||||
enum LogType {
|
||||
LOG,
|
||||
ERROR,
|
||||
}
|
||||
|
||||
signal entry_logged(message, type)
|
||||
|
||||
|
||||
func print_log(message):
|
||||
print(message)
|
||||
emit_signal("entry_logged", message, LogType.LOG)
|
||||
|
||||
|
||||
func print_error(message):
|
||||
push_error(message)
|
||||
printerr(message)
|
||||
emit_signal("entry_logged", message, LogType.ERROR)
|
||||
Reference in New Issue
Block a user