-1

Below is my entire player script (sorry if it is messy) and it would be really helpful if you could tell me why the rotation isn't working. I want the player to turn smoothly when the player presses a key. Thanks so much!

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)

Edit: This question has now been answered.

5
  • Why are you starting a new thread for an existing question? stackoverflow.com/questions/69823647/… Commented Nov 3, 2021 at 22:31
  • It was the easiest way for me to reply to the comments from the previous post Commented Nov 4, 2021 at 10:21
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. Commented Nov 4, 2021 at 14:04
  • It wasn’t me (though I should have). It is because you are spamming the forum with multiple topics relating to a single question. Commented Nov 4, 2021 at 15:29
  • Ok thanks that it wasn't you Dúthomhas. The reason I did this is it was the only way I knew I could reply to Theraot as it was too long for a comment Commented Nov 5, 2021 at 18:34

1 Answer 1

1

You are doing some odd mix of things here.


Unused input_angle

First, of all, just copying the over to Godot. I get a warning that input_angle is not used. And after a quick look, _target_angle right next is never assigned:

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

That is an easy fix. Just keep _target_angle:

var _target_angle := turn_input.angle()

Clean up

Second, not really a problem, but movement is this:

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

With that, you see all this code:

    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()

Delete it. Gone. Just keep the one liner above. It should do the same thing. It should do the same thing, with the weird behavior and all, but it is easier to see the code now.


The code looks like this now:

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)

What the movement?

Look at this line:

global_transform[3] += movement/7

What the Hell, Michigan?

That line is equivalent to this:

global_transform.origin += movement * 1/7

Notice this is motion, and it is not using delta. I will come back to that.


Rotation resetting

We need to promote _target_angle to a field, and only set it when there is some input. I also did clean the field further. The code now looks like this:

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)

As you can see I declare target_angle at the start, so it is not a local variable. That way, it keeps its value. Also I do this:

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

That way, only when turn_input is not empty, it sets _target_angle.


Wrong direction

It seems to be moving in the opposite direction it should. I'm not sure if this is intentional or not, given that I kept the order you had.

Anyway, fixing it is a matter of flipping the 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")
    )

This makes sense given that x grows to the right, and - actually - forward in Godot is negative z (here stored in the y).


Wrong orientation

The rotation of the character seems to be off by a quarter turn. This solves it:

_target_angle = 0.75 * TAU - turn_input.angle()

Actually it makes sense given that turn_input.angle() would be measured from the x axis, but 0 rotation is looking down the z axis. I did overlook that.


Motion again

Instead of changing the origin of the transform (by snaky means, no less), use move_and_slide, which you are already using. Thus, we are not going to have movement, instead we are going to write to vel. To ease doing that, I decided to normalize turn_input so we can use it directly to compute vel. And while we are at it, let us use the moveSpeed field you have. Which is very small by the way.

This is the final code:

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)
Sign up to request clarification or add additional context in comments.

1 Comment

Wow Theraot, I can't thank you enough. The code is working well and what you explained made a lot of sense. Thanks Again!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.