TurboWarp / packager

Converts Scratch projects into HTML files, zip archives, or executable programs for Windows, macOS, and Linux.
https://packager.turbowarp.org/
Mozilla Public License 2.0
241 stars 153 forks source link

Pointer lock #84

Closed GarboMuffin closed 3 years ago

GarboMuffin commented 3 years ago

For now, here's some custom JS to implement pointerlock (copy and paste it into the advanced options section):

(function () {
  const canvas = scaffolding._canvas;
  const vm = scaffolding.vm;
  const mouse = vm.runtime.ioDevices.mouse;
  let isLocked = false;

  const postMouseData = (e, isDown) => {
    const {movementX, movementY} = e;
    const {width, height} = scaffolding.layersRect;
    const x = mouse._clientX + movementX;
    const y = mouse._clientY - movementY;
    mouse._clientX = x;
    mouse._scratchX = Math.round(mouse.runtime.stageWidth * ((x / width) - 0.5));
    mouse._clientY = y;
    mouse._scratchY = Math.round(mouse.runtime.stageWidth * ((y / height) - 0.5));
    if (typeof isDown === 'boolean') {
      const data = {
        button: e.button,
        isDown
      };
      vm.postIOData('mouse', data);
    }
  };
  document.addEventListener("mousedown", (e) => {
    if (canvas.contains(e.target)) {
      e.stopPropagation();
      if (isLocked) {
        postMouseData(e, true);
      } else {
        canvas.requestPointerLock();
      }
    }
  }, true);
  document.addEventListener("mouseup", (e) => {
    e.stopPropagation();
    if (isLocked) {
      postMouseData(e, false);
    } else if (canvas.contains(e.target)) {
      canvas.requestPointerLock();
    }
  }, true);
  document.addEventListener("mousemove", (e) => {
    e.stopPropagation();
    if (isLocked) {
      postMouseData(e);
    }
  }, true);

  document.addEventListener('pointerlockchange', () => {
    isLocked = document.pointerLockElement === canvas;
  });
  document.addEventListener('pointerlockerror', (e) => {
    console.error('Pointer lock error', e);
  });

  const oldStep = vm.runtime._step;
  vm.runtime._step = function (...args) {
    const ret = oldStep.call(this, ...args);
    const {width, height} = scaffolding.layersRect;
    mouse._clientX = width / 2;
    mouse._clientY = height / 2;
    mouse._scratchX = 0;
    mouse._scratchY = 0;
    return ret;
  };
})();

Haven't tested it super thoroughly, but it seems to work good enough. Let me know if it's broken.

GarboMuffin commented 3 years ago

Next update will have a builtin option for pointer lock