I try to predict the time a rigid body ball needs to travel a given distance. Custom integrator is enabled. So the velocity stays constant through the travel.

I expected the distance between the ball start position, and the ball position after one second, is exactly the same than the linear_velocity length.

extends Node2D
var startPos:Vector2

func _ready():
    startPos = $Ball.position
    $Ball.linear_velocity = Vector2(0.0, 500.0)
    $Timer.start()
    
func _on_Timer_timeout():
    $Label.text = "Traveled " + str(($Ball.position - startPos).length()) + " \nVel " + str($Ball.linear_velocity)
    get_tree().set_pause(true)

The result is 491 for the travelled distance. Is linear_velocity intended to represent the vector traveled in one second ? If so I would expect the result as 500.

Are you accounting for the other settings like gravity and mass?

And @NeoD, what processing mode is your timer? Could be desync between render and processing frames?

You set velocity and timer in ready(). The timer is 'active immediately' but the physics engine hasn't "run" yet on the object which has to be added to the physics server, which I think is going to be at the end of the render frame (aka after all process() are called on scene tree nodes having the function). Not only does the rigid body need to be added to the server, the server needs a processing frame to 'move it'. In this case it's starting a physics frame behind the timer.

I think if you check the difference is going to be 1 physics step. (500/60 = 8.33333333333)

Keep in mind that the physics servers know nothing of the godot scene tree, only the physics objects added to them from the scene tree by the godot core engine. So the only things they know about are physics-bodies, (conditionally) areas (?), and joints. Adding, modifying or removing physics objects are subject to this delay.

In some sense this is necessary as physics objects like bodies/joints have multiple properties that may need configuration before being added to the server.

Joints get added to the server when they have a node_a, node_b or both set.

@Lethn gravity is a at (0, 0), mass is 1 @llasram I tried "idle" and "physics" for the same result.

@dotted After reading your explanations I changed the original code.

extends RigidBody2D

var startPos:Vector2
var timerstarted:bool

func _ready():
    startPos = position
    linear_velocity = Vector2(0.0, 500.0)
    #$Timer.start()
    
func _on_Timer_timeout():
    print("Traveled ", (position - startPos).length(), " Vel ", linear_velocity)
    get_tree().set_pause(true)
    
func _integrate_forces(state):
    if position != startPos and !timerstarted: # Try to detected the ball start.
        $Timer.start()
        timerstarted = true

But the result is still the same.

Try checking 1 physics frame after the timer ends or simply using OS.get_tick_msec() and see when distance traveled is 500

2 years later