Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Climbing on rope and fix to move only on x, y
#1
Pregunta 
Hello there,

I created this rope climbing with Unity joints:

https://youtu.be/mePXonwqEN0

Also this is a 2d game in a 3d world so I just tilted the z axis movement on the rope..

Can I do this two things with ObiRope better/cheaper than joints? Can I create a climbing system?

Thanks
Reply
#2
Yes, Obi can do this both more efficiently and better-looking. However Obi uses a completely different paradigm than the built-in physics engine (Obi is a particle-based, position-based engine, while Unity's is a rigidbody-based, velocity-based engine). It can take a while to get used to it.

So if you have some spare time to learn Obi, I'd give it a try. If you're short on time or you need to get your game out asap, better stick to your already-working system.

kind regards!
Reply
#3
Basically my old rope wich is using unity character joints is my probleme. It is just breaking every time when I attach colliders to it. So a unity rope with 3-4 segment is good but if you have more colliders and joints then the physics just kill the rope...

Is it very hard to create an Obi rope that can a player climb? Now I am using raycasts or sphere cast on the old rope and that is working good. 

How can I do this effect with Obi?
Reply
#4
(29-09-2021, 07:48 PM)lacasrac Wrote: Is it very hard to create an Obi rope that can a player climb?

Depends on how familiar you are with 3d matrix/vector math. If you can convert data back and forth between local/world space, and understand some basic vector stuff (dot/cross product, projection, normalization, etc), it should be fairly easy once you get used to Obi's particle-based approach.

Quote:Now I am using raycasts or sphere cast on the old rope and that is working good. 

You can use these with Obi too:
http://obi.virtualmethodstudio.com/manua...eries.html
Reply
#5
(30-09-2021, 08:11 AM)josemendez Wrote: Depends on how familiar you are with 3d matrix/vector math. If you can convert data back and forth between local/world space, and understand some basic vector stuff (dot/cross product, projection, normalization, etc), it should be fairly easy once you get used to Obi's particle-based approach.


You can use these with Obi too:
http://obi.virtualmethodstudio.com/manua...eries.html

Is there any way to get the neighbour particle/segment of the rope?
So basically:

I got a particle position when colliding my player's collider with the rope. Now I need to get the bottom and top particle from that particle.
How can I do this?  Or just get the 10. neightbor of the particle:

Something like this:

particleNowIndex

GetParticleAbove() => particles[particleNowIndex+1]
GetParticleBelow() => particles[particleNowIndex-1]

GetNextParticle(int plusIndex) => particles[particleNowIndex+plusIndex]

GetNextParticle(-1)
GetNextParticle(+1)
GetNextParticle(-10)
GetNextParticle(+10)

Colision detected via Solver_OnCollision

foreach (var contact in e.contacts)
{
    var collision = world.colliderHandles[contact.bodyB].owner;

    if (contact.distance < 0.025f)
    {
    ....
       _handTouchedChainIndex = contact.bodyA;
    } 
}


void SwingOnRope() {

   var handTouchedChainPosition = solver.positions[_handTouchedChainIndex];

}

Reply
#6
Ropes simply store a list of elements, and a list of particles. Elements are guaranteed to appear in the list in the same order they do in the rope, particles don't. Each element contains the solver indices of the 2 particles at its ends. This is all the info you can work with.

So finding the nth neighbor of a particle is very simple: you first need to find the first element that references it, and then just count "n" elements up/down of it. This can be done in linear time.

I wrote this method off the top of my head, haven't tested it but should work unless morning coffee hasn't kicked in yet. Returns the solver index of the nth neighbor particle. Takes a rope, actor index and neighbor offset as parameters:

Code:
int GetParticleNeighborIndex(ObiRopeBase rope, int particleIndex, int offset)
{
        int solverIndex = rope.solverIndices[particleIndex];
        int elementCount = rope.elements.Count;

        // find element for the current particle:
        int e = 0;
        for (; e < elementCount; ++e)
            if (rope.elements[e].particle1 == solverIndex) break;

        // return solver index of nth neighbor (accounting for special cases)
        if (e == elementCount - 1 && offset > 0)
            return rope.elements[e].particle2;
        else
        {
            int n = Mathf.Clamp(e + offset, 0, elementCount - 1);
            return rope.elements[n].particle1;
        }
    }

Also, keep in mind you could cache your current element to avoid having to iterate trough all elements every time you ask for a neighbor. If you know where in the rope you currently are, you can just go up and down from there in constant time.
Reply
#7
(05-10-2021, 09:00 AM)josemendez Wrote: Ropes simply store a list of elements, and a list of particles. Elements are guaranteed to appear in the list in the same order they do in the rope, particles don't. Each element contains the solver indices of the 2 particles at its ends. This is all the info you can work with.

So finding the nth neighbor of a particle is very simple: you first need to find the first element that references it, and then just count "n" elements up/down of it. This can be done in linear time.

I wrote this method off the top of my head, haven't tested it but should work unless morning coffee hasn't kicked in yet. Returns the solver index of the nth neighbor particle. Takes a rope, actor index and neighbor offset as parameters:

Code:
int GetParticleNeighborIndex(ObiRopeBase rope, int particleIndex, int offset)
{
        int solverIndex = rope.solverIndices[particleIndex];
        int elementCount = rope.elements.Count;

        // find element for the current particle:
        int e = 0;
        for (; e < elementCount; ++e)
            if (rope.elements[e].particle1 == solverIndex) break;

        // return solver index of nth neighbor (accounting for special cases)
        if (e == elementCount - 1 && offset > 0)
            return rope.elements[e].particle2;
        else
        {
            int n = Mathf.Clamp(e + offset, 0, elementCount - 1);
            return rope.elements[n].particle1;
        }
    }

Also, keep in mind you could cache your current element to avoid having to iterate trough all elements every time you ask for a neighbor. If you know where in the rope you currently are, you can just go up and down from there in constant time.


This code is working if I have only 1 rope in the solver, but if I put 2 ropes, I get this:

IndexOutOfRangeException: Index was outside the bounds of the array.


var solverIndex = _rope.solverIndices[particleIndex];
_MyScripts.CreateObiRope.GetParticleNeighborIndex (System.Int32 particleIndex, System.Int32 offset) (at Assets/_MyScripts/CreateObiRope.cs:332)
_MyScripts.CreateObiRope.StayOnRope () (at Assets/_MyScripts/CreateObiRope.cs:246)
_MyScripts.CreateObiRope.Climb () (at Assets/_MyScripts/CreateObiRope.cs:224)
_MyScripts.CollideObiRope.Update () (at Assets/_MyScripts/CollideObiRope.cs:76)
Reply
#8
(05-10-2021, 01:22 PM)lacasrac Wrote: This code is working if I have only 1 rope in the solver, but if I put 2 ropes, I get this:

IndexOutOfRangeException: Index was outside the bounds of the array.


var solverIndex = _rope.solverIndices[particleIndex];
_MyScripts.CreateObiRope.GetParticleNeighborIndex (System.Int32 particleIndex, System.Int32 offset) (at Assets/_MyScripts/CreateObiRope.cs:332)
_MyScripts.CreateObiRope.StayOnRope () (at Assets/_MyScripts/CreateObiRope.cs:246)
_MyScripts.CreateObiRope.Climb () (at Assets/_MyScripts/CreateObiRope.cs:224)
_MyScripts.CollideObiRope.Update () (at Assets/_MyScripts/CollideObiRope.cs:76)

You're passing a particle index that's < 0 or larger than the amount of particles in the rope. Make sure you're passing the index of the particle in the rope, not the index of the particle in the solver.
Reply
#9
I will try it tomorrow.
So basically this the first and last particle index of a rope?

private int GetFirstParticleIndex() => _rope.elements[0].particle1;

private int GetLastParticleIndex() => _rope.elements[_rope.elements.Count - 1].particle1;

I created a climb on obi rope video:

https://www.youtube.com/watch?v=XKSBt3euyxY


Can you help me how to improve? Now it is very ugly Gran sonrisa
I want something like in the Inside game... So basically if the player's foot collide with a particle then the particle attach to the player's foot and that elements between the hands + feet now moving just stay straight somehow. I tried adding to that colliding particle a fixed position but I don't know how to to that.


Also I noticed that the positions is not the ral world positions, so I added the solver's transform position to it, to get the world position.
+1: What is the Vector4 w value? Is it a big probelem is I just add a "0" to it?

public static class Vector4Utils
{
    public static Vector3 ToVector3(this Vector4 v) => new Vector3(v.x, v.y, v.z);
}

public static class Vector3Utils
{
    public static Vector4 ToVector4(this Vector3 v) => new Vector4(v.x, v.y, v.z, 0);
}


Thanks!
Reply
#10
(05-10-2021, 09:26 PM)lacasrac Wrote: So basically this the first and last particle index of a rope?

Almost. Last one should be:
private int GetLastParticleIndex() => _rope.elements[_rope.elements.Count - 1].particle2;

Look at this (terrible) diagram: "O" is a particle, "-----" is an element:

O-----O-----O-----O-----O

Each element references two particles: the second particle of element N is the first particle of element N+1.
The first particle of the first element is the first particle in the rope, and the second particle of the last element is the last particle in the rope. Like this:

(O)-----O                       O-----(O)


(05-10-2021, 09:26 PM)lacasrac Wrote: Can you help me how to improve? Now it is very ugly Gran sonrisa
I want something like in the Inside game... So basically if the player's foot collide with a particle then the particle attach to the player's foot and that elements between the hands + feet now moving just stay straight somehow. I tried adding to that colliding particle a fixed position but I don't know how to to that.

You could just fix the particles in place (by setting their inverse mass to zero, see the manual): http://obi.virtualmethodstudio.com/manua...icles.html) and then just set their positions to whatever you need.

(05-10-2021, 09:26 PM)lacasrac Wrote: Also I noticed that the positions is not the ral world positions, so I added the solver's transform position to it, to get the world position.

Yes, solver data is not expressed in world space. All particle data is expressed in the solver's local space. This is indicated throughout the manual:
http://obi.virtualmethodstudio.com/manua...olver.html

Quote:Solvers always perform the simulation in local space.

http://obi.virtualmethodstudio.com/manua...icles.html

Quote:All spatial particle properties (positions, orientations, velocities, vorticities, etc) are expressed in the solver's local space.

If you want your data expressed in world space instead you need to transform it. Unity contains functions to do just that (TransformPoint, TransformVector, TransformDirection).

If you're unfamiliar with the concept of vector spaces, they're used extensively in game making (both 2D and 3D) so better get used to them! Guiño

(05-10-2021, 09:26 PM)lacasrac Wrote: +1: What is the Vector4 w value? Is it a big probelem is I just add a "0" to it?

Quoting the manual:
http://obi.virtualmethodstudio.com/manua...icles.html

Quote:Dimensional data in Obi (such as positions and velocities) has 4 components (x,y,z,w) instead of the usual 3 (x,y,z). This is for efficiency reasons (memory alignment). You can safely ignore the fourth component in these, casting Vector4 to Vector3 whenever necessary.

So the fourth component is there to ensure 16 byte memory alignment for SIMD. It should always be zero.
Reply