Browse Source

Update background_loading.rst

Update tutorials/io/background_loading.rst

Co-authored-by: Yuri Sizov <[email protected]>

Update background_loading.rst

fix a warning about underlines
KittenDeveloper 2 năm trước cách đây
mục cha
commit
6e15d35a20
1 tập tin đã thay đổi với 43 bổ sung264 xóa
  1. 43 264
      tutorials/io/background_loading.rst

+ 43 - 264
tutorials/io/background_loading.rst

@@ -1,5 +1,3 @@
-:article_outdated: True
-
 .. _doc_background_loading:
 .. _doc_background_loading:
 
 
 Background loading
 Background loading
@@ -10,299 +8,80 @@ level), you might want to show a loading screen with some indication
 that progress is being made. The main load method
 that progress is being made. The main load method
 (``ResourceLoader::load`` or just ``load`` from GDScript) blocks your
 (``ResourceLoader::load`` or just ``load`` from GDScript) blocks your
 thread, making your game appear frozen and unresponsive while the resource is being loaded. This
 thread, making your game appear frozen and unresponsive while the resource is being loaded. This
-document discusses the alternative of using the ``ResourceInteractiveLoader`` class for smoother
+document discusses the alternative of using ``ResourceLoader``'s other methods class for smoother
 load screens.
 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.
-
+ResourceLoader
+--------------
 Usage
 Usage
 -----
 -----
 
 
 Usage is generally as follows
 Usage is generally as follows
 
 
-Obtaining a ResourceInteractiveLoader
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. code-block:: cpp
-
-    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
-~~~~~~~
-
-.. code-block:: cpp
-
-    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.
+Start a load request
+~~~~~~~~~~~~~~~~~~~~
 
 
-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.
+.. code-block:: gdscript
 
 
-Load progress (optional)
-~~~~~~~~~~~~~~~~~~~~~~~~
+    func ResourceLoader.load_threaded_request(path: String, type_hint: String = "", use_sub_threads: bool = false, cache_mode: int = 1) -> int
 
 
-To query the progress of the load, use the following methods:
+This method will start to load the resource using thread(s).
 
 
-.. code-block:: cpp
-
-    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)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Checking Status
+~~~~~~~~~~~~~~~
 
 
-.. code-block:: cpp
+.. code-block:: gdscript
 
 
-    Error ResourceInteractiveLoader::wait();
+    func ResourceLoader.load_threaded_get_status(path: String, progress: Array = []) -> int
 
 
-Use this method if you need to load the entire resource in the current
-frame, without any more steps.
+Returns ``ResourceLoader.THREAD_LOAD_FAILED``, ``ResourceLoader.THREAD_LOAD_IN_PROGRESS``, 
+``ResourceLoader.THREAD_LOAD_INVALID_RESOURCE``, or ``ResourceLoader.THREAD_LOAD_LOADED``.
+The progress can be obtained by passing an array variable via progress which will return a one element array containing the percentage.
 
 
-Obtaining the resource
-~~~~~~~~~~~~~~~~~~~~~~
+Getting the resource (forces completion)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 
-.. code-block:: cpp
+.. code-block:: gdscript
 
 
-    Ref<Resource> ResourceInteractiveLoader::get_resource();
+    func ResourceLoader.load_threaded_get(path: String) -> Resource
 
 
-If everything goes well, use this method to retrieve your loaded
-resource.
+To obtain the resource call this method. This will wait (block) until it can return the resource.
 
 
 Example
 Example
 -------
 -------
 
 
-This example demonstrates how to load a new scene. Consider it in the
-context of the :ref:`doc_singletons_autoload` example.
-
-First, we set up 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 could show a
-progress bar or loading screen.
-
-::
-
-    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 loading 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 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
-
-        # Wait for frames to let the "loading" animation show up.
-        if wait_frames > 0:
-            wait_frames -= 1
-            return
-
-        var t = OS.get_ticks_msec()
-        # Use "time_max" to control for how long we block this thread.
-        while OS.get_ticks_msec() < t + time_max:
-            # Poll your loader.
-            var err = loader.poll()
-
-            if err == ERR_FILE_EOF: # Finished loading.
-                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 length = get_node("animation").get_current_animation_length()
-
-        # Call this on a paused animation. Use "true" as the second argument to
-        # force the animation to update.
-        get_node("animation").seek(progress * length, true)
-
-
-    func set_new_scene(scene_resource):
-        current_scene = scene_resource.instantiate()
-        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 the main thread while you call ``poll`` on your loader class. When a
-resource is done loading, it might require some resources from the
-low-level APIs (RenderingServer, 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 argument "p_in_front" to put it in
-front of the queue.
-
-::
+This example demonstrates how to load a scene in the background.
+In this example we will have a button spawn a enemy when pressed.
+The enemy will be ``Enemy.tscn`` which we will load on ``_ready`` and instantiate when pressed.
+The path will be ``"Enemy.tscn"`` which is located at ``res://Enemy.tscn``.
 
 
-    func cancel_resource(path)
-
-Remove a resource from the queue, discarding any loading done.
+First, we will start a request to load the resource and connect the button:
 
 
 ::
 ::
 
 
-    func is_ready(path)
-
-Returns ``true`` if a resource is fully loaded and ready to be retrieved.
+    # Define the path of the enemy
+    const ENEMY_SCENE_PATH : String = "Enemy.tscn"
+    # It isn't necessary to use constants but it can make it easier if the resource is moved around.
 
 
-::
+        func _ready():
+            # Start the request for Enemy.tscn , this will not block
+            ResourceLoader.load_threaded_request(ENEMY_SCENE_PATH)
+            # Connect the button to our method on_button_pressed
+            self.pressed.connect(on_button_pressed)
 
 
-    func get_progress(path)
-
-Get the progress of a resource. Returns -1 if there was an error (for example if the
-resource is not in 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.
+Now on_button_pressed will be called when the button is pressed.
+This method will be used to spawn an enemy.
 
 
 ::
 ::
 
 
-    func get_resource(path)
-
-Returns the fully loaded resource, or ``null`` on error. If the resource is
-not fully loaded (``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_cutscene()
-
-    # Later, when the user presses the pause button for the first time:
-    pause_menu = queue.get_resource("res://pause_menu.tres").instantiate()
-    pause_menu.show()
-
-    # When you need a new scene:
-    queue.queue_resource("res://level_1.tscn", true)
-    # Use "true" as the second argument 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_progress("res://level_1.tscn"))
-
-    # When the user walks away from the trigger zone in your Metroidvania game:
-    queue.cancel_resource("res://zone_2.tscn")
+    func on_button_pressed(): # Button was pressed
+        # Obtain the resource now that we need it
+        var enemy_scene = ResourceLoader.load_threaded_get(ENEMY_SCENE_PATH)
+        # Instantiate the enemy scene
+        var enemy = enemy_scene.instantiate()
+        # Add it to the current scene
+        add_child(enemy)
+        
 
 
 **Note**: this code, in its current form, is not tested in real world
 **Note**: this code, in its current form, is not tested in real world
 scenarios. If you run into any issues, ask for help in one of
 scenarios. If you run into any issues, ask for help in one of