Unity creating (clone)(clone)(clone) etc

I’m creating a script that shoots bullets and destroys them off screen, it works for the most part and creates (clones), as intended, and destroys them, unity the generates (clone)(clone)(clone) etc and doesn’t destroy them off screen, this severely slows the game down after a couple of shots. How do I stop generating these and only generating (clone) as a pose to (clone)(clone)(clone)'s? Thanks for help in advance.

public class Bullet : MonoBehaviour {
     public float offset = 128f;
 
     public GameObject projectilePrefab;
 
     private List<GameObject> Projectiles = new List<GameObject>();
 
     private float projectileVelocity;
 
     void Start (){
         projectileVelocity = 3;
     }
 
     void Update(){
         if (Input.GetButtonDown ("Fire1")) {
             GameObject bullet = (GameObject)Instantiate (projectilePrefab, transform.position, Quaternion.identity);
             Projectiles.Add (bullet);
         }
         for (int i = 0; i < Projectiles.Count; i++) {
             GameObject goBullet = Projectiles *;*

if (goBullet != null) {
goBullet.transform.Translate (new Vector3 (100, 0) * Time.deltaTime * projectileVelocity);
}

Vector3 bulletScreenPos = (Camera.main.WorldToScreenPoint(goBullet.transform.position));
if (bulletScreenPos.x >= Screen.width + offset || bulletScreenPos.x <= 0) {
DestroyObject (goBullet);
Projectiles.Remove (goBullet);
}
}
}
}

Unity adds “(Clone)” to a game object’s name that has been created with Instantiate(), regardless if it already had it in its name or not. So usually this is caused by assigning the instantiated game object to the prefab field, for example like this:

GameObject prefab = Instantiate(prefab, transform.position, Quaternion.identity);

However, I don’t see that happening in your code, so I am puzzled. Are you sure the code you posted is what is currently causing this problem?

Some other observations: as Shemamforash said, don’t use DestroyObject(), it is deprecated, replace it with Destroy(). Then I noticed you first call Destroy(goBullet); then Projectiles.Remove(goBullet);. This can cause a problem, because the == (equality) operator of GameObject is overridden and returns null once a game object is marked to be destroyed, so Remove() will not be able to correctly find the object to be removed. Just reverse the order of these 2 calls, and that shall fix the problem.

Finally, you control bullet movement in a centralised way, that is, the Update() function of one script controls them. Instead you could rename this script to BulletCreator and only keep the if (Input...) and Instantiate() lines in them (that is, remove even Projectiles list!). Then create a new Bullet script that would be attached to your bullet prefab and it would do what is in the body of the for loop: move the game object with Translate(), and Destroy() if it is outside the screen. This would be a lot more manageable, easier to understand, and object oriented approach.

public class BulletCreator : MonoBehaviour {

    [SerializeField] private Bullet bulletPrefab = null;

    private void Update () {
        if (Input.GetButtonDown("Fire1")) { Instantiate(bulletPrefab, transform.position, Quaternion.identity); }
    }

}

public class Bullet : MonoBehaviour {

    private void Update () {
        transform.Translate(new Vector3(100, 0) * Time.deltaTime * projectileVelocity);

        Vector3 bulletScreenPos = Camera.main.WorldToScreenPoint(transform.position);
        if (bulletScreenPos.x >= Screen.width + offset || bulletScreenPos.x <= -offset) {             Destroy(gameObject); }
    }

}

NOTE: I use -offset for the low check to make it symmetrical. Also, if the bullet leaves the view vertically, it will never be destroyed, so implementing check against Screen.height could be useful.

DestroyObject is deprecated, so should be using Destroy() instead. Not sure if that is causing the behaviour, so give it a try and let me know.

Also you are iterating through Projectiles and removing them. If you remove an element from a list as you are iterating through it you can get some weird behaviour. I suggest iterating backwards in order to avoid this issue e.g.

for(int i = Projectiles.Count - 1; i >= 0; --i){
    //your code
}

Also you shouldn’t have to check if goBullet is null, as you are removing it from the list immediately after destroying it, so it will never be null (unless you are destroying it from somewhere else as well?).

Hope this helps!

@Shemamforash ok that did something, the (clone)(clone)'s are now only generated if I repeatedly spam fire, is there anyway to stop this apart from implementing a fire rate system?