- 方法概述
- 缘起一个BUG
- 解决办法
KinematicBody
中move_and_slide
方法,它的原型是下面这样的
Vector3 move_and_slide(linear_velocity: Vector3, up_direction: Vector3 = Vector3( 0, 0, 0 ), stop_on_slope: bool = false, max_slides: int = 4, floor_max_angle: float = 0.785398, infinite_inertia: bool = true)
很多时候我们只要给定此方法的前面两个参数(对象的速度以及对象的向上方向),就可以很简单的移动KinematicBody
对象了,如下:
move_and_slide(velocity,Vector3.UP)
这个方法还允许我们设置可滑行的坡度,非常方便。
缘起一个BUG老王之前并没有把move_and_slide
的Vector3
返回值当回事,直到很久以前的一篇博文《Godot Engine:3D角色移动(走/跑/跳)》被热心网友cgoxopx 指出有BUG:
原来的代码如下
extends KinematicBody
class_name Player
const walk_speed = 5.0
const run_speed = 10.0
var gravity:Vector3 = Vector3.DOWN*12
var speed:float = walk_speed
var jump_speed:float = 6.0
var velocity : Vector3 = Vector3.ZERO
var jump : bool = false
func _ready():
add_to_group("player")
func _physics_process(delta):
velocity += gravity*delta
get_input()
move_and_slide(velocity,Vector3.UP)
if jump and is_on_floor():
velocity.y = jump_speed
func get_input():
var vy = velocity.y
velocity = Vector3.ZERO
if Input.is_action_pressed("ui_run"):
speed = run_speed
if Input.is_action_just_released("ui_run"):
speed = walk_speed
if Input.is_action_pressed("ui_up"):
velocity += Vector3.FORWARD
if Input.is_action_pressed("ui_down"):
velocity += Vector3.BACK
if Input.is_action_pressed("ui_left"):
velocity += Vector3.LEFT
if Input.is_action_pressed("ui_right"):
velocity += Vector3.RIGHT
velocity = velocity.normalized()*speed
if velocity != Vector3.ZERO:
look_at(translation - velocity,Vector3.UP)
velocity.y = vy
#动作键和跳跃键
if Input.is_action_just_pressed("ui_action"):
print("action")
jump = false
if Input.is_action_just_pressed("ui_jump"):
jump = true
仔细看了一下代码,确实只考虑到了角色主动起跳时将重力加速度清零的情况,如果角色是站在悬崖上滑落,加速度是会积累到非常大,而且没有清零。
解决办法按照传统思路应该想办法获取到这种“滑落事件”,说实话这事儿还是有点麻烦,需要增加新的节点并且又要连接信号。老王差点想回复“直接用状态机吧”。后来查了一些教程,发现其实有非常非常简单的办法实现这个重力清零
将以上代码中的
move_and_slide(velocity,Vector3.UP)
改为
velocity = move_and_slide(velocity,Vector3.UP)
就OK了!
move_and_slide
的返回值到底是什么,其实就是通过我们所给的速度velocity
以及KinematicBody
对象的此时的各种碰撞因素,得出的实际运动速度。 比如,我们给一个处在地面的KinematicBody
对象一个值为(1.0,-5.0,1.0)
的速度,给的速度在Y轴
有一个向下的分量,但是由于对象在地面,所以这个分量会被抵消,那么实际的运动速度就是(1.0,0.0,1.0)
那么在本例中,其实我们根本没有必要“费尽心机”寻找什么“滑落事件”,如果我们把对象每一帧的实际速度“返还”给它,那么只要它在地面这,这个重力加速度就每时每刻都被清零了。