test_perf_contacts.gd 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. extends Test
  2. const OPTION_TYPE_ALL = "Shape type/All"
  3. const OPTION_TYPE_RECTANGLE = "Shape type/Rectangle"
  4. const OPTION_TYPE_SPHERE = "Shape type/Sphere"
  5. const OPTION_TYPE_CAPSULE = "Shape type/Capsule"
  6. const OPTION_TYPE_CONVEX_POLYGON = "Shape type/Convex Polygon"
  7. const OPTION_TYPE_CONCAVE_POLYGON = "Shape type/Concave Polygon"
  8. @export var spawns = []
  9. @export var spawn_count = 100
  10. @export var spawn_randomize = Vector2.ZERO
  11. @onready var options = $Options
  12. var _object_templates = []
  13. var _log_physics = false
  14. var _log_physics_time = 0
  15. var _log_physics_time_start = 0
  16. func _ready():
  17. await start_timer(0.5).timeout
  18. if is_timer_canceled():
  19. return
  20. var dynamic_shapes = $DynamicShapes
  21. while dynamic_shapes.get_child_count():
  22. var type_node = dynamic_shapes.get_child(0)
  23. type_node.position = Vector2.ZERO
  24. _object_templates.push_back(type_node)
  25. dynamic_shapes.remove_child(type_node)
  26. options.add_menu_item(OPTION_TYPE_ALL)
  27. options.add_menu_item(OPTION_TYPE_RECTANGLE)
  28. options.add_menu_item(OPTION_TYPE_SPHERE)
  29. options.add_menu_item(OPTION_TYPE_CAPSULE)
  30. options.add_menu_item(OPTION_TYPE_CONVEX_POLYGON)
  31. options.add_menu_item(OPTION_TYPE_CONCAVE_POLYGON)
  32. options.option_selected.connect(self._on_option_selected)
  33. await _start_all_types()
  34. func _physics_process(delta):
  35. super._physics_process(delta)
  36. if _log_physics:
  37. var time = Time.get_ticks_usec()
  38. var time_delta = time - _log_physics_time
  39. var time_total = time - _log_physics_time_start
  40. _log_physics_time = time
  41. Log.print_log(" Physics Tick: %.3f ms (total = %.3f ms)" % [0.001 * time_delta, 0.001 * time_total])
  42. func _log_physics_start():
  43. _log_physics = true
  44. _log_physics_time_start = Time.get_ticks_usec()
  45. _log_physics_time = _log_physics_time_start
  46. func _log_physics_stop():
  47. _log_physics = false
  48. func _exit_tree():
  49. for object_template in _object_templates:
  50. object_template.free()
  51. func _on_option_selected(option):
  52. cancel_timer()
  53. _despawn_objects()
  54. match option:
  55. OPTION_TYPE_ALL:
  56. await _start_all_types()
  57. OPTION_TYPE_RECTANGLE:
  58. await _start_type(_find_type_index("Rectangle"))
  59. OPTION_TYPE_SPHERE:
  60. await _start_type(_find_type_index("Sphere"))
  61. OPTION_TYPE_CAPSULE:
  62. await _start_type(_find_type_index("Capsule"))
  63. OPTION_TYPE_CONVEX_POLYGON:
  64. await _start_type(_find_type_index("ConvexPolygon"))
  65. OPTION_TYPE_CONCAVE_POLYGON:
  66. await _start_type(_find_type_index("ConcavePolygon"))
  67. func _find_type_index(type_name):
  68. for type_index in range(_object_templates.size()):
  69. var type_node = _object_templates[type_index]
  70. if String(type_node.name).find(type_name) > -1:
  71. return type_index
  72. Log.print_error("Invalid shape type: " + type_name)
  73. return -1
  74. func _start_type(type_index):
  75. if type_index < 0:
  76. return
  77. if type_index >= _object_templates.size():
  78. return
  79. await start_timer(1.0).timeout
  80. if is_timer_canceled():
  81. return
  82. _log_physics_start()
  83. _spawn_objects(type_index)
  84. await wait_for_physics_ticks(5).wait_done
  85. _log_physics_stop()
  86. await start_timer(1.0).timeout
  87. if is_timer_canceled():
  88. return
  89. _log_physics_start()
  90. _activate_objects()
  91. await wait_for_physics_ticks(5).wait_done
  92. _log_physics_stop()
  93. await start_timer(5.0).timeout
  94. if is_timer_canceled():
  95. return
  96. _log_physics_start()
  97. _despawn_objects()
  98. await wait_for_physics_ticks(5).wait_done
  99. _log_physics_stop()
  100. await start_timer(1.0).timeout
  101. func _start_all_types():
  102. Log.print_log("* Start all types.")
  103. for type_index in range(_object_templates.size()):
  104. await _start_type(type_index)
  105. if is_timer_canceled():
  106. return
  107. Log.print_log("* Done all types.")
  108. func _spawn_objects(type_index):
  109. var template_node = _object_templates[type_index]
  110. Log.print_log("* Spawning: " + String(template_node.name))
  111. for spawn in spawns:
  112. var spawn_parent = get_node(spawn)
  113. for _node_index in range(spawn_count):
  114. # Create a new object and shape every time to avoid the overhead of connecting many bodies to the same shape.
  115. var collision = template_node.get_child(0).duplicate()
  116. if collision is CollisionShape2D:
  117. collision.shape = collision.shape.duplicate()
  118. var body = template_node.duplicate()
  119. body.transform = Transform2D.IDENTITY
  120. if spawn_randomize != Vector2.ZERO:
  121. body.position.x = randf() * spawn_randomize.x
  122. body.position.y = randf() * spawn_randomize.y
  123. var prev_collision = body.get_child(0)
  124. body.remove_child(prev_collision)
  125. prev_collision.queue_free()
  126. body.add_child(collision)
  127. body.set_sleeping(true)
  128. spawn_parent.add_child(body)
  129. func _activate_objects():
  130. Log.print_log("* Activating")
  131. for spawn in spawns:
  132. var spawn_parent = get_node(spawn)
  133. for node_index in range(spawn_parent.get_child_count()):
  134. var node = spawn_parent.get_child(node_index) as RigidBody2D
  135. node.set_sleeping(false)
  136. func _despawn_objects():
  137. Log.print_log("* Despawning")
  138. for spawn in spawns:
  139. var spawn_parent = get_node(spawn)
  140. var object_count = spawn_parent.get_child_count()
  141. if object_count == 0:
  142. continue
  143. # Remove objects in reversed order to avoid the overhead of changing children index in parent.
  144. for object_index in range(object_count):
  145. var node = spawn_parent.get_child(object_count - object_index - 1)
  146. spawn_parent.remove_child(node)
  147. node.queue_free()