diff --git a/src/components/AssetsManagement/AssetPreview.vue b/src/components/AssetsManagement/AssetPreview.vue index 5c5b747..f309b27 100644 --- a/src/components/AssetsManagement/AssetPreview.vue +++ b/src/components/AssetsManagement/AssetPreview.vue @@ -55,7 +55,6 @@ export default{ async obj(){ if (!this.obj) return; gameEngine = new GameEngine(); - this.gameEngine = gameEngine; await gameEngine.init(this.$refs.target, { gizmo: true, xr: true, diff --git a/src/components/GamePreview/GamePreview.vue b/src/components/GamePreview/GamePreview.vue index 63826b3..99cc70d 100644 --- a/src/components/GamePreview/GamePreview.vue +++ b/src/components/GamePreview/GamePreview.vue @@ -56,14 +56,6 @@ export default { renderType: 'ST', cameraType: 'perspective', } - }, - methods:{ - async setGameHeader(){ - let screenshot = await this.engine.captureScreenshot(); - let fd = new FormData(); - fd.append('file', screenshot); - await this.$api.game.setHeader(this.modelValue.id, fd); - } } } \ No newline at end of file diff --git a/src/lib/GameEngine.js b/src/lib/GameEngine.js index 5f8d239..fbf3d09 100644 --- a/src/lib/GameEngine.js +++ b/src/lib/GameEngine.js @@ -263,31 +263,86 @@ class GameEngine extends EventManager{ }).bind(this) renderer.domElement.addEventListener('wheel', this._wheelEvent) - GameEngine.ktxLoader.detectSupport(renderer); } initXr() { + this.xrHandlers = { + onControllerEvent: (event=>{ + const controller = event.target; + if (!controller.userData?.active) return; + + if (this.opts.designMode){ + this.transformControls.getRaycaster().setFromXRController(controller); + switch (event.type) { + case 'selectstart': + this.transformControls.pointerDown(null); + break; + case 'selectend': + this.transformControls.pointerUp(null); + break; + case 'move': + this.transformControls.pointerHover(null); + this.transformControls.pointerMove(null); + break; + } + }else{ + this.draggable?.handleController(controller, event.type) + } + }).bind(this), + + onSelect: (event => { + const controller = event.target; + this.xrController1.userData.active = false; + this.xrController2.userData.active = false; + + if (controller === this.xrController1) { + this.xrController1.userData.active = true; + this.xrController1.add(this.controllerLine); + } + + if (controller === this.xrController2) { + this.xrController2.userData.active = true; + this.xrController2.add(this.controllerLine); + } + + if (this.opts.designMode){ + this.raycaster.setFromXRController(controller); + const intersects = this.raycaster.intersectObjects(this.activeObjects.children, true); + + intersects.forEach(o => { + while (o.object && !this.activeObjects.children.includes(o.object)) { + o.object = o.object.parent; + } + }) + + if (intersects.length > 0) { + setTimeout(() => { + this.transformControls.attach(intersects[0].object); + }, 100); + } + }else{ + this.clickable.handleController(controller, event); + } + }).bind(this), + + onConnect: e => { + e.target.gamepad = e.data.gamepad; + } + } + let c1 = this.renderer.xr.getController(0); - c1.addEventListener('select', this.onSelect.bind(this)); - c1.addEventListener('selectstart', this.onControllerEvent.bind(this)); - c1.addEventListener('selectend', this.onControllerEvent.bind(this)); - c1.addEventListener('move', this.onControllerEvent.bind(this)); c1.userData.active = false; - c1.addEventListener('connected', e => { - c1.gamepad = e.data.gamepad; - // this.session = this.renderer.xr.getSession(); - // this.session.addEventListener('selectstart', this.onControllerEvent.bind(this)); - }) let c2 = this.renderer.xr.getController(1); - c2.addEventListener('select', this.onSelect.bind(this)); - c2.addEventListener('selectstart', this.onControllerEvent.bind(this)); - c2.addEventListener('selectend', this.onControllerEvent.bind(this)); - c2.addEventListener('move', this.onControllerEvent.bind(this)); c2.userData.active = true; - c2.addEventListener('connected', e => { - c2.gamepad = e.data.gamepad; + + [c1, c2].forEach(c=>{ + c.addEventListener('select', this.xrHandlers.onSelect); + c.addEventListener('selectstart', this.xrHandlers.onControllerEvent); + c.addEventListener('selectend', this.xrHandlers.onControllerEvent); + c.addEventListener('move', this.xrHandlers.onControllerEvent); + c.addEventListener('connected', this.xrHandlers.onConnect) }) const controllerModelFactory = new XRControllerModelFactory(); @@ -307,6 +362,16 @@ class GameEngine extends EventManager{ this.xrCamera = this.renderer.xr.getCamera(); } + disposeXr(){ + [this.xrController1, this.xrController2].forEach(c=>{ + c.removeEventListener('select', this.xrHandlers.onSelect); + c.removeEventListener('selectstart', this.xrHandlers.onControllerEvent); + c.removeEventListener('selectend', this.xrHandlers.onControllerEvent); + c.removeEventListener('move', this.xrHandlers.onControllerEvent); + c.removeEventListener('connected', this.xrHandlers.onConnect); + }) + } + initCameraPivot() { this.cameraWorld = new THREE.Group(); this.cameraRig = new THREE.Group(); @@ -373,64 +438,6 @@ class GameEngine extends EventManager{ } } - onControllerEvent(event) { - const controller = event.target; - if (!controller.userData?.active) return; - - if (this.opts.designMode){ - this.transformControls.getRaycaster().setFromXRController(controller); - switch (event.type) { - case 'selectstart': - this.transformControls.pointerDown(null); - break; - case 'selectend': - this.transformControls.pointerUp(null); - break; - case 'move': - this.transformControls.pointerHover(null); - this.transformControls.pointerMove(null); - break; - } - }else{ - this.draggable?.handleController(controller, event.type) - } - } - - onSelect(event) { - const controller = event.target; - this.xrController1.userData.active = false; - this.xrController2.userData.active = false; - - if (controller === this.xrController1) { - this.xrController1.userData.active = true; - this.xrController1.add(this.controllerLine); - } - - if (controller === this.xrController2) { - this.xrController2.userData.active = true; - this.xrController2.add(this.controllerLine); - } - - if (this.opts.designMode){ - this.raycaster.setFromXRController(controller); - const intersects = this.raycaster.intersectObjects(this.activeObjects.children, true); - - intersects.forEach(o => { - while (o.object && !this.activeObjects.children.includes(o.object)) { - o.object = o.object.parent; - } - }) - - if (intersects.length > 0) { - setTimeout(() => { - this.transformControls.attach(intersects[0].object); - }, 100); - } - }else{ - this.clickable.handleController(controller, event); - } - } - $ = THREE; async load(url, path = assetPath, progress) { @@ -658,8 +665,14 @@ class GameEngine extends EventManager{ clearObject(o){ let disposables = [] o.traverse(object => { - if (!object.isMesh) return; - disposables.push(object); + if (object.isMesh) { + disposables.push(object); + } + if (object.isLight){ + object.shadow?.map?.dispose(); + object.shadow?.dispose(); + object.dispose(); + } }); disposables.forEach(object=>{ object.removeFromParent(); @@ -720,6 +733,7 @@ class GameEngine extends EventManager{ dispose(){ this.stop(); this.clearScene(); + this.disposeXr(); this.renderer.dispose(); this.pmremGenerator.dispose(); this.arBtn?.remove(); diff --git a/src/mixins/GameEnvironmentMixin.js b/src/mixins/GameEnvironmentMixin.js index 2c82523..7bdefec 100644 --- a/src/mixins/GameEnvironmentMixin.js +++ b/src/mixins/GameEnvironmentMixin.js @@ -8,7 +8,7 @@ let engine = null; export default { async mounted(){ - this.engine = engine = new GameEngine(); + engine = new GameEngine(); await engine.init(this.$refs.target, { xr: true, gizmo: this.env == 'GameDesigner', @@ -32,7 +32,8 @@ export default { window.removeEventListener('resize', this.resize); engine.tm?.setGame(null); engine.dispose(); - this.debug('Disposed scene', engine.renderer.info.memory) + this.debug('Disposed scene', engine.renderer.info.memory); + engine = null; }, computed:{ @@ -307,6 +308,13 @@ export default { async fullScreen(){ await engine.renderer.domElement.requestFullscreen() + }, + + async setGameHeader(){ + let screenshot = await engine.captureScreenshot(); + let fd = new FormData(); + fd.append('file', screenshot); + await this.$api.game.setHeader(this.modelValue.id, fd); } } } \ No newline at end of file