spring_arm.rst 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. .. _doc_spring_arm:
  2. Third-person camera with spring arm
  3. ===================================
  4. Introduction
  5. ------------
  6. 3D games will often have a third-person camera that follows and
  7. rotates around something such as a player character or a vehicle.
  8. In Godot, this can be done by setting a :ref:`Camera3D <class_Camera3D>` as a child of a node.
  9. However, if you try this without any extra steps, you'll notice that the camera clips through geometry and hides the scene.
  10. This is where the :ref:`SpringArm3D <class_SpringArm3D>` node comes in.
  11. What is a spring arm?
  12. ---------------------
  13. A spring arm has two main components that affect its behavior.
  14. The "length" of the spring arm is how far from its global position to check for collisions:
  15. .. image:: img/spring_arm_position_length.webp
  16. The "shape" of the spring arm is what it uses to check for collisions. The spring arm will "sweep" this shape from its origin out towards its length.
  17. .. image:: img/spring_arm_shape.webp
  18. The spring arm tries to keep all of its children at the end of its length. When the shape collides with something, the children are instead placed at or near that collision point:
  19. .. image:: img/spring_arm_children.webp
  20. Spring arm with a camera
  21. ------------------------
  22. When a camera is placed as a child of a spring arm, a pyramid representing the camera will be used as the shape.
  23. This pyramid represents the **near plane** of the camera:
  24. .. image:: img/spring_arm_camera_shape.webp
  25. .. note:: If the spring arm is given a specific shape, then that shape will **always** be used.
  26. The camera's shape is only used if the camera is a **direct child** of the spring arm.
  27. If no shape is provided and the camera is not a direct child, the spring arm will fall back to using a ray cast which is inaccurate for camera collisions and not recommended.
  28. Every physics process frame, the spring arm will perform a motion cast to check if anything is collided with:
  29. .. image:: img/spring_arm_camera_motion_cast.webp
  30. When the shape hits something, the camera will be placed at or near the collision point:
  31. .. image:: img/spring_arm_camera_collision.webp
  32. Setting up the spring arm and camera
  33. ------------------------------------
  34. Let's add a spring arm camera setup to the platformer demo.
  35. .. note:: You can download the Platformer 3D demo on `GitHub <https://github.com/godotengine/godot-demo-projects/tree/master/3d/platformer>`_ or using the `Asset Library <https://godotengine.org/asset-library/asset/2748>`_.
  36. In general, for a third-person camera setup, you will have three nodes as children of the node that you're following:
  37. - `Node3D` (the "pivot point" for the camera)
  38. - `SpringArm3D`
  39. - `Camera3D`
  40. Open the ``player/player.tscn`` scene. Set these up as children of our player and give them unique names so we can find them in our script. **Make sure to delete the existing camera node!**
  41. .. image:: img/spring_arm_editor_setup.webp
  42. Let's move the pivot point up by ``2`` on the Y-axis so that it's not on the ground:
  43. .. image:: img/spring_arm_pivot_setup.webp
  44. Give the spring arm a length of ``3`` so that it is placed behind the character:
  45. .. image:: img/spring_arm_length_setup.webp
  46. .. note:: Leave the **Shape** of the spring arm as ``<empty>``. This way, it will use the camera's pyramid shape.
  47. If you want, you can also try other shapes - a sphere is a common choice since it slides smoothly along edges.
  48. Update the top of ``player/player.gd`` to grab the camera and the pivot points by their unique names:
  49. .. code-block:: gdscript
  50. :caption: player/player.gd
  51. # Comment out this existing camera line.
  52. # @onready var _camera := $Target/Camera3D as Camera3D
  53. @onready var _camera := %Camera3D as Camera3D
  54. @onready var _camera_pivot := %CameraPivot as Node3D
  55. Add an ``_unhandled_input`` function to check for camera movement and then rotate the pivot point accordingly:
  56. .. code-block:: gdscript
  57. :caption: player/player.gd
  58. @export_range(0.0, 1.0) var mouse_sensitivity = 0.01
  59. @export var tilt_limit = deg_to_rad(75)
  60. func _unhandled_input(event: InputEvent) -> void:
  61. if event is InputEventMouseMotion:
  62. _camera_pivot.rotation.x -= event.relative.y * mouse_sensitivity
  63. # Prevent the camera from rotating too far up or down.
  64. _camera_pivot.rotation.x = clampf(_camera_pivot.rotation.x, -tilt_limit, tilt_limit)
  65. _camera_pivot.rotation.y += -event.relative.x * mouse_sensitivity
  66. By rotating the pivot point, the spring arm will also be rotated and it will change where the camera is positioned.
  67. Run the game and notice that mouse movement now rotates the camera around the character. If the camera moves into a wall, it collides with it.
  68. .. video:: video/spring_arm_camera.webm
  69. :alt: Camera attached to a spring arm colliding with walls
  70. :autoplay:
  71. :loop:
  72. :muted: