Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get collision data from Physics.OverlapBox()?

I'm trying to find other methods of registering collisions (other than OnCollisionEnter() and OnCollisionExit()). I'm currently using Physics.OverlapBox(), but I need more information about the collision; i.e., normal, point.

I can use Physics.BoxCast(), but the problem is that it moves a box a given distance, and using maxDistance = 0f won't work.

I need a method of checking for collisions similar to Physics.OverlapBox() except in that it would also return information about all collisions in the cast.

Any help is appreciated. Thanks.

like image 946
blackhole Avatar asked Sep 15 '18 01:09

blackhole


People also ask

How do you detect collisions without rigidbody?

There is an option to add 'isTrigger' property in any collider and you can listen to TriggerEvent in your script. This will work without having a rigidbody at all. But you do need to have colliders on the objects that have to collide.

What is rigidbody collision detection?

Description. The Rigidbody's collision detection mode. Use this to set up a Rigidbody's for continuous collision detection, which is used to prevent fast moving objects from passing through other objects without detecting collisions. For best results, set this value to CollisionDetectionMode.

How do I know if colliders overlap unity?

The physics system is layer-based so if you use layers then you can use 'Collider2D. IsTouchingLayers()' to see if your collider is touching anything on specific layer(s).

What is a collision object?

A collision object is a component you use to give a game object physical behaviour. A collision object has physical properties like weight, restitution and friction and its spatial extension is defined by one or more shapes that you attach to the component.

How does the overlapbox work with boxcollider?

//This script uses the OverlapBox that creates an invisible Box Collider that detects multiple collisions with other colliders. The OverlapBox in this case is the same size and position as the GameObject you attach it to (acting as a replacement for the BoxCollider component).

Is the overlapbox the right size?

It turns out that the OverlapBox wasn't incredibly large, but that the transforms needed to be updated manually since everything was happening in one frame. As a result, the OverlapBox was the right size, but all of the colliders that I had moved that frame hadn't actually been moved yet according to the physics engine.

How to check if a collider is inside a box?

Collider2D The Collider overlapping the box. Checks if a Collider falls within a box area. The box is defined by its center coordinate in world space and by its size. The optional layerMask allows the test to check only for objects on specific layers.

Can I use the z axis for collision detection in 2D?

Although the Z axis is not relevant for rendering or collisions in 2D, you can use the minDepth and maxDepth parameters to filter objects based on their Z coordinate. If more than one Collider falls within the box then the one returned will be the one with the lowest Z coordinate value.


2 Answers

Your concern, expressed in the comment to the first answer is valid, but the bad news is that there is no simple trick to go around it. What you should be looking for is called continuous collision detection with a simplified version described in my answer on a somewhat similar matter:

Basically, for each moving object in your scene you have to calculate moment of next collision within the fraction of the frame 0<t0<1, then advance positions to this moment t0 within the frame, update velocities due to collision and proceed further to the next collision t0<t1<1, until you reach time of tn=1 (end of frame), making sure you don't get stuck in a the middle of the frame due to rounding of calculation or "cornered" objects. For spherical colliders, that is usually done by using capsule vs capsule (for pairs of objects) intersection and capsule vs box for the boundaries.

In oppose to the simple engine from the answer I'm referring to, Unity has continuous collision detection. So you can enable continuous collisions and continuous dynamic which computationally is very expensive.

You can also try using RigidBody.SweepTest which returns the closest collision information. Notice that even though there is also RigidBody.SweepTestAll, it doesn't help much. Not only because it returns only first 128 collisions, but also because it doesn't process them as there is no reflection. For physically correct behaviour you have to do what described above - advance time till the first collision and update velocities. Either with the physics engine or by yourself. This is very costly and not many games are doing that even cheating by using simplified objects (spheres are the cheapest ones as two swept spheres are two capsules and their intersection is a relatively cheap calculation), but amount of steps, especially in the "cornered" case when objects have nowhere to go and therefore are constantly colliding could be very large and such cases happen more than one can expect.

For complex objects you unlikely can do better than SweepTest, unless you trigger it based on the simpler primitives, such as Physics.BoxCast or Physics.SphereCast. Again, even though there are Physics.BoxCastAll and Physics.SphereCastAll they are not particularly useful as only first collision is guaranteed to occur. Those xxxCastAll are the functions you wrote you were looking for, so give it a try, they might work well enough for your use case.

like image 53
isp-zax Avatar answered Sep 21 '22 03:09

isp-zax


You can use OverlapBox and use Collider's ClosestPoint to select a single point of overlap, and use that to make your collision calculations.

Collider[] cols = Physics.OverlapBox(...);
Vector3 myPosition = transform.position; // for example

foreach (Collider col in cols) {
    Vector3 closestPoint = col.ClosestPoint(myPosition);
    Vector3 positionDifference = (closestPoint-myPosition);
    Vector3 overlapDirection = positionDifference.normalized; 
}

This overlapDirection will point in the direction away from the the position you use in ClosestPoint to the center of each colliding collider. If you want something based on the surface of your object, what you can do is use that overlap direction to place a raycast aimed at your object, to find the normal that way:

// ...

foreach (Collider col in cols) {
    Vector3 closestPoint = col.ClosestPoint(myPosition);
    Vector3 positionDifference = (closestPoint-myPosition);
    Vector3 overlapDirection = positionDifference.normalized; 

    RaycastHit hit;
    int layerMask = 1;  // Set to something that will only hit your object
    float raycastDistance = 10.0; // something greater than your object's largest radius, 
                                  // so that the ray doesn't start inside of your object
    Vector3 rayStart = myPosition + overlapDirection * raycastDistance;
    Vector3 rayDirection = -overlapDirection ;

    if (Physics.Raycast(rayStart, rayDirection, out hit, Mathf.Infinity, layerMask)) {
        Debug.Log(hit.normal);
        Debug.Log(hit.position);
    } else {
        // The ray missed your object, somehow. 
        // Most likely it started inside your object 
        // or there is a mistake in the layerMask
    }
}
like image 25
Ruzihm Avatar answered Sep 20 '22 03:09

Ruzihm