Instantiating Material Depending on List Materials

Hey so my question above if not explained will in the title above is I want to create a list that you can assign values to using the inspector such as a list with 4 elements with the names of Concrete, Wood, Metal and in my shooting function all I do is if the gun hits List.Concrete.PhysicMaterial (Not code English just to show refrence ) for example then I want to spawn in List.HitEffect(Concrete) or something like that I have no idea on how to start this though I have tried to create a struct with these variables for a PhysicalMaterial, and a gameobject hit effect that is like an particle system and a decal.

Here is the code I have so far.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Weapon : MonoBehaviour
{

    public GameObject Bullet;
    private Camera MainCam;


    [System.Serializable]
    public struct FX
    {
        public PhysicMaterial ObjectPM;
        public GameObject HitEffect;
    }


    void Start()
    {

        MainCam = Camera.main;
    }


    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Shoot();
        }
    }

    void Shoot()
    {
        LayerMask Player = LayerMask.GetMask("Player");
        float MaxDistance = Mathf.Infinity;
        RaycastHit HitInfo;


        if (Physics.Raycast(MainCam.transform.position, MainCam.transform.forward,out HitInfo,MaxDistance))
        {
            InstantiateEffects(HitInfo);
        }

       
    }

    void InstantiateEffects(RaycastHit RaycastInfo)
    {
       //Here i will check if i hit a physical material inside the list so
       //so if we hit a concrete physical material and its in the list and has a hit effect I want to spawn that in
    }

}

RaycastInfo tells you what collider it hit. That collider tells you what Physic Material is on it.

RaycastInfo also tells you the point in space it hit and the normal of the contact point so you know where to face a decal.

There are a LOT of bullet hole scripts already out there so you might want to go look at some tutorials on Youtube rather than starting from scratch.

It really comes down to how hairy you want it to be… you might spawn an entire series of events, such as a hole with gas that leaks out until the tank is empty, or that can catch fire if you shoot again, etc., so start small and see what’s out there.

Hey I tried to make it like the way you said I should but for some reason it wont detect the physical material on the object it returns it but it says its the physical material that’s assigned but it always returns false on the if statements even when they are the same?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Weapon : MonoBehaviour
{
    public GameObject Bullet;
    private Camera MainCam;


    [System.Serializable]
    public struct FX
    {
        [Header("Concrete Effects")]
        public PhysicMaterial Concrete;
        [Space]
        public GameObject ConcreteFX;
        [Space]
        [Header("Metal Effects")]
        public PhysicMaterial Metal;
        [Space]
        public GameObject MetalFX;
        [Space]
        [Header("Wood Effects")]
        public PhysicMaterial Wood;
        [Space]
        public GameObject WoodFX;
    }

    public FX Effects;


    void Start()
    {

        MainCam = Camera.main;
    }


    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Shoot();
        }
    }

    void Shoot()
    {
        LayerMask Player = LayerMask.GetMask("Player");
        float MaxDistance = Mathf.Infinity;
        RaycastHit HitInfo;


        if (Physics.Raycast(MainCam.transform.position, MainCam.transform.forward,out HitInfo,MaxDistance, ~Player))
        {
            CalculateEffects(HitInfo);
        }
    }

    void CalculateEffects(RaycastHit RaycastInfo)
    {
        if (RaycastInfo.collider.material == Effects.Concrete) // Returns false
        {
            SpawnDecal(Effects.ConcreteFX, RaycastInfo);
        }

        if (RaycastInfo.collider.material == Effects.Metal)  // Returns false
        {
            SpawnDecal(Effects.MetalFX, RaycastInfo);
        }

        if (RaycastInfo.collider.material == Effects.Wood)// Returns false even when the object that the ray hit has the same physical material as referenced here I have did a print statement earlier to verify that.
        {
            SpawnDecal(Effects.WoodFX, RaycastInfo);
        }



    }

    void SpawnDecal(GameObject HitEffect, RaycastHit HitInformation)
    {
        Instantiate(HitEffect, HitInformation.point, Quaternion.LookRotation(HitInformation.normal));
    }

}

The collider has the same physical material as the Effects physical materials? But yet each check on the objects physical material returns false? Any clue on why that could be?

It certainly should, unless something changed it.

Honestly you might get a more flexible system if you go and attach custom scripts to the colliders you want to be marked up by bullet marks and explicitly put in that script what to mark it up with.

That way the bullet can just scan the collider for such an object, if it exists, tell it to put a bullet mark at .point. If it does not exist, then you know that doesn’t have bullet holes. This way if in the future you have another type of concrete you don’t have to duplicate and confuse things.

I would still go try some bullet hole tutorials because there are probably ways we haven’t even thought about yet that might be even better or easier.

Thanks a lot man yeah I thought about that too it felt too hard coded to enter but I have found the issue appeartly in Unity collider.material changes the material you hit to an instance which makes no sense so instead of that I used collider.sharedmaterial which worked perfectly fine but I might end up making a brand new script to handle my bullet holes like you recommended giving each object its type and checking when the bullet hits something it can check where the collision was and just instantiate the effect.

1 Like