Hoping to use Stride for a particular project, but it’s not coming easily.
One of the key things I need is the ability to run multiple scenes simultaneously while also having the ability to switch between them instantaneously.
Unless I really missed something, this is not a use-case Stride supports out-of-the-box. I don’t really need editor support for this kind of thing, so that’s fine.
I’m running into 2 separate issues here:
- Finding a good way make alterations to something like Stride.Engine.Game without recompiling the engine (e.g. by inheriting Game.cs and accessing protected properties rather than private or internal properties and classes)
- I’ve been able to set up a janky prototype that will run multiple scene instances simultaneously. Logic can update, but adding any physics components cause a crash.
The idea is to have several discreetly isolated ‘worlds’. Each would be their own separated scene containing entities, physics sim, audio sim. The user would only be looking at one at a time, but for gameplay reasons, each world must be continuously updated (physics/logic), even while offscreen.
UE4 has something called a UWorld, and Godot has Viewports (which allows for their children nodes to act as their own discreet world). After a bit of poking through the source code, SceneInstance appears to be Stride’s equivalent of a ‘world’.
Stride’s Scene class is simply a list of entities and references for supporting the creation of a scene hierarchy. The SceneInstance class contains a single scene hierarchy and exposes methods for manipulating the scene hierarchy (and since it inherits EntityManager, also exposes the ability to execute the update/process and drawing logic on the entities living in that hierarchy).
SceneSystem is a GameSystem that contains a single SceneInstance, and when it is updated, ‘tells’ the SceneInstance to perform drawing and update/process.
It seemed like what I would want to do is derive my own ‘ParallelSceneSystem’ class from SceneSystem that would maintain/manage a List of SceneInstances to swap out of the main SceneInstance when desired. I started to go down that road, but ran into this roadblock:
Game.cs
...
public InputManager Input { get; internal set; }
public SceneSystem SceneSystem { get; }
In my project I’m deriving a custom class (‘MyGame’) from the engine’s Game class. The Game has properties for all the major game systems (including SceneSystem). Trouble is the SceneSystem property is private set – in effect, readonly, even for an inherited Game class. So I can’t actually replace the normal SceneSystem with something like ‘ParallelSceneSystem’. I have no idea if that is entirely intentional/by-design, or an over-site. Most of the other systems are similarly readonly, although some (like InputSystem) are internal set. My options then became:
-
modify Stride’s source to make the property protected set
-
duplicate the Game class (instead of deriving from) and make it use whatever system I wanted (not a great way to go – Game touches a number of internal classes and properties that mean you are going to need to
-
ditch my custom ‘ParallelSceneSystem’ and manage the list of SceneInstances directly in MyGame (not a great approach imho – good enough for quick and dirty prototype)
I went with the last option just so I could determine if this idea would work.
public class MyGame : Game (removed ui/scene selection code for brevity)
...
List<SceneInstance> instances = new List<SceneInstance>();
protected override Task LoadContent()
{
SceneSystem.SceneInstance.Name = "main";
instances.Add(
new SceneInstance(this.Services,
Content.Load<Scene>("Scene01")) { Name = "Scene01" });
instances.Add(
new SceneInstance(this.Services,
Content.Load<Scene>("Scene02")) { Name = "Scene02" });
return base.LoadContent();
}
protected override void Update(GameTime gameTime)
{
base.Update(gameTime);
// manually update instances not loaded to the SceneSystem
foreach (var instance in instances)
{
// prevent update from firing twice on the scene living in SceneSystem
{
if (instance == SceneSystem.SceneInstance)
continue;
if (SceneSystem.SceneInstance.RootScene.Children
.Contains(instance.RootScene))
continue;
}
instance.Update(gameTime);
}
}
private void AttachScene(int sceneIndex)
{
// recapture the current scene to prepare for loading a different scene
var currentScene =
SceneSystem.SceneInstance.RootScene.Children.FirstOrDefault();
if(currentScene != null)
{
SceneCollection sc =
SceneSystem.SceneInstance.RootScene.Children as SceneCollection;
sc.Remove(currentScene);
SceneInstance originalInstance =
instances.Where(x => x.Name == currentScene.Name).FirstOrDefault();
originalInstance.RootScene = currentScene;
}
// get the desired scene and put it in place
var instance = instances[sceneIndex];
var scene = instance.RootScene;
instance.RootScene = null;
SceneSystem.SceneInstance.RootScene.Children.Add(scene);
}
Originally I was trying to completely swap out the SceneInstance in the SceneSystem. But I quickly ran into issues with the graphics compositor and cameras assignments and slots. I might revisit that since I want to do some complex compositing with cameras living in different ‘worlds’ down the line.
At the moment I have a main scene with a camera (and controller) and I’m attaching the scene I want as a child. Nothing remarkable here. Dynamically adding/removing children scenes at runtime is a noted feature of Stride.
The only unusual thing I’m really doing here is taking the scenes that are loaded in memory, packing them into SceneInstances, and then manually updating those SceneInstances on every update call. Admittedly it feels a bit kludgy. Since a scene can only belong to a single SceneInstance, I have to be careful when swapping scenes. I take the current scene, detach it, and put it back in the list of instances, then grab the scene I want, and detach it from it’s enclosing instance, and reattach it to the SceneSystem’s instance.
This partly works. You can have n-number of visually discreet scenes, and the entities living in each scene will be updated, meaning the scripted logic on entities runs. But the moment you add a physics component to an entity, when that scene is attached Stride crashes. No error message.
It’s entirely possible I missed something, or I’m barking up the wrong tree. Hoping someone might have some insight. I’ve been poking around in Stride’s source code and can’t quite figure out how physics components get their updates, and where this crash is happening.
The take away is that at present, to support this use case requires modification of the engine’s source.