The question is answered, right answer was accepted
Solved - only spawn item pickups if not previously picked up
Fixed the problem, see answers for corrected code for the entire item pickup system I've built
My goal here was to create a system to only spawns items if the player hasn't previously picked them up while being in the current scene. The problem I initially had was figuring out how to pass on the knowledge of whether or not an item was picked up after the scene was reloaded on player death. At first I intended to store all of the information in playerprefs, but I decided that I didn't want to clutter up that file with a ton of keys. So I moved on to using another script with dontdestroyonload to hold the information in arrays. I had a lot of difficulty getting this to work as intended, but I now have a working system that I'll briefly outline:
The ItemManifest script has two arrays GameObject[] items and bool[] itemsCollected. items[] is set via the unity editor with the spawnPoints for each scene individually. With a lot of difficulty I worked out the if statements necessary to destroy the dontdestroyonload ItemManifest when a new scene is loaded (not the current scene being reloaded if player died). itemsCollected is set in the PickupManager script, by searching through items[] to find the current item (had to make the item spawned a child of the spawn point, then check if the item's parent was equal to items[i]) so that the appropriate position in itemsCollected[] is set to true. The PickupSpawner script checks itemsCollected[] if an element is false, instantiate the appropriate item for that spawn point (the items being instantiated are set up as prefabs.
ItemManifest is attached to an empty game object. Spawn Points are children of the manifest object and are also empty game objects, with the pickup spawner script attached. The instantiated Items are children of the spawnpoints and have the pickupManager script attached.
Also worth noting, everytime I call SceneManager.LoadScene() in any script I'm also doing
PlayerPrefs.SetString("LastScene", SceneManager.GetActiveScene().name);
I didn't receive much help in the questions I created regarding this topic, but I feel like I should thank the general answers community because I adapted a lot of what I did from answers to vaguely similar questions on here, I actually learned a huge amount of stuff in the process of figuring this out.
Answer by mmorro1222 · Nov 13, 2016 at 09:18 AM
I realized I was using this.transform rather than item.transform, to check if there were other children of the spawn point. Even though this and item should technically be the same thing and it worked for the health and life pickups, changing this.transform to item.transform seems to have fixed the problem with coins being instantiated twice per spawn point.
Dumping all scripts previously mentioned in the many revisions of this question, because I noticed a good number of people are following this question.
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class PickupSpawner : MonoBehaviour
{
public GameObject coinPickup, healthPickup, lifePickup;
private Object clone;
public ItemManifest manifest;
void Awake()
{
manifest = GetComponentInParent<ItemManifest>();
StartCoroutine(startSpawn());
}
//IEnumerator to delay spawning items so ItemManifest has time to set collected array size.
IEnumerator startSpawn()
{
yield return new WaitForSeconds(0.2f);
//spawn items if not collected
for (int i = 0; i < manifest.items.Length; i++)
{
if (manifest.itemsCollected[i] == false)
{
Spawn(manifest.items[i]);
}
}
}
void Spawn(GameObject item)
{
if (item.tag == "CoinSpawn")
{
clone = Instantiate(coinPickup, item.transform.position, Quaternion.identity, item.transform);
if (item.transform.childCount > 1)
{
Destroy(clone);
}
}
else if (item.tag == "HealthSpawn")
{
clone = Instantiate(healthPickup, item.transform.position, Quaternion.identity, item.transform);
if (item.transform.childCount > 1)
{
Destroy(clone);
}
}
else if (item.tag == "LifeSpawn")
{
clone = Instantiate(lifePickup, item.transform.position, Quaternion.identity, item.transform);
if (item.transform.childCount > 1)
{
Destroy(clone);
}
}
}
}
using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
public class ItemManifest : MonoBehaviour
{
public GameObject[] items;
public bool[] itemsCollected;
// Use this for initialization
void Awake()
{
if (GameObject.FindGameObjectsWithTag("Manifest").Length < 1)
{
DontDestroyOnLoad(this);
//PlayerPrefs.SetString("LastScene", SceneManager.GetActiveScene().name);
}
this.tag = "Manifest";
if (PlayerPrefs.GetString("LastScene") == SceneManager.GetActiveScene().name && GameObject.FindGameObjectsWithTag("Manifest").Length > 1)
{
Destroy(gameObject);
}
PlayerPrefs.SetString("LastScene", SceneManager.GetActiveScene().name);
itemsCollected = new bool[items.Length];
}
void Update()
{
if (PlayerPrefs.GetString("LastScene") != SceneManager.GetActiveScene().name)
{
Destroy(gameObject);
}
}
public void setCollected(int i)
{
itemsCollected[i] = true;
}
}
using UnityEngine;
using System.Collections;
public class PickupManager : MonoBehaviour
{
public PlayerManager player;
public AudioSource sound;
public ItemManifest manifest;
private bool collected;
// Use this for initialization
void Awake()
{
player = GameObject.FindWithTag("Player").GetComponent<PlayerManager>();
sound = GetComponent<AudioSource>();
collected = false;
manifest = GameObject.Find("ItemManifest").GetComponent<ItemManifest>();
}
// Update is called once per frame
void Update()
{
if (!sound.isPlaying && collected == true)
Destroy(gameObject);
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player" && collected == false)
{
collected = true; //used to determine when to Destroy the gameObject
//search through item array to find this item
for (int i = 0; i < manifest.items.Length; i++)
{
if (this.transform.parent.gameObject == manifest.items[i])
{
manifest.setCollected(i);
}
}
//if-else block to determine effect of item
if (this.gameObject.tag == "Coin")
{
player.score += 1;
}
else if (this.gameObject.tag == "Health")
{
player.hearts = 3;
}
else if (this.gameObject.tag == "Life")
{
player.lives += 1;
}
//play coin/health/life pickup sound
sound.Play();
//remove game object from view, later destroyed when sound is not playing via update function
this.transform.localScale = new Vector3(0, 0, 0);
}
}
}