Moved certain tutorials to better-named subfolders from 'Misc'

This commit is contained in:
Neil Moore
2018-04-04 23:10:03 -04:00
parent 6493c06853
commit dc7463f7dc
15 changed files with 22 additions and 6 deletions

View File

@@ -1,299 +0,0 @@
.. _doc_background_loading:
Background loading
==================
When switching the main scene of your game (e.g. going to a new
level), you might want to show a loading screen with some indication
that progress is being made. The main load method
(``ResourceLoader::load`` or just ``load`` from GDScript) blocks your
thread while the resource is being loaded, so it's not good. This
document discusses the ``ResourceInteractiveLoader`` class for smoother
load screens.
ResourceInteractiveLoader
-------------------------
The ``ResourceInteractiveLoader`` class allows you to load a resource in
stages. Every time the method ``poll`` is called, a new stage is loaded,
and control is returned to the caller. Each stage is generally a
sub-resource that is loaded by the main resource. For example, if you're
loading a scene that loads 10 images, each image will be one stage.
Usage
-----
Usage is generally as follows
Obtaining a ResourceInteractiveLoader
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(String p_path);
This method will give you a ResourceInteractiveLoader that you will use
to manage the load operation.
Polling
~~~~~~~
::
Error ResourceInteractiveLoader::poll();
Use this method to advance the progress of the load. Each call to
``poll`` will load the next stage of your resource. Keep in mind that
each stage is one entire "atomic" resource, such as an image, or a mesh,
so it will take several frames to load.
Returns ``OK`` on no errors, ``ERR_FILE_EOF`` when loading is finished.
Any other return value means there was an error and loading has stopped.
Load progress (optional)
~~~~~~~~~~~~~~~~~~~~~~~~
To query the progress of the load, use the following methods:
::
int ResourceInteractiveLoader::get_stage_count() const;
int ResourceInteractiveLoader::get_stage() const;
``get_stage_count`` returns the total number of stages to load.
``get_stage`` returns the current stage being loaded.
Forcing completion (optional)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
Error ResourceInteractiveLoader::wait();
Use this method if you need to load the entire resource in the current
frame, without any more steps.
Obtaining the resource
~~~~~~~~~~~~~~~~~~~~~~
::
Ref<Resource> ResourceInteractiveLoader::get_resource();
If everything goes well, use this method to retrieve your loaded
resource.
Example
-------
This example demostrates how to load a new scene. Consider it in the
context of the :ref:`doc_singletons_autoload` example.
First we setup some variables and initialize the ``current_scene``
with the main scene of the game:
::
var loader
var wait_frames
var time_max = 100 # msec
var current_scene
func _ready():
var root = get_tree().get_root()
current_scene = root.get_child(root.get_child_count() -1)
The function ``goto_scene`` is called from the game when the scene
needs to be switched. It requests an interactive loader, and calls
``set_process(true)`` to start polling the loader in the ``_process``
callback. It also starts a "loading" animation, which can show a
progress bar or loading screen, etc.
::
func goto_scene(path): # game requests to switch to this scene
loader = ResourceLoader.load_interactive(path)
if loader == null: # check for errors
show_error()
return
set_process(true)
current_scene.queue_free() # get rid of the old scene
# start your "loading..." animation
get_node("animation").play("loading")
wait_frames = 1
``_process`` is where the loader is polled. ``poll`` is called, and then
we deal with the return value from that call. ``OK`` means keep polling,
``ERR_FILE_EOF`` means load is done, anything else means there was an
error. Also note we skip one frame (via ``wait_frames``, set on the
``goto_scene`` function) to allow the loading screen to show up.
Note how we use ``OS.get_ticks_msec`` to control how long we block the
thread. Some stages might load really fast, which means we might be able
to cram more than one call to ``poll`` in one frame, some might take way
more than your value for ``time_max``, so keep in mind we won't have
precise control over the timings.
::
func _process(time):
if loader == null:
# no need to process anymore
set_process(false)
return
if wait_frames > 0: # wait for frames to let the "loading" animation to show up
wait_frames -= 1
return
var t = OS.get_ticks_msec()
while OS.get_ticks_msec() < t + time_max: # use "time_max" to control how much time we block this thread
# poll your loader
var err = loader.poll()
if err == ERR_FILE_EOF: # load finished
var resource = loader.get_resource()
loader = null
set_new_scene(resource)
break
elif err == OK:
update_progress()
else: # error during loading
show_error()
loader = null
break
Some extra helper functions. ``update_progress`` updates a progress bar,
or can also update a paused animation (the animation represents the
entire load process from beginning to end). ``set_new_scene`` puts the
newly loaded scene on the tree. Because it's a scene being loaded,
``instance()`` needs to be called on the resource obtained from the
loader.
::
func update_progress():
var progress = float(loader.get_stage()) / loader.get_stage_count()
# update your progress bar?
get_node("progress").set_progress(progress)
# or update a progress animation?
var len = get_node("animation").get_current_animation_length()
# call this on a paused animation. use "true" as the second parameter to force the animation to update
get_node("animation").seek(progress * len, true)
func set_new_scene(scene_resource):
current_scene = scene_resource.instance()
get_node("/root").add_child(current_scene)
Using multiple threads
----------------------
ResourceInteractiveLoader can be used from multiple threads. A couple of
things to keep in mind if you attempt it:
Use a Semaphore
~~~~~~~~~~~~~~~
While your thread waits for the main thread to request a new resource,
use a Semaphore to sleep (instead of a busy loop or anything similar).
Not blocking main thread during the polling
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you have a mutex to allow calls from the main thread to your loader
class, don't lock it while you call ``poll`` on the loader. When a
resource is finished loading, it might require some resources from the
low level APIs (VisualServer, etc), which might need to lock the main
thread to acquire them. This might cause a deadlock if the main thread
is waiting for your mutex while your thread is waiting to load a
resource.
Example class
-------------
You can find an example class for loading resources in threads here:
:download:`resource_queue.gd <files/resource_queue.gd>`. Usage is as follows:
::
func start()
Call after you instance the class to start the thread.
::
func queue_resource(path, p_in_front = false)
Queue a resource. Use optional parameter "p_in_front" to put it in
front of the queue.
::
func cancel_resource(path)
Remove a resource from the queue, discarding any loading done.
::
func is_ready(path)
Returns true if a resource is done loading and ready to be retrieved.
::
func get_progress(path)
Get the progress of a resource. Returns -1 on error (for example if the
resource is not on the queue), or a number between 0.0 and 1.0 with the
progress of the load. Use mostly for cosmetic purposes (updating
progress bars, etc), use ``is_ready`` to find out if a resource is
actually ready.
::
func get_resource(path)
Returns the fully loaded resource, or null on error. If the resource is
not done loading (``is_ready`` returns false), it will block your thread
and finish the load. If the resource is not on the queue, it will call
``ResourceLoader::load`` to load it normally and return it.
Example:
~~~~~~~~
::
# initialize
queue = preload("res://resource_queue.gd").new()
queue.start()
# suppose your game starts with a 10 second cutscene, during which the user can't interact with the game.
# For that time we know they won't use the pause menu, so we can queue it to load during the cutscene:
queue.queue_resource("res://pause_menu.tres")
start_curscene()
# later when the user presses the pause button for the first time:
pause_menu = queue.get_resource("res://pause_menu.tres").instance()
pause_menu.show()
# when you need a new scene:
queue.queue_resource("res://level_1.tscn", true) # use "true" as the second parameter to put it at the front
# of the queue, pausing the load of any other resource
# to check progress
if queue.is_ready("res://level_1.tscn"):
show_new_level(queue.get_resource("res://level_1.tscn"))
else:
update_progress(queue.get_process("res://level_1.tscn"))
# when the user walks away from the trigger zone in your Metroidvania game:
queue.cancel_resource("res://zone_2.tscn")
**Note**: this code in its current form is not tested in real world
scenarios. Ask punto on IRC (#godotengine on irc.freenode.net) for help.

View File

@@ -1,40 +0,0 @@
.. _doc_data_paths:
Data paths
==========
Path separators
---------------
For the sake of supporting as many platforms as possible, Godot only
accepts unix style path separators (``/``). These work everywhere,
including Windows.
A path like: ``C:\Projects`` will become ``C:/Projects``.
Resource path
-------------
As mentioned before. Godot considers that a project exists at any
given folder that contains an "project.godot" text file, even if such
file is empty.
Accessing project files can be done by opening any path with ``res://``
as a base. For example, a texture located in the root of the project
folder may be opened from the following path: ``res://sometexture.png``.
Userdata path (persistent data)
-------------------------------
While the project is running, it is a very common scenario that the
resource path will be read-only, due to it being inside a package,
self contained executable, or system wide install location.
Storing persistent files in such scenarios should be done by using the
``user://`` prefix, for example: ``user://gamesave.txt``.
In some devices (for example, mobile ad consoles) this path is unique
for the app. Under desktop operating systems, the engine uses the
typical ``~/.local/share/godot/app_userdata/Name`` (check the project
name under the settings) in macOS and Linux, and ``APPDATA/Name``
for Windows.

View File

@@ -1,59 +0,0 @@
.. _doc_encrypting_save_games:
Encrypting save games
=====================
Why?
----
Because the world today is not the world of yesterday. A capitalist
oligarchy runs the world and forces us to consume in order to keep the
gears of this rotten society on track. As such, the biggest market for
video game consumption today is the mobile one. It is a market of poor
souls forced to compulsively consume digital content in order to forget
the misery of their every day life, commute, or just any other brief
free moment they have that they are not using to produce goods or
services for the ruling class. These individuals need to keep focusing
on their video games (because not doing so will produce them a
tremendous existential angst), so they go as far as spending money on
them to extend their experience, and their preferred way of doing so is
through in-app purchases and virtual currency.
But, imagine if someone was to find a way to edit the saved games and
assign the items and currency without effort? This would be terrible,
because it would help players consume the content much faster, and as
such run out of it sooner than expected. If this happens they will have
nothing that avoids them to think, and the tremendous agony of realizing
their own irrelevance would again take over their life.
No, we definitely do not want this to happen, so let's see how to
encrypt savegames and protect the world order.
How?
----
The class :ref:`File <class_File>` is simple to use, just open a
location and read/write data (integers, strings and variants). To create
an encrypted file, a passphrase must be provided, like this:
::
var f = File.new()
var err = f.open_encrypted_with_pass("user://savedata.bin", File.WRITE, "mypass")
f.store_var(game_state)
f.close()
This will make the file unreadable to users, but will still not avoid
them to share savefiles. To solve this, using the device unique id or
some unique user identifier is needed, for example:
::
var f = File.new()
var err = f.open_encrypted_with_pass("user://savedata.bin", File.WRITE, OS.get_unique_ID())
f.store_var(game_state)
f.close()
Note that ``OS.get_unique_ID()`` only works on iOS and Android.
This is all! Thanks for your cooperation, citizen.

View File

@@ -1,145 +0,0 @@
var thread
var mutex
var sem
var time_max = 100 # msec
var queue = []
var pending = {}
func _lock(caller):
mutex.lock()
func _unlock(caller):
mutex.unlock()
func _post(caller):
sem.post()
func _wait(caller):
sem.wait()
func queue_resource(path, p_in_front = false):
_lock("queue_resource")
if path in pending:
_unlock("queue_resource")
return
elif ResourceLoader.has(path):
var res = ResourceLoader.load(path)
pending[path] = res
_unlock("queue_resource")
return
else:
var res = ResourceLoader.load_interactive(path)
res.set_meta("path", path)
if p_in_front:
queue.insert(0, res)
else:
queue.push_back(res)
pending[path] = res
_post("queue_resource")
_unlock("queue_resource")
return
func cancel_resource(path):
_lock("cancel_resource")
if path in pending:
if pending[path] is ResourceInteractiveLoader:
queue.erase(pending[path])
pending.erase(path)
_unlock("cancel_resource")
func get_progress(path):
_lock("get_progress")
var ret = -1
if path in pending:
if pending[path] is ResourceInteractiveLoader:
ret = float(pending[path].get_stage()) / float(pending[path].get_stage_count())
else:
ret = 1.0
_unlock("get_progress")
return ret
func is_ready(path):
var ret
_lock("is_ready")
if path in pending:
ret = !(pending[path] is ResourceInteractiveLoader)
else:
ret = false
_unlock("is_ready")
return ret
func _wait_for_resource(res, path):
_unlock("wait_for_resource")
while true:
VS.flush()
OS.delay_usec(16000) # wait 1 frame
_lock("wait_for_resource")
if queue.size() == 0 || queue[0] != res:
return pending[path]
_unlock("wait_for_resource")
func get_resource(path):
_lock("get_resource")
if path in pending:
if pending[path] is ResourceInteractiveLoader:
var res = pending[path]
if res != queue[0]:
var pos = queue.find(res)
queue.remove(pos)
queue.insert(0, res)
res = _wait_for_resource(res, path)
pending.erase(path)
_unlock("return")
return res
else:
var res = pending[path]
pending.erase(path)
_unlock("return")
return res
else:
_unlock("return")
return ResourceLoader.load(path)
func thread_process():
_wait("thread_process")
_lock("process")
while queue.size() > 0:
var res = queue[0]
_unlock("process_poll")
var ret = res.poll()
_lock("process_check_queue")
if ret == ERR_FILE_EOF || ret != OK:
var path = res.get_meta("path")
if path in pending: # else it was already retrieved
pending[res.get_meta("path")] = res.get_resource()
queue.erase(res) # something might have been put at the front of the queue while we polled, so use erase instead of remove
_unlock("process")
func thread_func(u):
while true:
thread_process()
func start():
mutex = Mutex.new()
sem = Semaphore.new()
thread = Thread.new()
thread.start(self, "thread_func", 0)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -5,12 +5,6 @@ Miscellaneous
:maxdepth: 1
:name: toc-learn-features-misc
background_loading
data_paths
saving_games
encrypting_save_games
handling_quit_requests
pausing_games
internationalizing_games
locales
binary_serialization_api

View File

@@ -1,107 +0,0 @@
.. _doc_internationalizing_games:
Internationalizing games
========================
Introduction
------------
Sería excelente que el mundo hablara solo un idioma. Unfortunately for
us developers, that is not the case. While not generally a big
requirement when developing indie or niche games, it is also very common
that games going into a more massive market require localization.
Godot offers many tools to make this process more straightforward, so
this tutorial is more like a collection of tips and tricks.
Localization is usually done by specific studios hired for the job and,
despite the huge amount of software and file formats available for this,
the most common way to do localization to this day is still with
spreadsheets. The process of creating the spreadsheets and importing
them is already covered in the :ref:`doc_importing_translations` tutorial, so this
one could be seen more like a follow up to that one.
Configuring the imported translation
------------------------------------
The translations can get updated and re-imported when they change, but
they still have to be added to the project. This is done in Scene
> Project Settings > Localization:
.. image:: img/localization_dialog.png
This dialog allows to add or remove translations project-wide.
Localizing resources
--------------------
It is also possible to instruct Godot to open alternative versions of
assets (resources) depending on the current language. For this the
"Remaps" tab exists:
.. image:: img/localization_remaps.png
Select the resource to be remapped, and the alternatives for each
locale.
Converting keys to text
-----------------------
Some controls such as :ref:`Button <class_Button>`, :ref:`Label <class_Label>`,
etc. will automatically fetch a translation each time they are set a key
instead of a text. For example, if a label is assigned
"MAIN_SCREEN_GREETING1" and a key to different languages exists in the
translations, this will be automatically converted. This process is done
upon load though, so if the project in question has a dialog that allows
changing the language in the settings, the scenes (or at least the
settings scene) will have to be re-loaded for new text to have effect.
For code, the :ref:`Object.tr() <class_Object_tr>`
function can be used. This will just look-up the text into the
translations and convert it if found:
::
level.set_text(tr("LEVEL_5_NAME"))
status.set_text(tr("GAME_STATUS_" + str(status_index)))
Making controls resizable
--------------------------
The same text in different languages can vary greatly in length. For
this, make sure to read the tutorial on :ref:`doc_size_and_anchors`, as having
dynamically adjusted control sizes may help.
:ref:`Container <class_Container>` can be very useful, as well as the multiple options in
:ref:`Label <class_Label>` for text wrapping.
TranslationServer
-----------------
Godot has a server for handling the low level translation management
called the :ref:`TranslationServer <class_TranslationServer>`.
Translations can be added or removed during run-time, and the current
language be changed too.
Command line
------------
Language can be tested when running Godot from command line. For
example, to test a game in french, the following arguments can be
supplied:
::
c:\MyGame> godot -l fr
Translating the project name
----------------------------
The project name becomes the app name when exporting to different
operating systems and platforms. To specify the project name in more
than one language, create a new setting application/name in the project
settings dialog and append the locale identifier to it. For example:
.. image:: img/localized_name.png
As always, If you don't know the code of a language or zone, :ref:`check the
list <doc_locales>`.

View File

@@ -1,729 +0,0 @@
.. _doc_locales:
Locales
=======
This is the list of supported locales and variants in the engine. It's
based on the Unix standard locale strings:
+--------------+------------------------------------+
| Locale | Language and Variant |
+==============+====================================+
| aa | Afar |
+--------------+------------------------------------+
| aa_DJ | Afar (Djibouti) |
+--------------+------------------------------------+
| aa_ER | Afar (Eritrea) |
+--------------+------------------------------------+
| aa_ET | Afar (Ethiopia) |
+--------------+------------------------------------+
| af | Afrikaans |
+--------------+------------------------------------+
| af_ZA | Afrikaans (South Africa) |
+--------------+------------------------------------+
| agr_PE | Aguaruna (Peru) |
+--------------+------------------------------------+
| ak_GH | Akan (Ghana) |
+--------------+------------------------------------+
| am_ET | Amharic (Ethiopia) |
+--------------+------------------------------------+
| an_ES | Aragonese (Spain) |
+--------------+------------------------------------+
| anp_IN | Angika (India) |
+--------------+------------------------------------+
| ar | Arabic |
+--------------+------------------------------------+
| ar_AE | Arabic (United Arab Emirates) |
+--------------+------------------------------------+
| ar_BH | Arabic (Bahrain) |
+--------------+------------------------------------+
| ar_DZ | Arabic (Algeria) |
+--------------+------------------------------------+
| ar_EG | Arabic (Egypt) |
+--------------+------------------------------------+
| ar_IQ | Arabic (Iraq) |
+--------------+------------------------------------+
| ar_JO | Arabic (Jordan) |
+--------------+------------------------------------+
| ar_KW | Arabic (Kuwait) |
+--------------+------------------------------------+
| ar_LB | Arabic (Lebanon) |
+--------------+------------------------------------+
| ar_LY | Arabic (Libya) |
+--------------+------------------------------------+
| ar_MA | Arabic (Morocco) |
+--------------+------------------------------------+
| ar_OM | Arabic (Oman) |
+--------------+------------------------------------+
| ar_QA | Arabic (Qatar) |
+--------------+------------------------------------+
| ar_SA | Arabic (Saudi Arabia) |
+--------------+------------------------------------+
| ar_SD | Arabic (Sudan) |
+--------------+------------------------------------+
| ar_SY | Arabic (Syria) |
+--------------+------------------------------------+
| ar_TN | Arabic (Tunisia) |
+--------------+------------------------------------+
| ar_YE | Arabic (Yemen) |
+--------------+------------------------------------+
| as_IN | Assamese (India) |
+--------------+------------------------------------+
| ast_ES | Asturian (Spain) |
+--------------+------------------------------------+
| ayc_PE | Southern Aymara (Peru) |
+--------------+------------------------------------+
| ay_PE | Aymara (Peru) |
+--------------+------------------------------------+
| az_AZ | Azerbaijani (Azerbaijan) |
+--------------+------------------------------------+
| be | Belarusian |
+--------------+------------------------------------+
| be_BY | Belarusian (Belarus) |
+--------------+------------------------------------+
| bem_ZM | Bemba (Zambia) |
+--------------+------------------------------------+
| ber_DZ | Berber languages (Algeria) |
+--------------+------------------------------------+
| ber_MA | Berber languages (Morocco) |
+--------------+------------------------------------+
| bg | Bulgarian |
+--------------+------------------------------------+
| bg_BG | Bulgarian (Bulgaria) |
+--------------+------------------------------------+
| bhb_IN | Bhili (India) |
+--------------+------------------------------------+
| bho_IN | Bhojpuri (India) |
+--------------+------------------------------------+
| bi_TV | Bislama (Tuvalu) |
+--------------+------------------------------------+
| bn | Bengali |
+--------------+------------------------------------+
| bn_BD | Bengali (Bangladesh) |
+--------------+------------------------------------+
| bn_IN | Bengali (India) |
+--------------+------------------------------------+
| bo | Tibetan |
+--------------+------------------------------------+
| bo_CN | Tibetan (China) |
+--------------+------------------------------------+
| bo_IN | Tibetan (India) |
+--------------+------------------------------------+
| br_FR | Breton (France) |
+--------------+------------------------------------+
| brx_IN | Bodo (India) |
+--------------+------------------------------------+
| bs_BA | Bosnian (Bosnia and Herzegovina) |
+--------------+------------------------------------+
| byn_ER | Bilin (Eritrea) |
+--------------+------------------------------------+
| ca | Catalan |
+--------------+------------------------------------+
| ca_AD | Catalan (Andorra) |
+--------------+------------------------------------+
| ca_ES | Catalan (Spain) |
+--------------+------------------------------------+
| ca_FR | Catalan (France) |
+--------------+------------------------------------+
| ca_IT | Catalan (Italy) |
+--------------+------------------------------------+
| ce_RU | Chechen (Russia) |
+--------------+------------------------------------+
| chr_US | Cherokee (United States) |
+--------------+------------------------------------+
| cmn_TW | Mandarin Chinese (Taiwan) |
+--------------+------------------------------------+
| crh_UA | Crimean Tatar (Ukraine) |
+--------------+------------------------------------+
| csb_PL | Kashubian (Poland) |
+--------------+------------------------------------+
| cs | Czech |
+--------------+------------------------------------+
| cs_CZ | Czech (Czech Republic) |
+--------------+------------------------------------+
| cv_RU | Chuvash (Russia) |
+--------------+------------------------------------+
| cy_GB | Welsh (United Kingdom) |
+--------------+------------------------------------+
| da | Danish |
+--------------+------------------------------------+
| da_DK | Danish (Denmark) |
+--------------+------------------------------------+
| de | German |
+--------------+------------------------------------+
| de_AT | German (Austria) |
+--------------+------------------------------------+
| de_BE | German (Belgium) |
+--------------+------------------------------------+
| de_CH | German (Switzerland) |
+--------------+------------------------------------+
| de_DE | German (Germany) |
+--------------+------------------------------------+
| de_IT | German (Italy) |
+--------------+------------------------------------+
| de_LU | German (Luxembourg) |
+--------------+------------------------------------+
| doi_IN | Dogri (India) |
+--------------+------------------------------------+
| dv_MV | Dhivehi (Maldives) |
+--------------+------------------------------------+
| dz_BT | Dzongkha (Bhutan) |
+--------------+------------------------------------+
| el | Greek |
+--------------+------------------------------------+
| el_CY | Greek (Cyprus) |
+--------------+------------------------------------+
| el_GR | Greek (Greece) |
+--------------+------------------------------------+
| en | English |
+--------------+------------------------------------+
| en_AG | English (Antigua and Barbuda) |
+--------------+------------------------------------+
| en_AU | English (Australia) |
+--------------+------------------------------------+
| en_BW | English (Botswana) |
+--------------+------------------------------------+
| en_CA | English (Canada) |
+--------------+------------------------------------+
| en_DK | English (Denmark) |
+--------------+------------------------------------+
| en_GB | English (United Kingdom) |
+--------------+------------------------------------+
| en_HK | English (Hong Kong) |
+--------------+------------------------------------+
| en_IE | English (Ireland) |
+--------------+------------------------------------+
| en_IL | English (Israel) |
+--------------+------------------------------------+
| en_IN | English (India) |
+--------------+------------------------------------+
| en_NG | English (Nigeria) |
+--------------+------------------------------------+
| en_MT | English (Malta) |
+--------------+------------------------------------+
| en_NZ | English (New Zealand) |
+--------------+------------------------------------+
| en_PH | English (Philippines) |
+--------------+------------------------------------+
| en_SG | English (Singapore) |
+--------------+------------------------------------+
| en_US | English (United States) |
+--------------+------------------------------------+
| en_ZA | English (South Africa) |
+--------------+------------------------------------+
| en_ZM | English (Zambia) |
+--------------+------------------------------------+
| en_ZW | English (Zimbabwe) |
+--------------+------------------------------------+
| eo | Esperanto |
+--------------+------------------------------------+
| es | Spanish |
+--------------+------------------------------------+
| es_AR | Spanish (Argentina) |
+--------------+------------------------------------+
| es_BO | Spanish (Bolivia) |
+--------------+------------------------------------+
| es_CL | Spanish (Chile) |
+--------------+------------------------------------+
| es_CO | Spanish (Colombia) |
+--------------+------------------------------------+
| es_CR | Spanish (Costa Rica) |
+--------------+------------------------------------+
| en_CU | Spanish (Cuba) |
+--------------+------------------------------------+
| es_DO | Spanish (Dominican Republic) |
+--------------+------------------------------------+
| es_EC | Spanish (Ecuador) |
+--------------+------------------------------------+
| es_ES | Spanish (Spain) |
+--------------+------------------------------------+
| es_GT | Spanish (Guatemala) |
+--------------+------------------------------------+
| es_HN | Spanish (Honduras) |
+--------------+------------------------------------+
| es_MX | Spanish (Mexico) |
+--------------+------------------------------------+
| es_NI | Spanish (Nicaragua) |
+--------------+------------------------------------+
| es_PA | Spanish (Panama) |
+--------------+------------------------------------+
| es_PE | Spanish (Peru) |
+--------------+------------------------------------+
| es_PR | Spanish (Puerto Rico) |
+--------------+------------------------------------+
| es_PY | Spanish (Paraguay) |
+--------------+------------------------------------+
| es_SV | Spanish (El Salvador) |
+--------------+------------------------------------+
| es_US | Spanish (United States) |
+--------------+------------------------------------+
| es_UY | Spanish (Uruguay) |
+--------------+------------------------------------+
| es_VE | Spanish (Venezuela) |
+--------------+------------------------------------+
| et | Estonian |
+--------------+------------------------------------+
| et_EE | Estonian (Estonia) |
+--------------+------------------------------------+
| eu | Basque |
+--------------+------------------------------------+
| eu_ES | Basque (Spain) |
+--------------+------------------------------------+
| fa | Persian |
+--------------+------------------------------------+
| fa_IR | Persian (Iran) |
+--------------+------------------------------------+
| ff_SN | Fulah (Senegal) |
+--------------+------------------------------------+
| fi | Finnish |
+--------------+------------------------------------+
| fi_FI | Finnish (Finland) |
+--------------+------------------------------------+
| fil_PH | Filipino (Philippines) |
+--------------+------------------------------------+
| fo_FO | Faroese (Faroe Islands) |
+--------------+------------------------------------+
| fr | French |
+--------------+------------------------------------+
| fr_BE | French (Belgium) |
+--------------+------------------------------------+
| fr_CA | French (Canada) |
+--------------+------------------------------------+
| fr_CH | French (Switzerland) |
+--------------+------------------------------------+
| fr_FR | French (France) |
+--------------+------------------------------------+
| fr_LU | French (Luxembourg) |
+--------------+------------------------------------+
| fur_IT | Friulian (Italy) |
+--------------+------------------------------------+
| fy_DE | Western Frisian (Germany) |
+--------------+------------------------------------+
| fy_NL | Western Frisian (Netherlands) |
+--------------+------------------------------------+
| ga | Irish |
+--------------+------------------------------------+
| ga_IE | Irish (Ireland) |
+--------------+------------------------------------+
| gd_GB | Scottish Gaelic (United Kingdom) |
+--------------+------------------------------------+
| gez_ER | Geez (Eritrea) |
+--------------+------------------------------------+
| gez_ET | Geez (Ethiopia) |
+--------------+------------------------------------+
| gl_ES | Galician (Spain) |
+--------------+------------------------------------+
| gu_IN | Gujarati (India) |
+--------------+------------------------------------+
| gv_GB | Manx (United Kingdom) |
+--------------+------------------------------------+
| hak_TW | Hakka Chinese (Taiwan) |
+--------------+------------------------------------+
| ha_NG | Hausa (Nigeria) |
+--------------+------------------------------------+
| he | Hebrew |
+--------------+------------------------------------+
| he_IL | Hebrew (Israel) |
+--------------+------------------------------------+
| hi | Hindi |
+--------------+------------------------------------+
| hi_IN | Hindi (India) |
+--------------+------------------------------------+
| hne_IN | Chhattisgarhi (India) |
+--------------+------------------------------------+
| hr | Croatian |
+--------------+------------------------------------+
| hr_HR | Croatian (Croatia) |
+--------------+------------------------------------+
| hsb_DE | Upper Sorbian (Germany) |
+--------------+------------------------------------+
| ht_HT | Haitian (Haiti) |
+--------------+------------------------------------+
| hu | Hungarian |
+--------------+------------------------------------+
| hu_HU | Hungarian (Hungary) |
+--------------+------------------------------------+
| hus_MX | Huastec (Mexico) |
+--------------+------------------------------------+
| hy_AM | Armenian (Armenia) |
+--------------+------------------------------------+
| ia_FR | Interlingua (France) |
+--------------+------------------------------------+
| id | Indonesian |
+--------------+------------------------------------+
| id_ID | Indonesian (Indonesia) |
+--------------+------------------------------------+
| ig_NG | Igbo (Nigeria) |
+--------------+------------------------------------+
| ik_CA | Inupiaq (Canada) |
+--------------+------------------------------------+
| is | Icelandic |
+--------------+------------------------------------+
| is_IS | Icelandic (Iceland) |
+--------------+------------------------------------+
| it | Italian |
+--------------+------------------------------------+
| it_CH | Italian (Switzerland) |
+--------------+------------------------------------+
| it_IT | Italian (Italy) |
+--------------+------------------------------------+
| iu_CA | Inuktitut (Canada) |
+--------------+------------------------------------+
| ja | Japanese |
+--------------+------------------------------------+
| ja_JP | Japanese (Japan) |
+--------------+------------------------------------+
| kab_DZ | Kabyle (Algeria) |
+--------------+------------------------------------+
| ka_GE | Georgian (Georgia) |
+--------------+------------------------------------+
| kk_KZ | Kazakh (Kazakhstan) |
+--------------+------------------------------------+
| kl_GL | Kalaallisut (Greenland) |
+--------------+------------------------------------+
| km_KH | Central Khmer (Cambodia) |
+--------------+------------------------------------+
| kn_IN | Kannada (India) |
+--------------+------------------------------------+
| kok_IN | Konkani (India) |
+--------------+------------------------------------+
| ko | Korean |
+--------------+------------------------------------+
| ko_KR | Korean (South Korea) |
+--------------+------------------------------------+
| ks_IN | Kashmiri (India) |
+--------------+------------------------------------+
| ku | Kurdish |
+--------------+------------------------------------+
| ku_TR | Kurdish (Turkey) |
+--------------+------------------------------------+
| kw_GB | Cornish (United Kingdom) |
+--------------+------------------------------------+
| ky_KG | Kirghiz (Kyrgyzstan) |
+--------------+------------------------------------+
| lb_LU | Luxembourgish (Luxembourg) |
+--------------+------------------------------------+
| lg_UG | Ganda (Uganda) |
+--------------+------------------------------------+
| li_BE | Limburgan (Belgium) |
+--------------+------------------------------------+
| li_NL | Limburgan (Netherlands) |
+--------------+------------------------------------+
| lij_IT | Ligurian (Italy) |
+--------------+------------------------------------+
| ln_CD | Lingala (Congo) |
+--------------+------------------------------------+
| lo_LA | Lao (Laos) |
+--------------+------------------------------------+
| lt | Lithuanian |
+--------------+------------------------------------+
| lt_LT | Lithuanian (Lithuania) |
+--------------+------------------------------------+
| lv | Latvian |
+--------------+------------------------------------+
| lv_LV | Latvian (Latvia) |
+--------------+------------------------------------+
| lzh_TW | Literary Chinese (Taiwan) |
+--------------+------------------------------------+
| mag_IN | Magahi (India) |
+--------------+------------------------------------+
| mai_IN | Maithili (India) |
+--------------+------------------------------------+
| mg_MG | Malagasy (Madagascar) |
+--------------+------------------------------------+
| mh_MH | Marshallese (Marshall Islands) |
+--------------+------------------------------------+
| mhr_RU | Eastern Mari (Russia) |
+--------------+------------------------------------+
| mi_NZ | Maori (New Zealand) |
+--------------+------------------------------------+
| miq_NI | Mískito (Nicaragua) |
+--------------+------------------------------------+
| mk | Macedonian |
+--------------+------------------------------------+
| mk_MK | Macedonian (Macedonia) |
+--------------+------------------------------------+
| ml_IN | Malayalam (India) |
+--------------+------------------------------------+
| mni_IN | Manipuri (India) |
+--------------+------------------------------------+
| mn_MN | Mongolian (Mongolia) |
+--------------+------------------------------------+
| mr_IN | Marathi (India) |
+--------------+------------------------------------+
| ms | Malay |
+--------------+------------------------------------+
| ms_MY | Malay (Malaysia) |
+--------------+------------------------------------+
| mt | Maltese |
+--------------+------------------------------------+
| mt_MT | Maltese (Malta) |
+--------------+------------------------------------+
| my_MM | Burmese (Myanmar) |
+--------------+------------------------------------+
| myv_RU | Erzya (Russia) |
+--------------+------------------------------------+
| nah_MX | Nahuatl languages (Mexico) |
+--------------+------------------------------------+
| nan_TW | Min Nan Chinese (Taiwan) |
+--------------+------------------------------------+
| nb | Norwegian Bokmål |
+--------------+------------------------------------+
| nb_NO | Norwegian Bokmål (Norway) |
+--------------+------------------------------------+
| nds_DE | Low German (Germany) |
+--------------+------------------------------------+
| nds_NL | Low German (Netherlands) |
+--------------+------------------------------------+
| ne_NP | Nepali (Nepal) |
+--------------+------------------------------------+
| nhn_MX | Central Nahuatl (Mexico) |
+--------------+------------------------------------+
| niu_NU | Niuean (Niue) |
+--------------+------------------------------------+
| niu_NZ | Niuean (New Zealand) |
+--------------+------------------------------------+
| nl | Dutch |
+--------------+------------------------------------+
| nl_AW | Dutch (Aruba) |
+--------------+------------------------------------+
| nl_BE | Dutch (Belgium) |
+--------------+------------------------------------+
| nl_NL | Dutch (Netherlands) |
+--------------+------------------------------------+
| nn | Norwegian Nynorsk |
+--------------+------------------------------------+
| nn_NO | Norwegian Nynorsk (Norway) |
+--------------+------------------------------------+
| no | Norwegian |
+--------------+------------------------------------+
| no_NO | Norwegian (Norway) |
+--------------+------------------------------------+
| nr_ZA | South Ndebele (South Africa) |
+--------------+------------------------------------+
| nso_ZA | Pedi (South Africa) |
+--------------+------------------------------------+
| oc_FR | Occitan (France) |
+--------------+------------------------------------+
| om | Oromo |
+--------------+------------------------------------+
| om_ET | Oromo (Ethiopia) |
+--------------+------------------------------------+
| om_KE | Oromo (Kenya) |
+--------------+------------------------------------+
| or_IN | Oriya (India) |
+--------------+------------------------------------+
| os_RU | Ossetian (Russia) |
+--------------+------------------------------------+
| pa_IN | Panjabi (India) |
+--------------+------------------------------------+
| pap | Papiamento |
+--------------+------------------------------------+
| pap_AN | Papiamento (Netherlands Antilles) |
+--------------+------------------------------------+
| pap_AW | Papiamento (Aruba) |
+--------------+------------------------------------+
| pap_CW | Papiamento (Curaçao) |
+--------------+------------------------------------+
| pa_PK | Panjabi (Pakistan) |
+--------------+------------------------------------+
| pl | Polish |
+--------------+------------------------------------+
| pl_PL | Polish (Poland) |
+--------------+------------------------------------+
| pr | Pirate |
+--------------+------------------------------------+
| ps_AF | Pushto (Afghanistan) |
+--------------+------------------------------------+
| pt | Portuguese |
+--------------+------------------------------------+
| pt_BR | Portuguese (Brazil) |
+--------------+------------------------------------+
| pt_PT | Portuguese (Portugal) |
+--------------+------------------------------------+
| quy_PE | Ayacucho Quechua (Peru) |
+--------------+------------------------------------+
| quz_PE | Cusco Quechua (Peru) |
+--------------+------------------------------------+
| raj_IN | Rajasthani (India) |
+--------------+------------------------------------+
| ro | Romanian |
+--------------+------------------------------------+
| ro_RO | Romanian (Romania) |
+--------------+------------------------------------+
| ru | Russian |
+--------------+------------------------------------+
| ru_RU | Russian (Russia) |
+--------------+------------------------------------+
| ru_UA | Russian (Ukraine) |
+--------------+------------------------------------+
| rw_RW | Kinyarwanda (Rwanda) |
+--------------+------------------------------------+
| sa_IN | Sanskrit (India) |
+--------------+------------------------------------+
| sat_IN | Santali (India) |
+--------------+------------------------------------+
| sc_IT | Sardinian (Italy) |
+--------------+------------------------------------+
| sco | Scots |
+--------------+------------------------------------+
| sd_IN | Sindhi (India) |
+--------------+------------------------------------+
| se_NO | Northern Sami (Norway) |
+--------------+------------------------------------+
| sgs_LT | Samogitian (Lithuania) |
+--------------+------------------------------------+
| shs_CA | Shuswap (Canada) |
+--------------+------------------------------------+
| sid_ET | Sidamo (Ethiopia) |
+--------------+------------------------------------+
| si_LK | Sinhala (Sri Lanka) |
+--------------+------------------------------------+
| sk | Slovak |
+--------------+------------------------------------+
| sk_SK | Slovak (Slovakia) |
+--------------+------------------------------------+
| sl | Slovenian |
+--------------+------------------------------------+
| so | Somali |
+--------------+------------------------------------+
| so_DJ | Somali (Djibouti) |
+--------------+------------------------------------+
| so_ET | Somali (Ethiopia) |
+--------------+------------------------------------+
| so_KE | Somali (Kenya) |
+--------------+------------------------------------+
| so_SO | Somali (Somalia) |
+--------------+------------------------------------+
| son_ML | Songhai languages (Mali) |
+--------------+------------------------------------+
| sq | Albanian |
+--------------+------------------------------------+
| sq_AL | Albanian (Albania) |
+--------------+------------------------------------+
| sq_KV | Albanian (Kosovo) |
+--------------+------------------------------------+
| sq_MK | Albanian (Macedonia) |
+--------------+------------------------------------+
| sr | Serbian |
+--------------+------------------------------------+
| sr_BA | Serbian (Bosnia and Herzegovina) |
+--------------+------------------------------------+
| sr_CS | Serbian (Serbia and Montenegro) |
+--------------+------------------------------------+
| sr_ME | Serbian (Montenegro) |
+--------------+------------------------------------+
| sr_RS | Serbian (Serbia) |
+--------------+------------------------------------+
| ss_ZA | Swati (South Africa) |
+--------------+------------------------------------+
| st_ZA | Southern Sotho (South Africa) |
+--------------+------------------------------------+
| sv | Swedish |
+--------------+------------------------------------+
| sv_FI | Swedish (Finland) |
+--------------+------------------------------------+
| sv_SE | Swedish (Sweden) |
+--------------+------------------------------------+
| sw_KE | Swahili (Kenya) |
+--------------+------------------------------------+
| sw_TZ | Swahili (Tanzania) |
+--------------+------------------------------------+
| szl_PL | Silesian (Poland) |
+--------------+------------------------------------+
| ta | Tamil |
+--------------+------------------------------------+
| ta_IN | Tamil (India) |
+--------------+------------------------------------+
| ta_LK | Tamil (Sri Lanka) |
+--------------+------------------------------------+
| tcy_IN | Tulu (India) |
+--------------+------------------------------------+
| te_IN | Telugu (India) |
+--------------+------------------------------------+
| tg_TJ | Tajik (Tajikistan) |
+--------------+------------------------------------+
| the_NP | Chitwania Tharu (Nepal) |
+--------------+------------------------------------+
| th | Thai |
+--------------+------------------------------------+
| th_TH | Thai (Thailand) |
+--------------+------------------------------------+
| th_TH_TH | Thai (Thailand,TH) |
+--------------+------------------------------------+
| ti | Tigrinya |
+--------------+------------------------------------+
| ti_ER | Tigrinya (Eritrea) |
+--------------+------------------------------------+
| ti_ET | Tigrinya (Ethiopia) |
+--------------+------------------------------------+
| tig_ER | Tigre (Eritrea) |
+--------------+------------------------------------+
| tk_TM | Turkmen (Turkmenistan) |
+--------------+------------------------------------+
| tl_PH | Tagalog (Philippines) |
+--------------+------------------------------------+
| tn_ZA | Tswana (South Africa) |
+--------------+------------------------------------+
| tr | Turkish |
+--------------+------------------------------------+
| tr_CY | Turkish (Cyprus) |
+--------------+------------------------------------+
| tr_TR | Turkish (Turkey) |
+--------------+------------------------------------+
| ts_ZA | Tsonga (South Africa) |
+--------------+------------------------------------+
| tt_RU | Tatar (Russia) |
+--------------+------------------------------------+
| ug_CN | Uighur (China) |
+--------------+------------------------------------+
| uk | Ukrainian |
+--------------+------------------------------------+
| uk_UA | Ukrainian (Ukraine) |
+--------------+------------------------------------+
| unm_US | Unami (United States) |
+--------------+------------------------------------+
| ur | Urdu |
+--------------+------------------------------------+
| ur_IN | Urdu (India) |
+--------------+------------------------------------+
| ur_PK | Urdu (Pakistan) |
+--------------+------------------------------------+
| uz | Uzbek |
+--------------+------------------------------------+
| uz_UZ | Uzbek (Uzbekistan) |
+--------------+------------------------------------+
| ve_ZA | Venda (South Africa) |
+--------------+------------------------------------+
| vi | Vietnamese |
+--------------+------------------------------------+
| vi_VN | Vietnamese (Vietnam) |
+--------------+------------------------------------+
| wa_BE | Walloon (Belgium) |
+--------------+------------------------------------+
| wae_CH | Walser (Switzerland) |
+--------------+------------------------------------+
| wal_ET | Wolaytta (Ethiopia) |
+--------------+------------------------------------+
| wo_SN | Wolof (Senegal) |
+--------------+------------------------------------+
| xh_ZA | Xhosa (South Africa) |
+--------------+------------------------------------+
| yi_US | Yiddish (United States) |
+--------------+------------------------------------+
| yo_NG | Yoruba (Nigeria) |
+--------------+------------------------------------+
| yue_HK | Yue Chinese (Hong Kong) |
+--------------+------------------------------------+
| zh | Chinese |
+--------------+------------------------------------+
| zh_CN | Chinese (China) |
+--------------+------------------------------------+
| zh_HK | Chinese (Hong Kong) |
+--------------+------------------------------------+
| zh_SG | Chinese (Singapore) |
+--------------+------------------------------------+
| zh_TW | Chinese (Taiwan) |
+--------------+------------------------------------+
| zu_ZA | Zulu (South Africa) |
+--------------+------------------------------------+

View File

@@ -1,154 +0,0 @@
.. _doc_saving_games:
Saving games
============
Introduction
------------
Save games can be complicated. It can be desired to store more
information than the current level or number of stars earned on a level.
More advanced save games may need to store additional information about
an arbitrary number of objects. This will allow the save function to
scale as the game grows more complex.
Identify persistent objects
---------------------------
First we should identify what objects we want to keep between game
sessions and what information we want to keep from those objects. For
this tutorial, we will use groups to mark and handle objects to be saved
but other methods are certainly possible.
We will start by adding objects we wish to save to the "Persist" group.
As in the :ref:`doc_scripting_continued` tutorial, we can do this through
the GUI or through script. Let's add the relevant nodes using the GUI:
.. image:: img/groups.png
Once this is done when we need to save the game we can get all objects
to save them and then tell them all to save with this script:
::
var save_nodes = get_tree().get_nodes_in_group("Persist")
for i in save_nodes:
# Now we can call our save function on each node.
Serializing
-----------
The next step is to serialize the data. This makes it much easier to
read and store to disk. In this case, we're assuming each member of
group Persist is an instanced node and thus has a path. GDScript
has helper functions for this, such as :ref:`to_json()
<class_@GDScript_to_json>` and :ref:`parse_json()
<class_@GDScript_parse_json>`, so we will use a dictionary. Our node needs to
contain a save function that returns this data. The save function will look
like this:
::
func save():
var save_dict = {
"filename" : get_filename(),
"parent" : get_parent().get_path(),
"pos_x" : position.x, # Vector2 is not supported by JSON
"pos_y" : position.y,
"attack" : attack,
"defense" : defense,
"current_health" : current_health,
"max_health" : max_health,
"damage" : damage,
"regen" : regen,
"experience" : experience,
"tnl" : tnl,
"level" : level,
"attack_growth" : attack_growth,
"defense_growth" : defense_growth,
"health_growth" : health_growth,
"is_alive" : is_alive,
"last_attack" : last_attack
}
return save_dict
This gives us a dictionary with the style
``{ "variable_name":that_variables_value }`` which will be useful when
loading.
Saving and reading data
-----------------------
As covered in the :ref:`doc_filesystem` tutorial, we'll need to open a file
and write to it and then later read from it. Now that we have a way to
call our groups and get their relevant data, let's use to_json() to
convert it into an easily stored string and store them in a file. Doing
it this way ensures that each line is its own object so we have an easy
way to pull the data out of the file as well.
::
# Note: This can be called from anywhere inside the tree. This function is path independent.
# 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_nodes = get_tree().get_nodes_in_group("Persist")
for i in save_nodes:
var node_data = i.save()
save_game.store_line(to_json(node_data))
save_game.close()
Game saved! Loading is fairly simple as well. For that we'll read each
line, use parse_json() to read it back to a dict, and then iterate over
the dict to read our values. But we'll need to first create the object
and we can use the filename and parent values to achieve that. Here is our
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://save_game.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. This will vary wildly depending on the needs of a project, so take care with this step.
# For our example, we will accomplish this by deleting savable objects.
var save_nodes = get_tree().get_nodes_in_group("Persist")
for i in save_nodes:
i.queue_free()
# 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 not save_game.eof_reached():
var current_line = parse_json(save_game.get_line())
# First we need to create the object and add it to the tree and set its position.
var new_object = load(current_line["filename"]).instance()
get_node(current_line["parent"]).add_child(new_object)
new_object.position = Vector2(current_line["pos_x"], current_line["pos_y"]))
# Now we set the remaining variables.
for i in current_line.keys():
if i == "filename" or i == "parent" or i == "pos_x" or i == "pos_y":
continue
new_object.set(i, current_line[i])
save_game.close()
And now we can save and load an arbitrary number of objects laid out
almost anywhere across the scene tree! Each object can store different
data depending on what it needs to save.
Some notes
----------
We may have glossed over a step, but setting the game state to one fit
to start loading data can be very complicated. This step will need to be
heavily customized based on the needs of an individual project.
This implementation assumes no Persist objects are children of other
Persist objects. Doing so would create invalid paths. If this is one of
the needs of a project this needs to be considered. Saving objects in
stages (parent objects first) so they are available when child objects
are loaded will make sure they're available for the add_child() call.
There will also need to be some way to link children to parents as the
NodePath will likely be invalid.