Add _add/remove_current_scene
This commit is contained in:
parent
e3213aaef5
commit
a454a377f5
3 changed files with 129 additions and 16 deletions
|
@ -13,6 +13,65 @@
|
||||||
<link title="Multiple resolutions">$DOCS_URL/tutorials/rendering/multiple_resolutions.html</link>
|
<link title="Multiple resolutions">$DOCS_URL/tutorials/rendering/multiple_resolutions.html</link>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
<methods>
|
<methods>
|
||||||
|
<method name="_add_current_scene" qualifiers="virtual">
|
||||||
|
<return type="void" />
|
||||||
|
<param index="0" name="scene" type="Object" />
|
||||||
|
<description>
|
||||||
|
Called when the tree needs to add a scene as the current scene.
|
||||||
|
If you override this virtual method, you should add [param scene] to the tree, set the node as current scene via [member current_scene], and emit [signal current_scene_added].
|
||||||
|
[codeblocks]
|
||||||
|
[gdscript]
|
||||||
|
func _add_current_scene(scene: Object) -> void:
|
||||||
|
root.add_child(scene)
|
||||||
|
current_scene = scene
|
||||||
|
current_scene_added.emit(scene)
|
||||||
|
[/gdscript]
|
||||||
|
[csharp]
|
||||||
|
public void _AddCurrentScene(Object scene)
|
||||||
|
{
|
||||||
|
// Due to limitations, you have to cast scene from Object to Node.
|
||||||
|
Node node = scene as Node;
|
||||||
|
Root.AddChild(node);
|
||||||
|
CurrentScene = node;
|
||||||
|
EmitSignal(SignalNames.CurrentSceneAdded, node);
|
||||||
|
}
|
||||||
|
[/csharp]
|
||||||
|
[/codeblocks]
|
||||||
|
You can add the scene under another node instead of root. When this function is called for the first time, [param scene] is the initial scene specified by [member ProjectSettings.application/run/main_scene] or the editor.
|
||||||
|
[b]Note:[/b] The [method Node._ready] pass of the tree has not been run yet when the initial scene is adding in. Use [constant Node.NOTIFICATION_SCENE_INSTANTIATED] for the autoloaded scene to set up children node references before [code]_ready[/code] is called.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="_remove_current_scene" qualifiers="virtual">
|
||||||
|
<return type="Object" />
|
||||||
|
<description>
|
||||||
|
Called when the tree needs to remove the current scene.
|
||||||
|
If you override this virtual method, you should remove [member current_scene] from the tree, set [member current_scene] to null, and return the removed node. The node returned is then handled by the caller (will usually be deleted by the caller).
|
||||||
|
[codeblocks]
|
||||||
|
[gdscript]
|
||||||
|
func _remove_current_scene() -> Object:
|
||||||
|
var scene = current_scene
|
||||||
|
var parent = scene.get_parent()
|
||||||
|
if (parent):
|
||||||
|
parent.remove_child(scene)
|
||||||
|
current_scene = null
|
||||||
|
return scene
|
||||||
|
[/gdscript]
|
||||||
|
[csharp]
|
||||||
|
public GodotObject _RemoveCurrentScene()
|
||||||
|
{
|
||||||
|
Node scene = CurrentScene;
|
||||||
|
Node parent = scene.GetParent();
|
||||||
|
if (parent != null)
|
||||||
|
{
|
||||||
|
parent.RemoveChild(scene);
|
||||||
|
}
|
||||||
|
CurrentScene = null;
|
||||||
|
return scene;
|
||||||
|
}
|
||||||
|
[/csharp]
|
||||||
|
[/codeblocks]
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
<method name="call_group" qualifiers="vararg">
|
<method name="call_group" qualifiers="vararg">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<param index="0" name="group" type="StringName" />
|
<param index="0" name="group" type="StringName" />
|
||||||
|
@ -56,7 +115,7 @@
|
||||||
Returns [constant OK] on success, [constant ERR_CANT_CREATE] if the scene cannot be instantiated, or [constant ERR_INVALID_PARAMETER] if the scene is invalid.
|
Returns [constant OK] on success, [constant ERR_CANT_CREATE] if the scene cannot be instantiated, or [constant ERR_INVALID_PARAMETER] if the scene is invalid.
|
||||||
[b]Note:[/b] Operations happen in the following order when [method change_scene_to_packed] is called:
|
[b]Note:[/b] Operations happen in the following order when [method change_scene_to_packed] is called:
|
||||||
1. The current scene node is immediately removed from the tree. From that point, [method Node.get_tree] called on the current (outgoing) scene will return [code]null[/code]. [member current_scene] will be [code]null[/code], too, because the new scene is not available yet.
|
1. The current scene node is immediately removed from the tree. From that point, [method Node.get_tree] called on the current (outgoing) scene will return [code]null[/code]. [member current_scene] will be [code]null[/code], too, because the new scene is not available yet.
|
||||||
2. At the end of the frame, the formerly current scene, already removed from the tree, will be deleted (freed from memory) and then the new scene will be instantiated and added to the tree. [method Node.get_tree] and [member current_scene] will be back to working as usual.
|
2. At the end of the frame, the formerly current scene, already removed from the tree, will be deleted (freed from memory) and then the new scene will be instantiated and added to the tree. [signal current_scene_added] will be emitted when the new scene is added to the tree. [method Node.get_tree] and [member current_scene] will be back to working as usual.
|
||||||
This ensures that both scenes aren't running at the same time, while still freeing the previous scene in a safe way similar to [method Node.queue_free].
|
This ensures that both scenes aren't running at the same time, while still freeing the previous scene in a safe way similar to [method Node.queue_free].
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
|
@ -278,6 +337,12 @@
|
||||||
</member>
|
</member>
|
||||||
</members>
|
</members>
|
||||||
<signals>
|
<signals>
|
||||||
|
<signal name="current_scene_added">
|
||||||
|
<param index="0" name="node" type="Node" />
|
||||||
|
<description>
|
||||||
|
Emitted when the current scene is added to the tree.
|
||||||
|
</description>
|
||||||
|
</signal>
|
||||||
<signal name="node_added">
|
<signal name="node_added">
|
||||||
<param index="0" name="node" type="Node" />
|
<param index="0" name="node" type="Node" />
|
||||||
<description>
|
<description>
|
||||||
|
|
|
@ -1454,7 +1454,6 @@ Node *SceneTree::get_edited_scene_root() const {
|
||||||
|
|
||||||
void SceneTree::set_current_scene(Node *p_scene) {
|
void SceneTree::set_current_scene(Node *p_scene) {
|
||||||
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Changing scene can only be done from the main thread.");
|
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Changing scene can only be done from the main thread.");
|
||||||
ERR_FAIL_COND(p_scene && p_scene->get_parent() != root);
|
|
||||||
current_scene = p_scene;
|
current_scene = p_scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1467,9 +1466,12 @@ void SceneTree::_flush_scene_change() {
|
||||||
memdelete(prev_scene);
|
memdelete(prev_scene);
|
||||||
prev_scene = nullptr;
|
prev_scene = nullptr;
|
||||||
}
|
}
|
||||||
current_scene = pending_new_scene;
|
|
||||||
root->add_child(pending_new_scene);
|
Node *scene = pending_new_scene;
|
||||||
pending_new_scene = nullptr;
|
pending_new_scene = nullptr;
|
||||||
|
|
||||||
|
add_current_scene(scene);
|
||||||
|
|
||||||
// Update display for cursor instantly.
|
// Update display for cursor instantly.
|
||||||
root->update_mouse_cursor_state();
|
root->update_mouse_cursor_state();
|
||||||
}
|
}
|
||||||
|
@ -1496,12 +1498,10 @@ Error SceneTree::change_scene_to_packed(const Ref<PackedScene> &p_scene) {
|
||||||
pending_new_scene = nullptr;
|
pending_new_scene = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_scene = current_scene;
|
|
||||||
|
|
||||||
if (current_scene) {
|
if (current_scene) {
|
||||||
// Let as many side effects as possible happen or be queued now,
|
prev_scene = remove_current_scene();
|
||||||
// so they are run before the scene is actually deleted.
|
} else {
|
||||||
root->remove_child(current_scene);
|
prev_scene = nullptr;
|
||||||
}
|
}
|
||||||
DEV_ASSERT(!current_scene);
|
DEV_ASSERT(!current_scene);
|
||||||
|
|
||||||
|
@ -1519,15 +1519,54 @@ Error SceneTree::reload_current_scene() {
|
||||||
void SceneTree::unload_current_scene() {
|
void SceneTree::unload_current_scene() {
|
||||||
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Unloading the current scene can only be done from the main thread.");
|
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Unloading the current scene can only be done from the main thread.");
|
||||||
if (current_scene) {
|
if (current_scene) {
|
||||||
memdelete(current_scene);
|
Node *scene = remove_current_scene();
|
||||||
current_scene = nullptr;
|
if (scene) {
|
||||||
|
memdelete(scene);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneTree::add_current_scene(Node *p_current) {
|
void SceneTree::add_current_scene(Node *p_scene) {
|
||||||
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Adding a current scene can only be done from the main thread.");
|
ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Adding a current scene can only be done from the main thread.");
|
||||||
current_scene = p_current;
|
ERR_FAIL_COND_MSG(current_scene, "You can only add a current scene when there is no current scene.");
|
||||||
root->add_child(p_current);
|
|
||||||
|
if (!GDVIRTUAL_IS_OVERRIDDEN(_add_current_scene)) {
|
||||||
|
current_scene = p_scene;
|
||||||
|
root->add_child(p_scene);
|
||||||
|
|
||||||
|
emit_signal(current_scene_added_name, p_scene);
|
||||||
|
} else {
|
||||||
|
GDVIRTUAL_CALL(_add_current_scene, p_scene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *SceneTree::remove_current_scene() {
|
||||||
|
ERR_FAIL_COND_V_MSG(!Thread::is_main_thread(), nullptr, "Removing a current scene can only be done from the main thread.");
|
||||||
|
ERR_FAIL_COND_V_MSG(!current_scene, nullptr, "You can only remove a current scene when there is a current scene.");
|
||||||
|
|
||||||
|
if (!GDVIRTUAL_IS_OVERRIDDEN(_remove_current_scene)) {
|
||||||
|
Node *scene = current_scene;
|
||||||
|
|
||||||
|
Node *parent = scene->get_parent();
|
||||||
|
if (parent) {
|
||||||
|
parent->remove_child(scene);
|
||||||
|
}
|
||||||
|
current_scene = nullptr;
|
||||||
|
|
||||||
|
return scene;
|
||||||
|
} else {
|
||||||
|
Object *ret = nullptr;
|
||||||
|
GDVIRTUAL_CALL(_remove_current_scene, ret);
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *node = Object::cast_to<Node>(ret);
|
||||||
|
ERR_FAIL_COND_V_MSG(!node, nullptr, "_remove_current_scene must return a node.");
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always, bool p_process_in_physics, bool p_ignore_time_scale) {
|
Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always, bool p_process_in_physics, bool p_ignore_time_scale) {
|
||||||
|
@ -1734,6 +1773,8 @@ void SceneTree::_bind_methods() {
|
||||||
ADD_SIGNAL(MethodInfo("node_renamed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
|
ADD_SIGNAL(MethodInfo("node_renamed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
|
||||||
ADD_SIGNAL(MethodInfo("node_configuration_warning_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
|
ADD_SIGNAL(MethodInfo("node_configuration_warning_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
|
||||||
|
|
||||||
|
ADD_SIGNAL(MethodInfo("current_scene_added", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node")));
|
||||||
|
|
||||||
ADD_SIGNAL(MethodInfo("process_frame"));
|
ADD_SIGNAL(MethodInfo("process_frame"));
|
||||||
ADD_SIGNAL(MethodInfo("physics_frame"));
|
ADD_SIGNAL(MethodInfo("physics_frame"));
|
||||||
|
|
||||||
|
@ -1741,6 +1782,9 @@ void SceneTree::_bind_methods() {
|
||||||
BIND_ENUM_CONSTANT(GROUP_CALL_REVERSE);
|
BIND_ENUM_CONSTANT(GROUP_CALL_REVERSE);
|
||||||
BIND_ENUM_CONSTANT(GROUP_CALL_DEFERRED);
|
BIND_ENUM_CONSTANT(GROUP_CALL_DEFERRED);
|
||||||
BIND_ENUM_CONSTANT(GROUP_CALL_UNIQUE);
|
BIND_ENUM_CONSTANT(GROUP_CALL_UNIQUE);
|
||||||
|
|
||||||
|
GDVIRTUAL_BIND(_add_current_scene, "scene");
|
||||||
|
GDVIRTUAL_BIND(_remove_current_scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneTree *SceneTree::singleton = nullptr;
|
SceneTree *SceneTree::singleton = nullptr;
|
||||||
|
|
|
@ -153,6 +153,7 @@ private:
|
||||||
StringName node_added_name = "node_added";
|
StringName node_added_name = "node_added";
|
||||||
StringName node_removed_name = "node_removed";
|
StringName node_removed_name = "node_removed";
|
||||||
StringName node_renamed_name = "node_renamed";
|
StringName node_renamed_name = "node_renamed";
|
||||||
|
StringName current_scene_added_name = "current_scene_added";
|
||||||
|
|
||||||
int64_t current_frame = 0;
|
int64_t current_frame = 0;
|
||||||
int nodes_in_tree_count = 0;
|
int nodes_in_tree_count = 0;
|
||||||
|
@ -274,6 +275,9 @@ protected:
|
||||||
void _notification(int p_notification);
|
void _notification(int p_notification);
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
|
GDVIRTUAL1(_add_current_scene, Object *);
|
||||||
|
GDVIRTUAL0R(Object *, _remove_current_scene);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum {
|
enum {
|
||||||
NOTIFICATION_TRANSFORM_CHANGED = 2000
|
NOTIFICATION_TRANSFORM_CHANGED = 2000
|
||||||
|
@ -410,8 +414,8 @@ public:
|
||||||
Ref<Tween> create_tween();
|
Ref<Tween> create_tween();
|
||||||
TypedArray<Tween> get_processed_tweens();
|
TypedArray<Tween> get_processed_tweens();
|
||||||
|
|
||||||
//used by Main::start, don't use otherwise
|
void add_current_scene(Node *p_scene);
|
||||||
void add_current_scene(Node *p_current);
|
Node *remove_current_scene();
|
||||||
|
|
||||||
static SceneTree *get_singleton() { return singleton; }
|
static SceneTree *get_singleton() { return singleton; }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue