├── LICENSE ├── README.md ├── _config.yml ├── default_env.tres ├── entities ├── enemy.gd ├── enemy.tscn ├── godoty.tscn ├── player.gd ├── player.tscn ├── pos2D.tscn ├── rigid.tscn ├── teleport.gd └── teleport.tscn ├── hud ├── interface.tscn └── interface_slot.gd ├── icon.png ├── icon.png.import ├── img ├── simple.png └── simple.png.import ├── levels ├── blue.tscn ├── green.tscn └── red.tscn ├── project.godot └── scripts ├── globals.gd ├── globals.tscn ├── level_root.gd ├── save_load.gd └── save_load.tscn /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 rdmtt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Godot 3.1 Advanced Save System 2 | 3 | An advanced save system prototype for Godot 3.1. 4 | Based on this short guide: https://docs.godotengine.org/en/3.0/tutorials/io/saving_games.html. 5 | 6 | ![screenshot] 7 | 8 | This save system can be used in rpg games where the player moves from level to level and the game has to keep track of all the changes to those levels. 9 | 10 | The demo constist of three levels: green < red > blue. You move through them by stepping on the yellow arrows. White circles are rigid bodies, their properties will be saved either when you save to a slot (buttons at the top) OR automatically when moving to another level. Red blocks are enemies, they will get permanently deleted from the scene once collided with. Press RMB (right mouse button) to create new rigid bodies. You can also move objects from one level to another, but it's not shown in the demo. 11 | 12 | ## How the system works: 13 | 14 | * **Entering a level**. 15 | 16 | * **If the map has NOT been entered before**: 17 | - Load the original map. 18 | - Let the player change stuff. 19 | - Save when exiting or saving to a slot. 20 | 21 | * **Else**: 22 | - Load the original map. 23 | - Delete all dynamic nodes, add nodes that are in the save data and change their properties. 24 | 25 | **current_data** - objects and their variables in current world state. This data is "captured" when saving to a slot. When loading the game, the data from a slot hops in in place of current_data. 26 | 27 | ## What it can do: 28 | - Save predefined variables as well as custom ones (defined either in main file or nodes) 29 | - "Teleport" objects to different levels 30 | - Dynamicaly update the levels based on current_data and the save the data to a file 31 | - Create new nodes and save their properties 32 | 33 | ## Known bugs: 34 | - Loading from a text file doesn't work (something wrong with json parsing, I think). 35 | 36 | # Do you like it? 37 | Follow me on Itch.io - more cool Godot stuff coming soon! - https://radmatt.itch.io/ 38 | 39 | [screenshot]: https://i.imgur.com/DM68NuH.png 40 | 41 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /default_env.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" load_steps=2 format=2] 2 | 3 | [sub_resource type="ProceduralSky" id=1] 4 | 5 | [resource] 6 | background_mode = 2 7 | background_sky = SubResource( 1 ) 8 | 9 | -------------------------------------------------------------------------------- /entities/enemy.gd: -------------------------------------------------------------------------------- 1 | extends Area2D 2 | 3 | # Declare member variables here. Examples: 4 | # var a = 2 5 | # var b = "text" 6 | 7 | # Called when the node enters the scene tree for the first time. 8 | func _ready(): 9 | pass # Replace with function body. 10 | 11 | # Called every frame. 'delta' is the elapsed time since the previous frame. 12 | #func _process(delta): 13 | # pass 14 | 15 | 16 | func _on_enemy_body_entered(body): 17 | if body == G.player(): 18 | G.points += 1 19 | save_load.delete_actor(self) -------------------------------------------------------------------------------- /entities/enemy.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://entities/enemy.gd" type="Script" id=1] 4 | [ext_resource path="res://img/simple.png" type="Texture" id=2] 5 | 6 | [sub_resource type="RectangleShape2D" id=1] 7 | extents = Vector2( 25, 25 ) 8 | 9 | [node name="enemy" type="Area2D" groups=[ 10 | "persist", 11 | ]] 12 | script = ExtResource( 1 ) 13 | 14 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."] 15 | position = Vector2( -0.5, -0.5 ) 16 | shape = SubResource( 1 ) 17 | 18 | [node name="Sprite2" type="Sprite" parent="."] 19 | modulate = Color( 0.729412, 0.192157, 0.192157, 1 ) 20 | position = Vector2( -0.5, -0.5 ) 21 | texture = ExtResource( 2 ) 22 | region_enabled = true 23 | region_rect = Rect2( 12, 12, 49, 49 ) 24 | 25 | [node name="Sprite" type="Sprite" parent="."] 26 | modulate = Color( 1, 0.262745, 0.262745, 1 ) 27 | position = Vector2( -0.5, -6.5 ) 28 | texture = ExtResource( 2 ) 29 | region_enabled = true 30 | region_rect = Rect2( 12, 12, 49, 49 ) 31 | 32 | [connection signal="body_entered" from="." to="." method="_on_enemy_body_entered"] 33 | -------------------------------------------------------------------------------- /entities/godoty.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=2] 2 | 3 | [ext_resource path="res://icon.png" type="Texture" id=1] 4 | 5 | [sub_resource type="RectangleShape2D" id=1] 6 | extents = Vector2( 17.4887, 17.3367 ) 7 | 8 | [node name="godoty" type="RigidBody2D" groups=[ 9 | "persist", 10 | ]] 11 | mode = 2 12 | gravity_scale = 0.0 13 | linear_damp = 1.0 14 | 15 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."] 16 | shape = SubResource( 1 ) 17 | 18 | [node name="Sprite" type="Sprite" parent="."] 19 | scale = Vector2( 0.5, 0.5 ) 20 | texture = ExtResource( 1 ) 21 | 22 | -------------------------------------------------------------------------------- /entities/player.gd: -------------------------------------------------------------------------------- 1 | 2 | extends KinematicBody2D 3 | 4 | var HP = 100 5 | var time_alive = 0 6 | 7 | var next_pos_ID = "" 8 | 9 | const RUN = 400 10 | const WALK = 250 11 | 12 | var dir = Vector2() 13 | var velocity = Vector2() 14 | var movement_mult = WALK 15 | 16 | 17 | func _physics_process(delta): 18 | 19 | dir = Vector2() 20 | 21 | if Input.is_action_pressed("ui_right"): 22 | dir.x = 1 23 | elif Input.is_action_pressed("ui_left"): 24 | dir.x = -1 25 | 26 | if Input.is_action_pressed("ui_down"): 27 | dir.y = 1 28 | elif Input.is_action_pressed("ui_up"): 29 | dir.y = -1 30 | 31 | if Input.is_action_pressed("run"): 32 | movement_mult = RUN 33 | else: 34 | movement_mult = WALK 35 | 36 | velocity = (dir.normalized() * movement_mult) 37 | 38 | velocity = move_and_slide(velocity, Vector2()) 39 | 40 | time_alive += 0.05 41 | 42 | 43 | func _input(ev): 44 | if ev is InputEventMouseButton and ev.button_index == 2 and ev.pressed: 45 | print("HELLO") 46 | var g = load("res://entities/godoty.tscn").instance() 47 | g.global_position = ev.position 48 | G.level_root().get_node("main").add_child(g, true) 49 | # VERY IMPORTANT! Add children with human-readable names - add_child([path], TRUE) 50 | 51 | 52 | func save_this(): 53 | var dict = {} 54 | 55 | dict.time_alive = self.time_alive 56 | dict.HP = self.HP 57 | 58 | return dict -------------------------------------------------------------------------------- /entities/player.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=2] 2 | 3 | [ext_resource path="res://entities/player.gd" type="Script" id=1] 4 | [ext_resource path="res://icon.png" type="Texture" id=2] 5 | 6 | [sub_resource type="RectangleShape2D" id=1] 7 | extents = Vector2( 33.7054, 34.1511 ) 8 | 9 | [sub_resource type="GDScript" id=2] 10 | script/source = " 11 | extends Label 12 | 13 | 14 | func _process(delta): 15 | text = str(floor(get_parent().time_alive)) 16 | " 17 | 18 | [node name="player" type="KinematicBody2D" groups=[ 19 | "persist", 20 | "player", 21 | ]] 22 | script = ExtResource( 1 ) 23 | 24 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."] 25 | shape = SubResource( 1 ) 26 | 27 | [node name="icon" type="Sprite" parent="."] 28 | texture = ExtResource( 2 ) 29 | 30 | [node name="Label" type="Label" parent="."] 31 | margin_left = -95.5133 32 | margin_top = 40.0597 33 | margin_right = 97.4867 34 | margin_bottom = 54.0597 35 | align = 1 36 | script = SubResource( 2 ) 37 | 38 | -------------------------------------------------------------------------------- /entities/pos2D.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene format=2] 2 | 3 | [node name="pos2D" type="Position2D" groups=[ 4 | "pos", 5 | ]] 6 | 7 | -------------------------------------------------------------------------------- /entities/rigid.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://img/simple.png" type="Texture" id=1] 4 | 5 | [sub_resource type="PhysicsMaterial" id=1] 6 | rough = true 7 | 8 | [sub_resource type="CircleShape2D" id=2] 9 | radius = 23.0217 10 | 11 | [node name="rigid" type="RigidBody2D" groups=[ 12 | "persist", 13 | ]] 14 | editor/display_folded = true 15 | mode = 2 16 | physics_material_override = SubResource( 1 ) 17 | gravity_scale = 0.0 18 | linear_damp = 1.0 19 | 20 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."] 21 | position = Vector2( 0.5, 0.5 ) 22 | shape = SubResource( 2 ) 23 | 24 | [node name="simple2" type="Sprite" parent="."] 25 | modulate = Color( 0.690196, 0.690196, 0.690196, 1 ) 26 | position = Vector2( 0.5, 0.5 ) 27 | texture = ExtResource( 1 ) 28 | region_enabled = true 29 | region_rect = Rect2( 102, 14, 45, 45 ) 30 | 31 | [node name="simple" type="Sprite" parent="."] 32 | position = Vector2( 0.5, -5.5 ) 33 | texture = ExtResource( 1 ) 34 | region_enabled = true 35 | region_rect = Rect2( 102, 14, 45, 45 ) 36 | 37 | -------------------------------------------------------------------------------- /entities/teleport.gd: -------------------------------------------------------------------------------- 1 | extends Node2D 2 | 3 | export(String, FILE, "*.tscn") var map 4 | export var pos_id = "" 5 | 6 | 7 | func _on_Area2D_body_entered(body): 8 | if body == G.player(): 9 | get_tree().set_pause(true) 10 | save_load.update_current_data() 11 | G.change_level(map, pos_id) 12 | -------------------------------------------------------------------------------- /entities/teleport.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://entities/teleport.gd" type="Script" id=1] 4 | [ext_resource path="res://img/simple.png" type="Texture" id=2] 5 | 6 | [sub_resource type="CircleShape2D" id=1] 7 | radius = 31.975 8 | 9 | [node name="teleport" type="Node2D" groups=[ 10 | "persist", 11 | ]] 12 | script = ExtResource( 1 ) 13 | 14 | [node name="Area2D" type="Area2D" parent="."] 15 | 16 | [node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"] 17 | shape = SubResource( 1 ) 18 | 19 | [node name="Sprite" type="Sprite" parent="."] 20 | modulate = Color( 0.992157, 1, 0, 1 ) 21 | position = Vector2( 0, 11 ) 22 | rotation = 2.35619 23 | texture = ExtResource( 2 ) 24 | region_enabled = true 25 | region_rect = Rect2( 188, 8, 58, 58 ) 26 | 27 | [connection signal="body_entered" from="Area2D" to="." method="_on_Area2D_body_entered"] 28 | -------------------------------------------------------------------------------- /hud/interface.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=2] 2 | 3 | [ext_resource path="res://hud/interface_slot.gd" type="Script" id=1] 4 | 5 | [sub_resource type="GDScript" id=1] 6 | script/source = " 7 | extends Label 8 | 9 | 10 | func _process(delta): 11 | set_text(\"POINTS: \" + str(G.points)) 12 | " 13 | 14 | [node name="interface" type="CanvasLayer"] 15 | layer = 100 16 | 17 | [node name="save" type="VBoxContainer" parent="."] 18 | margin_left = 27.0 19 | margin_top = 26.0 20 | margin_right = 227.0 21 | margin_bottom = 109.0 22 | 23 | [node name="slot_1" type="Button" parent="save" groups=[ 24 | "save_load_button", 25 | ]] 26 | margin_right = 200.0 27 | margin_bottom = 25.0 28 | rect_min_size = Vector2( 200, 25 ) 29 | text = "save 1" 30 | script = ExtResource( 1 ) 31 | 32 | [node name="slot_2" type="Button" parent="save" groups=[ 33 | "save_load_button", 34 | ]] 35 | margin_top = 29.0 36 | margin_right = 200.0 37 | margin_bottom = 54.0 38 | rect_min_size = Vector2( 200, 25 ) 39 | text = "save 2" 40 | script = ExtResource( 1 ) 41 | slot = 2 42 | 43 | [node name="slot_3" type="Button" parent="save" groups=[ 44 | "save_load_button", 45 | ]] 46 | margin_top = 58.0 47 | margin_right = 200.0 48 | margin_bottom = 83.0 49 | rect_min_size = Vector2( 200, 25 ) 50 | text = "save 3" 51 | script = ExtResource( 1 ) 52 | slot = 3 53 | 54 | [node name="load" type="VBoxContainer" parent="."] 55 | margin_left = 240.0 56 | margin_top = 25.0 57 | margin_right = 440.0 58 | margin_bottom = 108.0 59 | 60 | [node name="slot_1" type="Button" parent="load" groups=[ 61 | "save_load_button", 62 | ]] 63 | margin_right = 200.0 64 | margin_bottom = 25.0 65 | rect_min_size = Vector2( 200, 25 ) 66 | text = "load 1" 67 | script = ExtResource( 1 ) 68 | type = "LOAD" 69 | 70 | [node name="slot_2" type="Button" parent="load" groups=[ 71 | "save_load_button", 72 | ]] 73 | margin_top = 29.0 74 | margin_right = 200.0 75 | margin_bottom = 54.0 76 | rect_min_size = Vector2( 200, 25 ) 77 | text = "load 2" 78 | script = ExtResource( 1 ) 79 | slot = 2 80 | type = "LOAD" 81 | 82 | [node name="slot_3" type="Button" parent="load" groups=[ 83 | "save_load_button", 84 | ]] 85 | margin_top = 58.0 86 | margin_right = 200.0 87 | margin_bottom = 83.0 88 | rect_min_size = Vector2( 200, 25 ) 89 | text = "load 3" 90 | script = ExtResource( 1 ) 91 | slot = 3 92 | type = "LOAD" 93 | 94 | [node name="Label" type="Label" parent="."] 95 | margin_left = 872.0 96 | margin_top = 17.0 97 | margin_right = 936.0 98 | margin_bottom = 31.0 99 | rect_scale = Vector2( 2, 2 ) 100 | text = "Points: 99" 101 | script = SubResource( 1 ) 102 | 103 | [node name="Label2" type="Label" parent="."] 104 | modulate = Color( 1, 1, 1, 0.392157 ) 105 | margin_left = 769.0 106 | margin_top = 489.0 107 | margin_right = 1011.0 108 | margin_bottom = 588.0 109 | text = "WASD or ARROWS to move 110 | SHIFT or SPACE to run 111 | RMB to create new objects 112 | 113 | Defeat enemies 114 | Teleport by stepping on yellow arrows" 115 | 116 | -------------------------------------------------------------------------------- /hud/interface_slot.gd: -------------------------------------------------------------------------------- 1 | extends Button 2 | 3 | export (int, 1, 3) var slot = 1 4 | export (String, "SAVE", "LOAD") var type = "SAVE" 5 | 6 | func _ready(): 7 | connect("pressed", self, "on_pressed") 8 | update() 9 | 10 | func update(): 11 | if type == "SAVE": 12 | if save_load.slots["slot_"+str(slot)].empty(): 13 | text = "save to slot " + str(slot) 14 | else: 15 | text = "overwrite slot " + str(slot) 16 | else: 17 | if save_load.slots["slot_"+str(slot)].empty(): 18 | text = "EMPTY" 19 | else: 20 | text = "load slot " + str(slot) 21 | 22 | func on_pressed(): 23 | match type: 24 | "SAVE": 25 | save_load.save_to_slot("slot_"+str(slot)) 26 | # save_load.save_to_file(slot) 27 | "LOAD": 28 | if ! save_load.slots["slot_"+str(slot)].empty(): 29 | save_load.load_from_slot("slot_"+str(slot)) 30 | # save_load.load_from_file(slot) 31 | for x in get_tree().get_nodes_in_group("save_load_button"): 32 | x.update() -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdmtt/Godot-3.1-Advanced-Save-System/14dd989b63a235f8b934a42d92f496fa4130fc71/icon.png -------------------------------------------------------------------------------- /icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://icon.png" 13 | dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /img/simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rdmtt/Godot-3.1-Advanced-Save-System/14dd989b63a235f8b934a42d92f496fa4130fc71/img/simple.png -------------------------------------------------------------------------------- /img/simple.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/simple.png-c1bde0f8422db9edacce6abcf340bd36.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://img/simple.png" 13 | dest_files=[ "res://.import/simple.png-c1bde0f8422db9edacce6abcf340bd36.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=false 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /levels/blue.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=8 format=2] 2 | 3 | [ext_resource path="res://scripts/level_root.gd" type="Script" id=1] 4 | [ext_resource path="res://img/simple.png" type="Texture" id=2] 5 | [ext_resource path="res://entities/pos2D.tscn" type="PackedScene" id=3] 6 | [ext_resource path="res://entities/teleport.tscn" type="PackedScene" id=4] 7 | [ext_resource path="res://entities/rigid.tscn" type="PackedScene" id=5] 8 | [ext_resource path="res://entities/enemy.tscn" type="PackedScene" id=6] 9 | 10 | [sub_resource type="RectangleShape2D" id=1] 11 | extents = Vector2( 520, 10 ) 12 | 13 | [node name="blue" type="Node2D" groups=[ 14 | "level_root", 15 | ]] 16 | script = ExtResource( 1 ) 17 | 18 | [node name="load" type="Timer" parent="."] 19 | pause_mode = 2 20 | wait_time = 0.2 21 | one_shot = true 22 | autostart = true 23 | 24 | [node name="floor" type="Sprite" parent="."] 25 | modulate = Color( 0.0196078, 0.160784, 0.380392, 1 ) 26 | position = Vector2( 513.541, 304.724 ) 27 | scale = Vector2( 21.5416, 13.189 ) 28 | texture = ExtResource( 2 ) 29 | region_enabled = true 30 | region_rect = Rect2( 11, 11, 50, 50 ) 31 | 32 | [node name="enter_1" parent="." instance=ExtResource( 3 )] 33 | position = Vector2( 184.794, 285.877 ) 34 | 35 | [node name="main" type="YSort" parent="."] 36 | 37 | [node name="teleport" parent="main" instance=ExtResource( 4 )] 38 | position = Vector2( 34.0093, 278.877 ) 39 | rotation = -1.57079 40 | map = "res://levels/red.tscn" 41 | pos_id = "enter_2" 42 | 43 | [node name="rigid" parent="main" instance=ExtResource( 5 )] 44 | position = Vector2( 340.119, 280.478 ) 45 | 46 | [node name="rigid3" parent="main" instance=ExtResource( 5 )] 47 | position = Vector2( 516.958, 471.807 ) 48 | 49 | [node name="rigid4" parent="main" instance=ExtResource( 5 )] 50 | position = Vector2( 485.449, 63.693 ) 51 | 52 | [node name="rigid5" parent="main" instance=ExtResource( 5 )] 53 | position = Vector2( 718.449, 107.693 ) 54 | 55 | [node name="enemy3" parent="main" instance=ExtResource( 6 )] 56 | position = Vector2( 884.094, 100.306 ) 57 | 58 | [node name="enemy6" parent="main" instance=ExtResource( 6 )] 59 | position = Vector2( 275.464, 524.909 ) 60 | 61 | [node name="enemy7" parent="main" instance=ExtResource( 6 )] 62 | position = Vector2( 866.247, 398.693 ) 63 | 64 | [node name="walls" type="Node2D" parent="."] 65 | editor/display_folded = true 66 | visible = false 67 | 68 | [node name="StaticBody2D" type="StaticBody2D" parent="walls"] 69 | editor/display_folded = true 70 | position = Vector2( 511, -9 ) 71 | 72 | [node name="CollisionShape2D" type="CollisionShape2D" parent="walls/StaticBody2D"] 73 | shape = SubResource( 1 ) 74 | 75 | [node name="StaticBody2D2" type="StaticBody2D" parent="walls"] 76 | editor/display_folded = true 77 | position = Vector2( 513, 608 ) 78 | 79 | [node name="CollisionShape2D" type="CollisionShape2D" parent="walls/StaticBody2D2"] 80 | shape = SubResource( 1 ) 81 | 82 | [node name="StaticBody2D3" type="StaticBody2D" parent="walls"] 83 | editor/display_folded = true 84 | position = Vector2( 1030, 338 ) 85 | rotation = -1.57079 86 | 87 | [node name="CollisionShape2D" type="CollisionShape2D" parent="walls/StaticBody2D3"] 88 | shape = SubResource( 1 ) 89 | 90 | [node name="StaticBody2D4" type="StaticBody2D" parent="walls"] 91 | editor/display_folded = true 92 | position = Vector2( -8, 343 ) 93 | rotation = -1.57079 94 | 95 | [node name="CollisionShape2D" type="CollisionShape2D" parent="walls/StaticBody2D4"] 96 | shape = SubResource( 1 ) 97 | 98 | [connection signal="timeout" from="load" to="." method="_on_load_timeout"] 99 | -------------------------------------------------------------------------------- /levels/green.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=8 format=2] 2 | 3 | [ext_resource path="res://scripts/level_root.gd" type="Script" id=1] 4 | [ext_resource path="res://img/simple.png" type="Texture" id=2] 5 | [ext_resource path="res://entities/pos2D.tscn" type="PackedScene" id=3] 6 | [ext_resource path="res://entities/teleport.tscn" type="PackedScene" id=4] 7 | [ext_resource path="res://entities/rigid.tscn" type="PackedScene" id=5] 8 | [ext_resource path="res://entities/enemy.tscn" type="PackedScene" id=6] 9 | 10 | [sub_resource type="RectangleShape2D" id=1] 11 | extents = Vector2( 520, 10 ) 12 | 13 | [node name="green" type="Node2D" groups=[ 14 | "level_root", 15 | ]] 16 | script = ExtResource( 1 ) 17 | 18 | [node name="load" type="Timer" parent="."] 19 | pause_mode = 2 20 | wait_time = 0.2 21 | one_shot = true 22 | autostart = true 23 | 24 | [node name="floor" type="Sprite" parent="."] 25 | modulate = Color( 0.0705882, 0.380392, 0.0196078, 1 ) 26 | position = Vector2( 513.541, 304.724 ) 27 | scale = Vector2( 21.5416, 13.189 ) 28 | texture = ExtResource( 2 ) 29 | region_enabled = true 30 | region_rect = Rect2( 11, 11, 50, 50 ) 31 | 32 | [node name="enter_1" parent="." instance=ExtResource( 3 )] 33 | position = Vector2( 846.135, 290.679 ) 34 | 35 | [node name="main" type="YSort" parent="."] 36 | 37 | [node name="teleport2" parent="main" instance=ExtResource( 4 )] 38 | position = Vector2( 983.911, 288.039 ) 39 | rotation = 1.57079 40 | map = "res://levels/red.tscn" 41 | pos_id = "enter_1" 42 | 43 | [node name="rigid" parent="main" instance=ExtResource( 5 )] 44 | position = Vector2( 130.119, 137.478 ) 45 | 46 | [node name="rigid5" parent="main" instance=ExtResource( 5 )] 47 | position = Vector2( 818.449, 126.693 ) 48 | 49 | [node name="enemy" parent="main" instance=ExtResource( 6 )] 50 | position = Vector2( 294.314, 520.983 ) 51 | 52 | [node name="enemy2" parent="main" instance=ExtResource( 6 )] 53 | position = Vector2( 265.875, 126.355 ) 54 | 55 | [node name="enemy3" parent="main" instance=ExtResource( 6 )] 56 | position = Vector2( 599.094, 530.306 ) 57 | 58 | [node name="enemy4" parent="main" instance=ExtResource( 6 )] 59 | position = Vector2( 508.875, 212.127 ) 60 | 61 | [node name="enemy5" parent="main" instance=ExtResource( 6 )] 62 | position = Vector2( 95.966, 334.378 ) 63 | 64 | [node name="enemy6" parent="main" instance=ExtResource( 6 )] 65 | position = Vector2( 697.464, 79.909 ) 66 | 67 | [node name="enemy7" parent="main" instance=ExtResource( 6 )] 68 | position = Vector2( 853.247, 537.693 ) 69 | 70 | [node name="walls" type="Node2D" parent="."] 71 | editor/display_folded = true 72 | visible = false 73 | 74 | [node name="StaticBody2D" type="StaticBody2D" parent="walls"] 75 | editor/display_folded = true 76 | position = Vector2( 511, -9 ) 77 | 78 | [node name="CollisionShape2D" type="CollisionShape2D" parent="walls/StaticBody2D"] 79 | shape = SubResource( 1 ) 80 | 81 | [node name="StaticBody2D2" type="StaticBody2D" parent="walls"] 82 | editor/display_folded = true 83 | position = Vector2( 513, 608 ) 84 | 85 | [node name="CollisionShape2D" type="CollisionShape2D" parent="walls/StaticBody2D2"] 86 | shape = SubResource( 1 ) 87 | 88 | [node name="StaticBody2D3" type="StaticBody2D" parent="walls"] 89 | editor/display_folded = true 90 | position = Vector2( 1030, 338 ) 91 | rotation = -1.57079 92 | 93 | [node name="CollisionShape2D" type="CollisionShape2D" parent="walls/StaticBody2D3"] 94 | shape = SubResource( 1 ) 95 | 96 | [node name="StaticBody2D4" type="StaticBody2D" parent="walls"] 97 | editor/display_folded = true 98 | position = Vector2( -8, 343 ) 99 | rotation = -1.57079 100 | 101 | [node name="CollisionShape2D" type="CollisionShape2D" parent="walls/StaticBody2D4"] 102 | shape = SubResource( 1 ) 103 | 104 | [connection signal="timeout" from="load" to="." method="_on_load_timeout"] 105 | -------------------------------------------------------------------------------- /levels/red.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=9 format=2] 2 | 3 | [ext_resource path="res://scripts/level_root.gd" type="Script" id=1] 4 | [ext_resource path="res://img/simple.png" type="Texture" id=2] 5 | [ext_resource path="res://entities/pos2D.tscn" type="PackedScene" id=3] 6 | [ext_resource path="res://entities/enemy.tscn" type="PackedScene" id=4] 7 | [ext_resource path="res://entities/teleport.tscn" type="PackedScene" id=5] 8 | [ext_resource path="res://entities/player.tscn" type="PackedScene" id=6] 9 | [ext_resource path="res://entities/rigid.tscn" type="PackedScene" id=7] 10 | 11 | [sub_resource type="RectangleShape2D" id=1] 12 | extents = Vector2( 520, 10 ) 13 | 14 | [node name="red" type="Node2D" groups=[ 15 | "level_root", 16 | ]] 17 | script = ExtResource( 1 ) 18 | 19 | [node name="load" type="Timer" parent="."] 20 | pause_mode = 2 21 | wait_time = 0.2 22 | one_shot = true 23 | autostart = true 24 | 25 | [node name="floor" type="Sprite" parent="."] 26 | modulate = Color( 0.380392, 0.0196078, 0.0196078, 1 ) 27 | position = Vector2( 513.541, 304.724 ) 28 | scale = Vector2( 21.5416, 13.189 ) 29 | texture = ExtResource( 2 ) 30 | region_enabled = true 31 | region_rect = Rect2( 11, 11, 50, 50 ) 32 | 33 | [node name="enter_1" parent="." instance=ExtResource( 3 )] 34 | position = Vector2( 197.794, 272.877 ) 35 | 36 | [node name="enter_2" parent="." instance=ExtResource( 3 )] 37 | position = Vector2( 865.135, 284.679 ) 38 | 39 | [node name="main" type="Node2D" parent="."] 40 | editor/display_folded = true 41 | 42 | [node name="enemy" parent="main" instance=ExtResource( 4 )] 43 | position = Vector2( 174, 94 ) 44 | 45 | [node name="enemy2" parent="main" instance=ExtResource( 4 )] 46 | position = Vector2( 590, 71 ) 47 | 48 | [node name="enemy3" parent="main" instance=ExtResource( 4 )] 49 | position = Vector2( 813, 412 ) 50 | 51 | [node name="enemy4" parent="main" instance=ExtResource( 4 )] 52 | position = Vector2( 311, 531 ) 53 | 54 | [node name="enemy5" parent="main" instance=ExtResource( 4 )] 55 | position = Vector2( 827, 142 ) 56 | 57 | [node name="enemy6" parent="main" instance=ExtResource( 4 )] 58 | position = Vector2( 148, 450 ) 59 | 60 | [node name="teleport" parent="main" instance=ExtResource( 5 )] 61 | position = Vector2( 34.0093, 278.877 ) 62 | rotation = -1.57079 63 | map = "res://levels/green.tscn" 64 | pos_id = "enter_1" 65 | 66 | [node name="teleport2" parent="main" instance=ExtResource( 5 )] 67 | position = Vector2( 984.911, 287.039 ) 68 | rotation = 1.57079 69 | map = "res://levels/blue.tscn" 70 | pos_id = "enter_1" 71 | 72 | [node name="player" parent="main" instance=ExtResource( 6 )] 73 | position = Vector2( 491, 308 ) 74 | 75 | [node name="rigid" parent="main" instance=ExtResource( 7 )] 76 | position = Vector2( 426, 217 ) 77 | 78 | [node name="rigid2" parent="main" instance=ExtResource( 7 )] 79 | position = Vector2( 500, 219 ) 80 | 81 | [node name="rigid3" parent="main" instance=ExtResource( 7 )] 82 | position = Vector2( 565, 254 ) 83 | 84 | [node name="rigid4" parent="main" instance=ExtResource( 7 )] 85 | position = Vector2( 390, 284 ) 86 | 87 | [node name="rigid5" parent="main" instance=ExtResource( 7 )] 88 | position = Vector2( 424, 391 ) 89 | 90 | [node name="rigid6" parent="main" instance=ExtResource( 7 )] 91 | position = Vector2( 514, 403 ) 92 | 93 | [node name="rigid7" parent="main" instance=ExtResource( 7 )] 94 | position = Vector2( 587, 336 ) 95 | 96 | [node name="rigid8" parent="main" instance=ExtResource( 7 )] 97 | position = Vector2( 377, 340 ) 98 | 99 | [node name="walls" type="Node2D" parent="."] 100 | editor/display_folded = true 101 | visible = false 102 | 103 | [node name="StaticBody2D" type="StaticBody2D" parent="walls"] 104 | editor/display_folded = true 105 | position = Vector2( 511, -9 ) 106 | 107 | [node name="CollisionShape2D" type="CollisionShape2D" parent="walls/StaticBody2D"] 108 | shape = SubResource( 1 ) 109 | 110 | [node name="StaticBody2D2" type="StaticBody2D" parent="walls"] 111 | editor/display_folded = true 112 | position = Vector2( 513, 608 ) 113 | 114 | [node name="CollisionShape2D" type="CollisionShape2D" parent="walls/StaticBody2D2"] 115 | shape = SubResource( 1 ) 116 | 117 | [node name="StaticBody2D3" type="StaticBody2D" parent="walls"] 118 | editor/display_folded = true 119 | position = Vector2( 1030, 338 ) 120 | rotation = -1.57079 121 | 122 | [node name="CollisionShape2D" type="CollisionShape2D" parent="walls/StaticBody2D3"] 123 | shape = SubResource( 1 ) 124 | 125 | [node name="StaticBody2D4" type="StaticBody2D" parent="walls"] 126 | editor/display_folded = true 127 | position = Vector2( -8, 343 ) 128 | rotation = -1.57079 129 | 130 | [node name="CollisionShape2D" type="CollisionShape2D" parent="walls/StaticBody2D4"] 131 | shape = SubResource( 1 ) 132 | 133 | [connection signal="timeout" from="load" to="." method="_on_load_timeout"] 134 | -------------------------------------------------------------------------------- /project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=4 10 | 11 | _global_script_classes=[ ] 12 | _global_script_class_icons={ 13 | 14 | } 15 | 16 | [application] 17 | 18 | config/name="Advanced Save System" 19 | run/main_scene="res://levels/red.tscn" 20 | config/icon="res://icon.png" 21 | 22 | [autoload] 23 | 24 | interface="*res://hud/interface.tscn" 25 | G="*res://scripts/globals.tscn" 26 | save_load="*res://scripts/save_load.tscn" 27 | 28 | [display] 29 | 30 | window/stretch/mode="viewport" 31 | window/stretch/aspect="keep_height" 32 | 33 | [input] 34 | 35 | ui_left={ 36 | "deadzone": 0.5, 37 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777231,"unicode":0,"echo":false,"script":null) 38 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":14,"pressure":0.0,"pressed":false,"script":null) 39 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"unicode":0,"echo":false,"script":null) 40 | ] 41 | } 42 | ui_right={ 43 | "deadzone": 0.5, 44 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777233,"unicode":0,"echo":false,"script":null) 45 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":15,"pressure":0.0,"pressed":false,"script":null) 46 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"unicode":0,"echo":false,"script":null) 47 | ] 48 | } 49 | ui_up={ 50 | "deadzone": 0.5, 51 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777232,"unicode":0,"echo":false,"script":null) 52 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null) 53 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":87,"unicode":0,"echo":false,"script":null) 54 | ] 55 | } 56 | ui_down={ 57 | "deadzone": 0.5, 58 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777234,"unicode":0,"echo":false,"script":null) 59 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":13,"pressure":0.0,"pressed":false,"script":null) 60 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":83,"unicode":0,"echo":false,"script":null) 61 | ] 62 | } 63 | run={ 64 | "deadzone": 0.5, 65 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":32,"unicode":0,"echo":false,"script":null) 66 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777237,"unicode":0,"echo":false,"script":null) 67 | ] 68 | } 69 | 70 | [rendering] 71 | 72 | environment/default_environment="res://default_env.tres" 73 | -------------------------------------------------------------------------------- /scripts/globals.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | var points = 0 4 | var player_name = "player" 5 | 6 | ########################################################################### 7 | # ADDITIONAL FUNCTIONS 8 | 9 | func player(): 10 | for x in get_tree().get_nodes_in_group("player"): 11 | return x 12 | 13 | func time(sec): 14 | var timer = Timer.new() 15 | timer.pause_mode = Node.PAUSE_MODE_PROCESS 16 | get_tree().get_root().add_child(timer) #to process 17 | timer.set_wait_time(sec) # Set Timer's delay to "sec" seconds 18 | timer.start() # Start the Timer counting down 19 | return timer 20 | 21 | func delete_actor(relate): 22 | save_load.current_data.erase([level_root().filename, relate.name]) 23 | relate.queue_free() 24 | 25 | func teleport_actor(relate, map, pos_ID): 26 | if save_load.current_data.has([level_root().filename, relate.name]): 27 | var old = (save_load.current_data[[level_root().filename, relate.name]]).duplicate() 28 | save_load.current_data[[map, relate.name]] = old 29 | save_load.current_data[[map, relate.name]]["next_pos_ID"] = pos_ID 30 | save_load.current_data.erase([level_root().filename, relate.name]) 31 | relate.queue_free() 32 | 33 | func change_level(map, pos_ID): 34 | teleport_actor(player(), map, pos_ID) 35 | yield(time(0.01), "timeout") 36 | get_tree().change_scene(map) 37 | 38 | func level_root(): 39 | for x in get_tree().get_nodes_in_group("level_root"): 40 | return x 41 | 42 | func main(): 43 | return level_root().get_node("main") 44 | 45 | func get_position_2D(ID): 46 | for x in get_tree().get_nodes_in_group("pos"): 47 | if x.name == ID: 48 | return x 49 | -------------------------------------------------------------------------------- /scripts/globals.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://scripts/globals.gd" type="Script" id=1] 4 | 5 | [node name="globals" type="Node"] 6 | pause_mode = 2 7 | script = ExtResource( 1 ) 8 | 9 | -------------------------------------------------------------------------------- /scripts/level_root.gd: -------------------------------------------------------------------------------- 1 | 2 | extends Node2D 3 | 4 | func _ready(): 5 | get_tree().set_pause(true) 6 | save_load.load_map() 7 | 8 | func _on_load_timeout(): # Yield() doesn't work in ready() so an autostart timer is needed 9 | save_load.update_current_data() 10 | yield(save_load.time(0.1), "timeout") 11 | get_tree().set_pause(false) -------------------------------------------------------------------------------- /scripts/save_load.gd: -------------------------------------------------------------------------------- 1 | 2 | ########################################################################################### 3 | # CODE BY RADMATT @rdmtt/radmtt 4 | # Credit me if you change, use or share it. 5 | ########################################################################################### 6 | 7 | ########################################################################################### 8 | # This is a prototype, there might be some bugs and limitations but it is, in my opinion, the correct way 9 | # of saving complicated games with multiple levels. 10 | # Please improve on it if you can and share it with the community. 11 | 12 | # SEE GITHUB REPSOITORY FOR MORE INFO - https://github.com/rdmtt/Godot-3.1-Advanced-Save-System 13 | ########################################################################################### 14 | 15 | extends "res://scripts/globals.gd" 16 | 17 | # not working properly 18 | #var paths = ["user://slot_1.save", "user://slot_2.save", "user://slot_3.save"] 19 | 20 | var last_saved_slot = 0 21 | 22 | var slots = { 23 | "slot_1":{}, 24 | "slot_2":{}, 25 | "slot_3":{}, 26 | } 27 | 28 | # UPDATED REGULARLY 29 | var current_data = { 30 | } 31 | 32 | # UPDATED AT MAP'S _READY 33 | var map_data = { 34 | } 35 | 36 | var visited_maps = [] 37 | 38 | func reset_data(): 39 | current_data = {} 40 | map_data = {} 41 | visited_maps = [] 42 | 43 | func update_current_data(): 44 | if level_root() != null: 45 | 46 | for x in get_tree().get_nodes_in_group("persist"): 47 | var actor_data = [] 48 | 49 | # save fixed variables (in func save_node()) 50 | actor_data = save_node(x).duplicate() 51 | 52 | # save custom variables 53 | if x.has_method("save_this"): 54 | var dict = x.save_this() 55 | for y in dict: 56 | actor_data[y] = dict[y] 57 | 58 | # stich save data together 59 | current_data[[level_root().get_filename(), x.name]] = actor_data 60 | 61 | current_data["last_map"] = level_root().get_filename() 62 | current_data["visited_maps"] = visited_maps.duplicate() 63 | 64 | current_data["date"] = {"second": OS.get_time()["second"], "minute": OS.get_time()["minute"], "hour" : OS.get_time()["hour"], "day": OS.get_date()["day"], "month" : OS.get_date()["month"], "year" : OS.get_date()["year"]} 65 | 66 | current_data["last_saved_slot"] = last_saved_slot 67 | 68 | 69 | # SAVING GLOBAL VALUES 70 | current_data["globals"] = {} 71 | var arr = ["points", "player_name"] 72 | 73 | for x in arr: 74 | current_data["globals"][x] = G.get(x) 75 | 76 | 77 | func update_map_data(): 78 | if level_root() != null: 79 | 80 | for x in get_tree().get_nodes_in_group("persist"): 81 | var actor_data = [] 82 | 83 | # save fixed variables (in func save_node()) 84 | actor_data = save_node(x).duplicate() 85 | 86 | # save custom variables 87 | if x.has_method("save_this"): 88 | var dict = x.save_this() 89 | for y in dict: 90 | actor_data[y] = dict[y] 91 | 92 | # stich save data together 93 | map_data[[level_root().get_filename(), x.name]] = actor_data 94 | 95 | 96 | 97 | 98 | func load_map(): 99 | # data structure ---- [[map_filename, node_name], node] 100 | update_map_data() 101 | 102 | var persist_nodes = get_tree().get_nodes_in_group("persist") 103 | 104 | var keys_in_map = [] 105 | for node in persist_nodes: 106 | keys_in_map.append([[level_root().filename, node.name], node]) 107 | 108 | 109 | if visited_maps.has(level_root().filename): 110 | # DELETE OBJECTS 111 | for x in keys_in_map: 112 | if !(current_data.has(x[0])): 113 | x[1].queue_free() 114 | else: 115 | visited_maps.append(level_root().filename) 116 | 117 | # ADD OBJECTS 118 | for x in current_data: 119 | if x[0] == level_root().filename and !(map_data.has(x)): 120 | var obj = load(current_data[x]["file"]).instance() 121 | obj.name = current_data[x]["name"] 122 | level_root().get_node("main").add_child(obj) 123 | 124 | # UPDATE OBJECTS 125 | yield(time(0.01), "timeout") 126 | for node in get_tree().get_nodes_in_group("persist"): 127 | update_node(node) 128 | 129 | 130 | 131 | 132 | func update_node(node): 133 | if current_data.has([level_root().filename, node.name]): 134 | var data = current_data[[level_root().filename, node.name]] 135 | 136 | if data.has("next_pos_ID"): 137 | if data["next_pos_ID"] != "": 138 | var pos = get_position_2D(data["next_pos_ID"]).global_position 139 | node.global_position = pos 140 | current_data[[level_root().filename, node.name]]["next_pos_ID"] = "" 141 | node.next_pos_ID = "" 142 | else: 143 | node.global_position = Vector2(data["pos"][0], data["pos"][1]) 144 | else: 145 | node.global_position = Vector2(data["pos"][0], data["pos"][1]) 146 | 147 | for x in data: 148 | if x == "scale": 149 | node.scale = Vector2(data["scale"][0], data["scale"][1]) 150 | else: 151 | node.set(x, data[x]) 152 | 153 | 154 | 155 | # IMPORTANT! THIS IS WHERE YOU DECLARE VALUES TO BE SAVED! 156 | func save_node(node): 157 | var all = {} 158 | 159 | if node is Node2D: 160 | all.parent = node.get_parent().get_path() 161 | all.file = node.get_filename() 162 | all.name = node.get_name() 163 | all.groups = node.get_groups() 164 | all.pos = [node.get_global_position().x, node.get_global_position().y] 165 | all.rotation_degrees = node.get_rotation_degrees() 166 | all.scale = [node.get_scale().x, node.get_scale().y] 167 | 168 | if node is RigidBody2D: 169 | all.mode = node.mode 170 | all.mass = node.mass 171 | all.weight = node.weight 172 | all.gravity_scale = node.gravity_scale 173 | all.linear_velocity = node.linear_velocity 174 | all.linear_damp = node.linear_damp 175 | all.angular_velocity = node.angular_velocity 176 | all.angular_damp = node.angular_damp 177 | 178 | 179 | return all 180 | 181 | 182 | 183 | func save_to_slot(slot_name): 184 | update_current_data() 185 | if slots.has(slot_name): 186 | slots[slot_name] = current_data.duplicate() 187 | # print("SAVED") 188 | else: 189 | print("THIS SLOT DOESN'T EXIST") 190 | 191 | 192 | func load_from_slot(slot_name): 193 | 194 | current_data = slots[slot_name].duplicate() 195 | visited_maps = slots[slot_name]["visited_maps"].duplicate() 196 | last_saved_slot = slots[slot_name]["last_saved_slot"] 197 | 198 | for x in slots[slot_name]["globals"].keys(): 199 | G.set(x, slots[slot_name]["globals"][x]) 200 | 201 | yield(time(0.01), "timeout") 202 | get_tree().change_scene(slots[slot_name]["last_map"]) 203 | 204 | 205 | # EXPORTING TO FILES NOT WORKING PROPERLY 206 | 207 | #func save_to_file(slot): 208 | # save_to_slot("slot_"+str(slot)) 209 | # yield(time(0.1), "timeout") 210 | # var save_game = File.new() 211 | # save_game.open(paths[slot+1], File.WRITE) 212 | # save_game.store_line(to_json(current_data.duplicate())) 213 | ## print(save_game.get_as_text()) 214 | # save_game.close() 215 | 216 | 217 | #func load_from_file(slot): 218 | # var save_game = File.new() 219 | # save_game.open(paths[slot+1], File.READ) 220 | # var data = parse_json(save_game.get_as_text()) 221 | ## var data = parse_json(save_game.get_line()) 222 | # yield(time(0.01), "timeout") 223 | # slots["slot_"+str(slot)] = data 224 | # save_game.close() 225 | # 226 | # yield(time(0.01), "timeout") 227 | # 228 | # load_from_slot("slot_"+str(slot)) 229 | 230 | -------------------------------------------------------------------------------- /scripts/save_load.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://scripts/save_load.gd" type="Script" id=1] 4 | 5 | [node name="save_load" type="Node"] 6 | pause_mode = 2 7 | script = ExtResource( 1 ) 8 | 9 | --------------------------------------------------------------------------------