I'm certain there's a better way to do this (Assigning damage value to projectile)

Hi there, first post. :slight_smile:

I set up a way to assign a damage value to fired/instantiated projectiles from a parent object’s gun scriptable object - which holds that data. It’s functional, but my spidey-senses tell me that it’s very much a beginner/poor-man’s-solution. I’m looking for a way to optimize it.

Here’s the general architecture:
*Each weapon’s gun Scriptable Object (gunSO) is attached to a “CurrentWeapon” script via each weapon’s prefab. “CurrentWeapon” manages things like shoot, zoom, and reload from the player’s inputs.
*In a child object (the gun), there’s a “WeaponFunctions” script, which takes inputs to its public methods from the gunSO assigned to “CurrentWeapon” to actually Raycast/launch projectiles/etc (i.e., interact with the world based on what the CurrentWeapon’s gunSO says it can/can’t do).
*Instantiated projectiles have a “Projectile” script attached which has the damage value and OnTriggerEnter functions.

Here’s the relevant code which I’m sure can be optimized (irrelevant code like animations, particles, timeSinceLastShot, referencing inputs, etc., has been omitted):

In “CurrentWeapon” script:

    GunSO thisGunSO;
    WeaponFunctions thisGun

    void Start()
    {
        // new weapon is made and the WeaponFunctions component is grabbed from it & referenced
    }

    void HandleShoot()
    {
        thisGun.Shoot(thisGunSO)
    }

In “WeaponFunctions” Script:

    public void Shoot(GunSO gunSO)
    {
        HandleShootType(gunSO);
    }

    void HandleShootType(GunSO gunSO)
    {
        if (gunSO.Raycast)
        {
            HandleShootRaycast(gunSO);
        }

        if (gunSO.Projectile)
        {
            HandleShootProjectile(gunSO);
        }
    }

void HandleShootProjectile(GunSO gunSO)
    {
        // code to calculate spawn point & target point, etc.

        GameObject currentProjectile = Instantiate(gunSO.projectilePrefab, attackPoint.position, Quaternion.identity);
        Projectile projectileScript = currentProjectile.GetComponent<Projectile>();
        projectileScript.AssignDamage(gunSO.damage);
        // Grabs the "Projectile" code from the instantiated projectile

        // code to add force & direction to the projectile
    }

In “Projectile” Script:

    public int assignedDamage = 0;

    void Start()
    {
        AssignDamage(assignedDamage);
    }

    void OnTriggerEnter(Collider other)
    {
        // code to deal damage equal to "assignedDamage"
    }

    public void AssignDamage(int amount)
    {
        assignedDamage = amount;
    }

Let me know how badly I did, haha.

Also let me know if I need to clarify anything because it’s a lot.

I suppose this also opens up a larger question about the architecture of the weapons - should any of these methods be in the gunSO script? Could anything be called from a more optimized place? Or would it make no difference?

Thanks!

That’s how I do it most of the time and it’s never really failed me. If you ever decide that you need pooling for your bullets then this is especially useful because you can often share the same bullet for many different attacks and just change some properties on the fly. This helps reduce the pool size which is usually what you want.

Could it be more efficient? Yeah, absolutely. But how many bullets are we talking here? A dozen to a hundred? Not really worth the time. Up to a thousand or so, probably still not worth the time except that you’d want to consider pooling for sure by that point. Several thousands or even higher in magnitude? Yeah, then you’d need to consider other ways of doing this but at that point the GameObjects and physics system themselves are what’s really holding you back and it would be worth considering other techniques altogether such as ECS.

It seems okay but it is a little unusual because it’s common to have several unique properties for different projectile types each with their own prefab. For example a different mesh and sound effect and these are typically set in the editor, and so then you may as well just set the damage amount in the editor also.

You could also derive the damage amount from other properties of a projectile, like velocity or scale, and so you wouldn’t even need a damage amount property.

Your spidey-sense could be tingling due to the weirdness involved with setting up assignedDamage as a separate step after the object has already been instantiated.

Because Unity’s API doesn’t offer any way to pass arguments to components when instantiating them - like you can when constructing plain old C# objects with the new operator - it can create a really weird situation, where you first have to instantiate objects into the scenes in a half-baked state, and then finish setting them up only after the Awake and OnEnable events have already been fired.

I’ve created some extension methods that fix this pain point by making it possible to pass arguments when Instantiating an object, which get delivered before the Awake and OnEnable events. With that HandleShootProjectile could be changed to be like this:

var projectile = projectilePrefab.Instantiate(damage, position, rotation);