singletons_autoload.rst 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. .. _doc_singletons_autoload:
  2. Singletons (AutoLoad)
  3. =====================
  4. Introduction
  5. ------------
  6. Scene singletons are very useful, catering to a common use case where you need
  7. to store persistent information between scenes.
  8. Albeit very powerful, the scene system by itself has a few drawbacks:
  9. - There is no common place to store information (e.g. a player's items etc.)
  10. required by more than one scene.
  11. - While it is possible for a scene that loads and unloads other scenes as
  12. its children to store information common to these child scenes, it is no
  13. longer possible to run these scenes by themselves and expect them to work
  14. correctly.
  15. - While information can be stored to disk in \`user://\` and this information
  16. can be loaded by scenes that require it, continuously saving and loading this
  17. data when changing scenes is cumbersome and may be slow.
  18. However there is still a need in Godot to create parts of a scene that:
  19. - Are always loaded, no matter which scene is opened from the editor
  20. - Can store global variables, such as player information, items, money
  21. etc. and share information between scenes
  22. - Can handle switching scenes and transitions
  23. - Acts like a singleton, since GDScript does not support global variables by design.
  24. Auto-loading nodes and scripts caters to this need.
  25. AutoLoad
  26. --------
  27. You can use AutoLoad to load a scene, or a script that inherits from Node (a node
  28. will be created and the script will be set to it).
  29. To autoload a scene or script, select Scene > Project Settings from the menu and switch
  30. to the AutoLoad tab. Each entry in the list requires a name, which is used as the name
  31. of the node, and the node is always added to the root viewport before any other scenes
  32. are loaded.
  33. .. image:: /img/singleton.png
  34. This means that any node can access a singleton named "playervariables" with:
  35. ::
  36. var player_vars = get_node("/root/playervariables")
  37. Custom scene switcher
  38. ---------------------
  39. This short tutorial will explain how to make a scene switcher using
  40. autoload. For simple scene switching, the
  41. :ref:`SceneTree.change_scene() <class_SceneTree_change_scene>`
  42. method suffices (described in :ref:`doc_scene_tree`), so this method is for
  43. more complex behavior when switching between scenes.
  44. First download the template from here:
  45. :download:`autoload.zip </files/autoload.zip>`, then open it.
  46. Two scenes are present, scene_a.scn and scene_b.scn on an otherwise
  47. empty project. Each are identical and contain a button connected to a
  48. callback for switching to the other scene. When the project runs, it
  49. starts in scene_a.scn. However, this currently does nothing and pressing the
  50. button does not work.
  51. global.gd
  52. ---------
  53. First of all, create a global.gd script. The easy way to create a
  54. resource from scratch is from the new resource button in the inspector tab:
  55. .. image:: /img/newscript.png
  56. Save the script as `global.gd`:
  57. .. image:: /img/saveasscript.png
  58. The script should open in the script editor. The next step is to add
  59. it to AutoLoad list. Select Scene > Project Settings from the menu,
  60. switch to the AutoLoad tab and add a new entry with name "global" that
  61. points to this file:
  62. .. image:: /img/addglobal.png
  63. Now, whenever you run any of your scenes, the script is always loaded.
  64. Returning to our script, the current scene needs to be fetched in the
  65. `_ready()` function. Both the current scene and `global.gd` are children of
  66. root, but the autoloaded nodes are always first. This means that the
  67. last child of root is always the loaded scene.
  68. Note: Make sure that global.gd extends Node, otherwise it won't be
  69. loaded!
  70. ::
  71. extends Node
  72. var current_scene = null
  73. func _ready():
  74. var root = get_tree().get_root()
  75. current_scene = root.get_child( root.get_child_count() -1 )
  76. Next up is the function for changing the scene. This function frees the
  77. current scene and replaces it with the requested one.
  78. ::
  79. func goto_scene(path):
  80. # This function will usually be called from a signal callback,
  81. # or some other function from the running scene.
  82. # Deleting the current scene at this point might be
  83. # a bad idea, because it may be inside of a callback or function of it.
  84. # The worst case will be a crash or unexpected behavior.
  85. # The way around this is deferring the load to a later time, when
  86. # it is ensured that no code from the current scene is running:
  87. call_deferred("_deferred_goto_scene",path)
  88. func _deferred_goto_scene(path):
  89. # Immediately free the current scene,
  90. # there is no risk here.
  91. current_scene.free()
  92. # Load new scene
  93. var s = ResourceLoader.load(path)
  94. # Instance the new scene
  95. current_scene = s.instance()
  96. # Add it to the active scene, as child of root
  97. get_tree().get_root().add_child(current_scene)
  98. # optional, to make it compatible with the SceneTree.change_scene() API
  99. get_tree().set_current_scene( current_scene )
  100. As mentioned in the comments above, we really want to avoid the
  101. situation of having the current scene being deleted while being used
  102. (code from functions of it being run), so using
  103. :ref:`Object.call_deferred() <class_Object_call_deferred>`
  104. is desired at this point. The result is that execution of the commands
  105. in the second function will happen at a later time when no code from
  106. the current scene is running.
  107. Finally, all that is left is to fill the empty functions in scene_a.gd
  108. and scene_b.gd:
  109. ::
  110. #add to scene_a.gd
  111. func _on_goto_scene_pressed():
  112. get_node("/root/global").goto_scene("res://scene_b.scn")
  113. and
  114. ::
  115. #add to scene_b.gd
  116. func _on_goto_scene_pressed():
  117. get_node("/root/global").goto_scene("res://scene_a.scn")
  118. Now if you run the project, you can switch between both scenes by pressing
  119. the button!
  120. To load scenes with a progress bar, check out the next tutorial,
  121. :ref:`doc_background_loading`