(01-12-2021, 08:32 AM)josemendez Wrote: Hi!
Contacts can be between a simplex and a collider, or between two simplices. If you subscribe to solver.OnCollision, contact.bodyA will always be a simplex index and contact.bodyB will always be a collider index. See: http://obi.virtualmethodstudio.com/manua...sions.html
If you subscribe to solver.OnParticleCollision, both bodyA and bodyB will always be simplex indices. For some reason, in your code you're using bodyA and bodyB to try and access the global collider array:
Code:ObiColliderBase colB = world.colliderHandles[contact.bodyB].owner;
ObiColliderBase colA = world.colliderHandles[contact.bodyA].owner;
Which will almost always cause an out of range exception.
To understand why, think about what would happen if you had 3 colliders and 10 simplices in your scene: if simplices 5 and 9 collide with each other, you will get a contact such that bodyA is 5 and bodyB is 9. You then try to access positions 5 and 9 in the world.colliderHandles array that only has 3 entries (because there's only 3 colliders in the scene), so you're essentially asking Unity to access data that doesn't exist ----> the error is trying to tell you that the index used to access that array is out of range: to access an array of size 3, you can only use indices 0,1 and 2.
This code deals with simplex-simplex collisions, so no need to check for colliders.
Code:foreach (Oni.Contact contact in e.contacts)
{
int particleIndexA = solver.simplices[contact.bodyA];
int particleIndexB = solver.simplices[contact.bodyB];
// retrieve the actor this particle belongs to:
ObiSolver.ParticleInActor paA = solver.particleToActor[particleIndexA];
ObiSolver.ParticleInActor paB = solver.particleToActor[particleIndexB];
var actorA = paA.actor as ObiRope;
var actorB = paB.actor as ObiRope;
actorA.GetComponent<RopeController>().CheckContact(actorB);
}
Thanks, i have another problem now.
It's rare, but it says that even if I pull the strings away from each other, they are in contact with each other. not sure, but this happens after partial thinning after another contact. I don't know if it's relevant. Here's the code I'm using right now:
Code:
using System;
using System.Collections.Generic;
using UnityEngine;
using Obi;
namespace _Game.Scripts.Entities.Rope
{
[RequireComponent(typeof(ObiSolver))]
public class RopeCutter : MonoBehaviour
{
private ObiSolver solver;
public GameObject[] damagezone;
void Awake(){
solver = GetComponent<ObiSolver>();
}
void OnEnable () {
solver.OnCollision += Solver_OnCollision;
solver.OnParticleCollision += Solver_OnParticleCollision;
}
void OnDisable(){
solver.OnCollision -= Solver_OnCollision;
solver.OnParticleCollision -= Solver_OnParticleCollision;
}
void Solver_OnCollision(object sender, ObiSolver.ObiCollisionEventArgs e)
{
var world = ObiColliderWorld.GetInstance();
// just iterate over all contacts in the current frame:
foreach (Oni.Contact contact in e.contacts)
{
// if this one is an actual collision:
ObiColliderBase col = world.colliderHandles[contact.bodyB].owner;
if (col != null)
{
// if (col.CompareTag("saw"))
//{
//TearRope(col, contact);
//}
if (col.CompareTag("saw"))
{
DamageRope(contact);
}
}
}
}
private void DamageRope(Oni.Contact contact)
{
// get the particle index:
int particleIndex = solver.simplices[contact.bodyA];
// retrieve the actor this particle belongs to:
ObiSolver.ParticleInActor pa = solver.particleToActor[particleIndex];
var actor = pa.actor as ObiRope;
// not a rope, stop:
if (actor == null) return;
if (actor.GetComponent<RopeController>().GetCanDamage())
{
StartCoroutine(actor.GetComponent<RopeController>().SetCanDamage());
float i = -1;
// check rope elements and tear the one that references this particle:
foreach (var elm in actor.elements)
{
i++;
if (elm.particle1 == particleIndex)
{
if (actor.GetComponent<RopeController>().run)
{
var obj = Instantiate(damagezone[actor.GetComponent<RopeController>().GetRopeColorIndex()]);
obj.GetComponent<TearedRope>().SetTearedRope(actor, solver, elm, i);
}
//actor.Tear(elm);
break;
}
}
}
}
private void Solver_OnParticleCollision(object sender, ObiSolver.ObiCollisionEventArgs e)
{
var world = ObiColliderWorld.GetInstance();
foreach (var contact in e.contacts)
{
// this one is an actual collision:
if (contact.distance < 0.01)
{
var pa = solver.particleToActor[contact.bodyA];
var po = solver.particleToActor[contact.bodyB];
if (pa != null && po != null)
{
//if (pa !=po)
if (pa.actor != null && po.actor != null)
{
if (pa.actor.gameObject != po.actor.gameObject)
{
Debug.Log(po.actor.gameObject + "'dan " + pa.actor.gameObject + "'ya");
(pa.actor).GetComponent<RopeController>().CheckContact(po.actor as ObiRope);
}
}
}
}
}
}
}
}
what is your suggestion?