【问题标题】:Learning about Saving and Loading in Unity; encountered error CS1513 for unknown reason学习 Unity 中的保存和加载;由于未知原因遇到错误 CS1513
【发布时间】:2026-01-09 05:15:01
【问题描述】:

所以我一直在为我的 Unity 项目制作一个保存/加载脚本,它看起来像这样(请不要复制):

using UnityEngine; 
 
 using System.Text;
 using System.IO;
 using System.Runtime.Serialization.Formatters.Binary;
 
 using System;
 using System.Runtime.Serialization;
 using System.Reflection;
 // Made By Wasabi.
 
 // === This is the info container class ===
 [Serializable ()]
 public class SaveData : ISerializable {
 
   // === Values ===
   public bool foundKeyCard1 = false;
   public bool foundKeyCard2 = false;
   public bool foundKeyCard3 = false;
   public bool foundKeyCard4 = false;
   public bool foundKeyCard5 = false;
   public bool foundKeyCard6 = false;
   public bool foundKeyCard7 = false;
   public bool foundKeyCard8 = false;
   public bool foundKeyCard9 = false;
   public bool foundKeyCard10 = false;
   public bool foundCarKeys1 = false;
   public float expscore = 0;
   public int levelReached = 1;
   // === /Values ===
 
   public SaveData () {}

   public SaveData (SerializationInfo info, StreamingContext ctxt)
   {
     foundKeyCard1 = (bool)info.GetValue("foundKeyCard1", typeof(bool));
     foundKeyCard2 = (bool)info.GetValue("foundKeyCard2", typeof(bool));
     foundKeyCard3 = (bool)info.GetValue("foundKeyCard3", typeof(bool));
     foundKeyCard4 = (bool)info.GetValue("foundKeyCard4", typeof(bool));
     foundKeyCard5 = (bool)info.GetValue("foundKeyCard5", typeof(bool));
     foundKeyCard6 = (bool)info.GetValue("foundKeyCard6", typeof(bool));
     foundKeyCard7 = (bool)info.GetValue("foundKeyCard7", typeof(bool));
     foundKeyCard8 = (bool)info.GetValue("foundKeyCard8", typeof(bool));
     foundKeyCard9 = (bool)info.GetValue("foundKeyCard9", typeof(bool));
     foundKeyCard10 = (bool)info.GetValue("foundKeyCard10", typeof(bool));
     foundCarKeys1 = (bool)info.GetValue("foundCarKeys1", typeof(bool)); 
     expscore = (float)info.GetValue("expscore", typeof(float));
 
     levelReached = (int)info.GetValue("levelReached", typeof(int));
   }
 
   public void GetObjectData (SerializationInfo info, StreamingContext ctxt)
   {
     info.AddValue("foundKeyCard1", (foundKeyCard1));
     info.AddValue("foundKeyCard2", (foundKeyCard2));
     info.AddValue("foundKeyCard3", (foundKeyCard3));
     info.AddValue("foundKeyCard4", (foundKeyCard4));
     info.AddValue("foundKeyCard5", (foundKeyCard5));
     info.AddValue("foundKeyCard6", (foundKeyCard6));
     info.AddValue("foundKeyCard7", (foundKeyCard7));
     info.AddValue("foundKeyCard8", (foundKeyCard8));
     info.AddValue("foundKeyCard9", (foundKeyCard9));
     info.AddValue("foundKeyCard10", (foundKeyCard10));
     info.AddValue("foundCarKeys1", (foundCarKeys1));
     info.AddValue("expscore", expscore);
     info.AddValue("levelReached", levelReached);
   }
 }
 
 // === This is the class that will be accessed from scripts ===
 public class SaveLoad {
 
   public static string currentFilePath = "SaveData.cjc";
 
   public static void Save ()  // Overloaded
   {
     Save (currentFilePath);
   }
   public static void Save (string filePath)
   {
     SaveData data = new SaveData ();
 
     Stream stream = File.Open(filePath, FileMode.Create);
     BinaryFormatter bformatter = new BinaryFormatter();
     bformatter.Binder = new VersionDeserializationBinder(); 
     bformatter.Serialize(stream, data);
     stream.Close();
   }
 
   public static void Load ()  { Load(currentFilePath);  }   // Overloaded
   public static void Load (string filePath) 
   {
     SaveData data = new SaveData ();
     Stream stream = File.Open(filePath, FileMode.Open);
     BinaryFormatter bformatter = new BinaryFormatter();
     bformatter.Binder = new VersionDeserializationBinder(); 
     data = (SaveData)bformatter.Deserialize(stream);
     stream.Close();
 
   }
 
 }
 
 // === This is required to guarantee a fixed serialization assembly name, which Unity likes to randomize on each compile
 // Do not change this
 public sealed class VersionDeserializationBinder : SerializationBinder 
 { 
     public override Type BindToType( string assemblyName, string typeName )
     { 
         if ( !string.IsNullOrEmpty( assemblyName ) && !string.IsNullOrEmpty( typeName ) ) 
         { 
             Type typeToDeserialize = null; 
 
             assemblyName = Assembly.GetExecutingAssembly().FullName; 
 
             // The following line of code returns the type. 
             typeToDeserialize = Type.GetType( String.Format( "{0}, {1}", typeName, assemblyName ) ); 
 
             return typeToDeserialize; 
         } 
 
         return null; 
     } 
 }

