void DrawSelectedObject() { if (_lineMaterial == null) { return; } NewBoxCollider box = _selectedObject.GetComponent <NewBoxCollider> (); if (box != null) { DrawCube(box.origin.dots, 1f); DrawCube(box.origin.dots, 1.0005f); DrawCube(box.origin.dots, 1.0006f); DrawCube(box.origin.dots, 1.0007f); DrawCube(box.origin.dots, 1.0008f); return; } NewSphereCollider sphere = _selectedObject.GetComponent <NewSphereCollider> (); if (sphere != null) { DrawSphere(sphere.radius, sphere.transform.position); return; } }
public bool BoxToBox(NewBoxCollider boxA, NewBoxCollider boxB) { // reference https://developer.mozilla.org/en-US/docs/Games/Techniques/3D_collision_detection // If all boxA axis are inside boxB then there is a collision return((boxA.minBounds.x < boxB.maxBounds.x && boxA.maxBounds.x > boxB.minBounds.x) && (boxA.minBounds.y < boxB.maxBounds.y && boxA.maxBounds.y > boxB.minBounds.y) && (boxA.minBounds.z < boxB.maxBounds.z && boxA.maxBounds.z > boxB.minBounds.z)); }
public bool SphereToBox(NewSphereCollider sphere, NewBoxCollider box) { // reference https://developer.mozilla.org/en-US/docs/Games/Techniques/3D_collision_detection // find the closest point on the box to the center of the sphere Vector3 closestPoint = Vector3.zero; closestPoint.x = Mathf.Max(box.minBounds.x, Mathf.Min(sphere.transform.position.x, box.maxBounds.x)); closestPoint.y = Mathf.Max(box.minBounds.y, Mathf.Min(sphere.transform.position.y, box.maxBounds.y)); closestPoint.z = Mathf.Max(box.minBounds.z, Mathf.Min(sphere.transform.position.z, box.maxBounds.z)); // distance between closest point and center of the sphere float distance = Mathf.Sqrt( (closestPoint.x - sphere.transform.position.x) * (closestPoint.x - sphere.transform.position.x) + (closestPoint.y - sphere.transform.position.y) * (closestPoint.y - sphere.transform.position.y) + (closestPoint.z - sphere.transform.position.z) * (closestPoint.z - sphere.transform.position.z)); return(distance < sphere.radius); }
public CollisionData BoxToBoxManifold(NewBoxCollider boxA, NewBoxCollider boxB) { // reference: https://gamedevelopment.tutsplus.com/tutorials/how-to-create-a-custom-2d-physics-engine-the-basics-and-impulse-resolution--gamedev-6331 // NOTE that I had to convert from 2D to 3D and add my own stuff (the tutorial wasn't entirely accurate) // Manifold Initialisation CollisionData manifold = new CollisionData(); manifold.bodyA = boxA.transform.gameObject.GetComponent <NewRigidBody> (); manifold.bodyB = boxB.transform.gameObject.GetComponent <NewRigidBody> (); manifold.bodyAobj = boxA.transform.gameObject; manifold.bodyBobj = boxB.transform.gameObject; manifold.normal = Vector3.zero; manifold.penetration = 0.0f; // Exit if there is not a collision manifold.wasCollision = BoxToBox(boxA, boxB); if (manifold.wasCollision == false) { return(manifold); } Vector3 relativePosition = boxB.transform.position - boxA.transform.position; float xOverlap = boxA.extents.x + boxB.extents.x - Mathf.Abs(relativePosition.x); // If overlapping in the x-axis if (xOverlap > 0.0f) { float yOverlap = boxA.extents.y + boxB.extents.y - Mathf.Abs(relativePosition.y); // If also overlapping on the y-axis if (yOverlap > 0.0f) { float zOverlap = boxA.extents.z + boxB.extents.z - Mathf.Abs(relativePosition.z); // Find axis of least penetration if (xOverlap < yOverlap && xOverlap < zOverlap) { if (relativePosition.x < 0.0f) { manifold.normal = new Vector3(-1.0f, 0.0f, 0.0f); } else { manifold.normal = new Vector3(1.0f, 0.0f, 0.0f); } manifold.penetration = xOverlap; } else if (yOverlap <= xOverlap && yOverlap < zOverlap) { if (relativePosition.y < 0.0f) { manifold.normal = new Vector3(0.0f, -1.0f, 0.0f); } else { manifold.normal = new Vector3(0.0f, 1.0f, 0.0f); } manifold.penetration = yOverlap; } else { if (relativePosition.z < 0.0f) { manifold.normal = new Vector3(0.0f, 0.0f, -1.0f); } else { manifold.normal = new Vector3(0.0f, 0.0f, 1.0f); } manifold.penetration = zOverlap; } } } return(manifold); }
public CollisionData BoxToBoxSAT(NewBoxCollider boxA, NewBoxCollider boxB) { // reference to seperating axis theorem: // https://gamedevelopment.tutsplus.com/tutorials/collision-detection-using-the-separating-axis-theorem--gamedev-169 // 3D axis found using: https://gamedev.stackexchange.com/questions/44500/how-many-and-which-axes-to-use-for-3d-obb-collision-with-sat CollisionData manifold = new CollisionData(); manifold.wasCollision = false; if (boxA == null || boxB == null) { return(manifold); } manifold.bodyA = boxA.transform.gameObject.GetComponent <NewRigidBody>(); manifold.bodyB = boxB.transform.gameObject.GetComponent <NewRigidBody>(); manifold.bodyAobj = boxA.transform.gameObject; manifold.bodyBobj = boxB.transform.gameObject; manifold.normal = Vector3.zero; manifold.penetration = 0.0f; // dots List <Vector3> boxADots = new List <Vector3> (); List <Vector3> boxBDots = new List <Vector3> (); for (int i = 0; i < boxA.origin.dots.Length; i++) { boxADots.Add(boxA.origin.dots [i]); boxBDots.Add(boxB.origin.dots [i]); } // normals List <Vector3> boxANormals = new List <Vector3> (); List <Vector3> boxBNormals = new List <Vector3> (); for (int i = 1; i < 3; i++) { boxANormals.Add(boxA.origin.normals[i]); boxBNormals.Add(boxB.origin.normals [i]); } boxANormals.Add(boxA.faces [1].normals [0]); boxBNormals.Add(boxB.faces [1].normals [0]); _currentStateDebug.Clear(); // Optimisation if (Vector3.Distance(boxA.transform.position, boxB.transform.position) > 10.0f) { return(manifold); } // Box 1 XYZ bool seperate_Q = isSeperate(boxADots, boxBDots, boxANormals[0], boxB.transform.name); bool seperate_P = isSeperate(boxADots, boxBDots, boxANormals[1], boxB.transform.name); bool seperate_5 = isSeperate(boxADots, boxBDots, boxANormals[2], boxB.transform.name); // Box 2 XYZ bool seperate_S = isSeperate(boxADots, boxBDots, boxBNormals[0], boxB.transform.name); bool seperate_R = isSeperate(boxADots, boxBDots, boxBNormals[1], boxB.transform.name); bool seperate_6 = isSeperate(boxADots, boxBDots, boxBNormals[2], boxB.transform.name); // Cross Products bool seperate_7 = isSeperate(boxADots, boxBDots, Vector3.Cross(boxANormals[0], boxBNormals[0]), boxB.transform.name); bool seperate_8 = isSeperate(boxADots, boxBDots, Vector3.Cross(boxANormals[0], boxBNormals[1]), boxB.transform.name); bool seperate_9 = isSeperate(boxADots, boxBDots, Vector3.Cross(boxANormals[0], boxBNormals[2]), boxB.transform.name); bool seperate_10 = isSeperate(boxADots, boxBDots, Vector3.Cross(boxANormals[1], boxBNormals[0]), boxB.transform.name); bool seperate_11 = isSeperate(boxADots, boxBDots, Vector3.Cross(boxANormals[1], boxBNormals[1]), boxB.transform.name); bool seperate_12 = isSeperate(boxADots, boxBDots, Vector3.Cross(boxANormals[1], boxBNormals[2]), boxB.transform.name); bool seperate_13 = isSeperate(boxADots, boxBDots, Vector3.Cross(boxANormals[2], boxBNormals[0]), boxB.transform.name); bool seperate_14 = isSeperate(boxADots, boxBDots, Vector3.Cross(boxANormals[2], boxBNormals[1]), boxB.transform.name); bool seperate_15 = isSeperate(boxADots, boxBDots, Vector3.Cross(boxANormals[2], boxBNormals[2]), boxB.transform.name); // If one is seperate then no collision manifold.wasCollision = !(seperate_10 || seperate_11 || seperate_12 || seperate_13 || seperate_14 || seperate_15 || seperate_5 || seperate_6 || seperate_7 || seperate_8 || seperate_9 || seperate_P || seperate_Q || seperate_R || seperate_S); if (manifold.wasCollision == true) { if (_previousStateDebug.Length > 0) { // Find penertration, normal and contact point Vector3 checkPoint = _previousStateDebug [0].faceA - Vector3.Scale(-manifold.normal / 2.0f, boxB.extents); manifold.penetration = Vector3.Distance(checkPoint, _previousStateDebug[0].faceA); manifold.normal = -_previousStateDebug [0].axis; manifold.contacts = new List <Vector3> (); for (int contactI = 0; contactI < _previousStateDebug.Length; contactI++) { manifold.contacts.Add(_previousStateDebug [contactI].faceA); } } else { Debug.LogWarning("No contact between? " + boxA.transform.name + "," + boxB.transform.name); } } else { _previousStateDebug = new SeperationDataDebug[_currentStateDebug.Count]; _currentStateDebug.CopyTo(_previousStateDebug); _currentStateDebug.Clear(); } return(manifold); }
public CollisionData BoxToSphereManifold(NewBoxCollider box, NewSphereCollider sphere) { // reference: https://gamedevelopment.tutsplus.com/tutorials/how-to-create-a-custom-2d-physics-engine-the-basics-and-impulse-resolution--gamedev-6331 // (NOTE reference is in 2d, had to add 3D as well as my own manifold stuff) // Initialise manifold CollisionData manifold = new CollisionData(); manifold.bodyA = box.transform.gameObject.GetComponent <NewRigidBody> (); manifold.bodyB = sphere.transform.gameObject.GetComponent <NewRigidBody> (); manifold.bodyAobj = box.transform.gameObject; manifold.bodyBobj = sphere.transform.gameObject; manifold.normal = Vector3.zero; manifold.penetration = 0.0f; manifold.wasCollision = false; Vector3 relativePosition = sphere.transform.position - box.transform.position; // Closest point on A to center of B Vector3 closestPoint = Vector3.zero; closestPoint.x = Mathf.Max(box.minBounds.x, Mathf.Min(sphere.transform.position.x, box.maxBounds.x)); closestPoint.y = Mathf.Max(box.minBounds.y, Mathf.Min(sphere.transform.position.y, box.maxBounds.y)); closestPoint.z = Mathf.Max(box.minBounds.z, Mathf.Min(sphere.transform.position.z, box.maxBounds.z)); // If Circle is inside Box bool inside = false; if (relativePosition == closestPoint) { inside = true; // Find closest axis if (Mathf.Abs(relativePosition.x) > Mathf.Abs(relativePosition.y) && Mathf.Abs(relativePosition.x) > Mathf.Abs(relativePosition.z)) { // Clamp to closest extent if (closestPoint.x > 0.0f) { closestPoint.x = box.extents.x; } else { closestPoint.x = -box.extents.x; } } // y-axis is shorter else if (Mathf.Abs(relativePosition.y) > Mathf.Abs(relativePosition.z)) { // Clamp to closest extent if (closestPoint.y > 0.0f) { closestPoint.y = box.extents.y; } else { closestPoint.y = -box.extents.y; } } // z-axis is shorter else { // Clamp to closest extent if (closestPoint.z > 0.0f) { closestPoint.z = box.extents.z; } else { closestPoint.z = -box.extents.z; } } } Vector3 normal = sphere.transform.position - closestPoint; float distance = (closestPoint.x - sphere.transform.position.x) * (closestPoint.x - sphere.transform.position.x) + (closestPoint.y - sphere.transform.position.y) * (closestPoint.y - sphere.transform.position.y) + (closestPoint.z - sphere.transform.position.z) * (closestPoint.z - sphere.transform.position.z); // If no collision then return manifold.wasCollision = (Mathf.Sqrt(distance) < sphere.radius); if (manifold.wasCollision == false) { return(manifold); } distance = Mathf.Sqrt(distance); // Flip collision normal if inside if (inside == true) { manifold.normal = Vector3.Normalize(-normal); } else { manifold.normal = Vector3.Normalize(normal); } manifold.penetration = sphere.radius - distance; // Contact point manifold.contacts = new List <Vector3> (); manifold.contacts.Add(closestPoint); return(manifold); }