【问题标题】:Loading game does not load the position of the player加载游戏不会加载玩家的位置
【发布时间】:2019-12-17 19:44:31
【问题描述】:

我一直在尝试在我的游戏中实现保存游戏功能。当我从保存中加载游戏时,它不会加载玩家的位置。

我有 2 个主要场景:游戏发生的场景和主菜单场景。主菜单使用了我的加载功能,它应该读取我的保存文件并将播放器放在给定位置,但是,它只是在默认位置加载场景。没有错误被抛出,没有警告消息。这是我所有的代码:

这是我的存档系统:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;



public static class SaveSystem 
{
    public static void SavePlayer (Player player)
    {
        BinaryFormatter formatter = new BinaryFormatter();
    string path = Application.persistentDataPath + "player.fun";
    FileStream stream = new FileStream(path, FileMode.Create);

    PlayerData data = new PlayerData(player);

    formatter.Serialize(stream, data);
    stream.Close();
}

public static PlayerData LoadPlayer ()
{

    string path = Application.persistentDataPath + "/player.fun";

    if (File.Exists(path))
    {
        BinaryFormatter formatter = new BinaryFormatter();
        FileStream stream = new FileStream(path, FileMode.Open);

        PlayerData data = formatter.Deserialize(stream) as PlayerData;
        stream.Close();
        return data;
    }
    else
    {
        Debug.LogError("Save file not in " + path);
        return null;
    }
    }
}

玩家数据的容器:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class PlayerData 
{
    public int level;
    public int health;
    public float[] position;
    public int stamina;

    public PlayerData (Player player)
    {
        level = player.level;
        health = player.health;
        stamina = player.stamina;
        position = new float[3];

        position[0] = player.transform.position.x;
        position[1] = player.transform.position.y;
        position[2] = player.transform.position.z;
    }


}

我的场景更改脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneChanger : MonoBehaviour
{
    public static bool Isload = false;
    public void gotoWelwardLoad()
    {
        SceneManager.LoadScene("Welward");
        bool Isload = true;
    }
    public void gotoWelward()
    {
        SceneManager.LoadScene("Welward");
    }
    public void gotomainmenu()
    {
        SceneManager.LoadScene("Menu");
    }
}

我的播放器脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Player : MonoBehaviour
{
    public int health = 1;
    public int stamina = 1;
    public int level = 1;

    public void SavePlayer ()
    {
        SaveSystem.SavePlayer(this);
    }

    public void LoadPlayer ()
    {
        SceneManager.LoadScene("Welward");
        PlayerData data = SaveSystem.LoadPlayer();
        level = data.level;
        health = data.health;
        stamina = data.stamina;

        Vector3 position;
        position.x = data.position[0];
        position.y = data.position[1];
        position.z = data.position[2];
        transform.position = position;
    }

    public static void gotomenu ()
    {
        SceneManager.LoadScene("Menu");
    }

    public static void Welward()
    {
        SceneManager.LoadScene("Welward");
        SaveSystem.LoadPlayer();
    }
}

与完整的统一项目文件的链接: https://drive.google.com/open?id=1mFH5aNklC0qMWeJjMT4KD0CbTTx65VRp

【问题讨论】:

  • 如果您的问题描述准确,几乎可以肯定该问题可以隔离到SaveSystem.SavePlayer()SaveSystem.LoadPlayer()。您很可能只是忘记保存或加载字段。
  • 记住一个简单的好习惯,在共享 Unity 项目时省略上传 Library/Obj/Logs/Build 文件夹(与您的 .gitignore 相同的规则)
  • 在您上传的项目中缺少字体(因此菜单上没有文字)。还缺少ThirdPersonController 预制件,如何在游戏中移动以测试保存/加载行为?
  • 同时,您的场景层次结构缺乏组织。有很多Button、GameObject、GameObject(1)等东西。考虑命名它们以保持井井有条。例如LoadButton、SaveButton等
  • @RobertHarvey “您很可能只是忘记保存或加载字段”是什么意思?

标签: c# unity3d save


【解决方案1】:

正如BugFinder 正确指出的那样,您的保存路径与加载路径不同。

尝试将Application.persistentDataPath + "player.fun"; 更改为Application.persistentDataPath + "/player.fun"; 以匹配您的加载代码。或者您可以将 string path 变量作为 const 向上移动到类中,然后引用它,因为它可以保证匹配。

之后,您还需要在某个地方调用Player.LoadPlayer(),因为在您现有的项目中,您不会在我能找到的任何地方这样做,并且当您当前调用它时,它会重新加载场景(这可能不是行为你想要)。我会从该方法中删除 SceneManager.LoadScene("Welward");

using UnityEngine;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

public static class SaveSystem
{
    // This is a way to make sure your path is the same, and not about to get overwritten
    public static string Path => Application.persistentDataPath + "/player.fun";

    public static void SavePlayer (Player player)
    {
        BinaryFormatter formatter = new BinaryFormatter();
        FileStream stream = new FileStream(Path, FileMode.Create);

        PlayerData data = new PlayerData(player);

        formatter.Serialize(stream, data);
        stream.Close();

        // It's helpful to print out where this is going
        Debug.Log($"Wrote to {Path}");
    }

    public static PlayerData LoadPlayer ()
    {
        if (File.Exists(Path))
        {
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(Path, FileMode.Open);

            PlayerData data = formatter.Deserialize(stream) as PlayerData;
            stream.Close();

            // It's also helpful to print out that it worked, not just log errors if it fails
            Debug.Log($"Successfully read from {Path}");
            return data;
        }
        else
        {
            Debug.LogError("Save file not in " + Path);
            return null;
        }
    }
}

【讨论】:

  • 啊,我没看到。我会立即尝试,使用 Bug Finder 的首选 "Path.Combine(Application.persistentDataPath,"player.fun");"与当前解决方案相反的功能。此外,我必须更改场景,因为从主菜单调用 LoadPlayer 函数,然后加载世界空间。
  • SaveSystem.LoadPlayer() 是从您的菜单中调用的,但 Player.LoadPlayer() 从未被调用,我可以看到。 Player.LoadPlayer() 可能应该被调用,因为这是您将保存文件中的位置应用到播放器变换的地方。
【解决方案2】:

值得注意的一件事是在保存时使用 Application.persistentDataPath + "player.fun"; 并在加载时使用 Application.persistentDataPath + "/player.fun"; 所以,也许因此它没有找到要加载的文件。如你所想。就个人而言,Path.Combine 是一个不错的选择,平台非特定等。因此请尝试将两者都替换为 Path.Combine(Application.persistentDataPath,"player.fun");

【讨论】:

    【解决方案3】:

    从您提供的代码中,我看不到您调用Player.LoadPlayer() 的部分。所以把它添加到播放器中:

    void Start(){
        LoadPlayer();
    }
    

    希望对你有帮助。

    【讨论】:

    • 我使用开始菜单中按钮的 onclick 功能在统一内部调用它。
    • @LeeJordan 等你在加载下一个场景之前调用它?
    猜你喜欢
    • 1970-01-01
    • 2019-05-11
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 1970-01-01
    • 2020-10-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多