我想就是这样。 CS1513 不在里面。如果您发现任何错误,请告诉我。但是问题出在我正在制作的另一个脚本中,当我关闭应用程序时会自动保存。如下图(请勿抄袭):

using UnityEngine;    // For Debug.Log, etc.
 
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
 
using System;
using System.Runtime.Serialization;
using System.Reflection;
// Made by Wasabi.

 void OnApplicationQuit()
 {
   public class SaveLoad {
 
     public static string currentFilePath = "SaveData.cjc";    
 
     public static void Save ()  // Overloaded
     {
       Save (currentFilePath);
     }
     public static void Save (string filePath)
     {
       SaveData data = new SaveData ();
 
       Stream stream = File.Open(filePath, 
  FileMode.Create);
       BinaryFormatter bformatter = new BinaryFormatter();
       bformatter.Binder = new 
  VersionDeserializationBinder(); 
       bformatter.Serialize(stream, data);
       stream.Close();
     }
   }
 }

现在我知道void OnApplicationQuit() 下的代码应该是我的保存程序。好吧,我不确定我的保存脚本的哪一部分是我的保存例程。所以如果你能帮我解决这个问题,请随时检查我的保存/加载脚本并告诉我我的实际保存程序是什么。但无论如何,它一直告诉我“错误,”}“预期 (11,7) CS1513。”我检查了我的脚本。我读过另一篇文章,答案是错误意味着我忘记了脚本末尾的结束“}”。好吧,就我而言,这似乎不是真的,因为它没有丢失任何“}”。我什至尝试在最后添加一个额外的“}”,但它仍然说了同样的话。所以它只有在我在打开“{”之后直接放另一个“}”时才会清除错误

void OnApplicationQuit() 这没有任何意义。但是当我这样做时,它会在

处显示另一个错误

void OnApplicationQuit()(具体而言:void OnApplicationQuit()OnApplicationQuit() 的开头)并且我不能为该命名空间使用方法或函数,我不知道这意味着什么,我不知道不认为这是真的。我相信第二个错误只是因为我不得不输入void OnApplicationQuit() {} 而被触发。这里发生了什么,我该如何解决它?另一件事:我在研究如何执行此操作后构建了我的保存/加载脚本,但是代码如何知道我何时收集了 keycard1?我是否必须在 keycard1 中创建一个脚本,当我收集它时告诉保存/加载脚本?这是否会导致我不得不在 Save/Load 脚本中添加更多脚本来检测 keycard1 脚本,告诉 Save/Load 脚本我选择了它?我对 Unity 的整个 C# 部分仍然很陌生,而且我完全是自学成才的。你看,我才刚刚开始做我的第一个严肃的项目。所以我需要知道我用来调用保存和加载的保存/加载脚本中的保存和加载例程到底是什么;因为我需要制作一个带有按钮的菜单屏幕,当按下这些按钮时,会调用保存或加载例程。因此,当我按下保存或加载按钮,查看我的脚本时,脚本会知道我有 KeyCard,还是我必须手动将其放入脚本中?最后,当我获得 KeyCard2 时,如何制作一个调用保存的脚本?

