Detect if there is any object between two objects

2019-06-14 04:06发布

I ran into an issue with box-casts while developing a 3D game for mobile.

I want to check the path between my player and his target, to avoid him passing through environmental objects (he doesn't have a rigidbody attached and movement is only possible between specific points).

This is the code that I used to check:

private bool CheckPath (Vector3 position, Vector3 target)
{
    Vector3 center = Vector3.Lerp(transform.position, target, 0.5f);
    Vector3 halfExtents = new Vector3(1, 1, (transform.position - target).magnitude) / 2;
    Quaternion rotation = Quaternion.LookRotation((transform.position - target).normalized);

    RaycastHit[] rhit = Physics.BoxCastAll(center, halfExtents, (transform.position - target).normalized, rotation);
    bool result = rhit.All(r => r.collider.tag != "Environment");

    DebugUtilities.BoxCastDebug.DrawBox(center, halfExtents, rotation, result ? Color.green : Color.red, 3);

    return result;
}

This code works for the most situations:

enter image description here

But fails, for example for this situation:

enter image description here

To visualize the box-cast I used the script from this Unity Answers link.

I am not sure where the problem lies, although the most likely cause would be a flaw in the debugging script mentioned above, which made me believe that my box-cast call was correct.

I am grateful for every solution, although a simple one would be more appreciated.

Some further information (if needed):

  • The objects that I want to make impassable are marked with a Environment tag.
  • I was not the one that wrote the debugging script, it seemed to work at first, so I was fine with it.

1条回答
唯我独甜
2楼-- · 2019-06-14 04:33

Three problems in your code

1.The position variable from the unction parameter is not used. You are instead using transform.position which means that the starting point may be wrong.

Replace all your transform.position with position.

2.You are performing the raycast backwards. It should not be transform.position - target. That should be target - transform.position.

3.Your Physics.BoxCastAll will not work properly since there is no ending to the raycast. Objects behind the starting will be detected by the raycast. Now, if you fix problem #2, the problem will reverse. Now, all the objects in behind the target will also be detected since you did not provide the raycast distance. You can provide the distance with Vector3.Distance(position, target) in the last parameter of the Physics.BoxCastAll function.

Fixed function:

private bool CheckPath(Vector3 position, Vector3 target)
{
    Vector3 halfExtents = Vector3.one;

    Quaternion rotation = Quaternion.LookRotation(target - position);
    Vector3 direction = target - position;
    float distance = Vector3.Distance(position, target);

    RaycastHit[] rhit = Physics.BoxCastAll(position, halfExtents, direction, rotation, distance);
    bool result = rhit.All(r => r.collider.tag != "Environment");

    Vector3 center = Vector3.Lerp(position, target, 0.5f);
    halfExtents = new Vector3(1, 1, (target - position).magnitude) / 2;
    DebugUtilities.DrawBox(center, halfExtents, rotation, result ? Color.green : Color.red);
    // Debug.DrawRay(position, direction, result ? Color.green : Color.red);
    return result;
}

It's worth setting up 3 objects (Cubes) in order to easily test this function. The first one is from Object (Player). The middle one should be the obstacle with the "Environment" tag. The last one should be the target Object where player is moving to.

enter image description here

Then you can use the script below to test it. Run it and move the obstacle away between the player and the target and it should work as expected.

public GameObject playerObject;
public GameObject targetObject;

void Update()
{
    Debug.Log("Path cleared: " + CheckPath(playerObject.transform.position, targetObject.transform.position));
}

You will get the similar result below:

enter image description here

查看更多
登录 后发表回答