Skip to content

Commit

Permalink
First init
Browse files Browse the repository at this point in the history
EiTaNBaRiBoA committed Jun 28, 2024
1 parent 80ebf89 commit bed1594
Showing 9 changed files with 280 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Normalize EOL for all files that Git considers text files.
* text=auto eol=lf
80 changes: 79 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,80 @@
# AsyncScene
## AsyncScene - Asynchronous Scene Loader

This Godot tool provides a simple way to load scenes asynchronously, improving your game's loading times and user experience.

### Features

- Load scenes in the background without freezing the main thread.
- Replace the current scene or add the loaded scene additively.
- Choose between immediate or manual scene switching after loading.
- Track loading progress with a percentage value.
- Receive notifications upon successful or failed scene loading.

### Installation

1. Copy the `AsyncScene.gd` script into your project.
2. Optionally, you can create a new resource type for easier access:
- Go to **Project > Project Settings > Plugins > Resource** and click "Create a Resource Type".
- Choose a name (e.g., "AsyncScene") and link it to the `AsyncScene.gd` script.

### Usage

**1. Loading a scene:**

```gdscript
extends Node2D
var scene : AsyncScene
func _ready() -> void:
# Replace the current scene immediately after loading:
scene = AsyncScene.new( "res://path/to/your/scene.tscn", AsyncScene.LoadingSceneOperation.ReplaceImmediate)
# Replace the current scene manually after loading (call scene.ChangeScene() later):
# scene = AsyncScene.new("res://path/to/your/scene.tscn", AsyncScene.LoadingSceneOperation.Replace)
# Add the loaded scene to the current scene tree:
# scene = AsyncScene.new("res://path/to/your/scene.tscn", AsyncScene.LoadingSceneOperation.Additive)
# Connect to the OnComplete signal to get notified when loading is finished:
scene.OnComplete.connect(on_scene_load_complete)
func on_scene_load_complete():
# Do something after the scene is loaded, e.g., hide loading screen.
pass
```

**2. Manually switching to the loaded scene (if using Replace mode):**

```gdscript
func _process(delta):
if scene and scene.isCompleted:
scene.ChangeScene()
```

**3. Accessing loading progress:**

```gdscript
func _process(delta):
if scene:
print("Loading progress: ", scene.progress, "%")
```

**4. Unloading the loaded scene:**

```gdscript
scene.UnloadScene()
```

**5. Getting the loading status:**

```gdscript
var status = scene.GetStatus() # Returns a string like "THREAD_LOAD_IN_PROGRESS", "THREAD_LOAD_LOADED", etc.
```

### Example

Check the provided `example.tscn` scene for a practical demonstration of how to use the AsyncScene tool.


This readme provides a basic overview of the AsyncScene tool and its usage. You can further customize and extend this tool to suit your specific needs.
101 changes: 101 additions & 0 deletions addons/AsyncSceneManager/AsyncScene.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
extends Node
class_name AsyncScene


enum LoadingSceneOperation {
ReplaceImmediate, ## Replaces scene as soon as it loads
Replace, ## Doesn't Replace scene immediate, and need to call ChangeScene(using the same path)
Additive ## Adding to the tree another scene
}
var status_names = {
ResourceLoader.THREAD_LOAD_IN_PROGRESS: "THREAD_LOAD_IN_PROGRESS",
ResourceLoader.THREAD_LOAD_FAILED: "THREAD_LOAD_FAILED",
ResourceLoader.THREAD_LOAD_INVALID_RESOURCE: "THREAD_LOAD_INVALID_RESOURCE",
ResourceLoader.THREAD_LOAD_LOADED: "THREAD_LOAD_LOADED"
}

var timer : Timer = Timer.new()
signal OnComplete
var packedScenePath : String = ""
var myRes : PackedScene = null
var currentSceneNode : Node = null
var progress : float = 0
var isCompleted : bool = false
var typeOperation : LoadingSceneOperation = LoadingSceneOperation.ReplaceImmediate

func _init(tscnPath : String, setOperation : LoadingSceneOperation = LoadingSceneOperation.ReplaceImmediate ) -> void:
packedScenePath = tscnPath
typeOperation = setOperation
if not ResourceLoader.exists(tscnPath):
printerr("Invalid scene path " + tscnPath)
return
ResourceLoader.load_threaded_request(tscnPath,"",true)
call_deferred("_setupUpdateSeconds")



func ChangeScene() -> void:
if not isCompleted:
printerr("Scene hasn't been loaded yet")
return
Engine.get_main_loop().root.get_tree().change_scene_to_packed(myRes)
currentSceneNode = Engine.get_main_loop().root.get_tree().current_scene

