Move Saving and Loading demo to Loading category

This commit is contained in:
Aaron Franke
2020-12-28 14:00:04 -06:00
parent 96baaa09e3
commit 0d9c0d15c6
14 changed files with 11 additions and 2 deletions

View File

@@ -0,0 +1,20 @@
# Saving and Loading (Serialization)
This demo showcases how to save a simple game with each serialization
format supported by Godot:
- ConfigFile
- JSON
More formats may be added in the future.
For more information, see this documentation article:
https://docs.godotengine.org/en/latest/tutorials/io/saving_games.html
Language: GDScript
Renderer: GLES 2
## Screenshots
![Screenshot](screenshots/save_load.png)

View File

@@ -0,0 +1,7 @@
[gd_resource type="Environment" load_steps=2 format=2]
[sub_resource type="ProceduralSky" id=1]
[resource]
background_mode = 2
background_sky = SubResource( 1 )

View File

@@ -0,0 +1,29 @@
extends KinematicBody2D
const MOVE_SPEED = 75
const DAMAGE_PER_SECOND = 15
# The node we should be "attacking" every frame.
# If `null`, nobody is in range to attack.
var attacking = null
func _process(delta):
if attacking:
attacking.health -= delta * DAMAGE_PER_SECOND
# warning-ignore:return_value_discarded
move_and_slide(Vector2(MOVE_SPEED, 0))
# The enemy went outside of the window. Move it back to the left.
if position.x >= 732:
position.x = -32
func _on_AttackArea_body_entered(body):
if body.name == "Player":
attacking = body
func _on_AttackArea_body_exited(_body):
attacking = null

View File

@@ -0,0 +1,30 @@
[gd_scene load_steps=5 format=2]
[ext_resource path="res://enemy.gd" type="Script" id=1]
[ext_resource path="res://icon.png" type="Texture" id=2]
[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 32, 32 )
[sub_resource type="RectangleShape2D" id=2]
extents = Vector2( 38, 38 )
[node name="Enemy" type="KinematicBody2D" groups=[
"enemy",
]]
position = Vector2( 64, 160 )
script = ExtResource( 1 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource( 1 )
[node name="Sprite" type="Sprite" parent="."]
modulate = Color( 2, 0.6, 0.5, 1 )
texture = ExtResource( 2 )
[node name="AttackArea" type="Area2D" parent="."]
[node name="CollisionShape2D" type="CollisionShape2D" parent="AttackArea"]
shape = SubResource( 2 )
[connection signal="body_entered" from="AttackArea" to="." method="_on_AttackArea_body_entered"]
[connection signal="body_exited" from="AttackArea" to="." method="_on_AttackArea_body_exited"]

View File

@@ -0,0 +1,13 @@
extends VBoxContainer
func _ready():
var file = File.new()
# Don't allow loading files that don't exist yet.
$SaveLoad/LoadConfigFile.disabled = not file.file_exists(ProjectSettings.globalize_path("user://save_config_file.ini"))
$SaveLoad/LoadJSON.disabled = not file.file_exists(ProjectSettings.globalize_path("user://save_json.json"))
func _on_open_user_data_folder_pressed():
# warning-ignore:return_value_discarded
OS.shell_open(ProjectSettings.globalize_path("user://"))

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.png"
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View File

@@ -0,0 +1,30 @@
extends KinematicBody2D
# The player's movement speed.
const MOVE_SPEED = 240
var health = 100 setget set_health
var motion = Vector2()
onready var progress_bar = $Sprite/ProgressBar
func _process(delta):
# Player movement (controller-friendly).
var velocity = Vector2.ZERO
velocity.x = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
velocity.y = Input.get_action_strength("move_down") - Input.get_action_strength("move_up")
position += velocity * MOVE_SPEED * delta
# Prevent the player from going outside the window.
position.x = clamp(position.x, 32, 700)
position.y = clamp(position.y, 32, 536)
func set_health(p_health):
health = p_health
progress_bar.value = health
if health <= 0:
# The player died.
# warning-ignore:return_value_discarded
get_tree().reload_current_scene()

View File

@@ -0,0 +1,71 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="Saving and Loading (Serialization)"
run/main_scene="res://save_load.tscn"
config/icon="res://icon.png"
[display]
window/size/height=576
window/stretch/mode="2d"
window/stretch/aspect="expand"
[input]
move_up={
"deadzone": 0.2,
"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)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":-1.0,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null)
, 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)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":90,"unicode":0,"echo":false,"script":null)
]
}
move_down={
"deadzone": 0.2,
"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)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":1.0,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":13,"pressure":0.0,"pressed":false,"script":null)
, 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)
]
}
move_left={
"deadzone": 0.2,
"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)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":-1.0,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":14,"pressure":0.0,"pressed":false,"script":null)
, 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)
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":81,"unicode":0,"echo":false,"script":null)
]
}
move_right={
"deadzone": 0.2,
"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)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":1.0,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":15,"pressure":0.0,"pressed":false,"script":null)
, 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)
]
}
[rendering]
quality/driver/driver_name="GLES2"
vram_compression/import_etc=true
vram_compression/import_etc2=false
environment/default_clear_color=Color( 0.133333, 0.2, 0.266667, 1 )
environment/default_environment="res://default_env.tres"

