0
\$\begingroup\$

I was just trying and make a simple 2D game. I have a simple circle sprite (red, green and blue). These circles fly upwards with my scripting as shown below:-

public class Direction : MonoBehaviour {
    public GameObject[] ballons;
    public float increase;
    public float timeInterval;
    public float timeForGetGo;
    public float increaseInterval;

    public float startTime;
    public float timeForNextSpawn;
    public Transform instantiatePos;
    void Start () {;
        StartCoroutine (direction ());

    }

    void Update () {
        increase += increaseInterval;
        direction ();
        Instantiater ();
    }

    IEnumerator direction (){
        while (true){
            foreach (GameObject gameObjects in ballons) {
                gameObjects.transform.position = new Vector3 (gameObjects.transform.position.x, gameObjects.transform.position.y + increase, 0f);
                yield return new WaitForSeconds (timeInterval);

                }
                }

So, instead of making them fly with one script by one script, which I normally do, I tried to make array of these gameObjects and make them go upwards. **It worked great!** But, I have a problem. I want these upward going circle to instantiate but when I instantiate them, they won't go upwards as they aren't in the list of arrays I put earlier as in:-

public GameObject[] ballons;

in first line in that script.

So, as in conclusion, my problem is the instantiated objects won't have same property coz the script is attached to another gameobject and not in the original gamobject itself. Any ideas?

\$\endgroup\$
1
\$\begingroup\$

Your method of iterating over these objects looks very confused.

IEnumerator direction (){ 
    while (true){
        foreach (GameObject gameObjects in ballons) { 
            gameObjects.transform.position = new Vector3 (gameObjects.transform.position.x, gameObjects.transform.position.y + increase, 0f); 
            yield return new WaitForSeconds (timeInterval); 
        }
    }
}

This says:

  • take only the first balloon

  • raise it by increase (where the size of increase grows proportionate to the number of frames your script has been active)

  • wait for timeInterval seconds

  • then, after you're done waiting, take only the second balloon...

(Also, you start one copy of this coroutine going in Start, then run a new copy for only one cycle — affecting only the first balloon — each frame in Update, in addition to the one that's running in the background)

That doesn't sound like what you really want.

I think you can do this more cleanly by attaching the rising behaviour to your balloon:

public class Balloon : MonoBehaviour {
    public Vector3 velocity;
    public Vector3 acceleration;

    void Update() {
        velocity += acceleration * Time.deltaTime;
        transform.Translate(velocity * Time.deltaTime, Space.World);
    }
}

This way your balloons handle their own animation and accumulation of speed over their lifetime, and your spawner can concern itself purely with when to spawn what:

public class BalloonSpawner : MonoBehaviour {
    // Create a prefab of your balloon and assign it in the Inspector.
    public Balloon balloonPrefab;

    public float spawnInterval;

    IEnumerator Start() {
         var delay = new WaitForSeconds(spawnInterval);
         while(true) {
              Instantiate(balloonPrefab, transform.position, Quaternion.identity);
              yield return delay;
         }
    }
}

But if you really prefer to have the spawner handle their movement, and have all objects accelerate together according to its lifetime, I'd recommend separating it from your coroutine and doing it in update for smoother motion:

public class RisingSpawner : MonoBehaviour {
    // Create a prefab of your balloon and assign it in the Inspector.
    public Transform spawnPrefab;

    public float spawnInterval;
    public Vector3 initialVelocity;
    public Vector3 acceleration;

    float _lifetime;
    List<Transform> _spawned = new List<Transform>();

    IEnumerator Start() {
         var delay = new WaitForSeconds(spawnInterval);
         while(true) {
              Instantiate(spawnPrefab, transform.position, Quaternion.identity);
              yield return delay;
         }
    }

    void Update() {
        // Purge any destroyed instances from our list before we iterate it.
        _spawned.RemoveAll(item => item == null);

        _lifetime += Time.deltaTime;
        var velocity = initialVelocity + acceleration * _lifetime;

        var shift = velocity * Time.deltaTime;

        foreach(var instance in _spawned) {
             instance.Translate(shift, Space.World);
        }
    }
}
\$\endgroup\$
0
\$\begingroup\$

You need to add instantiated objects to that array, and since one does not simply stretch or shrink an array, use List<GameObject> instead.

You can then write where you instantiate an object: direction.ballons.Add (instantiatedObject);

For this, you should have a reference to Direction class instance that controls balls' movement.

\$\endgroup\$
3
  • \$\begingroup\$ It says "Collection was modified; enumeration cannot execute " error \$\endgroup\$ – Sabin Pyakurel Aug 27 '19 at 13:40
  • \$\begingroup\$ @SabinPyakurel well, that is the problem of changing a collection that's being iterated upon. I use for instead of foreach to avoid it and when an object is removed, I mark it as removed and delete them from list only after iterating. \$\endgroup\$ – trollingchar Aug 27 '19 at 14:20
  • 1
    \$\begingroup\$ @trollingchar No need for that, simply run the for loop backwards. \$\endgroup\$ – S. Tarık Çetin Aug 27 '19 at 17:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.