UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

158 lines (157 loc) 5.48 kB
"use strict"; import { Euler, EventDispatcher, Vector3, Spherical } from "three"; import { CorePlayerKeyEvents } from "../../../core/player/KeyEvents"; const changeEvent = { type: "change" }; const lockEvent = { type: "lock" }; const unlockEvent = { type: "unlock" }; const PI_2 = Math.PI / 2; const tmpCameraUnproject = new Vector3(); const spherical = new Spherical(); const LOCK_ELEMENT_DEFAULT_HTML = ` <div style=" text-align:center; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); cursor: pointer; padding: 5px 10px; background:gray; border:white; color: white; "> <div style="font-size: 1rem">CLICK TO START</div> <div style="font-size: 0.6rem">press ESC to show your cursor</div> </div> `; export class PointerLockControls extends EventDispatcher { constructor(camera, domElement, options, player) { super(); this.camera = camera; this.domElement = domElement; this.options = options; this.player = player; this.isLocked = false; this.minPolarAngle = 0; // radians this.maxPolarAngle = Math.PI; // radians this.rotateSpeed = 1; this.euler = new Euler(0, 0, 0, "YXZ"); this.boundMethods = { lock: this.lock.bind(this), onMouseMove: this.onMouseMove.bind(this), onPointerlockChange: this.onPointerlockChange.bind(this), onPointerlockError: this.onPointerlockError.bind(this) }; this._azimuthalAngle = 0; this.connect(); this._showUnlockHTMLElement(); } onMouseMove(event) { if (this.isLocked === false) return; var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0; var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0; this.euler.setFromQuaternion(this.camera.quaternion); this.euler.y -= movementX * 2e-3 * this.rotateSpeed; this.euler.x -= movementY * 2e-3 * this.rotateSpeed; this.euler.x = Math.max(PI_2 - this.maxPolarAngle, Math.min(PI_2 - this.minPolarAngle, this.euler.x)); this.camera.quaternion.setFromEuler(this.euler); this._computeAzimuthalAngle(); this.dispatchEvent(changeEvent); } _computeAzimuthalAngle() { this.camera.updateMatrixWorld(); tmpCameraUnproject.set(0, 0, 1); this.camera.localToWorld(tmpCameraUnproject); tmpCameraUnproject.sub(this.camera.position); spherical.setFromVector3(tmpCameraUnproject); this._azimuthalAngle = spherical.theta; } onPointerlockChange() { var _a, _b; if (this.domElement.ownerDocument.pointerLockElement === this.domElement) { this.dispatchEvent(lockEvent); this.isLocked = true; this._removeHTMLElement(); if (this.player) { this._corePlayerKeyEvents = this._corePlayerKeyEvents || new CorePlayerKeyEvents(this.player); this._corePlayerKeyEvents.addEvents(); } } else { this.dispatchEvent(unlockEvent); this.isLocked = false; this._showUnlockHTMLElement(); (_a = this._corePlayerKeyEvents) == null ? void 0 : _a.removeEvents(); (_b = this.player) == null ? void 0 : _b.stop(); } } onPointerlockError() { console.error( "THREE.PointerLockControls: Unable to use Pointer Lock API (Note that you need to wait for 2 seconds to lock the pointer after having just unlocked it)" ); } connect() { this.domElement.ownerDocument.addEventListener("mousemove", this.boundMethods.onMouseMove); this.domElement.ownerDocument.addEventListener("pointerlockchange", this.boundMethods.onPointerlockChange); this.domElement.ownerDocument.addEventListener("pointerlockerror", this.boundMethods.onPointerlockError); } disconnect() { this.domElement.ownerDocument.removeEventListener("mousemove", this.boundMethods.onMouseMove); this.domElement.ownerDocument.removeEventListener("pointerlockchange", this.boundMethods.onPointerlockChange); this.domElement.ownerDocument.removeEventListener("pointerlockerror", this.boundMethods.onPointerlockError); } dispose() { this.disconnect(); this._removeHTMLElement(); } getObject() { return this.camera; } lock() { this.domElement.requestPointerLock(); } unlock() { this.domElement.ownerDocument.exitPointerLock(); } update(delta) { if (this.player) { this.player.setAzimuthalAngle(this._azimuthalAngle); this.player.update(delta); } } _unlockHTMLElementParent() { return this.domElement.parentElement; } _unlockHTMLElement() { return this.__unlockHTMLElement = this.__unlockHTMLElement || this._getUnlockHTMLElement(); } _showUnlockHTMLElement() { var _a; const el = this._unlockHTMLElement(); if (!el) { return; } (_a = this._unlockHTMLElementParent()) == null ? void 0 : _a.append(el); } _getUnlockHTMLElement() { const element = this.options.lockHTMLElement || this._createUnlockHTMLElement(); element.addEventListener("pointerdown", this.boundMethods.lock); return element; } _createUnlockHTMLElement() { const el = document.createElement("div"); el.innerHTML = LOCK_ELEMENT_DEFAULT_HTML; return el; } _removeHTMLElement() { var _a; if (!this.__unlockHTMLElement) { return; } (_a = this._unlockHTMLElementParent()) == null ? void 0 : _a.removeChild(this.__unlockHTMLElement); this.__unlockHTMLElement.removeEventListener("pointerdown", this.boundMethods.lock); this.__unlockHTMLElement = void 0; } }