Keeping variable from changing on another scene load - unity3d

I'm new to unity and i'm trying to load scenes based on items collected.
Problem is that the counter is not counting my acquired items.
I'm using OnTriggerEnter2D() to trigger the event; Below is the snippet:
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("Player"))
{
collectionNumber += 1;
Destroy(gameObject);
if (collectionNumber == 1)
{
collision.gameObject.transform.Find("Acquired_Items").GetChild(0).gameObject.SetActive(true);
qiCollector.gameObject.transform.GetChild(0).gameObject.SetActive(true);
}
else if (collectionNumber == 2)
{
collision.gameObject.transform.Find("Acquired_Items").GetChild(1).gameObject.SetActive(true);
qiCollector.gameObject.transform.GetChild(1).gameObject.SetActive(true);
}
else if (collectionNumber == 3)
{
collision.gameObject.transform.Find("Acquired_Items").GetChild(2).gameObject.SetActive(true);
qiCollector.gameObject.transform.GetChild(2).gameObject.SetActive(true);
}
else
{
Debug.LogWarning("All Items Collected !!");
}
cN.text = "Collection Number " + collectionNumber.ToString();
}
}
Whenever a new scene is loaded this script is loaded because it is on my quest item. And for every scene there is a quest item. So what I want to do is basically keep track of my collectionNumber, but it resets to 0.
Any help is much appreciated :)

First method:
Don't allow your object to be destroyed on scene load
https://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html
public static void DontDestroyOnLoad(Object target);
Above code will prevent destroying your GameObject and its components from getting destroyed when loading a new scene, thus your script values
Second Method:
Write out your only value into a player pref
https://docs.unity3d.com/ScriptReference/PlayerPrefs.html
// How to save the value
PlayerPrefs.SetInt("CollectionNumber", collectionNumber);
// How to get that value
collectionNumber = PlayerPrefs.GetInt("CollectionNumber", 0);
Third method:
Implement a saving mechanism:
In your case i would not suggest this

Related

How to stop GameObject duplications when reloading a scene?

I'm making a game where the player can switch back and forth between levels. I use "DontDestroyOnLoad" to bring my player between them, but whenever I reload a scene, it duplicates the player, as well as everything else I want to keep loaded. Does anyone know any easy fix to this? I'm new to programming so keep it simple please.
probably you need to write something like this:
public static <TypeName> instance = null;
void Awake() {
if (instance != null) {
Destroy(gameObject);
} else {
instance = this;
DontDestroyOnLoad(gameObject);
}
}

How do I change GameObject properties in scripts Unity?

I'm trying to save/load my game. In the load method, everytime I change the properties of a GameObject, those changes are applied and then get reverted shortly after. Here is my code:
public void Load()
{
SceneManager.LoadScene(sceneID);
List<GameObject> rootObjects = new List<GameObject>();
Scene scene = SceneManager.GetActiveScene();
scene.GetRootGameObjects(rootObjects);
int ncube = 0, npick = 0;
for (int i = 0; i < rootObjects.Count; ++i)
{
GameObject obj = rootObjects[i];
if (obj.CompareTag("Player"))
{
obj.transform.position = player.position;
obj.transform.rotation = player.rotation;
obj.transform.localScale = player.localScale;
}
else if (obj.CompareTag("Cube"))
{
obj.transform.position = cube[ncube].position;
obj.transform.rotation = cube[ncube].rotation;
obj.transform.localScale = cube[ncube].localScale;
++ncube;
}
else if (obj.CompareTag("Pickup"))
obj.SetActive(pickup[npick++]);
else if (obj.CompareTag("Door"))
obj.SetActive(door);
else if (obj.CompareTag("GreenWall"))
obj.SetActive(greenWall);
}
}
Those changes are applied to the GameObject, however they get aborted right away. How can I resolve this?
The script contains these lines of code is not a component of the GameObject.
Edit 1: Complete code updated.
Problem is I think that
Scene scene = SceneManager.GetActiveScene();
scene.GetRootGameObjects(rootObjects);
gets the objects from the scene before the Scene is fully loaded so they are reset.
From the Docu
When using SceneManager.LoadScene, the loading does not happen immediately, it completes in the next frame. This semi-asynchronous behavior can cause frame stuttering and can be confusing because load does not complete immediately.
I guess you rather should use SceneManager.sceneLoaded and do your stuff there like
public void Load()
{
SceneManager.LoadScene(sceneID);
}
And maybe in an extra component within the scene:
void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
// your stuff here
}
void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
though we don't know/see where player, cube[ncube] etc come from ...
for transparting values between Scenes you should get into using ScriptableObjects
The problem might be that SceneManager.LoadScene completes in the next frame. See the documentation: https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadScene.html
It says:
When using SceneManager.LoadScene, the loading does not happen
immediately, it completes in the next frame. This semi-asynchronous
behavior can cause frame stuttering and can be confusing because load
does not complete immediately.
You change the values within the same frame, thus they are overwritten when loading the scene finishes. Cou could use an event to prevent that behaviour: https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager-sceneLoaded.html

ARCore + Unity + Augmented Images - Load different prefabs for different Images

