kinematic_character_2d.rst 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. .. _doc_kinematic_character_2d:
  2. Kinematic character (2D)
  3. ========================
  4. Introduction
  5. ~~~~~~~~~~~~
  6. Yes, the name sounds strange. "Kinematic Character". What is that?
  7. The reason for the name is that, when physics engines came out, they were called
  8. "Dynamics" engines (because they dealt mainly with collision
  9. responses). Many attempts were made to create a character controller
  10. using the dynamics engines, but it wasn't as easy as it seemed. Godot
  11. has one of the best implementations of dynamic character controller
  12. you can find (as it can be seen in the 2d/platformer demo), but using
  13. it requires a considerable level of skill and understanding of
  14. physics engines (or a lot of patience with trial and error).
  15. Some physics engines, such as Havok seem to swear by dynamic character
  16. controllers as the best option, while others (PhysX) would rather
  17. promote the kinematic one.
  18. So, what is the difference?:
  19. - A **dynamic character controller** uses a rigid body with an infinite
  20. inertia tensor. It's a rigid body that can't rotate.
  21. Physics engines always let objects move and collide, then solve their
  22. collisions all together. This makes dynamic character controllers
  23. able to interact with other physics objects seamlessly, as seen in
  24. the platformer demo. However, these interactions are not always
  25. predictable. Collisions can take more than one frame to be
  26. solved, so a few collisions may seem to displace a tiny bit. Those
  27. problems can be fixed, but require a certain amount of skill.
  28. - A **kinematic character controller** is assumed to always begin in a
  29. non-colliding state, and will always move to a non-colliding state.
  30. If it starts in a colliding state, it will try to free itself like
  31. rigid bodies do, but this is the exception, not the rule. This makes
  32. their control and motion a lot more predictable and easier to
  33. program. However, as a downside, they can't directly interact with
  34. other physics objects, unless done by hand in code.
  35. This short tutorial will focus on the kinematic character controller.
  36. Basically, the old-school way of handling collisions (which is not
  37. necessarily simpler under the hood, but well hidden and presented as a
  38. nice and simple API).
  39. Physics process
  40. ~~~~~~~~~~~~~~~
  41. To manage the logic of a kinematic body or character, it is always
  42. advised to use physics process, because it's called before physics step and its execution is
  43. in sync with physics server, also it is called the same amount of times
  44. per second, always. This makes physics and motion calculation work in a
  45. more predictable way than using regular process, which might have spikes
  46. or lose precision if the frame rate is too high or too low.
  47. .. tabs::
  48. .. code-tab:: gdscript GDScript
  49. extends KinematicBody2D
  50. func _physics_process(delta):
  51. pass
  52. .. code-tab:: csharp
  53. using Godot;
  54. using System;
  55. public class PhysicsScript : KinematicBody2D
  56. {
  57. public override void _PhysicsProcess(float delta)
  58. {
  59. }
  60. }
  61. Scene setup
  62. ~~~~~~~~~~~
  63. To have something to test, here's the scene (from the tilemap tutorial):
  64. :download:`kbscene.zip <files/kbscene.zip>`. We'll be creating a new scene
  65. for the character. Use the robot sprite and create a scene like this:
  66. .. image:: img/kbscene.png
  67. You'll notice that there's a warning icon next to our CollisionShape2D node;
  68. that's because we haven't defined a shape for it. Create a new CircleShape2D
  69. in the shape property of CollisionShape2D. Click on <CircleShape2D> to go to the
  70. options for it, and set the radius to 30:
  71. .. image:: img/kbradius.png
  72. **Note: As mentioned before in the physics tutorial, the physics engine
  73. can't handle scale on most types of shapes (only collision polygons,
  74. planes and segments work), so always change the parameters (such as
  75. radius) of the shape instead of scaling it. The same is also true for
  76. the kinematic/rigid/static bodies themselves, as their scale affects the
  77. shape scale.**
  78. Now, create a script for the character, the one used as an example
  79. above should work as a base.
  80. Finally, instance that character scene in the tilemap, and make the
  81. map scene the main one, so it runs when pressing play.
  82. .. image:: img/kbinstance.png
  83. Moving the kinematic character
  84. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  85. Go back to the character scene, and open the script, the magic begins
  86. now! Kinematic body will do nothing by default, but it has a
  87. useful function called
  88. :ref:`KinematicBody2D.move_and_collide() <class_KinematicBody2D_method_move_and_collide>`.
  89. This function takes a :ref:`Vector2 <class_Vector2>` as
  90. an argument, and tries to apply that motion to the kinematic body. If a
  91. collision happens, it stops right at the moment of the collision.
  92. So, let's move our sprite downwards until it hits the floor:
  93. .. tabs::
  94. .. code-tab:: gdscript GDScript
  95. extends KinematicBody2D
  96. func _physics_process(delta):
  97. move_and_collide(Vector2(0, 1)) # Move down 1 pixel per physics frame
  98. .. code-tab:: csharp
  99. using Godot;
  100. using System;
  101. public class PhysicsScript : KinematicBody2D
  102. {
  103. public override void _PhysicsProcess(float delta)
  104. {
  105. // Move down 1 pixel per physics frame
  106. MoveAndCollide(new Vector2(0, 1));
  107. }
  108. }
  109. The result is that the character will move, but stop right when
  110. hitting the floor. Pretty cool, huh?
  111. The next step will be adding gravity to the mix, this way it behaves a
  112. little more like a regular game character:
  113. .. tabs::
  114. .. code-tab:: gdscript GDScript
  115. extends KinematicBody2D
  116. const GRAVITY = 200.0
  117. var velocity = Vector2()
  118. func _physics_process(delta):
  119. velocity.y += delta * GRAVITY
  120. var motion = velocity * delta
  121. move_and_collide(motion)
  122. .. code-tab:: csharp
  123. using Godot;
  124. using System;
  125. public class PhysicsScript : KinematicBody2D
  126. {
  127. const float gravity = 200.0f;
  128. Vector2 velocity;
  129. public override void _PhysicsProcess(float delta)
  130. {
  131. velocity.y += delta * gravity;
  132. var motion = velocity * delta;
  133. MoveAndCollide(motion);
  134. }
  135. }
  136. Now the character falls smoothly. Let's make it walk to the sides, left
  137. and right when touching the directional keys. Remember that the values
  138. being used (for speed at least) are pixels/second.
  139. This adds simple walking support by pressing left and right:
  140. .. tabs::
  141. .. code-tab:: gdscript GDScript
  142. extends KinematicBody2D
  143. const GRAVITY = 200.0
  144. const WALK_SPEED = 200
  145. var velocity = Vector2()
  146. func _physics_process(delta):
  147. velocity.y += delta * GRAVITY
  148. if Input.is_action_pressed("ui_left"):
  149. velocity.x = -WALK_SPEED
  150. elif Input.is_action_pressed("ui_right"):
  151. velocity.x = WALK_SPEED
  152. else:
  153. velocity.x = 0
  154. # We don't need to multiply velocity by delta because "move_and_slide" already takes delta time into account.
  155. # The second parameter of "move_and_slide" is the normal pointing up.
  156. # In the case of a 2D platformer, in Godot, upward is negative y, which translates to -1 as a normal.
  157. move_and_slide(velocity, Vector2(0, -1))
  158. .. code-tab:: csharp
  159. using Godot;
  160. using System;
  161. public class PhysicsScript : KinematicBody2D
  162. {
  163. const float gravity = 200.0f;
  164. const int walkSpeed = 200;
  165. Vector2 velocity;
  166. public override void _PhysicsProcess(float delta)
  167. {
  168. velocity.y += delta * gravity;
  169. if (Input.IsActionPressed("ui_left"))
  170. {
  171. velocity.x = -walkSpeed;
  172. }
  173. else if (Input.IsActionPressed("ui_right"))
  174. {
  175. velocity.x = walkSpeed;
  176. }
  177. else
  178. {
  179. velocity.x = 0;
  180. }
  181. // We don't need to multiply velocity by delta because "MoveAndSlide" already takes delta time into account.
  182. // The second parameter of "MoveAndSlide" is the normal pointing up.
  183. // In the case of a 2D platformer, in Godot, upward is negative y, which translates to -1 as a normal.
  184. MoveAndSlide(velocity, new Vector2(0, -1));
  185. }
  186. }
  187. And give it a try.
  188. This is a good starting point for a platformer. A more complete demo can be found in the demo zip distributed with the
  189. engine, or in the
  190. https://github.com/godotengine/godot-demo-projects/tree/master/2d/kinematic_character.