在Unity中保存和加载整个场景

3

好的,我一直在苦苦搜索,看了许多不同的帖子,但没有找到答案。

我的问题: 我在Unity中有一个场景,场景中没有任何东西,所有内容都是在游戏启动时随机生成的。当然,我想让玩家能够保存他的进度。我已经找到了在Unity中保存进度的方法,但所有方法都需要为每个要保存的类或对象编写脚本,但对我来说,这些脚本似乎效率低下,因为在我的游戏中,有随机生成的房屋和建筑物(相对容易保存),但这些建筑物内部还可以放置对象等等。另外,以后我计划添加角色,这些角色也需要被保存(例如他们在哪里,他们拿着什么等等)。正如我所提到的,为每个对象编写保存和加载脚本对我来说似乎效率低下,因为我习惯于使用Java的序列化,只需将包含所有数据的主对象写入文件即可,因此我正在寻找其他更简单的方法,可能是一种保存整个场景状态的方法,然后在加载时只需加载场景而不是从头开始生成它。

我的问题: 有没有一种方法可以保存包含所有对象及其信息的整个场景,然后进行加载?

提前感谢!

3个回答

2
在运行时保存场景并在以后重新加载它的内置方法是不存在的。在Unity构建中,场景以不可编辑的格式存储,这意味着每当您加载一个场景时,它将以与构建时相同的格式加载。这是一件好事,因为您不想在部署的游戏中编辑构建内容。
现在,这并不意味着场景不能包含逻辑以使自身配置不同。实际上,听起来就像是你正在做的事情。目标是将内容存储到保存文件中。
考虑从“我想要加载一个生成随机游戏玩法的场景”转变为“我想要加载一个基于文件配置自己的场景”的思维方式。这是一层抽象,可以更好地控制加载场景时发生的事情。
我建议创建一个JSON配置文件来存储您的重要信息,类似于以下内容:
{
  "house_locations": [
    {
      "position": "(0, 0, 0)",
      "objects": []
    },
    {
      "position": "(10, 10, 10)",
      "objects": []
    }
  ],
  "characters": [
    {
      "position": "(0, 0, 0)",
      "inventory": [
        {
          "item_name": "knife"
        },
        {
          "item_name": "shovel"
        }
      ]
    }
  ]
}

这只是一个简单的示例,您需要添加重要的数据来表示您的游戏。
接下来,当您想要开始游戏时,您只需要执行以下操作之一:
1. 您是否要开始新游戏?=> 生成随机配置文件,然后使用它来填充场景。 2. 您是否正在加载已保存的游戏?=> 使用保存的配置文件来填充场景。
您需要一些类似于“WorldBuilder”的脚本来处理此操作。在您的场景中,您可以像以下示例一样编写代码:
public class WorldBuilder : MonoBehaviour
{
  // This is the actual contents of the world, represented as a JSON string.
  private string _json = "";

  public void BuildWorld(string configFilePath)
  {
    _json = LoadConfiguration(configFilePath);
    BuildWorld(_json);
  }

  public void GenerateWorld()
  {
    _json = GenerateConfiguration();
    BuildWorld(_json);
  }

  public void SaveWorld(string targetFilePath)
  {
    // Save the contents of _json out to a file so that it can be loaded
    // up again later.
  }

  private string LoadConfiguration(string configFilePath)
  {
    // Load the actual file and return the file contents, which is a JSON string.
  }

  private void BuildWorld(string json)
  {
    // Actually build the world using the supplied JSON.
  }

  private string GenerateConfiguration()
  {
    // Return a randomly generated configuration file.
  }
}

这种方法将场景内容的保存和生成分开,使得编码更加易写易维护。

是的,这正是我不想做的事情 :P 但我猜我别无选择 - Coreggon
@Coreggon,你不想采取这种方法的原因是什么? - Aaron Cheney
2
因为我有很多对象,而且我不想为每个要保存的对象编写代码。 - Coreggon

0
我会把'LoadConfiguration'改名为 'LoadWorld'。实际上,我会将其命名为'WorldSave'和'WorldLoad',以便按字母顺序排列。
另外,请将加载设置为异步:
public IEnumerator WorldLoad(string localWorldFilePath)
{

   string filePath = Application.persistentDataPath + "/" + localWorldFilePath + ".json");
   string lines = null;


       //Loading the level loop:
       using (SteamReader streamReader = new StreamReader(filePath,Encoding.UTF8))
       {
          lines += streamReader.ReadToEnd();

          if (UnityEngine.Random.Range(0f,20f) > 15f) //< - probably a fancier way of doing this part)
             yield return new WaitForEndOfFrame();
       }

       //Okay, we're done loading so return this:
       yield return lines;
}

实际上,也可以将保存异步化,使用StreamWriter,并确保它也以UTF8编码,换句话说,不能仅使用File.Save和File.Load。

另一个想法是,如果您不希望进行修改,请加密您的文件(但人们仍然会解密它)。

在其他地方启动协程,您将“15f”设置得越低,它就会锁定游戏的时间越长,您将其设置得越高,它就会锁定游戏的时间越短,但速度会变慢。有一种方法可以在单独的线程或其他位置执行此操作,但我不是高级程序员。

worldBuilder.StartCoroutine(WorldLoad);

提示一: 理想情况下,您应该通过控制台创建自己的脚本语言,如果实时自定义场景文件加载和保存的想法是,您可以在实际游戏运行时创建和编辑您的级别,以便绕过使用Unity作为关卡编辑器的方式。
换句话说,您可以按 ~ 键并打开控制台,然后输入“WorldLoad(worldNameGoesHere)”,它将在您的游戏构建文件夹中加载世界。
此外,还有一种方法是使用编辑器脚本,您实际上可以挂钩并覆盖Unity的标准“场景保存”,以防您也想这样做。
提示二: 还要确保像上面那样以UTF8格式进行编码,以便在实现日语,中文等亚洲语言时不会在稍后变得麻烦。

0

好的,这不是我正在寻找的,我正在寻找保存玩家进度的方法,而不是保存在编辑器中所做的更改。 - Coreggon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接