How do I assign different prefabs to different images?
right now, I have all my prefabs loading in on top of each other but how do I get it so each prefab loads in only once on top of one image so each image has a different prefab?
I've modified the sample code (the frame corners) to load in my own prefab and used a dictionary to pair the prefabs with images from the database but when the program runs it instatiates all the prefabs in the same place rather than putting one prefrab on each image it puts all the prefabs on every image - this is the code I've been using:
public GameObject obj1, obj2, obj3, obj4;
Dictionary<int, GameObject> imagePrefabPairs;
public AugmentedImage Image;
void Start()
{
instantiateDictionary();
}
// TODO: make initialisation dynamic, to match the size of the db.
public void instantiateDictionary()
{
imagePrefabPairs = new Dictionary<int, GameObject>
{
{ 0, obj1 },
{ 1, obj2 },
{ 2, obj3 },
{ 3, obj4 }
};
}
public void Update()
{
if (Image == null || Image.TrackingState != TrackingState.Tracking)
{
obj1.SetActive(false);
obj2.SetActive(false);
obj3.SetActive(false);
obj4.SetActive(false);
return;
}
Pose _centerPose = Image.CenterPose;
imagePrefabPairs[Image.DatabaseIndex].transform.localPosition = _centerPose.position;
imagePrefabPairs[Image.DatabaseIndex].transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
imagePrefabPairs[Image.DatabaseIndex].SetActive(true);
}
I figure that I need to have some kind of if statement to ask if one prefab is loaded in and then just choose to load in the next one and have them instantiate one at a time but I am not sure how to do that, or if there is a more direct way to make that happen...?
You could change your AugmentedImageVisualizer prefab, so that at the start all your different objects are inactive (.SetActive(false);) For changing a prefab you can add it to your hierarchy, set all the objects inactive and then apply the changes. After apply you can delete the prefab from your game hierarchy.
Img 1: Add existing prefab to game hierarchy
Img 2: set all the attached objecty to inactive (1) and apply the changes to the prefab (2)
So when you detect a image from your imagedatabase the AugmentedImageVisualizer prefab is attached and only the object with the given index is set to active. Then your code should work.
Because at the start all your objects are inactive you could change this part of your code:
if (Image == null || Image.TrackingState != TrackingState.Tracking)
{
obj1.SetActive(false);
obj2.SetActive(false);
obj3.SetActive(false);
obj4.SetActive(false);
return;
}
so that you only deactivate the active object:
if (Image.TrackingState != TrackingState.Tracking)
{
imagePrefabPairs[Image.DatabaseIndex].SetActive(false);
return;
}
I assign different prefabs to different images by this way:
I modified the AugmentedImageExampleController.cs:.
I added a list for prefabs:
public List<AugmentedImageVisualizer> prefabs = new List<AugmentedImageVisualizer>();
For the related image for the prefab I did a reference by using the image.DatabaseIndex in the visualizer:
visualizer = (AugmentedImageVisualizer)Instantiate(prefabs[image.DatabaseIndex], anchor.transform);
In the inspector of ExampleController you can put in the prefabs (AugmentedImageVisualizer) now.
That's it, and its working fine!

Save active Scene Unity 3D

I am trying to save modification made when the scene is loaded (new object instantiated ..) and I would like to load them after.
My script is :
public void SaveGame()
{
PlayerPrefs.SetInt("Level", SceneManager.GetActiveScene().buildIndex);
PlayerPrefs.Save();
print("Game saved!");
Debug.Log("Game normally saved " + scene.name);
}
public void LoadGame()
{
SceneManager.LoadScene(PlayerPrefs.GetInt("Level"));
print("Game loaded!");
Debug.Log("Game normally Loaded ");
}
The problem is when I save the game , it saves the Scene which is in my asset but I want to save this scene without any modifications.
I think that I should get the scene active but with modifications so I should modify this part of code:
PlayerPrefs.SetInt("Level", SceneManager.GetActiveScene().buildIndex);
So is there any way to do this ?

Strange If/Else Behavior

Context
I am making a mobile game in which the player is required to touch objects in a specified order. The correct order is determined in a List called clickOrder. To determine the current object the player is supposed to click, currClickIndex is used.
Problem
When touching a correct object, the debug text will display "Correct" for a split second, and will then immediately change to "Wrong." What I am unsure about is why both the if and else blocks are executed when only touching a single object.
Code
void Update()
{
if (Input.touchCount == 1)
{
if (this.enabled)
{
Vector2 worldPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(worldPoint, Vector2.zero);
if (hit != null && hit.collider != null)
{
// check if the touched object is the correct one
if (hit.collider.gameObject == clickOrder[MyData.currClickIndex])
{
debug.text = "Correct";
MyData.currClickIndex++;
}
else
{
debug.text = "Wrong";
}
}
}
}
}
As soon as the correct object is being touched, you do this:
MyData.currClickIndex++;
which moves you forward in the ordered sequence, and from then on, the previously correct object is not correct anymore. But you're still touching it.
If you want to avoid this, you need to move forward in the sequence after you've touched the correct object.
if (there are touches and the correct object is being touched)
{
set a flag;
}
else if (a flag has been set)
{
MyData.currClickIndex++;
reset the flag;
}