Managing many projectile gameobjects with respect to source and destination gameobjects.

Hello, I am having an issue regarding managing projectiles in my game.

The idea that I am trying to achieve is for a unit to fire a projectile which then follows the target until it hits it, triggering damage. If the target dies before the remaining bullets have reached it, those bullets will travel to the targets last location.

On my first unit (soldier), in order to attack I enable a pooled projectile at the location of solider and set it as a child of the target unit (demon). The projectile has a script which basically gets the target gameobject from the parent it’s attached to as a reference, then changes its parent to the _PooledItems gameobject. The reason for moving the projectile to another parent is because I want the bullets to persist even if the target demon is destroyed (any bullets still travelling disappear if I destroy the demon). So basically i get my target info from the parent transform, change the parent to something else then continue with my script which moves the projectile to my target:

void OnEnable ()
    {
        Transform parent = GameObject.Find("_PooledItems").transform;
        targetObject = gameObject.transform.parent.gameObject;
        gameObject.transform.SetParent(parent);
        dest = targetObject.transform.position;
    }
    void Update ()
    {   
        if (targetObject == null)
        {
            gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, dest, Time.deltaTime * projectileSpeed);
            if (gameObject.transform.position == dest)
            {    
                gameObject.SetActive(false);
            }
        }
        else
        {
            RotateTowards(targetObject.transform);
            dest = targetObject.transform.position;
            gameObject.transform.position = Vector3.MoveTowards(gameObject.transform.position, dest, Time.deltaTime * projectileSpeed);

            if (gameObject.transform.position == dest)
            {             
                UnitEngine.takeDamage(damage, targetObject);
                gameObject.SetActive(false);
            }
        }

Problem:
I am using the parent of the projectile gameobject as a means to get the target info because I cannot think of how else to pass it this knowledge. This causes issues where target gameobjects are destroyed before another bullet has moved to a different parent causing some bullets to go missing.

Ideally I would like to enable a projectile gameobject, give it the knowledge of what unit shot it and what unit it’s target is.

Any ideas how to solve this problem?

As a bonus criteria, the solution will be potentially run thousands of times at once (think bullet hell, hence the object pooling) so I would like to avoid lengthy function calls if possible.

You could create a ‘Target’ GameObject. It contains a single script ‘BulletList’ and is attached to a demon. Bullets actually target the ‘Target’ and add themselves to the ‘BulletList’. When a bullet hits the ‘Target’, it removes itself from the ‘BulletList’.

When a demon dies, it leaves its (invisible) ‘Target’ behind. To do this just un-parent the Target.

Now, when a ‘Target’ has no parent and no bullets in its ‘BulletList’ it can safely be removed having “consumed” all its bullets.

To be honest that seems like a very strange implementation you’ve decided to use.

You have a few criteria

  1. figure out which unit shot the bullet
  2. figure out which target was shot at
  3. track the target’s existance. if it dies, pass the last known transform to the bullet

at no point does any of this need to (or should be) connected to other stuff (again, personal opinion).

Ideally, you should have some kind of BulletManager.cs script that is responsible for the general management of spawning bullets, determining their direction and, ultimately, destroying them. (the benefit of keeping it compartmentalised is a cleaner workflow)

I think writing out copy/paste code would be a little much because it would be a large system, but I can suggest some concepts.

// reference the end of each soldier's gun (this is how we know where the bullet starts)

public GameObject Solider1GunEnd;
public GameObject Solder2GunEnd;
public GameObject Soldier3GunEnd;

assuming they might not already exist, you would have to grab the component itself

public GameObject Solider1GunEnd;

void Start()
{
    Soldier1GunEnd = GameObject.FindWithTag("Soldier1");
}

Now it gets a little more complicated. You want a bullet to be shot, and for it to “chase” the enemy until they die (and if they die, the bullet should be destroyed)

To do this, you would need to reference the enemies in question in order to get their transform.position (or transform.localPosition)

// rerence the enemies so we can grab their world (or local) position. (so you can make the bullet follow the enemy)

public GameObject Enemy1;
public Vector3 Enemy1Position;


void UpdateEnemy1Position()
{
    float Enemy1X = Enemy1.transform.position.x;
    float Enemy1Y = Enemy1.transform.position.y;
    float Enemy1Z = Enemy1.transform.position.z;

    Enemy1Position = new Vector3(Enemy1X, Enemy1Y, Enemy1Z);
}

You could pass the Vector3 to the bullet X times a frame (60/30/10/5 etc. whatever you want for performace) and just move the bullet based on the enemy world position. When it dies,
you could have a onDeath() method that sets the Vector3 position before destroying the enemy, and then you have the bullets “final destination” transform.