# Eliminate bouncing when switching/sticking to a different surface

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:

How can I eliminate the bouncing?

The project setup looks like this:

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



## 1 Answer

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".

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: