I have created coins in a scene in unity that the player can collect and will disappear upon collection. however when the player leaves the scene and then comes back the coins reappear how can I prevent the coins from reappearing?
I have already tried using playerPrefs and that has not worked. I also know that I will need to use XML or JSON files in some way. I have tried using some basic saving and load mechanics with a Boolean that is false on start but when a coin is picked up it is set to true to prevent coins from respawning. However this has not worked as it applies to all coins in the scene not just the one picked up.
My current Idea is that I would use an array to get the positions of all the coins and other essentially data and iterate though it when the scene loads to check if the coin should spawn. However I do not know what code for this would look like.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.IO;
public class CoinScript : MonoBehaviour
{
private Transform myTransform;
[SerializeField] float rotationSpeed;
CoinCounterScript coinCounterScript;
public Transform CoinCounterText;
public GameObject CoinCounterTextOBJ;
public GameObject player;
public GameObject bullet;
[SerializeField] public bool isCollected;
[SerializeField] float speed;
public Boolean coinStored;
private string dataPath;
void Awake()
{
dataPath = Application.persistentDataPath + "/Player_Data/";
SaveObject coinStatus = new SaveObject
{
hasBeenCollected = false
};
string json = JsonUtility.ToJson(coinStatus);
Debug.Log(json);
SaveObject loadedSaveObject = JsonUtility.FromJson<SaveObject>(json);
saveData();
//loadData();
}
private void saveData()
{
SaveObject CoinStatusCollected = new SaveObject
{
//hasBeenCollected = true,
};
if(CoinStatusCollected.hasBeenCollected == false)
{
this.gameObject.SetActive(true);
Debug.Log("not collected");
}
else if(CoinStatusCollected.hasBeenCollected == true)
{
this.gameObject.SetActive(false);
}
string json = JsonUtility.ToJson(CoinStatusCollected);
Debug.Log(json);
// create file and place it in the data path
File.WriteAllText(dataPath + "CoinTestSave.txt", json);
}
public void loadData()
{
Debug.Log("calling loadData");
if(File.Exists(dataPath + "CoinTestSave.txt"))
{
string saveString = File.ReadAllText(dataPath + "CoinTestSave.txt");
SaveObject saveObject = JsonUtility.FromJson<SaveObject>(saveString);
Debug.Log("Coin status " + saveObject.hasBeenCollected);
//saveObject.hasBrokenDoor = true;
if(saveObject.hasBeenCollected == false)
{
this.gameObject.SetActive(true);
Debug.Log("not collected");
}
else if(saveObject.hasBeenCollected == true)
{
this.gameObject.SetActive(false);
Debug.Log("has been collected");
}
}
else
{
Debug.Log("no save");
}
}
// Start is called before the first frame update
void Start()
{
myTransform = this.GetComponent<Transform>();
coinCounterScript = GameObject.FindObjectOfType<CoinCounterScript>();
isCollected = false;
loadData();
}
void OnEnable()
{
// code below is used to ignore collisions
//with projectiles elsewhere in my game
GameObject[] otherObjects = GameObject.FindGameObjectsWithTag("PlayerProjectile");
foreach (GameObject obj in otherObjects)
{
Physics2D.IgnoreCollision(obj.GetComponent<Collider2D>(), GetComponent<Collider2D>());
}
}
// Update is called once per frame
void Update()
{
//while it not collected coin plays anim
if(isCollected == false)
{
myTransform.Rotate(rotationSpeed * Time.deltaTime, 0 ,0);
}
// when coin is collected it moves towards the
// coin counter on the left hand side of the screen
if(isCollected == true)
{
var step = speed * Time.deltaTime;
myTransform.Rotate(0, 0 ,0);
transform.position = Vector3.MoveTowards(transform.position, CoinCounterText.position, step);
Invoke("DestroySelf", 5);
}
// code to handle edgecases of class fields
//becoming null
if(player == null)
{
player = GameObject.FindGameObjectWithTag("Player");
//playerCol = player.GetComponent<BoxCollider2D>();
}
if(CoinCounterText == null)
{
CoinCounterTextOBJ = GameObject.FindGameObjectWithTag("UITestTag");
CoinCounterText = CoinCounterTextOBJ.GetComponent<Transform>();
}
}
public void OnCollisionEnter2D(Collision2D col)
{
//Destroy(gameObject);
if(col.gameObject.tag == "Player")
{
//coinCounterScript.CoinCounterTXT.enabled = true;
if(isCollected == false)
{
isCollected = true;
int collectedCollectableLayer = LayerMask.NameToLayer("CollectibleUnCollideable");
this.gameObject.layer = collectedCollectableLayer;
}
}
}
public void OnTriggerEnter2D(Collider2D col)
{
//when coin hits the coinCounter
// it is destroyed and the amount of coins
// the player has increases
if(col.gameObject.tag == "UITestTag")
{
Destroy(gameObject);
SaveObject saveObject = new SaveObject();
saveObject.hasBeenCollected = true;
saveData();
}
}
public void DestroySelf()
{
Destroy(gameObject);
}
public class SaveObject
{
public Boolean hasBeenCollected;
}
}
2
Answers
playerprefs can work quite nicely, at least if you dont have thousands of coins.
give each coin an id
then when you get the coin, do this
and in your coins start method do this
if you have a lot more coins
then use a package that creates a better playerprefs. or just go json
try using set active false use a script to detect collisions with the player, add a trigger event, and disable the coin after collection