RigidBody2D trap inside a circle
Asked Answered
N

2

0

I’m trying to trap objects (with RigidBody2D) inside a circle and use the object’s physics material to calculate bouncing/friction with the circle’s border… Yet I can’t figure out how to get less of a bouncy effect but something that transfers the velocity into velocity along the surface (that takes into account this friction/bounciness).

This is basically my current solution:

// offset = vector from center to current position
// distanceSqr = distance from center squared
// radius = radius of the sphere object is trapped in.
if (distanceSqr > radius * radius)
{
    // Reflect only if velocity is outwards
    float dot = Vector2.Dot(offset.normalized, m_rigidBody.velocity.normalized);
    if (dot > 0.0f)
    {
        // Reflect (Bounce)
        m_rigidBody.velocity = Vector3.Reflect(m_rigidBody.velocity, -offset.normalized);
        // Drag
        m_rigidBody.velocity = m_rigidBody.velocity * (1.0f - (drag));
    }

    // Trap Position inside
    m_transform.position = center + (offset.normalized * radius); // maximum distance (trap inside)
}

Another thing I’ve tried is to remove all outwards velocity of the rigidBody. But as long as it moves slightly to the side it comes to a halt very quickly because then it removes the upwards vector in sublty different directions and rather soon it removed all of it. :slight_smile:

Is there a way to figure out how to calculate a similar resulting velocity vector as it would’ve had if moved up against a point with a normal of an object (which is the information I have) of a regular RigidBody2D object?

I would love to be able to control the friction and bounciness just like with the Physics2d Material.

(Pointers on how this works in 3D space to calculate it nicely would - I think - also be good enough to point me in the direction of how to solve this)

Nathanialnathaniel answered 8/2 at 15:29 Comment(0)
N
0

So I’ve found a workaround that works very nicely. :slight_smile:

Instead of figuring out my own physics I wanted to rather rely mostly on the PhysX engine that is already implemented in Unity (so it works with basically all of RigidBody stuff I throw at it).

The solution I thought of was using the EdgeCollider2D that just has points laid out in a circular fashion! And it seems to work beautifully.

For anyone else that wants to do something similar and needs a high quality one here’s a small script I quickly put together. It’s an editor script that creates a small window that allows you to apply/set EdgeCollider2D to selected gameObjects where it lays out the points automatically in a circular fashion. :slight_smile: The window allows you to set how many vertices you want to have in the final circle.

using UnityEditor;
using UnityEngine;

public class CircleEdgeCollider : EditorWindow
{
    float radius = 1.0f;
    int vertices = 30;

    [MenuItem("Scripts/Colliders/CircleEdgeCollider")]
    public static void ShowWindow()
    {
        //Show existing window instance. If one doesn't exist, make one.
        EditorWindow.GetWindow(typeof(CircleEdgeCollider));
    }

    void OnGUI()
    {
        radius = EditorGUILayout.FloatField("Radius", radius);
        vertices = EditorGUILayout.IntField("Vertices", vertices);
        
        if (GUILayout.Button("Add CircleEdgeCollider")) this.AddCircleEdgeCollider();
    
    }

    void AddCircleEdgeCollider()
    {
        // Get selection
        GameObject[] sel;
        sel = Selection.gameObjects;
        if (sel.Length == 0) return;

        if (vertices < 2){
            Debug.LogError("Can't create a circle edge collider with less than 2 points.");
            return;
        }

        // Create list of points
        Vector2[] pts = new Vector2[vertices];
        for(int i=0; i<vertices; i++)
        {
            // Points on a circle
            Vector2 pt;
            pt.x = Mathf.Cos((i / ((float)vertices - 1.0f)) * (2f * Mathf.PI)) * radius;
            pt.y = Mathf.Sin((i / ((float)vertices - 1.0f)) * (2f * Mathf.PI)) * radius;
            pts *= pt;
        }

        GameObject obj;
        for (int i = 0; i < sel.Length; i++)
        {
            obj = sel;
            Debug.Log(obj.name);
            EdgeCollider2D coll = obj.GetComponent<EdgeCollider2D>();
            if (coll == null)
            {
             coll = obj.AddComponent<EdgeCollider2D>();
            }
            coll.points = pts;
        }
    }
}

Oh yeah, this is my first ever Editor script. :wink: But I hope this workaround can be useful to someone else as well.

Nathanialnathaniel answered 8/2 at 15:26 Comment(0)
S
0

Old topic but so neat! :hugs:
I was thinking about creating the circular EdgeCollider2D programmatically in a script of my object because I just started with Unity three days ago and didn’t know that extending the editor is THAT easy.

Best thing is, I don’t have to fiddle with the maths myself :blush:

PS: I know it’s old but would you mind fixing the code part. The array access [i] has been broken by the CMS I guess. Additionally, the type in the GetComponent and AddComponent calls cannot be inferred automatically for me. I had to add EdgeCollider2D as the generic arguments.

Stronghold answered 8/2 at 13:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.