此致,

芥末。

【问题讨论】:

  • “我可以向你保证,我使用的public static 字段和其他方法都很好”——不,它们不是。您应该始终避免使用可变的static 状态。此外,正如您自己写的:“我不是 C# 专家”,所以当您的程序目前明显错误时,您无法“向我们保证”您的程序的正确性。
  • @Dai 好的好的!抱歉,如果这显然冒犯了您或以任何方式侮辱了您。正确,我在c# 可能会说“低智商”,因为我是自学成才的,而且我已经有 2 周的时间自学了。 的意思是通过“我向你保证”是它在 Unity 中工作“非常好”,没有编译器错误或警告,所以它似乎没有造成任何麻烦.但是,如果它仅仅是低效的,那么尽管它是低效的。只要它有效,它就有效。希望这可以解决问题。

标签: c# unity3d


【解决方案1】:

请勿抄袭

我向你保证,我什至不想 ^^


你的第二个 sn-p 应该做什么?

您有一个方法声明 OnApplicationQuit(),并在该方法中声明了 public static 字段和其他方法。

-> c# 中不允许这样做。

  • 您的方法OnApplicationQuit() 应该在MonoBehaviour {...} 类型的类型内
  • 然后你不能在方法中使用访问修饰符。您宁愿简单地调用该静态方法SaveLoad.Save()

你宁愿在你的场景中有一个带有 component attached 的 GameObject

public class SaveLoadBehavior : MonoBehaviour
{
     private void Awake ()
     {
         SaveLoad.Load();
     }

     void OnApplicationQuit()
     {
         SaveLoad.Save();
     }
}

OnApplicationQuit

在此请注意,Unity 中的每个组件都需要写入一个单独且同名的文件中。所以在示例中它应该在SaveLoadBehaviour.cs 中(.cs 隐藏在 Unity 中)


实际上,您可能更愿意使用例如RuntimeInitializeOnLoadMethodApplication.quitting 这样你就不需要前面提到的组件和游戏对象了:

public class SaveLoad
{
    // will be automatically called on application start
    [RuntimeInitializeOnLoadMethod]
    private static void Init()
    {
        Load();
        // register a callback to the application quitting event
        Application.quitting += OnQuit;
    }

    // will be automatically called on application quit
    private static void OnQuit()
    {
        Save();
    }

    .... // Your load and save methods just the way you have them already

}

【讨论】:

  • 那么SaveLoad.Save(); 是我必须为“保存程序”做的所有事情吗?那么加载呢?另外,我要如何处理这个 GameObject 才能让它保存?
  • 对于加载,您调用 SaveLoad.Load(); .. 可能在组件的 AwakeStart 方法中。您只需将此 GameObject 放入您的场景中,然后它会自动与该场景一起加载。
  • 哇。我认为这会比这更困难。非常感谢!因此,我的保存/加载脚本充当了我的保存/加载序列的定义器,而我需要做的就是使用 public class somethingsomethingsomething : MonoBehaviour,然后使用您展示的其他内容? ...然后将其附加到某种菜单中的“保存游戏”按钮?
  • 哦,你指的是我附加的这个“游戏对象”;应该是我的角色吗?
  • 1) * 是“一本打开的书”,当然你可以复制代码.. 但是,如果你真正了解它的工作原理和原因,我会更喜欢;) ... 2) 是的根据using 声明并将其附加到场景中的游戏对象。但正如答案底部用作替代方法的方法所说,您甚至不需要不同的脚本或游戏对象,但您可以将其简单地放入您已有的类中;)