Obi Official Forum

Full Version: Help with creating rope on runtime
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hello, first off I want to say it's amazing asset, have messed around with it in the editor and everything worked as expected, however I have problems achieving the same on runtime.

I have checked the example code on 1 of your pages, but it seemed outdated. I have tried various things but can't seem to get it to work. I have tried the following code:


Code:
public class RopeGenerator : MonoBehaviour {

    private ObiRope rope;
    private ObiCurve path;
    private ObiSolver solver;
    private ObiRopeExtrudedRenderer ropeextruder;
    private ObiRopeCursor cursor;
    private MeshRenderer render;

    public Material RopeMaterial;

    public IEnumerator MakeRope(Transform fromtrans, Transform totrans, float ropeLength)
    {
        GameObject ropeObject = new GameObject("HitchRope", typeof(ObiSolver),
                                typeof(ObiRope),
                                typeof(ObiCurve),
                                typeof(ObiRopeExtrudedRenderer),
                                typeof(ObiRopeCursor));

        rope = ropeObject.GetComponent<ObiRope>();
        path = ropeObject.GetComponent<ObiCurve>();
        solver = ropeObject.GetComponent<ObiSolver>();
        ropeextruder = ropeObject.GetComponent<ObiRopeExtrudedRenderer>();
        cursor = ropeObject.GetComponent<ObiRopeCursor>();
        render = ropeObject.GetComponent<MeshRenderer>();

        rope.Solver = solver;
        rope.ropePath = path;
        ropeextruder.section = Resources.Load("DefaultRopeSection") as ObiRopeSection;

        render.material = RopeMaterial;
        
        ropeextruder.uvScale = new Vector2(1, 10);
       
        yield return rope.StartCoroutine(rope.GeneratePhysicRepresentationForMesh());

        cursor.ChangeLength(20);

        GameObject HandleObject01 = new GameObject("Obi Handle01", typeof(ObiParticleHandle));
        GameObject HandleObject02 = new GameObject("Obi Handle02", typeof(ObiParticleHandle));

        ObiParticleHandle handle01 = HandleObject01.GetComponent<ObiParticleHandle>();
        handle01.Actor = rope;
        handle01.AddParticle(0, fromtrans.position, Quaternion.identity, rope.invMasses[0], rope.invRotationalMasses[0]);
        handle01.AddParticle(1, fromtrans.position, Quaternion.identity, rope.invMasses[1], rope.invRotationalMasses[1]);  

        ObiParticleHandle handle02 = HandleObject02.GetComponent<ObiParticleHandle>();

        handle02.Actor = rope;
        int index = rope.UsedParticles - 1;
        handle02.AddParticle(index, totrans.position, Quaternion.identity, rope.invMasses[index], rope.invRotationalMasses[index]);
        handle02.AddParticle(index - 1, totrans.position, Quaternion.identity, rope.invMasses[index - 1], rope.invRotationalMasses[index - 1]);
        rope.AddToSolver(null);
    }
}
However I get an nullreferenceexception. that occurs in ObiRopeCursor.cs line 101.

The rope does appear in the scene tho. The effect I am going for is to generate a rope between 2 object where 1 of the objects could be both static or a moving object and the other object is always a moving object.

Help would be very much appreciated.
(06-06-2019, 12:00 PM)Smurfj3 Wrote: [ -> ]Hello, first off I want to say it's amazing asset, have messed around with it in the editor and everything worked as expected, however I have problems achieving the same on runtime.

I have checked the example code on 1 of your pages, but it seemed outdated. I have tried various things but can't seem to get it to work. I have tried the following code:


Code:
public class RopeGenerator : MonoBehaviour {

    private ObiRope rope;
    private ObiCurve path;
    private ObiSolver solver;
    private ObiRopeExtrudedRenderer ropeextruder;
    private ObiRopeCursor cursor;
    private MeshRenderer render;

    public Material RopeMaterial;

    public IEnumerator MakeRope(Transform fromtrans, Transform totrans, float ropeLength)
    {
        GameObject ropeObject = new GameObject("HitchRope", typeof(ObiSolver),
                                typeof(ObiRope),
                                typeof(ObiCurve),
                                typeof(ObiRopeExtrudedRenderer),
                                typeof(ObiRopeCursor));

        rope = ropeObject.GetComponent<ObiRope>();
        path = ropeObject.GetComponent<ObiCurve>();
        solver = ropeObject.GetComponent<ObiSolver>();
        ropeextruder = ropeObject.GetComponent<ObiRopeExtrudedRenderer>();
        cursor = ropeObject.GetComponent<ObiRopeCursor>();
        render = ropeObject.GetComponent<MeshRenderer>();

        rope.Solver = solver;
        rope.ropePath = path;
        ropeextruder.section = Resources.Load("DefaultRopeSection") as ObiRopeSection;

        render.material = RopeMaterial;
        
        ropeextruder.uvScale = new Vector2(1, 10);
       
        yield return rope.StartCoroutine(rope.GeneratePhysicRepresentationForMesh());

        cursor.ChangeLength(20);

        GameObject HandleObject01 = new GameObject("Obi Handle01", typeof(ObiParticleHandle));
        GameObject HandleObject02 = new GameObject("Obi Handle02", typeof(ObiParticleHandle));

        ObiParticleHandle handle01 = HandleObject01.GetComponent<ObiParticleHandle>();
        handle01.Actor = rope;
        handle01.AddParticle(0, fromtrans.position, Quaternion.identity, rope.invMasses[0], rope.invRotationalMasses[0]);
        handle01.AddParticle(1, fromtrans.position, Quaternion.identity, rope.invMasses[1], rope.invRotationalMasses[1]);  

        ObiParticleHandle handle02 = HandleObject02.GetComponent<ObiParticleHandle>();

        handle02.Actor = rope;
        int index = rope.UsedParticles - 1;
        handle02.AddParticle(index, totrans.position, Quaternion.identity, rope.invMasses[index], rope.invRotationalMasses[index]);
        handle02.AddParticle(index - 1, totrans.position, Quaternion.identity, rope.invMasses[index - 1], rope.invRotationalMasses[index - 1]);
        rope.AddToSolver(null);
    }
}
However I get an nullreferenceexception. that occurs in ObiRopeCursor.cs line 101.

The rope does appear in the scene tho. The effect I am going for is to generate a rope between 2 object where 1 of the objects could be both static or a moving object and the other object is always a moving object.

Help would be very much appreciated.

You cannot change the length of a rope that's not added to any solver, because the solver arrays are still null. move the "rope.AddToSolver(null);" line right after calling the rope.GeneratePhysicRepresentationForMesh() coroutine.

After that, there's also a couple other issues with your code. Ropes do not use oriented particles, so their invRotationalMasses array is null. Pass "1" as their inverse rotational mass instead, in the AddParticle() calls.

cheers,
Awesome thanks for the quick reply and indeed got it all working now, is there a page that explains more about the Solver since I don't understand why it actually works now. I find the line 'rope.AddToSolver(null);' very confusing.
(06-06-2019, 04:34 PM)Smurfj3 Wrote: [ -> ]Awesome thanks for the quick reply and indeed got it all working now, is there a page that explains more about the Solver since I don't understand why it actually works now. I find the line 'rope.AddToSolver(null);' very confusing.

Hi,

There's a description of how the overall architecture is designed here:
http://obi.virtualmethodstudio.com/tutor...cture.html

Quoting the manual, here's what happens when AddToSolver() is called:
Quote:Now, the basic steps that take place when an ObiActor gets added to an ObiSolver are:
  • ObiActor borrows a handful of particles from its ObiSolver, and sets their initial properties.
  • ObiActor asks its ObiConstraints components to generate constraints of multiple kinds between these particles.
  • In turn, each ObiConstraints component asks the ObiSolver to put these constraints in place
.

So basically, you first tell the actor which solver will be in charge of managing it:
Quote:actor.Solver = solver;
Then, you can AddToSolver() (particles and constraints needed to simulate the actor are allocated by the solver) or RemoveFromSolver() (the actor particles/constraints are deallocated and returned to the solver pool).