Posts: 23
Threads: 4
Joined: Feb 2021
Reputation:
0
29-04-2025, 11:33 AM
(This post was last modified: 29-04-2025, 11:50 AM by 0hsyn1.)
(29-04-2025, 11:08 AM)josemendez Wrote: ObiNativeContactList exists in the Obi namespace. Unless you're using a rather old version of the asset, it should be found just fine.
Ok, so you're not using contact callbacks directly then? Which event are you listening for? Keep in mind that this component reports the contact that caused the event, not the particle currently in contact. So if you eg. listen for the "collision enter" event and then move the object in contact with the rope, the contact won't be updated.
kind regards,
I am using version 6.0.1. I put the code in the namespace, even though I searched the whole project, I cannot find this "ObiNativeContactList"
When I bring the end of the rope to the finish area, I activate this code "ObiContactEventDispatcher", I assigned the "OnRopeContactEnter(ObiSolver solver, Oni.Contact contact)" function in another script to the onContactEnter event, so I can get the gameObjects that touch the rope.
What I want next is to create a gameObject at that contact point and move it to the end of the rope.
I want to do this movement as in your suggested "ObiRopeAttach" script. But I can't find the "M" value there correctly. The results, as in the picture I posted before, are irrelevant to the contact points. For example; It can be 0.58 when it should be 0.35f.
Update Info: I managed to get the code to work like this, I'm testing it
Code: using static Obi.ObiSolver;
namespace Obi
{
public class RopeContactNormalized : MonoBehaviour
{
public ObiRope rope;
// Start is called before the first frame update
void Start()
{
rope.solver.OnCollision += OnRopeContactEnter;
}
public void OnRopeContactEnter(ObiSolver solver, ObiCollisionEventArgs collisionEvent)
{
var world = ObiColliderWorld.GetInstance();
float normalizedCoordinate = -1;
var contacts = collisionEvent.contacts;
for (int i = 0; i < contacts.Count; ++i)
{
var contact = contacts[i];
if (contact.distance > 0.001f) continue;
int particleIndex = solver.simplices[contact.bodyA];
var col = world.colliderHandles[contact.bodyB].owner;
if (rope != null)
{
var elements = rope.elements;
int elementIndex = -1;
for (int j = 0; j < elements.Count; ++j)
{
var element = elements[j];
if (element.particle1 == particleIndex || element.particle2 == particleIndex)
{
elementIndex = j;
break;
}
}
if (elementIndex != -1)
{
normalizedCoordinate = (float)elementIndex / elements.Count;
Debug.Log("Normalized rope position: " + normalizedCoordinate);
break;
}
else
{
Debug.LogWarning("Element not found for particle " + particleIndex);
}
}
else
{
Debug.LogWarning("Rope reference is missing!");
}
}
if (normalizedCoordinate >= 0)
{
var smoother = rope.GetComponent<ObiPathSmoother>();
if (smoother != null)
{
var section = smoother.GetSectionAt(normalizedCoordinate);
Debug.DrawRay(section.position, section.normal, Color.red);
}
}
}
}
}
Posts: 6,466
Threads: 27
Joined: Jun 2017
Reputation:
413
Obi Owner:
29-04-2025, 12:18 PM
(This post was last modified: 29-04-2025, 12:18 PM by josemendez.)
(29-04-2025, 11:33 AM)0hsyn1 Wrote: I am using version 6.0.1. I put the code in the namespace, even though I searched the whole project, I cannot find this "ObiNativeContactList"
6.0.1 is already 5 years old. ObiNativeContactList was added later on during the 6.X cycle. For 6.0, use ObiCollisionEventArgs as the second argument of the callback instead. Looks like you already discovered this  .
(29-04-2025, 11:33 AM)0hsyn1 Wrote: Update Info: I managed to get the code to work like this, I'm testing it
Good to hear, let me know if you need further help.
kind regards,
Posts: 23
Threads: 4
Joined: Feb 2021
Reputation:
0
29-04-2025, 12:32 PM
(This post was last modified: 29-04-2025, 12:57 PM by 0hsyn1.)
(29-04-2025, 12:18 PM)josemendez Wrote: 6.0.1 is already 5 years old. ObiNativeContactList was added later on during the 6.X cycle. For 6.0, use ObiCollisionEventArgs as the second argument of the callback instead. Looks like you already discovered this .
Good to hear, let me know if you need further help.
kind regards,
If I want to switch to the new version, will I have a problem in my project?
I can't add this code "public void OnRopeContactEnter(ObiSolver solver, ObiCollisionEventArgs collisionEvent)" to the "onContactEnter" event in ObiContactEventDispatcher
Also, my project is 2d, does this cause any problems in finding the "M" value?
I have another question, when I move the object to which I attached the rope, the rope does not stick to the object completely, why? I use Particle Attechment
Posts: 6,466
Threads: 27
Joined: Jun 2017
Reputation:
413
Obi Owner:
29-04-2025, 01:14 PM
(This post was last modified: 29-04-2025, 01:19 PM by josemendez.)
(29-04-2025, 12:32 PM)0hsyn1 Wrote: If I want to switch to the new version, will I have a problem in my project?
It's hard to say, but most likely yes. There's many differences between versions 6 and 7, and your version is one of the oldest in the 6.X cycle so I'd avoid updating.
(29-04-2025, 12:32 PM)0hsyn1 Wrote: I can't add this code "public void OnRopeContactEnter(ObiSolver solver, ObiCollisionEventArgs collisionEvent)" to the "onContactEnter" event in ObiContactEventDispatcher
That doesn't make any sense whatsoever. In C#, the signature of the method you subscribe to an event must match the delegate.
The onContactEnter event in ObiContactEventDispatcher is triggered when a particle belonging to the actor first touches a collider. On the other hand, the method taking ObiCollisionEventArgs as argument is subscribed to the solver's OnCollision event, which returns all collisions that took place during the last simulation step. It's two completely different things, and I'm not sure which one you want. Would you mind clarifying what your goal is? You previously mentioned this:
(29-04-2025, 12:32 PM)0hsyn1 Wrote: I activate this code "ObiContactEventDispatcher", I assigned the "OnRopeContactEnter(ObiSolver solver, Oni.Contact contact)" function in another script to the onContactEnter event, so I can get the gameObjects that touch the rope.
This is not what ObiContactEventDispatcher's onContactEnter does: to get the gameObjects currently touching the rope, you should use solver.OnCollision and iterate trough all contacts as in the example script I shared. If you use ObiContactEventDispatcher, you'll get a single contact when the rope approaches an object, but it may or may not be the one currently in contact with it.
(29-04-2025, 12:32 PM)0hsyn1 Wrote: Also, my project is 2d, does this cause any problems in finding the "M" value?
Not at all. The engine works the same way both in 2D and 3D, 2D is just one spatial coordinate less.
(29-04-2025, 12:32 PM)0hsyn1 Wrote: I have another question, when I move the object to which I attached the rope, the rope does not stick to the object completely, why? I use Particle Attachment
Is it a dynamic or static attachment? If it's a dynamic one, how are you moving the object the rope is attached to?
kind regards
Posts: 23
Threads: 4
Joined: Feb 2021
Reputation:
0
29-04-2025, 02:14 PM
(This post was last modified: 29-04-2025, 02:39 PM by 0hsyn1.)
(29-04-2025, 01:14 PM)josemendez Wrote: It's hard to say, but most likely yes. There's many differences between versions 6 and 7, and your version is one of the oldest in the 6.X cycle so I'd avoid updating.
That doesn't make any sense whatsoever. In C#, the signature of the method you subscribe to an event must match the delegate.
The onContactEnter event in ObiContactEventDispatcher is triggered when a particle belonging to the actor first touches a collider. On the other hand, the method taking ObiCollisionEventArgs as argument is subscribed to the solver's OnCollision event, which returns all collisions that took place during the last simulation step. It's two completely different things, and I'm not sure which one you want. Would you mind clarifying what your goal is? You previously mentioned this:
This is not what ObiContactEventDispatcher's onContactEnter does: to get the gameObjects currently touching the rope, you should use solver.OnCollision and iterate trough all contacts as in the example script I shared. If you use ObiContactEventDispatcher, you'll get a single contact when the rope approaches an object, but it may or may not be the one currently in contact with it.
Not at all. The engine works the same way both in 2D and 3D, 2D is just one spatial coordinate less.
Is it a dynamic or static attachment? If it's a dynamic one, how are you moving the object the rope is attached to?
kind regards This is what I want "The onContactEnter event in ObiContactEventDispatcher is triggered when a particle belonging to the actor first touches a collider." and using the rope as a path from that point to the end.
Is there a place or method where I can see which of the black dots appearing in the Obi particle Renderer are touching and where I can get the world positions of all the black dots? I can create the path myself from there.
I made the fixed point static, the moving point dynamic. The object to which the rope is attached moves with Vector2 lerp. The target position is the position of the gameObject that I move with the rigidbody.
Posts: 6,466
Threads: 27
Joined: Jun 2017
Reputation:
413
Obi Owner:
29-04-2025, 03:45 PM
(This post was last modified: 29-04-2025, 04:18 PM by josemendez.)
(29-04-2025, 02:14 PM)0hsyn1 Wrote: This is what I want "The onContactEnter event in ObiContactEventDispatcher is triggered when a particle belonging to the actor first touches a collider." and using the rope as a path from that point to the end.
Then your original code using ObiContactEventDispatcher will do that. But judging from some other of your posts I was under the impression that it's not what you wanted... so I'm still a bit confused.
(29-04-2025, 02:14 PM)0hsyn1 Wrote: Is there a place or method where I can see which of the black dots appearing in the Obi particle Renderer are touching
Yes, that's what solver.OnCollision does. It's what I used in the script I shared: it iterate trough all contacts ("touch points" between particles and objects) and then finds the normalized coordinate for one of the touches.
(29-04-2025, 02:14 PM)0hsyn1 Wrote: and where I can get the world positions of all the black dots?
Yes, you can iterate over rope.solverIndices and retrieve the position of all particles from the solver.positions array. See the particles API page in the manual.
(29-04-2025, 02:14 PM)0hsyn1 Wrote: I made the fixed point static, the moving point dynamic. The object to which the rope is attached moves with Vector2 lerp. The target position is the position of the gameObject that I move with the rigidbody.
That doesn't make much sense. Dynamic attachments are meant to attach particles to a rigidbody that's moved using physics (setting their velocity, or adding forces to them), since they apply forces to both the rope and the attached rigidbody. If you use a dynamic attachment to an object, but then you move it using Vector2 lerp you're effectively defeating the point of using a dynamic attachment.
Either attach the rope to the rigidbody directly (not to an object that is then lerp'ed towards a rigidbody) or use a static attachment.
kind regards,
Posts: 6,466
Threads: 27
Joined: Jun 2017
Reputation:
413
Obi Owner:
29-04-2025, 04:09 PM
(This post was last modified: 29-04-2025, 04:17 PM by josemendez.)
(29-04-2025, 02:14 PM)0hsyn1 Wrote: This is what I want "The onContactEnter event in ObiContactEventDispatcher is triggered when a particle belonging to the actor first touches a collider." and using the rope as a path from that point to the end.
I tested this code (which is what your original code does I think, plus the corrections added throughout this thread) and it works correctly for me, or at least the way I think you want it to work:
Code: using UnityEngine;
using Obi;
public class RopeContactNormalized : MonoBehaviour
{
public ObiRope rope;
// Start is called before the first frame update
void Start()
{
GetComponent<ObiContactEventDispatcher>().onContactEnter.AddListener(OnRopeContactEnter);
}
public void OnRopeContactEnter(ObiSolver solver, Oni.Contact contact)
{
var world = ObiColliderWorld.GetInstance();
float normalizedCoordinate = -1;
int particleIndex = solver.simplices[contact.bodyA];
var col = world.colliderHandles[contact.bodyB].owner;
if (rope != null)
{
var elements = rope.elements;
int elementIndex = -1;
for (int i = 0; i < elements.Count; ++i)
{
var element = elements[i];
if (element.particle1 == particleIndex || element.particle2 == particleIndex)
{
elementIndex = i;
break;
}
}
if (elementIndex != -1)
{
normalizedCoordinate = (float)elementIndex / elements.Count;
Debug.Log("Normalized rope position: " + normalizedCoordinate);
}
else
{
Debug.LogWarning("Element not found for particle " + particleIndex);
}
}
else
{
Debug.LogWarning("Rope reference is missing!");
}
if (normalizedCoordinate >= 0)
{
var section = rope.GetComponent<ObiPathSmoother>().GetSectionAt(normalizedCoordinate);
Debug.DrawRay(section.position, section.normal, Color.red,10);
}
}
}
|