#Pendulum Motion Collisions

4 messages · Page 1 of 1 (latest)

frank lava
#

TLDR;

While swinging with this code, collisions behave strangely. I want it to just hit the wall and stop without vibrating through it or getting completely stuck.


Howdy!

Using: CharacterBody2D & StaticBody2D

I'm working on some prototypes for metroidvania abilities. I've decided to make a grappling hook/rope swing mechanic.
I've managed to get a swinging motion using some basic angular physics, but I've run into an issue.
Calculating tangential velocities and applying them like a normal linear velocity will cause a slow increase in the movement arc's radius. I don't want to go into too much detail, but this is because the equations we use assume constant motion, but Godot only applies motion every frame- meaning that the arc cannot be smooth.
To remedy this, I calculate the position that the pendulum should be on each frame and apply that position directly. Unfortunately, this means that I'm not able to use the built in collisions for Godot.

I've attempted setting the velocity to 0 during collision and moving the pendulum until it no longer collides, but this causes fidgety and glitch movement. Any ideas or solutions are appreciated.
Code Below!

#
extends CharacterBody2D

var L = 64;
var g = 2400
var swing_strength = 3600
var theta = 0.0
var omega = 0.0
var alpha = 0.0

var torque = 0.0
var pivot = Vector2(128,128)

func _ready() -> void:
    theta = position.angle_to(pivot)

func _physics_process(delta: float) -> void:
    # Shorten & Lengthen Rope
    if Input.is_action_pressed("ui_up"):
        if L > 32:
            L -= 1
    elif Input.is_action_pressed("ui_down"):
        if L < 128:
            L += 1;
    
    # Swing Left or Right
    if Input.is_action_pressed("ui_right"):
        torque = swing_strength/(L)
    elif Input.is_action_pressed("ui_left"):
        torque = -swing_strength/(L)
    else:
        torque = 0
    
    
    
    alpha = (-g/L * sin(theta)) + torque
    omega += alpha*delta
    theta += omega*delta
    omega*=.99
    
    var collision = move_and_collide(omega/L * Vector2(sin(theta), cos(theta)), true)
    
    if collision:
        omega = 0;
    else:
        position = pivot + Vector2(L*sin(theta), L*cos(theta))
    
    
    
    queue_redraw()

func _draw() -> void:
    draw_circle(pivot-position,8,Color.BLUE,true)
    draw_circle(Vector2.ZERO,8,Color.YELLOW,true)
    draw_line(Vector2.ZERO, pivot-position, Color.GREEN, 2, false)

red jetty
frank lava
# red jetty If you have the manually calculated target position you can't simply `move_and_c...

Cant believe I didnt think of this- thanks a ton!

This fixes the worst of the movement issues- but now im running into a new issue.
The new position continues to calculate as if the pendulum hadnt collided- so when the new position reaches the opposite side, the pendulum snaps into position on the other side as if it had followed the full arc. If I set the angular velocity to 0, it just gets stuck the wall.