UNPKG

qwc2

Version:
423 lines (416 loc) 18.5 kB
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); } function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); } function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } import { Controls, MOUSE, Raycaster, Vector2, Vector3 } from 'three'; var _twoPI = 2 * Math.PI; var STATE = { NONE: -1, ROTATE: 0, PAN: 1, TOUCH_ROTATE: 2, TOUCH_PAN: 3 }; var FirstPersonControls3D = /*#__PURE__*/function (_Controls) { function FirstPersonControls3D(object, mouseButtons) { var _this; _classCallCheck(this, FirstPersonControls3D); _this = _callSuper(this, FirstPersonControls3D, [object, null]); // Keyboard navigate _defineProperty(_this, "_handleKeyboardNav", function () { var lr = -_this._keyState.ArrowLeft + _this._keyState.ArrowRight; var du = -_this._keyState.ArrowDown + _this._keyState.ArrowUp; var pg = -_this._keyState.PageDown + _this._keyState.PageUp; var pitch = _this._keyState.Shift ? du * _this.keyRotateStep : 0; var yaw = _this._keyState.Control ? 0 : -lr * _this.keyRotateStep; var dx = _this._keyState.Control ? lr * _this.keyPanStep * 0.75 : 0; var dy = _this._keyState.Shift ? 0 : du * _this.keyPanStep; _this._rotate(yaw, pitch); _this._pan(dx, dy); if (pg) { var newPersonHeight = Math.max(2, _this.personHeight + _this.personHeight * pg * 0.05); _this.target.z += newPersonHeight - _this.personHeight; _this.personHeight = newPersonHeight; _this._changed = true; _this.update(); } }); // Event listeners _defineProperty(_this, "_onKeyDown", function (event) { if (event.key in _this._keyState) { _this._keyState[event.key] = true; if (!_this._keyboardNavInterval) { _this._keyboardNavInterval = setInterval(_this._handleKeyboardNav, 50); } } }); _defineProperty(_this, "_onKeyUp", function (event) { if (event.key in _this._keyState) { _this._keyState[event.key] = false; if (Object.values(_this._keyState).every(function (x) { return !x; })) { clearInterval(_this._keyboardNavInterval); _this._keyboardNavInterval = null; } } }); _defineProperty(_this, "_onBlur", function () { _this._keyState = { ArrowLeft: false, ArrowRight: false, ArrowUp: false, ArrowDown: false, PageUp: false, PageDown: false, Control: false, Shift: false }; clearInterval(_this._keyboardNavInterval); _this._keyboardNavInterval = null; }); _defineProperty(_this, "_onPointerDown", function (event) { if (!_this.enabled) { return; } if (_this._pointers.length === 0) { _this.domElement.setPointerCapture(event.pointerId); _this.domElement.addEventListener('pointermove', _this._onPointerMove); _this.domElement.addEventListener('pointerup', _this._onPointerUp); _this.domElement.addEventListener('pointercancel', _this._onPointerUp); } else if (_this._isTrackingPointer(event)) { return; } _this._addPointer(event); if (event.pointerType === 'touch') { _this._onTouchStart(event); } else { _this._onMouseDown(event); } }); _defineProperty(_this, "_onPointerMove", function (event) { if (event.pointerType === 'touch') { _this._onTouchMove(event); } else { _this._onMouseMove(event); } }); _defineProperty(_this, "_onPointerUp", function (event) { _this._removePointer(event); if (_this._pointers.length === 0) { _this.domElement.releasePointerCapture(event.pointerId); _this.domElement.removeEventListener('pointermove', _this._onPointerMove); _this.domElement.removeEventListener('pointerup', _this._onPointerUp); _this.domElement.removeEventListener('pointercancel', _this._onPointerUp); _this._interactionState = STATE.NONE; } else if (_this._pointers.length === 1) { var pointerId = _this._pointers[0]; var position = _this._pointerPositions[pointerId]; // minimal placeholder event - allows state correction on pointer-up _this._onTouchStart({ pointerId: pointerId, pageX: position.x, pageY: position.y }); } }); _defineProperty(_this, "_onMouseDown", function (event) { var buttonMap = { 0: 'LEFT', 1: 'MIDDLE', 2: 'RIGHT' }; _this._interactionState = STATE.NONE; if (_this.mouseButtons[buttonMap[event.button]] === MOUSE.ROTATE) { _this._interactionState = STATE.ROTATE; _this._interactionStart.set(event.clientX, event.clientY); } else if (_this.mouseButtons[buttonMap[event.button]] === MOUSE.PAN) { _this._interactionState = STATE.PAN; _this._interactionStart.set(event.clientX, event.clientY); } }); _defineProperty(_this, "_onMouseMove", function (event) { var deltaX = event.clientX - _this._interactionStart.x; var deltaY = event.clientY - _this._interactionStart.y; _this._interactionStart.set(event.clientX, event.clientY); if (_this._interactionState === STATE.PAN) { _this._pan(-deltaX * _this.mousePanSpeed, deltaY * _this.mousePanSpeed); } else if (_this._interactionState === STATE.ROTATE) { _this._rotate(_twoPI * deltaX * _this.mouseRotateSpeed / _this.domElement.clientHeight, // yes, height _twoPI * deltaY * _this.mouseRotateSpeed / _this.domElement.clientHeight); } }); _defineProperty(_this, "_onTouchStart", function (event) { _this._interactionState = STATE.NONE; if (_this._pointers.length === 1) { _this._interactionState = STATE.TOUCH_PAN; _this._interactionStart.set(event.pageX, event.pageY); } else if (_this._pointers.length === 2) { _this._interactionState = STATE.TOUCH_ROTATE; var _this$_getTwoPointerP = _this._getTwoPointerPosition(event), x = _this$_getTwoPointerP.x, y = _this$_getTwoPointerP.y; _this._interactionStart.set(x, y); } }); _defineProperty(_this, "_onTouchMove", function (event) { _this._trackPointer(event); if (_this._interactionState === STATE.TOUCH_PAN) { var deltaX = event.pageX - _this._interactionStart.x; var deltaY = event.pageY - _this._interactionStart.y; _this._interactionStart.set(event.pageX, event.pageY); _this._pan(-deltaX * _this.mousePanSpeed, deltaY * _this.mousePanSpeed); } else if (_this._interactionState === STATE.TOUCH_ROTATE) { var _this$_getTwoPointerP2 = _this._getTwoPointerPosition(event), x = _this$_getTwoPointerP2.x, y = _this$_getTwoPointerP2.y; var _deltaX = x - _this._interactionStart.x; var _deltaY = y - _this._interactionStart.y; _this._interactionStart.set(x, y); _this._rotate(_twoPI * _deltaX * _this.mouseRotateSpeed / _this.domElement.clientHeight, // yes, height _twoPI * _deltaY * _this.mouseRotateSpeed / _this.domElement.clientHeight); } }); _defineProperty(_this, "_onContextMenu", function (event) { event.preventDefault(); }); _this.mouseButtons = mouseButtons; // Step sizes _this.keyPanStep = 1.5; _this.keyRotateStep = 4 / 180 * Math.PI; _this.mousePanSpeed = 0.1; _this.mouseRotateSpeed = 10 / 180 * Math.PI; _this.personHeight = 3; _this.sceneContext = null; _this.enabled = false; _this.yaw = 0; _this.pitch = 0; _this.lookAt = new Vector3(0, 1, 0); // Target is the actual collision detection point _this.target = new Vector3().addVectors(_this.object.position, _this.lookAt.clone().multiplyScalar(3)); _this.isFirstPerson = true; // Internals _this._keyState = { ArrowLeft: false, ArrowRight: false, ArrowUp: false, ArrowDown: false, PageUp: false, PageDown: false, Control: false, Shift: false }; _this._keyboardNavInterval = null; _this._changed = false; _this._interactionState = STATE.NONE; _this._interactionStart = new Vector2(); _this._pointers = []; _this._pointerPositions = {}; return _this; } _inherits(FirstPersonControls3D, _Controls); return _createClass(FirstPersonControls3D, [{ key: "connect", value: function connect(sceneContext) { this.domElement = sceneContext.scene.domElement; this.sceneContext = sceneContext; this.domElement.addEventListener('pointerdown', this._onPointerDown); this.domElement.addEventListener('pointercancel', this._onPointerUp); this.domElement.addEventListener('contextmenu', this._onContextMenu); this.domElement.addEventListener('keydown', this._onKeyDown); this.domElement.addEventListener('keyup', this._onKeyUp); this.domElement.addEventListener('blur', this._onBlur); this.domElement.style.touchAction = 'none'; // disable touch scroll this.object.near = 0.1; this.sceneContext.scene.view.setControls(this); this.enabled = true; } }, { key: "disconnect", value: function disconnect() { this.enabled = false; this.sceneContext.scene.view.setControls(null); this.domElement.removeEventListener('pointerdown', this._onPointerDown); this.domElement.removeEventListener('pointermove', this._onPointerMove); this.domElement.removeEventListener('pointerup', this._onPointerUp); this.domElement.removeEventListener('pointercancel', this._onPointerUp); this.domElement.removeEventListener('contextmenu', this._onContextMenu); this.domElement.removeEventListener('keydown', this._onKeyDown); this.domElement.removeEventListener('keyup', this._onKeyUp); this.domElement.removeEventListener('blur', this._onBlur); this.domElement.style.touchAction = 'auto'; } }, { key: "setView", value: function setView(targetpos, lookAt) { var personHeight = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined; this.personHeight = personHeight !== null && personHeight !== void 0 ? personHeight : this.personHeight; this.target.copy(targetpos); this.lookAt.copy(lookAt); this.object.position.subVectors(targetpos, lookAt.clone().multiplyScalar(3)); this.pitch = Math.asin(Math.max(-1.0, Math.min(1.0, this.lookAt.z))); this.yaw = Math.atan2(-this.lookAt.x, this.lookAt.y); this.object.lookAt(this.target); this.dispatchEvent({ type: 'change' }); } }, { key: "panView", value: function panView(dx, dy) { if (dx || dy) { this._pan(dx, dy); } } }, { key: "tiltView", value: function tiltView(yaw, pitch) { this.yaw += yaw; this.pitch += pitch; if (yaw || pitch) { this._changed = true; this.update(); } } }, { key: "dispose", value: function dispose() { this.disconnect(); } }, { key: "update", value: function update() { var deltaTime = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; if (!this._changed) { return; } this.lookAt.x = -Math.sin(this.yaw) * Math.cos(this.pitch); this.lookAt.y = Math.cos(this.yaw) * Math.cos(this.pitch); this.lookAt.z = Math.sin(this.pitch); this.object.position.subVectors(this.target, this.lookAt.clone().multiplyScalar(3)); this.object.lookAt(this.target); this.dispatchEvent({ type: 'change' }); this._changed = false; } // Internals }, { key: "_rotate", value: function _rotate(yaw, pitch) { this.yaw += yaw; this.pitch = Math.max(-0.5 * Math.PI, Math.min(this.pitch + pitch, 0.5 * Math.PI)); this._changed = true; this.update(); } // deltaX and deltaY are in pixels; right and down are positive }, { key: "_pan", value: function _pan(deltaX, deltaY) { var cosY = Math.cos(this.yaw); var sinY = Math.sin(this.yaw); var dx = cosY * deltaX + -sinY * deltaY; var dy = sinY * deltaX + cosY * deltaY; var dir = new Vector2(dx, dy); var step = dir.length(); if (step < 0.001) { return; } dir.divideScalar(step); // Adjust step to avoid passing within any wall buffer zone var raycaster = new Raycaster(); raycaster.set(this.target, new Vector3(dir.x, dir.y, 0)); var inter = raycaster.intersectObjects(this.sceneContext.collisionObjects, true)[0]; var wallBuffer = 0.5; if (inter && inter.distance - wallBuffer < step) { var overstep = step - (inter.distance - wallBuffer); step -= overstep; this.target.x += step * dir.x; this.target.y += step * dir.y; // Project overstep onto wall var tangent = new Vector2(-inter.normal.y, inter.normal.x).normalize(); var slidestep = tangent.dot(dir) * overstep; if (slidestep < 0) { tangent.negate(); slidestep *= -1; } raycaster.set(this.target, new Vector3(tangent.x, tangent.y, 0)); var slideInter = raycaster.intersectObjects(this.sceneContext.collisionObjects, true)[0]; if (slideInter && slideInter.distance - wallBuffer < slidestep) { slidestep = slideInter.distance - wallBuffer; } this.target.x += slidestep * tangent.x; this.target.y += slidestep * tangent.y; } else { this.target.x += step * dir.x; this.target.y += step * dir.y; } // Stay above terrain // objects on terain var height = undefined; raycaster.set(this.target, new Vector3(0, 0, -1)); var vinter = raycaster.intersectObjects(this.sceneContext.collisionObjects, true)[0]; if (vinter) { height = vinter.point.z; } else { height = this.sceneContext.getTerrainHeightFromMap([this.target.x, this.target.y]); } if (height !== undefined) { var newHeight = height + this.personHeight; this.target.z = 0.75 * this.target.z + 0.25 * newHeight; } this._changed = true; this.update(); } }, { key: "_addPointer", value: // Touch pointer tracking function _addPointer(event) { this._pointers.push(event.pointerId); this._pointerPositions[event.pointerId] = new Vector2(event.pageX, event.pageY); } }, { key: "_removePointer", value: function _removePointer(event) { delete this._pointerPositions[event.pointerId]; this._pointers = this._pointers.filter(function (id) { return id !== event.pointerId; }); } }, { key: "_isTrackingPointer", value: function _isTrackingPointer(event) { return this._pointers.find(function (id) { return id === event.pointerId; }) !== undefined; } }, { key: "_trackPointer", value: function _trackPointer(event) { this._pointerPositions[event.pointerId].set(event.pageX, event.pageY); } }, { key: "_getTwoPointerPosition", value: function _getTwoPointerPosition(event) { var otherPointerId = event.pointerId === this._pointers[0] ? this._pointers[1] : this._pointers[0]; var otherPointerPos = this._pointerPositions[otherPointerId]; return { x: 0.5 * (event.pageX + otherPointerPos.x), y: 0.5 * (event.pageY + otherPointerPos.y) }; } }]); }(Controls); export { FirstPersonControls3D as default };