View File

@@ -0,0 +1,160 @@
[gd_scene load_steps=10 format=2]
[ext_resource path="res://enemy.tscn" type="PackedScene" id=1]
[ext_resource path="res://gui.gd" type="Script" id=2]
[ext_resource path="res://save_load_json.gd" type="Script" id=3]
[ext_resource path="res://save_load_config_file.gd" type="Script" id=4]
[ext_resource path="res://icon.png" type="Texture" id=5]
[ext_resource path="res://player.gd" type="Script" id=6]
[sub_resource type="RectangleShape2D" id=1]
extents = Vector2( 32, 32 )
[sub_resource type="StyleBoxFlat" id=2]
bg_color = Color( 0.45098, 1, 0.152941, 1 )
corner_radius_top_left = 16
corner_radius_top_right = 16
corner_radius_bottom_right = 16
corner_radius_bottom_left = 16
[sub_resource type="StyleBoxFlat" id=3]
bg_color = Color( 0, 0, 0, 0.25098 )
corner_radius_top_left = 16
corner_radius_top_right = 16
corner_radius_bottom_right = 16
corner_radius_bottom_left = 16
[node name="Node" type="Node"]
[node name="Game" type="Node2D" parent="."]
position = Vector2( 296, 8 )
[node name="Player" type="KinematicBody2D" parent="Game"]
position = Vector2( 48, 40 )
script = ExtResource( 6 )
[node name="CollisionShape2D" type="CollisionShape2D" parent="Game/Player"]
shape = SubResource( 1 )
[node name="Sprite" type="Sprite" parent="Game/Player"]
texture = ExtResource( 5 )
[node name="ProgressBar" type="ProgressBar" parent="Game/Player/Sprite"]
margin_left = -32.0
margin_top = -40.0
margin_right = 32.0
margin_bottom = -34.0
custom_styles/fg = SubResource( 2 )
custom_styles/bg = SubResource( 3 )
value = 100.0
percent_visible = false
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Enemy" parent="Game" instance=ExtResource( 1 )]
[node name="Enemy2" parent="Game" instance=ExtResource( 1 )]
position = Vector2( 376, 304 )
[node name="Enemy3" parent="Game" instance=ExtResource( 1 )]
position = Vector2( 232, 464 )
[node name="Control" type="Control" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 8.0
margin_top = 8.0
margin_right = -11.9999
margin_bottom = -12.0
__meta__ = {
"_edit_lock_": true,
"_edit_use_anchors_": false
}
[node name="VBoxContainer" type="VBoxContainer" parent="Control"]
margin_right = 269.0
margin_bottom = 330.0
custom_constants/separation = 30
script = ExtResource( 2 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="SaveLoad" type="GridContainer" parent="Control/VBoxContainer"]
margin_right = 269.0
margin_bottom = 78.0
custom_constants/vseparation = 8
custom_constants/hseparation = 8
columns = 2
[node name="SaveConfigFile" type="Button" parent="Control/VBoxContainer/SaveLoad"]
margin_right = 130.0
margin_bottom = 35.0
rect_min_size = Vector2( 0, 35 )
size_flags_horizontal = 3
text = "Save as ConfigFile"
script = ExtResource( 4 )
game_node = NodePath("../../../../Game")
player_node = NodePath("../../../../Game/Player")
[node name="LoadConfigFile" type="Button" parent="Control/VBoxContainer/SaveLoad"]
margin_left = 138.0
margin_right = 268.0
margin_bottom = 35.0
rect_min_size = Vector2( 0, 35 )
size_flags_horizontal = 3
text = "Load as ConfigFile"
script = ExtResource( 4 )
game_node = NodePath("../../../../Game")
player_node = NodePath("../../../../Game/Player")
[node name="SaveJSON" type="Button" parent="Control/VBoxContainer/SaveLoad"]
margin_top = 43.0
margin_right = 130.0
margin_bottom = 78.0
rect_min_size = Vector2( 0, 35 )
size_flags_horizontal = 3
text = "Save as JSON"
script = ExtResource( 3 )
game_node = NodePath("../../../../Game")
player_node = NodePath("../../../../Game/Player")
[node name="LoadJSON" type="Button" parent="Control/VBoxContainer/SaveLoad"]
margin_left = 138.0
margin_top = 43.0
margin_right = 268.0
margin_bottom = 78.0
rect_min_size = Vector2( 0, 35 )
size_flags_horizontal = 3
text = "Load as JSON"
script = ExtResource( 3 )
game_node = NodePath("../../../../Game")
player_node = NodePath("../../../../Game/Player")
[node name="OpenUserDataFolder" type="Button" parent="Control/VBoxContainer"]
margin_top = 108.0
margin_right = 269.0
margin_bottom = 143.0
rect_min_size = Vector2( 0, 35 )
hint_tooltip = "Click this button to check the saved files using the operating system's file manager."
text = "Open User Data Folder"
[node name="RichTextLabel" type="RichTextLabel" parent="Control/VBoxContainer"]
margin_top = 173.0
margin_right = 269.0
margin_bottom = 453.0
rect_min_size = Vector2( 0, 280 )
custom_constants/line_separation = 4
bbcode_enabled = true
bbcode_text = "Use the arrow keys or controller to move the player.
Use the save and load buttons to save/load the game with the respective format (each format is its own savegame)."
text = "Use the arrow keys or controller to move the player.
Use the save and load buttons to save/load the game with the respective format (each format is its own savegame)."
[connection signal="pressed" from="Control/VBoxContainer/SaveLoad/SaveConfigFile" to="Control/VBoxContainer/SaveLoad/SaveConfigFile" method="save_game"]
[connection signal="pressed" from="Control/VBoxContainer/SaveLoad/LoadConfigFile" to="Control/VBoxContainer/SaveLoad/LoadConfigFile" method="load_game"]
[connection signal="pressed" from="Control/VBoxContainer/SaveLoad/SaveJSON" to="Control/VBoxContainer/SaveLoad/SaveJSON" method="save_game"]
[connection signal="pressed" from="Control/VBoxContainer/SaveLoad/LoadJSON" to="Control/VBoxContainer/SaveLoad/LoadJSON" method="load_game"]
[connection signal="pressed" from="Control/VBoxContainer/OpenUserDataFolder" to="Control/VBoxContainer" method="_on_open_user_data_folder_pressed"]

View File

@@ -0,0 +1,52 @@
extends Button
# This script shows how to save data using Godot's custom ConfigFile format.
# ConfigFile can store any Godot type natively.
# The root game node (so we can get and instance enemies).
export(NodePath) var game_node
# The player node (so we can set/get its health and position).
export(NodePath) var player_node
const SAVE_PATH = "user://save_config_file.ini"
func save_game():
var config = ConfigFile.new()
var player = get_node(player_node)
config.set_value("player", "position", player.position)
config.set_value("player", "health", player.health)
var enemies = []
for enemy in get_tree().get_nodes_in_group("enemy"):
enemies.push_back({
position = enemy.position,
})
config.set_value("enemies", "enemies", enemies)
config.save(SAVE_PATH)
get_node("../LoadConfigFile").disabled = false
# `load()` is reserved.
func load_game():
var config = ConfigFile.new()
config.load(SAVE_PATH)
var player = get_node(player_node)
player.position = config.get_value("player", "position")
player.health = config.get_value("player", "health")
# Remove existing enemies and add new ones.
for enemy in get_tree().get_nodes_in_group("enemy"):
enemy.queue_free()
var enemies = config.get_value("enemies", "enemies")
# Ensure the node structure is the same when loading.
var game = get_node(game_node)
for enemy_config in enemies:
var enemy = preload("res://enemy.tscn").instance()
enemy.position = enemy_config.position
game.add_child(enemy)

View File

@@ -0,0 +1,62 @@
extends Button
# This script shows how to save data using the JSON file format.
# JSON is a widely used file format, but not all Godot types can be
# stored natively. For example, integers get converted into doubles,
# and to store Vector2 and other non-JSON types you need `var2str()`.
# The root game node (so we can get and instance enemies).
export(NodePath) var game_node
# The player node (so we can set/get its health and position).
export(NodePath) var player_node
const SAVE_PATH = "user://save_json.json"
func save_game():
var file = File.new()
file.open(SAVE_PATH, File.WRITE)
var player = get_node(player_node)
# JSON doesn't support complex types such as Vector2.
# `var2str()` can be used to convert any Variant to a String.
var save_dict = {
player = {
position = var2str(player.position),
health = var2str(player.health),
},
enemies = []
}
for enemy in get_tree().get_nodes_in_group("enemy"):
save_dict.enemies.push_back({
position = var2str(enemy.position),
})
file.store_line(to_json(save_dict))
get_node("../LoadJSON").disabled = false
# `load()` is reserved.
func load_game():
var file = File.new()
file.open(SAVE_PATH, File.READ)
var save_dict = parse_json(file.get_line())
var player = get_node(player_node)
# JSON doesn't support complex types such as Vector2.
# `str2var()` can be used to convert a String to the corresponding Variant.
player.position = str2var(save_dict.player.position)
player.health = str2var(save_dict.player.health)
# Remove existing enemies and add new ones.
for enemy in get_tree().get_nodes_in_group("enemy"):
enemy.queue_free()
# Ensure the node structure is the same when loading.
var game = get_node(game_node)
for enemy_config in save_dict.enemies:
var enemy = preload("res://enemy.tscn").instance()
enemy.position = str2var(enemy_config.position)
game.add_child(enemy)

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB