Here are a few code samples from my most recent 3D game which you can read about on the Untitled Movement Shooter page.

A simple damage number script which pops the number out when firing:

    void Start()
        // References
        rb = GetComponent<Rigidbody>();
        target = GameObject.FindWithTag("Player");
        hitNumber = GetComponentInChildren<TMP_Text>();

        // Dynamic sizing
        initScale = transform.localScale;

        // Crit coloring
        damageColor = critHit ? critColor : normalColor;

        // Shoots off damage number in a random direction.
        rb.AddForce(new Vector3(randDir(), 1.5f, randDir()), ForceMode.Impulse);

        // Destroy timer
        Destroy(this.gameObject, timeToDestroy);

    void Update()
        // If there's a player in the scene, look at them
        if(target != null)

        // Fade text with countdown of destroy timer.
        if(timeToDestroy > destroyCurTime)
            destroyCurTime += Time.deltaTime;
            hitNumber.color = new Color (damageColor.r, damageColor.g, damageColor.b, (timeToDestroy / destroyCurTime) - 1f);

        // Dynamic sizing
        float distance = (target.transform.position - transform.position).magnitude;
        float size = distance * fixedSize / 12.5f;
        transform.localScale = * size;

    // The scrunkly (color fade)
    public void updateDamageText(float damage, bool crit, float critHitMult)
        // Pass the crit outside of the referenced script (for color).
        critHit = crit;

        // Make sure that the other functions fire first

        // Update the text.
        hitNumber.text = "-" + System.Math.Round(damage,2).ToString();

I reference that inside of a interface for damageable items!

public interface IDamagable
    public void Damage(float damage, bool crit, float critHitMult, string gunName);

    public static void spawnHitNumber(float damage, bool crit, float critHitMult, Vector3 spawnLoc)
        GameObject curHitNumber = GameObject.Instantiate(Resources.Load<GameObject>("Prefabs/HitCanvas"), spawnLoc, Quaternion.identity);
        curHitNumber.GetComponent<HitNumberScript>().updateDamageText(damage, crit, critHitMult);

Utilizing Unity’s prefab system, I can very easily prototype this out and reference it inside of gun scripts.

Speaking of gun scripts…

[CreateAssetMenu(fileName="Gun", menuName="Weapon/Gun")]

public class GunData : ScriptableObject
    public enum GunType {

    public string gunName;
    public float damage;
    public float critHitMult;
    public float maxDistance;

    [Header("Weapon Type Data")]
    public GunType weaponType;

    // Automatic
    public int automaticFireRate;

    // Projectile
    public float projectileSpeed;
    public GameObject projectilePrefab;

    // Single shot
    public float singleShotDelay;

    [Header("Weapon Sounds")]
    public List<AudioClip> fireSounds = new List<AudioClip>();

I can create scriptable objects in Unity to rapidly prototype new weapon ideas, though any special gimics would have to be coded into the weapons themselves.