mirror of
https://github.com/godotengine/godot.git
synced 2024-11-21 19:42:43 +00:00
Updated tutorial_kinematic_char (markdown)
parent
6399e4196d
commit
7e5a0d0d37
@ -25,7 +25,6 @@ func _fixed_process(delta):
|
||||
func _ready():
|
||||
set_fixed_process(true)
|
||||
|
||||
|
||||
```
|
||||
|
||||
### Scene Setup
|
||||
@ -43,6 +42,125 @@ Finally, instance that character scene in the tilemap, and make the map scene th
|
||||
|
||||
<p align="center"><img src="images/kbinstance.png"></p>
|
||||
|
||||
### Creating the Kinematic Character
|
||||
### Moving the Kinematic Character
|
||||
|
||||
Go back to the character scene, and open the script, the magic begins now!
|
||||
Go back to the character scene, and open the script, the magic begins now! Kinematic body will do nothing by default, but it has a really useful function called [move](class_kinematicbody2d#move)(motion_vector:Vector2). This function takes a [Vector2](class_vector2) as an argument, and tries to apply that motion to the kinematic body. If a collision happens, it stops right at the moment of the collision.
|
||||
|
||||
So, let's move our sprite downwards until it hits the floor:
|
||||
|
||||
```python
|
||||
extends KinematicBody2D
|
||||
|
||||
func _fixed_process(delta):
|
||||
move( Vector2(0,1) ) #move down 1 pixel per physics frame
|
||||
|
||||
func _ready():
|
||||
set_fixed_process(true)
|
||||
|
||||
```
|
||||
|
||||
The result is that the character will move, but stop right when hitting the floor. Pretty cool, huh?
|
||||
The next step will be adding gravity to the mix, this way it behaves a little more like an actual game character:
|
||||
|
||||
```python
|
||||
|
||||
extends KinematicBody2D
|
||||
|
||||
const GRAVITY = 200.0
|
||||
var velocity = Vector2()
|
||||
|
||||
func _fixed_process(delta):
|
||||
|
||||
velocity.y += delta * GRAVITY
|
||||
|
||||
var motion = velocity * delta
|
||||
move( motion )
|
||||
|
||||
func _ready():
|
||||
set_fixed_process(true)
|
||||
|
||||
```
|
||||
|
||||
Now the character falls smoothly. Let's make it walk to the sides, left and right when touching the directional keys. Remember that the values being used (for speed at least) is pixels/second.
|
||||
|
||||
This adds simple walking support by pressing left and right:
|
||||
|
||||
```python
|
||||
extends KinematicBody2D
|
||||
|
||||
const GRAVITY = 200.0
|
||||
const WALK_SPEED = 200
|
||||
|
||||
var velocity = Vector2()
|
||||
|
||||
func _fixed_process(delta):
|
||||
|
||||
velocity.y += delta * GRAVITY
|
||||
|
||||
if (Input.is_action_pressed("ui_left")):
|
||||
velocity.x = -WALK_SPEED
|
||||
elif (Input.is_action_pressed("ui_right")):
|
||||
velocity.x = WALK_SPEED
|
||||
else:
|
||||
velocity.x = 0
|
||||
|
||||
var motion = velocity * delta
|
||||
move( motion )
|
||||
|
||||
func _ready():
|
||||
set_fixed_process(true)
|
||||
```
|
||||
|
||||
And give it a try.
|
||||
|
||||
And.. it doesn't work very well. If you go to the left against a wall, it gets stuck unless you release the arrow key. Once it is on the floor, it also gets stuck and it won't walk. What is going on??
|
||||
|
||||
The answer is, what it seems like it should be simple, it isn't that simple in reality. If the motion can't be completed, the character will stop moving. It's as simple as that. This diagram should illustrate better what is going on:
|
||||
|
||||
<p align="center"><img src="images/motion_diagram.png"></p>
|
||||
|
||||
Basically, the desired motion vector will never complete because it hits the floor and the wall to early in the motion trajectory and that makes it stop there. Remember that even though the character is on the floor, the gravity is always turning the motion vector downwards.
|
||||
|
||||
The solution? This situation is solved by "sliding" by the collision normal. KinematicBody2D provides two useful functions:
|
||||
|
||||
* [KinematicBody2D.is_colliding](class_kinematicbody2d#is_colliding)()
|
||||
* [KinematicBody2D.get_collision_normal](class_kinematicbody2d#get_collision_normal)()
|
||||
|
||||
So what we want to do is this:
|
||||
|
||||
<p align="center"><img src="images/motion_reflection.png"></p>
|
||||
|
||||
When colliding, the function move() returns the "remainder" of the motion vector. That means, if the motion vector is 40 pixels, but collision happened at 10 pixels, the same vector but 30 pixels long is returned.
|
||||
The correct way to solve the motion is, then, to slide by the normal this way:
|
||||
|
||||
```python
|
||||
func _fixed_process(delta):
|
||||
|
||||
velocity.y += delta * GRAVITY
|
||||
if (Input.is_action_pressed("ui_left")):
|
||||
velocity.x = - WALK_SPEED
|
||||
elif (Input.is_action_pressed("ui_right")):
|
||||
velocity.x = WALK_SPEED
|
||||
else:
|
||||
velocity.x = 0
|
||||
|
||||
var motion = velocity * delta
|
||||
motion = move( motion )
|
||||
|
||||
if (is_colliding()):
|
||||
var n = get_collision_normal()
|
||||
motion = n.slide( motion )
|
||||
velocity = n.slide( velocity )
|
||||
move( motion )
|
||||
|
||||
|
||||
|
||||
func _ready():
|
||||
set_fixed_process(true)
|
||||
|
||||
```
|
||||
|
||||
Note that not only the motion has been modified but also the velocity. This makes sense as it helps keep
|
||||
the new direction too.
|
||||
|
||||
The normal can also be used to detect that the character is on floor, by checking the angle. If the normal points up (or at least, within a certain threshold), the character can be determined to be there.
|
||||
|
Loading…
Reference in New Issue
Block a user