Rope/Cable custom physics interacting with collider2Ds

I’m making a 2D game, I want the fastest and the simplest possible implementation of rope/cable physics. I can sacrifice some accuracy, the physics itself is mostly there for animation/cosmetics. No colliders in it so far.

I did more-or-less standard Verlet integration with iterative distance constraints, and then added angular constraints and stiffness. I’m still wrestling with masses; Orbital mechanics was much easier, I swear. But nvm, I got it working, cleaned it up, and I’m more or less satisfied, it’s pretty decent.

Now I want to introduce interaction with the scene colliders. Such fun!
Ok, so how on Earth am I supposed to find a point of contact with Collider2D?

What I have tried so far
Verlet integration itself is fine, I can raycast there, but this doesn’t help me because the actual points relax iteratively, which is the main trick of this algorithm. So I’m supposed to resolve collisions after everything is done, not before. But once it’s finished, some points are already embedded inside the colliders. “Fine” I thought, “I can push them back onto the perimeter”. Nope, I can’t!

I can find the collider with OverlapPoint, and there is ClosestPoint both in Collider2D and Physics2D – but it doesn’t work! It works when the point is outside of the collider, but doesn’t work from the inside, which makes very little sense to me because it obviously works with the edges. Why wouldn’t it work with the edges, when it has all the info I don’t? Is this because of concave shapes?

In the end I’ve found a (moderately expensive, but worth-a-try) hack from the days when ClosestPoint wasn’t there at all, and that didn’t actually solve anything, though I’m not saying it’s impossible, I just lost my patience and the hack is ugly. At the moment, I’m just really curious, how is one supposed to work with colliders, if I’m supposed to explode their edges on my own and run my own nearest point computation, how’s that useful? I mean, I’m this close to also slap a quadtree, implement my own collider-like shapes and call it a day. Should I use only PolygonCollider2D?

Also, before anyone suggests it, I have no GameObject to use any kind of EdgeCollider. I mean, I will likely reorganize everything if that’s the only solution, I will have a GameObject eventually because I need to render this anyway, but for now it’s just points in space that I visualize with gizmos.

I was really thinking that the collider part would be the easiest. Sigh.

@MelvMay What would you recommend? How do we optimally and reliably interact with colliders in such a situation? I have very little experience with custom physics.

It’s hard to follow this TBH.

I don’t see how you have moving colliders if no Rigidbody2D are involved (Kinematic or otherwise). You cannot be moving such colliders without them unless you are just writing to the Transform which isn’t something you’re supposed to do. It’ll just cause such (Static) colliders to be completely recreated from scratch. In the very least, add a Rigidbody2D and set its body-type to Kinematic or Static and set the Rigidbody2D.position if you need to.

Circle, Capsule & Polygon are closed shapes. Any point inside a close shape is already at the closest point so it does work as it returns the point you passed. It’s not a perimeter check. Only edges are open shapes so there’s no inside so will return a point on the edge no matter which side you are on.

If you want a “perimeter” style check then use Physics2D/Rigidbody2D/Collider2D Distance which gives you a point-to-point distance and whether it’s overlapped or not (overlapped gives you a negative distance).

The above sounds like you did a whole bunch of stuff without considering how physics could be used with it then you want to use things that move without using Rigidbody2D and then are saying “how’s that useful” which from my POV doesn’t really make sense. Movement in physics is controlled by physics. For when it’s not, it provides a Kinematic Rigidbody2D. I know that sounds defensive but it’s not, it’s how it works! :slight_smile: I’m not saying this is how you approached this but from just reading what you put, it’s what it sounds like is all!

Verlet sim is cool and simple and I’m sure you have your reasons to do it but I wanted to highlight something that you likely already know but ropes are also pretty decent in Box2D:
https://www.youtube.com/watch?v=EH9nj3zcfFQ

btw, sorry if the above is stuff you already know. I don’t mean to sounds patronising or critical. I’m simply responding to not really understanding what you’re doing. Considering how much you wrote, there’s actually very little detail for me to comment on. :wink:

Yeah well, hm, I must’ve done a poor job explaining it.
It’s nothing too complicated, but I see I have confused you with my use case.

You have misunderstood me big time. I have no colliders OR rigidbodies. It’s just pure math. For this particular case, I don’t care about physics per se, pretend it’s not about physics, I just see colliders as capable polygon definitions idling in the scene. And why shouldn’t I?

Remember my essay on celestial bodies? No rigidbodies there either. No colliders. Nothing.
It works. I can even handle collisions. Call me crazy. I like to push the boundaries.

In this case I just need point-collider math. We don’t need rigidbodies to raycast, right? So we can obviously have ray-collider math. Why not point-collider math then? If we want to check which point was hit by a ray we can have that. Why can’t we do that from the inside? I really don’t see what’s the difference, in 3D as well, but especially in 2D. Why can’t I get the perimeter point that’s closest to some other point, all segments are already known, internally Unity already does distance checks from the segments themselves, it’s not magic.

Think about it this way: if I had my own shape (polygon definition) I could do this without issues. But if I’m already having a collider? Well that’s too bad, now you have to create a redundant shape from it, allocate arrays and produce garbage, because a collider API is as dumb as a brick, all while you know that it does everything you need and much more in the native code. That’s just annoying.

