cak3_lover
cak3_lover

Reputation: 1958

Descending pendulum motion in _physics_process

I'm trying to simulate pendulum motion within _physics_process as such:

extends KinematicBody2D

var direction:Vector2
var gravity_speed=30000

onready var rod=$rod
onready var pivot:Vector2=to_global(rod.points[1])

func _physics_process(delta):
    
    var theta=Vector2(1,0).angle_to(to_local(pivot)) * -1 # angle between local x_axis & pivot point vector 
    var sin_theta=sin(theta)
    var cos_theta=cos(theta)
    
    direction.y += gravity_speed * delta
    
    direction.x= direction.x + direction.y*sin_theta*cos_theta - direction.x*cos_theta*cos_theta
    direction.y= direction.y + direction.x*sin_theta*cos_theta - direction.y*sin_theta*sin_theta
    
    direction=move_and_slide(direction,Vector2.UP)
    rod.points[1]=rod.to_local(pivot)

enter image description here

But for some reason it seems to be "falling downwards" (increased gravity so it's visible faster): enter image description here

Any idea why this might be caused?

Note:
I'm ideally looking for a fix which involves _physics_process() so the object can interact with the environment as well

Minimal

Edit:

This is how I came up with the equation:

enter image description here

(theta *-1 & other -ve signs in the code because y is flipped)


Edit 2: What was causing the error?

I ran some simulations on my windows xp super computer and found out why the problem was being caused!

Turns out it's not a bug in godot but in how we deal with circular motion in physics

In physics, if we apply a tangential force continuously it causes the object to rotate in circular motion (emphasis on the keyword "continuously")

However, In godot we are NOT applying the tangential force continuously but instead apply it from frame to frame & as such our body tends to move forward tangential between those frames

Giving us an "Err or" from the trajectory we're suppose to be following:
enter image description here

This piles up in the long run and gives the illusion that the pendulum is stretching downwards:
enter image description here

(You can think of the universe having an infinite frame rate :P)

Upvotes: 1

Views: 412

Answers (1)

Camwin
Camwin

Reputation: 413

I have a solution. What was missing from this simulation was the tension force from the rod, in the direction of the pivot. The rod_length is calculated onready and is set from the starting distance, but it can be set manually or changed during runtime. I did have to add air resistance (which must be negative), because once the bug was fixed the pendulum no longer lost speed.

extends KinematicBody2D

var direction:Vector2
var gravity_speed=6000 #30000
var air_resistance = -200

onready var rod=$rod
onready var pivot:Vector2=to_global(rod.points[1])
onready var rod_length = get_position().distance_to(pivot)

func _physics_process(delta):
    direction=move_and_slide(direction,Vector2.UP)
    
    #gravity
    direction.y += gravity_speed * delta
    
    #air resistance
    direction += (direction.normalized() * air_resistance * delta).limit_length(direction.length())
    
    #pendulum motion
    var theta=Vector2(1,0).angle_to(to_local(pivot)) * -1 # angle between local x_axis & pivot point vector 
    var sin_theta=sin(theta)
    var cos_theta=cos(theta)
    direction.x= direction.x + direction.y*sin_theta*cos_theta - direction.x*cos_theta*cos_theta
    direction.y= direction.y + direction.x*sin_theta*cos_theta - direction.y*sin_theta*sin_theta
    
    #tension
    var tension = clamp(get_position().distance_to(pivot) - rod_length, 0, 1) * gravity_speed
    direction += get_position().direction_to(pivot) * tension * delta
    
    rod.points[1]=rod.to_local(pivot)

I am not sure exactly what was causing the issue, but the same issue persists if you do tension before pendulum motion, and a different issue appears if you do pendulum motion before air resistance or gravity.

I like this code a lot, but it may be worth noting a similar effect could be created by linking a StaticBody2D and a RigidBody2D with a PinJoint2D if one just needed a swinging object.

Upvotes: 2

Related Questions