0 votes

I'm trying to make a game where the player travels through a 2D world, carrying a chain that will be used to pick things up and interact with the environment. I'm still trying to get the chain to work, but the basic approach (chain adapted from this tutorial) is:

  • Have a player that is a RigidBody2D
  • Move the player using setappliedforce in physicsprocess
  • Have a child node (of the player) called Chain, with a child RigidBody2D called ChainStart
  • Build the rest of the chain by creating segments (also RigidBody2D) & attaching them together using PinJoint2D, starting at ChainStart

The collisions have been set so that the player/chain don't bump into each other.

Everything seems to work up until the point where the chain collides with the environment - at which point the segments can get "caught" and pull apart. I've tried adjusting the Bias property of PinJoint2D, but that approach has similar issues (the segments come apart and things "explode" a bit more).

Am I taking the right approach for my problem, using RigidBody2D and PinJoint2D? If so, what's the best way to keep the chain segments together? If not, is there another approach I should be considering?


Sample project/code/gifs

I created a small demo project to represent the issue, which can be found here.
And some gifs representing the issue.

Here's the relevant code from the demo project, starting with the chain creation:

func _ready():
    var player = get_node("boat")
    var chainStart = player.get_node("Chain").get_node("ChainStart")

    var child
    var parent = chainStart

    for i in range (loops):
        child = addLoop(parent, LOOP.instance(), 4) # a LOOP is a segment
        addPin(parent, child)
        parent = child
    child = addLoop(parent, ANCHOR.instance(), 6) # ANCHOR is just the last segment
    addPin(parent, child)

func addLoop(parent, loop, offset):
    loop.position = parent.global_position
    loop.position.y += offset
    add_child(loop)
    return loop

func addPin(parent, child):
    var pin = PIN.instance()
    pin.node_a = parent.get_path()
    pin.node_b = child.get_path()
    parent.add_child(pin)

And the player's movement:

func _physics_process(delta):
    set_applied_force(Vector2(50, 0)) # move one direction for demo

Thanks!

in Engine by (15 points)

1 Answer

+3 votes
Best answer

The problem here ist that the boat runs ahead no matter how the chain is tangled. Normally, the chain would get torn apart or pull the boat back.

For a start, you can set the linear and/or the angular damping of your chain
elements/rigidbodies. I tried with your project and found the value 2 quite ok.

Another approach would be a bit more complicated. You could attach a script to the pin joints physicsprocess and measure the distance between nodea and node_b (Vector2.length) if they get too far apart then apply a force to your boat (scaled by delta) that pulls the boat back in the direction nodeb->nodea (Scaled by the distance, and keep in mind that other joints may add their force too). If applied correctly I hope that the chain pulling boat will be stopped when the chain is tangled up too much.

by (3,252 points)
selected by

Thanks for taking the time to look at this.

For a start, you can set the linear and/or the angular damping of your chain elements/rigidbodies. I tried with your project and found the value 2 quite ok.

I tried this, but am still seeing strange behavior. The code I'm using is:

loop.linear_damp = 2
loop.angular_damp = 2

However, I'm not sure this would solve my problem, as I'm looking for a solution where the chain does not affect/pull the boat in any way. Ideally, the boat would move freely, and the chain would snake itself around any obstacles that it might pass over.

I realize this doesn't necessarily follow the laws of physics, so I may end up forgoing the physics engine route. But if you have any other suggestions, I'd love to hear em.

I tried out to do a pullback and the effect would be quite obvious. :-)
Chain with pullback

What you could try would be to lower the gravity for loop and anchor to i.e. 0.1.
Still there's no guarantee that the physics might go nuts when the player gets faster.

I'm sorry I didn't see your reply earlier, the alert went to my spam folder and I just found it.

I've put aside this project for now but I think both of your suggestions are good - I'll have to try lowering the gravity if & when I come back to it. The pullback effect is super nifty too. Thanks for your help with my unconventional question!

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.