Raycast layermask only one object from that mask

Take the above image.

I want to raycast to check if zombie 1 is in sight of the wizard (ignoring if other enemies are in the way). If i raycast with a layermask that contains the block layer and the enemy layer, the raycast will hit zombie 2 and therefore believe zombie 1 is in sight, when it is not.

How do i raycast and only hit one object from the layer? Or solve my problem another way?

Cheers.

Raycasting code below:

public bool AttemptShield(){

        GameObject player = GameObject.FindGameObjectWithTag("Player");

        Transform shieldTarget = null;

        Collider2D[] enemiesInRange = Physics2D.OverlapCircleAll(transform.position, shieldRange, LayerMaskStorage.instance.enemyMask);

        if(enemiesInRange == null){
            return false;
        }

        // Sort by dist to player
        var enemiesInRangeSorted = enemiesInRange.OrderBy(x => Vector2.Distance(player.transform.position, x.transform.root.position)).ToList();

        foreach (var enemy in enemiesInRange)
        {
            // Check if enemy has shield already
            bool hasShield = false;

            if(enemy.transform.root.Find("Shield"))
                hasShield = true;
         

            // Check if enemy is in view
            bool inSight = false;

            var dir = (enemy.transform.position - transform.position).normalized;
            var hit = Physics2D.Raycast(transform.position, dir, shieldRange, LayerMaskStorage.instance.enemyBlockMask);

            if(hit)
                if(hit.transform.tag == "Enemy")
                    inSight = true;

            //If enemy is in sight and doesn't have a shield, shield it and return
            if(inSight && !hasShield){
                Shield(enemy.gameObject);
                return true;
            }
        }

        return false;
    }

You can raycast against a single collider,

If that doesn’t solve your problem you can use raycast all to find everything along the line, but you will need to sort them yourself by for example distance or type.

There are many other types of cast to choose from.

As far as i can tell Collider2D.Raycast won’t solve the problem as its completely different than Collider.Raycast and doesn’t ‘raycast against a single collider’ but instead casts a ray into the Scene that starts at the Collider position and ignores the Collider itself.

I don’t see how RaycastAll would solve it either?

It sounds like you just need to do a Raycast that ignores all enemies (including your target) from the player to the position of the specific enemy. If you get no results, you know the path is clear.

// mask that hits everything EXCEPT enemies and players
// The "~" operator negates the mask so it's the opposite
var layerMask = ~LayerMask.GetMask("Enemy", "Player");

var dir = enemy.transform.position - transform.position;
if (!Physics2D.Raycast(transform.position, dir, dir.magnitude, layerMask)) {
  // We didn't hit anything! The path to the enemy is clear
}
else {
  // We hit a wall or something. The path to the enemy is obscured
}
1 Like

You’re right, I was assuming it worked like the 3D variant, but seems not.

You should be able to use RaycastAll though.
Shoot a ray from wizard to left towards Z1.
You would end up with an array with Z1, Z2 and Block in it.
Sort this array by ray hit distance from nearest to farthest. Now you can iterate through these and you would get to elements in this order: Z2, Block,Z1. Because Block is before Z2 you know that it is obscured.