move_and_collide()与move_and_slide()
KinematicBody2D有move_and_collide()与move_and_slide()两个关于移动与碰撞方法。
你可以看到两者的返回值类型是不同的。
move_and_slide()
平常使用时,move_and_slide()更像是一个简易函数,用于快速的实现KinematicBody2D移动和碰撞。它的行为就是:
- 以给定的线速度进行移动
- 如果指定了上的方向,就同时界定了什么是地板、墙和天花板
- 用它进行移动,如果碰到地面、墙体和天花板等地方,它既不会像小球一样反弹,也不会像一块石头一样掉在地上就不动了。如果遇到斜坡等地方,它会尽可能的滑动。
move_and_slide()的写法及其参数意义
代码来自:官方文档 - 使用KinematicBody2D - 平台运动```swift extends KinematicBody2D
export (int)var run speed = 100 export (int)var jump_speed = -400 export (int)var gravity = 1200
var velocity = Vector2() var jumping = false # 是否正在跳跃
func get_input() velocity.x = 0 var right = Input.is action pressed(‘ui_right’) var left = Input.is_action_pressed(‘ui_left’) var jump = Input.is action just pressed(‘ui_select’)
if jump and is_on_floor(): # 按下跳跃键但还未起跳时
jumping = true
velocity.y = jump_speed
if right:
velocity.x += run_speed
if left:
velocity.x -= run_speed
func _physics_process(delta): get_input() velocity.y + =gravity * delta # 模拟垂直方向上受重力下落 if jumping and is_on_floor(): # 也就是上次跳跃完落地之时,此时jumpingi还处于true,is_on_floor()也是true jumping = false velocity = move_and_slide(velocity) # 没有限定up_direction,则默认为Vector2(0,0),则四面皆是墙
<a name="igDX4"></a>
## 关于墙(wall)、天花板(ceiling)、地板(floor)
move_and_slide()有一个参数up_direction<br />
|  | 默认情况下,可以被看做是俯视角游戏,四面都是墙,没有天花板和地板。 |
| --- | --- |
|  | 2D平台游戏中,通常设定up_direction为Vector2.UP,此时,下面是地板,上面是天花板,左右是墙。 |
| --- | --- |
|  | 并且还有另一个参数floor_max_angle来设置墙和地板之间的临界值。<br />默认为45°,也就是说>45°的斜坡会被认为是墙,而<45°则会被认为是地板。 |
| --- | --- |
|  | KinematicBody2D有三个方法,用于判断当前KinematicBody2D到底是碰撞到了什么,是墙、是地面还是天花板。 |
| --- | --- |
|  | 对于平台跳跃游戏,可以有一个更直观的图解。 |
| --- | --- |
<a name="Kt44j"></a>
## move_and_collide()
|  | move_and_collide()返回的是一个 KinematicCollision2D类型,它提供KinematicBody2D发生碰撞后的数据,可以在发生碰撞后,获取到被碰撞物、碰撞点以及法线等的信息,并以此为基础进行高度自定义的碰撞响应,自由的返回新的速度向量。 |
| --- | --- |
<a name="g7ejh"></a>
## 实现碰撞后滑动、反弹以及反射
由于move_and_collide()是基于速度向量进行移动和碰撞检测,所以我们实现效果是基于对速度向量的修改。<br />而2D的速度向量是Vector2类型,也就是二维向量。因此我们要借助的就是Vector2的三个方法。<br /><br /><br />其中slide()就类似于move_and_slide(),而bounce()进行反弹,而reflect()进行反射。<br /><br />关于Vector2的reflect()<br />通过timothyqiu兄指正,reflect()的参数为反射平面,而非平面的法线,官方文档和内置文档存在谬误.<br />那么问题来了,对于同一个假想平面,有两个方向相反的向量,那么Vector2的reflect()对于这两个向量,是否会返回一致的向量呢?实际测试结果是:两者是一样的。笔者采用水平方向的Vector2.RIGHT和Vector2.LEFT测试,reflect()返回的结果向量都是一样的.<br />
```swift
func _physics_process(delta):
if can_move:
var collision = collider.move_and_collide(velocity * delta)
if collision:#发生碰撞
velocity = velocity.slide(collision.normal)
extends Node2D
var direction = Vector2.ONE
var speed = 100.0
var velocity = Vector2.ZERO
onready var collider = $碰撞体
onready var plane = $平面
func _ready()
velocity = direction * speed # 初始的速度向量
func _physics_process(delta):
var collision = collider.move_and_collide(velocity * delta)
if collision: # 发生碰撞
velocity = velocity.bounce(collision.normal) # 实现基于被碰撞物体的碰撞形状上碰撞,点法线进行反弹
move_and_slide()获取碰撞对象
当使用 move_and_slide() 时, 有可能发生多次碰撞, 因为滑动响应是计算出来的.
要处理这些碰撞, 可以使用 get_slide_count() 和 get_slide_collision():
velocity = move_and_slide(velocity)
for i in get_slide_count():
var collision = get_slide_collision(i)
print("I collided with ", collision.collider.name)