Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  Rope extension, vibration and collision
#1
Hello,
I am developing a project using the system in your Hook project as a reference. I can lengthen and shorten the rope, but the rope has problems interacting with colliders, as far as I understand the particle count is low. How can I increase this? If my method is wrong, please tell me.
When I wrap it around an obstacle, the rope vibrates.

Example of the project I am trying to make: https://play.google.com/store/apps/detai...lley&pli=1

Point A is fixed, point B is moveable.

Thank you Sonrisa

           
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Obi;
using System;

public class RopeCreate : MonoBehaviour
{
 

    [Header("Obi")]
    [SerializeField] Transform ropeEnd;
    public ObiSolver solver;
    public ObiCollider2D character;
    public float hookExtendRetractSpeed = 2;
    public Material material;
    public ObiRopeSection section;

    private ObiRope rope;
    private ObiRopeBlueprint blueprint;
    private ObiRopeExtrudedRenderer ropeRenderer;

    private ObiRopeCursor cursor;

    private RaycastHit hookAttachment;

    public Rigidbody2D characterRb;
    void Awake()
    {

        // Create both the rope and the solver:    
        rope = gameObject.AddComponent<ObiRope>();
        ropeRenderer = gameObject.AddComponent<ObiRopeExtrudedRenderer>();
        ropeRenderer.section = section;
        ropeRenderer.uvScale = new Vector2(1, 5);
        ropeRenderer.normalizeV = false;
        ropeRenderer.uvAnchor = 1;
        rope.GetComponent<MeshRenderer>().material = material;

        // Setup a blueprint for the rope:
        blueprint = ScriptableObject.CreateInstance<ObiRopeBlueprint>();
        blueprint.resolution = 0.5f;

        // Tweak rope parameters:
        rope.maxBending = 0.02f;

        // Add a cursor to be able to change rope length:
        cursor = rope.gameObject.AddComponent<ObiRopeCursor>();
        cursor.cursorMu = 0;
        cursor.direction = true;
    }

    private void Start()
    {
      

        if (!rope.isLoaded)
            LaunchHook();

        Debug.Log(GetRopeLength());
    }

    private void OnDestroy()
    {
        DestroyImmediate(blueprint);
    }

    /**
     * Raycast against the scene to see if we can attach the hook to something.
     */
    private void LaunchHook()
    {


        StartCoroutine(AttachHook());


    }

    private IEnumerator AttachHook()
    {

        yield return null;

        Vector3 startLocal = transform.position;
        Vector3 endLocal = ropeEnd.position;
        Vector3 direction = (endLocal - startLocal).normalized;

       
        blueprint.path.Clear();
        blueprint.path.AddControlPoint(startLocal, -direction, direction, Vector3.up, 0.1f, 0.1f, 1, 1, Color.white, "Hook start");
        blueprint.path.AddControlPoint(endLocal, -direction, direction, Vector3.up, 0.1f, 0.1f, 1, 1, Color.white, "Hook end");
        blueprint.path.FlushEvents();

       
        yield return blueprint.Generate();

        rope.ropeBlueprint = blueprint;
        rope.GetComponent<MeshRenderer>().enabled = true;

       
        var pinConstraints = rope.GetConstraintsByType(Oni.ConstraintType.Pin) as ObiConstraints<ObiPinConstraintsBatch>;
        pinConstraints.Clear();
        var batch = new ObiPinConstraintsBatch();

       
        batch.AddConstraint(rope.solverIndices[0], character, transform.localPosition, Quaternion.identity, 0, 0, float.PositiveInfinity);

       
        batch.AddConstraint(rope.solverIndices[blueprint.activeParticleCount - 1],
                            ropeEnd.GetComponent<ObiColliderBase>(),
                            //ropeEnd.position,
                            //ropeEnd.InverseTransformPoint(ropeStart.position),
                            Vector3.zero,
                            Quaternion.identity, 0, 0, float.PositiveInfinity);

        batch.activeConstraintCount = 2;
        pinConstraints.AddBatch(batch);

        rope.SetConstraintsDirty(Oni.ConstraintType.Pin);
    } 

  
    public void RopeIncrease()
    {
        cursor.ChangeLength(rope.restLength + hookExtendRetractSpeed * Time.deltaTime);
    }
    public void RopeDecrease()
    {
        cursor.ChangeLength(rope.restLength - hookExtendRetractSpeed * Time.deltaTime );

    }

    public float GetStrain()
    {
        float strain = rope.restLength / rope.CalculateLength();
        return strain;
    }

    public float GetRopeLength()
    {
        return rope.CalculateLength();
    }
}

Code:
public class CapsuleMove : MonoBehaviour
{
    [SerializeField]RopeCreate ropeCreate;
    [Header("Move")]
    const float speed = 500f;
   
    private Vector3 mOffset;
    private float mZCoord;
    private bool active;
    private Rigidbody2D rb;
    float startRotation;

