Scripts lost all data when load scene?

I’m create this script to handle the Claim VFX when user claim rewards in the Menu scene:

using DG.Tweening;
using UnityEngine;
using UnityEngine.Pool; 
using UnityEngine.UI;

public class RewardClaimVFX : MonoBehaviour
{
    [Header("VFX")]
    public GameObject rewardPrefab;
    public Transform rewardParent;
    public Transform rewardStart;
    public Transform rewardEnd;

    public Sprite goldSprite;
    public Sprite silverSprite;
    public Sprite coinSprite;

    public Transform coinMenuPos;
    public Transform silverMenuPos;
    public Transform goldMenuPos;
    public Transform coinShopPos;
    public Transform silverShopPos;
    public Transform goldShopPos;

    public float duration;
    public float rewardDelay;
    public float totalDelay;
    public Ease moveEase;

    // Unity Object Pool
    private ObjectPool<GameObject> rewardPool;

    private void OnEnable()
    {
        // Initialize the pool for reward objects
        rewardPool = new ObjectPool<GameObject>(
            createFunc: () =>
            {
                //Debug.Log(rewardParent);
                return Instantiate(rewardPrefab, rewardParent);
            },
            actionOnGet: obj => obj.SetActive(true),
            actionOnRelease: obj => obj.SetActive(false),
            actionOnDestroy: obj => Destroy(obj),
            defaultCapacity: 10,
            maxSize: 20
        );

        Debug.Log(rewardParent, this);
    }

    private void Start()
    {
        // Log all the public variables
        Debug.Log("rewardPrefab: " + rewardPrefab);
        Debug.Log("rewardParent: " + rewardParent);
        Debug.Log("rewardStart: " + rewardStart);
        Debug.Log("rewardEnd: " + rewardEnd);

        Debug.Log("goldSprite: " + goldSprite);
        Debug.Log("silverSprite: " + silverSprite);
        Debug.Log("coinSprite: " + coinSprite);

        Debug.Log("coinMenuPos: " + coinMenuPos);
        Debug.Log("silverMenuPos: " + silverMenuPos);
        Debug.Log("goldMenuPos: " + goldMenuPos);

        Debug.Log("coinShopPos: " + coinShopPos);
        Debug.Log("silverShopPos: " + silverShopPos);
        Debug.Log("goldShopPos: " + goldShopPos);

        Debug.Log("duration: " + duration);
        Debug.Log("rewardDelay: " + rewardDelay);
        Debug.Log("totalDelay: " + totalDelay);
        Debug.Log("moveEase: " + moveEase);
    }


    public void ClaimVFX(RewardType type, int amount, int currentPage)
    {
        // Log all the public variables to see their values when ClaimVFX is called
        Debug.Log("rewardPrefab: " + rewardPrefab);
        Debug.Log("rewardParent: " + rewardParent);
        Debug.Log("rewardStart: " + rewardStart);
        Debug.Log("rewardEnd: " + rewardEnd);

        Debug.Log("goldSprite: " + goldSprite);
        Debug.Log("silverSprite: " + silverSprite);
        Debug.Log("coinSprite: " + coinSprite);

        Debug.Log("coinMenuPos: " + coinMenuPos);
        Debug.Log("silverMenuPos: " + silverMenuPos);
        Debug.Log("goldMenuPos: " + goldMenuPos);

        Debug.Log("coinShopPos: " + coinShopPos);
        Debug.Log("silverShopPos: " + silverShopPos);
        Debug.Log("goldShopPos: " + goldShopPos);

        Debug.Log("duration: " + duration);
        Debug.Log("rewardDelay: " + rewardDelay);
        Debug.Log("totalDelay: " + totalDelay);
        Debug.Log("moveEase: " + moveEase);

        Debug.Log(rewardParent, this);

        amount = (type == RewardType.COIN) ? amount / 5 : amount;

        for (int i = 0; i < amount; ++i)
        {
            var targetDelay = i * rewardDelay;
            ShowReward(type, targetDelay, currentPage);
        }
    }

    public void ShowReward(RewardType type, float delay, int currentPage)
    {

        // Get a pooled object
        var rewardObject = rewardPool.Get();

        switch (type)
        {
            case RewardType.GOLD:
                rewardObject.GetComponent<Image>().sprite = goldSprite;
                rewardEnd = (currentPage < 0) ? goldShopPos : goldMenuPos;
                break;

            case RewardType.SILVER:
                rewardObject.GetComponent<Image>().sprite = silverSprite;
                rewardEnd = (currentPage < 0) ? silverShopPos : silverMenuPos;
                break;

            case RewardType.COIN:
                rewardObject.GetComponent<RectTransform>().sizeDelta = new Vector2(100f, 100f);
                rewardObject.GetComponent<Image>().sprite = coinSprite;
                rewardEnd = (currentPage < 0) ? coinShopPos : coinMenuPos;
                break;
        }

        var endPos = Camera.main.WorldToScreenPoint(rewardEnd.position);
        var offset = new Vector3(UnityEngine.Random.Range(-100f, 100f), UnityEngine.Random.Range(-100f, 100f), 0f);
        var startPos = offset + rewardStart.position;

        rewardObject.transform.position = startPos;
        rewardObject.transform.localScale = new Vector3(1f, 1f, 1f);

        rewardObject.transform.DOScale(Vector3.one, delay);
        rewardObject.transform.DOMove(endPos, duration)
            .SetEase(moveEase)
            .SetDelay(delay)
            .OnComplete(() =>
            {
                // Release the object back into the pool after the animation finishes
                rewardPool.Release(rewardObject);
            });
    }

    private void OnDestroy()
    {
        // Ensure the pool is cleared when this object is destroyed
        rewardPool.Clear();
    }
}

This Scripts is used for handling the play VFX when claim rewards. I assign all of this in hierarchy.

It works well when we first load from the LoadScene but when i press the play button and comeback from the PlayScene (which i use LoadSceneAsync(“Menu”) when returned from PlayScene, also we have some gameObject that have dontDestroyOnLoad() in Load and Menu scenes), it just doesnt work anymore.

I tested in Update method it all printed with value but when i invoke Claim Event they all show null.

Anyone have any idea what might be going on here?

Thanks!

your script data is lost, if you reload a sceen, or load in a new one yes by default - thats the quickest way to restart a level. Data is not carried and remembered forever, unless you configure it to be - this why theres the dontdestroy - these perpetuate throughout the lifetime of the game once made

Thanks for your advice but this scripts is used for when the user purchase something or claim a reward, it will instantiate the coin effects fly to the Coin Position(which position i assign them by hand). I’m just dont know how to fix it.

It sounds like your DontDestroyOnLoad games objects are referencing objects that are not part of this persistent game object.

The game objects from the first instance of the scene, are not the same game objects in the second scene instances, so you are going to have references to a bunch of destroyed objects.

Your DontDestroyOnLoad games objects should not be referencing anything outside its own hierarchy.

I have checked all my DontDestroyOnLoad objects but they don’t call any object that are not in the hierarchy.

And so you mean that the second time i load the Menu scene from Play scene, the reward Parent is reloaded and the scripts lost its data right?

I removed the pos of those UI and it run completely fine :slight_smile: I dont know why this work XD

using DG.Tweening;
using UnityEngine;
using UnityEngine.Pool; // Import Unity's Object Pooling system

public class RewardClaimVFX : MonoBehaviour
{
    [Header("VFX")]
    public GameObject rewardPrefab;
    public Transform rewardParent;
    public Transform rewardStart;
    public Transform rewardEnd;

    public Sprite goldSprite;
    public Sprite silverSprite;
    public Sprite coinSprite;

    public float duration;
    public float rewardDelay;
    public float totalDelay;
    public Ease moveEase;

    // Unity Object Pool
    private ObjectPool<GameObject> rewardPool;

    private void OnEnable()
    {
        // Initialize the pool for reward objects
        rewardPool = new ObjectPool<GameObject>(
            createFunc: () =>
            {
                return Instantiate(rewardPrefab, rewardParent);
            },
            actionOnGet: obj => obj.SetActive(true),
            actionOnRelease: obj => obj.SetActive(false),
            actionOnDestroy: obj => Destroy(obj),
            defaultCapacity: 10,
            maxSize: 20
        );

        Debug.Log("Reward Parent: " + rewardParent, this);
    }

    public void ClaimVFX(RewardType type, int amount, int currentPage)
    {
        Debug.Log("Reward Parent: " + rewardParent, this);

        amount = (type == RewardType.COIN) ? amount / 5 : amount;

        for (int i = 0; i < amount; ++i)
        {
            var targetDelay = i * rewardDelay;
            ShowReward(type, targetDelay, currentPage);
        }
    }

    public void ShowReward(RewardType type, float delay, int currentPage)
    {

        // Get a pooled object
        var rewardObject = rewardPool.Get();

        var endPos = Camera.main.WorldToScreenPoint(Camera.main.ViewportToWorldPoint(new Vector3(0.5f, 1f, Camera.main.nearClipPlane)));
        var offset = new Vector3(UnityEngine.Random.Range(-100f, 100f), UnityEngine.Random.Range(-100f, 100f), 0f);
        var startPos = offset + rewardStart.position;

        rewardObject.transform.position = startPos;
        rewardObject.transform.localScale = new Vector3(1f, 1f, 1f);

        rewardObject.transform.DOScale(Vector3.one, delay);
        rewardObject.transform.DOMove(endPos, duration)
            .SetEase(moveEase)
            .SetDelay(delay)
            .OnComplete(() =>
            {
                // Release the object back into the pool after the animation finishes
                rewardPool.Release(rewardObject);
            });
    }

    private void OnDisable()
    {
        // Ensure the pool is cleared when this object is destroyed
        rewardPool.Clear();
    }
}