2
\$\begingroup\$

I have an ai car script. The car needs to be able to slow down and or stop if it gets too close to another car. Right now I'm using 3 raycasts like so:

if (Physics.Raycast(lRay, out lHit, rs.forwardCollisionRayLength, rs.rayLayerMask) || Physics.Raycast(rRay, out rHit, rs.forwardCollisionRayLength, rs.rayLayerMask) || (Physics.Raycast(mRay, out mHit, rs.forwardCollisionRayLength, rs.rayLayerMask)))
{
    //some code...
}

However this is really long and inconvenient because it's a pain to figure out which raycast actually had the hit. And then there's other cases where multiple raycasts hit the same car, which point do I use, or if different raycasts hit different cars...Anyway, you can see that this is not ideal.

Also, depending on the size of an object, it could go between the raycasts. In the image below, the blue box is ok because its wider than the width between the raycasts, thus two of the raycasts find it. But on the other side, the green pole is too small, so the car can't see it and drives on.

enter image description here

I also need to get the distance between the hit.point and the car so that I know how much the car needs to slow down so that there's a reasonable distance between the two cars at all times.

I could use something like Physics.OverlapBox or Physics.CheckBox but then I can't get the distance between the closest point of the car, only the center of it. This is bad because some cars are longer than others - I need the distance between the nearest point of the car.

Also, keep performance in mind, I could solve the problem of objects going in between raycasts by adding more, but that will drain performance hugely, mainly because I have up to about 40 cars running at a time.

TL;DR: What are some alternatives for a raycast that can also give me the distance to the closest point?

\$\endgroup\$
  • \$\begingroup\$ You can break the if condition into three different ifs. That way you will know which ray hit the target. ---- Edit: Do not make performance assumptions, that's Profiler's job. \$\endgroup\$ – S. Tarık Çetin Jul 11 '17 at 2:51
  • \$\begingroup\$ I could, but then I have to write the same code multiple times, which is inefficient. I could then split the code inside that into another function, but there must have been a reason why I didn't do that before, I can't remember. Maybe I wasn't thinking... \$\endgroup\$ – mr-matt Jul 11 '17 at 2:53
  • \$\begingroup\$ You don't have to. You can use a local boolean flag and add a fourth if block, but again splitting into a method is always better. \$\endgroup\$ – S. Tarık Çetin Jul 11 '17 at 2:54
  • \$\begingroup\$ True, but then I still have the problem of objects going through them...Anyway, the current answer looks promising, so I'll probably scrap raycasts \$\endgroup\$ – mr-matt Jul 11 '17 at 2:54
3
\$\begingroup\$

There are other types of casts. Sounds like you might get some use out of Physics.BoxCast. Like the RayCast, BoxCast will return hit data that you can use to get all the same information as you would from a RayCast.

Also available, SphereCast or CapsuleCast. See the documentation for details.

\$\endgroup\$
  • \$\begingroup\$ This looks good. But what exactly does the hit return? Will it return the closest point, the center of the object, the point right in the middle? What if there were multiple cars in the same box? I don't quite understand how this will work... \$\endgroup\$ – mr-matt Jul 11 '17 at 2:56
  • \$\begingroup\$ It will return the point first hit by the square. You can choose to stop then, just hitting the first object, or use the raycast all version to get all such hits, one per object. Try it with a debug draw line to see the hit points \$\endgroup\$ – MichaelHouse Jul 11 '17 at 3:02
0
\$\begingroup\$

I asked a question here similar to this. The answer I posted there also solved this problem.

This is the code I used:

Collider[] cols = Physics.OverlapBox(position, scale, rotation, layerMask);
Vector3 bestPoint = Vector3.zero;
float closestSqrDistance = Mathf.Infinity;

for (int i = 0; i < cols.Length; i++)
{
    Vector3 pos = cols[i].ClosestPointOnBounds(centerPosition);
    Vector3 direction = pos - centerPosition;
    float sqrDist = direction.sqrMagnitude;

    if (sqrDist < closestSqrDistance)
    {
        closestSqrDistance = sqrDist;
        bestPoint = pos;
    }
}

In short, it gets all of the colliders intersecting a box, loops through all of them to find the closest point out of all the colliders and then calculates the distance based on that.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.