    [SerializeField] public bool isRopeLengthMax = false;

    public Vector2 startPos;

    private Vector2 previousPosition;
    private void Start()
    {
        rb = GetComponent<Rigidbody2D>();

      
    }

    private void OnMouseDown()
    {
       

        mZCoord = Camera.main.WorldToScreenPoint(transform.position).z;
        mOffset = transform.position - GetMouseAsWorldPoint();
        active = true;
        rb.velocity = Vector2.zero;
        rb.gravityScale = 0f;
       
        rb.constraints &= ~RigidbodyConstraints2D.FreezePositionX;
        rb.constraints &= ~RigidbodyConstraints2D.FreezePositionY;

    }

    private void OnMouseUp()
    {
        MouseDownEnded();
    }
    private void MouseDownEnded()
    {
        active = false;
        rb.gravityScale = 1f;
        rb.velocity = Vector2.zero;
        // rb.freezeRotation = true;
        rb.constraints = RigidbodyConstraints2D.FreezePositionX | RigidbodyConstraints2D.FreezePositionY | RigidbodyConstraints2D.FreezeRotation;       
    }

    private Vector3 GetMouseAsWorldPoint()
    {
        Vector3 mousePoint = Input.mousePosition;
        mousePoint.z = mZCoord;
        return Camera.main.ScreenToWorldPoint(mousePoint);
    }

    private void FixedUpdate()
    {
       
        if (isRopeLengthMax)
        {
            MouseDownEnded();

            return;
        }
        if (active)
        {

            Vector2 desiredPosition = (Vector2)(GetMouseAsWorldPoint() + mOffset);
            Vector2 direction = desiredPosition - rb.position;
            rb.velocity = direction.magnitude > 0.1f ? direction * Time.fixedDeltaTime * speed : Vector2.zero;

           

            float distanceMoved = Vector2.Distance(rb.position, previousPosition);
            if (distanceMoved < 0.05f)
            {
                return;
            }

            if (ropeCreate.GetStrain() > .9)
            {
                ropeCreate.RopeDecrease();
            }
            else
            {
                ropeCreate.RopeIncrease();
               // Debug.Log("Lenght" + ropeCreate.GetRopeLength());
            }

            previousPosition = rb.position;

        }
    }
}
Reply
#2
(19-04-2025, 08:00 AM)0hsyn1 Wrote: Hello,
I am developing a project using the system in your Hook project as a reference. I can lengthen and shorten the rope, but the rope has problems interacting with colliders, as far as I understand the particle count is low. How can I increase this?

Hi,

Increase the rope blueprint's resolution, which in your code is currently set to 0.5f. See the manual for details:
https://obi.virtualmethodstudio.com/manu...setup.html

You can also enable surface collisions. See:
https://obi.virtualmethodstudio.com/manu...sions.html

kind regards,
Reply
#3
(19-04-2025, 09:09 AM)josemendez Wrote: Hi,

Increase the rope blueprint's resolution, which in your code is currently set to 0.5f. See the manual for details:
https://obi.virtualmethodstudio.com/manu...setup.html

You can also enable surface collisions. See:
https://obi.virtualmethodstudio.com/manu...sions.html

kind regards,
Thanks for your quick reply, I was able to increase the number of particles.

But when I check the collision section and start wrapping the rope around the obstacle, vibrations occur. Can particles be affected by each other?
Reply
#4
(19-04-2025, 10:15 AM)0hsyn1 Wrote: But when I check the collision section and start wrapping the rope around the obstacle, vibrations occur.

I'm not sure about the nature of these "vibrations" you mention. Would it be possible for you to share a video of this?

(19-04-2025, 10:15 AM)0hsyn1 Wrote: Can particles be affected by each other?

Yes, they're already affected by each other in lots of ways: distance constraints keep them at a specific distance from each other, bend constraints try to keep them in a line as straight as possible, surface collisions make them react when a neighbor particle collides, etc.

kind regards,
Reply
#5
(22-04-2025, 06:37 PM)josemendez Wrote: I'm not sure about the nature of these "vibrations" you mention. Would it be possible for you to share a video of this?


Yes, they're already affected by each other in lots of ways: distance constraints keep them at a specific distance from each other, bend constraints try to keep them in a line as straight as possible, surface collisions make them react when a neighbor particle collides, etc.

kind regards,

I'm sharing a video, even though I increased the particle frequency, it can pass through when I move it a little faster.

Hey,
I marked the obi rigidbody kinamatics inside the obstacle I wrapped and rope.selfCollisions = false;
rope.surfaceCollisions = false; and the shaking stopped.

My only problem right now is to reduce the tension of the rope. Sometimes it can be too loose.
Another thing I want to ask is, can I access the position list of this rope? I will use it as a path to an object


Attached Files Thumbnail(s)
   
