test_collision_pairs.gd 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. extends Test
  2. const OPTION_TYPE_RECTANGLE = "Collision type/Rectangle (1)"
  3. const OPTION_TYPE_SPHERE = "Collision type/Sphere (2)"
  4. const OPTION_TYPE_CAPSULE = "Collision type/Capsule (3)"
  5. const OPTION_TYPE_CONVEX_POLYGON = "Collision type/Convex Polygon (4)"
  6. const OPTION_TYPE_CONCAVE_SEGMENTS = "Collision type/Concave Segments (5)"
  7. const OPTION_SHAPE_RECTANGLE = "Shape type/Rectangle"
  8. const OPTION_SHAPE_SPHERE = "Shape type/Sphere"
  9. const OPTION_SHAPE_CAPSULE = "Shape type/Capsule"
  10. const OPTION_SHAPE_CONVEX_POLYGON = "Shape type/Convex Polygon"
  11. const OPTION_SHAPE_CONCAVE_POLYGON = "Shape type/Concave Polygon"
  12. const OPTION_SHAPE_CONCAVE_SEGMENTS = "Shape type/Concave Segments"
  13. const OFFSET_RANGE = 120.0
  14. @export var offset := Vector2.ZERO
  15. @onready var options: OptionMenu = $Options
  16. var _update_collision := false
  17. var _collision_test_index := 0
  18. var _collision_shapes: Array[Shape2D] = []
  19. func _ready() -> void:
  20. _initialize_collision_shapes()
  21. options.add_menu_item(OPTION_TYPE_RECTANGLE)
  22. options.add_menu_item(OPTION_TYPE_SPHERE)
  23. options.add_menu_item(OPTION_TYPE_CAPSULE)
  24. options.add_menu_item(OPTION_TYPE_CONVEX_POLYGON)
  25. options.add_menu_item(OPTION_TYPE_CONCAVE_SEGMENTS)
  26. options.add_menu_item(OPTION_SHAPE_RECTANGLE, true, true)
  27. options.add_menu_item(OPTION_SHAPE_SPHERE, true, true)
  28. options.add_menu_item(OPTION_SHAPE_CAPSULE, true, true)
  29. options.add_menu_item(OPTION_SHAPE_CONVEX_POLYGON, true, true)
  30. options.add_menu_item(OPTION_SHAPE_CONCAVE_POLYGON, true, true)
  31. options.add_menu_item(OPTION_SHAPE_CONCAVE_SEGMENTS, true, true)
  32. options.option_selected.connect(_on_option_selected)
  33. options.option_changed.connect(_on_option_changed)
  34. await start_timer(0.5).timeout
  35. if is_timer_canceled():
  36. return
  37. _update_collision = true
  38. func _input(event: InputEvent) -> void:
  39. var key_event := event as InputEventKey
  40. if key_event and not key_event.pressed:
  41. if key_event.keycode == KEY_1:
  42. _on_option_selected(OPTION_TYPE_RECTANGLE)
  43. elif key_event.keycode == KEY_2:
  44. _on_option_selected(OPTION_TYPE_SPHERE)
  45. elif key_event.keycode == KEY_3:
  46. _on_option_selected(OPTION_TYPE_CAPSULE)
  47. elif key_event.keycode == KEY_4:
  48. _on_option_selected(OPTION_TYPE_CONVEX_POLYGON)
  49. elif key_event.keycode == KEY_5:
  50. _on_option_selected(OPTION_TYPE_CONCAVE_SEGMENTS)
  51. func _physics_process(delta: float) -> void:
  52. super._physics_process(delta)
  53. if not _update_collision:
  54. return
  55. _update_collision = false
  56. _do_collision_test()
  57. func set_h_offset(value: float) -> void:
  58. offset.x = value * OFFSET_RANGE
  59. _update_collision = true
  60. func set_v_offset(value: float) -> void:
  61. offset.y = -value * OFFSET_RANGE
  62. _update_collision = true
  63. func _initialize_collision_shapes() -> void:
  64. _collision_shapes.clear()
  65. for node: PhysicsBody2D in $Shapes.get_children():
  66. var body: PhysicsBody2D = node
  67. var shape := body.shape_owner_get_shape(0, 0)
  68. shape.resource_name = String(node.name).substr("RigidBody".length())
  69. _collision_shapes.push_back(shape)
  70. func _do_collision_test() -> void:
  71. clear_drawn_nodes()
  72. var shape := _collision_shapes[_collision_test_index]
  73. Log.print_log("* Start %s collision tests..." % shape.resource_name)
  74. var shape_query := PhysicsShapeQueryParameters2D.new()
  75. shape_query.set_shape(shape)
  76. var shape_scale := Vector2(0.5, 0.5)
  77. shape_query.transform = Transform2D.IDENTITY.scaled(shape_scale)
  78. for node: PhysicsBody2D in $Shapes.get_children():
  79. if not node.visible:
  80. continue
  81. var body: PhysicsBody2D = node
  82. var space_state := body.get_world_2d().direct_space_state
  83. Log.print_log("* Testing: %s" % String(body.name))
  84. var center := body.position
  85. # Collision at the center inside.
  86. var res := _add_collision(space_state, center, shape, shape_query)
  87. Log.print_log("Collision center inside: %s" % ("NO HIT" if res.is_empty() else "HIT"))
  88. Log.print_log("* Done.")
  89. func _add_collision(space_state: PhysicsDirectSpaceState2D, pos: Vector2, shape: Shape2D, shape_query: PhysicsShapeQueryParameters2D) -> Array[Vector2]:
  90. shape_query.transform.origin = pos + offset
  91. var results: Array[Vector2] = space_state.collide_shape(shape_query)
  92. var color := Color.GREEN
  93. if results.is_empty():
  94. color = Color.WHITE.darkened(0.5)
  95. # Draw collision query shape.
  96. add_shape(shape, shape_query.transform, color)
  97. # Draw contact positions.
  98. for contact_pos in results:
  99. add_circle(contact_pos, 1.0, Color.RED)
  100. return results
  101. func _on_option_selected(option: String) -> void:
  102. match option:
  103. OPTION_TYPE_RECTANGLE:
  104. _collision_test_index = _find_type_index("Rectangle")
  105. _update_collision = true
  106. OPTION_TYPE_SPHERE:
  107. _collision_test_index = _find_type_index("Sphere")
  108. _update_collision = true
  109. OPTION_TYPE_CAPSULE:
  110. _collision_test_index = _find_type_index("Capsule")
  111. _update_collision = true
  112. OPTION_TYPE_CONVEX_POLYGON:
  113. _collision_test_index = _find_type_index("ConvexPolygon")
  114. _update_collision = true
  115. OPTION_TYPE_CONCAVE_SEGMENTS:
  116. _collision_test_index = _find_type_index("ConcaveSegments")
  117. _update_collision = true
  118. func _find_type_index(type_name: String) -> int:
  119. for type_index in range(_collision_shapes.size()):
  120. var type_shape := _collision_shapes[type_index]
  121. if type_shape.resource_name.find(type_name) > -1:
  122. return type_index
  123. Log.print_error("Invalid collision type: " + type_name)
  124. return -1
  125. func _on_option_changed(option: String, checked: bool) -> void:
  126. var node: Node2D
  127. match option:
  128. OPTION_SHAPE_RECTANGLE:
  129. node = _find_shape_node("Rectangle")
  130. OPTION_SHAPE_SPHERE:
  131. node = _find_shape_node("Sphere")
  132. OPTION_SHAPE_CAPSULE:
  133. node = _find_shape_node("Capsule")
  134. OPTION_SHAPE_CONVEX_POLYGON:
  135. node = _find_shape_node("ConvexPolygon")
  136. OPTION_SHAPE_CONCAVE_POLYGON:
  137. node = _find_shape_node("ConcavePolygon")
  138. OPTION_SHAPE_CONCAVE_SEGMENTS:
  139. node = _find_shape_node("ConcaveSegments")
  140. if node:
  141. node.visible = checked
  142. node.get_child(0).disabled = not checked
  143. _update_collision = true
  144. func _find_shape_node(type_name: String) -> Node2D:
  145. var node: Node2D = $Shapes.find_child("RigidBody%s" % type_name)
  146. if not node:
  147. Log.print_error("Invalid shape type: " + type_name)
  148. return node