如何让播放器顺畅旋转

How to make player rotate smoothly

下面是我的整个播放器脚本(如果内容混乱请见谅),如果您能告诉我为什么旋转不起作用,那将非常有帮助。我希望播放器在按下某个键时能够平稳转动。非常感谢!

extends KinematicBody

var moveSpeed : float = 5.0
var jumpForce : float = 10.0
var gravity : float = 20
var vel : Vector3 = Vector3()
const _angular_speed:float = TAU
    
func _physics_process(delta):
    vel.x = 0
    vel.z = 0
    
    var turn_input := Vector2(
            Input.get_action_strength("move_left") - Input.get_action_strength("move_right"),
            Input.get_action_strength("move_forward") - Input.get_action_strength("move_backward")
    )
    var movement = Vector3()
    var input_angle := turn_input.angle()
    var _target_angle:float
    var angle_diff := wrapf(_target_angle - rotation.y, -PI, PI)
    rotation.y += clamp(delta * _angular_speed, 0, abs(angle_diff)) * sign(angle_diff)
        
    if Input.is_action_pressed("move_forward") and Input.is_action_pressed("move_left"):
        movement[2] = 1
        movement[0] = 1
    elif Input.is_action_pressed("move_forward") and Input.is_action_pressed("move_right"):
        movement[2] = 1
        movement[0] = -1
    elif Input.is_action_pressed("move_backward") and Input.is_action_pressed("move_left"):
        movement[2] = -1
        movement[0] = 1
    elif Input.is_action_pressed("move_backward") and Input.is_action_pressed("move_right"):
        movement[2] = -1
        movement[0] = -1
    else:
        if Input.is_action_pressed("move_forward"):
            movement[2] = 1
        if Input.is_action_pressed("move_backward"):
            movement[2] = -1
        if Input.is_action_pressed("move_left"):
            movement[0] = 1
        if Input.is_action_pressed("move_right"):
            movement[0] = -1
        
    movement = movement.normalized()
    global_transform[3] += movement/7
    
    vel.y -= gravity * delta
    
    if Input.is_action_pressed("jump") and is_on_floor():
        vel.y = jumpForce
    
    vel = move_and_slide(vel, Vector3.UP)

编辑:此问题现已得到解答。

你在这里做一些奇怪的事情。


未使用input_angle

首先,只需将其复制到 Godot。我收到一条警告,指出未使用 input_angle。快速查看后,下一个 _target_angle 从未分配:

var input_angle := turn_input.angle()
var _target_angle:float

这很容易解决。只保留 _target_angle:

var _target_angle := turn_input.angle()

清理

其次,不是真正的问题,但是movement是这样的:

var movement := Vector3(turn_input.x, 0.0, turn_input.y).normalized()

这样,您将看到所有这些代码:

    if Input.is_action_pressed("move_forward") and Input.is_action_pressed("move_left"):
        movement[2] = 1
        movement[0] = 1
    elif Input.is_action_pressed("move_forward") and Input.is_action_pressed("move_right"):
        movement[2] = 1
        movement[0] = -1
    elif Input.is_action_pressed("move_backward") and Input.is_action_pressed("move_left"):
        movement[2] = -1
        movement[0] = 1
    elif Input.is_action_pressed("move_backward") and Input.is_action_pressed("move_right"):
        movement[2] = -1
        movement[0] = -1
    else:
        if Input.is_action_pressed("move_forward"):
            movement[2] = 1
        if Input.is_action_pressed("move_backward"):
            movement[2] = -1
        if Input.is_action_pressed("move_left"):
            movement[0] = 1
        if Input.is_action_pressed("move_right"):
            movement[0] = -1
        
    movement = movement.normalized()

删除它。走了。只保留上面的一个衬垫。它应该做同样的事情。 它应该做同样的事情,具有奇怪的行为等等,但现在更容易看到代码。


代码现在看起来像这样:

extends KinematicBody

var moveSpeed : float = 5.0
var jumpForce : float = 10.0
var gravity : float = 20
var vel : Vector3 = Vector3()
const _angular_speed:float = TAU
    