I am ok with workarounds, but Collider2D.Distance is collider-collider. Why am I supposed to create a tiny circle collider for each point? Or god forbid a rigidbody. Doesn’t really sound that optimal, going from only 20 points to fully-fledged hierarchy of multiple GameObjects each with half a dozen components. I have made a rope out of 20 points, pre-allocated, completely done in each frame in less than 0.05 ms.

That said, once I get started with the actual Box2D stuff, I’ll do exactly what you recommend, that’s the proper way and the way it was meant to be. But this ain’t it. Not really a replacement for physics, this is its own thing, and I simply want it to smack into existing colliders in whatever way is the most optimal.

Nvm, if there is no obvious way, I’ll find a way. I just wanted to doublecheck if I’m blind or sth.
Thanks for the suggestions.

Right. So this is a question about just spatial queries I guess.

Hold on. You used the word “collider”. Are we now talking about Colliders or general intersection tests. Words matter.

So this is why I’m confused. We’re not supposed to be talking about 2D physics but this question.

Again, are we talking about algorithms or are you talking about 2D physics implementation here?

I’ll stop here as I’m totally confused now. Too many statement/questions going on here without a clear direction. What is it specifically you want?

You have a clear picture of where you’re racing to, I’m still on the starting block scratching my head. :wink:

So let me try to guess here.

You have a bunch of verlet-based positions, your sim is all working and grand. Now you’d like to perform some 2D physics checks to see how close this verlet-based “rope” is to actual 2D physics colliders?

You’d like the impact of this to be as minimal as possible.

So, you can attach a Static Rigidbody2D to each position on your rope that you want to have a Collider2D and disable the simulation on it. It now has absolutely zero CPU impact, only the memory overhead of it being there.

You can now set the Rigidbody2D.position to whatever you like. This happens immediately and when you do this, only the body position is updated, not the transform, not the broadphase of any attached colliders so it’s super fast.

You can now perform queries on the Rigidbody2D and its colliders either by Rigidbody2D.OverlapCollider or more directly on a specific Collider2D.OverlapCollider you’re using. This’ll give you any colliders overlapping in a List. Reuse this list for performance.

With a list of Collider2D you can now iterate them and perform whatever you like on them. Collider2D.Distance gives you a ColliderDistance2D which gives you the closest points to move out of overlap or to move together.

Note that you can also perform collider casts from your non-simulated Rigidbody2D/Collider2D combination. You just cannot query it directly as it’s not in the broadphase but you can use the collider physics shapes to query against stuff that is in the broadphase.

Here’s a crude example of a script on such a Static Rigidbody2D set to not simulated that has a collider. This script moves other collider via their Rigidbody2D out of overlap:

using System.Collections.Generic;
using UnityEngine;

public class SolveMyOverlaps : MonoBehaviour
{
    public ContactFilter2D ContactFilter;
    public List<Collider2D> Overlaps = new List<Collider2D>();

    private Collider2D m_Collider2D;

    void Start()
    {
        m_Collider2D = GetComponent<Collider2D>();
    }

    void Update()
    {
        var overlapCount = m_Collider2D.OverlapCollider(ContactFilter, Overlaps);
        for(var i = 0; i < overlapCount; ++i)
        {
            var otherCollider = Overlaps[i];
            var distanceResult = m_Collider2D.Distance(otherCollider);
            if (distanceResult.isOverlapped)
            {
                var body = otherCollider.attachedRigidbody;
                if (body)
                {
                    body.position += -distanceResult.distance * distanceResult.normal;
                }
            }
        }
    }
}

Alternatively, use a Static Rigidbody2D unsimulated and add an EdgeCollider2D (with an edge radius if you like) and adjust all its vertices then perform an overlap on it. So similar thing, different collider and only a single Rigidbody2D.

1 Like

Exactly, you got it :slight_smile:

Thanks for that info, I appreciate it. That sounds like something I’ve already tried, but it’s a fairly different take on it.

I’m currently in the midst of moving out (obv my computer is the last thing to go), I’ll check this approach as soon as I can get my paws back into business.

Thanks again.

1 Like

The main thing is that by turning off the simulation of the Rigidbody2D, it doesn’t have any overhead, nor do the shapes apart from the memory they occupy which is minimal. You can even use the same Rigidbody2D to perform multiple vertex queries if you like with minimal overhead. Moving such a Rigidbody2D won’t change the Colliders or shapes in them either, it’ll only change the Box2D pose so should be super fast.

Good luck with the move. One of the most stressful things you can do in life, apparently! :slight_smile:

1 Like

In my language there is this saying “from a horse, to a donkey”. In my case it’s more like “from a donkey, to an alpaca”, but hey Luke Skywalker showed us how to survive the winter with only a tauntaun!

I’m actually super curious about what you’re doing here. If you have something public such as something on GitHub or something private you want to share then DM me. I’d be more than happy to see what I could do to help and get it working or set-up something that would demonstrate.

I love me some Verlet sim. :wink:

I can continue with this now that I’ve finally settled down.
Sure thing, I’ll keep you posted! If everything goes according to plan, it should turn out pretty unique.

1 Like