func GetStatus() -> String:
return status_names.get(_getStatus())

#region Private

func _additiveScene() -> void:
currentSceneNode = myRes.instantiate()
Engine.get_main_loop().root.call_deferred("add_child",currentSceneNode)


## Unloading
func UnloadScene() -> void:
if not isCompleted:
printerr("Scene hasn't been loaded yet")
return
currentSceneNode.queue_free()
queue_free()


func _setupUpdateSeconds() -> void:
Engine.get_main_loop().root.add_child(timer)
timer.one_shot = false
timer.autostart = true
timer.set_wait_time(0.1)
timer.timeout.connect(_check_status)
timer.start()


func _getStatus() -> ResourceLoader.ThreadLoadStatus:
return ResourceLoader.load_threaded_get_status(packedScenePath)


func _check_status() -> void:
if isCompleted : return
if _getStatus() == ResourceLoader.THREAD_LOAD_LOADED:
myRes = ResourceLoader.load_threaded_get(packedScenePath)
if typeOperation == LoadingSceneOperation.ReplaceImmediate:
ChangeScene()
elif typeOperation == LoadingSceneOperation.Additive:
_additiveScene()
_complete()
elif _getStatus() == ResourceLoader.THREAD_LOAD_INVALID_RESOURCE:
_complete()
elif _getStatus() == ResourceLoader.THREAD_LOAD_FAILED:
_complete()
elif _getStatus() == ResourceLoader.THREAD_LOAD_IN_PROGRESS:
var progressArr : Array = []
ResourceLoader.load_threaded_get_status(packedScenePath,progressArr)
progress = progressArr.front() * 100



func _complete() -> void:
timer.queue_free()
OnComplete.emit()
isCompleted = true
progress = 100
#endregion
19 changes: 19 additions & 0 deletions addons/AsyncSceneManager/Examples/SceneChanging.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
extends Node2D

var scene : AsyncScene = null
@export var scenePath : String = 'res://addons/AsyncSceneManager/Examples/scene_to_load.tscn'


func _ready() -> void:
#scene = AsyncScene.new(scenePath,AsyncScene.LoadingSceneOperation.Replace) loading and later changing using scene.ChangeScene()
#scene = AsyncScene.new(scenePath,AsyncScene.LoadingSceneOperation.ReplaceImmediate) Immediately changing the scene after loading
scene = AsyncScene.new(scenePath,AsyncScene.LoadingSceneOperation.Additive) #Loading Scene additively to another scene
scene.OnComplete.connect(complete) #Binding to signal after complete loading

func complete() -> void:
#scene.UnloadScene() Unloading scene
#scene.ChangeScene() Changing the main scene manually
print("Loading complete")
pass


15 changes: 15 additions & 0 deletions addons/AsyncSceneManager/Examples/scene_main.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[gd_scene load_steps=2 format=3 uid="uid://ca76hnnn8ums7"]

[ext_resource type="Script" path="res://addons/AsyncSceneManager/Examples/SceneChanging.gd" id="1_bldvc"]

[node name="scene_main" type="Node2D"]
script = ExtResource("1_bldvc")

[node name="Label" type="Label" parent="."]
offset_left = 452.0
offset_right = 1152.0
offset_bottom = 261.0
theme_override_font_sizes/font_size = 191
text = "Scene 1"
horizontal_alignment = 1
vertical_alignment = 1
12 changes: 12 additions & 0 deletions addons/AsyncSceneManager/Examples/scene_to_load.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[gd_scene format=3 uid="uid://dqojfek3b58la"]

[node name="scene_to_load" type="Node2D"]

[node name="Label" type="Label" parent="."]
offset_top = 289.0
offset_right = 700.0
offset_bottom = 550.0
theme_override_font_sizes/font_size = 191
text = "Scene 2"
horizontal_alignment = 1
vertical_alignment = 1
Binary file added addons/AsyncSceneManager/Icon.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions addons/AsyncSceneManager/Icon.jpg.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://bbtg7trios1jk"
path="res://.godot/imported/Icon.jpg-f9230da019f0fcfc56881806ec8dc408.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://addons/AsyncSceneManager/Icon.jpg"
dest_files=["res://.godot/imported/Icon.jpg-f9230da019f0fcfc56881806ec8dc408.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
18 changes: 18 additions & 0 deletions project.godot
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
; 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=5

[application]

config/name="AsyncSceneManager"
config/features=PackedStringArray("4.3", "Forward Plus")

[debug]

gdscript/warnings/untyped_declaration=2

0 comments on commit bed1594

Please sign in to comment.