Top down ship friction as KinematicBody2D

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Demik

Greetings,

I am searching for 2-3 days on internet how to make my ship stop more naturally and every solution that I found didn’t work. I know that when keys are released a velocity.length should go to 0 but somehow I can’t figure out what formula to put and where.
Here is the code:

extends KinematicBody2D
export (int) var speed = 500
export (float) var rotation_speed = 1.5
export (float) var friction = 0.65


var velocity = Vector2()
var rotation_dir = 0
var acc = Vector2()
var pos = Vector2()
func _ready():

pass



func _physics_process(delta):
rotation_dir = 0
velocity = Vector2(0, 0)

if Input.is_action_pressed('right'):
    rotation_dir += 1
if Input.is_action_pressed('left'):
    rotation_dir -= 1
if Input.is_action_pressed('up'):
    acc = Vector2(0, -speed).rotated(rotation)
elif Input.is_action_pressed('down'):
    acc = Vector2(0, speed).rotated(rotation)
else:
    acc = Vector2(0, 0)
velocity += acc * delta
pos += velocity
rotation += rotation_dir * rotation_speed * delta

move_and_slide(pos, Vector2(0, 0))

I’ve tried adding after “else:” velocity*= pow(friction, delta) but it only made it faster.
If You could help me I would be very thankful because this is very frustrating not to find a solution for, I believe, very simple problem.

Firction is a force that depends on the normal force (gravity * mass if on horizontal plane) multiplied by a friction coefficient. If it’s a top-down game, i would directly define the friction acceleration, and each time, i would make the difference between that and the acc you calculated. However, you must have in mind that when the objects slows down too much, the object stops and the friction dissappears, so on each step you could ask if velocity is under some threshold and then set friction to 0. Something like this could work:

extends KinematicBody2D
export (int) var speed = 500
export (float) var rotation_speed = 1.5
export (float) var friction = 100


var velocity = Vector2()
var rotation_dir = 0
var speed_thresh = 50
var acc = Vector2()
var pos = Vector2()
func _ready():
    pass



func _physics_process(delta):
    rotation_dir = 0
   # i don't think you should reset velocity if you are trying to get an accelerated movement. I'll comment this ouyt
    #velocity = Vector2(0, 0)

    if Input.is_action_pressed('right'):
        rotation_dir += 1
    if Input.is_action_pressed('left'):
        friction = 100
        rotation_dir -= 1
    if Input.is_action_pressed('up'):
        friction = 100
        acc = Vector2(0, -speed).rotated(rotation)
    elif Input.is_action_pressed('down'):
        acc = Vector2(0, speed).rotated(rotation)
    else:
        acc = Vector2(0, 0)
    
    # Difference between acc and friction. Rotate rotation+180 is for making opposite vectors
    acc += Vector2(0,friction).rotaed(rotation+180)  
    velocity += acc * delta
    if abs(velocity.y) < speed_thresh and abs(velocity.x) < speed_thresh:
        velocity = 0
        friction = 0

    #Don't know why you accumulate in pos every frame. I would just use velocity
    #pos += velocity
    rotation += rotation_dir * rotation_speed * delta

    move_and_slide(velocity, Vector2(0, 0))

I cannot try this right now cause i’m not at home. But let me know if it does not work and i’ll try to make it right

p7f | 2018-12-29 23:33

:bust_in_silhouette: Reply From: Tapio Pyrhönen

If you put this after your move_ and_ slide the script will work nicely:

pos = pos.linear_interpolate(Vector2(0,0), friction * delta)

Funny, huh? The pos variable is doing what your velocity is supposed to do. Here’s a corrected script:

extends KinematicBody2D
export (int) var speed = 500
export (float) var rotation_speed = 1.5
export (float) var friction = 0.65

var velocity = Vector2()
var rotation_dir = 0
var acc = Vector2()

func _ready():
	pass


func _physics_process(delta):
	rotation_dir = 0

	if Input.is_action_pressed('right'):
	    rotation_dir += 1
	if Input.is_action_pressed('left'):
        rotation_dir -= 1
	if Input.is_action_pressed('up'):
        acc = Vector2(0, -speed).rotated(rotation)
	elif Input.is_action_pressed('down'):
        acc = Vector2(0, speed).rotated(rotation)
	else:
        acc = Vector2(0, 0)



	velocity += acc * delta
    rotation += rotation_dir * rotation_speed * delta

	move_and_slide(velocity, Vector2(0, 0))

    velocity = velocity.linear_interpolate(Vector2(0,0), friction * delta)

I removed the pos variable since it’s not needed, and I removed the part where you set velocity to zero, and I added the last line that does the friction part.

I’m sorry for such a late respond but I didn’t have time for project because of college duties. This solution is working PERFECTLY, thank You very much. I didn’t know such a simple one line of code could be answer to my problem.

Demik | 2019-01-13 20:02