So while trying to make a game with babylonjs I have noticed that scenes generated later seem to lose keyboard focus. For instance if I have a menu and then when I click a button to start a game level the button disposes of the menu scene and creates a new scene with the level meshes, materials, etc. Then for some reason even though I added an action listener to detect keyboard input it detects nothing unless the user clicks outside the canvas and back on it. I apologize though, try as I might (and I tried for hours) I could not replicate this problem on the playground, so posted below is the code for a nodejs example.
import {Engine} from '@babylonjs/core/Engines/engine';
import {ExecuteCodeAction} from '@babylonjs/core/Actions/directActions';
import {Vector3} from '@babylonjs/core/Maths/math';
import {Camera} from '@babylonjs/core/Cameras/camera';
import {Scene} from '@babylonjs/core/scene';
import {ActionManager} from '@babylonjs/core/Actions/actionManager';
import {AdvancedDynamicTexture} from '@babylonjs/gui/2D/advancedDynamicTexture';
import {Button} from '@babylonjs/gui/2D/controls/button';
var canvas = document.getElementById("renderCanvas");
var engine = new Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true });
var doit = () => {
engine.scenes[0].dispose();
activeDisplay = new Game(engine);
//activeDisplay = later;
}
class Menu{
constructor(engine){
this.screenWidth = engine.getRenderWidth()
this.screenHeight = engine.getRenderHeight();
this.scene = new Scene(engine);
this.gui = AdvancedDynamicTexture.CreateFullscreenUI("UI",true,this.scene);
this.camera = new Camera("camera",new Vector3(0,0,-10),this.scene);
this.start = new Button.CreateSimpleButton("start", "Game");
this.start.width = .2;
this.start.height = "40px";
this.start.color = "white";
this.start.background = "green";
this.start.onPointerUpObservable.add(doit);
this.gui.addControl(this.start);
}
}
class Game{
constructor(engine){
this.scene = new Scene(engine);
this.scene.clearColor.r = 1;
this.camera = new Camera("camera",new Vector3(0,0,-10),this.scene);
this.scene.actionManager = new ActionManager(this.scene);
this.scene.actionManager.registerAction(new ExecuteCodeAction(ActionManager.OnKeyDownTrigger, (evt) => {
switch(evt.sourceEvent.key){
case 'p':
console.log("The Key p was pressed");
}
}));
//engine._onCanvasFocus();
}
}
var activeDisplay = new Menu(engine);
//var later = new Game(engine);
engine.runRenderLoop(function(){
if (activeDisplay) {
activeDisplay.scene.render();
}
});
As you can see it starts by creating my game menu and then when you click the button it changed to the next scene(I made the background red so you can tell it changed). The odd thing is if you uncomment the two lines with the variable later it works, so it seems that creating the scene early will keep the keyboard but not later? Also if you uncomment the engine._onCanvasFocus() line it will also work but I don’t understand why I would need to have the engine refocus if it never lost focus. Although it would technically work with the onCanvasFocus line I don’t like that this feels like a hack, because if there is one thing that I have learned from coding it is that patching a bug with a hack instead of fixing the underlying issue with almost certainly lead to more bugs down the road. So what I’m trying to figure out is the root cause of this issue which I suspect has something to do with the Observers since that is what the onCanvasFocus method invokes but I can’t seem to figure it out.
Any help is appreciated. Also feel free to add me on discord 8Bit#6510 since I feel that this issue will have a lot of back and forth with what I have already tried and sharing information. Also I’m relatively new to babylon, so if there is a better approach to making a multilevel game than creating and disposing of a bunch of scenes please let me know. Thank you.