Detecting an object partially hidden by another object

Hello, I am trying to make a game where when the enemy is visible in your field of view you start losing health. The script works perfectly when there’s nothing in the way, however, when standing behind any objects, it becomes very inconsistent.

In these images, the enemy is not detected, though he is clearly visible.

if (GeometryUtility.TestPlanesAABB(planes, slenderMan.GetComponent<CapsuleCollider>().bounds))
        {

            if (Physics.CheckSphere(transform.position, 100))
            {

                Collider[] hitColliders = Physics.OverlapSphere(transform.position, 50, enemyMask);
               
                if (hitColliders.Length != 0)
                {
                   
                    Transform target = hitColliders[0].transform;
                    Vector3 targetDirection = ((target.position - transform.position).normalized);
                    if (Vector3.Angle(player.transform.position, targetDirection) < angle / 2)
                    {
                        float targetDistance = Vector3.Distance(transform.position, target.position);
                        if (!Physics.Raycast(transform.position, targetDirection, targetDistance, walls))
                        {
                            exposed = true;
                            Debug.DrawRay(player.position, targetDirection);
                        }

                        else
                            exposed = false;
                    }

                }

            }



        }
        else if (exposed == true)
            exposed = false;

This is the code I use to determine if the enemy is visible, how can I change it to make it work better?

Right now you’re just doing a single raycast at the center of the monster’s body. If that particlar part of it is obsured, your code will fail.

One way to fix this is to do multiple raycasts from many different parts of the monster’s body. For example add a bunch of empty objects as children of the monster (including attaching them to the monster’s bones if it is animated) and perform raycasts from all of those points (put them in array and do the raycast in a loop). Then consider the monster visible if ANY of those raycasts are not blocked.

2 Likes

You could also get more spiffy with Praetor’s suggestion above:

  • only raycast from the enemy’s eyes… that way if he walks with something blocking his face, he won’t see you

  • remember to cast each enemy’s sightpoint to a few places on you, otherwise if you only use your “center” then you could hide that center behind an object and be right back in the same place.

You can actually reverse the process which makes thing easier. The player camera is just a single point. It’s the root of the players view. So you can simply define several points on your enemy (one on each arm and other parts) and you simply do a raycast from those points towards the players camera position. So you have a way better defined mechanic which is more reliable. Spreading raycasts from the player has several issues since as the distance to the enemy changes the area occupied by the enemy on screen also gets smaller / larger.

Of course you could also use those reference points to cast towards the enemy. However depending on your enemy setup you may hit different colliders of the enemy. Casting in the other direction means the rays essentially hit the same spot. Technically you don’t even need to hit the player, you just need to know which rays hit something else first. So you could even exclude the player layer and just let the raycast end inside the players head. So if a ray has no collision, it reached the player. So there would be no need to analyze the object you’ve hit.

This worked actually, thanks