Reply
#6
(23-04-2025, 02:46 PM)0hsyn1 Wrote: I'm sharing a video, even though I increased the particle frequency, it can pass through when I move it a little faster.

May be tunneling. Set the solver's particleCCD to 1.

(23-04-2025, 02:46 PM)0hsyn1 Wrote: ht now is to reduce the tension of the rope. Sometimes it can be too loose.

Crank up the amount of substeps in your ObiSolver.

(23-04-2025, 02:46 PM)0hsyn1 Wrote: Another thing I want to ask is, can I access the position list of this rope? I will use it as a path to an object

Yes, you can access all particle properties in any actor.

For your purpose however, it's best to grab the position from the path smoother instead of rope particles, since it will give a smooth, continuous position instead of isolated points:

Code:
var smoother = GetComponent<ObiPathSmoother>();
var position = smoother.GetSectionAt(normalizedCoord).position;

normalizedCoord varies from 0 (start of the rope) to 1 (end of the rope). You can see an example implementation of a component that places an object along the rope in Obi/Scripts/RopeAndRod/Utils/ObiRopeAttach.cs

kind regards
Reply
#7
Code:
public void OnRopeContactEnter(ObiSolver solver, Oni.Contact contact)
{
     var world = ObiColliderWorld.GetInstance();
     var col = world.colliderHandles[contact.bodyB].owner;

     if (col != null && col.GetComponent<Item>() != null && !col.GetComponent<Item>().ColliderTriggerControl())
     {
         if (!GameManager.instance.usedItems.Contains(col.GetComponent<Item>()))
         {
             GameManager.instance.UsedItemsAdd(col.GetComponent<Item>());
           
             Debug.Log("Contact: " + col.name);

             
             int particleIndex = contact.bodyA;
             Vector2 contactPoint = solver.positions[particleIndex] + contact.normal * contact.distance;


         }
     }
}

How do I find the value of "normalizedCoord"?
Can I find a value that corresponds to the "M" value in the Obi Rope Attach code?
I need the collision value of the item with the rope (e.g. 0.658f) to be able to launch the object from that point.
Reply
#8
(27-04-2025, 07:43 PM)0hsyn1 Wrote: [code]
How do I find the value of "normalizedCoord"?
Can I find a value that corresponds to the "M" value in the Obi Rope Attach code?
“M” and “normalizedCoord” in my previous message represent the same value.

(27-04-2025, 07:43 PM)0hsyn1 Wrote: I need the collision value of the item with the rope (e.g. 0.658f) to be able to launch the object from that point.

Just divide the index of the particle by the total amount of active particles in the rope. This will give you a value in the 0-1 range.

Kind regards,
Reply
#9
(27-04-2025, 10:28 PM)josemendez Wrote: “M” and “normalizedCoord” in my previous message represent the same value.


Just divide the index of the particle by the total amount of active particles in the rope. This will give you a value in the 0-1 range.

Kind regards,

I am using this code but I am not getting the result I want, where am I going wrong?

My code;
Code:
int particleIndex = contact.bodyA;
Vector2 contactPoint = solver.positions[particleIndex] + contact.normal * contact.distance;


int activeParticleCount = rope.activeParticleCount;

float mu = 0;

if (activeParticleCount > 1)
     mu = (float)particleIndex / (activeParticleCount-1);

col.GetComponent<Item>().muValue =(mu);

Debug.Log("mu: " + mu);


   

Even if I try it in reverse as "1f-mu", I can't get the result I want.

As an additional question, I am extending this rope and I need to reset it to its initial state at the end of the game. How can I proceed?
Reply
#10
(28-04-2025, 06:38 AM)0hsyn1 Wrote: I am using this code but I am not getting the result I want, where am I going wrong?

My code;
Code:
int particleIndex = contact.bodyA;

contact.bodyA is not a particle index. To get the index of the particle in the actor, use the solver.simplices array and then look up solver.particleInActor to get the index of that particle in the rope. See "Retrieving the particle involved in a contact" in the manual: https://obi.virtualmethodstudio.com/manu...sions.html

(28-04-2025, 06:38 AM)0hsyn1 Wrote: As an additional question, I am extending this rope

If you're altering the topology of the rope in any way (extending/retracting/cutting the rope) the above approach using particles won't work. The reason is that there's no guarantee new particles (added when extending the rope) will be added at the end/start of the rope, so their indices may be unordered. You must use elements instead as explained in the manual: https://obi.virtualmethodstudio.com/manu...ropes.html

The approach is similar: get a particle index from the contact, then iterate over all elements until you find the one that references that particle. Once you have the index of the desired element, divide it by the number of elements in the rope to get the normalized coordinate.

(28-04-2025, 06:38 AM)0hsyn1 Wrote: and I need to reset it to its initial state at the end of the game. How can I proceed?

Simply reloading the original rope blueprint (by assigning it to rope.ropeBlueprint) should do it.

kind regards,
Reply