RaycastAll selective penetration

Hi !
How can i achieve a selective penetration for RaycastAll ?
For example, the ray can go through enemy NPC with specific tag, but stuck at wall with specific tag too.
Here is simple graphic about what i mean.

[157022-example.png*|157022]

And my shooting script

public Camera fpsCam;

[Header("GUN STATS")]
public int damage;
public float range;
public float fireRate = 20f;
public float impactForce = 30f;
public float nextTimeToFire = 0f;

[Header("SFX")]
public AudioSource[] fire_sounds;
public int generator_fire_sounds;
public AudioClip impact_sfx_concrete;

[Header("VFX")]  
public Transform BulletHolePrefab;
public GameObject impactEffect;

void Start()
{

}

void Update()
{
    if (Input.GetButton("Fire1") && Time.time >= nextTimeToFire) 
    {
        nextTimeToFire = Time.time + 1f / fireRate;

        Shoot();
    }

}

void Shoot()
{
    Ray ray = fpsCam.ScreenPointToRay(Input.mousePosition);

    RaycastHit[] hits = Physics.RaycastAll(ray, range);

    for (int i = 0; i < hits.Length; i++)
    {
        RaycastHit hit = hits*;*

if (hit.collider.CompareTag(“Penetrable”))
{
Debug.Log(“Enemy takes” + damage + “damage and penetrated”);
hit.collider.SendMessage(“Apply_Damage”, damage, SendMessageOptions.DontRequireReceiver);
//Apply force to rigidobdy
if (hit.rigidbody != null)
{
hit.rigidbody.AddForce(transform.forward * impactForce);
}
}
// Spawn bullet hole prefab
Quaternion hit1Rotation = Quaternion.FromToRotation(Vector3.up, hit.normal);
Transform bulletHole1 = Instantiate(BulletHolePrefab, hit.point + (hit.normal * 0.01f), hit1Rotation) as Transform;
bulletHole1.parent = hit.transform;
}
//Play shoot sounds
generator_fire_sounds = Random.Range(0, 3);
fire_sounds[generator_fire_sounds].Play();
}

I generally see three options here:

  • Don’t use RaycastAll since it will always detect all hits that are on the line of the ray. Instead you can use a normal raycast and just apply your penetration logic based on the first hit. So if you hit an enemy you simply cast another ray from the first hit point + a little offset into the same direction. So you essentially continue the ray manually. If you hit a wall or nothing you just stop the loop, otherwise just rinse and repeat.
  • For the second option you could of course use RaycastAll and manually sort and analyse the hits. So first make sure they are sorted from nearest to furtherst hit. Then you can simply walk through your hits in order and see what they are. Once you each a non penetratable object you can stop. Otherwise you just handle your hits in order.
  • Finally another kind of hybrid solution is to first doing an ordinary raycast but you ignore your enemies and you only looking for objects which could obstruct your ray. When you get a hit you use that hit distance as your distance parameter for your RaycastAll call. That way if you hit a wall first your actual RaycastAll would be much shorter and essentially stops at the first obstacle. If the wall you hit is behind your actual enemies the RaycastAll call would catch those enemies before that wall.

Personally I would probably go with solution one or two. The order of the hits is generally quite interesting. Many penetrating mechanics include a “loss of energy” as you penetrate an object / enemy. That way stronger weapons could even penetrate small walls and still cause some damage to the targets behind that wall. Also the penetraion through an enemy could also weaken the shot. With the first or second approach you can modify the shot energy as you walk through the hits. In order to apply wall-thickness testing you can simply do another collider.Raycast from the opposite side if you hit a wall to see how thick the wall is. Though this all depends on what kind of mechanic you have in mind.