Each Stage is the root of a heirachy of StageNodes. Classes that inherit StageNode are:
StageActorParticleSystemGeomCameraLightThese are the basic building blocks of your scene.
StageNodes can be parents and children of other StageNodes. To build this heirarchy you make use of the StageNode::set_parent method. set_parent can take a node ID, or the node itself.
All StageNodes by default are children of the Stage they belong to. If you want to detach a node from its parent (and reparent it under the Stage) then simply pass a nullptr to set_parent:
auto a1 = stage_->new_actor();
auto a2 = stage_->new_actor();
a2->set_parent(a1);
// a1 is now a2's parent
a2->set_parent(nullptr);
// a1 and a2 are now both direct children of stage_
There are a number of ways to traverse your stage heirarchy but they are all exposed through standard C++ begin/end pairs designed to be used with C++ range for-loops. The below code shows a number of examples of traversing a stage's tree:
for(auto node: stage->each_descendent()) {} // Root-to-leaf iteration
for(auto node: actor->each_ancestor()) {} // Traverse up the tree
for(auto node: actor->each_sibling()) {} // Iterate the siblings of the actor
for(auto node: stage->each_child()) {} // Iterate direct-children only
StageNodes are only updated if the owning Stage is attached to an active Pipeline. You can check this by checking Stage::is_part_of_active_pipeline().
It is highly recommended that if you are manipulating a Stage in a background thread (e.g. in the load() method of a Scene) that you do not attach the Stage to a pipeline until you are finished manipulating. This should prevent threading problems.
You can destroy a StageNode by calling its destroy() method. This won't release the StageNode immediately, but it will fire the signal_destroyed signal. The actual clean-up of the node will happen after late_update(), but before the render queue is built. This helps prevent issues where queued tasks try to access deleted nodes.
When the clean-up process runs, an additional signal_cleaned_up signal will fire just before deletion of the node.
StageNodes have a helper method called destroy_after(Seconds) that you can call to fire destroy() after the number of seconds have passed. Internally this simply queues a coroutine to call destroy(). Be aware, destroy_after is a fire-and-forget method - you can't cancel once you've triggered it!
Note:
is_marked_for_destruction()will return false until the elapsed time has passed, anddestroy()has been called.
You can give stage nodes names using StageNode::set_name, and later search for those nodes recursively using StageNode::find_descendent_with_name. If a name is duplicated, only the first match found
will be returned.
You can set a name during construction of a stage node by chaining using the set_name_and_get(name) method:
auto actor = stage->new_actor()->set_name_and_get("Actor 1");
By default, stage nodes (excluding cameras) will be culled with a scene partitioner if they are deemed to be offscreen. You can disable this behaviour for a stage node by toggling its cullable state:
node->set_cullable(false); // Will always be renderered
assert(!node->is_cullable());
Sometimes it's useful for a stage node to be "attached" to another node, without forming a parent child relationship. An example would be a Skybox, which should always stay surrounding the camera, but shouldn't follow the camera's rotation - and also doesn't conceptually make sense to be a child of the camera. For this reason StageNode::link_position(node) exists. The following code would make actor synchronise its position with camera.
auto actor = stage->new_actor();
auto camera = stage->new_camera();
actor->link_position(camera);
Note: the linked node will update its position at the end of
late_updatephase, therefore its possible that the position will not match what you would expect duringupdate,fixed_update, orlate_updatebut the position will synchronise before rendering.