1

First of all I want to say that I have already read all the related question for the problem but none of them has helped in my scenario.

Problem:

I am working with Unity and Leap Motion. I am actually instantiating some game object when some collision conditions are met by Leap Motion hands. Those game objects are basically atoms as in chemistry and are spheres.

So what I am doing is when someone rings two atoms closer to each other then they form molecule. For this I instantiate a molecule using prefab and make both atoms and bonds(also instantiated are cylinder in shape) as a child of the molecule game objects which are attached to atoms using configurable joints.

All of this is working properly but their occurs some cases when some atoms overlap each other despite having rigid body attached to them. Also I have checked that isTrigger is not checked on any of them. Also once they overlap, they do not separate at all even if I try changing value from inspector while being in play mode.

Here is the screenshot of the same.

Molecule

Code is relatively big so I am only adding code for molecule formation.

private void createBonds(MoleculeData moleculeData, Molecule molecule)
    {
        // local coords are --> in Unity Y is going up, Z is left & X is coming out of screen.. 
        // we will always keep Y of all atoms equal to each other and move them only in XZ space/plane
        // for eg if the angle between two atoms needs to be 90 degree then one atom needs to be farther on X axis and other on Z axis 
        // basically rcos(angle) & rsin(angle) to get projection in x & z axis
        // x = rsin(angle) & z = rcos(angle)

        List<Transform> allObjects = new List<Transform>();

        int numBonds = moleculeData.bonds.Count;
        float startAngle = 0;

        var centerAtomTransform = moleculeData.centralAtom.gameObject.transform;
        allObjects.Add(centerAtomTransform);

        moleculeData.centralAtom.parentMolecule = molecule;

        centerAtomTransform.localRotation = Quaternion.identity;
        centerAtomTransform.gameObject.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezeAll;

        float radiusSphere = moleculeData.centralAtom.gameObject.GetComponent<SphereCollider>().radius;
        float scale = centerAtomTransform.localScale.x; // we are assuming all scales are equal (which currently are)

        float actualRadiusOfSphere = radiusSphere * scale;

        List<Bond> allBondsFormed = new List<Bond>();

        if (moleculeData.structure == StructureType.StraightLine || moleculeData.structure == StructureType.FlatTriangle || moleculeData.structure == StructureType.Triangle)
        {
            float anglePhi = 0; // this is polar angle from positive y-axis 

            List<Vector3> positionsOnSphereBoundary = new List<Vector3>();

            for (int i = 0; i < numBonds; i++)
            {
                float xPointOnSphereBoundary = actualRadiusOfSphere * Mathf.Sin(Mathf.Deg2Rad * startAngle) + Mathf.Sin(Mathf.Deg2Rad * anglePhi);
                float yPointOnSphereBoundary = actualRadiusOfSphere * Mathf.Cos(Mathf.Deg2Rad * anglePhi);
                float zPointOnSphereBoundary = actualRadiusOfSphere * Mathf.Cos(Mathf.Deg2Rad * startAngle) + Mathf.Sin(Mathf.Deg2Rad * anglePhi);

                var positionOnSphereBoundary = new Vector3(centerAtomTransform.position.x + xPointOnSphereBoundary, centerAtomTransform.position.y + yPointOnSphereBoundary, centerAtomTransform.position.z + zPointOnSphereBoundary);

                positionsOnSphereBoundary.Add(positionOnSphereBoundary);

                startAngle += (float)moleculeData.bondAngle;
            }

            for (int i = 0; i < positionsOnSphereBoundary.Count; i++)
            {
                var directionVectorFromAtom2ToAtom1 = centerAtomTransform.position - positionsOnSphereBoundary.ElementAt(i);


                directionVectorFromAtom2ToAtom1.Normalize();

                var bondProp = moleculeData.bonds.ElementAt(i);

                if (bondProp.bondLength == 0.0)
                {
                    bondProp.bondLength = .08f;
                }

                var finalAtomTwoPos = positionsOnSphereBoundary.ElementAt(i) + directionVectorFromAtom2ToAtom1 * bondProp.bondLength;
                Transform secondAtomTransform = null;
                Atom secondAtom = null;
                if (bondProp.connectedAtomOne != moleculeData.centralAtom)
                {
                    secondAtomTransform = bondProp.connectedAtomOne.gameObject.transform;
                    secondAtom = bondProp.connectedAtomOne;
                }
                else if (bondProp.connectedAtomTwo != moleculeData.centralAtom)
                {
                    secondAtomTransform = bondProp.connectedAtomTwo.gameObject.transform;
                    secondAtom = bondProp.connectedAtomTwo;
                }
                else
                {
                    throw new System.Exception("Shall not occur??");
                }

                secondAtomTransform.gameObject.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezeAll;

                secondAtomTransform.localRotation = Quaternion.identity;
                secondAtomTransform.position = finalAtomTwoPos;

                #region BondStickInit
                var bondStick = (bondProp.subType == SubBondType.Triple) ? Instantiate(tripleBondStickPrefab) : (bondProp.subType == SubBondType.Double) ? Instantiate(doubleBondStickPrefab) : Instantiate(bondStickPrefab); //Intantiate a bond stick between the atoms

                bondStick.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezeAll;

                var bond = bondStick.GetComponent<Bond>(); //Get the bond component of the bondstick
                bond.SetAtoms(moleculeData.centralAtom, secondAtom); //Add atoms to the bondstick
                bond.InitBondStick(moleculeData.centralAtom.transform, secondAtom.transform, bondProp.bondLength, actualRadiusOfSphere); //Initialize the bond stick
                bond.SetBondType(bondProp.type, bondProp.subType);
                allObjects.Add(bondStick.transform);
                allObjects.Add(secondAtomTransform);
                allBondsFormed.Add(bond);
                #endregion

                secondAtom.parentMolecule = molecule;
                moleculeData.centralAtom.AddConnectedAtom(secondAtom);
                secondAtom.AddConnectedAtom(moleculeData.centralAtom);

                molecule.AddAtoms(moleculeData.centralAtom, secondAtom);
                molecule.AddBond(bond);
                //update reactive spots, since we added new bond
                moleculeData.centralAtom.RemoveReactiveSpots(bond);
                secondAtom.RemoveReactiveSpots(bond);
                secondAtomTransform.gameObject.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.None;

            }
        }
Vivek Mishra
  • 5,669
  • 9
  • 46
  • 84

1 Answers1

1

All of this is working properly but their occurs some cases when some atoms overlap each other despite having rigid body attached to them..

I looked very close at your code and saw this:

secondAtomTransform.localRotation = Quaternion.identity;
secondAtomTransform.position = finalAtomTwoPos;

Don't do that. That's not how to properly rotate or move a Rigidbody. Since this is just part of your code, get ride of any code where you are moving or rotating Rigidbody Object with Transform.position or Transform.localRotation.

Rigibody should be moved with the Rigidbody.MovePosition function and rotated with the Rigidbody.MoveRotation function.


While I expect this to work, if the problem still occur then change the Rigidbody's Interpolate to from None to Interpolate. Another thing to do is to change the Rigidbody's Collision Detection to continuous.

Programmer
  • 121,791
  • 22
  • 236
  • 328
  • I had access to the transform component, so I fetched rigidbody from it and then called movePosition method. I checked using Logs but it returns same position before and after moving. I also changed interpolate and collision as you said but nothing changed – Vivek Mishra Aug 01 '17 at 12:58
  • Also these methods are not called in Update or FIxedUpdate method. These are called from Leap Motion callback methods so I think that is the issue that MovePosition is not working – Vivek Mishra Aug 01 '17 at 13:29
  • To be honest with you `MovePosition` should fix the issue you described in this question. I do suggest you create an empty project and study how to use it. I think you have to redesign/rewrite your app code to work with `MovePosition`. It sucks but that seems like a good way to go. – Programmer Aug 01 '17 at 13:33
  • `secondAtomTransform.gameObject.GetComponent().MovePosition(finalAtomTwoPos)`. This is how I called the method. Is this correct ? – Vivek Mishra Aug 01 '17 at 13:34
  • Yes. So, what's the problem? Is the overlapping still happening? – Programmer Aug 01 '17 at 13:49
  • MovePosition doesn't changes the position. I logged both positions before and after moving both were same. – Vivek Mishra Aug 01 '17 at 13:50
  • but one strange thing I noticed. `secondAtomTransform.gameObject.GetComponent().position` and `secondAtomTransform.position` returns different values. – Vivek Mishra Aug 01 '17 at 13:52
  • This is why I told you to create a simple new scene with a new test script. Create an object with a rigidbody then try to move it this way and see what happens. If it works then you moving that object from multiple places. – Programmer Aug 01 '17 at 13:55
  • I will try and let you know after that – Vivek Mishra Aug 01 '17 at 13:56