浏览代码

Update Saving games documentation for Godot 4.0 (#6371)

Eddie (Xiao Di) Li 2 年之前
父节点
当前提交
5c80189d97
共有 1 个文件被更改,包括 38 次插入33 次删除
  1. 38 33
      tutorials/io/saving_games.rst

+ 38 - 33
tutorials/io/saving_games.rst

@@ -65,7 +65,7 @@ The save function will look like this:
 
     func save():
         var save_dict = {
-            "filename" : get_filename(),
+            "filename" : get_scene_file_path(),
             "parent" : get_parent().get_path(),
             "pos_x" : position.x, # Vector2 is not supported by JSON
             "pos_y" : position.y,
@@ -88,11 +88,11 @@ The save function will look like this:
 
  .. code-tab:: csharp
 
-    public Godot.Collections.Dictionary<string, object> Save()
+    public Godot.Collections.Dictionary<string, Variant> Save()
     {
-        return new Godot.Collections.Dictionary<string, object>()
+        return new Godot.Collections.Dictionary<string, Variant>()
         {
-            { "Filename", GetFilename() },
+            { "Filename", SceneFilePath },
             { "Parent", GetParent().GetPath() },
             { "PosX", Position.x }, // Vector2 is not supported by JSON
             { "PosY", Position.y },
@@ -136,12 +136,11 @@ way to pull the data out of the file as well.
     # Go through everything in the persist category and ask them to return a
     # dict of relevant variables.
     func save_game():
-        var save_game = File.new()
-        save_game.open("user://savegame.save", File.WRITE)
+        var save_game = FileAccess.open("user://savegame.save", FileAccess.WRITE)
         var save_nodes = get_tree().get_nodes_in_group("Persist")
         for node in save_nodes:
             # Check the node is an instanced scene so it can be instanced again during load.
-            if node.filename.empty():
+            if node.scene_file_path.is_empty():
                 print("persistent node '%s' is not an instanced scene, skipped" % node.name)
                 continue
 
@@ -158,7 +157,6 @@ way to pull the data out of the file as well.
 
             # Store the save dictionary as a new line in the save file.
             save_game.store_line(json_string)
-        save_game.close()
 
  .. code-tab:: csharp
 
@@ -168,34 +166,34 @@ way to pull the data out of the file as well.
     // dict of relevant variables.
     public void SaveGame()
     {
-        var saveGame = new File();
-        saveGame.Open("user://savegame.save", (int)File.ModeFlags.Write);
+        using var saveGame = FileAccess.Open("user://savegame.save", FileAccess.ModeFlags.Write);
 
         var saveNodes = GetTree().GetNodesInGroup("Persist");
         foreach (Node saveNode in saveNodes)
         {
             // Check the node is an instanced scene so it can be instanced again during load.
-            if (saveNode.Filename.Empty())
+            if (string.IsNullOrEmpty(saveNode.SceneFilePath))
             {
-                GD.Print(String.Format("persistent node '{0}' is not an instanced scene, skipped", saveNode.Name));
+                GD.Print($"persistent node '{saveNode.Name}' is not an instanced scene, skipped");
                 continue;
             }
 
             // Check the node has a save function.
             if (!saveNode.HasMethod("Save"))
             {
-                GD.Print(String.Format("persistent node '{0}' is missing a Save() function, skipped", saveNode.Name));
+                GD.Print($"persistent node '{saveNode.Name}' is missing a Save() function, skipped");
                 continue;
             }
 
             // Call the node's save function.
             var nodeData = saveNode.Call("Save");
 
+            // JSON provides a static method to serialized JSON string
+            var jsonString = JSON.Stringify(nodeData);
+
             // Store the save dictionary as a new line in the save file.
-            saveGame.StoreLine(JSON.Print(nodeData));
+            saveGame.StoreLine(jsonString);
         }
-
-        saveGame.Close();
     }
 
 
@@ -212,8 +210,7 @@ load function:
     # Note: This can be called from anywhere inside the tree. This function
     # is path independent.
     func load_game():
-        var save_game = File.new()
-        if not save_game.file_exists("user://savegame.save"):
+        if not FileAccess.file_exists("user://savegame.save"):
             return # Error! We don't have a save to load.
 
         # We need to revert the game state so we're not cloning objects
@@ -226,8 +223,10 @@ load function:
 
         # Load the file line by line and process that dictionary to restore
         # the object it represents.
-        save_game.open("user://savegame.save", File.READ)
-        while save_game.get_position() < save_game.get_len():
+        var save_game = FileAccess.open("user://savegame.save", FileAccess.READ)
+        while save_game.get_position() < save_game.get_length():
+            var json_string = save_game.get_line()
+
             # Creates the helper class to interact with JSON
             var json = JSON.new()
 
@@ -251,16 +250,13 @@ load function:
                     continue
                 new_object.set(i, node_data[i])
 
-        save_game.close()
-
  .. code-tab:: csharp
 
     // Note: This can be called from anywhere inside the tree. This function is
     // path independent.
     public void LoadGame()
     {
-        var saveGame = new File();
-        if (!saveGame.FileExists("user://savegame.save"))
+        if (!FileAccess.FileExists("user://savegame.save"))
             return; // Error! We don't have a save to load.
 
         // We need to revert the game state so we're not cloning objects during loading.
@@ -273,30 +269,39 @@ load function:
 
         // Load the file line by line and process that dictionary to restore the object
         // it represents.
-        saveGame.Open("user://savegame.save", (int)File.ModeFlags.Read);
+        using var saveGame = FileAccess.Open("user://savegame.save", FileAccess.ModeFlags.Read);
 
-        while (saveGame.GetPosition() < saveGame.GetLen())
+        while (saveGame.GetPosition() < saveGame.GetLength())
         {
-            // Get the saved dictionary from the next line in the save file
-            var nodeData = new Godot.Collections.Dictionary<string, object>((Godot.Collections.Dictionary)JSON.Parse(saveGame.GetLine()).Result);
+            var jsonString = saveGame.GetLine();
+
+            // Creates the helper class to interact with JSON
+            var json = new JSON();
+            var parseResult = json.Parse(jsonString);
+            if (parseResult != Error.Ok)
+            {
+                GD.Print($"JSON Parse Error: {json.GetErrorMessage()} in {jsonString} at line {json.GetErrorLine()}");
+                continue;
+            }
+
+            // Get the data from the JSON object
+            var nodeData = new Godot.Collections.Dictionary<string, Variant>((Godot.Collections.Dictionary)json.Data);
 
             // Firstly, we need to create the object and add it to the tree and set its position.
             var newObjectScene = (PackedScene)ResourceLoader.Load(nodeData["Filename"].ToString());
             var newObject = (Node)newObjectScene.Instantiate();
             GetNode(nodeData["Parent"].ToString()).AddChild(newObject);
-            newObject.Set("Position", new Vector2((float)nodeData["PosX"], (float)nodeData["PosY"]));
+            newObject.Set("position", new Vector2((float)nodeData["PosX"], (float)nodeData["PosY"]));
 
             // Now we set the remaining variables.
-            foreach (KeyValuePair<string, object> entry in nodeData)
+            foreach (KeyValuePair<string, Variant> entry in nodeData)
             {
-                string key = entry.Key.ToString();
+                string key = entry.Key;
                 if (key == "Filename" || key == "Parent" || key == "PosX" || key == "PosY")
                     continue;
                 newObject.Set(key, entry.Value);
             }
         }
-
-        saveGame.Close();
     }