test_collision_pairs.gd 5.9 KB

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