0
\$\begingroup\$

I made a car game with coins and power up but i wrote a code for magnet power up but in start work fine but after i get power up magnet all coin in surface i collect but after this don`t spawn coin any more and show me this error: Picture 1. And here my code: Picture 1

//Car script
//PowerUp Magnet Sector
    public bool magnetPowerUp = false;
    public float MagnetDuration;
    
    
     private void OnCollisionEnter2D(Collision2D col)
    {
        //Magnet
        if (col.gameObject.tag == "Magnet")
        {
            col.gameObject.SetActive(false);
            StartCoroutine(Magnet());
        }
     }
     
     IEnumerator Magnet()
    {
        magnetPowerUp = true;
        yield return new WaitForSeconds(MagnetDuration);
        magnetPowerUp = false;
    }

    //CoinScript
    
    using UnityEngine;
using System.Collections;

public class CoinSpaws : MonoBehaviour
{
    public carController car;
    public GameObject player;
    public GameObject[] coins;
    int coinNo;
    public float maxPos = 1.7f;
    public float delayTimer;
    float timer;

    // Use this for initialization
    void Start()
    {

        timer = delayTimer;

    }

    // Update is called once per frame
    void Update()
    {

        timer -= Time.deltaTime;
        if (timer <= 0)
        {

            Vector3 coinPos = new Vector3(Random.Range(-1.7f, 1.7f), transform.position.y, transform.position.z);
            coinNo = Random.Range(0, 2);
            Instantiate(coins[coinNo], coinPos, transform.rotation);
            timer = delayTimer;

        }

        if (car.magnetPowerUp)
        {
            coins = GameObject.FindGameObjectsWithTag("coin");
            foreach (var treasure in coins)
            {
                treasure.transform.position = Vector2.MoveTowards(treasure.transform.position, player.transform.position, 5.0f * Time.deltaTime);
            }
        }
    }


}

enter image description here

\$\endgroup\$
2
\$\begingroup\$

You're using your coins array to do double duty:

  • first, it acts as a list of (2) possible coin prefabs to randomly choose from for spawning new coins.

  • then, it acts as a list of all coins currently active in your game scene, so you can attract them to your magnet power.

So think of what happens once your magnet has sucked up all the coins. Now FindObjectsOfType gives you an empty array, since there's no coins left in your scene. The next time you try to spawn a coin, you're trying to select the first or second item in an array of zero items, which generates an index out of range error.

To fix this, you should use a separate variable for each job. One variable stores your coin prefabs to use for spawning, and one tracks your currently active coins. Don't overwrite one with the other.

And, ideally, don't search your whole scene for coins every frame. ;) It's much more efficient to just add them to a list as you spawn them, and remove them as they're collected.


Since you asked for code examples, I'd recommend refactoring this substantially, to put the responsibility for counting & enumerating coins on the coin objects themselves:

using System.Collections.Generic;

public class Coin : MonoBehaviour {

    // The Coin class will keep track of how many of its instances have been spawned.
    static List<Coin> _activeInstances = new List<Coin>;
    static void Add(Coin coin) {
        coin._index = _activeInstances.Count;
        _activeInstances.Add(coin);        
    }
    static void Remove(Coin coin) {
        // Swap the last coin into the gap left by this one.
        _activeInstances[coin._index] = _activeInstances[_activeInstances.Count - 1];
        _activeInstances[coin._index]._index = coin._index;
        // Shorten our list of coins by one.
        _activeInstances.RemoveAt(_activeInstances.Length - 1);
    }

    public static void AttractAll(Vector3 target, float speed) {
        foreach(var coin in _activeInstances) {
            // If using physics triggers for coin collection, consider using
            // Rigidbodies & velocity instead of manipulating position directly.
            Vector3 pos = coin.transform.position;
            pos = Vector3.MoveTowards(pos, target, speed * Time.deltaTime);
            coin.transform.position = pos;
        }
    }

    int _index;
    void Awake() {
        Coin.Add(this);
    }
    void OnDestroy() {
        Coin.Remove(this);
    }

    // If you're using OnTriggerEnter or similar messages to trigger 
    // coin collection, you can put that here, or on the player.
}

Now our Spawner doesn't need to know anything about the kinds of objects it's spawning, or about the car or magnets. It doesn't even need an Update loop anymore, it can just run a periodic coroutine to spawn more coins.

public class Spawner : MonoBehaviour {
    public float spawnInterval = 3f;
    public GameObject[] spawnPrefabs;
    Vector2 SpawnVariation = new Vector2(1.7f, 0f);

    void Start() {
        StartCoroutine(Spawn());
    }

    IEnumerator Spawn() {
        while(true) {
            yield return new WaitForSeconds(spawnInterval);

            int spawnIndex = Random.Range(0, spawnPrefabs.Length);
            Vector3 position = transform.position;
            position.x += Random.Range(-1f, 1f) * spawnVariation.x;
            position.y += Random.Range(-1f, 1f) * spawnVariation.x;
            var instance = Instantiate(spawnPrefabs[spawnIndex], position, Quaternion.Identity);            
        }
    }
}

And the attraction can happen be handled within our magnet powerup script, rather than in the spawners or on the coins, so neither needs to know about the player or magnets.

IEnumerator Magnet() {
    magnetPowerUp = true;
    for(float t = 0; t < MagnetDuration; t += Time.deltaTime) {
        Coin.AttractAll(transform.position, 5.0f);
        yield return null;
    }
    magnetPowerUp = false;
}
\$\endgroup\$
3
  • \$\begingroup\$ any quickly code to help this \$\endgroup\$ – Driton Jul 1 '17 at 17:40
  • \$\begingroup\$ thank you so much this code work fine but i have one more question about magnet. when i use magnet i collect coins immediately from spawn but i like to collect eg. box collider and to collect coins just when coins touch the box collider. For example see last picture. \$\endgroup\$ – Driton Jul 6 '17 at 14:35
  • 1
    \$\begingroup\$ That sounds like a new question you should put into a new post, if you can't find an answer by searching in the existing Q&A and tutorials available. \$\endgroup\$ – DMGregory Jul 6 '17 at 14:53

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.