ray-casting.rst 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. .. _doc_ray-casting:
  2. Physics Ray Casting and Queries (2D and 3D)
  3. ===========================================
  4. Introduction
  5. ~~~~~~~~~~~~
  6. One of the most common tasks in game development is casting a ray (or
  7. custom shaped object) and see what it hits. This enables complex
  8. behaviors, AI, etc. to take place.
  9. This tutorial will explain how to do this in 2D and 3D.
  10. Godot stores all the low level game information in servers, while the
  11. scene is just a frontend. As such, ray casting is generally a
  12. lower-level task. For simple raycasts, node such as
  13. :ref:`RayCast <class_RayCast>` and
  14. :ref:`RayCast2D <class_RayCast2D>`
  15. will work, as they will return every frame what the result of a raycast
  16. is.
  17. Many times, though, ray-casting needs to be a more interactive process
  18. so a way to do this by code must exist.
  19. Space
  20. ~~~~~
  21. In the physics world, Godot stores all the low level collision and
  22. physics information in a *space*. The current 2d space (for 2D Physics)
  23. can be obtained by calling
  24. `CanvasItem.get\_world\_2d().get\_space() <https://github.com/okamstudio/godot/wiki/class_canvasitem#get_world_2d>`__.
  25. For 3D, it's
  26. `Spatial.get\_world().get\_space() <https://github.com/okamstudio/godot/wiki/class_spatial#get_world>`__.
  27. The resulting space
  28. :ref:`RID <class_RID>` can be used
  29. in
  30. :ref:`PhysicsServer <class_PhysicsServer>`
  31. and
  32. :ref:`Physics2DServer <class_Physics2DServer>`
  33. respectively for 3D and 2D.
  34. Acessing Space
  35. ~~~~~~~~~~~~~~
  36. Godot physics runs by default in the same thread as game logic, but may
  37. be set to run on a separate thread to work more efficiently. Due to
  38. this, the only time accessing space is safe is during the
  39. `Node.\_fixed\_process(delta) <https://github.com/okamstudio/godot/wiki/class_node#_fixed_process>`__
  40. callback. Accessing it from outside this function may result in an error
  41. due to space being *locked*.
  42. To perform queries into physics space, the
  43. :ref:`Physics2DDirectSpaceState <class_Physics2DDirectSpaceState>`
  44. and
  45. :ref:`PhysicsDirectSpaceState <class_PhysicsDirectSpaceState>`
  46. must be used.
  47. In code, for 2D spacestate, this code must be used:
  48. ::
  49. func _fixed_process(delta):
  50. var space_rid = get_world_2d().get_space()
  51. var space_state = Physics2DServer.space_get_direct_state(space_rid)
  52. Of course, there is a simpler shortcut:
  53. ::
  54. func _fixed_process(delta):
  55. var space_state = get_world_2d().get_direct_space_state()
  56. For 3D:
  57. ::
  58. func _fixed_process(delta):
  59. var space_state = get_world().get_direct_space_state()
  60. Raycast Query
  61. ~~~~~~~~~~~~~
  62. For performing a 2D raycast query, the method
  63. :ref:`Physics2DDirectSpaceState.intersect_ray() <class_Physics2DDirectSpaceState_intersect_ray>`
  64. must be used, for example:
  65. ::
  66. func _fixed_process(delta):
  67. var space_state = get_world().get_direct_space_state()
  68. # use global coordinates, not local to node
  69. var result = space_state.intersect_ray( Vector2(0,0), Vector2(50,100) )
  70. Result is a dictionary, if ray didn't hit anything, the dictionary will
  71. be empty. If it did hit something it will contain collision information:
  72. ::
  73. if (not result.empty()):
  74. print("Hit at point: ",result.position)
  75. The collision result dictionary, when something hit, has this format:
  76. ::
  77. {
  78. position:Vector2 # point in world space for collision
  79. normal:Vector2 # normal in world space for collision
  80. collider:Object # Object collided or null (if unassociated)
  81. collider_id:ObjectID # Object it collided against
  82. rid:RID # RID it collided against
  83. shape:int # shape index of collider
  84. metadata:Variant() # metadata of collider
  85. }
  86. # in case of 3D, Vector3 is returned.
  87. Collision Exceptions
  88. ~~~~~~~~~~~~~~~~~~~~
  89. It is a very common case to attempt casting a ray from a character or
  90. another game scene to try to infer properties of the world around it.
  91. The problem with this is that the same character has a collider, so the
  92. ray can never leave the origin (it will keep hitting it's own collider),
  93. as evidenced in the following image.
  94. .. image:: /img/raycast_falsepositive.png
  95. To avoid self-intersection, the intersect\_ray() function can take an
  96. optional third parameter which is an array of exceptions. This is an
  97. example of how to use it from a KinematicBody2D or any other
  98. collisionobject based node:
  99. ::
  100. extends KinematicBody2D
  101. func _fixed_process(delta):
  102. var space_state = get_world().get_direct_space_state()
  103. var result = space_state.intersect_ray( get_global_pos(), enemy_pos, [ self ] )
  104. The extra argument is a list of exceptions, can be objects (need Godot
  105. 1.1beta2+ for this) or RIDs.
  106. 3D Ray Casting From Screen
  107. ~~~~~~~~~~~~~~~~~~~~~~~~~~
  108. Casting a ray from screen to 3D physics space is useful for object
  109. picking. There is not much of a need to do this because
  110. :ref:`CollisionObject <class_CollisionObject>`
  111. has an "input\_event" signal that will let you know when it was clicked,
  112. but in case there is any desire to do it manually, here's how.
  113. To cast a ray from the screen, the
  114. :ref:`Camera <class_Camera>` node
  115. is needed. Camera can be in two projection modes, perspective and
  116. orthogonal. Because of this, both the ray origin and direction must be
  117. obtained. (origin changes in orthogonal, while direction changes in
  118. perspective):
  119. .. image:: /img/raycast_projection.png
  120. To obtain it using a camera, the following code can be used:
  121. ::
  122. const ray_length = 1000
  123. func _input(ev):
  124. if ev.type==InputEvent.MOUSE_BUTTON and ev.pressed and ev.button_index==1:
  125. var camera = get_node("camera")
  126. var from = camera.project_ray_origin(ev.pos)
  127. var to = from + camera.project_ray_normal(ev.pos) * ray_length
  128. Of course, remember that during \_input(), space may be locked, so save
  129. your query for \_fixed\_process().