3
\$\begingroup\$

I am following this tutorial to make a KinematicBody2D align to the surfaces below it.

When switching from one surface to another, the character bounces until it corrects/aligns its rotation, as shown here:

animation showing character bouncing

How can I eliminate the bouncing?

I've uploaded a minimal version of the project on GitHub.

The project setup looks like this: Godot editor screenshot

And this is the player script:

extends KinematicBody2D

export (int) var speed = 600
export (int) var jump_speed = -600
export (int) var gravity = 1000

var velocity := Vector2.ZERO

export (float, 0, 1.0) var friction = 0.1
export (float, 0, 1.0) var acceleration = 0.25

var last_collission = null;

func get_input():
    var dir = 0
    if Input.is_action_pressed("ui_right"):
        dir = 1 
        $RightRay.enabled = true
        $LeftRay.enabled = false
    if Input.is_action_pressed("ui_left"):
        dir = -1 
        $RightRay.enabled = false
        $LeftRay.enabled = true
    if dir != 0:
        velocity.x = lerp(velocity.x, dir * speed, acceleration)
    else:
        if !is_jumping:
            $RightRay.enabled = false
            $LeftRay.enabled = false
        velocity.x = lerp(velocity.x, 0, friction)

var is_jumping = false
func _physics_process(delta):
    get_input()
    velocity.y += gravity * delta
    var snap = transform.y * 128 if !is_jumping else Vector2.ZERO
    velocity = move_and_slide_with_snap(velocity.rotated(rotation),
                    snap, -transform.y, true, 4, PI/3)
#   velocity = velocity.linear_interpolate(velocity.rotated(-rotation), 0.8)
    velocity = velocity.rotated(-rotation)

    if is_on_floor():
#       velocity.x += speed * delta
        if !is_jumping :
            rotation = get_floor_normal().angle()  + PI/2
        
        is_jumping = false

        if Input.is_action_just_pressed("ui_accept"):
            is_jumping = true
            velocity.y = jump_speed
            $RightRay.enabled = true
            $LeftRay.enabled = true
    
    if  $RightRay.is_colliding():   
        rotation =  $RightRay.get_collision_normal().angle() + PI/2
        $RightRay.enabled = false
        $LeftRay.enabled = false
        
    if  $LeftRay.is_colliding():        
        rotation =  $LeftRay.get_collision_normal().angle() + PI/2
        $RightRay.enabled = false
        $LeftRay.enabled = false
    
\$\endgroup\$
0

1 Answer 1

4
\$\begingroup\$

The problem is that you are using velocity as the node's local velocity instead of the global velocity. That is to say, the reference system of the velocity is the local coordinate system of the node. That is, the velocity direction will be affected by the node's rotation:

velocity = move_and_slide_with_snap(velocity.rotated(rotation),snap, -transform.y, true, 4, PI/3)
velocity = velocity.rotated(-rotation) 

This makes it easy to switch between different gravity reference systems, but at the moment of switching, the speed also rotates, which leads to "bouncing".

enter image description here enter image description here

The solution depends on the effect you want. Sometimes we think that a certain motion phenomenon is "correct" because it more or less conforms to the motion law of the real world: objects have inertia. Switching the gravity reference frame is a pure game mechanism. So I think of two solutions: clear the speed and retain the speed.

Clear the speed:

if  $RightRay.is_colliding():   
    rotation =  $RightRay.get_collision_normal().angle() + PI/2
    velocity = Vector2.ZERO
    $RightRay.enabled = false
    $LeftRay.enabled = false
    
if  $LeftRay.is_colliding():    
    rotation =  $LeftRay.get_collision_normal().angle() + PI/2
    velocity = Vector2.ZERO
    $RightRay.enabled = false
    $LeftRay.enabled = false

Retain the speed:

if  $RightRay.is_colliding():   
    var rotation_pre = rotation
    rotation =  $RightRay.get_collision_normal().angle() + PI/2
    velocity = velocity.rotated(rotation_pre-rotation)
    $RightRay.enabled = false
    $LeftRay.enabled = false
    
if  $LeftRay.is_colliding():    
    var rotation_pre = rotation 
    rotation =  $LeftRay.get_collision_normal().angle() + PI/2
    velocity = velocity.rotated(rotation_pre-rotation)
    $RightRay.enabled = false
    $LeftRay.enabled = false

Result:

enter image description here

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .