简体   繁体   English

直接播放场景时,场景保存和加载工作正常,但是当我从主菜单加载时,它是 null 异常

[英]Scene save&load works fine when playing scene directly,but when i load from main menu it's null exception

when i starting my game on the game scene,everything is fine,but when i load from menu,first time is ok,then there is saving data to json,and when i come back to main menu,and then again press play it's " Object reference not set to an instance of an object " for my saveScript which is attached to empty gameObject on game scene.当我在游戏场景开始我的游戏时,一切都很好,但是当我从菜单加载时,第一次是好的,然后将数据保存到 json,当我回到主菜单,然后再次按下播放它的“ Object 引用未设置为 object 的实例“我的 saveScript 附加到游戏场景中的空游戏对象。

loading just只加载

SceneManager.LoadSceneAsync("game");

SAVE SCRIPT保存脚本

public void PopulateSaveData(SaveData sd)
    {
        //character
        sd.s_XP = XP;
        respawnScript.instance.PopulateSaveData(sd);
        sd.s_x = gameObject.transform.position.x;
        sd.s_y = gameObject.transform.position.y;
        sd.s_z = gameObject.transform.position.z;

        playerHealth.instance.PopulateSaveData(sd);
        //sword
        playerSword.instance.PopulateSaveData(sd);
        //inventory
        Inventory.instance.PopulateSaveData(sd);
        //sd.s_allItemsPositions = allItemsPositions;
        //sd.s_allPotionInteractions = GameObject.FindObjectsOfType<potionInteraction>().ToList();
        if (allPotionInteractionO.Count > 0)
        {
            Debug.Log("ALL POTIONS COUNT " + allPotionInteractionO[0]);
            sd.s_allPotionInteractions = allPotionInteractionO;
        }
        
        sd.s_allWeaponInteractions = all_swords;
        sd.s_allWeaponInteractionsGO = all_swordsGO;

        for (int i = 0; i < all_swordsGO.Count; i++)
        {
            sd.s_allSwordsRotation.Add(all_swordsGO[i].transform.rotation);
        }
        for (int i = 0; i < all_swordsGO.Count; i++)
        {
            //because some objects can be destroyed thats why im initializing list again
            //allInteractableGameObjects = GameObject.FindGameObjectsWithTag("interactable object").ToList();
            // sd.s_allItemsPositions.Add(allInteractableGameObjects[i].transform.position);
            sd.s_allSwordsPositions.Add(all_swordsGO[i].transform.position);

        }
        for (int i = 0; i < allPotionInteractionO.Count; i++)
        {
            sd.s_allPotionsPositions.Add(allPotionInteractionO[i].transform.position);
        }
        ///going through list and check if there is used item,then saving its bool to another list at same position
        for (int i = 0; i < allPotionInteractionO.Count; i++)
        {
            if (allPotionInteractionO[i].isUsed)
            {
                allPotionsIsUsed[i] = true;
            }
        }
        sd.s_allPotionsIsUsed = allPotionsIsUsed;
        //quest part
        for (int i = 0; i < allNPCS.Count; i++)
        {
            if (allNPCS[i].quest == null)
            {
                allNpcQuests[i] = null;
            }
        }
        sd.s_allQuests = allNpcQuests;
        if(MarieleQuest.instance.currentMarieleQuest!=null)
        {
            sd.s_currentQuest = MarieleQuest.instance.currentMarieleQuest;
        }
        foreach (Slot slot in slotsToSave)
        {
            slot.PopulateSaveData(sd);

        }
        //enemies
        foreach (EnemyStats enemy in all_enemies)
        {
            enemy.PopulateSaveData(sd);
        }
        //procedural enemies
        foreach (ProceduralStats enemy in all_procedural_enemies)
        {
            enemy.PopulateSaveData(sd);
        }
    } 

LOAD加载

public void LoadFromSaveData(SaveData sd)
    {
        if (SceneManager.GetActiveScene().name == "game")
        {
            //character
            XP = sd.s_XP;
            if (sd.s_HP > 0)
            {
                playerHealth.instance.LoadFromSaveData(sd);
            }
            else if (sd.s_HP == 0)
            {
                playerHealth.instance.currentHealth = 100;
            }
            if (sd.s_respawnObject != null)
            {
                respawnScript.instance.LoadFromSaveData(sd);
            }
            if (sd.s_x != 0 && sd.s_y != 0 && sd.s_z != 0)
            {
                gameObject.transform.position = new Vector3(sd.s_x, sd.s_y, sd.s_z);
            }
            //sword
            if (sd.s_sword != null && sd.s_temp != null && sd.s_currentSword != null && sd.s_currentSwordGO != null)
            {
                playerSword.instance.LoadFromSaveData(sd);

            }
            else
            {
                playerSword.instance.currentSwordGameObject = GameObject.Find("character/mixamorig:Hips/mixamorig:Spine/mixamorig:Spine1/" + playerSword.instance.currentSwordGameObject.name);
                playerSword.instance.temp = playerSword.instance.currentSwordGameObject;
            }


            //potions
            if (sd.s_allPotionsIsUsed.Count > 0)
            {
                allPotionsIsUsed = sd.s_allPotionsIsUsed;
            }
            //quest
            if (sd.s_allQuests.Count > 0)
            {
                Debug.Log("SD ALL QUESTS" + sd.s_allQuests);
                allNpcQuests = sd.s_allQuests;
            }
            if (sd.s_allQuests.Count > 0)
            {
                for (int i = 0; i < allNPCS.Count; i++)
                {
                    allNPCS[i].quest = allNpcQuests[i];
                }
            }
            if (sd.s_currentQuest != null)
            {
                MarieleQuest.instance.currentMarieleQuest = sd.s_currentQuest;
            }
          

            if (sd.s_allPotionInteractions.Count > 0)//second pattern in if is changed(FOR REMEMBER)
            {
                Debug.Log("SD ALL POTIONS > 0");
                if (sd.s_allPotionInteractions[0] != null)
                {
                    allPotionInteractionO = sd.s_allPotionInteractions;
                }
                else
                {
                    allPotionInteractionO = GameObject.FindObjectsOfType<potionInteraction>().ToList();
                }
                for (int b = 0; b < allPotionInteractionO.Count; b++)
                {
                    allPotionInteractionO[b].isUsed = allPotionsIsUsed[b];
                }
                for (int i = 0; i < allPotionInteractionO.Count; i++)
                {

                    if (allPotionInteractionO[i].isUsed)
                    {
                        allPotionInteractionO[i].gameObject.SetActive(false);
                    }
                }
            }


            Inventory.instance.LoadFromSaveData(sd);
            if (sd.s_allWeaponInteractions.Count > 0)
            {

                //all_swords = sd.s_allWeaponInteractions;
               // all_swordsGO = sd.s_allWeaponInteractionsGO;
                for (int i = 0; i < all_swordsGO.Count; i++)
                {
                    if (!Inventory.instance.itemsGameObjects.Contains(all_swordsGO[i])
                    && all_swordsGO[i] != playerSword.instance.currentSwordGameObject)
                    {
                        all_swordsGO[i].SetActive(true);

                        all_swordsGO[i].transform.rotation = sd.s_allSwordsRotation[i];


                    }
                }
                for (int j = 0; j < sd.s_allSwordsPositions.Count; j++)
                {
                    //Debug.Log(sd.s_allItemsPositions[j] + " " + allInteractableGameObjects[j].name);
                    all_swordsGO[j].transform.position = sd.s_allSwordsPositions[j];
                    allPotionInteractionO[j].transform.position = sd.s_allPotionsPositions[j];
                }
            }

            foreach (Slot slot in slotsToSave)
            {
                slot.LoadFromSaveData(sd);

            }
            //enemies
            foreach (EnemyStats enemy in all_enemies)
            {
                enemy.LoadFromSaveData(sd);
            }
            foreach (string id in dead_enemies_ids)
            {
                SaveData.EnemyData enemyData = new SaveData.EnemyData();
                enemyData.e_Health = 0;
                enemyData.e_id = id;
                sd.enemyData.Add(enemyData);
            }
            //procedural enemies
            foreach (ProceduralStats enemy in all_procedural_enemies)
            {
                enemy.LoadFromSaveData(sd);
            }
            foreach (string id in all_procedural_ids)
            {
                SaveData.ProceduralEnemyData enemyData = new SaveData.ProceduralEnemyData();
                enemyData.e_ProcHealth = 0;
                enemyData.e_ProcId = id;
                sd.proceduralEnemyData.Add(enemyData);
            }
        }
    }

these two scripts just writing data to lists,and reading it from saved file, saving is called once OnApplicationQuit()这两个脚本只是将数据写入列表,然后从保存的文件中读取,保存被调用一次OnApplicationQuit()
load called at the end of Start()Start()结束时调用 load
when i open scene game just from itself and close and load again,everything work fine,because its destroying objects and load them again,but当我仅从自身打开场景游戏并关闭并再次加载时,一切正常,因为它会破坏对象并再次加载它们,但是
once i start from main menu,from there do LoadScene("game") i'm getting error that some fields are not exist anymore ,but it's like unreal一旦我从主菜单开始,从那里做LoadScene("game")我得到一些字段不再存在的错误,但这就像不真实
SaveData script which have all info and store it to file,then read SaveData 脚本,其中包含所有信息并将其存储到文件中,然后读取

public class SaveData : MonoBehaviour
{
    private void Awake()
    {
        
        
    }
    private void Start()
    {
        s_inventoryGO = new List<GameObject>();
        Debug.Log("s_inventoryGO" + s_inventoryGO.Count);
    }
    //character saving
    public int s_XP;
    public GameObject s_respawnObject;
    public float s_x;
    public float s_y;
    public float s_z;
    //inventory
    public List<Item> s_inventory = new List<Item>();
    public List<GameObject> s_inventoryGO = new List<GameObject>();
    public List<GameObject> s_allGameObjectInventory = new List<GameObject>();
    
    public List<GameObject> s_allInteractableObjects = new List<GameObject>();
    public List<potionInteraction> s_allPotionInteractions = new List<potionInteraction>();
    public List<weaponInteract> s_allWeaponInteractions = new List<weaponInteract>();
    public List<GameObject> s_allWeaponInteractionsGO = new List<GameObject>();
    public List<Quaternion> s_allSwordsRotation = new List<Quaternion>();
    public List<Vector3> s_allSwordsPositions = new List<Vector3>();
    public List<Vector3> s_allPotionsPositions = new List<Vector3>();
    public List<bool> s_allPotionsIsUsed = new List<bool>();
    public List<Quest> s_allQuests = new List<Quest>();

    public Quest s_currentQuest;
    public int s_HP;
    [System.Serializable]
    public struct SlotsData
    {
        public Item s_slotItem;
        public string s_id;
        //public Sprite s_icon ;
    }
    public List<SlotsData> s_slots = new List<SlotsData>();
    
    //sword
    public Transform s_sword;
    public GameObject s_currentSwordGO;
    public GameObject s_temp;
    public swordEquipping s_currentSword;
    //enemy saving
    [System.Serializable]
    public struct EnemyData
    {
        public int e_Health;
        public string e_id;
    }
    public List<EnemyData> enemyData = new List<EnemyData>();
    //procedural enemy saving
    [System.Serializable]
    public struct ProceduralEnemyData
    {
        public int e_ProcHealth;
        public string e_ProcId;
    }
    public List<ProceduralEnemyData> proceduralEnemyData = new List<ProceduralEnemyData>();
    public string toJson()
    {
        return JsonUtility.ToJson(this);
    }
    public void LoadFromJson(string json)
    {

        JsonUtility.FromJsonOverwrite(json, this);
    }


}

When using DontDestroyOnLoad wherever you want this object to exist, make a copy of it in your scene if you want the data stored to persist between your game session.在您希望此 object 存在的任何地方使用DontDestroyOnLoad时,如果您希望存储的数据在您的游戏 session 之间持续存在,请在您的场景中复制它。

Here is a snippet from the docs这是来自文档的片段

void Awake()
{
    GameObject[] objs = GameObject.FindGameObjectsWithTag("music");

    if (objs.Length > 1)
    {
        Destroy(this.gameObject);
    }

    DontDestroyOnLoad(this.gameObject);
}

It will search for other objects in the scene with the same tag.它将搜索场景中具有相同标签的其他对象。 If it finds it, it will destroy itself.如果它找到它,它会毁掉自己。 What you can do here is have a public Init() function on your script.你可以在这里做的是在你的脚本上有一个公共的 Init() function。 When a new scene is loaded with the object and your object already finds an instance of itself, it can pass the local references to the existing object.当使用 object 加载新场景并且您的 object 已经找到自己的实例时,它可以将本地引用传递给现有的 object。 Something like...就像是...

public GameObject objRef1;
public GameObject objRef2;
  
public void Init(GameObject obj1, GameObject obj2)
{
    objRef1 = obj1;
    objRef2 = obj2;
    ...
    etc.
}

Inside of the Awake() of the new object, you would call the existing objects Init with the local references it has, which work as it loaded with your scene.在新的 object 的Awake()内部,您可以使用它所具有的本地引用调用现有对象 Init,当它与您的场景一起加载时,它们会起作用。

void Awake()
{
    // make the tag unique so you only grab objects of this save type
    GameObject[] objs = GameObject.FindGameObjectsWithTag("yourObjectsTag");

    if (objs.Length > 1)
    {
        objs[0].GetComponent<YourScriptName>().Init(obj1, obj2, ..., etc.);
        Destroy(this.gameObject);
    }

    DontDestroyOnLoad(this.gameObject);
}

In this approach it means you have a local copy of your DontDestroyOnLoad object in every scene so when the existing one loads in, it can just grab the references from it.在这种方法中,这意味着您在每个场景中都有一个 DontDestroyOnLoad object 的本地副本,因此当加载现有场景时,它可以从中获取参考。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM