Repository navigation
Scene Graph
The Scene Graph module is the highest-level abstraction in Genode. It contains the core building block components for your game logic.
Almost every other module class in Genode can be heavily incorporated with the usage of SceneGraph classes that allow you to choose the right amount of abstraction based on your requirements. Thus, it is highly recommended that you explore all other modules' documentation first before reading further.
The Gx::Node class represents a fundamental building block in the scene graph hierarchy. As a core structural unit, a node object can be considered a container that can hold other nodes and has transformation properties—hence, it implements Gx::Transformable.
This parent-child structure simplifies complex scene composition. For instance, attaching multiple nodes to another single node object allows you to logically group related nodes that can be manipulated easily, such as applying transformations (like position, rotation, scale) that cascade down the hierarchy.
Caution
The nodes hold non-owning pointers of their children, and you are responsible for ensuring the lifetime of objects in the hierarchy. This allows you to modify hierarchy (such as removing a child from a node and adding it to a different node) without having to construct and destroy node objects.
Warning
Gx::Node by default is conditionally copyable: it can only be copied if it has no child. The copy constructor will throw Gx::InvalidOperationException if you're trying to copy a node that has children. This is because it is not trivial to perform a deep clone of a node object and its hierarchy without imposing an intrusive interface such as a clonable interface.
Rather than making a copy, you should write a function or a factory class to re-create an object from scratch based on the node properties.
For this reason, exercise extra caution when instantiating a node object via Gx::ResourceManager::Instantiate!
Important
In Genode, a node object is not strictly a renderable element. They can be objects with no visual properties but are still transformable. For example, you can create an audio listener as a node object. This object then would use the transform properties to represent the position of the audio listener in 2D space.
Every node carries a version number that can be retrieved via GetVersion(). The version is intended for observation by consumers that care about the node: when the version changes, it indicates that the node has changed in a way that is considered significant, and consumers that store the node structure or other important information derived from it may need to rebuild their caches.
The version changes whenever the node structure or identity changes:
-
AddChild,RemoveChild, andClearChildrenyield a new version because the set of children has changed. -
SetNameandSetTagalso yield a new version. Name and Tag are considered important because they may change how children and parents are populated (e.g., lookups viaGetChildByName,GetChildrenByTag, orMatch) and could significantly change the overall node structure.
The built-in containers use this mechanism to avoid repeating expensive work. For example, Gx::RenderableContainer no longer downcasts every child to Gx::Renderable on every frame; instead, it caches the Gx::Renderable pointers of its children and only repopulates them when the node version changes. This removes the per-frame cost of virtual inheritance lookups that previously made deep hierarchies expensive to render.
Derived node implementations can change the version via the protected SetVersion() function. Be mindful when doing so: other consumers may react by repopulating the whole node structure, which can be expensive. The version should monotonically increase in general cases, and it should only change when the node has actually changed in a way that invalidates what consumers may have cached.
The Gx::Scene class represents a logical container and organizational root for all elements of a particular segment of your game. In Genode, all these elements are expressed as the Gx::Node object. Everything in the Scene should be a node object. In fact, the Gx::Scene itself implements the Gx::Node class.
The scene objects are typically managed by a Gx::SceneDirector instance that either comes from Gx::Application or you can manually create and manage a scene director instance. Alternatively, it is also perfectly fine to manage the scene objects manually or create a "scene director" implementation on your own. See the scene director section to learn more about how your game interacts with your scenes. However, it is strongly recommended that you first understand how Gx::Scene works as described below.
The following code illustrates a typical implementation of the Gx::Scene class.
class AnotherScene : public Gx::Scene { /* implement additional scene here */ };
class MyGameScene : public Gx::Scene
{
public:
// Use System Context to inject a pre-configured resource manager that represents a resource manager that shared across the scenes
// Note that you shouldn't perform scene setup here; use the `Initialize` function instead
MyGameScene(Gx::ResourceManager& sharedResources) :
m_sharedResources(sharedResources)
{
}
~MyGameScene() = default; // Same advice as the constructor: use the `Finalize` function instead
protected:
// Initialize the scene using `Initialize` function
void Initialize() override
{
// Load a sprite from a file
auto& sprite = m_localResources.AddFromFile<Gx::Sprite>("/some/path/to/sprite/metadata.json");
// Load an animation from the shared resource manager
// The file will not be loaded if the shared resources already have the animation
auto& animation = m_sharedResources.AddFromFile<Gx::Animation>("/some/path/to/animation/metadata.json");
animation.Reset(); // Reset animation state to initial just in case there were leftover dirty states when it was being used in the other scenes.
// Both of these entities implement `Gx::Node` and can be added to the scene directly and conveniently
AddChild(sprite, animation);
// Run a fade-out tween via Gx::TaskContainer
Run<Gx::Fade>(sprite, 000, sf::seconds(5.f)); // completely fade-out the sprite in 5 seconds
// Use GetDirector().Present() or GetDirector().Dismiss() to navigate to another scene or go back to the previous scene, respectively
// The following code illustrates navigating to another scene when the animation finishes and go back to the previous scene if it is interrupted
animation.SetAnimationCallback([this] (Gx::Animation& it)
{
if (it.GetState() == Gx::Animation::AnimationState::Completed)
{
GetDirector().Present<AnotherScene>();
}
if (it.GetState() == Gx::Animation::AnimationState::Stopped)
{
if (GetDirector().Dismiss())
{
std::cout << "Going back to the previous scene";
}
else
{
std::cout << "Previous scene is not available: the current scene is the first running scene";
}
}
});
}
// Note: you don't have to render or update your objects manually here
// your scene will automatically do it for you. See "Container" section for more details
private:
Gx::ResourceManager& m_sharedResources;
Gx::ResourceManager m_localResources; // will be destroyed when the scene is no longer active
};
class SpriteLoader : public Gx::ResourceLoader<Gx::Sprite> { /* implement the loader here */ };
class AnimationLoader : public Gx::ResourceLoader<Gx::Animation> { /* implement the loader here */ };
class MyGame : public Gx::Application
{
protected:
void Boot() override
{
// Register resource loaders to make resource manager works properly
Gx::ResourceLoaderFactory::Register<Gx::Sprite, SpriteLoader>();
Gx::ResourceLoaderFactory::Register<Gx::Animation, AnimationLoader>();
// Provide the shared resource manager using the Singleton scope
// This makes every scene receive the same resource manager instance via its scene context
GetModule<Gx::Context>().Provide<Gx::ResourceManager>(Gx::Context::Scope::Singleton);
// Note that each Scene holds its own scoped Context created from the root Context
// Dependencies provided with the default Local scope are created per scene instead
// Finally, activate the scene by using the provided scene director
GetModule<Gx::SceneDirector>().Present<MyGameScene>();
}
int Shutdown() override
{
return 0;
}
};Gx::Scene has several important lifecycle functions. None of these are pure virtual abstract functions; however, it is highly recommended that the core lifecycle functions be used in any scenario to prevent undefined behaviors and unexpected errors.
-
Initialize: Called when the scene is activated by the scene director. Use this to initialize your high-level scene logic states and resources. -
Render: Called when the scene is being rendered. -
Update: Called when the scene is being updated. -
Input: Called when the scene receives user input. -
OnAppFocusChanged: Called when the window focus is changed -
OnAppResized: Called when the window is resized -
OnAppClose: Called when the window is about to close. Returnfalseto cancel the close event. -
Finalize: Called when the scene is about to be deactivated. Use this to clean up objects that the scene manually manages.
Important
Using the Initialize and Finalize functions is strongly recommended instead of constructor and destructor.
Typical functions such as GetDirector, GetContext, and Require<T> will likely not be available in the constructors because the core components have not been initialized when your scene is constructed. Also, some resources and components are not guaranteed to be alive in the destructor either.
Note that the windowing event is for the window associated with the scene via Gx::SceneDirector and Gx::Application. If the Scene were managed by a Gx::SceneDirector that is not bound to a Gx::Application instance, these events wouldn't be triggered unless you manually propagate the event to the Gx::SceneDirector.
In addition, you can define a custom Initialize function that accepts any number of parameters with any type. You can invoke this initializer function via Gx::SceneDirector::Present. The parameters may be copyable or move-only.
class MyScene : public Gx::Scene
{
public:
// Important: this needs to be public!
void Initialize(const std::string& message)
{
std::cout << message;
}
};
// Usage:
Gx::SceneDirector& director = // ...
director.Present<MyScene>("this is the message");Important
This custom Initialize function must use public modifier. Otherwise, the Present call will cause a compile error.
The default parameterless Initialize function will still be called regardless of the existence of the custom initializer function. However, use only one initialize function at a time for the best maintainability.
Whether the initializer can be replayed on Dismiss depends on the parameter types, not on how you pass them at the call site:
-
Copyable parameters are recorded in the scene history stack, so the initializer is replayed with the same values when the scene is reached again via
Dismiss. Passing them withstd::moveor as rvalue references does not change this: a copyable value is still copied into the recorded values, andDismissreplaysInitializeusing that copy. -
Move-only parameters (or any parameter list that contains one) are moved into
Initializeand consumed by the call, so the initializer is not recorded in the history stack.
Caution
A move-only initializer is not replayed on Dismiss. When a scene that was presented with move-only parameters is reached again via Dismiss, it falls back to the parameterless Initialize(), unless you pass fresh parameters to Dismiss<T> explicitly.
This is inherent: the values were consumed the first time the initializer ran, so there is nothing left to replay.
Each scene owns its own System Context. When a scene is staged by the scene director, a new scope is created from the root context (the context of the Gx::Application or the one managed by the Gx::SceneDirector), and the scene holds that scope for its entire lifetime. Use GetContext() to access it, or the Require<T>() shortcut to resolve a dependency from it directly.
The context respects the scope of each dependency:
- Dependencies provided with
Gx::Context::Scope::Local(the default) are local to the scene scope. Each scene creates its own instances of them, and those instances are destroyed together with the scene when the scene is destroyed. - Dependencies provided with
Gx::Context::Scope::Singletonare shared across scopes. Every scene resolves the same instance, and its lifetime is bound to the root context rather than any scene.
This gives local dependencies a natural per-scene lifetime: state that should not leak between scenes (e.g., a scene-specific resource manager or gameplay systems) can simply be provided with the local scope, and each presented scene will work with a fresh instance.
Note that the scene's Finalize runs before the scene object is destroyed, so local dependencies are still available in Finalize and may be used for cleanup.
Gx::Presentable represents an object that can be presented by a Gx::Presentable::Parent in stack-like order: presenting pushes the object on top of the presentation stack, and only the topmost object can be dismissed. Gx::Scene implements Gx::Presentable::Parent, making the scene the typical place to present these objects.
The most common presentables are graphical, such as Gx::Dialog from the UI module. However, presentables are not limited to graphical objects: anything that needs to be ordered in a stack-like behavior can implement Gx::Presentable (e.g., modal states or input capture layers).
Use Present to present an object on the scene and Dismiss to dismiss the topmost one:
class MyScene : public Gx::Scene
{
protected:
void Initialize() override
{
// Present a dialog on top of the scene
Present(m_confirmDialog);
// ...
// Dismiss the topmost presentable (the dialog in this case)
Dismiss();
}
private:
Gx::Dialog m_confirmDialog;
};While presented on a scene, a presentable participates in the scene lifecycle based on the interfaces it implements:
- Presentables that implement
Gx::Renderableare rendered above the scene children, in presentation order. - Presentables that implement
Gx::Updatableare updated every frame, together with the scene children. - Input is exclusive to the topmost presentable: while at least one presentable is presented, only the topmost one receives input (if it implements
Gx::Inputable), and the scene children do not. This gives presentables a modal behavior by default.
Use IsPresenting(presentable) to check whether the specified presentable is currently the topmost one. Dismiss(presentable) only succeeds when the specified presentable is the topmost; it returns false otherwise, enforcing the stack order.
Present accepts an optional Gx::PresentationContext that describes how the object should be presented; it is delivered to the presentable through the protected OnPresented function. For graphical presentables, Gx::GraphicalPresentationContext carries the presentation Bounds and an IsCentered flag. When an object is presented on a scene with the default context, the scene supplies a Gx::GraphicalPresentationContext covering the current view size with IsCentered enabled, which places the presentable at the center of the view.
Since Gx::PresentationContext is an open base struct, custom presentable implementations may define their own context type carrying whatever presentation parameters they need.
A Gx::Presentable implementation must provide the following functions:
-
Dismiss(): Dismiss the object from whatever parent is presenting it. A typical implementation forwards the call to the parent received inOnPresented. -
OnPresented(Parent& parent, const PresentationContext& context)(protected): Called when the object is presented. Use the context to position or configure the object. -
OnDismissed(Parent& parent)(protected): Called when the object is dismissed.
The SceneGraph module provides built-in containers that simplify the parent-child processing of a node object. These containers are abstract classes that implement Gx::Node and can be used as a building block to create a custom node object. By default, the Gx::Scene class implements all of these containers.
Note
These containers rely on virtual inheritance to compose with Gx::Node. The typed children of a container (e.g., the Gx::Renderable children of a Gx::RenderableContainer) are cached and only repopulated when the node version changes, so the cost of resolving the child types is not paid on every frame.
Note
These containers do not explicitly check and process the children recursively. You must ensure that the children (particularly the ones that may have nested children) implement the appropriate containers to make every node properly visited and processed.
The Gx::RenderableContainer represents a container of renderable objects. Rendering the container will render all container children that implement Gx::Renderable in back-to-front order.
Gx::RenderableContainer& container = //...
Gx::Sprite sprite = // ...
Gx::Text text = // ...
// Add sprite and text into the container
container.AddChild(sprite, text);
// Render the container
Gx::RenderSurface& surface = // ...
surface.Render(container); // This will render the sprite and then the textThe Gx::UpdatableContainer represents a container of updatable objects. Updating the container will update all container children that implement Gx::Updatable in back-to-front order.
Gx::UpdatableContainer& container = //...
Gx::Animation animation = // ...
Gx::Updatable& updatable = // ...
// Add animation and updatable into the container
container.AddChild(animation, updatable);
// Update the container
container.Update(delta); // This will update the animation and then the updatableThe Gx::InputableContainer represents a container of objects that can listen to user input. Propagating input events to the container will fire the input events to all container children that implement Gx::Inputable in back-to-front order.
Gx::InputableContainer& container = //...
Gx::Inputable& input1 = // ...
Gx::Inputable& input2 = // ...
// Add inputables object to the container
container.AddChild(input1, input2);
// Fire the input event
sf::Event& ev = // ...
container.Input(ev); // This will trigger the input callback of the input1 and then the input2The Gx::RenderBatchContainer represents a container batch of renderable objects. Rendering the container will render all container children that implement Gx::Renderable in a single batch. This container implements Gx::RenderableContainer and Gx::UpdatableContainer.
Warning
The container impose rendering limitations that are subject to the Sprite Batch limitations.
Gx::RenderBatchContainer& container = //...
Gx::Sprite sprite = // ...
Gx::Text text = // ...
// Add sprite and text into the container
container.AddChild(sprite, text);
// Render the container
Gx::RenderSurface& surface = // ...
surface.Render(container); // This will render the sprite and the text in batchThe Gx::TaskContainer represents a non-copyable container of task objects. Unlike all the other containers, it manages the Gx::Task objects rather than the Gx::Node objects. In addition, Gx::TaskContainer manages the lifetime of its task children.
Gx::TaskContainer implements Gx::Updatable, and it needs to be updated every frame to work correctly.
Important
The container won't manage task objects added via AddChild. Gx::Task class is not designed to work with Gx::Node simultaneously.
Use Run<T> to create and start a task. The template parameter represents the type of Gx::Task. You will need to specify parameters matching the public constructor parameters of the given task type; they will be forwarded using perfect forwarding to the task constructor.
The created task is stored internally within the task container and will continue to exist as long as it is in the Initial or Running state. The Run<T> function returns std::weak_ptr<T>; use this to determine whether the task is running and exists within the container.
Gx::TaskContainer& container = // ...
Gx::Colorable& colorable = // ...
// Create and start fade tween via container
std::weak_ptr<Gx::Fade> fade = container.Run<Gx::Fade>(colorable, 255, sf::seconds(5.f));
// ... sometimes later: check if fade is still alive
if (auto ptr = fade.lock())
{
// Task is still alive; you can do something with it
ptr->Reset(); // reset the fade tween while it is still running
}
else
{
// Task is no longer alive; it's either stopped or completed
}You can also provide a temporary task that the container will copy.
Gx::TaskContainer& container = // ...
Gx::Colorable& colorable = // ...
// The specified task will be copied, so it must be a copy-constructible type!
container.Run(Gx::Fade(colorable, 255, sf::seconds(5.f));Alternatively, you can provide a reference for tasks that you manage manually. The task object will not be destroyed but removed from the container once it is stopped or completed.
Gx::TaskContainer& container = // ...
Gx::Colorable& colorable = // ...
// Create and manage your own task
auto fade = Gx::Fade(colorable, 255, sf::seconds(5.f);
// The specified task will be referenced but not destroyed when it no longer running
container.Run(fade);Caution
When using this overload, you are responsible for ensuring the task is alive while running inside the container. Otherwise, it is undefined behavior, and memory corruption may occur.
Important
The task that started via the Run call will not updated immediately and will be updated in the next Update() frame.
Therefore, you should exercise extra caution when altering the task states as it may affect the initial values of task states for certain types of tasks.
See Tween documentation for more details.
You can stop a task directly from the task std::weak_ptr; The task will removed in the next Update cycle of Gx::TaskContainer. However, you can stop it via the container by using a reference
Gx::TaskContainer& container = // ...
Gx::Colorable& colorable = // ...
// Create and manage your own task
auto fade = Gx::Fade(colorable, 255, sf::seconds(5.f);
container.Run(fade);
// ...
// Stop the task via container
container.Stop(fade);You can also stop all running tasks by calling StopAll.
The Gx::SceneDirector represents a class that manages the scene construction and destruction. It has one active scene at a time.
The Gx::SceneDirector implements Gx::Renderable, Gx::Updatable, and Gx::Inputable. When you render, update, or delegate input events to the director, it will be delegated to the currently active scene.
The Gx::SceneDirector will only keep one scene object alive at a time. The scene object is created whenever you activate a scene via the Present or Dismiss function. If another scene is presented beforehand, it will be destroyed. Scene object creation is based on the deserializer specified during the scene registration. The registration itself could be implicitly called by the Gx::SceneDirector when possible.
By default, Gx::Application creates and manages a Gx::SceneDirector for you. The application instance automatically forwards the lifecycle call events such as Render, Update, and Input.
Use GetModule<Gx::SceneDirector>() to get the scene director instance from the application instance.
class MyAwesomeGame : public Gx::Application
{
public:
// Application constructor
MyAwesomeGame(std::string title, const sf::VideoMode& mode, const sf::View& view, const bool fullScreen, const sf::ContextSettings& settings) :
Gx::Application(std::move(title), mode, view, fullScreen, settings)
{
}
protected:
void Boot() override
{
// Implement your game initialization here..
// ...
// You can Register scenes and Present the initial scene here
GetModule<Gx::SceneDirector>().Present<MyAwesomeScene>();
}
// The rest of your application implementation..
}You don't have to create Gx::SceneDirector manually when you're using Gx::Application. Use the director provided by the application class, which can be retrieved by calling GetModule<Gx::SceneDirector>().
If you're not using the application class, create the director by specifying Gx::RenderSurface to the constructor. It will be used when a scene needs to get or set a sf::View from the actual surface.
Gx::RenderSurface& surface = // ...
auto director = Gx::SceneDirector(surface);Note
An internal System Context will be used instead of the application context when a scene director is created this way.
Typically, you don't need to register your scene manually because the director will attempt to register the scene when you try Present it if it is not registered. However, you can manually register your scene by calling Register.
The registration tells the scene director how a scene should be constructed. The default Register function will assume the scene to be created using either the System Context provided by the associated application or a context managed by the scene director internally.
This means the framework will automatically inject the dependency that the scene needs via the constructor.
class MyScene : public Gx::Scene
{
public:
// Dependencies are injected automatically by the system context when a scene is registered implicitly by default or registered using the default Register overload
MyScene(Gx::ResourceManager& sharedResources)
{
// Do something with shared resources here..
// Note: do not initialize your resource here directly, see Lifecycle for more details
}
// The rest of scene implementation goes here..
};
Gx::SceneDirector director = // ...
// Register the scene using default register overload
director.Register<MyScene>();
// Additionally, you may configure the system context here before presenting the scene
// If you're using application class, do this in the `Boot()` function and use `GetModule<Gx::Context>()` to retrieve the context
// Otherwise, use `director.GetContext()` to get the system context managed by the scene director
// Internally, the scene will be created using the System Context `Instantiate<T>` function within a new scope when it is presentedIn some cases, you may wish to specify the scene instantiation manually or to make your scene deserializable from a file or other sources that can be loaded via a Resource Loader. In these cases, you can register your scene via the Register overload that accepts a scene deserializer function with the Gx::ResourceContext parameter.
class MyScene : public Gx::Scene { /* scene implementation here.. */ };
Gx::SceneDirector director = // ...
// Register the scene
director.Register<MyScene>([] (const Gx::ResourceContext& ctx)
{
// Create your scene here, for example, use resource loader:
std::unique_ptr<Gx::ResourceLoader<MyScene>> mySceneLoader = Gx::ResourceLoaderFactory::CreateLoader<MyScene>();
// Return scene as Gx::ResourcePtr
mySceneLoader->LoadFromFile("/path/to/myscene/metadata.json", ctx);
});Important
Using the default Register will prevent the scene header from using class forwarding of its dependencies regardless of whether the parameter is a pointer or reference.
The Gx::SceneDirector needs to determine whether the scene is constructible via System Context. Thus, it is impossible to do so when one or more dependencies are forwarded because they're not concrete types.
Use the Present<T> function to create and activate a scene. The scene object will be made based on how it was registered. Present has several overloads that could affect how the scene is created and initialized.
When a scene is presented, it will be pushed to a scene history stack internally. This will allow you to go back to the previously presented scene without knowing the actual scene.
You can call the Present<T> function without any parameters. When a scene is presented this way, the Gx::ResourceContext::Default is passed to the scene deserializer.
class MyScene : public Gx::Scene { /* scene implementation here.. */ };
SceneDirector& director = // ...
director.Present<MyScene>();You can also specify a custom Gx::ResourceContext when presenting a scene. The specified resource context will be forwarded to the scene deserializer.
The specified Gx::ResourceContext is captured and copied to the scene history stack.
class MyScene : public Gx::Scene { /* scene implementation here.. */ };
SceneDirector& director = // ...
Gx::ResourceContext& context = // ...
director.Present<MyScene>(context);if you have a scene with a custom Initialize function, you can pass custom parameters when calling Present. Copyable parameters are captured and recorded in the scene history stack for replay; move-only parameters are consumed on first use and not recorded.
See the Scene Lifecycle section for more details.
class MyScene : public Gx::Scene
{
public:
void Initialize(std::string message)
{
std::cout << "received message: " << message.c_str();
}
// Implement the rest of the scene..
};
SceneDirector& director = // ...
director.Present<MyScene>("hello world");Finally, you can specify resource context and scene initializer parameters when calling Present<T>. Make sure the context is positioned first in the arguments.
Both Gx::ResourceContext and the initializer parameters are captured and copied to the scene history stack. Therefore, the specified Gx::ResourceContext must be copyable.
class MyScene : public Gx::Scene
{
public:
void Initialize(std::string message)
{
std::cout << "received message: " << message.c_str();
}
// Implement the rest of the scene..
};
SceneDirector& director = // ...
// Register the scene
director.Register<MyScene>([] (const Gx::ResourceContext& ctx)
{
// Create your scene here. For example, use resource loader:
std::unique_ptr<Gx::ResourceLoader<MyScene>> mySceneLoader = Gx::ResourceLoaderFactory::CreateLoader<MyScene>();
// Return scene as Gx::ResourcePtr
mySceneLoader->LoadFromFile("/path/to/myscene/metadata.json", ctx);
});
Gx::ResourceContext& context = // ...
director.Present<MyScene>(context, "hello world");You can return to the previous scene by calling the Dismiss function. When dismissing a scene, the active scene will be erased from the history stack. The Dismiss function returns a boolean indicating whether the director returned to the previous scene successfully. It will only return false when the history stack is empty, meaning there is no scene to return to.
When the currently active scene is dismissed successfully, the previous scene will be constructed and initialized in the same manner when they're presented. For example, if the scene was presented using a custom Gx::ResourceContext and initializer parameters, the scene will be presented using those parameters again that were captured during the Present<T> call when the scene is activated via the Dismiss call.
This replay only applies to copyable initializer parameters. As noted in the Scene Lifecycle section, a scene presented with move-only parameters is re-initialized through the parameterless Initialize() on Dismiss, unless you supply fresh parameters via Dismiss<T>.
Like Present<T>, the dismiss function has multiple overloads.
Call Dismiss() to go back to the previous scene.
SceneDirector& director = // ...
// Dismiss the current active scene and go back to the previous scene if available
// The scene deserializer and scene initializer will be replayed with the same parameters if they were specified during `Present<T>` call (copyable parameters only)
director.Dismiss();Similar to the Present<T> counterpart, you can call Dismiss with a custom resource context or initializer parameters or both. However, to specify initializer parameters, you must provide the scene type to dismiss by calling Dismiss<T> instead.
Using Dismiss<T> will also allow you to return to a specific scene. This will remove any subsequent scenes between the specified and currently active scenes. The scene history stack is preserved, and the director will do nothing when the specified scene type does not exist in the scene history stack.
SceneDirector& director = // ...
// Dismiss the current active scene and construct the previous scene with a custom resource context
Gx::ResourceContext& context = // ...
director.Dismiss(context);
// ... Or using initializer parameters to initialize the previous scene with new parameters
director.Dismiss<MyPreviousScene>("hello world", 3.14f, true);
// ... You can also jump back straight to a specific scene using the template Dismiss function
director.Dismiss<MyFirstScene>(); // using default initializer
// ... Finally you can use both a custom resource context and initializer parameters
director.Dismiss<MyGameScene>(context, "hello world", 3.14f, true);Copyright © 2024 - CXO2
This open-source library is licensed under the zlib/libpng license.