How can you operate the pointer lock when you click a specific element?

I want to mark the start on the screen and press the letter to lock the pointer.

I wrote the code to hide the elements I clicked through the “visibility” option and lock the pointer through eventListener “mouseover”.

When you click the start character, the mouse lock function is currently completed, but the part where the menu is displayed again after detecting the “esc” key does not work.

Is there an example of a code that detects pointer lock when unlocking to “esc”?

The actions I want to do are as follows.

When you click the start button, the start button disappears and the mouse locks.

When you press esc, the restart button appears and the mouse is unlocked.

Hey @jspp welcome to Babylon! :wave:

Do you have an example Playground (PG) of your code? Will be good for people to see what’s going on. I’m also curious, are you using Babylon GUI for this? Sounds like it, but if not I would really recommend it for something like this.

Sounds like you just need a bunch of boolean flags to guard against any clicks/updating pointer positions, but let’s see what you have. :slight_smile:

Use the html element without using Babylon gui.


const BabylonScene = () => {
  const reactCanvas = useRef(null);

  const [width, setWidth] = useState<number>(window.innerWidth)
  const [height, setHeight] = useState<number>(window.innerHeight)
  const [loaded, setLoaded] = useState<boolean>(false)
  const [menuVisible, setMenuVisible] = useState<boolean>(true)
  
    useEffect(() => {
    canvas = document.getElementById("canvas")
    let engine = new Engine(canvas, true)
    scene = new Scene(engine)

    createScene()

    let renderLoop = function () {
      if (scene) {
        scene.render();
      }
    };
    engine.runRenderLoop(renderLoop);

    console.log('re-redering check :engine')

    if (window) {
      const resize = () => {
        if (scene) {
          scene.getEngine().resize();
          engine?.resize()
          setWidth(window.innerWidth)
          setHeight(window.innerHeight)
          console.log('re-rendering check :resize')
        }
      };
      window.addEventListener("resize", resize);

      return () => {
        window.removeEventListener("resize", resize);
      };
    }
  }, [])

  
  useEffect(()=>{
    canvas.addEventListener("mouseover", () => {
      canvas.requestPointerLock = canvas.requestPointerLock ||
        canvas.msRequestPointerLock || canvas.mozRequestPointerLock ||
        canvas.webkitRequestPointerLock;

        if (canvas.requestPointerLock) {
          canvas.requestPointerLock()
        canvas.removeEventListener("mouseover", () => {
        })
      }
    })
  }, [canvas])

  return (
    <>
      {loaded? <div></div> : <Loading />}
      <PauseMenu  visible={menuVisible}>
        <PauseMenuInner onClick={ ()=> setMenuVisible(false) }>
        <h3>How to Operation?</h3>
        <h4>move: wasd</h4>
        <h4>jump: space bar</h4>
        <h4>fly: keyboad <span style={{fontSize:'22px'}}>"F"</span> key</h4>
        <h4>run: keyboad <span style={{fontSize:'22px'}}>"Shift"</span> key</h4>
        </PauseMenuInner>
      </PauseMenu>
      {menuVisible ? <div></div> : <Aim>+</Aim>}

      <canvas 
        id="canvas"
        width={width}
        height={height}  
      />
    </>
  );
};

export default BabylonScene;

const PauseMenu = styled.div.attrs((props)=>{

})`
  visibility:${(props) => (props.visible ? 'visible' : 'hidden')};
  width:100vw;
  height:100vh;
  background-color:rgba(128, 128, 128, 0.411);
  position:absolute;
  display:flex;
  flex-direction: column;
  justify-content: center;
`

const PauseMenuInner = styled.div`
  display:flex;
  flex-direction: column;
  align-items: center;
  background-color:skyblue;
  width:100vw;
`
const Aim = styled.div`
  background-color: red;
  position:absolute;
  top:50%;
  left:50%;
`

Click on the “PauseMenu” element to hide it and at the same time lock the mouse through the “Mouseover” event.

Now I want to activate “PauseMenu” by clicking “esc”.

Here, one problem occurs, and the esc button is not detected because the button for releasing “PointerLock” is “esc”.

If you press the “esc” button twice, it is detected once, but this is not good in terms of user experience.

A question that’s not that important. )

  1. And if there is no mouse click after the first screen rendering, the movement function through “wasd” does not work, is it normal?

@PolygonalSun might be able to help with this ?

Because the pointerlock consumes the first Escape press, you won’t be able to just listen and react to it directly but you can add a listener for pointerlockchange. If document.pointerLockElement isn’t equal to your canvas, you can then excute the same could that you would for your PauseMenu. Here’s an example PG that demonstrates how to do this: PointerLock Event Example | Babylon.js Playground (babylonjs.com).

As for you other question, it might be related to focus. When you first click on the screen, you set your focus to that element and any input event will be dispatched to it. If it doesn’t have focus, it won’t react to any keyboard input. If you call focus() on your canvas, at the beginning, it should address this.:

...
createScene();
canvas.focus();

let renderLoop ...
1 Like

Hello @jspp just checking in was your question answered?