Search code examples
vectorgdscript

Move "forwards" when KiematicBody is rotated with GDScript


I have a very basic third person controller:

func _physics_process(delta):
    vel.x = 0
    
    if Input.is_action_pressed("move_forward"):
        vel.x += SPEED * delta
    if Input.is_action_pressed("turn_left"):
        rotate_y(deg2rad(ROTATION_INTENSITY))
    
    move_and_collide(vel)

However on rotating and then moving forward, the player will move forward on the x axis instead of the direction the player is pointed. How do i fix this? Thanks in advance!


Solution

  • Your KinematicBody is an Spatial, and as such it is positioned by a Transform.

    You can get the Transform from the parent Spatial (or the root of the scene tree if there is no parent Spatial) from the transform property.

    And you can get the Transform from root of the scene directly from the global_transform property.

    The Transform has two parts:

    Together they encode a coordinate system. In particular basis has three vectors that hold the direction and scale of each of the axis of the coordinate system. And origin has the position of the origin of the coordinate system.

    Now, Godot's coordinate system in 3D is right handed with UP = Y and FORWARD = -Z. You can confirm this with the constants Vector3.UP and Vector3.FORWARD. Also notice this differs from Unity and Unreal which are left handed.


    Ergo, if you want the direction of one of the axis, you can get it form the basis of the global transform. Like this:

    var forward := -global_transform.basis.z
    var backward := global_transform.basis.z
    var left := -global_transform.basis.x
    var right := global_transform.basis.x 
    var down := -global_transform.basis.y
    var up := global_transform.basis.y
    

    You could use those to build your velocity in global coordinates, for example:

    velocity += global_transform.basis.x * SPEED
    

    Alternatively, you can convert vectors from local to global space with to_global (and from global to local with to_local) so you can do this:

    var forward := to_global(Vector3.FORWARD)
    var backward:= to_global(Vector3.BACKWARD)
    var left := to_global(Vector3.LEFT)
    var right := to_global(Vector3.RIGHT)
    var down := to_global(Vector3.DOWN)
    var up := to_global(Vector3.UP)
    

    This also means you may build your velocity in local coordinates, and convert it to global coordinates at the end:

    move_and_slide(to_global(velocity))
    

    And just to be clear, move_and_slide expects global coordinates.


    I will also point out that it is possible to rotate a vector with rotated and project a vector onto another with project.