func _physics_process(delta):
    vel.x = 0
    vel.z = 0
    var turn_input := Vector2(
        Input.get_action_strength("move_left") - Input.get_action_strength("move_right"),
        Input.get_action_strength("move_forward") - Input.get_action_strength("move_backward")
    )
    var _target_angle := turn_input.angle()
    var angle_diff := wrapf(_target_angle - rotation.y, -PI, PI)
    rotation.y += clamp(delta * _angular_speed, 0, abs(angle_diff)) * sign(angle_diff)
    var movement := Vector3(turn_input.x, 0.0, turn_input.y).normalized()
    global_transform[3] += movement/7
    vel.y -= gravity * delta
    if Input.is_action_pressed("jump") and is_on_floor():
        vel.y = jumpForce
    
    vel = move_and_slide(vel, Vector3.UP)

什么movement

看看这一行:

global_transform[3] += movement/7

什么鬼,密歇根?

那一行相当于:

global_transform.origin += movement * 1/7

注意这是运动,它没有使用 delta。我会回到那个。


旋转重置

我们需要将_target_angle提升为一个字段,只有在有输入的时候才设置。 我也进一步清理了字段。代码现在看起来像这样:

extends KinematicBody

const _angular_speed:float = TAU

var moveSpeed := 5.0
var jumpForce := 10.0
var gravity := 20
var vel := Vector3()

var _target_angle:float
    
func _physics_process(delta):
    vel.x = 0
    vel.z = 0
    var turn_input := Vector2(
        Input.get_action_strength("move_left") - Input.get_action_strength("move_right"),
        Input.get_action_strength("move_forward") - Input.get_action_strength("move_backward")
    )
    if turn_input.length_squared() > 0:
        _target_angle = turn_input.angle()

    var angle_diff := wrapf(_target_angle - rotation.y, -PI, PI)
    rotation.y += clamp(delta * _angular_speed, 0, abs(angle_diff)) * sign(angle_diff)
    var movement := Vector3(turn_input.x, 0.0, turn_input.y).normalized()
    global_transform[3] += movement/7
    vel.y -= gravity * delta
    if Input.is_action_pressed("jump") and is_on_floor():
        vel.y = jumpForce
    
    vel = move_and_slide(vel, Vector3.UP)

如你所见,我在开始时声明了target_angle,所以它不是局部变量。这样,它就保持了它的价值。我也这样做:

if turn_input.length_squared() > 0:
    _target_angle = turn_input.angle()

这样,只有当turn_input不为空时,才设置_target_angle


方向错误

它似乎在向相反的方向移动。鉴于我遵守了您的订单,我不确定这是不是故意的。

无论如何,修复它就是翻转输入的问题:

    var turn_input := Vector2(
        Input.get_action_strength("move_right") - Input.get_action_strength("move_left"),
        Input.get_action_strength("move_backward") - Input.get_action_strength("move_forward")
    )

这是有道理的,因为 x 向右增长,并且 - 实际上 - Godot 中的前向是负数 z(这里存储在 y 中)。


方向错误

角色的旋转似乎偏离了四分之一圈。这解决了它:

_target_angle = 0.75 * TAU - turn_input.angle()

实际上这是有道理的,因为 turn_input.angle() 是从 x 轴测量的,但是 0 旋转是向下看 z 轴。我确实忽略了这一点。


再次运动

不要更改转换的 origin(通过狡猾的方式,不少于此),而是使用您已经在使用的 move_and_slide。因此,我们不会 movement,而是写入 vel。为了简化操作,我决定对 turn_input 进行归一化,以便我们可以直接使用它来计算 vel。在此期间,让我们使用您拥有的 moveSpeed 字段。 顺便说一句,它很小。

这是最终代码:

extends KinematicBody

const _angular_speed:float = TAU

var moveSpeed := 500.0
var jumpForce := 10.0
var gravity := 20
var vel := Vector3()

var _target_angle:float
    
func _physics_process(delta:float) -> void:
    # Input
    var turn_input := Vector2(
        Input.get_action_strength("move_right") - Input.get_action_strength("move_left"),
        Input.get_action_strength("move_backward") - Input.get_action_strength("move_forward")
    ).normalized()
    
    # Rotation
    if turn_input.length_squared() > 0:
        _target_angle = 0.75 * TAU - turn_input.angle()

    var angle_diff := wrapf(_target_angle - rotation.y, -PI, PI)
    rotation.y += clamp(delta * _angular_speed, 0, abs(angle_diff)) * sign(angle_diff)
    
    # Velocity
    vel.x = turn_input.x * moveSpeed * delta
    vel.z = turn_input.y * moveSpeed * delta
    vel.y -= gravity * delta
    if Input.is_action_pressed("jump") and is_on_floor():
        vel.y = jumpForce

    # Motion
    vel = move_and_slide(vel, Vector3.UP)