Disable one of multiple scenes

Hi there - I switch often between scenes in a game i am making. However, now that I am keeping one of hte scenes alive in the background for performance reasons, I notice it still receives full input from the engine even though I am not “rendering” it.

What is the best way to “disable” a scene when it is not hte current visually active scene. Do I simply do scene.detachControl()?

the attached playground shows two scenes. If you interact with one, you will see that the second scene will always mimic the first even though it is not always rendered. More importantly, any ActionManager also trigger even though objects in the hidden scene are not “visible”.

As I see in your PG you are already controlling which scene is rendered so rendering wise you are fine

Now as you said if you call scene.detachControl you should also be fine from the input management

I organize my scenes using a ScreenManager. (Named “screen” to distinguish from scene.)
Interface Screen brings lifecycle methods activate and deactivate.

export interface Screen {
    activate(): void;
    deactivate(): void;
    render(): void;
    dispose(): void;
}

export class ScreenManager {
    private readonly screens: Screen[] = [];

    constructor() {
    }

    dispose() {
        this.clearScreens();
    }

    getTopScreen() {
        return this.screens.length > 0 ? this.screens[this.screens.length - 1] : null;
    }

    pushScreen(screen: Screen) {
        const topScreen = this.getTopScreen();
        if (topScreen !== null) {
            topScreen.deactivate();
        }
        this.screens.push(screen);
        screen.activate();
    }

    popScreen(numberOfScreens = 1) {
        if (numberOfScreens < 1) {
            return;
        }
        let topScreen = this.getTopScreen();
        if (topScreen === null) {
            return;
        }
        topScreen.deactivate();

        while (numberOfScreens > 0) {
            topScreen = this.getTopScreen();
            if (topScreen === null) {
                return;
            }
            topScreen.dispose();
            this.screens.pop();
            numberOfScreens--;
        }

        topScreen = this.getTopScreen();
        if (topScreen === null) {
            return;
        }
        topScreen.activate();
    }

    private clearScreens() {
        this.popScreen(this.screens.length);
    }
}

The main class App utilizes the ScreenManager:

export class App {
    readonly engine: Engine;
    readonly screenManager = new ScreenManager();
    private readonly resizeHandler = () => this.resize();
    private readonly renderHandler = () => this.render();
    private disposed = false;

    constructor(
        readonly canvasElement: HTMLCanvasElement
    ) {
        this.engine = new Engine(canvasElement, true);
        this.load();
    }

    dispose() {
        this.disposed = true;
        this.stop();
        this.screenManager.dispose();
        this.engine.dispose();
    }

    private async load() {
        // Load stuff...

        this.screenManager.pushScreen(new MyFirstSceen(this));
    }

    run() {
        window.addEventListener('resize', this.resizeHandler);
        this.engine.runRenderLoop(this.renderHandler);
    }

    stop() {
        window.removeEventListener('resize', this.resizeHandler);
        this.engine.stopRenderLoop(this.renderHandler);
    }

    private resize() {
        this.engine.resize();
    }

    private render() {
        const topScreen = this.screenManager.getTopScreen();
        if (topScreen === null) {
            return;
        }
        topScreen.render();
    }

}

You then can implement your “screens”:

export class MyFirstScreen implements Screen {
    readonly engine: Engine;
    readonly scene: Scene;

    constructor(
        readonly app: App
    ) {
        this.engine = this.app.engine;
        this.scene = new Scene(this.engine);
        
        // Setup scene...
    }

    activate() {
        this.scene.attachControl();

        this.engine.onResizeObservable.add(this.resize, undefined, undefined, this);
        this.resize();
    }

    deactivate() {
        // this.debugLayerManager.hide();
        
        this.engine.onResizeObservable.removeCallback(this.resize, this);

        this.scene.detachControl();
    }

    resize() {
    }

    render() {
        this.scene.render();
    }

    dispose() {
        this.scene.dispose();
    }

    private pushSecondScreen() {
        this.app.screenManager.pushScreen(new MySecondScreen(this.app));
    }
}